# TCP2UART AT 固件使用手册

## 1. 文档范围

本文档定义 `TCP2UART` 项目的最终 AT 外部协议。

本文档只描述最终协议模型，不保留任何历史展开式实例字段，不包含测试记录，不讨论旧版兼容命令。

适用对象：

- 上位机开发人员
- 联调与测试人员
- 固件接口实现人员

## 2. 设备与接口

- 主控：`STM32F103R8T6`
- 以太网芯片：`CH390D`
- 配置口：`USART1`
- 数据口：`USART2`、`USART3`

职责划分：

- `USART1`：AT 配置口
- `USART2 / USART3`：业务数据口，可工作于普通透传或 MUX 透传模式

## 3. 最终协议模型

本项目最终控制协议由三部分组成：

1. `MUX`：全局数据承载模式开关
2. `NET`：全局静态网络配置记录
3. `LINK[ROLE]`：按角色名组织的链路配置记录（`S1/S2/C1/C2`）

约束如下：

- 设备只有一张网卡，因此本地网络参数只配置一次
- DHCP 不属于最终协议范围
- 所有 AT 文本命令必须以 `\r\n` 结尾
- 当 `DSTMASK=0x00` 时，MUX 数据口中的系统控制帧进入 AT 解析路径，其控制文本同样必须以 `\r\n` 结尾

## 4. MUX 帧格式

当 `MUX=1` 时，数据口使用如下帧格式：

```text
SYNC | LEN_H | LEN_L | SRCID | DSTMASK | PAYLOAD | TAIL
```

字段定义：

- `SYNC`：帧起始标记，建议固定为 `0x7E`
- `LEN_H / LEN_L`：`PAYLOAD` 长度，高字节在前
- `SRCID`：单字节源端点 ID
- `DSTMASK`：单字节目标端点位图
- `PAYLOAD`：负载数据
- `TAIL`：帧结束标记，建议固定为 `0x7F`

规则：

- `DSTMASK != 0x00`：业务数据帧
- `DSTMASK = 0x00`：系统控制帧
- 系统控制帧的 `PAYLOAD` 为 AT 文本，必须以 `\r\n` 结束

## 5. 统一端点编码

`UART` 与 `TCP` 逻辑实例统一进入同一套编码空间：

| 端点 | 编码 |
|------|------|
| `C1` | `0x01` |
| `C2` | `0x02` |
| `UART2` | `0x04` |
| `UART3` | `0x08` |
| `S1` | `0x10` |
| `S2` | `0x20` |

说明：

- `SRCID` 必须为单一端点值
- `DSTMASK` 可以是一个或多个端点编码按位或的结果
- `DSTMASK=0x00` 保留给系统控制帧

## 6. AT 命令总则

### 6.1 命令结尾

所有 AT 命令均必须以 `\r\n` 结尾。

例如：

```text
AT\r\n
AT+MUX?\r\n
AT+NET=192.168.1.100,255.255.255.0,192.168.1.1,02:00:00:00:00:01\r\n
```

### 6.2 持久化规则

参数设置成功后只写入当前运行配置，不会自动写入 Flash。

若要掉电保持，必须执行：

1. `AT+SAVE\r\n`
2. `AT+RESET\r\n`

### 6.3 响应风格

- 成功：`OK`
- 需要保存后生效时，允许追加提示文本
- 失败：`ERROR: <reason>`

## 7. 默认配置

### 7.1 MUX 默认值

```text
MUX = 0
```

### 7.2 NET 默认值

```text
NET = 192.168.1.100,255.255.255.0,192.168.1.1,02:00:00:00:00:01
```

### 7.3 LINK 默认值

```text
LINK:S1 = 1,8080,0.0.0.0,0,U0
LINK:S2 = 0,8081,0.0.0.0,0,U1
LINK:C1 = 1,9001,192.168.1.200,9000,U1
LINK:C2 = 0,9002,192.168.1.201,9001,U0
```

说明：

- `S1/S2/C1/C2` 为对外可见角色名
- 内部索引映射由固件管理，不对外暴露

UART 记号约定：

- `U0 = USART2`
- `U1 = USART3`

### 7.4 BAUD 默认值

```text
BAUD = U0,115200 / U1,115200
```

## 8. AT 命令定义

### 8.1 测试设备在线

命令：

```text
AT\r\n
```

返回：

```text
OK
```

### 8.2 查询摘要

命令：

```text
AT+?\r\n
AT+QUERY\r\n
```

推荐返回格式：

```text
+NET:IP=192.168.1.100,MASK=255.255.255.0,GW=192.168.1.1,MAC=02:00:00:00:00:01
+LINK:S1,EN=1,LPORT=8080,RIP=0.0.0.0,RPORT=0,UART=U0
+LINK:S2,EN=0,LPORT=8081,RIP=0.0.0.0,RPORT=0,UART=U1
+LINK:C1,EN=1,LPORT=9001,RIP=192.168.1.200,RPORT=9000,UART=U1
+LINK:C2,EN=0,LPORT=9002,RIP=192.168.1.201,RPORT=9001,UART=U0
+MUX:0
+MAP:UART2=0x04,UART3=0x08,C1=0x01,C2=0x02,S1=0x10,S2=0x20
+BAUD:U0=115200,U1=115200
OK
```

### 8.3 MUX 类命令

#### 设置 MUX

```text
AT+MUX=1\r\n
```

参数：

- `0`：普通透传模式
- `1`：MUX 透传模式

查询：

```text
AT+MUX?\r\n
```

返回示例：

```text
+MUX:1
OK
```

### 8.4 NET 类命令

#### 设置 NET

```text
AT+NET=192.168.1.100,255.255.255.0,192.168.1.1,02:00:00:00:00:01\r\n
```

字段顺序：

```text
IP,MASK,GW,MAC
```

查询：

```text
AT+NET?\r\n
```

返回示例：

```text
+NET:IP=192.168.1.100,MASK=255.255.255.0,GW=192.168.1.1,MAC=02:00:00:00:00:01
OK
```

**MAC 设置说明：**

当MAC设置为全0时，固件将使用硬件MAC地址，此时通过AT+?查询到的MAC地址即为当前生效的硬件MAC地址。

### 8.5 BAUD 类命令

#### 查询 UART 波特率

```text
AT+BAUD?\r\n
```

返回示例：

```text
+BAUD:U0=115200,U1=115200
OK
```

#### 设置 UART 波特率

```text
AT+BAUD=U0,115200\r\n
AT+BAUD=U1,38400\r\n
```

字段顺序：

```text
UART,BAUDRATE
```

字段说明：

- `UART`：`U0/U1`
- `BAUDRATE`：范围 `1200~921600`

说明：

- 该命令只更新当前运行配置记录，不会立即重初始化 `USART2/USART3`
- 执行 `AT+SAVE` 后再执行 `AT+RESET`，重启时按保存值生效

### 8.6 LINK 类命令

#### 设置单条 LINK 记录

```text
AT+LINK=S1,1,8080,0.0.0.0,0,U0\r\n
AT+LINK=C1,1,9001,192.168.1.200,9000,U1\r\n
```

字段顺序：

```text
ROLE,EN,LPORT,RIP,RPORT,UART
```

字段说明：

- `ROLE`：链路角色名，固定为 `S1/S2/C1/C2`
- `EN`：`0/1`
- `LPORT`：本地端口
- `RIP`：对端 IP
- `RPORT`：对端端口
- `UART`：`U0/U1`

说明：

- `Server` 与 `Client` 共用同一条 `LINK` 记录模型
- `Server` 中 `RIP/RPORT` 可作为允许接入的对端约束或预设对端信息
- `Client` 中 `RIP/RPORT` 表示远端目标地址与端口

#### 查询单条 LINK

```text
AT+LINK=S1\r\n
```

返回示例：

```text
+LINK:S1,EN=1,LPORT=8080,RIP=0.0.0.0,RPORT=0,UART=U0
OK
```

#### 查询全部 LINK

```text
AT+LINK?\r\n
```

返回示例：

```text
+LINK:S1,EN=1,LPORT=8080,RIP=0.0.0.0,RPORT=0,UART=U0
+LINK:S2,EN=0,LPORT=8081,RIP=0.0.0.0,RPORT=0,UART=U1
+LINK:C1,EN=1,LPORT=9001,RIP=192.168.1.200,RPORT=9000,UART=U1
+LINK:C2,EN=0,LPORT=9002,RIP=192.168.1.201,RPORT=9001,UART=U0
OK
```

## 9. 保存与复位命令

### 9.1 保存配置

```text
AT+SAVE\r\n
```

成功返回：

```text
OK: Configuration saved
```

### 9.2 软件复位

```text
AT+RESET\r\n
```

返回：

```text
OK: Resetting...
```

### 9.3 恢复默认值

```text
AT+DEFAULT\r\n
```

返回：

```text
OK: Defaults restored
```

## 10. 常见错误返回

| 场景 | 返回 |
|------|------|
| 未知命令 | `ERROR: Unknown command` |
| 非法端口 | `ERROR: Invalid port` |
| 非法波特率 | `ERROR: Invalid baudrate` |
| 非法 IP 地址 | `ERROR: Invalid IP format` |
| 非法掩码 | `ERROR: Invalid mask format` |
| 非法网关 | `ERROR: Invalid gateway format` |
| 非法远端 IP | `ERROR: Invalid remote IP format` |
| 非法 MAC | `ERROR: Invalid MAC format` |
| 非法 `SRCID` / `DSTMASK` | `ERROR: Invalid route field` |
| Flash 保存失败 | `ERROR: Save failed` |

## 11. 推荐配置流程

```text
AT+NET=192.168.1.123,255.255.255.0,192.168.1.1,02:00:00:00:00:01\r\n
AT+LINK=S1,1,10001,0.0.0.0,0,U1\r\n
AT+LINK=S2,1,10003,0.0.0.0,0,U1\r\n
AT+LINK=C1,1,20001,192.168.1.201,10002,U0\r\n
AT+MUX=1\r\n
AT+SAVE\r\n
AT+RESET\r\n
```

## 12. 故障排查建议

### 12.1 发送 `AT` 没有返回

优先检查：

1. 是否连接到 `USART1`
2. 串口参数是否为 `115200 8N1`
3. 是否严格使用 `\r\n` 作为命令结尾
4. 接线是否正确
5. 设备是否正常上电运行

### 12.2 设置成功但重启后参数丢失

检查是否漏掉以下步骤：

1. `AT+SAVE\r\n`
2. `AT+RESET\r\n`

### 12.3 MUX 模式数据口有丢包

若 `MUX=1` 下出现“主机侧已发送，但设备对端收到数量明显偏少”的现象，优先按以下顺序检查：

1. 固件版本是否已经包含 `2026-04-18` 的 MUX 丢包修复。
2. MUX 帧是否完整，尤其是：
   - `SYNC=0x7E`
   - `LEN_H/LEN_L`
   - `SRCID`
   - `DSTMASK`
   - `TAIL=0x7F`
3. 上位机发送方式是否把一帧拆成多个不连续小片段，或在帧间插入无效字节。
4. TCP 对端是否出现拥塞、窗口缩小或应用层不及时取数，导致发送路径出现背压。
5. RTT 中是否存在链路错误、发送失败或持续重连现象。

当前版本的修复点如下：

1. MUX 解析器改为在整帧完整到齐前不推进 UART RX ring 读指针，避免半帧被破坏性消费。
2. TCP 发送路径与 UART 写入路径不再把背压和短写静默视为成功，便于及早暴露链路承载问题。

现场回归结果：在修复后的固件中，MUX 模式持续发送 `670` 包，接收端 `670` 包全部到达，`0` 丢包。

## 13. 相关文件

- AT 命令实现：[config.c](/D:/code/STM32Project/TCP2UART/App/config.c)
- 配置结构与默认值：[config.h](/D:/code/STM32Project/TCP2UART/App/config.h)
- 调试与测试记录：[uart-ch390-debug-handoff.md](/D:/code/STM32Project/TCP2UART/uart-ch390-debug-handoff.md)
