FC_BIN_HVAC/APP/main.c

520 lines
18 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
// Таблица CRC32 для полинома 0xEDB88320 (IEEE 802.3)
static const uint32_t crc32_table[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
};
// Структура для параметров командной строки
typedef struct {
char *filename;
int write_crc; // Флаг: записывать CRC в файл
int verify_crc; // Флаг: проверять CRC
int show_only; // Флаг: только показать CRC без записи
int verbose; // Флаг: подробный вывод
} ProgramOptions;
// Прототипы функций
void print_usage(const char *program_name);
int parse_arguments(int argc, char *argv[], ProgramOptions *options);
uint32_t calculate_crc32(const uint8_t *data, uint32_t len);
uint32_t calculate_file_crc32_without_last4(const char *filename, int verbose);
uint32_t calculate_file_crc32_full(const char *filename, int verbose);
int write_crc32_to_file(const char *filename, uint32_t crc_value, int verbose);
int verify_crc32(const char *filename, int verbose);
/**
* @brief Вычисляет CRC32 (IEEE 802.3) для блока данных в памяти
*/
uint32_t calculate_crc32(const uint8_t *data, uint32_t len) {
uint32_t crc = 0xFFFFFFFF;
for (uint32_t i = 0; i < len; i++) {
crc = (crc >> 8) ^ crc32_table[(crc ^ data[i]) & 0xFF];
}
return crc ^ 0xFFFFFFFF;
}
/**
* @brief Вычисляет CRC32 для файла, исключая последние 4 байта
* Используется для записи и проверки CRC
*/
uint32_t calculate_file_crc32_without_last4(const char *filename, int verbose) {
FILE *file = NULL;
uint8_t *buffer = NULL;
long file_size = 0;
uint32_t crc = 0;
file = fopen(filename, "rb");
if (file == NULL) {
perror("Failed to open file");
return 0;
}
// Получаем размер файла
if (fseek(file, 0, SEEK_END) != 0) {
perror("Failed to seek to end");
fclose(file);
return 0;
}
file_size = ftell(file);
if (file_size < 4) {
fprintf(stderr, "File size (%ld bytes) is less than 4 bytes\n", file_size);
fclose(file);
return 0;
}
long data_size = file_size - 4; // Размер данных без последних 4 байт
if (verbose) {
printf("File size: %ld bytes\n", file_size);
printf("Data size for CRC calculation (without last 4 bytes): %ld bytes\n", data_size);
}
// Выделяем память под данные
buffer = (uint8_t*)malloc(data_size);
if (buffer == NULL && data_size > 0) {
perror("Failed to allocate memory");
fclose(file);
return 0;
}
// Возвращаемся в начало
if (fseek(file, 0, SEEK_SET) != 0) {
perror("Failed to seek to beginning");
free(buffer);
fclose(file);
return 0;
}
// Читаем данные (все, кроме последних 4 байт)
if (data_size > 0) {
size_t bytes_read = fread(buffer, 1, data_size, file);
if (bytes_read != data_size) {
fprintf(stderr, "Failed to read file data. Read %zu bytes, expected %ld bytes\n",
bytes_read, data_size);
free(buffer);
fclose(file);
return 0;
}
}
// Вычисляем CRC
if (data_size > 0) {
crc = calculate_crc32(buffer, data_size);
} else {
crc = calculate_crc32(NULL, 0);
}
free(buffer);
fclose(file);
return crc;
}
/**
* @brief Вычисляет CRC32 для всего файла (включая последние 4 байта)
* Используется только для показа CRC
*/
uint32_t calculate_file_crc32_full(const char *filename, int verbose) {
FILE *file = NULL;
uint8_t *buffer = NULL;
long file_size = 0;
uint32_t crc = 0;
file = fopen(filename, "rb");
if (file == NULL) {
perror("Failed to open file");
return 0;
}
if (fseek(file, 0, SEEK_END) != 0) {
perror("Failed to seek to end");
fclose(file);
return 0;
}
file_size = ftell(file);
if (verbose) {
printf("File size: %ld bytes\n", file_size);
}
if (file_size <= 0) {
fprintf(stderr, "File is empty\n");
fclose(file);
return 0;
}
buffer = (uint8_t*)malloc(file_size);
if (buffer == NULL) {
perror("Failed to allocate memory");
fclose(file);
return 0;
}
if (fseek(file, 0, SEEK_SET) != 0) {
perror("Failed to seek to beginning");
free(buffer);
fclose(file);
return 0;
}
size_t bytes_read = fread(buffer, 1, file_size, file);
if (bytes_read != file_size) {
fprintf(stderr, "Failed to read entire file\n");
free(buffer);
fclose(file);
return 0;
}
crc = calculate_crc32(buffer, file_size);
free(buffer);
fclose(file);
return crc;
}
/**
* @brief Записывает CRC32 в последние 4 байта файла
*/
int write_crc32_to_file(const char *filename, uint32_t crc_value, int verbose) {
FILE *file = NULL;
long file_size;
file = fopen(filename, "rb+");
if (file == NULL) {
perror("Failed to open file for writing");
return -1;
}
if (fseek(file, 0, SEEK_END) != 0) {
perror("Failed to seek to end");
fclose(file);
return -1;
}
file_size = ftell(file);
if (file_size < 4) {
fprintf(stderr, "File size (%ld bytes) is less than 4 bytes\n", file_size);
fclose(file);
return -1;
}
// Перемещаемся на позицию последних 4 байт
if (fseek(file, file_size - 4, SEEK_SET) != 0) {
perror("Failed to seek to CRC position");
fclose(file);
return -1;
}
// Записываем CRC в little-endian порядке
uint8_t crc_bytes[4];
crc_bytes[0] = (crc_value >> 0) & 0xFF;
crc_bytes[1] = (crc_value >> 8) & 0xFF;
crc_bytes[2] = (crc_value >> 16) & 0xFF;
crc_bytes[3] = (crc_value >> 24) & 0xFF;
size_t bytes_written = fwrite(crc_bytes, 1, 4, file);
if (bytes_written != 4) {
fprintf(stderr, "Failed to write CRC to file\n");
fclose(file);
return -1;
}
fclose(file);
if (verbose) {
printf("CRC32 value written: 0x%08X (%u)\n", crc_value, crc_value);
printf("Written to bytes: %ld-%ld\n", file_size - 4, file_size - 1);
printf("Byte order: little-endian (LSB first)\n");
}
return 0;
}
/**
* @brief Проверяет CRC32, сравнивая вычисленное значение с сохраненным
*/
int verify_crc32(const char *filename, int verbose) {
FILE *file = NULL;
long file_size;
uint32_t calculated_crc = 0;
uint32_t stored_crc = 0;
file = fopen(filename, "rb");
if (file == NULL) {
perror("Failed to open file");
return -1;
}
if (fseek(file, 0, SEEK_END) != 0) {
perror("Failed to seek to end");
fclose(file);
return -1;
}
file_size = ftell(file);
if (file_size < 4) {
fprintf(stderr, "File size (%ld bytes) is less than 4 bytes\n", file_size);
fclose(file);
return -1;
}
if (verbose) {
printf("File size: %ld bytes\n", file_size);
}
// Читаем сохраненный CRC из последних 4 байт
if (fseek(file, file_size - 4, SEEK_SET) != 0) {
perror("Failed to seek to stored CRC");
fclose(file);
return -1;
}
uint8_t crc_bytes[4];
size_t bytes_read = fread(crc_bytes, 1, 4, file);
if (bytes_read != 4) {
fprintf(stderr, "Failed to read stored CRC\n");
fclose(file);
return -1;
}
stored_crc = (uint32_t)crc_bytes[0] << 0 |
(uint32_t)crc_bytes[1] << 8 |
(uint32_t)crc_bytes[2] << 16 |
(uint32_t)crc_bytes[3] << 24;
fclose(file);
// Вычисляем CRC для данных (без последних 4 байт)
calculated_crc = calculate_file_crc32_without_last4(filename, verbose);
if (calculated_crc == 0) {
fprintf(stderr, "Failed to calculate CRC\n");
return -1;
}
// Всегда выводим значения CRC при проверке
printf("\n╔════════════════════════════════════════╗\n");
printf("║ CRC32 Verification ║\n");
printf("╠════════════════════════════════════════╣\n");
printf("║ Stored CRC : 0x%08X (%10u) ║\n", stored_crc, stored_crc);
printf("║ Calculated CRC : 0x%08X (%10u) ║\n", calculated_crc, calculated_crc);
printf("╚════════════════════════════════════════╝\n");
if (calculated_crc == stored_crc) {
printf("\n✓ VERIFIED: CRC matches! File integrity check passed.\n");
return 0;
} else {
printf("\n✗ MISMATCH: File is corrupted or CRC was not written correctly!\n");
printf(" Difference: 0x%08X\n", calculated_crc ^ stored_crc);
return 1;
}
}
/**
* @brief Выводит справку
*/
void print_usage(const char *program_name) {
printf("\nCRC32 Tool for BIN files\n");
printf("========================\n\n");
printf("Usage: %s [OPTIONS] <filename>\n\n", program_name);
printf("Options:\n");
printf(" -w, --write Calculate CRC32 from all except last 4 bytes\n");
printf(" and write it to last 4 bytes\n");
printf(" -c, --check Verify CRC32 by comparing with stored value\n");
printf(" -s, --show-only Calculate and display CRC32 of entire file\n");
printf(" -v, --verbose Show detailed information\n");
printf(" -h, --help Show this help\n");
printf("\nExamples:\n");
printf(" %s -s firmware.bin # Show CRC32 of entire file\n", program_name);
printf(" %s -w firmware.bin # Write CRC32 to last 4 bytes\n", program_name);
printf(" %s -c firmware.bin # Verify CRC32\n", program_name);
printf(" %s -v -w firmware.bin # Write with verbose output\n", program_name);
printf("\nNote:\n");
printf(" For -w and -c operations, CRC is calculated from the first\n");
printf(" (file_size - 4) bytes, ignoring the last 4 bytes.\n");
printf("\n");
}
/**
* @brief Разбирает аргументы командной строки
*/
int parse_arguments(int argc, char *argv[], ProgramOptions *options) {
int option_index = 0;
int c;
static struct option long_options[] = {
{"write", no_argument, 0, 'w'},
{"check", no_argument, 0, 'c'},
{"show-only", no_argument, 0, 's'},
{"verbose", no_argument, 0, 'v'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
memset(options, 0, sizeof(ProgramOptions));
while ((c = getopt_long(argc, argv, "wcsvh", long_options, &option_index)) != -1) {
switch (c) {
case 'w':
options->write_crc = 1;
break;
case 'c':
options->verify_crc = 1;
break;
case 's':
options->show_only = 1;
break;
case 'v':
options->verbose = 1;
break;
case 'h':
print_usage(argv[0]);
return -1;
case '?':
return -1;
}
}
if (optind >= argc) {
fprintf(stderr, "Error: No filename specified.\n");
print_usage(argv[0]);
return -1;
}
options->filename = argv[optind];
if (!options->write_crc && !options->verify_crc && !options->show_only) {
options->show_only = 1;
}
int mode_count = options->write_crc + options->verify_crc + options->show_only;
if (mode_count > 1) {
fprintf(stderr, "Error: Cannot use multiple modes\n");
return -1;
}
return 0;
}
/**
* @brief Главная функция
*/
int main(int argc, char *argv[]) {
ProgramOptions options;
uint32_t crc_value;
int result = 0;
if (parse_arguments(argc, argv, &options) != 0) {
return 1;
}
if (options.show_only) {
// Показать CRC всего файла
printf("\n--- CRC32 of %s ---\n", options.filename);
crc_value = calculate_file_crc32_full(options.filename, options.verbose);
if (crc_value == 0) {
fprintf(stderr, "Failed to calculate CRC32\n");
return 1;
}
printf("\nCRC32 (full file): 0x%08X (%u)\n", crc_value, crc_value);
}
else if (options.write_crc) {
// Записать CRC
printf("\n--- Writing CRC32 to %s ---\n", options.filename);
if (options.verbose) {
printf("\nStep 1: Calculating CRC32 from first (file_size - 4) bytes...\n");
}
crc_value = calculate_file_crc32_without_last4(options.filename, options.verbose);
if (crc_value == 0) {
fprintf(stderr, "Failed to calculate CRC32\n");
return 1;
}
// Всегда выводим вычисленное CRC при записи
printf("\n╔════════════════════════════════════════╗\n");
printf("║ CRC32 Calculation ║\n");
printf("╠════════════════════════════════════════╣\n");
printf("║ Calculated CRC : 0x%08X (%10u) ║\n", crc_value, crc_value);
printf("╚════════════════════════════════════════╝\n");
if (options.verbose) {
printf("\nStep 2: Writing to last 4 bytes...\n");
}
result = write_crc32_to_file(options.filename, crc_value, options.verbose);
if (result != 0) {
fprintf(stderr, "Failed to write CRC32\n");
return 1;
}
printf("\n✓ CRC32 successfully written to file\n");
// Опционально: проверим сразу после записи
if (options.verbose) {
printf("\n--- Verifying after write ---\n");
verify_crc32(options.filename, 0);
}
}
else if (options.verify_crc) {
// Проверить CRC
printf("\n--- Verifying CRC32 for %s ---\n", options.filename);
result = verify_crc32(options.filename, options.verbose);
}
return result;
}