#include "DLT_Utilities.hpp" extern "C" { #include "stdlib.h" #include "string.h" #include "sys/time.h" } /** * @brief 从文件加载 * @param path_to_file 文件路径串 * @return std::string 错误信息 */ std::string DLT_Log::Load_From_File(const char *path_to_file) { // 尝试打开文件 FILE *pFile = fopen(path_to_file, "rb"); if (pFile == nullptr) return "File \"" + std::string(path_to_file) + "\" open failed."; // Lambda 读取头 auto Lambda_Read_Header = [&](DLT_Msg &Msg) -> std::string { // 读取存储头 if (fread(&(Msg.storage_header), sizeof(Msg.storage_header), 1, pFile) != 1) { if (feof(pFile)) return "Unexpected EOF."; else return "File read failed."; } // 检查存储头 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, pFile) != 1) { if (feof(pFile)) return "Unexpected EOF."; else 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; } // 消息头长度统计 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 { if (fread(&Msg.payload[0], Msg.payload.size(), 1, pFile) != 1) { if (feof(pFile)) return "Unexpected EOF."; else return "File read failed."; } return std::string(); }; // 错误信息串 std::string err_str; // 循环解析文件 while (true) { DLT_Msg Msg = {0}; err_str = Lambda_Read_Header(Msg); if (!err_str.empty()) break; if (Msg.payload.size() > 0) err_str = Lambda_Read_Payload(Msg); 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 break; // 读取结束判定 if (fgetc(pFile) == EOF) break; else fseek(pFile, -1, SEEK_CUR); } fclose(pFile); return err_str; } /** * @brief 以CSV格式导出到文件 * @param path_to_file 文件路径串 * @return std::string 错误信息 */ std::string DLT_Log::Export_CSV(const char *path_to_file) { // 尝试打开文件 FILE *pFile = fopen(path_to_file, "wb"); if (pFile == nullptr) return "File \"" + std::string(path_to_file) + "\" open failed."; // 打印首行 { 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(pFile, "B%d,", count); fseek(pFile, -1, SEEK_CUR); fprintf(pFile, "\r\n"); } // 遍历每行数据 size_t line_count = 0; for (auto Msg : this->private_msg_list) { // 输出索引号 fprintf(pFile, "%d,", line_count); // 输出日期和时间 { 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(pFile, "%s.%d,", time_str, Msg.storage_header.microseconds); } // 输出头附加信息 { // 存在扩展时间戳 if (Msg.standard_header.htyp.WTMS) { /**< Timestamp since system start in 0.1 milliseconds */ char time_str[20]; 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, pFile); // 输出剩余的时间 fprintf(pFile, ".%s,", p_sec_end); } else { fprintf(pFile, "0."); for (int count = 4 - strlen(time_str); count > 0; count--) fputc('0', pFile); fprintf(pFile, "%s,", time_str); } } else fprintf(pFile, "N/A,"); // 消息计数 fprintf(pFile, "%d,", Msg.standard_header.mcnt); // 存在扩展ECU ID if (Msg.standard_header.htyp.WEID) fprintf(pFile, "%.4s,", Msg.standard_header_extra.ecu); else fprintf(pFile, "%.4s,", Msg.storage_header.ecu); // 输出 Apid 和 Ctid if (Msg.standard_header.htyp.UEH) { fprintf(pFile, "%.4s,", Msg.extendedheader.apid); fprintf(pFile, "%.4s,", Msg.extendedheader.ctid); } else { // skip apid && ctid fprintf(pFile, "N/A,N/A,"); } // 存在 Session ID if (Msg.standard_header.htyp.WSID) fprintf(pFile, "%d,", Msg.standard_header_extra.seid); else fprintf(pFile, "N/A,"); // 输出 Type 、Subtype 、Mode 、#Args if (Msg.standard_header.htyp.UEH) { const char *Type_str[] = {"log", "trace", "network", "control"}; const char *SubType_Str[][0xF] = { // LOG {"fatal", "error", "warn", "info", "debug", "verbose", nullptr}, // Trace {"variable", "function in", "function out", "state", "vbf", nullptr}, // Network {"IPC", "CAN", "FlexRay", "Most", "Ethernet", "SOME/IP", "0x7", "0x8", "0x9", "0xA", "0xB", "0xC", "0xD", "0xE", "0xF"}, // Control {"Request", "response", nullptr}, }; // Type && Subtype 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(pFile, "%s,", Msg.extendedheader.msin.VERB ? "verbose" : "non-verbose"); fprintf(pFile, "%d,", Msg.extendedheader.noar); } else fprintf(pFile, "N/A,N/A,N/A,N/A,"); } // Payload概览列跳过 fprintf(pFile, ","); // 逐个打印 Payload for (auto data_byte : Msg.payload) fprintf(pFile, "%0X,", data_byte); // 结束行 fseek(pFile, -1, SEEK_CUR); fprintf(pFile, "\r\n"); line_count++; } fclose(pFile); return std::string(); } // 对消息列表进行排序 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); }