有些CRC被定义为处理每个字节中从MSB到LSB的位,有些被定义为处理从LSB到MSB的位(后者通常是被描述为“反映”的顺序并使用相反的多项式)。您的代码将新位放入 CRC 的 LSB 端并右移,这适用于反射 CRC,但 CRC-16-DECT 似乎是非反射 CRC 之一。
您输入的“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;
}
Result:
$ gcc -Wall -o crc16 crc16.c
$ ./crc16
28713 (0x7029)
$