我需要使用Python计算此CRC,以便与Aurora(ABB)太阳能逆变器进行通信。
这是文档:http://www.drhack.it/images/PDF/AuroraCommunicationProtocol_4_2.pdf 在最后一页中有计算CRC的说明,我需要在python中进行。
我收到的消息是
MESSAGE_GRID_VOLTAGE = bytes.fromhex("023b010000000000")
结果应为:
CRC_L = FF
CRC_H = 2C
然后我需要像这样发送完整的带有CRC的消息:
MESSAGE_GRID_VOLTAGE = bytes.fromhex("023b010000000000ff2c")
如何在python中做到这一点?谢谢!
这是我尝试过的代码:
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
答案 0 :(得分:2)
根据引用的文档,该算法实际上是标准的16位CCITT CRC。可以使用Python的标准crcmod
来计算。
您在这里:
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())
输出: 023b010000000000ff2c
答案 1 :(得分:1)
您需要将该算法应用于邮件的每个字节。稍微复杂一点是,Aurora PDF文件中给出的算法假定计算是使用8位无符号算术执行的。要在Python中处理该问题,我们可以使用0xff的位掩码。这是该代码的稍微优化的版本。
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))
输出
2cff = 2c ff
上面的代码有效,但是有更简单的方法来计算CRC。如果您需要计算很多CRC,我们可以使用表格来加快处理过程。
正如Wikipedia Cyclic redundancy check文章所提到的那样,CRC算法通常根据编码为十六进制数的多项式来指定。这是一个使用逆多项式表示的函数。
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
为了加快速度,我们可以计算一张表。
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))
如果愿意,可以打印表并将其粘贴到脚本中,这样就不必每次运行脚本时都计算表。