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
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With