Skip to content

Instantly share code, notes, and snippets.

@Semnodime
Last active July 28, 2021 14:27
Show Gist options
  • Save Semnodime/8c843623d2bfa46af1da6cee56df8df9 to your computer and use it in GitHub Desktop.
Save Semnodime/8c843623d2bfa46af1da6cee56df8df9 to your computer and use it in GitHub Desktop.
CRC Calculation for the Nordic nRF24L01
"""Small snippet that demonstrates how to calculate the crc for packets transmitted via the Nordic NRF24L01."""
def bin2hex(x):
def bin2hex_helper(r):
while r:
yield r[0:2].upper()
r = r[2:]
hex_data = hex(int(x, 2))[2:]
return list(bin2hex_helper(hex_data))
def split_packet(packet, parts):
"""Split a string of 1s and 0s into multiple substrings as specified by parts.
Example: "111000011000", (3, 4, 2) -> ["111", "0000", "11", "000"]
:param packet: String of 1s and 0s
:param parts: Tuple of length of substrings
:return: list of substrings
"""
out = []
packet = packet.replace(' ', '')
for part_length in parts:
out.append(packet[0:part_length])
packet = packet[part_length:]
out.append(packet)
return out
def parse_packet(packet, address_length):
"""Split a packet into its fields and return them as tuple."""
preamble, address, payload_length, pid, no_ack, rest = split_packet(packet=packet,
parts=(8, 8 * address_length, 6, 2, 1))
payload, crc = split_packet(packet=rest, parts=(int(payload_length, 2) * 8,))
assert preamble in ('10101010', '01010101')
assert len(crc) in (8, 16)
return preamble, address, payload_length, pid, no_ack, payload, crc
def crc(bits, init=0xFF, polynomial=0x107, mode=8):
"""Calculate the crc value for the polynomial initialized with 0xFF)
:param mode: 8 or 16 bit crc
:param init: Initial value of the crc registers
:param polynomial: standard is 0x107 = 0b100000111 = x^8+x^2+x^1+1 Note: The code does the same for 0x07
:param bits: String of 1s and 0s
:return:
"""
crc = init
max_crc_value = (1 << mode) - 1 # e.g. 0xFF for mode 8bit-crc
for bit in bits:
bit = int(bit, 2)
crc <<= 1
if (crc >> mode) ^ bit: # top most lfsr bit xor current data bit
crc ^= polynomial
crc &= max_crc_value # trim the crc to reject carry over bits
return crc
if __name__ == '__main__':
"""Split test packets into their fields and validate the crc."""
packets = \
(
'10101010 11101110 00000011 00001000 00001011 01000111 000100 00 0 10101010 10101010 10101010 10101010 10010010',
'10101010 11101110 00000011 00001000 00001011 01000111 000100 01 0 10101010 10101010 10101010 10101010 01010110',
'10101010 11101110 00000011 00001000 00001011 01000111 000100 10 0 10101010 10101010 10101010 10101010 00011101',
'10101010 11101110 00000011 00001000 00001011 01000111 000100 11 0 10101010 10101010 10101010 10101010 11011001',
)
for packet in packets:
preamble, address, payload_length, pid, no_ack, payload, crc_received = \
parse_packet(packet=packet, address_length=5)
crc_received = hex(int(crc_received, 2)) # convert into hex format
print(packet)
print('\n'.join((
f'preamble: {preamble}',
f'address: {bin2hex(address)}',
f'payload length: {int(payload_length, 2)}',
f'pid: {int(pid, 2)}',
f'no_ack: {int(no_ack, 2) == 1}',
f'payload: {bin2hex(payload)}',
f'crc: {crc_received}')))
crc_calculated = hex(crc(address + payload_length + pid + no_ack + payload, mode=8))
if crc_received == crc_calculated:
print('CRC is valid!')
else:
print(f'CRC mismatch! Calculated CRC is f{crc_calculated}.')
print('---------')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment