Реализация CRC в Java для шестнадцатеричной строки

Мне было поручено реализовать 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 при делении на порождающий полином дают нулевой остаток при отсутствии ошибок передачи».

Насколько я вижу, другой информации об этом нигде в сети нет.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
72
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В документе есть правила о том, над чем рассчитывается 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 может быть передан как часть сообщения.

Другие вопросы по теме