Ответ 1
Есть несколько деталей, которые вам нужно "совместить" для конкретной реализации CRC. Даже при использовании одного и того же полинома могут быть разные результаты из-за незначительных различий в том, как обрабатываются биты данных, используя определенное начальное значение для CRC (иногда это ноль, иногда 0xffff) и/или инвертирование бит CRC. Например, иногда одна реализация будет работать из младших бит байтов данных, тогда как иногда они будут работать с битами верхнего порядка вниз (как это делается в настоящее время).
Кроме того, вам нужно "вытолкнуть" последние бит CRC после запуска всех бит данных.
Имейте в виду, что алгоритмы CRC были разработаны для аппаратного обеспечения, поэтому некоторые из способов обработки битового заказа могут не иметь особого смысла с точки зрения программного обеспечения.
Если вы хотите сопоставить CRC16 с полиномом 0x8005, как показано на странице калькулятора CRM lammertbies.nl, вам необходимо внести следующие изменения в функцию CRC:
- a) запускать биты данных через цикл CRC, начиная с младшего значащего бита, а не из самого значащего бита
- b) вытащите последние 16 бит CRC из регистра CRC после того, как вы закончили с входными данными.
- c) отменить бит CRC (я предполагаю, что этот бит переносится с аппаратных реализаций)
Итак, ваша функция может выглядеть так:
#define CRC16 0x8005
uint16_t gen_crc16(const uint8_t *data, uint16_t size)
{
uint16_t out = 0;
int bits_read = 0, bit_flag;
/* Sanity check: */
if(data == NULL)
return 0;
while(size > 0)
{
bit_flag = out >> 15;
/* Get next bit: */
out <<= 1;
out |= (*data >> bits_read) & 1; // item a) work from the least significant bits
/* Increment bit counter: */
bits_read++;
if(bits_read > 7)
{
bits_read = 0;
data++;
size--;
}
/* Cycle check: */
if(bit_flag)
out ^= CRC16;
}
// item b) "push out" the last 16 bits
int i;
for (i = 0; i < 16; ++i) {
bit_flag = out >> 15;
out <<= 1;
if(bit_flag)
out ^= CRC16;
}
// item c) reverse the bits
uint16_t crc = 0;
i = 0x8000;
int j = 0x0001;
for (; i != 0; i >>=1, j <<= 1) {
if (i & out) crc |= j;
}
return crc;
}
Эта функция возвращает 0xbb3d
для меня, когда я передаю "123456789"
.