def ecc_encode(msg, pad = False): """ encode message 'msg' which must be of length MAX_LENGTH: 1. pad msg if 'pad' is True 2. Map each 4bit word of 'msg' to one of the base vectors. 3. Transpose and repeat message twice. The encoding attempts to map nicely to current physical low power devices which generally support packet handling and where packet lengths are generally limited to 255 bytes (TI: CC1101 and CC1120 etc, Freescale RF MCU, HopeRF RFM69W, Silicon Labs RF MCU etc). """ if pad: msg = pad(msg) length = MAX_LENGTH assert len(msg) == length div = length / 8 enc_msg_high = [] enc_msg_low = [] for c in msg: enc_msg_high.append(BASE_VECTORS[c >> 4]) enc_msg_low.append(BASE_VECTORS[c % 16]) ## transpose tr_msg_high = bit_transpose(enc_msg_high) tr_msg_low = bit_transpose(enc_msg_low) ## duplicate out = [] for i in range(8 * 2): _from = i * div _to = (i+1) * div out.extend(tr_msg_high[_from:_to]) out.extend(tr_msg_high[_from:_to]) out.extend(tr_msg_low[_from:_to]) out.extend(tr_msg_low[_from:_to]) return s_to_a(out)
def ecc_encode(msg, pad=False): """ encode message 'msg' which must be of length MAX_LENGTH: 1. pad msg if 'pad' is True 2. Map each 4bit word of 'msg' to one of the base vectors. 3. Transpose and repeat message twice. The encoding attempts to map nicely to current physical low power devices which generally support packet handling and where packet lengths are generally limited to 255 bytes (TI: CC1101 and CC1120 etc, Freescale RF MCU, HopeRF RFM69W, Silicon Labs RF MCU etc). """ if pad: msg = pad(msg) length = MAX_LENGTH assert len(msg) == length div = length / 8 enc_msg_high = [] enc_msg_low = [] for c in msg: enc_msg_high.append(BASE_VECTORS[c >> 4]) enc_msg_low.append(BASE_VECTORS[c % 16]) ## transpose tr_msg_high = bit_transpose(enc_msg_high) tr_msg_low = bit_transpose(enc_msg_low) ## duplicate out = [] for i in range(8 * 2): _from = i * div _to = (i + 1) * div out.extend(tr_msg_high[_from:_to]) out.extend(tr_msg_high[_from:_to]) out.extend(tr_msg_low[_from:_to]) out.extend(tr_msg_low[_from:_to]) return s_to_a(out)
def test(): import random msg = pad(s_to_a('Hello QuietCasting')) assert msg[0] == 18 assert len(msg) == MAX_LENGTH tr_msg = bit_transpose(msg) assert reverse_bit_transpose(tr_msg) == msg print 'Encoding ...' enc = ecc_encode(msg) print enc print 'Corrupting message (random) ...' rec = [] for c in enc: e = 0 for i in range(8): r = random.randint(0, 999) if r < 5: e |= 1 e <<= 1 rec.append(c ^ e) total = 0 for (i, j) in zip(rec, enc): if i != j: total += 1 print total, 'corrupted characters detected ...' print rec print 'Decoding ...' dec = ecc_decode(rec) print dec if dec[1] == msg: print 'Decoded succesfully!' else: print 'Errors detected' print dec print msg print 'Corrupting message (burst) ...' rec = array.array('B', [c ^ 255 for c in enc[:24]]) + enc[24:] total = 0 for (i, j) in zip(rec, enc): if i != j: total += 1 print total, 'corrupted characters detected ...' print rec print 'Decoding ...' dec = ecc_decode(rec) print dec if dec[1] == msg: print 'Decoded succesfully!' else: print 'Errors detected' print dec print msg
def ecc_decode(received_code): """ decode 'received_code'. 'received_code' is the set of MAX_LENGTH * 4 bytes making up the received packet. the optimal decoded message is the one maximizing the posterior probability given the received code using Bayes rule. An iterative algorithm may be appropriate here but to keep things simple we will follow a simpler scheme where we just use the reverse map to detect the most probable message word. """ length = MAX_LENGTH * 4 div = MAX_LENGTH / 8 assert len(received_code) == length ## break duplicate data into 2 parts and each part into high bit ## and low pit parts code_1_high = [] code_1_low = [] code_2_high = [] code_2_low = [] while received_code: (head, received_code) = (received_code[:div], received_code[div:]) code_1_high.extend(head) (head, received_code) = (received_code[:div], received_code[div:]) code_2_high.extend(head) (head, received_code) = (received_code[:div], received_code[div:]) code_1_low.extend(head) (head, received_code) = (received_code[:div], received_code[div:]) code_2_low.extend(head) ## transpose tr_code_1_high = reverse_bit_transpose(code_1_high) tr_code_1_low = reverse_bit_transpose(code_1_low) tr_code_2_high = reverse_bit_transpose(code_2_high) tr_code_2_low = reverse_bit_transpose(code_2_low) # decode dec_code = [] has_error = False for i in range(MAX_LENGTH): high1 = REVERSE_MAP[tr_code_1_high[i]] low1 = REVERSE_MAP[tr_code_1_low[i]] high2 = REVERSE_MAP[tr_code_2_high[i]] low2 = REVERSE_MAP[tr_code_2_low[i]] c = 0 ## do high bits if high1 < 16 and high2 < 16: if high1 == high2: c = high1 else: has_error = True elif high1 < 16 and high2 == 16: c = high1 elif high1 == 16 and high2 < 16: c = high2 else: has_error = True c <<= 4 ## do low bits if low1 < 16 and low2 < 16: if low1 == low2: c |= low1 else: has_error = True elif low1 < 16 and low2 == 16: c |= low1 elif low1 == 16 and low2 < 16: c |= low2 else: has_error = True dec_code.append(c) return (has_error, s_to_a(dec_code))
def test(): import random msg = pad(s_to_a('Hello QuietCasting')) assert msg[0] == 18 assert len(msg) == MAX_LENGTH tr_msg = bit_transpose(msg) assert reverse_bit_transpose(tr_msg) == msg print 'Encoding ...' enc = ecc_encode(msg) print enc print 'Corrupting message (random) ...' rec = [] for c in enc: e = 0 for i in range(8): r = random.randint(0,999) if r < 5: e |= 1 e <<= 1 rec.append(c ^ e) total = 0 for (i,j) in zip(rec, enc): if i!=j: total += 1 print total, 'corrupted characters detected ...' print rec print 'Decoding ...' dec = ecc_decode(rec) print dec if dec[1] == msg: print 'Decoded succesfully!' else: print 'Errors detected' print dec print msg print 'Corrupting message (burst) ...' rec = array.array('B', [c^255 for c in enc[:24]]) + enc[24:] total = 0 for (i,j) in zip(rec, enc): if i!=j: total += 1 print total, 'corrupted characters detected ...' print rec print 'Decoding ...' dec = ecc_decode(rec) print dec if dec[1] == msg: print 'Decoded succesfully!' else: print 'Errors detected' print dec print msg