#include "DLT_Utilities.hpp" extern "C" { #include "stdlib.h" #include "string.h" #include "sys/time.h" } // 构造函数 DLT_Log::DLT_Log() { // 初始化内容 this->loaded_msg_count = 0; this->max_payload_len = 0; this->Msg_List_Head = nullptr; this->Msg_List_End = nullptr; } // 析构函数 DLT_Log::~DLT_Log() { 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; 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 (feof(p_file)) return DLT_Type::DLT_ERROR_END_OF_FILE; else return DLT_Type::DLT_ERROR_FILE_READ_FAILED; } // 检查存储头 if (memcmp(Msg->storage_header.pattern, "DLT\x01", 4)) return DLT_Type::DLT_ERROR_INVALID_HEADER; } // 标准头 { // 读取标准头 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字段 // [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, 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; else return DLT_Type::DLT_ERROR_FILE_READ_FAILED; } } // 计算Payload长度 Msg->payload_length = Msg->standard_header.len - msg_header_len; 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; // 读取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); this->mem_use -= Msg->payload_length; Msg->payload_buffer = nullptr; if (feof(p_file)) return DLT_Type::DLT_ERROR_INCOMPLETE_DATA; else return DLT_Type::DLT_ERROR_FILE_READ_FAILED; } return ::DLT_Type::DLT_ERROR_NONE; } DLT_Type::DLT_Err DLT_Log::load_from_file(const char *file_name_str) { // 打开文件 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; 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; // 打印首行 { fprintf(p_file, "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"); } // 遍历每行数据 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++) { // 输出索引号 fprintf(p_file, "%d,", line_count); // 输出日期和时间 { time_t timestamp = (time_t)p_msg->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); } // 输出头附加信息 { // 存在扩展时间戳 if (p_msg->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); 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); // 输出剩余的时间 fprintf(p_file, ".%s,", p_sec_end); } else { fprintf(p_file, "0."); for (int count = 4 - strlen(time_str); count > 0; count--) fputc('0', p_file); fprintf(p_file, "%s,", time_str); } } else fprintf(p_file, "N/A,"); // 消息计数 fprintf(p_file, "%d,", p_msg->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); else fprintf(p_file, "%.4s,", p_msg->Msg.storage_header.ecu); // 输出 Apid 和 Ctid if (p_msg->Msg.standard_header.htyp.UEH) { fprintf(p_file, "%.4s,", p_msg->Msg.extendedheader.apid); fprintf(p_file, "%.4s,", p_msg->Msg.extendedheader.ctid); } else { // skip apid && ctid fprintf(p_file, "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); else fprintf(p_file, "N/A,"); // 输出 Type 、Subtype 、Mode 、#Args if (p_msg->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(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]); // Mode && #Args fprintf(p_file, "%s,", p_msg->Msg.extendedheader.msin.VERB ? "verbose" : "non-verbose"); fprintf(p_file, "%d,", p_msg->Msg.extendedheader.noar); } else fprintf(p_file, "N/A,N/A,N/A,N/A,"); } // Payload概览行 fprintf(p_file, ","); // 逐个打印 Payload for (size_t count = 0; count < p_msg->Msg.payload_length; count++) fprintf(p_file, "%0X,", p_msg->Msg.payload_buffer[count]); fseek(p_file, -1, SEEK_CUR); fprintf(p_file, "\r\n"); p_msg = p_msg->p_next; } fclose(p_file); return DLT_Type::DLT_ERROR_NONE; }