Мне было поручено реализовать CRC с использованием Java. Мне не дали спецификации, чтобы следовать, но я следую этому PDF:
https://cdn.standards.iteh.ai/samples/6904/2c02d323a7ae41838de8b8b806cf3725/ISO-2111-1985.pdf
Мне дали два примера строк для сравнения:
Поток байтов (шестнадцатеричный): 220017e11201040c9ebce8003201028149d3d904808d14
Поток байтов с ISO2111 (Hex): 1002220017e11201040c9ebce8003201028149d3d904808d141003939c
Первая строка — это необработанные данные, которые я получил, а вторая строка — это то, как они должны выглядеть после применения ISO2111 (по словам человека, который сделал запрос).
Добавление DLE (1002 в начале, 1003 в конце) было тривиальным, но я не могу воспроизвести контрольную сумму в конце передачи (939c).
Сначала я преобразую строку в массив байтов, а затем передаю ее в функцию ниже.
Код Java, который я использовал для вычисления CRC16:
public static String calculateCRC16(final byte[] bytes) {
int CRC = 0xFFFF; // initial CRC value : 0xFFFF -> max value of 65535
int POLYNOMIAL = 0x1021; // 0x1021 = x^16 + x^12 + x^5 + 1
for (byte b : bytes) {
for (int i = 0; i < 8; i++) {
boolean bit = ((b >> (7 - i) & 1) == 1);
boolean c15 = ((CRC >> 15 & 1) == 1);
CRC <<= 1;
if (c15 ^ bit) {
CRC ^= POLYNOMIAL;
}
}
}
CRC &= 0xffff;
return Integer.toHexString(CRC);
}
Проблема в том, что для данной строки выводится d806, а не 939c. Значение d806 кажется правильным согласно некоторым онлайн-калькуляторам CRC. Я что-то пропустил? Данные, которые они отправили, просто составлены? Я неправильно истолковал раздел 8 в PDF? Вот что он говорит:
8 Последовательность проверки блока (BCS) BCS должен соответствовать следующим правилам: 8.1 Это должна быть 16-битовая последовательность (два октета).
8.2 Последовательность информационных битов, содержащихся в защищаемом блоке данных, может быть представлена полиномом L(x) (GF 2): BCS – это остаток после деления полинома Lfxi IGF2), умноженный на x16, на производящий многочлен p(x) = x16 + x12 + x5 + 1 (GF2). GF2 означает, что эти полиномы имеют свои коэффициенты в двухэлементном поле Галуа.
8.3 БКС передается на линию, начинающуюся с коэффициента старшего члена.
8.4 В приемнике последовательные входящие защищенные данные и BCS при делении на порождающий полином дают нулевой остаток при отсутствии ошибок передачи».
Насколько я вижу, другой информации об этом нигде в сети нет.




В документе есть правила о том, над чем рассчитывается CRC (они называют это BCS), и о том, как избавиться от байтов DLE перед этим. В результате CRC для примера сообщения начинается после ведущего 1002 и поднимается до 03 перед CRC, но DLE (10) перед 03 удаляется.
Таким образом, CRC рассчитывается по:
220017e11201040c9ebce8003201028149d3d904808d1403
Затем прямая CRC с полиномом 0x1021, нулевым начальным значением и нулевым конечным исключающим ИЛИ дает результат 0x939c. Вы можете найти этот конкретный 16-битный CRC, называемый CRC-16/XMODEM. Расчет:
static private int crc16xmodem(byte[] message) {
int crc = 0;
for (byte octet : message) {
crc ^= (int)octet << 8;
for (int k = 0; k < 8; k++)
crc = (crc & 0x8000) != 0 ? (crc << 1) ^ 0x1021 : crc << 1;
}
return crc & 0xffff;
}
Прочтите правила DLE. Случай, который не встречается в вашем примере, это: DLE DLE в сообщении становится DLE, поскольку этот первый DLE является escape-последовательностью, так что второй DLE может быть передан как часть сообщения.