Димон Безпарольный 0 Posted January 13 (edited) · Report post Считаю контрольную сумму 16-ти байт Quote 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F Формирую бинарный файл с этими данными, получаю результат 0xСECEE288(crc файла в Проводнике). Контроллер выдает 0x31311D77. Загнал алгоритм (код ниже) в C-Free компилятор. Тоже получил 0xСECEE288. Сравнил сформированные таблицы - одинаковые. Закипел. Код формирования таблицы unsigned long crc_table[256]; Таблица глобальная void Crc32Init(void) { unsigned long crc; for (int i = 0; i < 256; i++) //инициализируем таблицу расчёта Crc32 { crc = i; for (int j = 0; j < 8; j++) //цикл перебора полинома crc = crc & 1 ? (crc >> 1) ^ 0xEDB88320UL : crc >> 1; crc_table[i] = crc; } inCRC = 0xFFFFFFFF; } Код самого подсчета unsigned long int Crc32(unsigned char Byte) { inCRC = (inCRC >> 8) ^ crc_table[(inCRC ^ Byte) & 0xFF]; return inCRC ^ 0xFFFFFFFF; } inCRC - глобальная переменная unsigned long int inCRC = 0xFFFFFFFF; в которой накапливается сумма. Может подскажет кто, где я накосячил? Edited January 13 by Димон Безпарольный Quote Ответить с цитированием Share this post Link to post Share on other sites
Obam 0 Posted January 13 · Report post 2 * 2, конечно, "сэм-восэм", но c 1 до 15 никак не 16 чисел, входные байты могут и "зеркалиться" относительно их середины. А "если мы с вами посмотрим, то мы с вами увидим" ((с) моя школьная историчка): 0xСECEE288 инверсия 0x31311D77. Quote Ответить с цитированием Share this post Link to post Share on other sites
Димон Безпарольный 0 Posted January 14 · Report post 8 hours ago, Obam said: 0xСECEE288 инверсия 0x31311D77 Точно инверсия. Буду разбираться откуда она берется. Сам алгоритм выдает на двух компиляторах данные без инверсии. Quote Ответить с цитированием Share this post Link to post Share on other sites
Димон Безпарольный 0 Posted Friday at 08:48 AM (edited) · Report post Нашел причину. Выполнение строки: return inCRC ^ 0xFFFFFFFF; Дает разный результат на компьютерном С++ и в камне. В камне return inCRC ^ 0xFFFFFFFF; и return inCRC; дает одинаковый результат! На компьютерном С++ - дает инверсию. Так например Crc32(0x55); дает число 0x36fcb509 в камне независимо от варианта команды return. На С-Free на компьютере будет 0xC9034AF6 при команде return inCRC ^ 0xFFFFFFFF; и 0x36fcb509 при команде return inCRC; Почему в камне вычисление значения 0x36fcb509 ^ 0xFFFFFFFF; не инвертирует число, а на компьютере происходит инверсия? Подозреваю что что - то с разрядностью но не могу понять что. Edited Friday at 08:48 AM by Димон Безпарольный Quote Ответить с цитированием Share this post Link to post Share on other sites
Darth Vader 0 Posted Friday at 04:46 PM · Report post 14.01.2021 в 00:49, Димон Безпарольный сказал: Может подскажет кто, где я накосячил? Построение функций принципиально косячное. Не используйте в них глобальные переменные! Использование такого стиля дает сплошные побочные эффекты. Функции зависят черт-знает от чего и портят кучу всего в программе. Всё необходимое для своей работы функция должна получать через параметры. Нужны дополнительные хранилища вспомогательных данных - используйте локальные переменные. Нужно, чтобы локальные переменные сохраняли значения между вызовами - делайте их локальными статическими. По существу: как вы проверяли результат? Приведите полный текст тестовой программы. Вы, случаем, не значение вашей глобальной переменной inCRC32 проверяли? А вот эта функция 14.01.2021 в 00:49, Димон Безпарольный сказал: unsigned long int Crc32(unsigned char Byte) мне вообще непонятна. Зачем считать CRC32 от одного байта? А еще её результат зависит от двух глобальных объектов программы, один из которых ещё и изменяется ей же самой. Просто набор штампов, как не следует писать программы. Нормальные функции подсчета CRC32 произвольного объекта данных data размером size байт выглядят примерно так: uint32_t Crc32(const void *data, uint32_t size); Да, для платформонезависимости результата пользуйтесь именами типов из файла stdint.h. Иначе один и тот же ваш код будет давать разный результат на разных архитектурах: на 8-битных один, на 16-битных другой, на 32-битных третий, а на 64-битных четвертый. Quote Ответить с цитированием Share this post Link to post Share on other sites
Димон Безпарольный 0 Posted Friday at 05:59 PM (edited) · Report post 1 hour ago, Darth Vader said: Зачем считать CRC32 от одного байта? Функция работает получая данные как с массивов, так и на лету с приема байт. Согласен что написано криво, надо причесать. Но это не решит проблемы потому что на глюк не похоже. Если инвертировать результат, функция считает CRC правильно на лету, из EEPROM 2580, из ФЛЭШ контроллера и еще бог знает откуда - проблем нет. Для проверки работы функции я написал вызов: Crc32Init(); Crc32(0x55); Так вот. В коде функции: unsigned long int Crc32(unsigned char Byte) { inCRC = (inCRC >> 8) ^ crc_table[(inCRC ^ Byte) & 0xFF]; return inCRC ^ 0xFFFFFFFF; } Есть строка return inCRC ^ 0xFFFFFFFF;. Она ничего не меняет. Т.е. возвращаемый результат будет тем же, что и при return inCRC; Это в камне. Приходится дополнительно инвертировать результат чтобы совпало с вариантом на ПК. А вот в варианте на ПК return inCRC ^ 0xFFFFFFFF; как раз инвертирует результат как и должно быть. Что мне пока непонятно. Один и тот же код работает по разному. Нашел причину. Вызов функции был неправильным. Правильно надо присваивать значение CRC локальной переменной uint32_t . CRCSUM = Crc32(Chr); Тогда результат подсчета будет правильный. Всем спасибо за советы. Пошел причесывать код. Edited Friday at 06:35 PM by Димон Безпарольный Quote Ответить с цитированием Share this post Link to post Share on other sites
Димон Безпарольный 0 Posted Friday at 06:38 PM · Report post 1 hour ago, Darth Vader said: Не используйте в них глобальные переменные! Перед подсчетом CRC32 нужно вызвать Crc32Init(); Она в частности проинициализирует inCRC = 0xFFFFFFFF;. Переменная inCRC используется в двух функциях. Поэтому она глобальна. Как тогда реализовать иначе? Quote Ответить с цитированием Share this post Link to post Share on other sites
Darth Vader 0 Posted Friday at 07:24 PM (edited) · Report post 1 час назад, Димон Безпарольный сказал: Как тогда реализовать иначе? Сделать ОДНУ функцию, которая всё делает сама. Например так: // Реализация функции расчёта CRC-32 // data_p - указатель на произвольный объект // len - размер объекта в байтах uint32_t Crc32(const void *data_p, uint32_t len) { static const uint32_t Crc32Table[256] = { 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D }; const uint8_t *buf = (const uint8_t*)data_p; uint32_t crc = 0xFFFFFFFF; while (len--) { crc = (crc >> 8) ^ Crc32Table[(crc ^ *buf++) & 0xFF]; } return ~crc; }; Это быстрый табличный расчёт CRC32 с полиномом 0x04C11DB7. Для другого полинома будут другие значения в массиве Crc32Table[256]. Взято отсюда. Проведен небольшой рефакторинг: тип входного параметра-указателя для универсальности заменен на void*, константный массив спрятан внутрь функции, типы заменены на более конкретные. Edited Friday at 07:41 PM by Darth Vader Quote Ответить с цитированием Share this post Link to post Share on other sites
Димон Безпарольный 0 Posted Friday at 07:29 PM (edited) · Report post 12 minutes ago, Darth Vader said: Сделать ОДНУ функцию, которая всё делает сама. Спасибо. Хочу только заметить что мной пишется бутлоадер для камней с большим количеством ОЗУ. Ему неважно сколько ОЗУ будет съедено. Да и ПЗУ тоже. Но вот ПЗУ желательно поменьше. Чисто субъективно. Также непонятно как налету считать CRC. Файл прошивки может быть гораздо больше чем ОЗУ. А вот потеря времени на расчет таблицы малозначительна. Принятые данные напрямую пишутся в 2580 и налету считается CRC. Данные пишутся по 256 байт за раз. Как вариант можно CRC считать тоже по 256 байт. Edited Friday at 07:37 PM by Димон Безпарольный Quote Ответить с цитированием Share this post Link to post Share on other sites
Darth Vader 0 Posted Friday at 07:29 PM · Report post 47 минут назад, Димон Безпарольный сказал: Переменная inCRC используется в двух функциях. Поэтому она глобальна. Ситуация ничего не напоминает? В С++ именно для таких ситуаций придуманы классы. Общие данные - это данные (поля) класса. Функции, оперирующие этими общими данными - это функции-члены класса. Так что в некоторых случаях, если нужна большая гибкость расчета, удобнее сделать класс CRC32. Quote Ответить с цитированием Share this post Link to post Share on other sites
Димон Безпарольный 0 Posted Friday at 07:31 PM · Report post 1 minute ago, Darth Vader said: Ситуация ничего не напоминает? В С++ именно для таких ситуаций придуманы классы. Общие данные - это данные (поля) класса. Функции, оперирующие этими общими данными - это функции-члены класса. Так что в некоторых случаях, если нужна большая гибкость расчета, удобнее сделать класс CRC32. Код написан на Си. Quote Ответить с цитированием Share this post Link to post Share on other sites
Darth Vader 0 Posted Friday at 07:40 PM (edited) · Report post 35 минут назад, Димон Безпарольный сказал: Код написан на Си. Код может быть написан на чем угодно. Один файл на Си, другой на С++, третий на ассемблере. Всё равно компилируются они раздельно. А линкеру всё равно, на чем были написаны исходные коды объектных модулей. Так что писать стоит на том, на чем удобней в данный конкретный момент. Но уж если хочется чистого Си, то можно сделать закат солнца вручную и изобрести понятие класса и указателя this средствами Си: - описываем тип структуры с полями-данными, необходимыми для работы всех функций - во все функции добавляем в качестве первого параметра указатель на эту структуру с именем this - внутри функций обращаетесь к необходимым общим данным через этот указатель this - перед началом нового расчета создаете эту структуру. Причем она может быть как глобальной, так и локальной. - вызываете ваши функции, передавая им в качестве первого параметра указатель на структуру. Edited Friday at 08:09 PM by Darth Vader Quote Ответить с цитированием Share this post Link to post Share on other sites