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).

Asked By: Qrlet

||

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.

Answered By: Mark Adler

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
Answered By: Amin Saidani
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
Answered By: user11436151

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

Answered By: Sz'

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

Answered By: jonahbardos
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.