BLF/APP/blf.h

396 lines
19 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.

/**
* @file blf.h
* @brief Заголовочный файл библиотеки для создания BLF-файлов (Vector).
* @details Определяет структуры, константы и функции для работы с форматом BLF.
* Поддерживает stdio (ПК) и FatFS (встраиваемые системы) через условную компиляцию.
* Не использует динамическую память контекст выделяется пользователем.
*
* @author (Ваше имя)
* @date 2026-03-20
*/
#ifndef BLF_H
#define BLF_H
#include <stdint.h>
/* -------------------------------------------------------------------------
* Обёртка для вывода ошибок (может быть переопределена до включения заголовка)
* ------------------------------------------------------------------------- */
#ifndef BLF_ERROR_PRINTF
#include <stdio.h>
#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; /* месяц (112) */
uint16_t dayOfWeek; /* день недели (06, 0 = воскресенье) */
uint16_t day; /* день месяца */
uint16_t hour; /* часы (023) */
uint16_t minute; /* минуты (059) */
uint16_t second; /* секунды (059) */
uint16_t milliseconds; /* миллисекунды (0999) */
} 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 <stdio.h>
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 */