【问题标题】:How to calculate this CRC using Python?如何使用 Python 计算这个 CRC?
【发布时间】:2018-11-18 07:05:03
【问题描述】:

我需要使用 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

【问题讨论】:

  • 到目前为止你尝试了什么?
  • 我尝试使用 ^ 运算符,但它不支持字节,也许我应该尝试将字节转换为数字然后将其恢复为字节,我害怕搞砸一些东西从这些到多的转换。
  • 我在 c# 中找到了这段代码,如果我尝试将其转换为 python,我仍然遇到同样的问题:dreamincode.net/forums/topic/193903-crc-calculation-problem
  • 我在 c# 中尝试过,但它不起作用,crc 不正确,即使我尝试使用用户编写的示例消息。
  • 向我们展示一些 Python 代码!在这里,希望您向我们展示您为解决问题所做的努力。

标签: python crc


【解决方案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))

如果您愿意,可以打印表格并将其粘贴到脚本中,这样您就不必每次运行脚本时都计算表格。

【讨论】:

  • 谢谢,感谢您为解释该过程所做的工作,但用户“Adrian W”的回答很容易实现
【解决方案2】:

根据引用的文档,该算法实际上是一个标准的 16 Bit CCITT CRC。这可以用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

【讨论】:

  • crcmod 不是标准的 Python 模块,但我想从 PyPI 安装它很容易。
  • 你是对的,crcmod 不是标准发行版的一部分。您可以使用pip install crcmod 安装它。另见pypi.org/project/crcmod
  • 我建议更新答案以反映 crcmod 不是标准的。
猜你喜欢
  • 1970-01-01
  • 2020-03-24
  • 2017-08-02
  • 1970-01-01
  • 1970-01-01
  • 2019-09-27
  • 2021-03-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多