找出正确的 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;
}
我正在使用来自 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;
}