Search code examples
pythoncrc

Implementing a special CRC algorithm in Python using crcmod


I'm trying to implement the "VÖV 04.05.1" CRC algorithm in python. This is used in data telegrams for public transport communication in Germany. The standard that describes the algorithm is behind a paywall and copyright protected, so I can't publish the original document here, but this is a summary:

Basically, it uses CRC-16 with the following generator polynomial: G(x) = x^16 + x^14 + x^13 + x^11 + x^10 + x^9 + x^8 + x^6 + x^5 + x^1 + 1

The resulting bits then have to be inverted.

Currently I'm using the crcmod package for python to generate the CRC. The polynom is translated to 0x16f63 in HEX (at least I think so). This is my code:

import crcmod

#message from which the checksum is to be formed
msg = "00000000000000000000000010000000"

#crcmod parameters
crc16 = crcmod.mkCrcFun(0x16f63, rev=True, initCrc=0x0000, xorOut=0x0000)

#interpret string as binary, convert to bytes, calculate CRC
crc_result = crc16(int(msg, 2).to_bytes((len(msg) + 7) // 8, 'big'))

#print result in BIN and HEX
print(bin(crc_result))
print(hex(crc_result))

The standard contains two examples for CRC calculation:

  1. 00000000000000000000000000000001 must result in a CRC of 0x4c7d
  2. 00000000000000000000000010000000 must result in a CRC of 0x909c

Despite fiddling around with the parameters, I don't get the correct results. Even with inverted bits. I appreciate any help!


Solution

  • Don´t look to deep in the spec, it is confusing because of weird bit orders (info bytes are mirrored, but CRC bytes are not!). Simply concat the information bits in the received order to "msg" and run it aginst:

    import crcmod
    msg = "00000000000000000000000010000000"
    
    #crcmod parameters
    crc16 = crcmod.mkCrcFun(0x16f63, rev=False, initCrc=0xFFFF, xorOut=0xFFFF)
    
    #interpret string as binary, convert to bytes, calculate CRC
    crc_result = crc16(int(msg, 2).to_bytes((len(msg) + 7) // 8, 'big'))
    
    #print result in BIN and HEX
    print(bin(crc_result))
    print(hex(crc_result))
    

    Result for msg = "00000000000000000000000000000001":

    0b1001000010011100
    0x909c
    

    Result for msg = "00000000000000000000000010000000":

    0b100110001111101
    0x4c7d
    

    More test data for verification can be found here: https://github.com/tlm-solutions/telegram-decoder/blob/master/data/valid_r09_16_telegrams.json