Compare commits
30
Commits
38b498e841
..
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8cdd2662ba | ||
|
|
5cc61e9486 | ||
|
|
986028a3a3 | ||
|
|
80a18b6a79 | ||
|
|
35636fd438 | ||
|
|
68fba7efd5 | ||
|
|
3ec4327d45 | ||
|
|
df949ce460 | ||
|
|
f9f10209ca | ||
|
|
fa4e79dc86 | ||
|
|
e0afc4963f | ||
|
|
07ee870601 | ||
|
|
923ba12ae9 | ||
|
|
ce6f9646c4 | ||
|
|
e80d14d347 | ||
|
|
b11e74e815 | ||
|
|
057438652a | ||
|
|
4da02ddb60 | ||
|
|
a23f562906 | ||
|
|
7aa8c6750d | ||
|
|
975495b2b7 | ||
|
|
f1e29aaba9 | ||
|
|
20d1c5576f | ||
|
|
f6e70335f9 | ||
|
|
b86798db10 | ||
|
|
2972630f25 | ||
|
|
0f2f2720fc | ||
|
|
cfb1be0efd | ||
|
|
7666ec39fe | ||
|
|
34509a68a6 |
Vendored
+10
-1
@@ -7,12 +7,21 @@
|
||||
"request": "launch",
|
||||
"preLaunchTask": "project_debug_build_task", // 预构建脚本
|
||||
"program": "${workspaceFolder}\\Build\\Debug\\DLT_Splitter.exe", // 调试目标
|
||||
"args": [ // 附加参数
|
||||
"args": [
|
||||
// 附加参数
|
||||
],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}", // 工作目录
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"setupCommands": [
|
||||
{
|
||||
// 启用优化打印输出
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
// "ignoreFailures": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
+5
-2
@@ -5,7 +5,10 @@
|
||||
#define MAIN_FRAME_TITTLE L"DLT Splitter —— Dev by : LuChiChick"
|
||||
|
||||
// 主窗体最小面积
|
||||
#define MAIN_FRAME_SIZE_WIDTH_MIN 350
|
||||
#define MAIN_FRAME_SIZE_HEIGHT_MIN 350 * 1.5
|
||||
#define MAIN_FRAME_SIZE_WIDTH_MIN 400
|
||||
#define MAIN_FRAME_SIZE_HEIGHT_MIN 400 * 1.5
|
||||
|
||||
// 单次允许选择的最大文件数量
|
||||
#define MAX_SINGLE_SELECT_FILE_COUNT 512
|
||||
|
||||
#endif
|
||||
+47
-89
@@ -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,75 +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<uint8_t> 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<DLT_Msg> 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<DLT_Msg> &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 导出为CSV
|
||||
* @param file_name_str 目标文件名
|
||||
* @return DLT_Type::DLT_Err 错误类型枚举
|
||||
* @brief 以CSV格式导出到文件
|
||||
* @param path_to_file 文件路径串
|
||||
* @return std::string 错误信息
|
||||
*/
|
||||
DLT_Type::DLT_Err export_to_csv(const char *file_name_str);
|
||||
std::string Export_CSV(const char *path_to_file);
|
||||
|
||||
/**
|
||||
* @brief 清理请求的存储并恢复初始状态
|
||||
* @param null
|
||||
* @return null
|
||||
*/
|
||||
void clear(void);
|
||||
// 对消息列表进行排序
|
||||
void Sort(void);
|
||||
|
||||
// 清除缓存的信息
|
||||
void Clear(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -5,13 +5,17 @@
|
||||
#include "imgui_impl_win32.h"
|
||||
#include "imgui_impl_dx11.h"
|
||||
|
||||
#include "Workflow_Editor.hpp"
|
||||
#include "Type_Descriptions.hpp"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "windows.h"
|
||||
#include "d3d11.h"
|
||||
}
|
||||
|
||||
#include "Type_Descriptions.hpp"
|
||||
// 主窗体句柄
|
||||
extern HWND Main_Window_hWnd;
|
||||
|
||||
// D3D11 相关
|
||||
extern ID3D11Device *g_pd3dDevice; // D3D11 设备句柄
|
||||
@@ -26,4 +30,7 @@ extern ID3D11RenderTargetView *g_mainRenderTargetView; // D3D11 渲染目标
|
||||
extern Input_File_Node *input_dlt_file_list_head;
|
||||
extern size_t input_dlt_file_count;
|
||||
|
||||
// 节点编辑器
|
||||
extern class Workflow_Editor Workflow_Editor;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef __ID_GENERATOR__
|
||||
#define __ID_GENERATOR__
|
||||
|
||||
#include <vector>
|
||||
|
||||
// 唯一ID生成器
|
||||
class Independent_ID_Generator
|
||||
{
|
||||
protected:
|
||||
// 连续ID串
|
||||
typedef struct
|
||||
{
|
||||
int begin;
|
||||
int end;
|
||||
} Continuous_ID_Section;
|
||||
std::vector<Continuous_ID_Section> continuous_id_list;
|
||||
|
||||
public:
|
||||
// 获取ID
|
||||
int Request_ID(void);
|
||||
// 释放ID true-> success / false -> fail
|
||||
bool Release_ID(const int ID);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,185 @@
|
||||
#ifndef __JSON_UTILITIES_HPP__
|
||||
#define __JSON_UTILITIES_HPP__
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "stdint.h"
|
||||
}
|
||||
|
||||
#include "vector"
|
||||
#include "string"
|
||||
|
||||
class Json_Pair; // Json 键值对
|
||||
class Json_Arry; // Json 数组 元素必须是值
|
||||
class Json_Object; // Json 对象 对象内必须是键值对序列
|
||||
class Json_Value; // Json 值(可以是数组、对象、字符串、浮点数值和整数值、逻辑值、NULL)
|
||||
|
||||
/**
|
||||
* @brief Json文件 格式检查
|
||||
* @param path_to_file 文件路径串
|
||||
* @return std::string 错误值
|
||||
*/
|
||||
std::string JsonFile_FormatCheck(const char *path_to_file);
|
||||
|
||||
/**
|
||||
* @brief 解析Json文件
|
||||
* @param path_to_file 文件路径串
|
||||
* @param pJson_Value Value 指针
|
||||
* @return std::string 错误值
|
||||
*/
|
||||
std::string JsonFile_Parse(const char *path_to_file, Json_Value *pJson_Value);
|
||||
|
||||
/**
|
||||
* @brief Json对象保存
|
||||
* @param path_to_file 文件路径串
|
||||
* @param value Json Value
|
||||
* @param enable_pretty_print 启用美观打印
|
||||
* @return std::string 错误值
|
||||
*/
|
||||
std::string Json_Export(const char *path_to_file, Json_Value value, bool enable_pretty_print = true);
|
||||
|
||||
// Json 数组
|
||||
class Json_Arry
|
||||
{
|
||||
private:
|
||||
// 元素列表
|
||||
std::vector<Json_Value> private_element_list;
|
||||
|
||||
public:
|
||||
// 只读引用
|
||||
const std::vector<Json_Value> &element_list = this->private_element_list;
|
||||
|
||||
// 默认构造
|
||||
Json_Arry() = default;
|
||||
// 列表构造
|
||||
Json_Arry(std::initializer_list<Json_Value> init_list) : private_element_list(init_list) {};
|
||||
Json_Arry(std::vector<Json_Value> init_list) : private_element_list(init_list) {};
|
||||
// 浅拷贝构造
|
||||
Json_Arry(const Json_Arry &temp);
|
||||
|
||||
// 深拷贝
|
||||
Json_Arry &operator=(const Json_Arry &another);
|
||||
// 获取元素大小
|
||||
size_t size(void) const;
|
||||
// 数组索引重载
|
||||
Json_Value operator[](size_t index) const;
|
||||
|
||||
// 是否为空
|
||||
bool isEmpty(void) const;
|
||||
};
|
||||
|
||||
// Json 值定义
|
||||
class Json_Value
|
||||
{
|
||||
public:
|
||||
// 类型枚举
|
||||
typedef enum
|
||||
{
|
||||
TYPE_NULL, // 空值
|
||||
TYPE_STR, // 字符串
|
||||
TYPE_ARRY, // 数组
|
||||
TYPE_OBJ, // 对象
|
||||
TYPE_NUM_INTEGER, // 整数常数
|
||||
TYPE_NUM_FLOAT, // 浮点常数
|
||||
TYPE_BOOLEAN, // 布尔逻辑值
|
||||
} Type;
|
||||
|
||||
protected:
|
||||
Type private_type = TYPE_NULL; // 类型枚举
|
||||
void *p_mem = nullptr; // 数据内存
|
||||
public:
|
||||
// 只读引用
|
||||
const Type &type = this->private_type;
|
||||
|
||||
// 默认构造
|
||||
Json_Value() = default;
|
||||
|
||||
// 值构造
|
||||
Json_Value(std::string str);
|
||||
Json_Value(const char *str) : Json_Value(std::string(str)) {};
|
||||
Json_Value(Json_Arry arry);
|
||||
Json_Value(std::initializer_list<Json_Value> init_list) : Json_Value(Json_Arry(init_list)) {};
|
||||
Json_Value(Json_Object object);
|
||||
Json_Value(int64_t num_integer);
|
||||
Json_Value(int num_integer) : Json_Value((int64_t)num_integer) {};
|
||||
Json_Value(double num_float);
|
||||
Json_Value(float num_float) : Json_Value((double)num_float) {};
|
||||
Json_Value(bool boolean);
|
||||
// 浅拷贝构造
|
||||
Json_Value(const Json_Value &temp);
|
||||
|
||||
// 深拷贝
|
||||
Json_Value &operator=(const Json_Value &another);
|
||||
|
||||
// 析构函数
|
||||
~Json_Value();
|
||||
|
||||
// 获取值
|
||||
std::string asString(void) const;
|
||||
Json_Arry asArry(void) const;
|
||||
Json_Object asObject(void) const;
|
||||
int64_t asInteger(void) const;
|
||||
double asFloat(void) const;
|
||||
bool asBoolean(void) const;
|
||||
|
||||
// 是否为空
|
||||
bool isNull(void) const;
|
||||
};
|
||||
|
||||
// Json 键值对定义
|
||||
class Json_Pair
|
||||
{
|
||||
private:
|
||||
std::string private_key_str; // 键
|
||||
Json_Value private_value; // 值
|
||||
public:
|
||||
// 只读引用
|
||||
std::string &key = this->private_key_str;
|
||||
Json_Value &value = this->private_value;
|
||||
|
||||
// 默认构造
|
||||
Json_Pair() = default;
|
||||
// 必要构造
|
||||
Json_Pair(std::string key, Json_Value value) : private_key_str(key), private_value(value) {};
|
||||
// 浅拷贝构造
|
||||
Json_Pair(const Json_Pair &temp);
|
||||
|
||||
// 深拷贝
|
||||
Json_Pair &operator=(const Json_Pair &another);
|
||||
};
|
||||
|
||||
// Json 对象
|
||||
class Json_Object
|
||||
{
|
||||
private:
|
||||
// 元素列表
|
||||
std::vector<Json_Pair> private_element_list;
|
||||
|
||||
public:
|
||||
// 只读引用
|
||||
std::vector<Json_Pair> const &element_list = this->private_element_list;
|
||||
|
||||
// 默认构造
|
||||
Json_Object() = default;
|
||||
// 列表构造
|
||||
Json_Object(std::initializer_list<Json_Pair> init_list) : private_element_list(init_list) {};
|
||||
Json_Object(std::vector<Json_Pair> init_list) : private_element_list(init_list) {};
|
||||
// 浅拷贝构造
|
||||
Json_Object(const Json_Object &temp);
|
||||
|
||||
// 深拷贝
|
||||
Json_Object &operator=(const Json_Object &another);
|
||||
|
||||
// 获取元素大小
|
||||
size_t size(void) const;
|
||||
// 数组索引重载
|
||||
Json_Pair operator[](size_t index) const;
|
||||
|
||||
// 由Key 查找值
|
||||
Json_Value get(std::string key) const;
|
||||
|
||||
// 是否为空
|
||||
bool isEmpty(void) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,375 @@
|
||||
#ifndef __NODES_AND_CONNECTORS__
|
||||
#define __NODES_AND_CONNECTORS__
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include "imgui.h"
|
||||
#include "imnodes.h"
|
||||
#include "ID_Generator.hpp"
|
||||
#include "DLT_Utilities.hpp"
|
||||
#include "Json_Utilities.hpp"
|
||||
|
||||
// =====================================接口抽象======================================================
|
||||
|
||||
class Abs_Connector // 抽象接口类
|
||||
{
|
||||
public:
|
||||
typedef enum
|
||||
{
|
||||
CONNECTOR_TYPE_UNKNOWN, // 未知连接点类型
|
||||
CONNECTOR_TYPE_OUTPUT, // 输出
|
||||
CONNECTOR_TYPE_INPUT, // 输入
|
||||
CONNECTOR_TYPE_INPUT_EXCLUSIVE, // 独占输入,新连接必须断开旧连接
|
||||
} Connector_Type_Enum; // 接口类型枚举
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t package_count = 0; // 包计数 (常规非0)
|
||||
size_t total_count = 0; // 总计数 (常规非0,不定长包时为0)
|
||||
void *p_content_mem = nullptr; // 包存储
|
||||
size_t content_size = 0; // 包大小
|
||||
} Package; // 接口包定义
|
||||
|
||||
protected:
|
||||
// ID 分配器
|
||||
Independent_ID_Generator *ID_Generator;
|
||||
|
||||
int id; // ID
|
||||
Connector_Type_Enum type; // 类型标识
|
||||
const char *socket_str; // 套接字字符串
|
||||
|
||||
std::vector<Abs_Connector *> related_connector_list; // 关联列表
|
||||
Package pkg; // 接口包(仅输出类节点持有)
|
||||
|
||||
public:
|
||||
// 显式禁用默认构造
|
||||
Abs_Connector() = delete;
|
||||
|
||||
// 必要构造
|
||||
Abs_Connector(Independent_ID_Generator *ID_Generator, Connector_Type_Enum type, const char *socket_str);
|
||||
|
||||
// 析构
|
||||
~Abs_Connector();
|
||||
|
||||
// 连接到目标连接点
|
||||
virtual bool Connect_To(Abs_Connector *target);
|
||||
|
||||
// 断开所有连接
|
||||
virtual void Disconnect_All(void);
|
||||
|
||||
// 与指定的接口断开连接
|
||||
virtual bool Disconnect_To(Abs_Connector *target);
|
||||
|
||||
/**
|
||||
* 注册包
|
||||
* @param p_content 目标容物指针
|
||||
* @param content_size 容物大小
|
||||
* @param count 当前包位置
|
||||
* @param total_count 包流总长度
|
||||
*/
|
||||
virtual bool Register_Package(const void *p_content, size_t content_size, size_t count, size_t total_count);
|
||||
|
||||
// 获取包
|
||||
virtual const Package Get_Package(void);
|
||||
|
||||
// 获取关联接口列表
|
||||
virtual std::vector<Abs_Connector *> Get_Related_List(void);
|
||||
|
||||
// 获取ID
|
||||
virtual int Get_ID(void);
|
||||
|
||||
// 获取接口类型
|
||||
virtual Connector_Type_Enum Get_Type(void);
|
||||
|
||||
// 获取套接字字符串
|
||||
virtual const char *Get_Socket_Str(void);
|
||||
|
||||
// 默认风格连接点绘制
|
||||
virtual void Show(void);
|
||||
};
|
||||
|
||||
// =====================================节点抽象======================================================
|
||||
|
||||
class Abs_Node // 抽象节点类
|
||||
{
|
||||
public:
|
||||
typedef enum
|
||||
{
|
||||
NODE_TYPE_UNKNOWN, // 未知节点类型
|
||||
NODE_TYPE_CONNECTOR_TEST, // 接口测试节点
|
||||
NODE_TYPE_MSG_LINE_INPUT, // 消息输入节点
|
||||
NODE_TYPE_FILTER, // 筛选器节点
|
||||
NODE_TYPE_LOGIC_AND, // 逻辑与门节点
|
||||
NODE_TYPE_LOGIC_OR, // 逻辑或门节点
|
||||
NODE_TYPE_LOGIC_NOT, // 逻辑非门节点
|
||||
NODE_TYPE_CSV_EXPORTER, // CSV输出节点
|
||||
} Node_Type_Enum; // 节点类型枚举
|
||||
|
||||
protected:
|
||||
// ID 分配器
|
||||
Independent_ID_Generator *Node_ID_Generator; // 节点ID生成器
|
||||
Independent_ID_Generator *Connector_ID_Generator; // 连接点ID生成器
|
||||
|
||||
int id; // ID
|
||||
Node_Type_Enum type; // 类型
|
||||
ImVec2 initial_position; // 初始位置
|
||||
|
||||
bool close_flag; // 关闭标志位
|
||||
|
||||
// 接口列表
|
||||
std::vector<std::shared_ptr<Abs_Connector>> Connector_List;
|
||||
|
||||
public:
|
||||
// 显式禁用默认构造
|
||||
Abs_Node() = delete;
|
||||
|
||||
// 必要构造
|
||||
Abs_Node(Independent_ID_Generator *Node_ID_Generator,
|
||||
Independent_ID_Generator *Connector_ID_Generator,
|
||||
Node_Type_Enum type,
|
||||
ImVec2 initial_position = ImVec2(0, 0));
|
||||
|
||||
// 析构
|
||||
~Abs_Node();
|
||||
|
||||
// 绘制节点
|
||||
virtual void Show(void) = 0;
|
||||
|
||||
// 执行处理流程
|
||||
virtual bool Execute_Process(void) = 0;
|
||||
|
||||
// 获取ID
|
||||
virtual int Get_ID(void);
|
||||
|
||||
// 获取节点类型
|
||||
virtual Node_Type_Enum Get_Type(void);
|
||||
|
||||
// 获取关闭信号
|
||||
virtual bool Get_CloseFlag(void);
|
||||
|
||||
// 获取节点配置参数
|
||||
virtual Json_Arry Get_Arguments(void);
|
||||
|
||||
// 应用配置参数
|
||||
virtual bool Apply_Arguments(Json_Arry Arg_Arry);
|
||||
|
||||
// 获取接口列表
|
||||
std::vector<std::shared_ptr<Abs_Connector>> &Get_Connector_List(void);
|
||||
};
|
||||
|
||||
// ====================================接口类声明================================================
|
||||
|
||||
// Boolean 状态输入接口
|
||||
class Boolean_InPut_Connector : public Abs_Connector
|
||||
{
|
||||
public:
|
||||
// 显式禁用默认构造
|
||||
Boolean_InPut_Connector() = delete;
|
||||
|
||||
// 必要构造
|
||||
explicit Boolean_InPut_Connector(Independent_ID_Generator *ID_Generator, bool exclusive_flag = false) : Abs_Connector(ID_Generator, exclusive_flag ? CONNECTOR_TYPE_INPUT_EXCLUSIVE : CONNECTOR_TYPE_INPUT, "Boolean") {}
|
||||
};
|
||||
|
||||
// Boolean 状态输出接口
|
||||
class Boolean_OutPut_Connector : public Abs_Connector
|
||||
{
|
||||
public:
|
||||
// 显式禁用默认构造
|
||||
Boolean_OutPut_Connector() = delete;
|
||||
|
||||
// 必要构造
|
||||
explicit Boolean_OutPut_Connector(Independent_ID_Generator *ID_Generator) : Abs_Connector(ID_Generator, CONNECTOR_TYPE_OUTPUT, "Boolean") {}
|
||||
};
|
||||
|
||||
// DLT信息输入接口
|
||||
class MSG_InPut_Connector : public Abs_Connector
|
||||
{
|
||||
public:
|
||||
// 显式禁用默认构造
|
||||
MSG_InPut_Connector() = delete;
|
||||
|
||||
// 必要构造
|
||||
explicit MSG_InPut_Connector(Independent_ID_Generator *ID_Generator, bool exclusive_flag = false) : Abs_Connector(ID_Generator, exclusive_flag ? CONNECTOR_TYPE_INPUT_EXCLUSIVE : CONNECTOR_TYPE_INPUT, "DLT MSG") {}
|
||||
};
|
||||
|
||||
// DLT信息输出接口
|
||||
class MSG_OutPut_Connector : public Abs_Connector
|
||||
{
|
||||
public:
|
||||
// 显式禁用默认构造
|
||||
MSG_OutPut_Connector() = delete;
|
||||
|
||||
// 必要构造
|
||||
explicit MSG_OutPut_Connector(Independent_ID_Generator *ID_Generator) : Abs_Connector(ID_Generator, CONNECTOR_TYPE_OUTPUT, "DLT MSG") {}
|
||||
};
|
||||
|
||||
// CSV 列输入接口
|
||||
class CSV_Column_Input_Connector : public Abs_Connector
|
||||
{
|
||||
public:
|
||||
// 显式禁用默认构造
|
||||
CSV_Column_Input_Connector() = delete;
|
||||
|
||||
// 必要构造
|
||||
explicit CSV_Column_Input_Connector(Independent_ID_Generator *ID_Generator, bool exclusive_flag = false) : Abs_Connector(ID_Generator, exclusive_flag ? CONNECTOR_TYPE_INPUT_EXCLUSIVE : CONNECTOR_TYPE_INPUT, "CSV Column") {}
|
||||
};
|
||||
|
||||
// CSV 列输出接口
|
||||
class CSV_Column_Output_Connector : public Abs_Connector
|
||||
{
|
||||
public:
|
||||
// 显式禁用默认构造
|
||||
CSV_Column_Output_Connector() = delete;
|
||||
|
||||
// 必要构造
|
||||
explicit CSV_Column_Output_Connector(Independent_ID_Generator *ID_Generator) : Abs_Connector(ID_Generator, CONNECTOR_TYPE_OUTPUT, "CSV Column") {}
|
||||
};
|
||||
|
||||
// ====================================节点类声明================================================
|
||||
|
||||
// 接口测试节点
|
||||
class Connector_Test_Node : public Abs_Node
|
||||
{
|
||||
private:
|
||||
float node_width = 0;
|
||||
|
||||
public:
|
||||
// 显式禁用默认构造
|
||||
Connector_Test_Node() = delete;
|
||||
|
||||
// 必要构造
|
||||
Connector_Test_Node(Independent_ID_Generator *Node_ID_Generator,
|
||||
Independent_ID_Generator *Connector_ID_Generator,
|
||||
ImVec2 initial_position = ImVec2(0, 0));
|
||||
|
||||
// 绘制节点
|
||||
virtual void Show(void);
|
||||
|
||||
// 执行处理流程
|
||||
virtual bool Execute_Process(void);
|
||||
};
|
||||
|
||||
// DLT信息输入类,起始点
|
||||
class MSG_Input_Node : public Abs_Node
|
||||
{
|
||||
private:
|
||||
float node_width = 0;
|
||||
|
||||
DLT_Log log;
|
||||
|
||||
// 执行相关
|
||||
bool excute_flag = false;
|
||||
size_t private_excute_count = 0;
|
||||
size_t private_excute_end_count = 0;
|
||||
bool private_finish_flag = false;
|
||||
|
||||
public:
|
||||
// 只读引用
|
||||
const bool &finish_flag = this->private_finish_flag;
|
||||
const size_t &excute_count = this->private_excute_count;
|
||||
const size_t &excute_end_count = this->private_excute_end_count;
|
||||
|
||||
// 显式禁用默认构造
|
||||
MSG_Input_Node() = delete;
|
||||
|
||||
// 必要构造
|
||||
MSG_Input_Node(Independent_ID_Generator *Node_ID_Generator,
|
||||
Independent_ID_Generator *Connector_ID_Generator,
|
||||
ImVec2 initial_position = ImVec2(0, 0));
|
||||
|
||||
// 绘制节点
|
||||
virtual void Show(void);
|
||||
|
||||
// 执行处理流程
|
||||
virtual bool Execute_Process(void);
|
||||
};
|
||||
|
||||
// 筛选器节点
|
||||
class Filter_Node : public Abs_Node
|
||||
{
|
||||
private:
|
||||
float node_width = 0;
|
||||
|
||||
public:
|
||||
// 显式禁用默认构造
|
||||
Filter_Node() = delete;
|
||||
|
||||
// 必要构造
|
||||
Filter_Node(Independent_ID_Generator *Node_ID_Generator,
|
||||
Independent_ID_Generator *Connector_ID_Generator,
|
||||
ImVec2 initial_position = ImVec2(0, 0));
|
||||
|
||||
// 绘制节点
|
||||
virtual void Show(void);
|
||||
|
||||
// 执行处理流程
|
||||
virtual bool Execute_Process(void);
|
||||
};
|
||||
|
||||
// 逻辑与门
|
||||
class Logic_AND_Node : public Abs_Node
|
||||
{
|
||||
private:
|
||||
float node_width = 0;
|
||||
|
||||
public:
|
||||
// 显式禁用默认构造
|
||||
Logic_AND_Node() = delete;
|
||||
|
||||
// 必要构造
|
||||
Logic_AND_Node(Independent_ID_Generator *Node_ID_Generator,
|
||||
Independent_ID_Generator *Connector_ID_Generator,
|
||||
ImVec2 initial_position = ImVec2(0, 0));
|
||||
|
||||
// 绘制节点
|
||||
virtual void Show(void);
|
||||
|
||||
// 执行处理流程
|
||||
virtual bool Execute_Process(void);
|
||||
};
|
||||
|
||||
// 逻辑与门
|
||||
class Logic_OR_Node : public Abs_Node
|
||||
{
|
||||
private:
|
||||
float node_width = 0;
|
||||
|
||||
public:
|
||||
// 显式禁用默认构造
|
||||
Logic_OR_Node() = delete;
|
||||
|
||||
// 必要构造
|
||||
Logic_OR_Node(Independent_ID_Generator *Node_ID_Generator,
|
||||
Independent_ID_Generator *Connector_ID_Generator,
|
||||
ImVec2 initial_position = ImVec2(0, 0));
|
||||
|
||||
// 绘制节点
|
||||
virtual void Show(void);
|
||||
|
||||
// 执行处理流程
|
||||
virtual bool Execute_Process(void);
|
||||
};
|
||||
|
||||
// 逻辑与门
|
||||
class Logic_NOT_Node : public Abs_Node
|
||||
{
|
||||
private:
|
||||
float node_width = 0;
|
||||
|
||||
public:
|
||||
// 显式禁用默认构造
|
||||
Logic_NOT_Node() = delete;
|
||||
|
||||
// 必要构造
|
||||
Logic_NOT_Node(Independent_ID_Generator *Node_ID_Generator,
|
||||
Independent_ID_Generator *Connector_ID_Generator,
|
||||
ImVec2 initial_position = ImVec2(0, 0));
|
||||
|
||||
// 绘制节点
|
||||
virtual void Show(void);
|
||||
|
||||
// 执行处理流程
|
||||
virtual bool Execute_Process(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -17,6 +17,9 @@ namespace Widgets
|
||||
|
||||
// 工作流区域
|
||||
void Workflow_Area(const ImVec2 &size = ImVec2(0, 0));
|
||||
|
||||
// 控制面板区域
|
||||
void Control_Panel(const ImVec2 &size = ImVec2(0, 0));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,94 @@
|
||||
#ifndef __WORKFLOW_EDITOR_HPP__
|
||||
#define __WORKFLOW_EDITOR_HPP__
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include "imgui.h"
|
||||
#include "imnodes.h"
|
||||
#include "ID_Generator.hpp"
|
||||
#include "Nodes_And_Connectors.hpp"
|
||||
#include "Json_Utilities.hpp"
|
||||
|
||||
// 节点编辑器类
|
||||
class Workflow_Editor
|
||||
{
|
||||
protected:
|
||||
// ID 分配器
|
||||
Independent_ID_Generator Connector_ID_Generator; // 连接点ID生成器
|
||||
Independent_ID_Generator Node_ID_Generator; // 节点ID生成器
|
||||
Independent_ID_Generator Edge_ID_Generator; // 边ID生成器
|
||||
|
||||
// 边定义
|
||||
typedef struct
|
||||
{
|
||||
int id = -1; // 边ID
|
||||
int source_connector_id = -1; // 源连接点
|
||||
int target_connector_id = -1; // 目标连接点
|
||||
enum Edge_Type_Enum
|
||||
{
|
||||
EDGE_TYPE_NORMAL, // 普通边
|
||||
EDGE_TYPE_EXCLUSIVE, // 独占边
|
||||
} type = EDGE_TYPE_NORMAL;
|
||||
} Edge;
|
||||
|
||||
// 数据池
|
||||
std::vector<std::shared_ptr<Abs_Node>> Node_Pool; // 节点池
|
||||
std::vector<Edge> Edge_Pool; // 边池
|
||||
|
||||
// 配置剪切板
|
||||
Json_Object Config_Clipboard;
|
||||
|
||||
/**
|
||||
* 顶层索引为起始工作流节点(N个元素即N个处理流程)
|
||||
* 次级索引为工作序列,表示完成一个处理流程的非冲突序列
|
||||
*/
|
||||
std::vector<std::vector<std::shared_ptr<Abs_Node>>> Process_Route; // 工作层级路由
|
||||
|
||||
// 删除节点 返回迭代器指定位置的下一个位置的迭代器,仅限内部使用
|
||||
std::vector<std::shared_ptr<Abs_Node>>::iterator Del_Node(std::vector<std::shared_ptr<Abs_Node>>::iterator iterator);
|
||||
|
||||
// 删除边 返回迭代器指定位置的下一个位置的迭代器,仅限内部使用
|
||||
std::vector<Edge>::iterator Del_Link(std::vector<Edge>::iterator iterator);
|
||||
|
||||
// 从节点和边列表构建配置对象
|
||||
Json_Object Generate_Config(std::vector<std::shared_ptr<Abs_Node>> Node_List, std::vector<Edge> Edge_List);
|
||||
|
||||
// 从配置对象应用 true -> success / false -> failed
|
||||
bool Apply_Config(Json_Object Config_Object, ImVec2 initial_position = ImVec2(0, 0));
|
||||
|
||||
public:
|
||||
// 绘制节点编辑器
|
||||
void Show(void);
|
||||
|
||||
// 新增节点 true -> success / false -> failed
|
||||
bool Add_Node(Abs_Node::Node_Type_Enum type, ImVec2 initial_position = ImVec2(0, 0));
|
||||
|
||||
// 删除节点 true -> success / false -> failed
|
||||
bool Del_Node(int target_node_id);
|
||||
|
||||
// 新增连接 true -> success / false -> failed
|
||||
bool Add_Link(int source_connector_id, int target_connector_id);
|
||||
|
||||
// 删除连接 true -> success / false -> failed
|
||||
bool Del_Link(int source_connector_id, int target_connector_id);
|
||||
|
||||
// 创建工作路由 true -> success / false -> failed
|
||||
bool Build_Process_Route(void);
|
||||
|
||||
// 清除工作路由 true -> success / false -> failed
|
||||
bool Clear_Process_Route(void);
|
||||
|
||||
// 开始执行工作流
|
||||
bool Execute_Workflow(void);
|
||||
|
||||
// 清除整个工作区
|
||||
void Clear_All(void);
|
||||
|
||||
// 加载取配置文件 true -> success / false -> failed
|
||||
bool Load_Config(const char *file_path, ImVec2 initial_position = ImVec2(0, 0));
|
||||
|
||||
// 存储配置文件 true -> success / false -> failed
|
||||
bool Store_Config(const char *file_path);
|
||||
};
|
||||
|
||||
#endif
|
||||
+3269
-3268
File diff suppressed because it is too large
Load Diff
@@ -41,7 +41,7 @@ COMPLIER_PREFIX = \
|
||||
C_COMPLIER = $(strip $(COMPLIER_PREFIX))gcc
|
||||
|
||||
# C++编译工具
|
||||
C++_COMPLIER = $(strip $(COMPLIER_PREFIX))g++
|
||||
CXX_COMPLIER = $(strip $(COMPLIER_PREFIX))g++
|
||||
|
||||
# Windows 资源文件编译工具
|
||||
WIN_RES_COMPLIER = windres
|
||||
@@ -194,13 +194,13 @@ $(BUILD_DIR)/$(SUB_DIR_DEBUG): | $(BUILD_DIR)
|
||||
# Release 最终可执行文件编译任务
|
||||
$(BUILD_DIR)/$(SUB_DIR_RELEASE)/$(TARGET_FILE_NAME).exe: $(RELEASE_OBJECTS)
|
||||
@echo ====== [Release] All File Compiled. Now Linking... ======
|
||||
$(C++_COMPLIER) $(RELEASE_OBJECTS) -static -o $@ $(LIB_LINK) $(LDFLAGS)
|
||||
$(CXX_COMPLIER) $(RELEASE_OBJECTS) -static -s -o $@ $(LIB_LINK) $(LDFLAGS)
|
||||
@echo ====== [Release] Program Link Finished ======
|
||||
|
||||
# Debug 最终可执行文件编译任务
|
||||
$(BUILD_DIR)/$(SUB_DIR_DEBUG)/$(TARGET_FILE_NAME).exe: $(DEBUG_OBJECTS)
|
||||
@echo ====== [Debug] All File Compiled. Now Linking... ======
|
||||
$(C++_COMPLIER) $(DEBUG_OBJECTS) -static -o $@ $(LIB_LINK) $(LDFLAGS)
|
||||
$(CXX_COMPLIER) $(DEBUG_OBJECTS) -static -o $@ $(LIB_LINK) $(LDFLAGS)
|
||||
@echo ====== [Debug] Program Link Finished ======
|
||||
|
||||
# C Release 目标文件编译
|
||||
@@ -211,7 +211,7 @@ $(BUILD_DIR)/$(SUB_DIR_RELEASE)/%.o: %.c Makefile | $(BUILD_DIR)/$(SUB_DIR_RELEA
|
||||
# C++ Release 目标文件编译
|
||||
$(BUILD_DIR)/$(SUB_DIR_RELEASE)/%.o: %.cpp Makefile | $(BUILD_DIR)/$(SUB_DIR_RELEASE)
|
||||
@echo ====== [Release] C++ Source File "$<" Compiling... ======
|
||||
$(C++_COMPLIER) -c $(CXXFLAGS) $(RELEASE_OPT) -Wa,-a,-ad,-ahlms=$(BUILD_DIR)/$(SUB_DIR_RELEASE)/$(notdir $(<:.cpp=.lst)) $< -o $@
|
||||
$(CXX_COMPLIER) -c $(CXXFLAGS) $(RELEASE_OPT) -Wa,-a,-ad,-ahlms=$(BUILD_DIR)/$(SUB_DIR_RELEASE)/$(notdir $(<:.cpp=.lst)) $< -o $@
|
||||
|
||||
# Release 资源脚本文件编译
|
||||
$(BUILD_DIR)/$(SUB_DIR_RELEASE)/%.o: %.rc Makefile | $(BUILD_DIR)/$(SUB_DIR_RELEASE)
|
||||
@@ -226,7 +226,7 @@ $(BUILD_DIR)/$(SUB_DIR_DEBUG)/%.o: %.c Makefile | $(BUILD_DIR)/$(SUB_DIR_DEBUG)
|
||||
# C++ Debug 目标文件编译
|
||||
$(BUILD_DIR)/$(SUB_DIR_DEBUG)/%.o: %.cpp Makefile | $(BUILD_DIR)/$(SUB_DIR_DEBUG)
|
||||
@echo ====== [Debug] C++ Source File "$<" Compiling... ======
|
||||
$(C++_COMPLIER) -c $(CXXFLAGS) $(DEBUG_OPT) -g -Wa,-a,-ad,-ahlms=$(BUILD_DIR)/$(SUB_DIR_DEBUG)/$(notdir $(<:.cpp=.lst)) $< -o $@
|
||||
$(CXX_COMPLIER) -c $(CXXFLAGS) $(DEBUG_OPT) -g -Wa,-a,-ad,-ahlms=$(BUILD_DIR)/$(SUB_DIR_DEBUG)/$(notdir $(<:.cpp=.lst)) $< -o $@
|
||||
|
||||
# Debug 资源脚本文件编译
|
||||
$(BUILD_DIR)/$(SUB_DIR_DEBUG)/%.o: %.rc Makefile | $(BUILD_DIR)/$(SUB_DIR_DEBUG)
|
||||
|
||||
+17
-36
@@ -1,38 +1,19 @@
|
||||
#include "Command_Solve.hpp"
|
||||
#include "DLT_Utilities.hpp"
|
||||
#include "Global_Variables.hpp"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "windows.h"
|
||||
#include "CSV_Utilities.hpp"
|
||||
}
|
||||
|
||||
#include "CSV_Utilities.hpp"
|
||||
|
||||
DLT_Log File;
|
||||
|
||||
// 命令行处理
|
||||
void Pre_Command_Solve(void)
|
||||
{
|
||||
CSV_Table CSV;
|
||||
CSV.insert_column_before((unsigned)0, "First insert");
|
||||
CSV.append_column("Test column");
|
||||
CSV.append_column("Test column 2");
|
||||
CSV.append_column("Test column 3");
|
||||
CSV.insert_column_after("Test column 2", "Test insert column");
|
||||
CSV.insert_column_after("Test column 3", "Test insert column after End");
|
||||
|
||||
CSV.insert_column_before("Test column", "Test insert column before Head");
|
||||
CSV.insert_column_before("Test column", "Test insert column before Origin");
|
||||
|
||||
CSV.insert_cell_before("Test column 2", 0, "0");
|
||||
CSV.append_cell("Test column 2", "1");
|
||||
CSV.insert_cell_before("Test column 2", 0, "Insert");
|
||||
CSV.insert_cell_after("Test column 3", (unsigned)0, "Insert Cell");
|
||||
CSV.append_cell("Test column 3", "1");
|
||||
CSV.append_cell("Test column 3", "MyWawwww,dwadawdawd");
|
||||
CSV.append_cell("Test column 3", "3");
|
||||
|
||||
CSV.export_to_file("new.csv");
|
||||
|
||||
// 获取命令行
|
||||
int argc;
|
||||
LPWSTR *argv;
|
||||
@@ -41,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);
|
||||
}
|
||||
+275
-291
@@ -7,366 +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;
|
||||
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;
|
||||
|
||||
// 读取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)
|
||||
// 错误信息串
|
||||
std::string err_str;
|
||||
// 循环解析文件
|
||||
while (true)
|
||||
{
|
||||
free(Msg->payload_buffer);
|
||||
this->mem_use -= Msg->payload_length;
|
||||
Msg->payload_buffer = nullptr;
|
||||
DLT_Msg Msg = {0};
|
||||
|
||||
if (feof(p_file))
|
||||
return DLT_Type::DLT_ERROR_INCOMPLETE_DATA;
|
||||
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
|
||||
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;
|
||||
|
||||
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::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);
|
||||
char *p_sec_end = time_str + strlen(time_str) - 4;
|
||||
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);
|
||||
// 输出剩余的时间
|
||||
fprintf(p_file, ".%s,", p_sec_end);
|
||||
// 输出秒
|
||||
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(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] = {
|
||||
@@ -381,29 +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++;
|
||||
}
|
||||
|
||||
return DLT_Type::DLT_ERROR_NONE;
|
||||
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);
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
#include "Global_Variables.hpp"
|
||||
|
||||
// 主窗体句柄
|
||||
HWND Main_Window_hWnd = nullptr;
|
||||
|
||||
// D3D11 相关
|
||||
ID3D11Device *g_pd3dDevice = nullptr; // D3D11 设备句柄
|
||||
ID3D11DeviceContext *g_pd3dDeviceContext = nullptr; // D3D11 设备上下文句柄
|
||||
@@ -11,4 +14,7 @@ ID3D11RenderTargetView *g_mainRenderTargetView = nullptr; // D3D11 渲染目标
|
||||
|
||||
// 文件输入相关
|
||||
Input_File_Node *input_dlt_file_list_head;
|
||||
size_t input_dlt_file_count;
|
||||
size_t input_dlt_file_count;
|
||||
|
||||
// 节点编辑器
|
||||
class Workflow_Editor Workflow_Editor;
|
||||
@@ -0,0 +1,98 @@
|
||||
#include "ID_Generator.hpp"
|
||||
|
||||
// 请求ID
|
||||
int Independent_ID_Generator::Request_ID()
|
||||
{
|
||||
// 没有元素时
|
||||
if (this->continuous_id_list.size() == 0)
|
||||
{
|
||||
this->continuous_id_list.push_back({0, 0});
|
||||
|
||||
// 判定分配情况
|
||||
if (this->continuous_id_list.size() == 0)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 第一段未从最小 ID 开启
|
||||
auto first_iterator = this->continuous_id_list.begin();
|
||||
if (first_iterator->begin != 0)
|
||||
{
|
||||
if (first_iterator->begin == 1)
|
||||
first_iterator->begin--;
|
||||
else
|
||||
{
|
||||
// 划分新段
|
||||
size_t pre_size = this->continuous_id_list.size();
|
||||
first_iterator = this->continuous_id_list.insert(first_iterator, {0, 0});
|
||||
if (!(this->continuous_id_list.size() > pre_size))
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 仅第一段时
|
||||
if (this->continuous_id_list.size() == 1)
|
||||
{
|
||||
first_iterator->end++;
|
||||
return first_iterator->end;
|
||||
}
|
||||
|
||||
// 有两段及以上时,判断是否出现合并
|
||||
auto second_iterator = first_iterator + 1;
|
||||
if (first_iterator->end + 2 == second_iterator->begin)
|
||||
{
|
||||
int target_id = first_iterator->end + 1;
|
||||
first_iterator->end = second_iterator->end;
|
||||
this->continuous_id_list.erase(second_iterator);
|
||||
return target_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
first_iterator->end++;
|
||||
return first_iterator->end;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 释放ID true-> success / false -> fail
|
||||
bool Independent_ID_Generator::Release_ID(const int ID)
|
||||
{
|
||||
// 遍历查找所属片
|
||||
for (auto iterator = this->continuous_id_list.begin(); iterator != this->continuous_id_list.end(); iterator++)
|
||||
{
|
||||
// 找到对应的ID所属片
|
||||
if (ID >= iterator->begin && ID <= iterator->end)
|
||||
{
|
||||
// 散点删除
|
||||
if (iterator->begin == iterator->end)
|
||||
this->continuous_id_list.erase(iterator);
|
||||
else if (ID == iterator->begin) // 前端点
|
||||
iterator->begin++;
|
||||
else if (ID == iterator->end) // 后端点
|
||||
iterator->end--;
|
||||
else // 中间段
|
||||
{
|
||||
// 插入后返回新的迭代器
|
||||
size_t pre_size = this->continuous_id_list.size();
|
||||
iterator = this->continuous_id_list.insert(iterator, {iterator->begin, ID - 1});
|
||||
|
||||
// 判定分配是否成功
|
||||
if (!(this->continuous_id_list.size() > pre_size))
|
||||
return false;
|
||||
|
||||
// 记录ID
|
||||
iterator++;
|
||||
iterator->begin = ID + 1;
|
||||
}
|
||||
|
||||
// 完成并退出
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 没有找到所属片
|
||||
return false;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
+43
-23
@@ -12,6 +12,7 @@ extern "C"
|
||||
#include "d3d11.h"
|
||||
#include "tchar.h"
|
||||
#include "wchar.h"
|
||||
#include "locale.h"
|
||||
}
|
||||
|
||||
// 自定义头文件
|
||||
@@ -35,6 +36,9 @@ extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg
|
||||
// 入口主函数
|
||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
||||
{
|
||||
// 设置本地化以支持特殊字符
|
||||
setlocale(LC_ALL, ".UTF-8");
|
||||
|
||||
// 命令行前置处理
|
||||
Pre_Command_Solve();
|
||||
|
||||
@@ -61,20 +65,20 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
RegisterClassExW(&wc);
|
||||
|
||||
// 创建窗体
|
||||
HWND hwnd = CreateWindowW(wc.lpszClassName, // 创建的窗体类名
|
||||
MAIN_FRAME_TITTLE, // 窗体标题
|
||||
WS_OVERLAPPEDWINDOW, // 窗体风格为标准可重叠的顶层窗口
|
||||
100, // 起始坐标x
|
||||
100, // 起始坐标y
|
||||
(int)(MAIN_FRAME_SIZE_WIDTH_MIN * main_scale), // 窗体长
|
||||
(int)(MAIN_FRAME_SIZE_HEIGHT_MIN * main_scale), // 窗体宽
|
||||
nullptr, // 父窗体句柄
|
||||
nullptr, // 菜单句柄
|
||||
wc.hInstance, // 创建实例句柄
|
||||
nullptr); // 额外的事件参数指针
|
||||
Main_Window_hWnd = CreateWindowW(wc.lpszClassName, // 创建的窗体类名
|
||||
MAIN_FRAME_TITTLE, // 窗体标题
|
||||
WS_OVERLAPPEDWINDOW, // 窗体风格为标准可重叠的顶层窗口
|
||||
(GetSystemMetrics(SM_CXSCREEN) - (MAIN_FRAME_SIZE_WIDTH_MIN * main_scale)) / 2, // 起始坐标x,设置为屏幕正中
|
||||
(GetSystemMetrics(SM_CYSCREEN) - (MAIN_FRAME_SIZE_HEIGHT_MIN * main_scale)) / 2, // 起始坐标y,设置为屏幕正中
|
||||
(int)(MAIN_FRAME_SIZE_WIDTH_MIN * main_scale), // 窗体长
|
||||
(int)(MAIN_FRAME_SIZE_HEIGHT_MIN * main_scale), // 窗体宽
|
||||
nullptr, // 父窗体句柄
|
||||
nullptr, // 菜单句柄
|
||||
wc.hInstance, // 创建实例句柄
|
||||
nullptr); // 额外的事件参数指针
|
||||
|
||||
// 在窗体内创建 Direct 3D 设备
|
||||
if (!CreateDeviceD3D(hwnd))
|
||||
if (!CreateDeviceD3D(Main_Window_hWnd))
|
||||
{
|
||||
// 未创建完成时清理 Direct 3D 设备并清理窗体注册类
|
||||
CleanupDeviceD3D();
|
||||
@@ -85,11 +89,11 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
}
|
||||
|
||||
// 启用文件拖拽输入
|
||||
DragAcceptFiles(hwnd, TRUE);
|
||||
DragAcceptFiles(Main_Window_hWnd, TRUE);
|
||||
|
||||
// 显示窗体并强制更新一次窗体
|
||||
ShowWindow(hwnd, SW_SHOWDEFAULT);
|
||||
UpdateWindow(hwnd);
|
||||
ShowWindow(Main_Window_hWnd, SW_SHOWDEFAULT);
|
||||
UpdateWindow(Main_Window_hWnd);
|
||||
|
||||
// 检查版本
|
||||
IMGUI_CHECKVERSION();
|
||||
@@ -133,7 +137,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
}
|
||||
|
||||
// 初始化渲染器后端(Renderer backends)
|
||||
ImGui_ImplWin32_Init(hwnd);
|
||||
ImGui_ImplWin32_Init(Main_Window_hWnd);
|
||||
ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);
|
||||
|
||||
// 字体配置相关
|
||||
@@ -164,7 +168,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
{
|
||||
// 非阻塞式获取所有窗体消息,Pick消息后从消息队列删除,并转译和派发消息
|
||||
MSG msg;
|
||||
while (PeekMessage(&msg, nullptr, 0U, 0U, PM_REMOVE))
|
||||
while (PeekMessageW(&msg, nullptr, 0U, 0U, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&msg); // 转译
|
||||
DispatchMessageW(&msg); // 派发
|
||||
@@ -236,7 +240,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
ImNodes::DestroyContext(); // 销毁 ImNodes 上下文
|
||||
|
||||
CleanupDeviceD3D(); // 清理 Direct 3D 设备
|
||||
DestroyWindow(hwnd); // 销毁窗体
|
||||
DestroyWindow(Main_Window_hWnd); // 销毁窗体
|
||||
UnregisterClassW(wc.lpszClassName, wc.hInstance); // 取消窗体注册类
|
||||
|
||||
return 0;
|
||||
@@ -342,6 +346,10 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
// 获取拖拽的文件总数
|
||||
UINT fileCount = DragQueryFileW(hDrop, 0xFFFFFFFF, NULL, 0);
|
||||
|
||||
// 非法输入检测
|
||||
bool with_illegal_input = false;
|
||||
bool with_duplicated_input = false;
|
||||
|
||||
// 添加到文件列表
|
||||
for (UINT count = 0; count < fileCount; count++)
|
||||
{
|
||||
@@ -357,26 +365,31 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
int size_needed = WideCharToMultiByte(CP_UTF8, 0, filePath, -1, NULL, 0, NULL, NULL);
|
||||
WideCharToMultiByte(CP_UTF8, 0, filePath, -1, file_path_multi_byte, size_needed, NULL, NULL);
|
||||
|
||||
/**
|
||||
* @todo 文件类型筛选
|
||||
*/
|
||||
|
||||
// 重复文件剔除
|
||||
bool duplicated = false;
|
||||
for (Input_File_Node *p_file_node = input_dlt_file_list_head; p_file_node != nullptr; p_file_node = p_file_node->p_next)
|
||||
if (!strcmp(p_file_node->file_name_str, file_path_multi_byte))
|
||||
{
|
||||
duplicated = true;
|
||||
with_duplicated_input = true;
|
||||
break;
|
||||
}
|
||||
if (duplicated)
|
||||
continue;
|
||||
|
||||
// 文件类型后缀过滤
|
||||
const char *p_extension_name = file_path_multi_byte + (strlen(file_path_multi_byte) - 4);
|
||||
if (p_extension_name[0] != '.' || toupper(p_extension_name[1]) != 'D' || toupper(p_extension_name[2]) != 'L' || toupper(p_extension_name[3]) != 'T')
|
||||
{
|
||||
with_illegal_input = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 开辟新文件节点
|
||||
Input_File_Node *p_new_file_node = (Input_File_Node *)malloc(sizeof(Input_File_Node));
|
||||
p_new_file_node->file_name_str = (char *)malloc(strlen(file_path_multi_byte) + 1);
|
||||
memset(p_new_file_node->file_name_str, '\0', strlen(file_path_multi_byte) + 1);
|
||||
memcpy(p_new_file_node->file_name_str, file_path_multi_byte, strlen(file_path_multi_byte));
|
||||
memcpy(p_new_file_node->file_name_str, file_path_multi_byte, strlen(file_path_multi_byte) + 1);
|
||||
p_new_file_node->p_next = nullptr;
|
||||
|
||||
// 插入文件列表
|
||||
@@ -396,6 +409,13 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
|
||||
// 释放拖拽资源(必须调用,否则内存泄漏)
|
||||
DragFinish(hDrop);
|
||||
|
||||
if (with_duplicated_input)
|
||||
MessageBoxW(hWnd, L"存在重复输入", L"", MB_OK | MB_ICONWARNING);
|
||||
|
||||
if (with_illegal_input)
|
||||
MessageBoxW(hWnd, L"存在非法输入,仅支持 .dlt 文件", L"", MB_OK | MB_ICONWARNING);
|
||||
|
||||
return 0;
|
||||
}
|
||||
case WM_SIZE: // 窗体大小变事件
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+373
-15
@@ -1,9 +1,17 @@
|
||||
#include "UI_Layout.hpp"
|
||||
#include "imgui_impl_win32.h"
|
||||
#include "Global_Variables.hpp"
|
||||
#include "Config.hpp"
|
||||
#include "DLT_Utilities.hpp"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "windows.h"
|
||||
#include "stdio.h"
|
||||
}
|
||||
|
||||
#include "thread"
|
||||
|
||||
// UI布局
|
||||
void UI_Layout()
|
||||
{
|
||||
@@ -28,15 +36,58 @@ void UI_Layout()
|
||||
// 设置窗体相关属性,不允许停靠
|
||||
window_flags |= ImGuiWindowFlags_NoDocking;
|
||||
|
||||
// 临时设置一下窗体大小,动态扩张窗体
|
||||
{
|
||||
static size_t Width = MAIN_FRAME_SIZE_WIDTH_MIN;
|
||||
static size_t Height = MAIN_FRAME_SIZE_HEIGHT_MIN;
|
||||
if (!(Width >= 1400 && Height >= 700))
|
||||
{
|
||||
SetWindowPos(
|
||||
Main_Window_hWnd,
|
||||
NULL,
|
||||
(GetSystemMetrics(SM_CXSCREEN) - (Width)) / 2,
|
||||
(GetSystemMetrics(SM_CYSCREEN) - (Height)) / 2,
|
||||
Width,
|
||||
Height,
|
||||
SWP_NOZORDER);
|
||||
|
||||
if (Height < 700)
|
||||
Height += 5;
|
||||
if (Width < 1400)
|
||||
Width += 20;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Begin("Main Panel", NULL, window_flags); // 创建主面板
|
||||
ImGui::PopStyleVar(2); // 退出绘制风格栈中的设置项
|
||||
{
|
||||
const ImGuiStyle &style = ImGui::GetStyle();
|
||||
float main_scale = ImGui_ImplWin32_GetDpiScaleForMonitor(MonitorFromPoint(POINT{0, 0}, MONITOR_DEFAULTTOPRIMARY));
|
||||
|
||||
// 拖拽输入区域
|
||||
Widgets::Drag_Input_Area(ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().x / 2));
|
||||
// 左半部分
|
||||
ImGui::BeginChild("Left Part", ImVec2(MAIN_FRAME_SIZE_WIDTH_MIN, ImGui::GetContentRegionAvail().y));
|
||||
{
|
||||
|
||||
// 文件列表组件
|
||||
Widgets::File_List_Area();
|
||||
// 拖拽输入区域
|
||||
Widgets::Drag_Input_Area(ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().x / 2 > MAIN_FRAME_SIZE_WIDTH_MIN * main_scale / 2 ? MAIN_FRAME_SIZE_WIDTH_MIN * main_scale / 2 : ImGui::GetContentRegionAvail().x / 2));
|
||||
|
||||
// 文件列表组件
|
||||
Widgets::File_List_Area(ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y - (ImGui::GetTextLineHeightWithSpacing() + 20 * main_scale + style.ItemSpacing.y)));
|
||||
|
||||
// 导出文件
|
||||
Widgets::Control_Panel(ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetTextLineHeightWithSpacing() + 20 * main_scale));
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
// 右半部分
|
||||
ImGui::BeginChild("Right Part", ImVec2(0, 0));
|
||||
{
|
||||
// 工作流节点编辑器
|
||||
Workflow_Editor.Show();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
@@ -51,7 +102,130 @@ void Widgets::Drag_Input_Area(const ImVec2 &size)
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
|
||||
// 显示一个按钮,作为拖拽源
|
||||
static bool pressed_hover = false;
|
||||
ImGui::Button(pressed_hover ? u8"松开左键以添加" : u8"拖拽文件到此处", ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y));
|
||||
|
||||
if (ImGui::Button(pressed_hover ? u8"松开左键以添加" : u8"单击选择文件或拖拽文件到此处", ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y)))
|
||||
{
|
||||
OPENFILENAMEW ofn; // common dialog box structure
|
||||
wchar_t szFile[MAX_PATH * MAX_SINGLE_SELECT_FILE_COUNT] = {L'\0'}; // buffer for file name
|
||||
|
||||
// Initialize OPENFILENAME
|
||||
ZeroMemory(&ofn, sizeof(ofn));
|
||||
ofn.lStructSize = sizeof(ofn); // 结构体大小
|
||||
ofn.hwndOwner = Main_Window_hWnd; // 对话框唤起窗体
|
||||
ofn.lpstrFile = szFile; // 输出缓冲区
|
||||
ofn.nMaxFile = sizeof(szFile); // 缓冲区大小
|
||||
ofn.lpstrFilter = L"(.dlt)\0*.dlt\0"; // 文件格式筛选器
|
||||
ofn.nFilterIndex = 1; // 默认选择的筛选器
|
||||
|
||||
// 文件路径必须存在 | 文件本身必须存在 | 允许多文件选择 | 使用资源管理器
|
||||
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT | OFN_EXPLORER;
|
||||
|
||||
// Display the Open dialog box.
|
||||
|
||||
// 处理文件输入
|
||||
if (GetOpenFileNameW(&ofn))
|
||||
{
|
||||
// 重复输入检测
|
||||
bool with_duplicated_input = false;
|
||||
|
||||
wchar_t *p_first_str = ofn.lpstrFile;
|
||||
// 单文件
|
||||
if ((p_first_str[wcslen(p_first_str)] == L'\0') && (p_first_str[wcslen(p_first_str) + 1] == L'\0'))
|
||||
{
|
||||
char file_path_multi_byte[MAX_PATH] = {'\0'};
|
||||
int size_needed = WideCharToMultiByte(CP_UTF8, 0, p_first_str, -1, NULL, 0, NULL, NULL);
|
||||
WideCharToMultiByte(CP_UTF8, 0, p_first_str, -1, file_path_multi_byte, size_needed, NULL, NULL);
|
||||
|
||||
for (Input_File_Node *p_file_node = input_dlt_file_list_head; p_file_node != nullptr; p_file_node = p_file_node->p_next)
|
||||
if (!strcmp(p_file_node->file_name_str, file_path_multi_byte))
|
||||
{
|
||||
with_duplicated_input = true;
|
||||
break;
|
||||
}
|
||||
if (with_duplicated_input)
|
||||
{
|
||||
MessageBoxW(Main_Window_hWnd, L"存在重复输入", L"", MB_OK | MB_ICONWARNING);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// 开辟新文件节点
|
||||
Input_File_Node *p_new_file_node = (Input_File_Node *)malloc(sizeof(Input_File_Node));
|
||||
p_new_file_node->file_name_str = (char *)malloc(strlen(file_path_multi_byte) + 1);
|
||||
memset(p_new_file_node->file_name_str, '\0', strlen(file_path_multi_byte) + 1);
|
||||
memcpy(p_new_file_node->file_name_str, file_path_multi_byte, strlen(file_path_multi_byte) + 1);
|
||||
p_new_file_node->p_next = nullptr;
|
||||
|
||||
// 插入文件列表
|
||||
if (input_dlt_file_list_head == nullptr)
|
||||
input_dlt_file_list_head = p_new_file_node;
|
||||
else
|
||||
{
|
||||
Input_File_Node *p_target_node = input_dlt_file_list_head;
|
||||
for (size_t count = 1; count < input_dlt_file_count; count++)
|
||||
p_target_node = p_target_node->p_next;
|
||||
|
||||
p_target_node->p_next = p_new_file_node;
|
||||
}
|
||||
|
||||
input_dlt_file_count++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 多文件输入时
|
||||
char public_path_multi_byte[MAX_PATH] = {'\0'};
|
||||
int size_needed = WideCharToMultiByte(CP_UTF8, 0, p_first_str, -1, NULL, 0, NULL, NULL);
|
||||
WideCharToMultiByte(CP_UTF8, 0, p_first_str, -1, public_path_multi_byte, size_needed, NULL, NULL);
|
||||
|
||||
for (wchar_t *p_file_name_str = ofn.lpstrFile + wcslen(ofn.lpstrFile) + 1; *p_file_name_str != L'\0'; p_file_name_str += (wcslen(p_file_name_str) + 1))
|
||||
{
|
||||
char file_name_multi_byte[MAX_PATH] = {'\0'};
|
||||
char file_path_multi_byte[MAX_PATH] = {'\0'};
|
||||
int size_needed = WideCharToMultiByte(CP_UTF8, 0, p_file_name_str, -1, NULL, 0, NULL, NULL);
|
||||
WideCharToMultiByte(CP_UTF8, 0, p_file_name_str, -1, file_name_multi_byte, size_needed, NULL, NULL);
|
||||
|
||||
// 拼接完整路径
|
||||
sprintf(file_path_multi_byte, "%s\\%s", public_path_multi_byte, file_name_multi_byte);
|
||||
|
||||
for (Input_File_Node *p_file_node = input_dlt_file_list_head; p_file_node != nullptr; p_file_node = p_file_node->p_next)
|
||||
if (!strcmp(p_file_node->file_name_str, file_path_multi_byte))
|
||||
{
|
||||
with_duplicated_input = true;
|
||||
break;
|
||||
}
|
||||
if (with_duplicated_input)
|
||||
continue;
|
||||
|
||||
// 开辟新文件节点
|
||||
Input_File_Node *p_new_file_node = (Input_File_Node *)malloc(sizeof(Input_File_Node));
|
||||
p_new_file_node->file_name_str = (char *)malloc(strlen(file_path_multi_byte) + 1);
|
||||
memset(p_new_file_node->file_name_str, '\0', strlen(file_path_multi_byte) + 1);
|
||||
memcpy(p_new_file_node->file_name_str, file_path_multi_byte, strlen(file_path_multi_byte) + 1);
|
||||
p_new_file_node->p_next = nullptr;
|
||||
|
||||
// 插入文件列表
|
||||
if (input_dlt_file_list_head == nullptr)
|
||||
input_dlt_file_list_head = p_new_file_node;
|
||||
else
|
||||
{
|
||||
Input_File_Node *p_target_node = input_dlt_file_list_head;
|
||||
for (size_t count = 1; count < input_dlt_file_count; count++)
|
||||
p_target_node = p_target_node->p_next;
|
||||
|
||||
p_target_node->p_next = p_new_file_node;
|
||||
}
|
||||
|
||||
input_dlt_file_count++;
|
||||
}
|
||||
|
||||
if (with_duplicated_input)
|
||||
{
|
||||
MessageBoxW(Main_Window_hWnd, L"存在重复输入", L"", MB_OK);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 仅在外部拖拽入内时触发,内部拖拽不触发
|
||||
pressed_hover = (ImGui::IsItemHovered() && (GetAsyncKeyState(VK_LBUTTON) < 0) && (!ImGui::IsMouseDown(ImGuiMouseButton_Left)));
|
||||
|
||||
@@ -63,22 +237,52 @@ void Widgets::Drag_Input_Area(const ImVec2 &size)
|
||||
void Widgets::File_List_Area(const ImVec2 &size)
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 10.0f);
|
||||
ImGui::BeginChild("File_List_Area", ImVec2(size.x, size.y), ImGuiChildFlags_Border);
|
||||
ImGui::BeginChild("File_List_Area_Wrapper", size, ImGuiChildFlags_Border);
|
||||
ImGui::PopStyleVar();
|
||||
{
|
||||
|
||||
ImGui::Dummy(ImVec2(ImGui::GetContentRegionAvail().x - 30, ImGui::GetContentRegionAvail().y));
|
||||
int element_id = 0;
|
||||
Input_File_Node *p_file_node_pre = nullptr;
|
||||
Input_File_Node *p_file_node = input_dlt_file_list_head;
|
||||
for (size_t count = 0; count < input_dlt_file_count; count++)
|
||||
{
|
||||
ImGui::PushID(element_id++);
|
||||
|
||||
const float spacing = 4;
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 10.0f); // 绘制风格栈压入窗口圆角为10
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_GrabRounding, 10.0f); // 抓取条圆角
|
||||
static int int_value = 0;
|
||||
ImGui::SameLine();
|
||||
// 点击了删除
|
||||
if (ImGui::Button("X"))
|
||||
{
|
||||
if (p_file_node == input_dlt_file_list_head)
|
||||
{
|
||||
free(input_dlt_file_list_head->file_name_str);
|
||||
input_dlt_file_list_head = input_dlt_file_list_head->p_next;
|
||||
free(p_file_node);
|
||||
p_file_node = input_dlt_file_list_head;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_file_node_pre->p_next = p_file_node->p_next;
|
||||
free(p_file_node->file_name_str);
|
||||
free(p_file_node);
|
||||
}
|
||||
input_dlt_file_count--;
|
||||
count--;
|
||||
ImGui::PopID();
|
||||
continue;
|
||||
}
|
||||
|
||||
ImGui::VSliderInt("int", ImVec2(30, ImGui::GetContentRegionAvail().y), &int_value, 0, 5);
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::PopStyleVar(3);
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
ImGui::InputText("##Text_Show", p_file_node->file_name_str, strlen(p_file_node->file_name_str) + 1, ImGuiInputTextFlags_ElideLeft | ImGuiInputTextFlags_ReadOnly | ImGuiInputTextFlags_NoUndoRedo);
|
||||
|
||||
ImGui::PopID();
|
||||
|
||||
p_file_node = p_file_node->p_next;
|
||||
if (count == 0)
|
||||
p_file_node_pre = input_dlt_file_list_head;
|
||||
else
|
||||
p_file_node_pre = p_file_node_pre->p_next;
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
}
|
||||
@@ -105,4 +309,158 @@ void Widgets::Workflow_Area(const ImVec2 &size)
|
||||
ImNodes::EndNode();
|
||||
}
|
||||
ImNodes::EndNodeEditor();
|
||||
}
|
||||
|
||||
void Widgets::Control_Panel(const ImVec2 &size)
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 10.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
|
||||
ImGui::BeginChild("Control_Panel", size, ImGuiChildFlags_Border);
|
||||
ImGui::PopStyleVar(2);
|
||||
{
|
||||
static bool export_confirmed = false;
|
||||
static bool export_task_created = false;
|
||||
static char export_file_path_str[MAX_PATH] = {'\0'};
|
||||
|
||||
if (!export_confirmed)
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 10.0f);
|
||||
if (ImGui::Button(u8"导出", ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y)))
|
||||
{
|
||||
if (input_dlt_file_list_head == nullptr)
|
||||
MessageBoxW(Main_Window_hWnd, L"需要至少输入一个文件", L"", MB_OK | MB_ICONERROR);
|
||||
else
|
||||
{
|
||||
OPENFILENAMEW ofn; // common dialog box structure
|
||||
static wchar_t szFile[MAX_PATH] = {L'\0'}; // buffer for file name
|
||||
|
||||
// Initialize OPENFILENAME
|
||||
ZeroMemory(&ofn, sizeof(ofn));
|
||||
ofn.lStructSize = sizeof(ofn); // 结构体大小
|
||||
ofn.hwndOwner = Main_Window_hWnd; // 对话框唤起窗体
|
||||
ofn.lpstrFile = szFile; // 输出缓冲区
|
||||
ofn.nMaxFile = sizeof(szFile); // 缓冲区大小
|
||||
ofn.lpstrFilter = L"(.csv)\0*.csv\0"; // 文件格式筛选器
|
||||
ofn.nFilterIndex = 1; // 默认选择的筛选器
|
||||
|
||||
// 文件路径必须存在 | 文件本身必须存在 | 使用资源管理器
|
||||
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER;
|
||||
|
||||
if (GetSaveFileNameW(&ofn))
|
||||
{
|
||||
// 提取文件路径
|
||||
memset(export_file_path_str, '\0', sizeof(export_file_path_str));
|
||||
int size_needed = WideCharToMultiByte(CP_UTF8, 0, szFile, -1, NULL, 0, NULL, NULL);
|
||||
WideCharToMultiByte(CP_UTF8, 0, szFile, -1, export_file_path_str, size_needed, NULL, NULL);
|
||||
|
||||
wchar_t File_Name[MAX_PATH] = {L'\0'};
|
||||
wchar_t *p_str_end = szFile + wcslen(szFile);
|
||||
|
||||
// 处理后缀
|
||||
char *p_extension_name = export_file_path_str + (strlen(export_file_path_str) - 4);
|
||||
|
||||
if (p_extension_name[0] != '.' || toupper(p_extension_name[1]) != 'C' || toupper(p_extension_name[2]) != 'S' || toupper(p_extension_name[3]) != 'V')
|
||||
{
|
||||
p_extension_name += 4;
|
||||
p_extension_name[0] = '.';
|
||||
p_extension_name[1] = 'c';
|
||||
p_extension_name[2] = 's';
|
||||
p_extension_name[3] = 'v';
|
||||
|
||||
p_str_end[0] = L'.';
|
||||
p_str_end[1] = L'c';
|
||||
p_str_end[2] = L's';
|
||||
p_str_end[3] = L'v';
|
||||
}
|
||||
|
||||
while (p_str_end != szFile && *(p_str_end - 1) != L'\\')
|
||||
p_str_end--;
|
||||
|
||||
size_t len = wcslen(p_str_end);
|
||||
for (size_t count = 0; count < len; count++, p_str_end++)
|
||||
File_Name[count] = *p_str_end;
|
||||
|
||||
memcpy(szFile, File_Name, sizeof(File_Name));
|
||||
|
||||
// 判定是否覆盖文件
|
||||
FILE *p_file = fopen(export_file_path_str, "rb");
|
||||
if (p_file != nullptr)
|
||||
{
|
||||
fclose(p_file);
|
||||
if (MessageBoxW(Main_Window_hWnd, L"文件已存在,是否覆盖?", L"", MB_YESNO | MB_DEFBUTTON2 | MB_ICONWARNING) == IDYES)
|
||||
export_confirmed = true;
|
||||
}
|
||||
else
|
||||
export_confirmed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
else
|
||||
{
|
||||
// 创建导出任务
|
||||
if (!export_task_created)
|
||||
{
|
||||
export_task_created = true;
|
||||
|
||||
// 执行导出任务的线程
|
||||
std::thread export_thread(
|
||||
[&]()
|
||||
{
|
||||
DLT_Log Log;
|
||||
std::string err_str;
|
||||
|
||||
Input_File_Node *p_file_list = input_dlt_file_list_head;
|
||||
|
||||
while (p_file_list != nullptr)
|
||||
{
|
||||
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_str.empty())
|
||||
{
|
||||
Log.Sort();
|
||||
err_str = Log.Export_CSV(export_file_path_str);
|
||||
}
|
||||
|
||||
if (err_str.empty())
|
||||
{
|
||||
MessageBoxW(Main_Window_hWnd, L"导出完成", L"", MB_OK);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 工具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;
|
||||
};
|
||||
|
||||
// 输出错误信息
|
||||
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;
|
||||
});
|
||||
|
||||
// 分离线程
|
||||
export_thread.detach();
|
||||
}
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 12.5f);
|
||||
ImGui::ProgressBar(-1.0f * (float)ImGui::GetTime(), ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y), u8"正在导出...");
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user