一些 CRC 被定义为处理从每个字节从 MSB 到 LSB 的位,而一些被定义为处理从 LSB 到 MSB 的位(后者通常是被描述为“反射”的顺序并使用反向多项式)。您的代码将新位放入 CRC 的 LSB 端并右移,这适用于反射 CRC,但 CRC-16-DECT 似乎是非反射的之一。
您输入的“10100011”建议使用二进制,但正在处理为 8 字节 ASCII 字符串。
要查看将 10100011 视为二进制并首先从 MSB 工作时会发生什么,这是一个手动计算(因为 8 位输入不需要太多努力):
polynomial coefficients
|
| 10100010 <--- quotient (irrelevant)
v __________
10000010110001001 ) 10100011 <-------- input
^ 10000010110001001
-----------------
= 100001110001001
^ 10000010110001001
-----------------
= 101110101101
^ 10000010110001001
-----------------
remainder (CRC) -----> = 111000000101001
= 0x7029 = 28713
因此,将输入视为二进制并首先使用 MSB 是正确的做法。
这里有一些 C 代码来完成这项工作(因为我不是很喜欢 PHP,最终你还是想要 C 代码):
#include <stdio.h>
#include <stdint.h>
static uint16_t crc16(const uint8_t *data, size_t len)
{
size_t i, j;
uint16_t crc = 0;
for (i = 0; i < len; i++) {
crc ^= (data[i] << 8); /* data at top end, not bottom */
for (j = 0; j < 8; j++) {
if ((crc & 0x8000) == 0x8000) /* top bit, not bottom */
crc = (crc << 1) ^ 0x0589; /* shift left, not right */
else
crc <<= 1; /* shift left, not right */
}
}
return crc;
}
int main(void)
{
const uint8_t in[] = { 0xa3 }; /* = 10100011 in binary */
uint16_t crc = crc16(in, sizeof(in));
printf("%u (0x%x)\n", crc, crc);
return 0;
}
结果:
$ gcc -Wall -o crc16 crc16.c
$ ./crc16
28713 (0x7029)
$