Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to calculate this CRC using Python?

Tags:

python

crc

I need to calculate this CRC using Python for the communication with Aurora (ABB) solar inverter.

This is the document: http://www.drhack.it/images/PDF/AuroraCommunicationProtocol_4_2.pdf in the last page there are the instructions to calculate the CRC, i need to do that in python.

The message that i have is

MESSAGE_GRID_VOLTAGE = bytes.fromhex("023b010000000000")

The results should be:

CRC_L = FF

CRC_H = 2C

Then i need to send the message complete with the CRC like this:

MESSAGE_GRID_VOLTAGE = bytes.fromhex("023b010000000000ff2c")

How can i do that in python? Thanks!

Here is the code that i tried:

message = "023b010000000000"

BccLo= int ("FF",16)
BccHi= int("FF", 16)

New = int(message, 16)

New = New ^ BccLo
Tmp=New << 4
New=Tmp ^ New
Tmp=New >> 5
BccLo=BccHi
BccHi= New ^ Tmp
Tmp=New << 3
BccLo=BccLo ^ Tmp
Tmp=New >> 4
BccLo=BccLo ^ Tmp

CRC_L = ~BccLo
CRC_H = ~BccHi
like image 551
Simone Luconi Avatar asked Apr 14 '26 10:04

Simone Luconi


2 Answers

According to the cited document, the algorithm is actually a standard 16 Bit CCITT CRC. This can be calculated with crcmod.

Here you go:

import crcmod

# this is a standard CCITT CRC even if it does not look like
# (crcmod applies xorOut to initCrc, so initCrc is in reality 0xffff, not 0)
_CRC_FUNC = crcmod.mkCrcFun(0x11021, initCrc=0, xorOut=0xffff)

data = bytearray.fromhex("023b010000000000")
crc = _CRC_FUNC(data)
data.append(crc & 0xff)
data.append(((crc >> 8) & 0xff))

print (data.hex())

Output: 023b010000000000ff2c

like image 172
Adrian W Avatar answered Apr 17 '26 00:04

Adrian W


You need to apply that algorithm to each byte of your message. A slight complication is that the algorithm given in the Aurora PDF file assumes the calculation is being performed with 8 bit unsigned arithmetic. To handle that in Python we can use a bitmask of 0xff. Here's a slightly optimized version of that code.

def crc_16(msg):
    lo = hi = 0xff
    mask = 0xff
    for new in msg:
        new ^= lo
        new ^= (new << 4) & mask
        tmp = new >> 5
        lo = hi
        hi = new ^ tmp
        lo ^= (new << 3) & mask
        lo ^= new >> 4
    lo ^= mask
    hi ^= mask
    return hi << 8 | lo

# Test

msg = bytes.fromhex("023b010000000000")
out = crc_16(msg)
hi, lo = out >> 8, out & 0xff
print('{:04x} = {:02x} {:02x}'.format(out, hi, lo))

output

2cff = 2c ff

The above code works, but there are simpler ways to calculate CRCs. And we can use a table to speed up the process, if you need to calculate a lot of CRCs.

As the Wikipedia Cyclic redundancy check article mentions, CRC algorithms are usually specified in terms of a polynomial encoded as a hexadecimal number. Here's a function that does that using the reversed polynomial representation.

def crc_16_CCITT(msg):
    poly = 0x8408
    crc = 0xffff
    for byte in msg:
        for _ in range(8):
            if (byte ^ crc) & 1:
                crc = (crc >> 1) ^ poly
            else:
                crc >>= 1
            byte >>= 1
    return crc ^ 0xffff

To speed things up, we can compute a table.

def make_crc_table():
    poly = 0x8408
    table = []
    for byte in range(256):
        crc = 0
        for bit in range(8):
            if (byte ^ crc) & 1:
                crc = (crc >> 1) ^ poly
            else:
                crc >>= 1
            byte >>= 1
        table.append(crc)
    return table

table = make_crc_table()

def crc_16_fast(msg):
    crc = 0xffff
    for byte in msg:
        crc = table[(byte ^ crc) & 0xff] ^ (crc >> 8)
    return crc ^ 0xffff

# Test

msg = bytes.fromhex("023b010000000000")
out = crc_16_fast(msg)
hi, lo = out >> 8, out & 0xff
print('{:04x} = {:02x} {:02x}'.format(out, hi, lo))

If you like, you can print the table & paste it into your script, so that you don't have to compute the table every time you run the script.

like image 22
PM 2Ring Avatar answered Apr 16 '26 22:04

PM 2Ring



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!