/** * @file blf.h * @brief Заголовочный файл библиотеки для создания BLF-файлов (Vector). * @details Определяет структуры, константы и функции для работы с форматом BLF. * Поддерживает stdio (ПК) и FatFS (встраиваемые системы) через условную компиляцию. * Не использует динамическую память – контекст выделяется пользователем. * * @author (Ваше имя) * @date 2026-03-20 */ #ifndef BLF_H #define BLF_H #include /* ------------------------------------------------------------------------- * Обёртка для вывода ошибок (может быть переопределена до включения заголовка) * ------------------------------------------------------------------------- */ #ifndef BLF_ERROR_PRINTF #include #define BLF_ERROR_PRINTF(...) printf(__VA_ARGS__) #endif /* ------------------------------------------------------------------------- * Константы формата BLF (сигнатуры, типы объектов, флаги) * ------------------------------------------------------------------------- */ #define BL_FILE_SIGNATURE 0x47474F4Cu /* "LOGG" – сигнатура файла */ #define BL_OBJ_SIGNATURE 0x4A424F4Cu /* "LOBJ" – сигнатура объекта */ #define BL_OBJ_TYPE_CAN_MESSAGE 1 /* CAN-сообщение (устаревшее) */ #define BL_OBJ_TYPE_CAN_MESSAGE2 86 /* CAN-сообщение расширенное */ #define BL_OBJ_TYPE_LIN_MESSAGE 11 /* LIN-сообщение */ #define BL_OBJ_TYPE_LIN_SND_ERROR 15 /* Ошибка отправки LIN */ #define BL_OBJ_TYPE_LOG_CONTAINER 10 /* Контейнер */ #define BL_OBJ_TYPE_ENV_DATA 9 /* Данные окружения (ENV_DATA) */ #define BL_OBJ_FLAG_TIME_ONE_NANS 0x00000002 /* Временная метка в наносекундах */ #define BL_OBJ_FLAG_TIME_TEN_MICS 0x00000001 /* Временная метка в 10 микросекундах */ /* Флаги CAN-сообщения: бит 7 = RTR, биты 0-3 = направление */ #define CAN_MSG_FLAGS(dir, rtr) \ ((uint8_t)(((uint8_t)(rtr & 0x01) << 7) | ((uint8_t)(dir & 0x0F)))) #define CAN_DIR_TX 1 /* передача */ #define CAN_DIR_RX 0 /* приём */ /* Направления LIN-сообщений */ #define LIN_DIR_RX 0 #define LIN_DIR_TX 1 /* ------------------------------------------------------------------------- * Упакованные структуры BLF (соответствуют двоичному формату Vector) * ------------------------------------------------------------------------- */ #if defined(_MSC_VER) #pragma pack(push, 1) #else #define PACKED __attribute__((packed)) #endif /* Системное время (используется в заголовке файла) */ typedef struct PACKED { uint16_t year; /* год */ uint16_t month; /* месяц (1–12) */ uint16_t dayOfWeek; /* день недели (0–6, 0 = воскресенье) */ uint16_t day; /* день месяца */ uint16_t hour; /* часы (0–23) */ uint16_t minute; /* минуты (0–59) */ uint16_t second; /* секунды (0–59) */ uint16_t milliseconds; /* миллисекунды (0–999) */ } SYSTEMTIME; /** * @brief Заголовок BLF-файла (структура FileStatistics). * @details Размер 144 байта. Содержит общую информацию о файле. */ typedef struct PACKED { uint32_t signature; /* "LOGG" */ uint32_t statisticsSize; /* sizeof(FileHeader) = 144 */ uint32_t apiNumber; /* версия API, например 4070100 */ uint8_t applicationId; /* 1 = CANalyzer/CANoe */ uint8_t compressionLevel; /* 0 – без сжатия */ uint8_t applicationMajor; /* старшая версия приложения */ uint8_t applicationMinor; /* младшая версия приложения */ uint64_t fileSize; /* полный размер файла (с выравниванием) */ uint64_t uncompressedFileSize; /* размер несжатых данных */ uint32_t objectCount; /* количество объектов верхнего уровня */ uint32_t applicationBuild; /* номер сборки приложения */ SYSTEMTIME measurementStartTime; /* время начала записи */ SYSTEMTIME lastObjectTime; /* время последнего объекта */ uint64_t restorePointsOffset; /* смещение до точек восстановления (0) */ uint32_t reservedFileStatistics[16]; /* зарезервировано */ } FileHeader; /* Базовый заголовок объекта (16 байт) */ typedef struct PACKED { uint32_t mSignature; /* "LOBJ" */ uint16_t mHeaderSize; /* размер полного заголовка (обычно sizeof(VBLObjectHeader)) */ uint16_t mHeaderVersion; /* версия заголовка (1) */ uint32_t mObjectSize; /* полный размер объекта (заголовок + данные) */ uint32_t mObjectType; /* тип объекта */ } VBLObjectHeaderBase; /* Полный заголовок объекта версии 1 (32 байта) */ typedef struct PACKED { VBLObjectHeaderBase mBase; /* базовые поля */ uint32_t mObjectFlags; /* флаги (например, временная метка в наносекундах) */ uint16_t mClientIndex; /* индекс клиента (обычно 0) */ uint16_t mObjectVersion; /* версия данных объекта (0) */ uint64_t mObjectTimeStamp; /* временная метка (наносекунды) */ } VBLObjectHeader; /* Данные CAN-сообщения (устаревший тип, 16 байт) */ typedef struct PACKED { uint16_t mChannel; /* номер канала */ uint8_t mFlags; /* бит 7 = RTR, остальные – направление */ uint8_t mDLC; /* длина данных (0-8) */ uint32_t mID; /* идентификатор */ uint8_t mData[8]; /* данные */ } VBLCANMessage; /** * @brief Данные CAN-сообщения расширенного типа (ObjectType = 86) * @details Содержит дополнительную информацию о длительности кадра и количестве бит * Размер: 32 байта (заголовок) + данные (зависит от DLC) */ typedef struct PACKED { uint16_t mChannel; /* номер канала */ uint8_t mFlags; /* бит 7 = RTR, остальные – направление */ uint8_t mDLC; /* длина данных (0-8) */ uint32_t mID; /* идентификатор */ uint8_t mData[8]; /* данные */ uint32_t mFrameLength; /* длительность сообщения в наносекундах */ uint8_t mBitCount; /* общее количество бит сообщения */ uint8_t mReserved1; /* зарезервировано, должно быть 0 */ uint16_t mReserved2; /* зарезервировано, должно быть 0 */ } VBLCANMessage2; /* Данные LIN-сообщения (устаревший тип, 20 байт) */ typedef struct PACKED { uint16_t mChannel; uint8_t mID; /* идентификатор (6 бит) */ uint8_t mDLC; uint8_t mData[8]; uint8_t mFSMId; /* всегда 0 */ uint8_t mFSMState; /* всегда 0 */ uint8_t mHeaderTime; /* длительность заголовка в битовых временах */ uint8_t mFullTime; /* длительность всего кадра в битовых временах */ uint16_t mCRC; /* контрольная сумма */ uint8_t mDir; /* направление */ uint8_t mReserved; } VBLLINMessage; /* Данные ошибки LIN (отсутствие ответа, 10 байт) */ typedef struct PACKED { uint16_t mChannel; uint8_t mID; uint8_t mDLC; uint8_t mFSMId; uint8_t mFSMState; uint8_t mHeaderTime; uint8_t mFullTime; } VBLLINSendError; /* Дополнительные данные контейнера (тип 10) */ typedef struct PACKED { uint16_t compressionMethod; /* 0 – без сжатия */ uint16_t reserved1; uint32_t reserved2; uint32_t uncompressedFileSize; /* размер данных внутри контейнера */ uint32_t reserved3; } LogContainerData; /* Полный заголовок контейнера (базовый + данные) */ typedef struct PACKED { VBLObjectHeaderBase base; LogContainerData data; } ContainerHeader; /* ------------------------------------------------------------------------- * Удобные структуры для передачи данных (в миллисекундах) * ------------------------------------------------------------------------- */ typedef struct PACKED { uint8_t channel; uint32_t id; uint8_t flags; uint8_t dlc; uint8_t data[8]; uint32_t timestamp; /* в миллисекундах */ uint32_t frameLength; /* длительность сообщения в наносекундах (опционально) */ uint8_t bitCount; /* количество бит сообщения (опционально) */ } CanMessageStruct; typedef struct PACKED { uint8_t channel; uint8_t id; uint8_t dlc; uint8_t data[8]; uint8_t dir; uint32_t timestamp; /* в миллисекундах */ uint16_t checksum; } LinMessageStruct; typedef struct PACKED { uint8_t channel; uint8_t id; uint8_t dlc; uint32_t timestamp; /* в миллисекундах */ } LinSendErrorStruct; typedef struct PACKED { char name[4]; /* имя переменной (до 3 символов) */ const uint8_t* data; uint32_t data_len; uint32_t timestamp; /* в миллисекундах */ } EnvDataStruct; /* Возврат к стандартному выравниванию */ #if defined(_MSC_VER) #pragma pack(pop) #else #undef PACKED #endif /* ------------------------------------------------------------------------- * Контекст BLF-файла (полное определение – для выделения на стеке) * ------------------------------------------------------------------------- */ /* Условное включение дескриптора файла в зависимости от USE_FATFS */ #ifdef USE_FATFS #include "ff.h" /* FatFS */ typedef FIL BlfFileHandle; #else #include typedef FILE* BlfFileHandle; #endif typedef struct { BlfFileHandle fp; /* дескриптор файла */ FileHeader header; /* заголовок файла (будет перезаписан в конце) */ long headerPos; /* позиция заголовка в файле */ int objectCount; /* количество объектов верхнего уровня */ uint64_t maxTimestamp; /* максимальная временная метка (для lastObjectTime) */ int in_container; /* флаг: внутри контейнера */ ContainerHeader container_hdr; /* заголовок открытого контейнера */ long container_hdr_pos; /* позиция заголовка контейнера в файле */ uint64_t container_timestamp; /* временная метка контейнера */ int use_can_message2; /* флаг: использовать VBLCANMessage2 вместо VBLCANMessage */ } BLFContext; /* ------------------------------------------------------------------------- * Прототипы функций API * ------------------------------------------------------------------------- */ /** * @brief Инициализирует BLF-контекст и создаёт новый файл. * @param ctx Указатель на предварительно выделенный контекст. * @param filename Имя файла. * @param startTime Время начала измерения. * @param use_can_message2 Использовать расширенный формат CAN-сообщений (VBLCANMessage2). * @return 0 при успехе, -1 при ошибке. */ int blf_open_ex(BLFContext *ctx, const char *filename, const SYSTEMTIME *startTime, int use_can_message2); /** * @brief Инициализирует BLF-контекст и создаёт новый файл (использует старый формат CAN). * @param ctx Указатель на предварительно выделенный контекст. * @param filename Имя файла. * @param startTime Время начала измерения. * @return 0 при успехе, -1 при ошибке. */ static inline int blf_open(BLFContext *ctx, const char *filename, const SYSTEMTIME *startTime) { return blf_open_ex(ctx, filename, startTime, 0); } /** * @brief Начинает новый контейнер (объект типа LOG_CONTAINER). * @param ctx Контекст. * @param timestamp Временная метка контейнера (наносекунды). * @return 0 при успехе, -1 при ошибке. */ int blf_start_container(BLFContext *ctx, uint64_t timestamp); /** * @brief Завершает текущий контейнер, обновляя его заголовок. * @param ctx Контекст. * @return 0 при успехе, -1 при ошибке. */ int blf_end_container(BLFContext *ctx); /** * @brief Добавляет CAN-сообщение (устаревший формат VBLCANMessage). * @param ctx Контекст. * @param channel Номер канала. * @param id Идентификатор. * @param flags Флаги (направление, RTR). * @param dlc Длина данных (0-8). * @param data Данные (если NULL, заполняет нулями). * @param timestamp Временная метка в наносекундах. * @return 0 при успехе, -1 при ошибке. */ int blf_add_can_message(BLFContext *ctx, uint16_t channel, uint32_t id, uint8_t flags, uint8_t dlc, const uint8_t *data, uint64_t timestamp); /** * @brief Добавляет CAN-сообщение в расширенном формате (VBLCANMessage2). * @param ctx Контекст. * @param channel Номер канала. * @param id Идентификатор. * @param flags Флаги (направление, RTR). * @param dlc Длина данных (0-8). * @param data Данные (если NULL, заполняет нулями). * @param timestamp Временная метка в наносекундах. * @param frameLength Длительность сообщения в наносекундах. * @param bitCount Общее количество бит сообщения. * @return 0 при успехе, -1 при ошибке. */ int blf_add_can_message2(BLFContext *ctx, uint16_t channel, uint32_t id, uint8_t flags, uint8_t dlc, const uint8_t *data, uint64_t timestamp, uint32_t frameLength, uint8_t bitCount); /** * @brief Добавляет LIN-сообщение (устаревший тип). * @param ctx Контекст. * @param channel Номер канала. * @param id Идентификатор (6 бит). * @param dlc Длина данных. * @param data Данные. * @param dir Направление (LIN_DIR_RX / LIN_DIR_TX). * @param timestamp Временная метка в наносекундах. * @param checksum Контрольная сумма. * @return 0 при успехе, -1 при ошибке. */ int blf_add_lin_message_obsolete(BLFContext *ctx, uint16_t channel, uint8_t id, uint8_t dlc, const uint8_t *data, uint8_t dir, uint64_t timestamp, uint16_t checksum); /** * @brief Добавляет событие отсутствия ответа LIN. * @param ctx Контекст. * @param channel Номер канала. * @param id Идентификатор. * @param dlc Ожидаемая длина данных. * @param timestamp Временная метка в наносекундах. * @return 0 при успехе, -1 при ошибке. */ int blf_add_lin_send_error(BLFContext *ctx, uint16_t channel, uint8_t id, uint8_t dlc, uint64_t timestamp); /** * @brief Добавляет данные окружения (ENV_DATA). * @param ctx Контекст. * @param name Имя переменной (строка). * @param data Указатель на данные. * @param data_len Длина данных в байтах. * @param timestamp Временная метка в наносекундах. * @return 0 при успехе, -1 при ошибке. */ int blf_add_env_data(BLFContext *ctx, const char *name, const uint8_t *data, uint32_t data_len, uint64_t timestamp); /* Удобные обёртки, принимающие структуры с временем в миллисекундах */ int blf_add_can_message_struct(BLFContext *ctx, const CanMessageStruct *msg); int blf_add_can_message2_struct(BLFContext *ctx, const CanMessageStruct *msg); int blf_add_lin_message_struct(BLFContext *ctx, const LinMessageStruct *msg); int blf_add_lin_send_error_struct(BLFContext *ctx, const LinSendErrorStruct *err); int blf_add_env_data_struct(BLFContext *ctx, const EnvDataStruct *env); /** * @brief Закрывает BLF-файл, обновляет заголовок. * @param ctx Контекст. * @return 0 при успехе, -1 при ошибке. */ int blf_close(BLFContext *ctx); #endif /* BLF_H */