【问题标题】:Convert CRC16 CCITT code from C to Python将 CRC16 CCITT 代码从 C 转换为 Python
【发布时间】:2021-07-10 21:26:37
【问题描述】:

我想做一个基于 CRC16-CCITT 的特定校验和计算的 Python 实现(实际上是 MicroPython)。 它将在微控制器上用于通过串行连接检查数据完整性。

该算法可作为 C 实现。

校验和是 16 位,输入 CCITT。校验和从消息的第一个字节开始。 C语言计算CRC16 CCITT的示例代码:

#include <stdint.h>

uint16_t crc_ccitt_update( uint16_t crc, uint8_t data ) {

  uint16_t ret_val;

  data ^= ( uint8_t )(crc) & (uint8_t )(0xFF);
  data ^= data << 4;

  ret_val = ((((uint16_t)data << 8) | ((crc & 0xFF00) >> 8))
            ^ (uint8_t)(data >> 4)
            ^ ((uint16_t)data << 3));

  return ret_val;

}

uint16_t get_crc16z(uint8_t *p, uint16_t len) {

  uint16_t crc16_data=0;

  while(len--) {
      crc16_data = crc_ccitt_update(crc16_data, p[0]); p++;
  }

  return(crc16_data);

}

要检查的数据包的示例是:

0x3D 0x01 0x08 0x06 0x3A 0x00 0x98 0x81

最后两个字节携带校验和作为 LSB 和 MSB,因此预期的校验和是(字节反转):

0x8198

我的 C 语言编码技能与将其转换为 Python 代码相去甚远。所以我首先尝试在网上找到现有的功能。存在很多功能,但似乎总是有实现细节。所以我未能生成有效的 CRC 值。

在线位置示例: Online CRC calculator, Sunshine's homepage

我尝试过的示例函数(其中之一):

def crc16(data : bytearray, offset , length):
    if data is None or offset < 0 or offset > len(data)- 1 and offset+length > len(data):
        return 0
    crc = 0xFFFF
    for i in range(0, length):
        crc ^= data[offset + i] << 8
        for j in range(0,8):
            if (crc & 0x8000) > 0:
                crc =(crc << 1) ^ 0x1021
            else:
                crc = crc << 1
    return crc & 0xFFFF

packet = b'3D0108063A009881'

crc = crc16(packet, 0, int(len(packet)))

print('CRC:', crc)

checksum = int(b'8198', 16)
print('Check:', checksum)

我什至不确定我是否正确使用它们。很可能不会。

第二步是使用现有的 C 代码尝试 Ctypes 实现。我使用以下命令在 Mac 上成功生成了一个共享库:

gcc -shared -Wl,-install_name,CRC16_CCITT.so -o CRC16_CCITT.so -fPIC crc16_ccitt.c

但我的 C 技能再次不允许我正确“填充”共享库。当我放弃时,看看我失败的尝试(可能甚至不是正确的 Python 代码):

from ctypes import *

#load the shared object file
crc16_ccitt = CDLL('./CRC16_CCITT.so')

data = b'3D0108063A009881'

pointer = byref(data, 0)

crc = crc16_ccitt.get_crc16z(pointer, len(data))

print('CRC16-CCITT:', crc)

第一个检查是编译、链接和运行现有的 C 代码,以查看它是否产生预期的结果。提供的代码已经被我修改过,因为在原始文档中有一些明显的拼写错误(函数调用不匹配)。但我不知道如何在 C 中运行它。需要添加一些主函数,并且需要使用正确的数据类型放置参数。

我尝试的最后一件事是阅读 CRC 算法的理论。这足以让我的头爆炸。

最后的手段stackoverflow

因此,如果能在将现有 C 代码转换为纯 Python 方面提供任何帮助,我将不胜感激。

谢谢。

安德烈亚斯

【问题讨论】:

    标签: python c micropython crc16


    【解决方案1】:

    在提供的 Python 代码中实现的 CRC 不是 CCITT CRC-16。有趣的是,它被称为false CCITT CRC-16 in this catalog。提供的 C 代码中实现的 CRC 实际上是CCITT CRC-16

    Python 代码很容易修改以反映正确的定义:

    def crc16(data : bytearray, offset , length):
        if data is None or offset < 0 or offset > len(data)- 1 and offset+length > len(data):
            return 0
        crc = 0
        for i in range(0, length):
            crc ^= data[offset + i]
            for j in range(0,8):
                if (crc & 1) > 0:
                    crc = (crc >> 1) ^ 0x8408
                else:
                    crc = crc >> 1
        return crc
    

    【讨论】:

    • 感谢您的快速答复。我现在的问题是,这是否代表我帖子开头给出的 C 代码。当我将 (data = b'3D0108063A009881', 0, 8) 作为输入时,我得到 crc=14820 和校验和 = 33176(最后两个字节的数据交换 b'8198')。我是否以错误的方式使用该功能?
    • 你给它错误的数据。要给它0x3D 0x01 0x08 0x06 0x3A 0x00,您的测试字符串需要看起来像:b'\x3D\x01\x08\x06\x3A\x00'
    • 当使用 data = b'\x3D\x01\x08\x06\x3A\x00\x98\x81' 和 print(crc16(data, 0, 8)) 我得到 crc=0。我似乎没有和 crc 交朋友...
    • 仔细看我的评论。我最后没有包括 CRC。
    • 该死的。我一直在做错事。感谢您指出这一点。我总是检查包括校验和在内的 crc。相信我,我仔细阅读了您的评论,但我太专注于将整个包裹放入支票中。当我检查其他可用代码时,这肯定也是一个问题。非常感谢。感谢您分享您的时间和知识,请耐心等待我。
    猜你喜欢
    • 2012-10-23
    • 2021-08-12
    • 2020-10-27
    • 1970-01-01
    • 1970-01-01
    • 2020-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多