From 3ec4327d451fb494f50727e066700db6baba74fc Mon Sep 17 00:00:00 2001 From: LuChiChick <1084116302@qq.com> Date: Thu, 30 Apr 2026 20:49:57 +0800 Subject: [PATCH] Refactor DLT_Utilities to use STL containers, removing manual memory management && Add a debug output for command-line argument input --- Inc/DLT_Utilities.hpp | 141 +++------- Src/Command_Solve.cpp | 29 +- Src/DLT_Utilities.cpp | 633 +++++++++++++++++------------------------- Src/UI_Layout.cpp | 45 +-- 4 files changed, 348 insertions(+), 500 deletions(-) diff --git a/Inc/DLT_Utilities.hpp b/Inc/DLT_Utilities.hpp index aa1f8de..76a90e3 100644 --- a/Inc/DLT_Utilities.hpp +++ b/Inc/DLT_Utilities.hpp @@ -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__ #define __DLT_UTILITIES_HPP__ +#include "vector" +#include "string" + extern "C" { #include "stdint.h" @@ -8,13 +20,14 @@ extern "C" } // 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 { 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 */ } DltStorageHeader; + // The structure of the DLT standard header. This header is used in each DLT message. typedef struct { struct @@ -39,9 +53,7 @@ namespace DLT_Type uint16_t len; /**< Length of the complete message, without storage header */ } 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 { char ecu[4]; /**< ECU id */ @@ -49,39 +61,21 @@ namespace DLT_Type uint32_t tmsp; /**< Timestamp since system start in 0.1 milliseconds */ } 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 { struct { - uint8_t VERB : 1; // (Verbose) 冗余模式 1 启用 0 不启用 - uint8_t MSTP : 3; // (Message Type) - uint8_t MTIN : 4; // (Message Type Info) + uint8_t VERB : 1; // (Verbose) 冗余模式 1 启用 0 不启用 + uint8_t MSTP : 3; // (Message Type) 消息类型 + uint8_t MTIN : 4; // (Message Type Info) 选定类型下的消息条目 } msin; /**< messsage info */ uint8_t noar; /**< number of arguments */ char apid[4]; /**< application id */ char ctid[4]; /**< context id */ } DltExtendedHeader; - #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消息条目结构定义 typedef struct { @@ -89,82 +83,39 @@ namespace DLT_Type DltStandardHeader standard_header; // 标准头 DltStandardHeaderExtra standard_header_extra; // 标准头额外内容 DltExtendedHeader extendedheader; // 扩展头 - size_t payload_length; // 消息长度 - uint8_t *payload_buffer; // 载荷 - } DLT_Msg; // 文件中的消息条目 + std::vector payload; // 载荷 + } DLT_Msg; - // DLT消息链表节点 - typedef struct DLT_Msg_Node_Struct - { - DLT_Msg Msg; - DLT_Msg_Node_Struct *p_next; - } 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); +protected: + // 最长载荷长度 + size_t private_max_payload_len = 0; + // 消息列表 + std::vector private_msg_list; public: - DLT_Log(); // 构造函数 - ~DLT_Log(); // 析构函数 - /** - * @brief 从文件加载DLT消息,多个文件会顺序加入 - * @param file_name_str 目标文件名 - * @return DLT_Type::DLT_Err 错误类型枚举 - */ - DLT_Type::DLT_Err load_from_file(const char *file_name_str); + // 只读引用 + const std::vector &msg_list = this->private_msg_list; + const size_t &max_payload_len = this->private_max_payload_len; /** - * @brief 获取解析完成的消息列表 - * @param p_msg_list 消息列表存入的指针 - * @return 消息列表计数 + * @brief 从文件加载 + * @param path_to_file 文件路径串 + * @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 将消息列表按时间戳排序 - * @param null - * @return DLT_Type::DLT_Err 错误类型枚举 + * @brief 以CSV格式导出到文件 + * @param path_to_file 文件路径串 + * @return std::string 错误信息 */ - DLT_Type::DLT_Err sort_msg_list(void); + std::string Export_CSV(const char *path_to_file); - /** - * @brief 导出为CSV - * @param file_name_str 目标文件名 - * @return DLT_Type::DLT_Err 错误类型枚举 - */ - DLT_Type::DLT_Err export_to_csv(const char *file_name_str); + // 对消息列表进行排序 + void Sort(void); - /** - * @brief 清理请求的存储并恢复初始状态 - * @param null - * @return null - */ - void clear(void); + // 清除缓存的信息 + void Clear(void); }; #endif \ No newline at end of file diff --git a/Src/Command_Solve.cpp b/Src/Command_Solve.cpp index 0ae9dba..536b9b5 100644 --- a/Src/Command_Solve.cpp +++ b/Src/Command_Solve.cpp @@ -1,5 +1,6 @@ #include "Command_Solve.hpp" #include "DLT_Utilities.hpp" +#include "Global_Variables.hpp" extern "C" { @@ -21,21 +22,21 @@ void Pre_Command_Solve(void) if (argc <= 1) 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); - char *strTo = (char *)malloc(size_needed); - WideCharToMultiByte(CP_UTF8, 0, argv[1], -1, &strTo[0], size_needed, NULL, NULL); + // printf("Arg[%d]:%s\n", count, strTo); + // free(strTo); - 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; - File.get_msg_list(p_list); - - free(strTo); - - err = File.export_to_csv("test.csv"); - - if (err == DLT_Type::DLT_ERROR_NONE) - return; + MessageBoxW(Main_Window_hWnd, (L"[Debug] Argument input:\n" + cmd_string).c_str(), L"", MB_OK); } \ No newline at end of file diff --git a/Src/DLT_Utilities.cpp b/Src/DLT_Utilities.cpp index 52ac622..4e63480 100644 --- a/Src/DLT_Utilities.cpp +++ b/Src/DLT_Utilities.cpp @@ -7,459 +7,296 @@ extern "C" #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; - this->max_payload_len = 0; - this->Msg_List_Head = nullptr; - this->Msg_List_End = nullptr; -} + // 尝试打开文件 + FILE *pFile = fopen(path_to_file, "rb"); + if (pFile == nullptr) + return "File \"" + std::string(path_to_file) + "\" open failed."; -// 析构函数 -DLT_Log::~DLT_Log() -{ - clear(); -} - -// 清理请求的存储并恢复初始状态 -void DLT_Log::clear(void) -{ - - if (this->Msg_List_Head == nullptr) - return; - - // 释放分配的空间 - while (this->Msg_List_Head != nullptr) + // Lambda 读取头 + auto Lambda_Read_Header = [&](DLT_Msg &Msg) -> std::string { - 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)) - return DLT_Type::DLT_ERROR_END_OF_FILE; + if (feof(pFile)) + return "Unexpected EOF."; else - return DLT_Type::DLT_ERROR_FILE_READ_FAILED; + return "File read failed."; } // 检查存储头 - if (memcmp(Msg->storage_header.pattern, "DLT\x01", 4)) - return DLT_Type::DLT_ERROR_INVALID_HEADER; - } + if (memcmp(Msg.storage_header.pattern, "DLT\x01", 4)) + return "Invalid storage header pattern.Must be \"DLT0x01\"."; - // 标准头 - { // 读取标准头 - if (fread(&(Msg->standard_header), sizeof(Msg->standard_header), 1, p_file) != 1) + if (fread(&(Msg.standard_header), sizeof(Msg.standard_header), 1, pFile) != 1) { - if (feof(p_file)) - return DLT_Type::DLT_ERROR_INCOMPLETE_DATA; + if (feof(pFile)) + return "Unexpected EOF."; else - return DLT_Type::DLT_ERROR_FILE_READ_FAILED; + return "File read failed."; } + // 检查标准头协议版本 + if (Msg.standard_header.htyp.VERS != 0x01) + return "Unsupported protocol version."; + // 反向拼接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) // DLT标准头是大端序,与小端序存储的uint16正好相反,所以需要反向 { uint16_t len_swap; - *((uint8_t *)&len_swap) = *(((uint8_t *)&Msg->standard_header.len) + 1); - *(((uint8_t *)&len_swap) + 1) = *((uint8_t *)&Msg->standard_header.len); - Msg->standard_header.len = len_swap; + *((uint8_t *)&len_swap) = *(((uint8_t *)&Msg.standard_header.len) + 1); + *(((uint8_t *)&len_swap) + 1) = *((uint8_t *)&Msg.standard_header.len); + 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 + if (Msg.standard_header.htyp.WEID) + { + msg_header_len += sizeof(Msg.standard_header_extra.ecu); + + if (fread(&(Msg.standard_header_extra.ecu), sizeof(Msg.standard_header_extra.ecu), 1, pFile) != 1) + { + if (feof(pFile)) + return "Unexpected EOF."; + else + return "File read failed."; + } + } + + // 含有额外的 Session ID (会话ID) + if (Msg.standard_header.htyp.WSID) + { + msg_header_len += sizeof(Msg.standard_header_extra.seid); + + if (fread(&(Msg.standard_header_extra.seid), sizeof(Msg.standard_header_extra.seid), 1, pFile) != 1) + { + if (feof(pFile)) + return "Unexpected EOF."; + else + return "File read failed."; + } + + // 反向拼接Session ID字段 + // [PRS_Dlt_00091] ⌈The Standard Header and the Extended Header shall be in big endian format (MSB first).⌋ (RS_LT_00016,RS_LT_00013) + { + uint32_t data_swap; + + *((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) + 2) = *(((uint8_t *)&Msg.standard_header_extra.seid) + 1); + *(((uint8_t *)&data_swap) + 3) = *((uint8_t *)&Msg.standard_header_extra.seid); + + Msg.standard_header_extra.seid = data_swap; + } + } + + // 含有额外的 timestamp (0.1ms 自系统启动后的时间计数) + if (Msg.standard_header.htyp.WSID) + { + msg_header_len += sizeof(Msg.standard_header_extra.tmsp); + + if (fread(&(Msg.standard_header_extra.tmsp), sizeof(Msg.standard_header_extra.tmsp), 1, pFile) != 1) + { + if (feof(pFile)) + return "Unexpected EOF."; + else + return "File read failed."; + } + + // 反向拼接Session ID字段 + // [PRS_Dlt_00091] ⌈The Standard Header and the Extended Header shall be in big endian format (MSB first).⌋ (RS_LT_00016,RS_LT_00013) + { + uint32_t data_swap; + + *((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) + 2) = *(((uint8_t *)&Msg.standard_header_extra.tmsp) + 1); + *(((uint8_t *)&data_swap) + 3) = *((uint8_t *)&Msg.standard_header_extra.tmsp); + + Msg.standard_header_extra.tmsp = data_swap; + } + } + } + + // 扩展头读取 + if (Msg.standard_header.htyp.UEH) + { + msg_header_len += sizeof(Msg.extendedheader); + + // 读取标扩展头 + if (fread(&(Msg.extendedheader), sizeof(Msg.extendedheader), 1, pFile) != 1) + { + if (feof(pFile)) + return "Unexpected EOF."; + else + return "File read failed."; + } + } + + // 分配payload空间并无错误信息返回 + Msg.payload.resize(Msg.standard_header.len - msg_header_len); + return std::string(); + }; + + // Lambda 读取载荷 + auto Lambda_Read_Payload = [&](DLT_Msg &Msg) -> std::string { - // 含有额外的ECU ID - if (Msg->standard_header.htyp.WEID) + if (fread(&Msg.payload[0], Msg.payload.size(), 1, pFile) != 1) { - 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 (feof(p_file)) - return DLT_Type::DLT_ERROR_INCOMPLETE_DATA; - else - return DLT_Type::DLT_ERROR_FILE_READ_FAILED; - } - } - - // 含有额外的 Session ID (会话ID) - if (Msg->standard_header.htyp.WSID) - { - 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 (feof(p_file)) - return DLT_Type::DLT_ERROR_INCOMPLETE_DATA; - else - return DLT_Type::DLT_ERROR_FILE_READ_FAILED; - } - - // 反向拼接Session ID字段 - // [PRS_Dlt_00091] ⌈The Standard Header and the Extended Header shall be in big endian format (MSB first).⌋ (RS_LT_00016,RS_LT_00013) - { - uint32_t data_swap; - - *((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) + 2) = *(((uint8_t *)&Msg->standard_header_extra.seid) + 1); - *(((uint8_t *)&data_swap) + 3) = *((uint8_t *)&Msg->standard_header_extra.seid); - - Msg->standard_header_extra.seid = data_swap; - } - } - - // 含有额外的 timestamp (0.1ms 自系统启动后的时间计数) - if (Msg->standard_header.htyp.WSID) - { - 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 (feof(p_file)) - return DLT_Type::DLT_ERROR_INCOMPLETE_DATA; - else - return DLT_Type::DLT_ERROR_FILE_READ_FAILED; - } - - // 反向拼接Session ID字段 - // [PRS_Dlt_00091] ⌈The Standard Header and the Extended Header shall be in big endian format (MSB first).⌋ (RS_LT_00016,RS_LT_00013) - { - uint32_t data_swap; - - *((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) + 2) = *(((uint8_t *)&Msg->standard_header_extra.tmsp) + 1); - *(((uint8_t *)&data_swap) + 3) = *((uint8_t *)&Msg->standard_header_extra.tmsp); - - Msg->standard_header_extra.tmsp = data_swap; - } - } - } - - // 扩展头读取 - if (Msg->standard_header.htyp.UEH) - { - msg_header_len += sizeof(Msg->extendedheader); - - // 读取标扩展头 - if (fread(&(Msg->extendedheader), sizeof(Msg->extendedheader), 1, p_file) != 1) - { - if (feof(p_file)) - return DLT_Type::DLT_ERROR_INCOMPLETE_DATA; + if (feof(pFile)) + return "Unexpected EOF."; else - return DLT_Type::DLT_ERROR_FILE_READ_FAILED; + return "File read failed."; } - } - // 计算Payload长度 - Msg->payload_length = Msg->standard_header.len - msg_header_len; + return std::string(); + }; - return DLT_Type::DLT_ERROR_NONE; -} - -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) + // 错误信息串 + std::string err_str; + // 循环解析文件 + while (true) { - Msg->payload_buffer = nullptr; - return DLT_Type::DLT_ERROR_NONE; - } + DLT_Msg Msg = {0}; - // 读取Payload - Msg->payload_buffer = (uint8_t *)malloc(Msg->payload_length); - this->mem_use += Msg->payload_length; + err_str = Lambda_Read_Header(Msg); + if (!err_str.empty()) + break; - if (Msg->payload_buffer == nullptr) - return DLT_Type::DLT_ERROR_MEM_ALLOCATE_FAILED; + if (Msg.payload.size() > 0) + err_str = Lambda_Read_Payload(Msg); - if (fread(Msg->payload_buffer, Msg->payload_length, 1, p_file) != 1) - { - free(Msg->payload_buffer); - this->mem_use -= Msg->payload_length; - Msg->payload_buffer = nullptr; - - if (feof(p_file)) - return DLT_Type::DLT_ERROR_INCOMPLETE_DATA; + if (err_str.empty() == true) + { + 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 - return DLT_Type::DLT_ERROR_FILE_READ_FAILED; + break; + + // 读取结束判定 + if (fgetc(pFile) == EOF) + break; + else + fseek(pFile, -1, SEEK_CUR); } - return ::DLT_Type::DLT_ERROR_NONE; + fclose(pFile); + return err_str; } -DLT_Type::DLT_Err DLT_Log::load_from_file(const char *file_name_str) +/** + * @brief 以CSV格式导出到文件 + * @param path_to_file 文件路径串 + * @return std::string 错误信息 + */ +std::string DLT_Log::Export_CSV(const char *path_to_file) { - // 打开文件 - FILE *p_file = fopen(file_name_str, "rb"); - if (p_file == nullptr) - return DLT_Type::DLT_ERROR_FILE_OPEN_FAILED; - - // 解析消息内容 - { - 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; - 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)); - this->mem_use += sizeof(DLT_Type::DLT_Msg_Node); - 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) - { - this->Msg_List_Head = this->Msg_List_End = p_target_msg; - } - else - { - this->Msg_List_End->p_next = p_target_msg; - this->Msg_List_End = p_target_msg; - } - - // 统计最长长度 - if (Msg.payload_length > this->max_payload_len) - 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)) -{ - if (this->loaded_msg_count != 0) - p_msg_list = this->Msg_List_Head; - else - p_msg_list = nullptr; - - 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; + // 尝试打开文件 + FILE *pFile = fopen(path_to_file, "wb"); + if (pFile == nullptr) + return "File \"" + std::string(path_to_file) + "\" open 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++) - fprintf(p_file, "B%d,", count); - fseek(p_file, -1, SEEK_CUR); - fprintf(p_file, "\r\n"); + fprintf(pFile, "B%d,", count); + fseek(pFile, -1, SEEK_CUR); + fprintf(pFile, "\r\n"); } // 遍历每行数据 - DLT_Type::DLT_Msg_Node *p_msg = this->Msg_List_Head; - for (size_t line_count = 0; line_count < this->loaded_msg_count; line_count++) + size_t line_count = 0; + 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(×tamp); char time_str[100] = {'\0'}; // 格式化为 "YY/MM/DD HH:MM:SS" 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 */ 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) { char *p_sec_end = time_str + strlen(time_str) - 4; // 输出秒 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 { - fprintf(p_file, "0."); + fprintf(pFile, "0."); for (int count = 4 - strlen(time_str); count > 0; count--) - fputc('0', p_file); - fprintf(p_file, "%s,", time_str); + fputc('0', pFile); + fprintf(pFile, "%s,", time_str); } } 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 - if (p_msg->Msg.standard_header.htyp.WEID) - fprintf(p_file, "%.4s,", p_msg->Msg.standard_header_extra.ecu); + if (Msg.standard_header.htyp.WEID) + fprintf(pFile, "%.4s,", Msg.standard_header_extra.ecu); else - fprintf(p_file, "%.4s,", p_msg->Msg.storage_header.ecu); + fprintf(pFile, "%.4s,", Msg.storage_header.ecu); // 输出 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(p_file, "%.4s,", p_msg->Msg.extendedheader.ctid); + fprintf(pFile, "%.4s,", Msg.extendedheader.apid); + fprintf(pFile, "%.4s,", Msg.extendedheader.ctid); } else { // skip apid && ctid - fprintf(p_file, "N/A,N/A,"); + fprintf(pFile, "N/A,N/A,"); } // 存在 Session ID - if (p_msg->Msg.standard_header.htyp.WSID) - fprintf(p_file, "%d,", p_msg->Msg.standard_header_extra.seid); + if (Msg.standard_header.htyp.WSID) + fprintf(pFile, "%d,", Msg.standard_header_extra.seid); else - fprintf(p_file, "N/A,"); + fprintf(pFile, "N/A,"); // 输出 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 *SubType_Str[][0xF] = { @@ -474,31 +311,83 @@ DLT_Type::DLT_Err DLT_Log::export_to_csv(const char *file_name_str) }; // Type && Subtype - fprintf(p_file, "%s,", Type_str[p_msg->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,", Type_str[Msg.extendedheader.msin.MSTP]); + fprintf(pFile, "%s,", SubType_Str[Msg.extendedheader.msin.MSTP][(Msg.extendedheader.msin.MTIN - 1) % 0xF]); // Mode && #Args - fprintf(p_file, "%s,", p_msg->Msg.extendedheader.msin.VERB ? "verbose" : "non-verbose"); - fprintf(p_file, "%d,", p_msg->Msg.extendedheader.noar); + fprintf(pFile, "%s,", Msg.extendedheader.msin.VERB ? "verbose" : "non-verbose"); + fprintf(pFile, "%d,", Msg.extendedheader.noar); } else - fprintf(p_file, "N/A,N/A,N/A,N/A,"); + fprintf(pFile, "N/A,N/A,N/A,N/A,"); } - // Payload概览行 - fprintf(p_file, ","); + // Payload概览列跳过 + fprintf(pFile, ","); // 逐个打印 Payload - for (size_t count = 0; count < p_msg->Msg.payload_length; count++) - fprintf(p_file, "%0X,", p_msg->Msg.payload_buffer[count]); + for (auto data_byte : Msg.payload) + fprintf(pFile, "%0X,", data_byte); - fseek(p_file, -1, SEEK_CUR); - fprintf(p_file, "\r\n"); - - p_msg = p_msg->p_next; + // 结束行 + fseek(pFile, -1, SEEK_CUR); + fprintf(pFile, "\r\n"); + 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 empty_list; + this->private_msg_list.swap(empty_list); } \ No newline at end of file diff --git a/Src/UI_Layout.cpp b/Src/UI_Layout.cpp index ac5542c..e5af472 100644 --- a/Src/UI_Layout.cpp +++ b/Src/UI_Layout.cpp @@ -409,38 +409,45 @@ void Widgets::Control_Panel(const ImVec2 &size) [&]() { DLT_Log Log; + std::string err_str; + Input_File_Node *p_file_list = input_dlt_file_list_head; - DLT_Type::DLT_Err err; while (p_file_list != nullptr) { - err = Log.load_from_file(p_file_list->file_name_str); - if (err != DLT_Type::DLT_ERROR_NONE) + err_str = Log.Load_From_File(p_file_list->file_name_str); + if (!err_str.empty()) break; p_file_list = p_file_list->p_next; } - if (err != DLT_Type::DLT_ERROR_NONE) + if (err_str.empty()) { - switch (err) - { - 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); - } + Log.Sort(); + err_str = Log.Export_CSV(export_file_path_str); + } + + if (err_str.empty()) + { + MessageBoxW(Main_Window_hWnd, L"导出完成", L"", MB_OK); } else { - // 排序后导出 - Log.sort_msg_list(); - err = Log.export_to_csv(export_file_path_str); + // 工具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; + }; - if (err == DLT_Type::DLT_ERROR_NONE) - MessageBoxW(Main_Window_hWnd, L"导出完成", L"", MB_OK); - else - MessageBoxW(Main_Window_hWnd, L"导出失败,检查文件占用", L"", MB_OK | MB_ICONERROR); + // 输出错误信息 + MessageBoxW(Main_Window_hWnd, (L"导出失败\n" + Lambda_String_To_WString(err_str)).c_str(), L"", MB_OK | MB_ICONERROR); } export_confirmed = false; export_task_created = false;