Здравствуйте, fk0, Вы писали:
fk0> Пример ниже. Прекрасно видно, что на случайных данных, на совершенно разных последовательностях (случайных), даже на коротких (несколко байт) пакетах можно нарваться на ситуацию, когда CRC совпадает, а хвост пакета (а то и весь пакет!) испорчен нулём или FF. Позапускай программу несколько раз (./a.out | less). Что характерно -- CRC должен быть равен заполняющему (всё портящему) байту. Так вот в реальном приборе, где проблемы были, там, догадайся...
Во-первых, с самого начала: твой пример попросту с багом. Если его исправить как следует:
$ diff -u m.c.00 m.c
--- m.c.orig
+++ m.c
@@ -67,7 +67,7 @@
/* compute CRC of damaged packet */
ncrc=0;
for (n=0; n<plen; n++)
- ncrc=crc_byte(copy[n], crc);
+ ncrc=crc_byte(copy[n], ncrc);
/* check if crc doesn't protect data integrity */
if (crc != ncrc) continue;
то у меня получается в самом коротком случае 3 байта испорченных, иногда 4, обычно же оно не находит случаев короче чем 8 байт. Для CRC-8 это очень хороший результат. А твой пример умудряется находить даже последовательности с изменением одного последнего байта, что заведомо показывает на ошибочность твоего кода (собственно почему я и стал рыть).
Далее по частям программы:
fk0>/* compute CRC-8 for SMBUS (x^8 + x^2 + x + 1) */
fk0>uint_fast8_t crc_byte(uint_fast8_t byte, uint_fast8_t crc)
fk0>{
fk0>uint_fast8_t b;
fk0> b=byte^crc;
fk0> if (b&(1<<0)) crc^=0x7;
fk0> if (b&(1<<1)) crc^=0xe;
fk0> if (b&(1<<2)) crc^=0x1c;
fk0> if (b&(1<<3)) crc^=0x38;
fk0> if (b&(1<<4)) crc^=0x70;
fk0> if (b&(1<<5)) crc^=0xe0;
fk0> if (b&(1<<6)) crc^=0xc7;
fk0> if (b&(1<<7)) crc^=0x89;
fk0> return crc;
fk0>}
Не знаю, что ты здесь хотел нарисовать, но это никак не CRC в обычном понимании.
В обычном было бы примерно так:
uint_fast8_t crc_byte(uint_fast8_t byte, uint_fast8_t crc)
{
uint_fast8_t old = crc;
crc = byte;
if (old & (1<<0)) crc ^= 0x07;
... аналогичные варианты для остальных битов ...
return crc;
}
Может, твой код преобразуется в то, что делается по классике, но тут получается как минимум смещение на байт, и я с ходу не берусь предсказать результаты этого смещения и степень устойчивости результата.
Откуда код? Ты это взял из спецификации SMBus? Кстати, там точно передача начинается со старшего бита?
fk0> Вообще-то CRC считается и бестабличными методами достаточно быстро, если такая задача стоит. Опять же смотри пример. Все возражения "почему не 16-32 бита" -- потому что блоки не по 4 килобайта, а по десятку байт. А 16 бит принципиально ситуацию тут не изменит вообще.
Думаю, таки изменит. Не зря на Ethernet при типичном размере пакета в пару сотен байт уже применялся CRC-32.
Но твоя ситуация вообще-то показывает контекст не для CRC. CRC предназначен для случаев именно одиночных независимых искажений потока (изменения битов, выпадения/добавления целых байт). Причём на SMBus, аналогично RS-232, невозможно держать AFAIK линию данных всё время на одном уровне — потому что тогда не будут видны границы байтов. Ситуация, когда хвост пакета целиком становится битами одного значения, означает сбой уже в кодере или декодере протокола, а не помеху/сбой на линии. Такие вещи должны отлавливаться на другом уровне и обвинять CRC в их неотлове — нелепость.
Если ты хочешь проверить CRC на корректность детекта в условиях, в которых он предназначен работать — меняй произвольно 1 из ~100 байтов не обязательно в хвосте.