Refactor DLT_Utilities to use STL containers, removing manual memory management && Add a debug output for command-line argument input

This commit is contained in:
LuChiChick 2026-04-30 20:49:57 +08:00
parent df949ce460
commit 3ec4327d45
4 changed files with 348 additions and 500 deletions

View File

@ -1,6 +1,18 @@
/**
*
* DLTv1 https://www.autosar.org/fileadmin/standards/R20-11/FO/AUTOSAR_PRS_LogAndTraceProtocol.pdf
* DLTv2 https://www.autosar.org/fileadmin/standards/R22-11/FO/AUTOSAR_PRS_LogAndTraceProtocol.pdf
* COVESA https://github.com/COVESA
* dlt-viewer开源项目 https://github.com/COVESA/dlt-viewer
* DLT文件结构设计定义 https://github.com/COVESA/dlt-daemon/blob/master/doc/dlt_design_specification.md
*/
#ifndef __DLT_UTILITIES_HPP__ #ifndef __DLT_UTILITIES_HPP__
#define __DLT_UTILITIES_HPP__ #define __DLT_UTILITIES_HPP__
#include "vector"
#include "string"
extern "C" extern "C"
{ {
#include "stdint.h" #include "stdint.h"
@ -8,13 +20,14 @@ extern "C"
} }
// DLT 类型定义 // DLT 类型定义
namespace DLT_Type class DLT_Log
{ {
#pragma pack(1) // 紧凑字节对齐 protected:
// 紧凑字节对齐
#pragma pack(1)
/** // The structure of the DLT file storage header. This header is used before each stored DLT message.
* The structure of the DLT file storage header. This header is used before each stored DLT message. // 存储头不是AUTOSAR规范定义的一部分来自COVESA开源项目实现
*/
typedef struct typedef struct
{ {
char pattern[4]; /**< This pattern should be DLT0x01 */ char pattern[4]; /**< This pattern should be DLT0x01 */
@ -23,6 +36,7 @@ namespace DLT_Type
char ecu[4]; /**< The ECU id is added, if it is not already in the DLT message itself */ char ecu[4]; /**< The ECU id is added, if it is not already in the DLT message itself */
} DltStorageHeader; } DltStorageHeader;
// The structure of the DLT standard header. This header is used in each DLT message.
typedef struct typedef struct
{ {
struct struct
@ -39,9 +53,7 @@ namespace DLT_Type
uint16_t len; /**< Length of the complete message, without storage header */ uint16_t len; /**< Length of the complete message, without storage header */
} DltStandardHeader; } DltStandardHeader;
/** // The structure of the DLT extra header parameters. Each parameter is sent only if enabled in htyp.
* The structure of the DLT extra header parameters. Each parameter is sent only if enabled in htyp.
*/
typedef struct typedef struct
{ {
char ecu[4]; /**< ECU id */ char ecu[4]; /**< ECU id */
@ -49,39 +61,21 @@ namespace DLT_Type
uint32_t tmsp; /**< Timestamp since system start in 0.1 milliseconds */ uint32_t tmsp; /**< Timestamp since system start in 0.1 milliseconds */
} DltStandardHeaderExtra; } DltStandardHeaderExtra;
/** // The structure of the DLT extended header. This header is only sent if enabled in htyp parameter.
* The structure of the DLT extended header. This header is only sent if enabled in htyp parameter.
*/
typedef struct typedef struct
{ {
struct struct
{ {
uint8_t VERB : 1; // (Verbose) 冗余模式 1 启用 0 不启用 uint8_t VERB : 1; // (Verbose) 冗余模式 1 启用 0 不启用
uint8_t MSTP : 3; // (Message Type) uint8_t MSTP : 3; // (Message Type) 消息类型
uint8_t MTIN : 4; // (Message Type Info) uint8_t MTIN : 4; // (Message Type Info) 选定类型下的消息条目
} msin; /**< messsage info */ } msin; /**< messsage info */
uint8_t noar; /**< number of arguments */ uint8_t noar; /**< number of arguments */
char apid[4]; /**< application id */ char apid[4]; /**< application id */
char ctid[4]; /**< context id */ char ctid[4]; /**< context id */
} DltExtendedHeader; } DltExtendedHeader;
#pragma pack(0) // 恢复字节对齐 #pragma pack(0) // 恢复字节对齐
// DLT 错误信息枚举
typedef enum
{
DLT_ERROR_NONE = 0, // 无错误
DLT_ERROR_NULL_POINTER, // 空指针
DLT_ERROR_FILE_OPEN_FAILED, // 文件打开失败
DLT_ERROR_FILE_READ_FAILED, // 文件读取失败
DLT_ERROR_FILE_CREATE_FAILED, // 文件创建失败
DLT_ERROR_END_OF_FILE, // 文件结尾
DLT_ERROR_INVALID_HEADER, // 非法头
DLT_ERROR_INCOMPLETE_DATA, // 数据不完整
DLT_ERROR_MEM_ALLOCATE_FAILED, // 内存分配失败
DLT_ERROR_MSG_LIST_EMPTY, // 消息列表为空
} DLT_Err;
// DLT消息条目结构定义 // DLT消息条目结构定义
typedef struct typedef struct
{ {
@ -89,82 +83,39 @@ namespace DLT_Type
DltStandardHeader standard_header; // 标准头 DltStandardHeader standard_header; // 标准头
DltStandardHeaderExtra standard_header_extra; // 标准头额外内容 DltStandardHeaderExtra standard_header_extra; // 标准头额外内容
DltExtendedHeader extendedheader; // 扩展头 DltExtendedHeader extendedheader; // 扩展头
size_t payload_length; // 消息长度 std::vector<uint8_t> payload; // 载荷
uint8_t *payload_buffer; // 载荷 } DLT_Msg;
} DLT_Msg; // 文件中的消息条目
// DLT消息链表节点 protected:
typedef struct DLT_Msg_Node_Struct // 最长载荷长度
{ size_t private_max_payload_len = 0;
DLT_Msg Msg; // 消息列表
DLT_Msg_Node_Struct *p_next; std::vector<DLT_Msg> private_msg_list;
} DLT_Msg_Node;
}
// DLT 日志类
class DLT_Log
{
private:
size_t loaded_msg_count; // 消息条目计数
size_t max_payload_len; // 最长载荷长度
size_t mem_use; // 存储占用
DLT_Type::DLT_Msg_Node *Msg_List_Head; // 消息列表头
DLT_Type::DLT_Msg_Node *Msg_List_End; // 消息列表尾
/**
* @brief dlt头
* @param p_file
* @param Msg
* @return DLT_Type::DLT_Err
*/
DLT_Type::DLT_Err dlt_file_read_header(FILE *p_file, DLT_Type::DLT_Msg *Msg);
/**
* @brief dlt载荷
* @param p_file
* @param Msg
* @return DLT_Type::DLT_Err
*/
DLT_Type::DLT_Err dlt_file_read_payload(FILE *p_file, DLT_Type::DLT_Msg *Msg);
public: public:
DLT_Log(); // 构造函数 // 只读引用
~DLT_Log(); // 析构函数 const std::vector<DLT_Msg> &msg_list = this->private_msg_list;
/** const size_t &max_payload_len = this->private_max_payload_len;
* @brief DLT消息
* @param file_name_str
* @return DLT_Type::DLT_Err
*/
DLT_Type::DLT_Err load_from_file(const char *file_name_str);
/** /**
* @brief * @brief
* @param p_msg_list * @param path_to_file
* @return * @return std::string
*/ */
size_t get_msg_list(DLT_Type::DLT_Msg_Node *(&p_msg_list)); std::string Load_From_File(const char *path_to_file);
/** /**
* @brief * @brief CSV格式导出到文件
* @param null * @param path_to_file
* @return DLT_Type::DLT_Err * @return std::string
*/ */
DLT_Type::DLT_Err sort_msg_list(void); std::string Export_CSV(const char *path_to_file);
/** // 对消息列表进行排序
* @brief CSV void Sort(void);
* @param file_name_str
* @return DLT_Type::DLT_Err
*/
DLT_Type::DLT_Err export_to_csv(const char *file_name_str);
/** // 清除缓存的信息
* @brief void Clear(void);
* @param null
* @return null
*/
void clear(void);
}; };
#endif #endif

View File

@ -1,5 +1,6 @@
#include "Command_Solve.hpp" #include "Command_Solve.hpp"
#include "DLT_Utilities.hpp" #include "DLT_Utilities.hpp"
#include "Global_Variables.hpp"
extern "C" extern "C"
{ {
@ -21,21 +22,21 @@ void Pre_Command_Solve(void)
if (argc <= 1) if (argc <= 1)
return; return;
DLT_Type::DLT_Err err; // 输出测试用参数信息
std::wstring cmd_string;
for (int count = 0; count < argc; count++)
{
// int size_needed = WideCharToMultiByte(CP_UTF8, 0, argv[count], -1, NULL, 0, NULL, NULL);
// char *strTo = (char *)malloc(size_needed);
// WideCharToMultiByte(CP_UTF8, 0, argv[count], -1, strTo, size_needed, NULL, NULL);
int size_needed = WideCharToMultiByte(CP_UTF8, 0, argv[1], -1, NULL, 0, NULL, NULL); // printf("Arg[%d]:%s\n", count, strTo);
char *strTo = (char *)malloc(size_needed); // free(strTo);
WideCharToMultiByte(CP_UTF8, 0, argv[1], -1, &strTo[0], size_needed, NULL, NULL);
err = File.load_from_file(strTo); wchar_t Num_str[100] = {'\0'};
wsprintf(Num_str, L"%d", count);
cmd_string += std::wstring(L"Arg[") + Num_str + L"]:" + argv[count] + L"\n";
}
DLT_Type::DLT_Msg_Node *p_list; MessageBoxW(Main_Window_hWnd, (L"[Debug] Argument input:\n" + cmd_string).c_str(), L"", MB_OK);
File.get_msg_list(p_list);
free(strTo);
err = File.export_to_csv("test.csv");
if (err == DLT_Type::DLT_ERROR_NONE)
return;
} }

View File

@ -7,121 +7,87 @@ extern "C"
#include "sys/time.h" #include "sys/time.h"
} }
// 构造函数 /**
DLT_Log::DLT_Log() * @brief
* @param path_to_file
* @return std::string
*/
std::string DLT_Log::Load_From_File(const char *path_to_file)
{ {
// 初始化内容 // 尝试打开文件
this->loaded_msg_count = 0; FILE *pFile = fopen(path_to_file, "rb");
this->max_payload_len = 0; if (pFile == nullptr)
this->Msg_List_Head = nullptr; return "File \"" + std::string(path_to_file) + "\" open failed.";
this->Msg_List_End = nullptr;
}
// 析构函数 // Lambda 读取头
DLT_Log::~DLT_Log() auto Lambda_Read_Header = [&](DLT_Msg &Msg) -> std::string
{
clear();
}
// 清理请求的存储并恢复初始状态
void DLT_Log::clear(void)
{
if (this->Msg_List_Head == nullptr)
return;
// 释放分配的空间
while (this->Msg_List_Head != nullptr)
{ {
DLT_Type::DLT_Msg_Node *p_target = this->Msg_List_Head;
this->Msg_List_Head = this->Msg_List_Head->p_next;
if (p_target->Msg.payload_buffer != nullptr)
free(p_target->Msg.payload_buffer);
free(p_target);
}
// 初始化内容
this->loaded_msg_count = 0;
this->max_payload_len = 0;
this->mem_use = 0;
this->Msg_List_Head = nullptr;
this->Msg_List_End = nullptr;
}
DLT_Type::DLT_Err DLT_Log::dlt_file_read_header(FILE *p_file, DLT_Type::DLT_Msg *Msg)
{
if (Msg == nullptr)
return DLT_Type::DLT_ERROR_NULL_POINTER;
// 存储头
{
// 读取存储头 // 读取存储头
if (fread(&(Msg->storage_header), sizeof(Msg->storage_header), 1, p_file) != 1) if (fread(&(Msg.storage_header), sizeof(Msg.storage_header), 1, pFile) != 1)
{ {
if (feof(p_file)) if (feof(pFile))
return DLT_Type::DLT_ERROR_END_OF_FILE; return "Unexpected EOF.";
else else
return DLT_Type::DLT_ERROR_FILE_READ_FAILED; return "File read failed.";
} }
// 检查存储头 // 检查存储头
if (memcmp(Msg->storage_header.pattern, "DLT\x01", 4)) if (memcmp(Msg.storage_header.pattern, "DLT\x01", 4))
return DLT_Type::DLT_ERROR_INVALID_HEADER; return "Invalid storage header pattern.Must be \"DLT0x01\".";
// 读取标准头
if (fread(&(Msg.standard_header), sizeof(Msg.standard_header), 1, pFile) != 1)
{
if (feof(pFile))
return "Unexpected EOF.";
else
return "File read failed.";
} }
// 标准头 // 检查标准头协议版本
{ if (Msg.standard_header.htyp.VERS != 0x01)
// 读取标准头 return "Unsupported protocol version.";
if (fread(&(Msg->standard_header), sizeof(Msg->standard_header), 1, p_file) != 1)
{
if (feof(p_file))
return DLT_Type::DLT_ERROR_INCOMPLETE_DATA;
else
return DLT_Type::DLT_ERROR_FILE_READ_FAILED;
}
// 反向拼接len字段 // 反向拼接len字段
// [PRS_Dlt_00091] ⌈The Standard Header and the Extended Header shall be in big endian format (MSB first).⌋ (RS_LT_00016,RS_LT_00013) // [PRS_Dlt_00091] ⌈The Standard Header and the Extended Header shall be in big endian format (MSB first).⌋ (RS_LT_00016,RS_LT_00013)
// DLT标准头是大端序与小端序存储的uint16正好相反所以需要反向 // DLT标准头是大端序与小端序存储的uint16正好相反所以需要反向
{ {
uint16_t len_swap; uint16_t len_swap;
*((uint8_t *)&len_swap) = *(((uint8_t *)&Msg->standard_header.len) + 1); *((uint8_t *)&len_swap) = *(((uint8_t *)&Msg.standard_header.len) + 1);
*(((uint8_t *)&len_swap) + 1) = *((uint8_t *)&Msg->standard_header.len); *(((uint8_t *)&len_swap) + 1) = *((uint8_t *)&Msg.standard_header.len);
Msg->standard_header.len = len_swap; Msg.standard_header.len = len_swap;
}
} }
// 消息头长度统计 // 消息头长度统计
size_t msg_header_len = sizeof(Msg->standard_header); size_t msg_header_len = sizeof(Msg.standard_header);
// 标准头扩展部分 // 标准头扩展部分
{ {
// 含有额外的ECU ID // 含有额外的ECU ID
if (Msg->standard_header.htyp.WEID) if (Msg.standard_header.htyp.WEID)
{ {
msg_header_len += sizeof(Msg->standard_header_extra.ecu); msg_header_len += sizeof(Msg.standard_header_extra.ecu);
if (fread(&(Msg->standard_header_extra.ecu), sizeof(Msg->standard_header_extra.ecu), 1, p_file) != 1) if (fread(&(Msg.standard_header_extra.ecu), sizeof(Msg.standard_header_extra.ecu), 1, pFile) != 1)
{ {
if (feof(p_file)) if (feof(pFile))
return DLT_Type::DLT_ERROR_INCOMPLETE_DATA; return "Unexpected EOF.";
else else
return DLT_Type::DLT_ERROR_FILE_READ_FAILED; return "File read failed.";
} }
} }
// 含有额外的 Session ID (会话ID) // 含有额外的 Session ID (会话ID)
if (Msg->standard_header.htyp.WSID) if (Msg.standard_header.htyp.WSID)
{ {
msg_header_len += sizeof(Msg->standard_header_extra.seid); msg_header_len += sizeof(Msg.standard_header_extra.seid);
if (fread(&(Msg->standard_header_extra.seid), sizeof(Msg->standard_header_extra.seid), 1, p_file) != 1) if (fread(&(Msg.standard_header_extra.seid), sizeof(Msg.standard_header_extra.seid), 1, pFile) != 1)
{ {
if (feof(p_file)) if (feof(pFile))
return DLT_Type::DLT_ERROR_INCOMPLETE_DATA; return "Unexpected EOF.";
else else
return DLT_Type::DLT_ERROR_FILE_READ_FAILED; return "File read failed.";
} }
// 反向拼接Session ID字段 // 反向拼接Session ID字段
@ -129,26 +95,26 @@ DLT_Type::DLT_Err DLT_Log::dlt_file_read_header(FILE *p_file, DLT_Type::DLT_Msg
{ {
uint32_t data_swap; uint32_t data_swap;
*((uint8_t *)&data_swap) = *(((uint8_t *)&Msg->standard_header_extra.seid) + 3); *((uint8_t *)&data_swap) = *(((uint8_t *)&Msg.standard_header_extra.seid) + 3);
*(((uint8_t *)&data_swap) + 1) = *(((uint8_t *)&Msg->standard_header_extra.seid) + 2); *(((uint8_t *)&data_swap) + 1) = *(((uint8_t *)&Msg.standard_header_extra.seid) + 2);
*(((uint8_t *)&data_swap) + 2) = *(((uint8_t *)&Msg->standard_header_extra.seid) + 1); *(((uint8_t *)&data_swap) + 2) = *(((uint8_t *)&Msg.standard_header_extra.seid) + 1);
*(((uint8_t *)&data_swap) + 3) = *((uint8_t *)&Msg->standard_header_extra.seid); *(((uint8_t *)&data_swap) + 3) = *((uint8_t *)&Msg.standard_header_extra.seid);
Msg->standard_header_extra.seid = data_swap; Msg.standard_header_extra.seid = data_swap;
} }
} }
// 含有额外的 timestamp (0.1ms 自系统启动后的时间计数) // 含有额外的 timestamp (0.1ms 自系统启动后的时间计数)
if (Msg->standard_header.htyp.WSID) if (Msg.standard_header.htyp.WSID)
{ {
msg_header_len += sizeof(Msg->standard_header_extra.tmsp); msg_header_len += sizeof(Msg.standard_header_extra.tmsp);
if (fread(&(Msg->standard_header_extra.tmsp), sizeof(Msg->standard_header_extra.tmsp), 1, p_file) != 1) if (fread(&(Msg.standard_header_extra.tmsp), sizeof(Msg.standard_header_extra.tmsp), 1, pFile) != 1)
{ {
if (feof(p_file)) if (feof(pFile))
return DLT_Type::DLT_ERROR_INCOMPLETE_DATA; return "Unexpected EOF.";
else else
return DLT_Type::DLT_ERROR_FILE_READ_FAILED; return "File read failed.";
} }
// 反向拼接Session ID字段 // 反向拼接Session ID字段
@ -156,310 +122,181 @@ DLT_Type::DLT_Err DLT_Log::dlt_file_read_header(FILE *p_file, DLT_Type::DLT_Msg
{ {
uint32_t data_swap; uint32_t data_swap;
*((uint8_t *)&data_swap) = *(((uint8_t *)&Msg->standard_header_extra.tmsp) + 3); *((uint8_t *)&data_swap) = *(((uint8_t *)&Msg.standard_header_extra.tmsp) + 3);
*(((uint8_t *)&data_swap) + 1) = *(((uint8_t *)&Msg->standard_header_extra.tmsp) + 2); *(((uint8_t *)&data_swap) + 1) = *(((uint8_t *)&Msg.standard_header_extra.tmsp) + 2);
*(((uint8_t *)&data_swap) + 2) = *(((uint8_t *)&Msg->standard_header_extra.tmsp) + 1); *(((uint8_t *)&data_swap) + 2) = *(((uint8_t *)&Msg.standard_header_extra.tmsp) + 1);
*(((uint8_t *)&data_swap) + 3) = *((uint8_t *)&Msg->standard_header_extra.tmsp); *(((uint8_t *)&data_swap) + 3) = *((uint8_t *)&Msg.standard_header_extra.tmsp);
Msg->standard_header_extra.tmsp = data_swap; Msg.standard_header_extra.tmsp = data_swap;
} }
} }
} }
// 扩展头读取 // 扩展头读取
if (Msg->standard_header.htyp.UEH) if (Msg.standard_header.htyp.UEH)
{ {
msg_header_len += sizeof(Msg->extendedheader); msg_header_len += sizeof(Msg.extendedheader);
// 读取标扩展头 // 读取标扩展头
if (fread(&(Msg->extendedheader), sizeof(Msg->extendedheader), 1, p_file) != 1) if (fread(&(Msg.extendedheader), sizeof(Msg.extendedheader), 1, pFile) != 1)
{ {
if (feof(p_file)) if (feof(pFile))
return DLT_Type::DLT_ERROR_INCOMPLETE_DATA; return "Unexpected EOF.";
else else
return DLT_Type::DLT_ERROR_FILE_READ_FAILED; return "File read failed.";
} }
} }
// 计算Payload长度 // 分配payload空间并无错误信息返回
Msg->payload_length = Msg->standard_header.len - msg_header_len; Msg.payload.resize(Msg.standard_header.len - msg_header_len);
return std::string();
};
return DLT_Type::DLT_ERROR_NONE; // Lambda 读取载荷
} auto Lambda_Read_Payload = [&](DLT_Msg &Msg) -> std::string
DLT_Type::DLT_Err DLT_Log::dlt_file_read_payload(FILE *p_file, DLT_Type::DLT_Msg *Msg)
{
if (Msg == nullptr)
return DLT_Type::DLT_ERROR_NULL_POINTER;
if (Msg->payload_length == 0)
{ {
Msg->payload_buffer = nullptr; if (fread(&Msg.payload[0], Msg.payload.size(), 1, pFile) != 1)
return DLT_Type::DLT_ERROR_NONE;
}
// 读取Payload
Msg->payload_buffer = (uint8_t *)malloc(Msg->payload_length);
this->mem_use += Msg->payload_length;
if (Msg->payload_buffer == nullptr)
return DLT_Type::DLT_ERROR_MEM_ALLOCATE_FAILED;
if (fread(Msg->payload_buffer, Msg->payload_length, 1, p_file) != 1)
{ {
free(Msg->payload_buffer); if (feof(pFile))
this->mem_use -= Msg->payload_length; return "Unexpected EOF.";
Msg->payload_buffer = nullptr;
if (feof(p_file))
return DLT_Type::DLT_ERROR_INCOMPLETE_DATA;
else else
return DLT_Type::DLT_ERROR_FILE_READ_FAILED; return "File read failed.";
} }
return ::DLT_Type::DLT_ERROR_NONE; return std::string();
} };
DLT_Type::DLT_Err DLT_Log::load_from_file(const char *file_name_str) // 错误信息串
{ std::string err_str;
// 打开文件 // 循环解析文件
FILE *p_file = fopen(file_name_str, "rb"); while (true)
if (p_file == nullptr) {
return DLT_Type::DLT_ERROR_FILE_OPEN_FAILED; DLT_Msg Msg = {0};
// 解析消息内容 err_str = Lambda_Read_Header(Msg);
{ if (!err_str.empty())
DLT_Type::DLT_Err err = DLT_Type::DLT_ERROR_NONE;
while (1)
{
DLT_Type::DLT_Msg Msg = {0};
err = dlt_file_read_header(p_file, &Msg);
if (err != DLT_Type::DLT_ERROR_NONE)
{
if (err == DLT_Type::DLT_ERROR_END_OF_FILE)
break; break;
fclose(p_file);
return err;
}
err = dlt_file_read_payload(p_file, &Msg);
if (err != DLT_Type::DLT_ERROR_NONE)
{
fclose(p_file);
return err;
}
DLT_Type::DLT_Msg_Node *p_target_msg = (DLT_Type::DLT_Msg_Node *)malloc(sizeof(DLT_Type::DLT_Msg_Node)); if (Msg.payload.size() > 0)
this->mem_use += sizeof(DLT_Type::DLT_Msg_Node); err_str = Lambda_Read_Payload(Msg);
if (p_target_msg == nullptr)
{
this->mem_use -= sizeof(DLT_Type::DLT_Msg_Node);
fclose(p_file);
return DLT_Type::DLT_ERROR_MEM_ALLOCATE_FAILED;
}
p_target_msg->p_next = nullptr;
p_target_msg->Msg = Msg;
if (this->Msg_List_Head == nullptr) if (err_str.empty() == true)
{ {
this->Msg_List_Head = this->Msg_List_End = p_target_msg; if (Msg.payload.size() > this->private_max_payload_len)
this->private_max_payload_len = Msg.payload.size();
this->private_msg_list.push_back(Msg);
} }
else else
{ break;
this->Msg_List_End->p_next = p_target_msg;
this->Msg_List_End = p_target_msg; // 读取结束判定
if (fgetc(pFile) == EOF)
break;
else
fseek(pFile, -1, SEEK_CUR);
} }
// 统计最长长度 fclose(pFile);
if (Msg.payload_length > this->max_payload_len) return err_str;
this->max_payload_len = Msg.payload_length;
this->loaded_msg_count++;
}
}
fclose(p_file);
return DLT_Type::DLT_ERROR_NONE;
} }
size_t DLT_Log::get_msg_list(DLT_Type::DLT_Msg_Node *(&p_msg_list)) /**
* @brief CSV格式导出到文件
* @param path_to_file
* @return std::string
*/
std::string DLT_Log::Export_CSV(const char *path_to_file)
{ {
if (this->loaded_msg_count != 0) // 尝试打开文件
p_msg_list = this->Msg_List_Head; FILE *pFile = fopen(path_to_file, "wb");
else if (pFile == nullptr)
p_msg_list = nullptr; return "File \"" + std::string(path_to_file) + "\" open failed.";
return this->loaded_msg_count;
}
DLT_Type::DLT_Err DLT_Log::sort_msg_list(void)
{
// 临时分配的排序用指针数组
DLT_Type::DLT_Msg_Node **Node_P_Arr = (DLT_Type::DLT_Msg_Node **)malloc(sizeof(DLT_Type::DLT_Msg_Node *) * this->loaded_msg_count);
if (Node_P_Arr == nullptr)
return DLT_Type::DLT_ERROR_MEM_ALLOCATE_FAILED;
// 填充地址数组
{
DLT_Type::DLT_Msg_Node *p_target_node = this->Msg_List_Head;
for (size_t count = 0; count < loaded_msg_count; count++)
{
Node_P_Arr[count] = p_target_node;
p_target_node = p_target_node->p_next;
}
}
// qsort排序
qsort(Node_P_Arr,
loaded_msg_count,
sizeof(DLT_Type::DLT_Msg_Node *),
// 升序,小时间戳在前
[](const void *param1, const void *param2) -> int
{
DLT_Type::DLT_Msg_Node *Node1 = *(DLT_Type::DLT_Msg_Node **)param1;
DLT_Type::DLT_Msg_Node *Node2 = *(DLT_Type::DLT_Msg_Node **)param2;
if (Node1->Msg.storage_header.seconds > Node2->Msg.storage_header.seconds)
return 1;
else if (Node1->Msg.storage_header.seconds == Node2->Msg.storage_header.seconds)
{
if (Node1->Msg.storage_header.microseconds > Node2->Msg.storage_header.microseconds)
return 1;
else if (Node1->Msg.storage_header.microseconds == Node2->Msg.storage_header.microseconds)
{
// 存在0.1ms时间戳
if (Node1->Msg.standard_header.htyp.WTMS && Node2->Msg.standard_header.htyp.WTMS)
{
if (Node1->Msg.standard_header_extra.tmsp > Node2->Msg.standard_header_extra.tmsp)
return 1;
else if (Node1->Msg.standard_header_extra.tmsp == Node2->Msg.standard_header_extra.tmsp)
return 0;
else if (Node1->Msg.standard_header_extra.tmsp < Node2->Msg.standard_header_extra.tmsp)
return -1;
}
else
return 0;
}
else
return -1;
}
else
return -1;
return 0;
});
// 重新连接消息列表
{
this->Msg_List_Head = Node_P_Arr[0];
this->Msg_List_End = Node_P_Arr[this->loaded_msg_count - 1];
this->Msg_List_End->p_next = nullptr;
DLT_Type::DLT_Msg_Node *p_target = Node_P_Arr[0];
for (size_t count = 1; count < this->loaded_msg_count; count++)
{
p_target->p_next = Node_P_Arr[count];
p_target = p_target->p_next;
}
}
// 释放空间
free(Node_P_Arr);
return DLT_Type::DLT_ERROR_NONE;
}
DLT_Type::DLT_Err DLT_Log::export_to_csv(const char *file_name_str)
{
FILE *p_file = fopen(file_name_str, "wb");
if (p_file == nullptr)
return DLT_Type::DLT_ERROR_FILE_CREATE_FAILED;
// 打印首行 // 打印首行
{ {
fprintf(p_file, "Index,Date&Time(Local),Timestamp,Count,ECU ID,Application ID,Context ID ,Session ID,Type,Sub Type,Mode,#Args,Payload,"); fprintf(pFile, "Index,Date&Time(Local),Timestamp,Count,ECU ID,Application ID,Context ID ,Session ID,Type,Sub Type,Mode,#Args,Payload,");
for (size_t count = 0; count < this->max_payload_len; count++) for (size_t count = 0; count < this->max_payload_len; count++)
fprintf(p_file, "B%d,", count); fprintf(pFile, "B%d,", count);
fseek(p_file, -1, SEEK_CUR); fseek(pFile, -1, SEEK_CUR);
fprintf(p_file, "\r\n"); fprintf(pFile, "\r\n");
} }
// 遍历每行数据 // 遍历每行数据
DLT_Type::DLT_Msg_Node *p_msg = this->Msg_List_Head; size_t line_count = 0;
for (size_t line_count = 0; line_count < this->loaded_msg_count; line_count++) for (auto Msg : this->private_msg_list)
{ {
// 输出索引号 // 输出索引号
fprintf(p_file, "%d,", line_count); fprintf(pFile, "%d,", line_count);
// 输出日期和时间 // 输出日期和时间
{ {
time_t timestamp = (time_t)p_msg->Msg.storage_header.seconds; time_t timestamp = (time_t)Msg.storage_header.seconds;
struct tm *time_struct = localtime(&timestamp); struct tm *time_struct = localtime(&timestamp);
char time_str[100] = {'\0'}; char time_str[100] = {'\0'};
// 格式化为 "YY/MM/DD HH:MM:SS" // 格式化为 "YY/MM/DD HH:MM:SS"
strftime(time_str, sizeof(time_str), "%Y/%m/%d %H:%M:%S", time_struct); strftime(time_str, sizeof(time_str), "%Y/%m/%d %H:%M:%S", time_struct);
fprintf(p_file, "%s.%d,", time_str, p_msg->Msg.storage_header.microseconds); fprintf(pFile, "%s.%d,", time_str, Msg.storage_header.microseconds);
} }
// 输出头附加信息 // 输出头附加信息
{ {
// 存在扩展时间戳 // 存在扩展时间戳
if (p_msg->Msg.standard_header.htyp.WTMS) if (Msg.standard_header.htyp.WTMS)
{ {
/**< Timestamp since system start in 0.1 milliseconds */ /**< Timestamp since system start in 0.1 milliseconds */
char time_str[20]; char time_str[20];
sprintf(time_str, "%d", p_msg->Msg.standard_header_extra.tmsp); sprintf(time_str, "%d", Msg.standard_header_extra.tmsp);
if (strlen(time_str) > 4) if (strlen(time_str) > 4)
{ {
char *p_sec_end = time_str + strlen(time_str) - 4; char *p_sec_end = time_str + strlen(time_str) - 4;
// 输出秒 // 输出秒
for (char *p = time_str; p < p_sec_end; p++) for (char *p = time_str; p < p_sec_end; p++)
fputc(*p, p_file); fputc(*p, pFile);
// 输出剩余的时间 // 输出剩余的时间
fprintf(p_file, ".%s,", p_sec_end); fprintf(pFile, ".%s,", p_sec_end);
} }
else else
{ {
fprintf(p_file, "0."); fprintf(pFile, "0.");
for (int count = 4 - strlen(time_str); count > 0; count--) for (int count = 4 - strlen(time_str); count > 0; count--)
fputc('0', p_file); fputc('0', pFile);
fprintf(p_file, "%s,", time_str); fprintf(pFile, "%s,", time_str);
} }
} }
else else
fprintf(p_file, "N/A,"); fprintf(pFile, "N/A,");
// 消息计数 // 消息计数
fprintf(p_file, "%d,", p_msg->Msg.standard_header.mcnt); fprintf(pFile, "%d,", Msg.standard_header.mcnt);
// 存在扩展ECU ID // 存在扩展ECU ID
if (p_msg->Msg.standard_header.htyp.WEID) if (Msg.standard_header.htyp.WEID)
fprintf(p_file, "%.4s,", p_msg->Msg.standard_header_extra.ecu); fprintf(pFile, "%.4s,", Msg.standard_header_extra.ecu);
else else
fprintf(p_file, "%.4s,", p_msg->Msg.storage_header.ecu); fprintf(pFile, "%.4s,", Msg.storage_header.ecu);
// 输出 Apid 和 Ctid // 输出 Apid 和 Ctid
if (p_msg->Msg.standard_header.htyp.UEH) if (Msg.standard_header.htyp.UEH)
{ {
fprintf(p_file, "%.4s,", p_msg->Msg.extendedheader.apid); fprintf(pFile, "%.4s,", Msg.extendedheader.apid);
fprintf(p_file, "%.4s,", p_msg->Msg.extendedheader.ctid); fprintf(pFile, "%.4s,", Msg.extendedheader.ctid);
} }
else else
{ {
// skip apid && ctid // skip apid && ctid
fprintf(p_file, "N/A,N/A,"); fprintf(pFile, "N/A,N/A,");
} }
// 存在 Session ID // 存在 Session ID
if (p_msg->Msg.standard_header.htyp.WSID) if (Msg.standard_header.htyp.WSID)
fprintf(p_file, "%d,", p_msg->Msg.standard_header_extra.seid); fprintf(pFile, "%d,", Msg.standard_header_extra.seid);
else else
fprintf(p_file, "N/A,"); fprintf(pFile, "N/A,");
// 输出 Type 、Subtype 、Mode 、#Args // 输出 Type 、Subtype 、Mode 、#Args
if (p_msg->Msg.standard_header.htyp.UEH) if (Msg.standard_header.htyp.UEH)
{ {
const char *Type_str[] = {"log", "trace", "network", "control"}; const char *Type_str[] = {"log", "trace", "network", "control"};
const char *SubType_Str[][0xF] = { const char *SubType_Str[][0xF] = {
@ -474,31 +311,83 @@ DLT_Type::DLT_Err DLT_Log::export_to_csv(const char *file_name_str)
}; };
// Type && Subtype // Type && Subtype
fprintf(p_file, "%s,", Type_str[p_msg->Msg.extendedheader.msin.MSTP]); fprintf(pFile, "%s,", Type_str[Msg.extendedheader.msin.MSTP]);
fprintf(p_file, "%s,", SubType_Str[p_msg->Msg.extendedheader.msin.MSTP][(p_msg->Msg.extendedheader.msin.MTIN - 1) % 0xF]); fprintf(pFile, "%s,", SubType_Str[Msg.extendedheader.msin.MSTP][(Msg.extendedheader.msin.MTIN - 1) % 0xF]);
// Mode && #Args // Mode && #Args
fprintf(p_file, "%s,", p_msg->Msg.extendedheader.msin.VERB ? "verbose" : "non-verbose"); fprintf(pFile, "%s,", Msg.extendedheader.msin.VERB ? "verbose" : "non-verbose");
fprintf(p_file, "%d,", p_msg->Msg.extendedheader.noar); fprintf(pFile, "%d,", Msg.extendedheader.noar);
} }
else else
fprintf(p_file, "N/A,N/A,N/A,N/A,"); fprintf(pFile, "N/A,N/A,N/A,N/A,");
} }
// Payload概览 // Payload概览列跳过
fprintf(p_file, ","); fprintf(pFile, ",");
// 逐个打印 Payload // 逐个打印 Payload
for (size_t count = 0; count < p_msg->Msg.payload_length; count++) for (auto data_byte : Msg.payload)
fprintf(p_file, "%0X,", p_msg->Msg.payload_buffer[count]); fprintf(pFile, "%0X,", data_byte);
fseek(p_file, -1, SEEK_CUR); // 结束行
fprintf(p_file, "\r\n"); fseek(pFile, -1, SEEK_CUR);
fprintf(pFile, "\r\n");
p_msg = p_msg->p_next; line_count++;
} }
fclose(p_file); fclose(pFile);
return std::string();
return DLT_Type::DLT_ERROR_NONE; }
// 对消息列表进行排序
void DLT_Log::Sort(void)
{
// Quick Sort
qsort(&this->private_msg_list[0],
this->private_msg_list.size(),
sizeof(this->private_msg_list[0]),
[](const void *param1, const void *param2) -> int
{
const DLT_Msg *pMsg1 = (const DLT_Msg *)param1;
const DLT_Msg *pMsg2 = (const DLT_Msg *)param2;
if (pMsg1->storage_header.seconds > pMsg2->storage_header.seconds)
return 1;
else if (pMsg1->storage_header.seconds == pMsg2->storage_header.seconds)
{
if (pMsg1->storage_header.microseconds > pMsg2->storage_header.microseconds)
return 1;
else if (pMsg1->storage_header.microseconds == pMsg2->storage_header.microseconds)
{
// 存在0.1ms时间戳
if (pMsg1->standard_header.htyp.WTMS && pMsg2->standard_header.htyp.WTMS)
{
if (pMsg1->standard_header_extra.tmsp > pMsg2->standard_header_extra.tmsp)
return 1;
else if (pMsg1->standard_header_extra.tmsp == pMsg2->standard_header_extra.tmsp)
return 0;
else
return -1;
}
else
return 0;
}
else
return -1;
}
else
return -1;
return 0;
});
}
// 清除缓存的信息
void DLT_Log::Clear(void)
{
this->private_max_payload_len = 0;
// 清空内容
std::vector<DLT_Msg> empty_list;
this->private_msg_list.swap(empty_list);
} }

View File

@ -409,38 +409,45 @@ void Widgets::Control_Panel(const ImVec2 &size)
[&]() [&]()
{ {
DLT_Log Log; DLT_Log Log;
std::string err_str;
Input_File_Node *p_file_list = input_dlt_file_list_head; Input_File_Node *p_file_list = input_dlt_file_list_head;
DLT_Type::DLT_Err err;
while (p_file_list != nullptr) while (p_file_list != nullptr)
{ {
err = Log.load_from_file(p_file_list->file_name_str); err_str = Log.Load_From_File(p_file_list->file_name_str);
if (err != DLT_Type::DLT_ERROR_NONE) if (!err_str.empty())
break; break;
p_file_list = p_file_list->p_next; p_file_list = p_file_list->p_next;
} }
if (err != DLT_Type::DLT_ERROR_NONE) if (err_str.empty())
{ {
switch (err) Log.Sort();
{ err_str = Log.Export_CSV(export_file_path_str);
case DLT_Type::DLT_ERROR_FILE_OPEN_FAILED: // 文件打开失败
MessageBoxW(Main_Window_hWnd, L"文件打开失败,检查路径是否存在特殊字符", L"", MB_OK | MB_ICONERROR);
break;
default:
MessageBoxW(Main_Window_hWnd, L"文件加载失败", L"", MB_OK | MB_ICONERROR);
} }
}
else
{
// 排序后导出
Log.sort_msg_list();
err = Log.export_to_csv(export_file_path_str);
if (err == DLT_Type::DLT_ERROR_NONE) if (err_str.empty())
{
MessageBoxW(Main_Window_hWnd, L"导出完成", L"", MB_OK); MessageBoxW(Main_Window_hWnd, L"导出完成", L"", MB_OK);
}
else else
MessageBoxW(Main_Window_hWnd, L"导出失败,检查文件占用", L"", MB_OK | MB_ICONERROR); {
// 工具Lambda string 转 wstring
auto Lambda_String_To_WString = [](const std::string &str) -> std::wstring
{
if (str.empty())
return std::wstring();
int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.size(), nullptr, 0);
if (len <= 0)
return std::wstring();
std::wstring wstr(len, L'\0');
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.size(), &wstr[0], len);
return wstr;
};
// 输出错误信息
MessageBoxW(Main_Window_hWnd, (L"导出失败\n" + Lambda_String_To_WString(err_str)).c_str(), L"", MB_OK | MB_ICONERROR);
} }
export_confirmed = false; export_confirmed = false;
export_task_created = false; export_task_created = false;