Source code for roboclaw.data_manip

"""A module for manipulating dat including generating CRC values and datatype constraints.
For more information on how CRC algorithms work: https://www.zlib.net/crc_v3.txt"""

[docs]def make_poly(bit_length, msb=False): """Make `int` "degree polynomial" in which each bit represents a degree who's coefficient is 1 :param int bit_length: The amount of bits to play with :param bool msb: `True` make only the MSBit 1 and the rest a 0. `False` makes all bits 1. """ if msb: return 1 << ((8 * int(bit_length / 8)) - 1) result = 0 for x in range(int(bit_length / 8)): result += 0xff << int(x * 8) return result
[docs]def crc16(data, deg_poly=0x1021, init_value=0): """Calculates a checksum of 16-bit length""" return crc_bits(data, 16, deg_poly, init_value)
[docs]def crc32(data, deg_poly=0x5b06, init_value=0x555555): """Calculates a checksum of 32-bit length. Default ``deg_poly`` and ``init_value`` values are BLE compliant.""" return crc_bits(data, 32, deg_poly, init_value)
[docs]def crc_bits(data, bit_length, deg_poly, init_value): """Calculates a checksum of various sized buffers :param bytearray data: This `bytearray` of data to be uncorrupted. :param int bit_length: The length of bits that will represent the checksum. :param int deg_poly: A preset "degree polynomial" in which each bit represents a degree who's coefficient is 1. :param int init_value: This will be the value that the checksum will use while shifting in the buffer data. """ crc = init_value mask = make_poly(bit_length, msb=True) # 0x8000 for _ in range(8): # shift out initial value 1 bit @ a time. if crc & mask: # if divisible # 0x1021 is a standard polynomial used for crc16 algorithms # behaves like unsigned subtraction crc = (crc << 1) ^ deg_poly else: crc = crc << 1 # bring down next bit for binary for byte in data: # for each byte crc ^= (byte << 8) for _ in range(8): # for each bit if crc & mask: # if divisible # 0x1021 is a standard polynomial used for crc16 algorithms # behaves like unsigned subtraction crc = (crc << 1) ^ deg_poly else: crc = crc << 1 # bring down next bit for binary long-division return crc & make_poly(bit_length) # return only the remainder
[docs]def validate16(data, deg_poly=0x1021, init_value=0): """Validates a received data by comparing the calculated 16-bit checksum with the checksum included at the end of the data""" return validate(data, 16, deg_poly, init_value)
[docs]def validate(data, bit_length, deg_poly, init_value): """Validates a received checksum of various sized buffers :param bytearray data: This `bytearray` of data to be uncorrupted. :param int bit_length: The length of bits that will represent the checksum. :param int deg_poly: A preset "degree polynomial" (in which each bit represents a degree who's coefficient is 1) as a quotient. :param int init_value: This will be the value that the checksum will use while shifting in the buffer data. :Returns: `True` if data was uncorrupted. `False` if something went wrong. (either checksum didn't match or payload is altered). """ cal_d = crc_bits(data[:-(bit_length / 8)], bit_length, deg_poly, init_value) rcv_d = 0 for byte in data[-(bit_length / 8):]: rcv_d = (rcv_d << 8) | byte print(cal_d == rcv_d) return cal_d == rcv_d