找出正确的 CRC 多项式

Finding out the correct CRC polynomial

我正在使用来自 Basecam electronics 的 simpleBGC 万向节控制器。控制器有一个用于通信的串口API,需要为发送到控制器的命令计算crc16校验和(https://www.basecamelectronics.com/file/SimpleBGC_2_6_Serial_Protocol_Specification.pdf)(第3页)

我想发送重置命令到控制器,格式如下:

Header:{起始字符:'$',命令 ID:'114',负载大小:'3',header 校验和:'117'}

有效负载:{3,0,0}(3 个字节对应重置选项和重置时间)

crc16 校验和:? (使用为所有字节计算的多项式 0x8005 除了开始字符

我的命令的十六进制表示是:0x24720375030000,我需要找到 0x720375030000 的 crc16 校验和。我使用了不同的 crc 计算器,但控制器没有响应命令,我认为 crc 校验和不正确。 为了找到正确的 crc16 校验和,我发送了 crc16 校验和的所有可能组合,并发现控制器在校验和为“7b25”时做出响应。 所以十六进制的正确命令是:“24 720375030000 7b25”。 但是这个校验和 7b25 并不对应多项式 0x8005。 如何找到正确的多项式或crc16计算函数?

您是否尝试了所链接文档附录中的代码?它工作正常,并为示例数据的 CRC 生成 0x257b。然后以 little-endian 顺序写入流中,给出您期望的 7b 25

这里有一个比附录中的更简单、更快的 C 实现:

#include <stddef.h>

// Return a with the low 16 bits reversed and any bits above that zeroed.
static unsigned rev16(unsigned a) {
    a = (a & 0xff00) >> 8 | (a & 0x00ff) << 8;
    a = (a & 0xf0f0) >> 4 | (a & 0x0f0f) << 4;
    a = (a & 0xcccc) >> 2 | (a & 0x3333) << 2;
    a = (a & 0xaaaa) >> 1 | (a & 0x5555) << 1;
    return a;
}

// Implement the CRC specified in the BASECAM SimpleBGC32 2.6x serial protocol
// specification. Return crc updated with the length bytes at message. If
// message is NULL, then return the initial CRC value. This CRC is like
// CRC-16/ARC, but with the bits reversed.
//
// This is a simple bit-wise implementation. Byte-wise and word-wise algorithms
// using tables exist for higher speed if needed. Also this implementation
// chooses to reverse the CRC bits as opposed to the data bits, as done in the
// specficiation appendix. The CRC only needs to be reversed once at the start
// and once at the end, whereas the alternative is reversing every data byte of
// the message. Reversing the CRC twice is faster for messages with length
// greater than two bytes.
unsigned crc16_simplebgc(unsigned crc, void const *message, size_t length) {
    if (message == NULL)
        return 0;
    unsigned char const *data = message;
    crc = rev16(crc);
    for (size_t i = 0; i < length; i++) {
        crc ^= data[i];
        for (int k = 0; k < 8; k++)
            crc = crc & 1 ? (crc >> 1) ^ 0xa001 : crc >> 1;
    }
    return rev16(crc);
}

#include <stdio.h>

// Example usage of crc_simplebgc(). A CRC can be computed all at once, or with
// portions of the data at a time.
int main(void) {
    unsigned crc = crc16_simplebgc(0, NULL, 0);         // set initial CRC
    crc = crc16_simplebgc(crc, "\x72\x03\x75", 3);      // first three bytes
    crc = crc16_simplebgc(crc, "\x03\x00\x00", 3);      // remaining bytes
    printf("%04x\n", crc);                              // prints 257b
    return 0;
}