基线:UDP 收包长度校验 + SQLite 表描述符重构 + 清理设计文档

This commit is contained in:
zjk
2026-08-19 22:31:23 +08:00
parent e455e2e9da
commit 7819ea621f
8 changed files with 486 additions and 1139 deletions
-128
View File
@@ -1,128 +0,0 @@
# PowerManager系统架构优化设计方案
## 1. 总体架构
```mermaid
classDiagram
class PowerManagerCore {
+startup()
+shutdown()
+getSystemState()
}
class StateMachineService {
+triggerEvent()
+getCurrentState()
+addStateListener()
}
class CommunicationMediator {
+registerHandler()
+sendMessage()
+addMessageListener()
}
PowerManagerCore --> StateMachineService
PowerManagerCore --> CommunicationMediator
```
## 2. 状态机重构方案
### 2.1 状态设计模式
```cpp
class IPowerState {
public:
virtual void onEntry(PowerContext&) = 0;
virtual void handleEvent(PowerContext&, const Event&) = 0;
virtual void onExit(PowerContext&) = 0;
};
```
### 2.2 状态转换规则
```yaml
# states_config.yaml
transitions:
- from: STANDBY
event: START_CMD
to: OPERATING
- from: OPERATING
event: STOP_CMD
to: STANDBY
```
## 3. 通信中介者设计
### 3.1 核心架构
```mermaid
sequenceDiagram
participant Upper as 上位机
participant Mediator as 通信中介者
participant Lower as 下位机
Upper->>Mediator: 控制命令(JSON)
Mediator->>Lower: 设备指令(ProtocolBuffer)
Lower->>Mediator: 状态更新
Mediator->>Upper: 系统报告
```
### 3.2 关键实现
```cpp
class CommunicationMediator {
// 线程安全消息队列
moodycamel::ConcurrentQueue<Message> queue;
// 消息处理线程
void processMessages() {
while (running) {
Message msg;
if (queue.try_dequeue(msg)) {
handlers[msg.type]->handle(msg);
}
}
}
};
```
## 4. 数据库服务设计
### 4.1 日志策略模式
```cpp
class ILogStrategy {
public:
virtual bool log(const SystemLog& log) = 0;
};
class SQLiteLogStrategy : public ILogStrategy {
// SQLite实现...
};
class FileLogStrategy : public ILogStrategy {
// 文件系统实现...
};
```
## 5. 实施计划
### 5.1 阶段划分
```mermaid
gantt
title 重构实施甘特图
section 核心框架
接口定义 :2025-04-08, 3d
基础实现 :2025-04-11, 5d
section 模块重构
状态机 :2025-04-16, 5d
通信模块 :2025-04-21, 5d
section 测试验证
单元测试 :2025-04-26, 3d
集成测试 :2025-04-29, 5d
```
## 6. 性能指标
| 模块 | 当前QPS | 目标QPS | 优化手段 |
|----------------|---------|---------|-----------------------|
| 状态机处理 | 100 | 500 | 无锁状态转换 |
| 消息处理 | 200 | 1000 | 批量处理+线程池 |
| 数据库写入 | 50 | 300 | 异步写入+批量提交 |
-277
View File
@@ -1,277 +0,0 @@
# 上位机控制程序设计文档
## 1. 程序架构设计
采用MVC模式设计,主要分为以下模块:
### 1.0 系统架构图
```mermaid
graph TD
A[用户界面] -->|控制指令| B[控制器]
B -->|发送命令| C[通信模块]
C -->|UDP协议| D[下位机]
D -->|状态反馈| C
C -->|解析数据| B
B -->|更新状态| A
B -->|记录数据| E[数据库]
```
### 1.1 消息处理流程
1. 接收原始UDP数据
2. 根据消息ID选择解析器
3. 验证校验码
4. 解析为结构化数据
5. 触发状态更新事件
6. 存储到数据库
### 1.1 通信模块 (Model) - 详细设计
#### 消息类型映射表
| 消息ID | 消息名称 | 处理函数 | 更新频率 |
|--------|----------|----------|----------|
| 0x0005 | 高压母线状态 | parse_high_vol_bus | 1Hz |
| 0x0006 | 高压A母线状态 | parse_high_a_vol_bus | 1Hz |
| 0x0007 | 低压主母线状态 | parse_low_main_bus | 1Hz |
| 0x0008 | 低压汇流排状态 | parse_low_bus | 1Hz |
#### 异常处理机制
1. 校验失败:丢弃数据并记录错误日志
2. 超时处理:3次重试后标记设备离线
3. 数据异常:触发告警并显示在界面
```python
class UDPMessageHandler:
"""UDP消息处理基类"""
def __init__(self, ip, port):
self.ip = ip
self.port = port
self.socket = None
def connect(self):
"""建立UDP连接"""
pass
def send_message(self, msg):
"""发送消息"""
pass
def receive_message(self):
"""接收消息"""
pass
def close(self):
"""关闭连接"""
pass
class PowerMessageHandler(UDPMessageHandler):
"""电源管理专用消息处理器"""
def __init__(self, ip, port):
super().__init__(ip, port)
self.message_parsers = {
0x0005: self.parse_high_vol_bus,
0x0006: self.parse_high_a_vol_bus,
# 其他消息类型...
}
def parse_high_vol_bus(self, data):
"""解析高压母线消息"""
pass
# 其他消息解析方法...
```
### 1.2 界面模块 (View) - 详细设计
#### 主界面布局
```mermaid
graph LR
A[标题栏] --> B[状态区]
B --> C[电压电流仪表盘]
B --> D[断路器状态指示灯]
A --> E[控制区]
E --> F[电源控制按钮组]
E --> G[参数设置面板]
A --> H[日志区]
H --> I[实时消息列表]
H --> J[历史记录查询]
```
#### 组件说明
1. 电压电流仪表盘:实时显示各母线电压电流值
2. 断路器状态指示灯:绿色-闭合,红色-断开
3. 电源控制按钮组:带防误触保护(需长按3秒)
4. 参数设置面板:输入验证和范围检查
```python
class MainWindow(tk.Tk):
"""主窗口"""
def __init__(self):
super().__init__()
self.title("电源管理系统")
self.geometry("1200x800")
self.create_widgets()
def create_widgets(self):
"""创建界面组件"""
self.status_frame = StatusFrame(self)
self.control_frame = ControlFrame(self)
self.log_frame = LogFrame(self)
# 布局管理
self.status_frame.pack(side=tk.TOP, fill=tk.X)
self.control_frame.pack(side=tk.LEFT, fill=tk.Y)
self.log_frame.pack(side=tk.RIGHT, expand=True, fill=tk.BOTH)
class StatusFrame(tk.Frame):
"""状态显示面板"""
def update_status(self, data):
"""更新状态显示"""
pass
class ControlFrame(tk.Frame):
"""控制面板"""
def create_buttons(self):
"""创建控制按钮"""
pass
```
### 1.3 控制器模块 (Controller) - 详细设计
#### 状态管理机制
1. 使用有限状态机(FSM)管理电源系统状态
2. 状态转换规则:
- 仅当所有预检通过才允许上电
- 故障时自动进入安全状态
- 人工确认后才能复位
#### 命令处理流程
```mermaid
sequenceDiagram
用户->>界面: 点击控制按钮
界面->>控制器: 发送控制命令
控制器->>业务逻辑: 验证命令有效性
业务逻辑->>通信模块: 发送UDP指令
通信模块->>下位机: 传输控制报文
下位机-->>通信模块: 返回应答
通信模块->>控制器: 更新命令状态
控制器->>界面: 显示操作结果
控制器->>数据库: 记录操作日志
```
```python
class PowerManagerController:
"""主控制器"""
def __init__(self):
self.message_handler = PowerMessageHandler("192.168.1.100", 5000)
self.view = MainWindow()
# 绑定事件
self.bind_events()
def bind_events(self):
"""绑定UI事件"""
self.view.control_frame.on_button_click = self.handle_control_command
def handle_control_command(self, cmd):
"""处理控制命令"""
pass
def start(self):
"""启动应用程序"""
self.message_handler.connect()
self.view.mainloop()
```
## 2. 接口规范
### 2.1 模块交互架构
```mermaid
classDiagram
class Communication {
+send_command(cmd: dict) bool
+get_status() dict
+subscribe(callback: function)
+on_message_received(data: bytes)
}
class Controller {
+handle_ui_event(event: dict)
+update_system_status(status: dict)
+log_operation(log: dict)
}
class UI {
+update_status(data: dict)
+show_alert(level: int, msg: str)
+log_message(source: str, msg: str)
}
Communication --> Controller : 状态更新通知
Controller --> UI : 界面更新指令
UI --> Controller : 用户操作事件
```
### 2.2 详细接口定义
#### 通信模块 → 控制器
```python
# 状态更新通知
{
"msg_type": "status_update",
"timestamp": "2025-05-04T10:20:00",
"data": {
"voltage": 220.5,
"current": 15.2,
"breaker_state": True
}
}
# 错误通知
{
"msg_type": "error",
"code": 1001,
"message": "校验失败"
}
```
#### 控制器 → 界面
```python
# 状态显示更新
{
"component": "voltage_meter",
"value": 220.5,
"unit": "V",
"normal_range": [210, 230]
}
# 告警信息
{
"level": 2, # 1-警告 2-错误 3-严重
"message": "A相电压过高",
"suggestion": "检查A相负载"
}
```
#### 界面 → 控制器
```python
# 按钮操作事件
{
"event_type": "button_click",
"button_id": "power_on",
"timestamp": "2025-05-04T10:20:01"
}
# 参数设置事件
{
"event_type": "param_set",
"param": "voltage_limit",
"value": 230,
"unit": "V"
}
```
### 2.3 错误处理规范
1. 通信错误:自动重试3次后通知控制器
2. 业务逻辑错误:记录详细日志并通知界面
3. 界面错误:显示友好提示并保持最后正常状态
## 3. 数据库设计
(之前已完成的数据库表结构...)
+2 -1
View File
@@ -342,12 +342,13 @@ bool LowerCommManager::listenThreadFunc()
{
try
{
memset(Buff, 0, sizeof(Buff));
int nRead = m_udpComm->udpScoket->iRecieveMessage(Buff, sizeof(Buff));
cout<<MOOS::ConsoleColours::yellow()<< "RECEVE DATA COUNT:" << nRead << MOOS::ConsoleColours::reset() << endl;
if(nRead > 0)
{
try {
if(m_udpComm->pushMsgToQueue(Buff))
if(m_udpComm->pushMsgToQueue(Buff, nRead))
{
//更新当前状态
if(!updatePoweSystemStates())
File diff suppressed because it is too large Load Diff
+12 -2
View File
@@ -66,12 +66,22 @@ private:
bool createTableInternal(const std::string& tableName, const std::string& columns);
bool createAllTablesUnlocked();
// 泛化插入:表名 + 列描述(名称 + 绑定器),所有类型共用这一条路径
// 列描述:名称 + SQL 类型 + 绑定器(无捕获函数指针)
struct Column {
const char* name;
const char* sqlType;
void (*bind)(sqlite3_stmt*, int& idx, const void* obj);
};
bool insertGeneric(const std::string& table, const std::vector<Column>& cols, const void* obj);
// 表描述:表名 + 数据列。建表(DDL)与插入(DML)共用这一份,作为唯一数据源。
struct TableDesc {
const char* name;
std::vector<Column> columns;
};
// 泛化插入:按表名在注册表中查找描述并绑定,所有类型共用这一条路径
bool insertGeneric(const char* tableName, const void* obj);
// 所有协议结构表的描述注册表(不含 msg_log 等特殊表)
static const std::vector<TableDesc>& allTables();
};
#endif // SQLITE_H
+44 -23
View File
@@ -36,8 +36,11 @@ Checksum udpComm::calculateChecksum(const unsigned char* data, int dataSize, int
}
return checksum;
}
bool udpComm::getMsgId(char *m,unsigned short &id)
bool udpComm::getMsgId(char *m, size_t len, unsigned short &id)
{
if (m == NULL || len < sizeof(m_header)) {
return false;
}
m_header h;
h = *reinterpret_cast<m_header *>(m);
// 判断消息是否有效
@@ -56,7 +59,11 @@ bool udpComm::getMsgId(char *m,unsigned short &id)
// LOG_F(ERROR, "Msg Header errar start1: %d, start2: %d", h.start1, h.start2);
return false;
}
bool udpComm::getMsgFromBuff(char *m, msg_CcuStateFbMsg &s) {
bool udpComm::getMsgFromBuff(char *m, size_t len, msg_CcuStateFbMsg &s) {
if (m == NULL || len < sizeof(msg_CcuStateFbMsg)) {
sError.push_back("CcuStat Msg length error");
return false;
}
Checksum sum;
msg_CcuStateFbMsg *p;
p = reinterpret_cast<msg_CcuStateFbMsg *>(m);
@@ -69,8 +76,12 @@ bool udpComm::getMsgFromBuff(char *m, msg_CcuStateFbMsg &s) {
return true;
}
bool udpComm::getMsgFromBuff(char *m, msg_CcuSetParmFbMsg &s)
bool udpComm::getMsgFromBuff(char *m, size_t len, msg_CcuSetParmFbMsg &s)
{
if (m == NULL || len < sizeof(msg_CcuSetParmFbMsg)) {
sError.push_back("CcuSetParm Msg length error");
return false;
}
Checksum sum;
msg_CcuSetParmFbMsg *p;
p = reinterpret_cast<msg_CcuSetParmFbMsg *>(m);
@@ -85,8 +96,12 @@ bool udpComm::getMsgFromBuff(char *m, msg_CcuSetParmFbMsg &s)
return true;
}
bool udpComm::getMsgFromBuff(char *m, msg_disHighVolBusFbMsg &s)
bool udpComm::getMsgFromBuff(char *m, size_t len, msg_disHighVolBusFbMsg &s)
{
if (m == NULL || len < sizeof(msg_disHighVolBusFbMsg)) {
sError.push_back("DisSys HVBus Msg length error");
return false;
}
cChecksum sum;
msg_disHighVolBusFbMsg *p;
p = reinterpret_cast<msg_disHighVolBusFbMsg *>(m);
@@ -101,8 +116,12 @@ bool udpComm::getMsgFromBuff(char *m, msg_disHighVolBusFbMsg &s)
return true;
}
bool udpComm::getMsgFromBuff(char *m, msg_disHighAVolBusFbMsg &s)
bool udpComm::getMsgFromBuff(char *m, size_t len, msg_disHighAVolBusFbMsg &s)
{
if (m == NULL || len < sizeof(msg_disHighAVolBusFbMsg)) {
sError.push_back("DisSys HVABus Msg length error");
return false;
}
cChecksum sum;
msg_disHighAVolBusFbMsg *p;
p = reinterpret_cast<msg_disHighAVolBusFbMsg *>(m);
@@ -115,8 +134,12 @@ bool udpComm::getMsgFromBuff(char *m, msg_disHighAVolBusFbMsg &s)
s = *p;
return true;
}
bool udpComm::getMsgFromBuff(char *m, msg_disLowMainBusFbMsg &s)
bool udpComm::getMsgFromBuff(char *m, size_t len, msg_disLowMainBusFbMsg &s)
{
if (m == NULL || len < sizeof(msg_disLowMainBusFbMsg)) {
sError.push_back("DisSys HVBBus Msg length error");
return false;
}
cChecksum sum;
msg_disLowMainBusFbMsg *p;
p = reinterpret_cast<msg_disLowMainBusFbMsg *>(m);
@@ -130,8 +153,12 @@ bool udpComm::getMsgFromBuff(char *m, msg_disLowMainBusFbMsg &s)
return true;
}
bool udpComm::getMsgFromBuff(char *m, msg_disLowBusFbMsg &s)
bool udpComm::getMsgFromBuff(char *m, size_t len, msg_disLowBusFbMsg &s)
{
if (m == NULL || len < sizeof(msg_disLowBusFbMsg)) {
sError.push_back("DisSys LVBus Msg length error");
return false;
}
cChecksum sum;
msg_disLowBusFbMsg *p;
p = reinterpret_cast<msg_disLowBusFbMsg *>(m);
@@ -145,35 +172,29 @@ bool udpComm::getMsgFromBuff(char *m, msg_disLowBusFbMsg &s)
return true;
}
bool udpComm::pushMsgToQueue(unsigned char *m)
bool udpComm::pushMsgToQueue(unsigned char *m, size_t len)
{
if(m==NULL)
if(m==NULL || len < sizeof(m_header))
{
// sError.push_back("pushMsgToQueue faile,Msg is NULL");
LOG_F(ERROR, "pushMsgToQueue faile,Msg is NULL m: %p", m);
LOG_F(ERROR, "pushMsgToQueue faile,Msg is NULL or too short m: %p len: %zu", m, len);
return false;
}
unsigned char* Buff = m;
//消息头鉴定
char *header = new char[sizeof(m_header)];
unsigned short id;
memcpy(header,Buff,sizeof(m_header));
if(!getMsgId(header,id))
if(!getMsgId((char *)Buff, len, id))
{
// sError.push_back("pushMsgToQueue faile,Msg ID error");
// LOG_F(INFO, "pushMsgToQueue faile,Msg ID error header: %p", header);
delete []header;
return false;
}
delete []header;
//输入消息
switch (id)
{
case CCU_STATE_FB_ID: //CCU_STATE_FB 0x0051
{
msg_CcuStateFbMsg s;
if(getMsgFromBuff((char *)Buff,s))
if(getMsgFromBuff((char *)Buff, len, s))
{
if (m_commLogger) m_commLogger->onFrame(0, id, "ccuState", Buff, sizeof(msg_CcuStateFbMsg), true);
std::lock_guard<std::mutex> lock(m_mutexCcuState);
@@ -198,7 +219,7 @@ bool udpComm::pushMsgToQueue(unsigned char *m)
case CCU_SET_PARM_FB_ID: //CCU_SET_PARM_FB 0x0040
{
msg_CcuSetParmFbMsg s;
if(getMsgFromBuff((char *)Buff,s))
if(getMsgFromBuff((char *)Buff, len, s))
{
if (m_commLogger) m_commLogger->onFrame(0, id, "ccuSetParmFb", Buff, sizeof(msg_CcuSetParmFbMsg), true);
std::lock_guard<std::mutex> lock(m_mutexCcuSetParm);
@@ -223,7 +244,7 @@ bool udpComm::pushMsgToQueue(unsigned char *m)
case DIS_HVBUS_FB_ID: //DIS_HVBUS_FB 0x0020
{
msg_disHighVolBusFbMsg s;
if(getMsgFromBuff((char *)Buff,s))
if(getMsgFromBuff((char *)Buff, len, s))
{
if (m_commLogger) m_commLogger->onFrame(0, id, "disHighVolBusState", Buff, sizeof(msg_disHighVolBusFbMsg), true);
std::lock_guard<std::mutex> lock(m_mutexDisHighVolBus);
@@ -248,7 +269,7 @@ bool udpComm::pushMsgToQueue(unsigned char *m)
case DIS_HVBUSA_FB_ID: //DIS_HVBUSA_FB 0x0006
{
msg_disHighAVolBusFbMsg s;
if(getMsgFromBuff((char *)Buff,s))
if(getMsgFromBuff((char *)Buff, len, s))
{
if (m_commLogger) m_commLogger->onFrame(0, id, "disHighAVolBusState", Buff, sizeof(msg_disHighAVolBusFbMsg), true);
std::lock_guard<std::mutex> lock(m_mutexDisHighAVolBus);
@@ -273,7 +294,7 @@ bool udpComm::pushMsgToQueue(unsigned char *m)
case DIS_HVBUSB_FB_ID: //DIS_HVBUSB_FB 0x0007
{
msg_disLowMainBusFbMsg s;
if(getMsgFromBuff((char *)Buff,s))
if(getMsgFromBuff((char *)Buff, len, s))
{
if (m_commLogger) m_commLogger->onFrame(0, id, "disLowMainBusState", Buff, sizeof(msg_disLowMainBusFbMsg), true);
std::lock_guard<std::mutex> lock(m_mutexDisHighBVolBus);
@@ -298,7 +319,7 @@ bool udpComm::pushMsgToQueue(unsigned char *m)
case DIS_LVBUS_FB_ID: //DIS_LVBUS_FB 0x0008
{
msg_disLowBusFbMsg s;
if(getMsgFromBuff((char *)Buff,s))
if(getMsgFromBuff((char *)Buff, len, s))
{
if (m_commLogger) m_commLogger->onFrame(0, id, "disLowBusState", Buff, sizeof(msg_disLowBusFbMsg), true);
std::lock_guard<std::mutex> lock(m_mutexDisLowBus);
+8 -8
View File
@@ -27,15 +27,15 @@ public:
string ccuHost;
long int ccuPort;
bool pushMsgToQueue(unsigned char *m);
bool pushMsgToQueue(unsigned char *m, size_t len);
bool clearMsgQueue();
bool getMsgFromBuff(char *m, msg_CcuStateFbMsg &s);
bool getMsgFromBuff(char *m, msg_CcuSetParmFbMsg &s);
bool getMsgFromBuff(char *m, msg_disHighVolBusFbMsg &s);
bool getMsgFromBuff(char *m, msg_disHighAVolBusFbMsg &s);
bool getMsgFromBuff(char *m, msg_disLowMainBusFbMsg &s);
bool getMsgFromBuff(char *m, msg_disLowBusFbMsg &s);
bool getMsgFromBuff(char *m, size_t len, msg_CcuStateFbMsg &s);
bool getMsgFromBuff(char *m, size_t len, msg_CcuSetParmFbMsg &s);
bool getMsgFromBuff(char *m, size_t len, msg_disHighVolBusFbMsg &s);
bool getMsgFromBuff(char *m, size_t len, msg_disHighAVolBusFbMsg &s);
bool getMsgFromBuff(char *m, size_t len, msg_disLowMainBusFbMsg &s);
bool getMsgFromBuff(char *m, size_t len, msg_disLowBusFbMsg &s);
bool popMsgFormQueue(double &time,msg_CcuStateFbMsg &m);
bool popMsgFormQueue(double &time,msg_CcuSetParmFbMsg &m);
@@ -78,7 +78,7 @@ public:
return false;
}
bool getMsgId(char *m,unsigned short &id);
bool getMsgId(char *m, size_t len, unsigned short &id);
Checksum calculateChecksum(const unsigned char* data, int size);
Checksum calculateChecksum(const unsigned char* data, int dataSize, int checkSize);
+68 -7
View File
@@ -31,7 +31,7 @@ TEST(UdpCommTest, GetMsgId)
h.start2 = DIS_MSG_HEAD2;
h.id = DIS_HVBUS_FB_ID;
memcpy(buf, &h, sizeof(h));
EXPECT_TRUE(u.getMsgId(buf, id));
EXPECT_TRUE(u.getMsgId(buf, sizeof(buf), id));
EXPECT_EQ(id, DIS_HVBUS_FB_ID);
// CCU 头
@@ -39,14 +39,18 @@ TEST(UdpCommTest, GetMsgId)
h.start2 = CCU_UDPMSG_START2;
h.id = CCU_STATE_FB_ID;
memcpy(buf, &h, sizeof(h));
EXPECT_TRUE(u.getMsgId(buf, id));
EXPECT_TRUE(u.getMsgId(buf, sizeof(buf), id));
EXPECT_EQ(id, CCU_STATE_FB_ID);
// 非法头
h.start1 = 0x11;
h.start2 = 0x22;
memcpy(buf, &h, sizeof(h));
EXPECT_FALSE(u.getMsgId(buf, id));
EXPECT_FALSE(u.getMsgId(buf, sizeof(buf), id));
// 长度不足 m_header → 拒绝(不读越界)
EXPECT_FALSE(u.getMsgId(buf, sizeof(m_header) - 1, id));
EXPECT_FALSE(u.getMsgId(NULL, sizeof(m_header), id));
}
TEST(UdpCommTest, GetMsgFromBuffCcu)
@@ -63,14 +67,34 @@ TEST(UdpCommTest, GetMsgFromBuffCcu)
m.checkCode = u.calculateChecksum((unsigned char*)&m, sizeof(m));
msg_CcuStateFbMsg out{};
EXPECT_TRUE(u.getMsgFromBuff((char*)&m, out));
EXPECT_TRUE(u.getMsgFromBuff((char*)&m, sizeof(m), out));
EXPECT_EQ(out.data.ins_soc, 42u);
EXPECT_EQ(out.data.dyn_soc, 66u);
EXPECT_EQ(out.data.fc_status, 0x04u);
// 篡改数据 → 校验失败
m.data.dyn_soc = 99;
EXPECT_FALSE(u.getMsgFromBuff((char*)&m, out));
EXPECT_FALSE(u.getMsgFromBuff((char*)&m, sizeof(m), out));
// 截断帧(长度不足)→ 拒绝,不写输出
m.data.dyn_soc = 66;
m.checkCode = u.calculateChecksum((unsigned char*)&m, sizeof(m));
msg_CcuStateFbMsg untouched{};
untouched.data.ins_soc = 0xEE;
EXPECT_FALSE(u.getMsgFromBuff((char*)&m, sizeof(m) - 1, untouched));
EXPECT_EQ(untouched.data.ins_soc, 0xEEu);
// 超长帧(长度超出)→ 接受,忽略尾字节
unsigned char longBuf[sizeof(m) + 16];
memset(longBuf, 0, sizeof(longBuf));
memcpy(longBuf, &m, sizeof(m));
msg_CcuStateFbMsg outLong{};
EXPECT_TRUE(u.getMsgFromBuff((char*)longBuf, sizeof(longBuf), outLong));
EXPECT_EQ(outLong.data.ins_soc, 42u);
// 空指针 / 长度不足 → 拒绝
EXPECT_FALSE(u.getMsgFromBuff(NULL, sizeof(m), out));
EXPECT_FALSE(u.getMsgFromBuff((char*)&m, 0, out));
}
TEST(UdpCommTest, GetMsgFromBuffDis)
@@ -86,13 +110,50 @@ TEST(UdpCommTest, GetMsgFromBuffDis)
m.checkCode = (cChecksum)(u.calculateChecksum((unsigned char*)&m, sizeof(m), sizeof(cChecksum)) & 0xFF);
msg_disHighVolBusFbMsg out{};
EXPECT_TRUE(u.getMsgFromBuff((char*)&m, out));
EXPECT_TRUE(u.getMsgFromBuff((char*)&m, sizeof(m), out));
EXPECT_EQ(out.data.fuelCellCircuitBreaker, 0x55u);
EXPECT_EQ(out.data.powerBusVoltage, 5200u);
// 篡改 → 校验失败
m.data.fuelCellCircuitBreaker = 0xAA;
EXPECT_FALSE(u.getMsgFromBuff((char*)&m, out));
EXPECT_FALSE(u.getMsgFromBuff((char*)&m, sizeof(m), out));
// 截断帧 → 拒绝
m.data.fuelCellCircuitBreaker = 0x55;
m.checkCode = (cChecksum)(u.calculateChecksum((unsigned char*)&m, sizeof(m), sizeof(cChecksum)) & 0xFF);
EXPECT_FALSE(u.getMsgFromBuff((char*)&m, sizeof(m) - 1, out));
}
TEST(UdpCommTest, PushMsgToQueueLengthGuard)
{
udpComm u;
msg_CcuStateFbMsg m;
memset(&m, 0, sizeof(m));
m.header.start1 = CCU_UDPMSG_START1;
m.header.start2 = CCU_UDPMSG_START2;
m.header.id = CCU_STATE_FB_ID;
m.data.ins_soc = 42;
m.checkCode = u.calculateChecksum((unsigned char*)&m, sizeof(m));
// 合法帧入队成功
EXPECT_TRUE(u.pushMsgToQueue((unsigned char*)&m, sizeof(m)));
EXPECT_EQ(u.m_qReceiveCcuStateBuffer.size(), 1u);
EXPECT_EQ(u.m_qReceiveCcuStateBuffer.front().second.data.ins_soc, 42u);
// 空指针 / 长度不足 m_header → 拒绝
EXPECT_FALSE(u.pushMsgToQueue(NULL, sizeof(m)));
EXPECT_FALSE(u.pushMsgToQueue((unsigned char*)&m, sizeof(m_header) - 1));
// 截断帧(合法头 + 校验和,但长度不足整包)→ 拒绝入队
msg_CcuStateFbMsg shortM;
memset(&shortM, 0, sizeof(shortM));
shortM.header.start1 = CCU_UDPMSG_START1;
shortM.header.start2 = CCU_UDPMSG_START2;
shortM.header.id = CCU_STATE_FB_ID;
shortM.checkCode = u.calculateChecksum((unsigned char*)&shortM, sizeof(shortM) - 8);
size_t before = u.m_qReceiveCcuStateBuffer.size();
EXPECT_FALSE(u.pushMsgToQueue((unsigned char*)&shortM, sizeof(shortM) - 8));
EXPECT_EQ(u.m_qReceiveCcuStateBuffer.size(), before);
}
TEST(UdpCommTest, GetDate)