Некоторые CRC определены для обработки битов от каждого байта от MSB до LSB, а некоторые определены для обработки битов от LSB до MSB (последний обычно является порядком, который описывается как "отраженный")и использует обратный полином).Ваш код вставляет новые биты в конце LSB CRC и сдвигает вправо, что подходит для отраженного 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)
$