DLT_Splitter/Src/DLT_Utilities.cpp

393 lines
14 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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(&timestamp);
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);
}