393 lines
14 KiB
C++
393 lines
14 KiB
C++
#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<DLT_Msg> empty_list;
|
||
this->private_msg_list.swap(empty_list);
|
||
} |