diff --git a/APP/blf.c b/APP/blf.c index 58403ba..1301dd9 100644 --- a/APP/blf.c +++ b/APP/blf.c @@ -150,7 +150,7 @@ static void systemtime_add_ms(SYSTEMTIME *st, uint64_t ms) { * Реализация API-функций * ------------------------------------------------------------------------- */ -int blf_open(BLFContext *ctx, const char *filename, const SYSTEMTIME *startTime) { +int blf_open_ex(BLFContext *ctx, const char *filename, const SYSTEMTIME *startTime, int use_can_message2) { memset(ctx, 0, sizeof(*ctx)); if (startTime == NULL) { @@ -182,6 +182,9 @@ int blf_open(BLFContext *ctx, const char *filename, const SYSTEMTIME *startTime) /* Инициализируем lastObjectTime тем же временем (будет скорректировано при закрытии) */ ctx->header.lastObjectTime = *startTime; + /* Сохраняем флаг использования расширенного формата CAN */ + ctx->use_can_message2 = use_can_message2; + /* Запись заголовка в начало файла */ ctx->headerPos = blf_file_tell(ctx); if (ctx->headerPos < 0) { @@ -336,6 +339,66 @@ int blf_add_can_message(BLFContext *ctx, return 0; } +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) { + if (!ctx) { + BLF_ERROR_PRINTF("ERROR: blf_add_can_message2: null context\n"); + return -1; + } + if (dlc > 8) { + BLF_ERROR_PRINTF("ERROR: CAN message DLC > 8\n"); + return -1; + } + + VBLObjectHeader objHdr; + VBLCANMessage2 canMsg2; + + canMsg2.mChannel = channel; + canMsg2.mFlags = flags; + canMsg2.mDLC = dlc; + canMsg2.mID = id; + if (data && dlc <= 8) { + memcpy(canMsg2.mData, data, dlc); + if (dlc < 8) memset(canMsg2.mData + dlc, 0, 8 - dlc); + } else { + memset(canMsg2.mData, 0, 8); + } + canMsg2.mFrameLength = frameLength; + canMsg2.mBitCount = bitCount; + canMsg2.mReserved1 = 0; + canMsg2.mReserved2 = 0; + + objHdr.mBase.mSignature = BL_OBJ_SIGNATURE; + objHdr.mBase.mHeaderSize = sizeof(VBLObjectHeader); + objHdr.mBase.mHeaderVersion = 1; + objHdr.mBase.mObjectSize = sizeof(VBLObjectHeader) + sizeof(VBLCANMessage2); + objHdr.mBase.mObjectType = BL_OBJ_TYPE_CAN_MESSAGE2; + objHdr.mObjectFlags = BL_OBJ_FLAG_TIME_ONE_NANS; + objHdr.mClientIndex = 0; + objHdr.mObjectVersion = 0; + objHdr.mObjectTimeStamp = timestamp; + + if (blf_file_write(ctx, &objHdr, sizeof(objHdr)) != 0) { + BLF_ERROR_PRINTF("ERROR: Failed to write CAN message2 header\n"); + return -1; + } + if (blf_file_write(ctx, &canMsg2, sizeof(canMsg2)) != 0) { + BLF_ERROR_PRINTF("ERROR: Failed to write CAN message2 body\n"); + return -1; + } + + if (!ctx->in_container) ctx->objectCount++; + if (timestamp > ctx->maxTimestamp) ctx->maxTimestamp = timestamp; + return 0; +} + int blf_add_lin_message_obsolete(BLFContext *ctx, uint16_t channel, uint8_t id, @@ -516,12 +579,29 @@ int blf_add_env_data(BLFContext *ctx, /* Удобные обёртки (преобразование времени) */ int blf_add_can_message_struct(BLFContext *ctx, const CanMessageStruct *msg) { uint64_t ts_ns = (uint64_t)msg->timestamp * 1000000ULL; - return blf_add_can_message(ctx, msg->channel, msg->id, msg->flags, msg->dlc, msg->data, ts_ns); + + /* Если в структуре есть frameLength и bitCount и включен расширенный формат */ + if (ctx->use_can_message2 && (msg->frameLength > 0 || msg->bitCount > 0)) { + return blf_add_can_message2(ctx, msg->channel, msg->id, msg->flags, + msg->dlc, msg->data, ts_ns, + msg->frameLength, msg->bitCount); + } else { + return blf_add_can_message(ctx, msg->channel, msg->id, msg->flags, + msg->dlc, msg->data, ts_ns); + } +} + +int blf_add_can_message2_struct(BLFContext *ctx, const CanMessageStruct *msg) { + uint64_t ts_ns = (uint64_t)msg->timestamp * 1000000ULL; + return blf_add_can_message2(ctx, msg->channel, msg->id, msg->flags, + msg->dlc, msg->data, ts_ns, + msg->frameLength, msg->bitCount); } int blf_add_lin_message_struct(BLFContext *ctx, const LinMessageStruct *msg) { uint64_t ts_ns = (uint64_t)msg->timestamp * 1000000ULL; - return blf_add_lin_message_obsolete(ctx, msg->channel, msg->id, msg->dlc, msg->data, msg->dir, ts_ns, msg->checksum); + return blf_add_lin_message_obsolete(ctx, msg->channel, msg->id, msg->dlc, + msg->data, msg->dir, ts_ns, msg->checksum); } int blf_add_lin_send_error_struct(BLFContext *ctx, const LinSendErrorStruct *err) { diff --git a/APP/blf.h b/APP/blf.h index d2a3304..bbca80e 100644 --- a/APP/blf.h +++ b/APP/blf.h @@ -27,12 +27,14 @@ * ------------------------------------------------------------------------- */ #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_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) \ @@ -105,7 +107,7 @@ typedef struct PACKED { uint64_t mObjectTimeStamp; /* временная метка (наносекунды) */ } VBLObjectHeader; -/* Данные CAN-сообщения (16 байт) */ +/* Данные CAN-сообщения (устаревший тип, 16 байт) */ typedef struct PACKED { uint16_t mChannel; /* номер канала */ uint8_t mFlags; /* бит 7 = RTR, остальные – направление */ @@ -114,6 +116,23 @@ typedef struct PACKED { 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; @@ -165,6 +184,8 @@ typedef struct PACKED { uint8_t dlc; uint8_t data[8]; uint32_t timestamp; /* в миллисекундах */ + uint32_t frameLength; /* длительность сообщения в наносекундах (опционально) */ + uint8_t bitCount; /* количество бит сообщения (опционально) */ } CanMessageStruct; typedef struct PACKED { @@ -222,6 +243,7 @@ typedef struct { ContainerHeader container_hdr; /* заголовок открытого контейнера */ long container_hdr_pos; /* позиция заголовка контейнера в файле */ uint64_t container_timestamp; /* временная метка контейнера */ + int use_can_message2; /* флаг: использовать VBLCANMessage2 вместо VBLCANMessage */ } BLFContext; /* ------------------------------------------------------------------------- @@ -232,9 +254,22 @@ typedef struct { * @brief Инициализирует BLF-контекст и создаёт новый файл. * @param ctx Указатель на предварительно выделенный контекст. * @param filename Имя файла. + * @param startTime Время начала измерения. + * @param use_can_message2 Использовать расширенный формат CAN-сообщений (VBLCANMessage2). * @return 0 при успехе, -1 при ошибке. */ -int blf_open(BLFContext *ctx, const char *filename, const SYSTEMTIME *startTime); +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). @@ -252,7 +287,7 @@ int blf_start_container(BLFContext *ctx, uint64_t timestamp); int blf_end_container(BLFContext *ctx); /** - * @brief Добавляет CAN-сообщение. + * @brief Добавляет CAN-сообщение (устаревший формат VBLCANMessage). * @param ctx Контекст. * @param channel Номер канала. * @param id Идентификатор. @@ -270,6 +305,29 @@ int blf_add_can_message(BLFContext *ctx, 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 Контекст. @@ -323,6 +381,7 @@ int blf_add_env_data(BLFContext *ctx, /* Удобные обёртки, принимающие структуры с временем в миллисекундах */ 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); diff --git a/APP/main.c b/APP/main.c index 9d05dee..8399f1d 100644 --- a/APP/main.c +++ b/APP/main.c @@ -2,6 +2,7 @@ * @file main.c * @brief Пример использования библиотеки blf для создания BLF-файла. * @details Демонстрирует создание контейнера с CAN, LIN, LIN Error и ENV_DATA объектами. + * Показывает использование как старого формата CAN, так и расширенного VBLCANMessage2. * Контекст создаётся на стеке (без динамической памяти). * * Компиляция для обычного ПК: @@ -24,79 +25,44 @@ typedef struct { uint16_t channel5; } AdcSample; + int main() { BLFContext ctx; int ret; - // Задаём время начала измерения (1 января 2025 года, 00:00:00.000) -/* - SYSTEMTIME startTime = { - .year = 2025, - .month = 1, - .dayOfWeek = 3, // не критично - .day = 1, - .hour = 0, - .minute = 0, - .second = 0, - .milliseconds = 0 - }; -*/ - SYSTEMTIME startTime = { - .year = 0, - .month = 0, - .dayOfWeek = 0, // не критично - .day = 0, - .hour = 0, - .minute = 0, - .second = 0, - .milliseconds = 0 - }; + SYSTEMTIME startTime = {2025, 1, 3, 1, 0, 0, 0, 0}; - ret = blf_open(&ctx, "log.blf", &startTime); + // Открываем файл со старым форматом CAN (VBLCANMessage) + ret = blf_open_ex(&ctx, "log.blf", &startTime, 1); if (ret != 0) { BLF_ERROR_PRINTF("Failed to open file, exiting.\n"); return 1; } - // 2. Начинаем контейнер с временной меткой 0 секунда (1e9 нс) - if (blf_start_container(&ctx, 0000000000ULL) != 0) { + // Начинаем контейнер + if (blf_start_container(&ctx, 0) != 0) { BLF_ERROR_PRINTF("Failed to start container\n"); blf_close(&ctx); return 1; } - - // 3. Добавляем CAN-сообщение -/* + // Добавляем CAN сообщения в старом формате CanMessageStruct canMsg = { - .channel = 1, - .id = 0x538, - .flags = CAN_MSG_FLAGS(CAN_DIR_RX, 0), - .dlc = 8, - .data = {0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22}, - .timestamp = 9000 // 9 секунд (миллисекунды) - }; - - if (blf_add_can_message_struct(&ctx, &canMsg) != 0) { - BLF_ERROR_PRINTF("Failed to add CAN message\n"); - blf_close(&ctx); - return 1; - } -*/ - - CanMessageStruct canMsg = { - .channel = 1, + .channel = 2, .id = 0x3F1, .flags = CAN_MSG_FLAGS(CAN_DIR_RX, 0), .dlc = 8, - .data = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, - .timestamp = 0 // 9 секунд (миллисекунды) + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + .timestamp = 0 + // frameLength и bitCount не используются в старом формате }; - uint8_t j = 0; + int j = 0; + int k = 0; - for (uint32_t i = 0; i < 100000; ++i) { + for (uint32_t i = 0; i < 10000; ++i) { + // Заполняем данные canMsg.data[0] = j; canMsg.data[1] = j / 2; canMsg.data[2] = j / 3; @@ -109,84 +75,135 @@ int main() { canMsg.timestamp += 100; if (blf_add_can_message_struct(&ctx, &canMsg) != 0) { - BLF_ERROR_PRINTF("Failed to add CAN message\n"); - blf_close(&ctx); return 1; } - ++j; + ++k; - if (j >= 100) { - j = 0; + if (k > 100) { + k = 0; + ++j; + if (j >= 100) { + j = 0; + } } } -/* - // 4. Добавляем LIN-сообщение - LinMessageStruct linMsg = { - .channel = 1, - .id = 0x45, - .dlc = 4, - .data = {0xAA, 0xBB, 0xCC, 0xDD}, - .dir = LIN_DIR_TX, - .timestamp = 9100, - .checksum = 0x5678 - }; - if (blf_add_lin_message_struct(&ctx, &linMsg) != 0) { - BLF_ERROR_PRINTF("Failed to add LIN message\n"); - blf_close(&ctx); - return 1; - } - - // 5. Добавляем LIN-ошибку отсутствия ответа - LinSendErrorStruct sendErr = { - .channel = 1, - .id = 0x12, - .dlc = 8, - .timestamp = 9200 - }; - if (blf_add_lin_send_error_struct(&ctx, &sendErr) != 0) { - BLF_ERROR_PRINTF("Failed to add LIN send error\n"); - blf_close(&ctx); - return 1; - } - - // 6. Добавляем данные окружения (АЦП) - AdcSample samples; - samples.channel1 = (uint16_t) (1); - samples.channel2 = (uint16_t) (2); - samples.channel3 = (uint16_t) (3); - samples.channel4 = (uint16_t) (4); - samples.channel5 = (uint16_t) (5); - - EnvDataStruct envData = { - .name = "ADC", - .data = (uint8_t *) &samples, - .data_len = sizeof(samples), - .timestamp = 9300 - }; - if (blf_add_env_data_struct(&ctx, &envData) != 0) { - BLF_ERROR_PRINTF("Failed to add ENV_DATA\n"); - blf_close(&ctx); - return 1; - } -*/ - - // 7. Завершаем контейнер + // Завершаем контейнер if (blf_end_container(&ctx) != 0) { BLF_ERROR_PRINTF("Failed to end container\n"); blf_close(&ctx); return 1; } - // 8. Закрываем файл (заголовок обновляется автоматически) + // Закрываем файл + ret = blf_close(&ctx); + if (ret != 0) { + BLF_ERROR_PRINTF("Failed to close file\n"); + return 1; + } + return 0; +} + +/* +int main() { + BLFContext ctx; + int ret; + + // Время начала измерения (1 января 2025 года, 00:00:00.000) + SYSTEMTIME startTime = { + .year = 2025, + .month = 1, + .dayOfWeek = 3, + .day = 1, + .hour = 0, + .minute = 0, + .second = 0, + .milliseconds = 0 + }; + + // Открываем файл с поддержкой расширенного формата CAN (VBLCANMessage2) + ret = blf_open_ex(&ctx, "log.blf", &startTime, 1); + if (ret != 0) { + BLF_ERROR_PRINTF("Failed to open file, exiting.\n"); + return 1; + } + + BLF_ERROR_PRINTF("Using extended CAN format (VBLCANMessage2)\n"); + + // Начинаем контейнер + if (blf_start_container(&ctx, 0) != 0) { + BLF_ERROR_PRINTF("Failed to start container\n"); + blf_close(&ctx); + return 1; + } + + // Добавляем CAN-сообщения с дополнительной информацией о длительности кадра + CanMessageStruct canMsg = { + .channel = 1, + .id = 0x3F1, + .flags = CAN_MSG_FLAGS(CAN_DIR_RX, 0), + .dlc = 8, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + .timestamp = 0, + .frameLength = 6200, // 6.2 мкс длительность сообщения + .bitCount = 108 // 108 бит общее количество + }; + + uint8_t j = 0; + + for (uint32_t i = 0; i < 10000; ++i) { + // Заполняем данные + canMsg.data[0] = j; + canMsg.data[1] = j / 2; + canMsg.data[2] = j / 3; + canMsg.data[3] = j / 4; + canMsg.data[4] = j / 5; + canMsg.data[5] = j / 6; + canMsg.data[6] = j / 7; + canMsg.data[7] = j / 8; + + canMsg.timestamp += 100; // каждые 100 мс + + // Используем расширенную функцию добавления CAN-сообщения + if (blf_add_can_message2_struct(&ctx, &canMsg) != 0) { + BLF_ERROR_PRINTF("Failed to add CAN message2\n"); + blf_close(&ctx); + return 1; + } + + ++j; + if (j >= 100) { + j = 0; + } + + // Периодически выводим прогресс + if (i % 10000 == 0) { + BLF_ERROR_PRINTF("Added %u messages (frameLength=%u ns, bitCount=%u)\n", + i, canMsg.frameLength, canMsg.bitCount); + } + } + + + // Завершаем контейнер + if (blf_end_container(&ctx) != 0) { + BLF_ERROR_PRINTF("Failed to end container\n"); + blf_close(&ctx); + return 1; + } + + // Закрываем файл ret = blf_close(&ctx); if (ret != 0) { BLF_ERROR_PRINTF("Failed to close file\n"); return 1; } - BLF_ERROR_PRINTF("File log.blf created. Top-level objects: %d\n", ctx.objectCount); + BLF_ERROR_PRINTF("File log_extended.blf created successfully!\n"); + BLF_ERROR_PRINTF("Top-level objects: %d\n", ctx.objectCount); + BLF_ERROR_PRINTF("Used extended CAN format (ObjectType=%d)\n", BL_OBJ_TYPE_CAN_MESSAGE2); + return 0; -} \ No newline at end of file +} +*/ \ No newline at end of file