# 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`
- 连接稳定性：频繁重连、并发请求（若后续支持）

