Код CRC8 не работает должным образом

Мне нужно отправить строку, за которой следует ее полином CRC8, 0x31 (= X^8 + X^5 + X^4 + 1), я успешно закодировал это после некоторых проблем, но, похоже, это не так. работать правильно, когда я проверяю результаты. Я использовал некоторые онлайн-калькуляторы CRC, поэтому проверьте, в порядке ли мои результаты, но я не получаю одинаковых результатов, независимо от того, что я пытаюсь сделать.

На самом деле разные калькуляторы CRC дают разные результаты, что меня беспокоит... Вот мои испытания онлайн-калькуляторов CRC, всегда использующие: CRC8, полином 0x31, данные = TEMPS; (начало моей строки)

На http://www.sunshine2k.de/coding/javascript/crc/crc_js.html :

На https://www.lddgo.net/en/encrypt/crc:

На http://zorc.breitbandkatze.de/crc.html:

Не кажется нормальным получать разные результаты при одинаковых входных параметрах, это меня сильно смущает. Я что-то упустил?

Что бы я ни пытался, я не получаю ни одного из этих результатов с моим собственным кодом. Вот мой код расчета CRC с использованием библиотеки CRC RobTillaart (https://github.com/RobTillaart/CRC):

   String crcData = "TEMPS;";
  int crcDataLength = crcData.length();
  char arrayForCrc[crcDataLength+1];
  crcData.toCharArray(arrayForCrc, crcDataLength+1);
  
  crcTrame = CRC8(0x31,0,0,false,false);
  crcTrame.add((uint8_t *)arrayForCrc, crcDataLength+1);
  String stringCrcNoHex = String(crcTrame.getCRC());
  String stringCrc = String(crcTrame.getCRC(), HEX);

Шестнадцатеричный результат этого примера кода – 0xBA (186 десятичных знаков). Я проверил все входные параметры с помощью get и print, все они верны:

arrayForCrc = "TEMPS;" полином = 0x31 Начальное исключающее ИЛИ = 0 Исключающее ИЛИ=0 Обратный=ложь Реверсаут=ложь

Буду очень признателен за помощь, так как я застрял и не знаю, что еще попробовать. Спасибо :)

, 👍0

Обсуждение

Я мог бы объяснить это, если бы вы получали 0xB**5**, но не 0xBA. Это помогает иметь полностью компилируемый код., @timemage

Я только что заполнил ваш код догадками до такой степени, что он скомпилирован с последней версией этой библиотеки, и у меня он _is_ печатает 0xB5, а не 0xBA. Так что либо мы оба запутались, либо вы ошиблись номером в своем вопросе., @timemage

Еще раз проверьте свой снимок экрана с солнечным светом, потому что, если я вставлю в него именно то, что у вас есть, и вычислю, я не получу 0x6E; [Я получаю ожидаемое значение 0x49](https://imgur.com/a/btfECVA). Что касается теста скриншота «lddgo», он не совсем действителен. Настройки реверса включены. Как только вы правильно получите 0x49 на солнечном свете, включите обе опции отражения, и вы увидите, что вы [теперь получите 0x73](https://imgur.com/a/LFlGuCu), который соответствует тому, что у вас есть в lddgo. Итак, я бы удалил его, потому что это не имеет ничего общего с проблемой, с которой вы столкнулись с библиотекой., @timemage


1 ответ


2

Шестнадцатеричный результат этого примера кода: 0xBA (186 десятичный)

Насколько я могу судить, нет; это 0xB5, что ожидается по простой причине, которую вы увидите. И при небольшом изменении он соответствует значению 0x49. Я склонен полагать, что ваш код верен, насколько вы его показали, но ваш отчет о том, что происходит, неверен.

Я проверил все входные параметры с помощью gets и prints, все они правильные

Ну, нет. Как я уже упоминал в комментариях к вопросу, я получаю ожидаемый 0x49 на первом сайте, который вы упомянули, с правильными настройками. Я не уверен, почему вы показываете 0x6E. Но угадайте, что произойдет, если я нажму Enter после "TEMPS;"? 0x6Е. Символ новой строки имеет значение. Кроме того, я действительно получаю 0xBA, если использую правильный ввод, но не могу установить CRC8 на пользовательский и изменить 0x07 на 0x31 в полиноме. Возможно, именно так вы нашли это значение.

Если вы переключитесь в байтовый режим, сайт будет ожидать последовательность значений кодов символов и игнорировать пробелы (кроме того, что они будут рассматриваться как разделители). Вы можете поместить в него 0x54 0x45 0x4d 0x50 0x53 в байтовом режиме, чтобы также увидеть результат 0x49. Затем вы можете добавить 0x0D (перевод строки), чтобы увидеть, что это приводит к 0x6E из предыдущего.

Что касается среднего сайта, настройки неверны (настройка reverse включена для ввода и вывода), и я не вижу, как сделать их правильными ; у них, кажется, нет пользовательской опции. Однако вы можете включить параметры отражения на первом сайте, чтобы получить тот же результат, что и на втором сайте, чтобы убедиться, что это именно то, что происходит. Вывод третьего сайта соответствует тому, что вы в него вложили. Это просто не соответствует тому, что на самом деле делает ваш код.

Ваша основная проблема заключается в +1 в этой строке:

crcTrame.add((uint8_t *)arrayForCrc, crcDataLength+1);

Вы включили в расчет завершающий нуль. Это 7 байтов: 'T', 'E', 'M', 'P', 'S', ';', '\0'. Эти веб-сайты просто не делают этого; они не добавляют автоматически нулевой терминатор в конце всего, что вы вводите в строковом режиме. В качестве альтернативы, если вы хотели использовать нулевой терминатор в вычислении CRC, ваш код в порядке, но вам нужно будет переключиться на режим ввода HEX на веб-сайте и ввести в него 0x00 после шестнадцатеричного значения для других символов в TEMPS;, чтобы они совпадали. И это будет соответствовать, я проверил это. Также можно: перевести первый сайт в байтовый режим и поставить "0x54 0x45 0x4d 0x50 0x53 0x3b 0x00" в него, и вы увидите, что теперь он выдает 0xB5, как и ваш текущий код.

В противном случае вам просто нужно не вводить нулевой терминатор в расчет:

crcTrame.add((uint8_t *)arrayForCrc, crcDataLength);

Это приведет к тому, что 0x49 выйдет из crcTrame.getCRC() вместо 0xB5:

#include "CRC8.h"

void setup() {
  Serial.begin(9600);
}

void loop() {
  String crcData = "TEMPS;";
  int crcDataLength = crcData.length();
  char arrayForCrc[crcDataLength+1];
  crcData.toCharArray(arrayForCrc, crcDataLength+1);

  auto crcTrame = CRC8(0x31,0,0,false,false);
  crcTrame.add((uint8_t *)arrayForCrc, crcDataLength);
  String stringCrcNoHex = String(crcTrame.getCRC());
  String stringCrc = String(crcTrame.getCRC(), HEX);

  Serial.println(stringCrc);
}

Если вы также хотите проверить правильность того, что произошло с выводом 0x6E ранее, вы можете изменить crcData на String crcData = "TEMPS;\n" (добавив новую строку) и посмотрите, как он начнет печатать 6E.


В String есть функция .getBytes(), которая в значительной степени является тем, что у вас есть без необходимости в приведении:

crcTrame.getBytes(arrayForCrc, crcDataLength);

Я не уверен, есть ли у вас веская причина для "TEMPS;" чтобы начать жизнь в String или затем получить ее в массиве символов. Если вы делаете это только для того, чтобы затем вызвать crcTrame.add(), вам не нужно:

#include "CRC8.h"

void setup() {
  Serial.begin(9600);
}

void loop() {
  String crcData = "TEMPS;";
  int crcDataLength = crcData.length();

  auto crcTrame = CRC8(0x31,0,0,false,false);
  crcTrame.add(
    (const uint8_t *)crcData.c_str(),
    crcData.length() // <- Does not count null terminator.
  );
  String stringCrcNoHex = String(crcTrame.getCRC());
  String stringCrc = String(crcTrame.getCRC(), HEX);

  Serial.println(stringCrc);
}

Примечание. Я создаю stringCrc только для того, чтобы отразить то, что вы делали. Здесь это может быть просто Serial.println(crcTrame.getCRC(), HEX); и, возможно, в любом контексте, в котором вы это делаете. Приведение также может быть выполнено в более C++ одобрено (хотя более уродливый способ с crcTrame.add(reinterpret_cast<const uint8_t *>(crcData.c_str()), crcData.length());

Любая последовательность из любого количества вызовов add(), которая передает одни и те же данные в том же порядке для вычисления, даст один и тот же CRC. Существует также перегруженная функция add(), которая принимает отдельный символ. вообще без указателя. Таким образом, ваши данные не обязательно должны поступать из String, быть строкой с завершающим нулем или массивом символов или полностью помещаться в памяти.

,