# DTU-HMI 通信协议设计文档 ## 1. 文档说明 - 文档名称:`DTU-HMI` 通信协议设计文档 - 协议名称:RemoDispBus(项目内实现) - 适用范围:`DTU-HMI` 与远程显示上位机(如 `remo_disp_server.py`)之间的 TCP 通信 - 对应实现:`src/remoteDisplay.c`、`src/remoteDisplay.h` ## 2. 协议目标 本协议用于实现以下能力: - 上位机与设备端建立会话并获取显示参数 - 上位机按需读取 LCD 显存内容用于渲染 - 上位机向设备端下发按键事件 - 维持连接活性(保活) ## 3. 传输层与连接模型 - 传输层:TCP - 服务器角色:`DTU-HMI`(设备端) - 客户端角色:远程显示上位机 - 默认监听端口:`7003` - 连接模式:单连接处理(当前连接断开后继续接受下一连接) 连接与处理流程(文字图): ```text [TcpServer_Listen:7003] | v [Accept 客户端连接] | v [接收并累积缓冲区数据] | v [解析完整协议帧] | 成功 | 不完整/非法 v v [命令分发与处理] [继续接收数据] | v [发送应答帧] | v [继续处理当前连接,直到断开] ``` ## 4. 帧结构定义 ### 4.1 通用帧格式 协议帧格式如下: ```text [TAG][CMD][LEN_H][LEN_L][DATA...][CRC] ``` 字段说明: - `TAG`:1 字节,报文方向标记 - `CMD`:1 字节,命令码 - `LEN_H` + `LEN_L`:2 字节,大端,表示 `DATA` 长度 - `DATA`:可变长,长度由 `LEN` 指定 - `CRC`:1 字节,`DATA` 区逐字节异或 ### 4.2 TAG 约定 - 客户端 -> 设备端:`0xAA` - 设备端 -> 客户端:`0xBB` ### 4.3 CRC 算法 - 初值:`0x00` - 计算范围:仅 `DATA` 字段 - 算法:`crc = data[0] ^ data[1] ^ ... ^ data[n-1]` - `DATA` 长度为 0 时,CRC 结果为 `0x00` ## 5. 命令字定义 当前实现支持 4 个命令: - `0x00`:`CMD_KEEPLIVE` - `0x01`:`CMD_INIT` - `0x02`:`CMD_KEY` - `0x03`:`CMD_LCDMEM` ## 6. 命令详细设计 ### 6.1 CMD_KEEPLIVE(0x00) #### 请求 - `DATA`:空(长度 0) #### 响应 - `CMD`:`0x00` - `DATA`:空(长度 0) - 用于连接保活与链路探测 --- ### 6.2 CMD_INIT(0x01) #### 请求 - `DATA`:空(长度 0) #### 响应 - `DATA` 长度:8 字节 - 格式: ```text [LCD_W_H][LCD_W_L][LCD_H_H][LCD_H_L][MEM_B3][MEM_B2][MEM_B1][MEM_B0] ``` 字段含义: - `LCD_W`:屏幕宽度(当前为 `160`) - `LCD_H`:屏幕高度(当前为 `160`) - `MEM`:显存总字节数(当前为 `160 * 160 = 25600`) 字节序:全部为大端编码 --- ### 6.3 CMD_KEY(0x02) #### 请求 - `DATA`:至少 1 字节 - `DATA[0]`:按键值(如 `KEY_U/KEY_D/KEY_L/KEY_R/KEY_ENT/KEY_ESC`) #### 处理行为 - 设备端将按键写入: - `g_tRemoteKey.byKeyValid = EN_KEY_FLAG_NEW` - `g_tRemoteKey.byKeyValue = DATA[0]` #### 响应 - 当前实现:不发送显式响应帧 - 建议:后续版本增加 ACK,以便上位机确认按键注入结果 --- ### 6.4 CMD_LCDMEM(0x03) #### 请求 - `DATA` 长度:建议 4 字节 - 格式:`[ADDR_B3][ADDR_B2][ADDR_B1][ADDR_B0]`(大端起始地址) 若请求长度小于 4,设备端默认起始地址为 0。 #### 响应 - `DATA` 格式: ```text [ADDR_B3][ADDR_B2][ADDR_B1][ADDR_B0][LCD_MEM_SLICE...] ``` - 前 4 字节回显起始地址 - 后续为显存片段: - 若 `start_addr < LCD_DISPLAYMEMORYSIZE`,返回从该地址到末尾的全部显存 - 若 `start_addr >= LCD_DISPLAYMEMORYSIZE`,仅返回 4 字节地址(无显存数据) ## 7. 帧解析与容错策略 设备端接收缓冲解析规则: 1. 至少 5 字节才可判定为候选帧(最小帧) 2. 首字节必须是 `TAG_CLIENT(0xAA)` 3. 根据 `LEN` 计算总帧长:`4 + len + 1` 4. 缓冲长度不足总帧长时,继续接收 5. CRC 不匹配则视为非法帧 6. 成功解析后按 `consume` 字节从缓冲区移除 异常处理策略: - 长时间无法成帧且缓冲接近上限(`4096-256`)时,清空缓冲防止越界 - `recv` 返回 `0` 或 `<0`,认为连接结束,关闭当前客户端 - 未知命令:回空应答(同命令码,空 `DATA`) ## 8. 协议示例报文 说明:以下示例均为十六进制字节流。 ### 8.1 KEEPLIVE 请求/响应 - 请求:`AA 00 00 00 00` - `CRC=00`(空数据) - 响应:`BB 00 00 00 00` ### 8.2 INIT 请求/响应(示意) - 请求:`AA 01 00 00 00` - 响应头:`BB 01 00 08 ... CRC` - 响应 `DATA` 示例(160x160,25600): - `00 A0 00 A0 00 00 64 00` ### 8.3 KEY 请求(上键示例) - 若上键值为 `0x02`,请求可为: - `AA 02 00 01 02 02` - 其中末尾 CRC=`0x02` ### 8.4 LCDMEM 请求(从 0 地址读取) - 请求:`AA 03 00 04 00 00 00 00 00` - `DATA` 为 4 字节地址 `0x00000000` - CRC=`00` - 响应:`BB 03 LEN_H LEN_L [00 00 00 00][显存数据...] CRC` ## 9. 状态与时序约定 推荐交互顺序: ```text 1) 连接 TCP 7003 2) 发送 CMD_INIT 获取屏幕参数 3) 周期发送 CMD_LCDMEM 拉取显存 4) 有用户操作时发送 CMD_KEY 5) 周期发送 CMD_KEEPLIVE 保活 ``` ## 10. 安全性与边界约束 当前协议属于内网轻量协议,未设计鉴权与加密机制。建议在生产化场景补充: - 连接鉴权(口令/Token) - 传输加密(TLS 或应用层加密) - 命令频率限制与异常连接清理 ## 11. 兼容性与扩展建议 - 保留 `CMD` 空间用于后续扩展 - 建议新增统一 ACK/NACK 机制(含错误码) - 建议引入协议版本字段(可放在 `CMD_INIT` 响应或扩展头中) - 建议为 `CMD_KEY` 增加长度校验(当前默认读取 `DATA[0]`) ## 12. 与代码映射关系 - 帧解析:`parse_frame` - CRC 计算:`calc_crc` - 应答构造发送:`send_reply` - 命令处理:`handle_cmd_keeplive` / `handle_cmd_init` / `handle_cmd_key` / `handle_cmd_lcdmem` - 线程入口:`tcp_server_thread_fn` - 服务启动:`StartTcpServerThread` ## 13. 测试建议(协议方向) 建议将以下场景纳入自动化测试: - 正常帧:4 类命令全部覆盖 - 异常帧:错误 TAG、错误 CRC、截断帧、超长无效数据 - 边界值:`LEN=0`、`start_addr=0`、`start_addr=LCD_DISPLAYMEMORYSIZE-1`、`start_addr>=LCD_DISPLAYMEMORYSIZE` - 连接稳定性:频繁重连、并发请求(若后续支持)