nrf24_packet_decoder.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. #
  2. # NRF24L01+ Enhanced ShockBurst packets decoder
  3. #
  4. payload_len_default = 4
  5. packets = \
  6. (
  7. '10101010 11101110 00000011 00001000 00001011 01000111 000100 10 0 10101010 10101010 10101010 10101010 00011101',
  8. '10101010 11001000 11001000 11000011 110011 10 0 00001011 00000011 00000101 00000000 0010001100100000',
  9. )
  10. def bin2hex(x):
  11. def bin2hex_helper(r):
  12. while r:
  13. yield r[0:2].upper()
  14. r = r[2:]
  15. fmt = "{0:0" + str(int(len(x) / 8 * 2)) + "X}"
  16. hex_data = fmt.format(int(x, 2))
  17. return list(bin2hex_helper(hex_data))
  18. def split_packet(packet, parts):
  19. """Split a string of 1s and 0s into multiple substrings as specified by parts.
  20. Example: "111000011000", (3, 4, 2) -> ["111", "0000", "11", "000"]
  21. :param packet: String of 1s and 0s
  22. :param parts: Tuple of length of substrings
  23. :return: list of substrings
  24. """
  25. out = []
  26. packet = packet.replace(' ', '')
  27. for part_length in parts:
  28. out.append(packet[0:part_length])
  29. packet = packet[part_length:]
  30. out.append(packet)
  31. return out
  32. def parse_packet(packet, address_length):
  33. """Split a packet into its fields and return them as tuple."""
  34. preamble, address, payload_length, pid, no_ack, rest = split_packet(packet=packet,
  35. parts=(8, 8 * address_length, 6, 2, 1))
  36. payload, crc = split_packet(packet=rest, parts=((payload_len_default if int(payload_length, 2) > 32 else int(payload_length, 2)) * 8,))
  37. assert preamble in ('10101010', '01010101')
  38. assert len(crc) in (8, 16)
  39. return preamble, address, payload_length, pid, no_ack, payload, crc
  40. def crc(bits, size=8):
  41. """Calculate the crc value for the polynomial initialized with 0xFF/0xFFFF)
  42. :param size: 8 or 16 bit crc
  43. :param bits: String of 1s and 0s
  44. :return:
  45. :polynomial: 1 byte CRC - standard is 0x107 = 0b100000111 = x^8+x^2+x^1+1, result the same for 0x07
  46. :polynomial: 2 byte CRC - standard is 0x11021 = X^16+X^12+X^5+1, result the same for 0x1021
  47. """
  48. if size == 8:
  49. polynomial = 0x107
  50. crc = 0xFF
  51. else:
  52. polynomial = 0x11021
  53. crc = 0xFFFF
  54. max_crc_value = (1 << size) - 1 # e.g. 0xFF for mode 8bit-crc
  55. for bit in bits:
  56. bit = int(bit, 2)
  57. crc <<= 1
  58. if (crc >> size) ^ bit: # top most lfsr bit xor current data bit
  59. crc ^= polynomial
  60. crc &= max_crc_value # trim the crc to reject carry over bits
  61. return crc
  62. if __name__ == '__main__':
  63. for packet in packets:
  64. fld = packet.split(' ');
  65. address_length = -1
  66. for f in fld:
  67. if len(f) == 6: break
  68. address_length += 1
  69. preamble, address, payload_length, pid, no_ack, payload, crc_received = \
  70. parse_packet(packet=packet, address_length=address_length)
  71. crc_size = len(crc_received)
  72. crc_received = hex(int(crc_received, 2))
  73. print(f"Packet: {packet}")
  74. print('\n'.join((
  75. f'Preamble: {preamble}',
  76. f'Address: {address_length} bytes - {bin2hex(address)}',
  77. f'Payload length in packet: {int(payload_length, 2)}, used: {(payload_len_default if int(payload_length, 2) > 32 else int(payload_length, 2))}',
  78. f'Pid: {int(pid, 2)}',
  79. f'No_ack: {int(no_ack, 2) == 1}',
  80. f'Payload: {bin2hex(payload)}',
  81. f'CRC{crc_size}: {crc_received}')))
  82. crc_calculated = hex(crc(address + payload_length + pid + no_ack + payload, size=crc_size))
  83. if crc_received == crc_calculated:
  84. print('CRC is valid!')
  85. else:
  86. print(f'CRC mismatch! Calculated CRC is f{crc_calculated}.')
  87. print('-------------')