This commit is contained in:
cfif 2026-03-25 17:10:56 +03:00
parent 89e6119ae6
commit 09fd02419a
3 changed files with 273 additions and 117 deletions

View File

@ -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) {

View File

@ -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);

View File

@ -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;
}
}
*/