Начальное значение CCITT CRC 16 бит 0xffff

Мне нужно рассчитать значение 16-битной контрольной суммы CCITT для данных, переданных в качестве параметра, вместе с длиной. Если я заполню свой массив TempStr тестовыми данными «123456789», использую полином 0x8408 с длиной, исключающей нулевой символ завершения, я получу строку результата 6E90 (Hex). Вместе с нулевым символом завершения я получаю 907A. Когда я заменяю полином на 0x1201, я получаю результаты 29E2 (Hex) и EFE8 (Hex) с и без символа завершения.

Мои вопросы:
Нужно ли рассчитывать CRC с нулевым символом завершения или без него, чтобы получить правильное значение?
Использовать ли в алгоритме полином 0x1201 или обратный полином 0x8408?
Правильный ли CRC приведенных данных 0x29B1? Мне нужно правильное значение, чтобы определить, работает ли функция правильно.
Правильно ли рассчитан этот конкретный тип CRC?
wData = (без знака int) 0xff & * PDATA ++ ??
Если кто-то может объяснить мне, что не так и как исправить мою проблему, я был бы очень признателен.
Спасибо

Это код, который использует и отображает функцию Calculate_CRC16:

CHAR_t TestStr[] = {"123456789"};
unsigned short CrcTest = calculate_CRC16(TestStr,sizeof(TestStr)-1);
QString CrcDisplay = QString("CrcTest : %1").arg(CrcTest);
ui->txtDebug->setText(CrcDisplay);

Это функция Calculate_CRC16:

UINT16_t MainWindow::calculate_CRC16(CHAR_t* pData, UINT16_t wLength)
{

UCHAR_t i;
UINT16_t wData;
UINT16_t wCrc = 0xffff;

if (wLength == 0)
return (~wCrc);

do
{
for (i=0, wData=(unsigned int)0xff & *pData++; i < 8; i++, wData >>= 1)
{
if ((wCrc & 0x0001) ^ (wData & 0x0001))
wCrc = (wCrc >> 1) ^ CRC_POLY;
else  wCrc >>= 1;
}
} while (--wLength);

wCrc = ~wCrc;
wData = wCrc;
wCrc = (wCrc << 8) | (wData >> 8 & 0xff);

return (wCrc);
}

5

Решение

Результат 0x29b1 для «ложный» CCITT CRC-16 (ссылка на каталог CRC). Который, видимо, тот, который вам нужен. Из каталога:

width=16 poly=0x1021 init=0xffff refin=false refout=false xorout=0x0000 check=0x29b1 name="CRC-16/CCITT-FALSE"

Так что нет битов разворота (refin, refout ложный). CRC инициализируется с 0xffff и не подвергается постобработке.

Чтобы исправить ваш код с наименьшими изменениями:

if (wLength == 0)
return wCrc;

do
{
for (i=0, wData=((unsigned int)0xff & *pData++) << 8; i < 8; i++, wData <<= 1)
{

if ((wCrc & 0x8000) ^ (wData & 0x8000))
wCrc = (wCrc << 1) ^ 0x1021;
else  wCrc <<= 1;
}
} while (--wLength);

return wCrc & 0xffff;

или сделать это более разумно:

while (wLength--) {
wCrc ^= *(unsigned char *)pData++ << 8;
for (i=0; i < 8; i++)
wCrc = wCrc & 0x8000 ? (wCrc << 1) ^ 0x1021 : wCrc << 1;
}
return wCrc & 0xffff;
4

Другие решения

Если вы посмотрите, он рассчитает CRC для разных строк (или шестнадцатеричных последовательностей, для проверки с или без NUL)
http://www.lammertbies.nl/comm/info/crc-calculation.html

В соответствии с этим, вы НЕ должны рассчитывать, включая завершающий ноль, чтобы получить значение 0x29B1 для вашего расчета.

Поскольку вы начинаете с младшего бита, вы должны использовать «не обратный» полином.

Я думаю, что проблема в том, что вы перемещаетесь в неправильном направлении, когда вы перемещаете «wCrc» в своих вычислениях.

Другими словами:

wCrc = (wCrc >> 1) ^ CRC_POLY;

должно быть:

wCrc = (wCrc << 1) ^ CRC_POLY;

и аналогично:

wCrc >>= 1;

должно быть:

wCrc <<= 1;

Однако я не уверен на 100%.

2

Существует ряд различных вариантов алгоритмов CRC.

  • Побитовый расчет по сравнению со справочной таблицей
  • Отраженные байты и неотраженные байты (сначала MSbit или LSbit).
  • Добавление дополненных битов в конце сообщения или нет.

Этот последний момент вызывает путаницу. Возвращаясь к теории CRC, CRC можно рассматривать как длинное деление в GF (2), где результатом является остаток от длинного деления. Чтобы сделать правильный расчет в соответствии с базовой теорией, N нулевые биты должны быть добавлены в конец сообщения, чтобы получить правильный ответ. Есть алгоритмы CRC, которые делают вычисления таким образом.

Однако чаще всего алгоритмы CRC выполняются другим способом, так что сообщение не нуждается в нулевых битах, добавляемых в конец сообщения. Этот расчет часто называют «прямым алгоритмом». Это более удобно в использовании и функционально эквивалентно, Кроме что любое «начальное значение» алгоритма необходимо изменить, чтобы учесть этот вариант алгоритма.

В случае CRC-16 / CCITT это приводит к путанице относительно правильного начального значения: должно ли оно быть 0xFFFF или же 0x1D0F? Можно утверждать, что 0xFFFF является правильным начальным значением для алгоритма, который добавляет расширенные биты к сообщению. Если используется «прямой алгоритм», начальное значение должно быть установлено на 0x1D0F чтобы получить тот же результат.

Таким образом, вы должны знать об этой разнице и использовать ту, которая необходима для взаимодействия с программой / системой, с которой вы взаимодействуете.

Дальнейшее чтение:

0
А ты уже прошел курс программирования? Супер скидка!
Прокачать скилл $$$
×