Calculating CRC16 in Python
Question:
I’m trying to evaluate appropriate checksum based on CRC-16 algorithm using crcmod Python module and 2.7 version of Python interpreter. The checksum parameters are:
- CRC order: 16
- CRC polynomial: 0x8005
- Inital value: 0xFFFF
- Final value: 0x0000
- Direct: True
Code:
crc16 = crcmod.mkCrcFun(0x18005, rev=False, initCrc=0xFFFF, xorOut=0x0000)
print hex(crc16(str(int(0x5A0001))))
and for the input 0x5A0001
it prints 0x7E16
while I should get something like 0xCE0A
.
I checked on http://www.lokker.net/Java/crc/CRCcalculation2.htm and the computed value is 0xACE
which is correct (with respect to the order).
Answers:
crcmod
is working fine. You are not giving it the three bytes you think you are giving it. Your str(int(0x5A0001))
is providing seven bytes, which are the ASCII characters 5898241
— the conversion of 0x5a0001
to decimal.
To feed it the bytes 0x5a 0x00 0x01
, you would instead (as one approach):
print hex(crc16("5a0001".decode("hex")))
That prints 0xace
.
Here is a python implementation of CRC-16/CCITT-FALSE
def crc16(data : bytearray, offset , length):
if data is None or offset < 0 or offset > len(data)- 1 and offset+length > len(data):
return 0
crc = 0xFFFF
for i in range(0, length):
crc ^= data[offset + i] << 8
for j in range(0,8):
if (crc & 0x8000) > 0:
crc =(crc << 1) ^ 0x1021
else:
crc = crc << 1
return crc & 0xFFFF
- data : bytearray of the data you want to calculate CRC for
- offset : from which offset you want to start calculating CRC
- length : to which offset you want to calculate CRC
def crc16(data : bytearray, offset, length):
if data is None or offset < 0 or offset > len(data) - 1 and offset + length > len(data):
return 0
print("uzunluk=", len(data))
print(data)
crc = 0xFFFF
for i in range(length):
crc ^= data[offset + i]
for j in range(8):
print(crc)
if ((crc & 0x1) == 1):
print("bb1=", crc)
crc = int((crc / 2)) ^ 40961
print("bb2=", crc)
else:
crc = int(crc / 2)
return crc & 0xFFFF
A working single function example for CRC-16-ANSI, CRC-16-IBM based on pycrc code.
It is easy to modify but input or output reflection capability is not included:
def crc16(data: bytes):
xor_in = 0x0000 # initial value
xor_out = 0x0000 # final XOR value
poly = 0x8005 # generator polinom (normal form)
reg = xor_in
for octet in data:
# reflect in
for i in range(8):
topbit = reg & 0x8000
if octet & (0x80 >> i):
topbit ^= 0x8000
reg <<= 1
if topbit:
reg ^= poly
reg &= 0xFFFF
# reflect out
return reg ^ xor_out
Here is a code you can use to generate a crc 16 for a data packet to send
def crc16_generator_hex(data: list[int]) -> str:
"""CRC-16-MODBUS Hex Algorithm
Parameters
----------
data : list[int]
Data packets received.
Returns
-------
str
CRC as hex string
Raises
----------
ValueError
If data packet in each index contains a byte > 256
"""
data = bytearray(data)
crc = 0xFFFF
# Calculate CRC-16 checksum for data packet
for b in data:
crc ^= b
for _ in range(0, 8):
bcarry = crc & 0x0001
crc >>= 1
if bcarry:
crc ^= 0xa001
return hex(crc)
I have a repo with detailed examples you can use as a reference.
https://github.com/jonahbardos/Python-CRC16
I’m trying to evaluate appropriate checksum based on CRC-16 algorithm using crcmod Python module and 2.7 version of Python interpreter. The checksum parameters are:
- CRC order: 16
- CRC polynomial: 0x8005
- Inital value: 0xFFFF
- Final value: 0x0000
- Direct: True
Code:
crc16 = crcmod.mkCrcFun(0x18005, rev=False, initCrc=0xFFFF, xorOut=0x0000)
print hex(crc16(str(int(0x5A0001))))
and for the input 0x5A0001
it prints 0x7E16
while I should get something like 0xCE0A
.
I checked on http://www.lokker.net/Java/crc/CRCcalculation2.htm and the computed value is 0xACE
which is correct (with respect to the order).
crcmod
is working fine. You are not giving it the three bytes you think you are giving it. Your str(int(0x5A0001))
is providing seven bytes, which are the ASCII characters 5898241
— the conversion of 0x5a0001
to decimal.
To feed it the bytes 0x5a 0x00 0x01
, you would instead (as one approach):
print hex(crc16("5a0001".decode("hex")))
That prints 0xace
.
Here is a python implementation of CRC-16/CCITT-FALSE
def crc16(data : bytearray, offset , length):
if data is None or offset < 0 or offset > len(data)- 1 and offset+length > len(data):
return 0
crc = 0xFFFF
for i in range(0, length):
crc ^= data[offset + i] << 8
for j in range(0,8):
if (crc & 0x8000) > 0:
crc =(crc << 1) ^ 0x1021
else:
crc = crc << 1
return crc & 0xFFFF
- data : bytearray of the data you want to calculate CRC for
- offset : from which offset you want to start calculating CRC
- length : to which offset you want to calculate CRC
def crc16(data : bytearray, offset, length):
if data is None or offset < 0 or offset > len(data) - 1 and offset + length > len(data):
return 0
print("uzunluk=", len(data))
print(data)
crc = 0xFFFF
for i in range(length):
crc ^= data[offset + i]
for j in range(8):
print(crc)
if ((crc & 0x1) == 1):
print("bb1=", crc)
crc = int((crc / 2)) ^ 40961
print("bb2=", crc)
else:
crc = int(crc / 2)
return crc & 0xFFFF
A working single function example for CRC-16-ANSI, CRC-16-IBM based on pycrc code.
It is easy to modify but input or output reflection capability is not included:
def crc16(data: bytes):
xor_in = 0x0000 # initial value
xor_out = 0x0000 # final XOR value
poly = 0x8005 # generator polinom (normal form)
reg = xor_in
for octet in data:
# reflect in
for i in range(8):
topbit = reg & 0x8000
if octet & (0x80 >> i):
topbit ^= 0x8000
reg <<= 1
if topbit:
reg ^= poly
reg &= 0xFFFF
# reflect out
return reg ^ xor_out
Here is a code you can use to generate a crc 16 for a data packet to send
def crc16_generator_hex(data: list[int]) -> str:
"""CRC-16-MODBUS Hex Algorithm
Parameters
----------
data : list[int]
Data packets received.
Returns
-------
str
CRC as hex string
Raises
----------
ValueError
If data packet in each index contains a byte > 256
"""
data = bytearray(data)
crc = 0xFFFF
# Calculate CRC-16 checksum for data packet
for b in data:
crc ^= b
for _ in range(0, 8):
bcarry = crc & 0x0001
crc >>= 1
if bcarry:
crc ^= 0xa001
return hex(crc)
I have a repo with detailed examples you can use as a reference.
https://github.com/jonahbardos/Python-CRC16