将 CRC16 CCITT 代码从 C 转换为 Python

Convert CRC16 CCITT code from C to Python

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

该算法可作为 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 技能又一次不允许我正确地 'populate' 共享库。当我放弃时,看看我失败的尝试(这可能甚至不是正确的 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)

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

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

不得已Whosebug

因此,如果能帮助我将现有的 C 代码转换为纯代码,我将不胜感激 Python。

谢谢。

安德烈亚斯

提供的 Python 代码中实现的 CRC 不是 CCITT CRC-16。有趣的是,它被称为 false CCITT CRC-16 in this catalog. The CRC implemented in the provided C code is in fact the 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