8 changed files with 655 additions and 48 deletions
@ -0,0 +1,250 @@ |
|||
# EC800K TCP 透传模式优化方案 |
|||
|
|||
## 1. 适用范围 |
|||
|
|||
当前工程使用 Quectel EC800K,通过 UART2 连接模块,通过 `AT+QIOPEN` 的透传模式承载 TCP 数据: |
|||
|
|||
```text |
|||
AT+QIOPEN=1,0,"TCP",<server>,<port>,0,2 |
|||
``` |
|||
|
|||
飞控数据保持原有透传路径,不增加新的 TCP 连接,也不要求第一阶段解析完整 MAVLink 数据。 |
|||
|
|||
## 2. 目标 |
|||
|
|||
- 保持飞控数据的透明传输。 |
|||
- 使用服务器现有的 MAVLink 心跳检测下行链路。 |
|||
- 使用 EC800K 的 TCP keepalive 处理网络黑洞。 |
|||
- 正确处理 `NO CARRIER` 和分包 URC。 |
|||
- TCP 断开时优先关闭 Socket 并重连,只有 AT 状态机无响应时才复位模块。 |
|||
- 避免重复发送 `QIOPEN` 和连续快速重连。 |
|||
|
|||
## 3. 连接初始化 |
|||
|
|||
在 `QIOPEN` 前完成 PDP 激活和透传参数配置: |
|||
|
|||
```text |
|||
AT+QIACT? |
|||
AT+QIACT=1 // PDP 未激活时执行 |
|||
AT+QICFG="transpktsize",512 |
|||
AT+QICFG="transwaittm",0 |
|||
AT+QICFG="passiveclosed",1 |
|||
AT+QICFG="tcp/keepalive",1,30,25,3 |
|||
``` |
|||
|
|||
实际配置前先执行: |
|||
|
|||
```text |
|||
AT+QICFG=? |
|||
``` |
|||
|
|||
确认当前 EC800K 固件支持的参数范围。`tcp/keepalive` 中的 `interval_time` 必须遵守当前固件文档范围,不能直接使用其他模块的参数。 |
|||
|
|||
配置后查询并记录: |
|||
|
|||
```text |
|||
AT+QICFG="passiveclosed" |
|||
AT+QICFG="tcp/keepalive" |
|||
AT+QICFG="transpktsize" |
|||
AT+QICFG="transwaittm" |
|||
``` |
|||
|
|||
## 4. 透传状态机 |
|||
|
|||
建议将连接状态划分为: |
|||
|
|||
```text |
|||
DISCONNECTED |
|||
CONNECTING |
|||
TRANSPARENT_CONNECTED |
|||
SUSPECTED |
|||
EXITING_TRANSPARENT |
|||
CLOSING |
|||
RECONNECT_WAIT |
|||
``` |
|||
|
|||
正常连接流程: |
|||
|
|||
```text |
|||
DISCONNECTED |
|||
-> QIACT |
|||
-> CONNECTING |
|||
-> QIOPEN |
|||
-> 收到 CONNECT |
|||
-> TRANSPARENT_CONNECTED |
|||
``` |
|||
|
|||
一次连接尝试只能发送一次 `QIOPEN`。等待 `CONNECT` 或 `+QIOPEN:<connectID>,<err>` 后再决定成功或失败,不能在一个循环条件中重复发送同一条 `QIOPEN`。 |
|||
|
|||
重连间隔建议退避: |
|||
|
|||
```text |
|||
1 秒 -> 2 秒 -> 5 秒 -> 10 秒 -> 30 秒 |
|||
``` |
|||
|
|||
## 5. 服务器心跳检测 |
|||
|
|||
服务器连接建立后会定期发送 MAVLink 心跳包。第一阶段先不解析 MAVLink,只要透传接收路径收到服务器数据,就更新: |
|||
|
|||
```text |
|||
last_server_rx_tick |
|||
server_rx_bytes |
|||
server_rx_read_events |
|||
``` |
|||
|
|||
设备超时应设置为服务器心跳周期的 2~3 倍: |
|||
|
|||
| 服务器心跳周期 | 建议设备超时 | |
|||
|---|---:| |
|||
| 3 秒 | 10~12 秒 | |
|||
| 5 秒 | 15 秒左右 | |
|||
| 10 秒 | 25~30 秒 | |
|||
|
|||
当前已确认服务器每 3 秒发送一次 MAVLink 心跳,工程宏 `LTE_SERVER_SILENCE_TIMEOUT_SEC` 设置为 `15`,允许连续丢失多个心跳后再进入恢复流程。若服务器心跳周期发生变化,应同步调整该值。一般应设置为心跳周期的 2~3 倍,并保留网络抖动余量。 |
|||
|
|||
不要只允许丢失一个心跳包就重连。超时后先标记 `SUSPECTED`,停止普通发送,再执行恢复流程。 |
|||
|
|||
第一阶段的“任意下行数据”只用于快速验证链路,不能证明收到的必然是 MAVLink HEARTBEAT,也不能证明服务器一定收到了设备上行数据。读取次数也不等于 MAVLink 包数量,因此应记录为 `server_rx_read_events`。后续如果需要严格判断心跳,再使用现有 MAVLink 库只识别 `MAVLINK_MSG_ID_HEARTBEAT`,不解析其他消息。服务器如果没有固定下行心跳,不能使用该方法作为连接判断。 |
|||
|
|||
## 6. 断连事件处理 |
|||
|
|||
### 6.1 `NO CARRIER` |
|||
|
|||
在透传模式下,EC800K 因网络错误或 Socket 断开通常会上报: |
|||
|
|||
```text |
|||
NO CARRIER |
|||
``` |
|||
|
|||
模块会退出透传模式。程序应支持完整和分包匹配: |
|||
|
|||
```text |
|||
记录断连原因 |
|||
停止 UART3 -> UART2 的发送 |
|||
connect_sta = false |
|||
执行 AT+QICLOSE=0 |
|||
进入 RECONNECT_WAIT |
|||
``` |
|||
|
|||
收到 `NO CARRIER` 后通常不需要再次发送 `+++`,因为模块已经退出透传模式。 |
|||
|
|||
### 6.2 服务器心跳超时 |
|||
|
|||
如果超过配置的心跳超时时间没有收到服务器数据: |
|||
|
|||
```text |
|||
TRANSPARENT_CONNECTED |
|||
-> SUSPECTED |
|||
-> 暂停飞控数据发送 |
|||
-> 严格退出透传 |
|||
-> QICLOSE |
|||
-> QIOPEN 重连 |
|||
``` |
|||
|
|||
### 6.3 `+++` 退出透传 |
|||
|
|||
只有在程序仍处于透传模式、但需要主动恢复时才发送 `+++`。必须满足: |
|||
|
|||
```text |
|||
发送前至少 1 秒没有其他 UART 数据 |
|||
+++ 输入期间没有其他数据 |
|||
发送后至少 1 秒没有其他数据 |
|||
等待模块返回 OK |
|||
``` |
|||
|
|||
执行期间必须暂停飞控发送线程,否则 `+++` 可能被当作普通 TCP 数据发送。 |
|||
|
|||
暂停不能只依赖 `connect_sta=false`。所有 UART2 写路径必须检查统一的发送闸门,必要时使用互斥锁,确保停止当前写操作后再等待 1 秒静默。`+++`、退出后的 AT 命令和恢复透传必须与飞控发送互斥。 |
|||
|
|||
## 7. Socket 恢复和模块复位 |
|||
|
|||
推荐恢复顺序: |
|||
|
|||
```text |
|||
NO CARRIER 或心跳超时 |
|||
-> 停止业务发送 |
|||
-> 必要时 +++ 并等待 OK |
|||
-> AT+QICLOSE=0 |
|||
-> 查询/恢复 PDP |
|||
-> 单次 QIOPEN |
|||
-> 收到 CONNECT 后恢复透传 |
|||
``` |
|||
|
|||
以下情况才执行 EC800K 复位: |
|||
|
|||
- `+++` 超时; |
|||
- `AT+QICLOSE` 超时; |
|||
- `AT+QIACT` 长时间无响应; |
|||
- 连续多个 AT 命令无响应; |
|||
- UART2 长时间没有任何模块响应。 |
|||
|
|||
TCP 断开本身不等于 EC800K 死机,不能每次 `NO CARRIER` 都直接复位模块。 |
|||
|
|||
AT 等待时间必须按官方上限设计:`QIACT` 最长可达 150 秒,`QIOPEN` 建议最长等待 150 秒,`QICLOSE` 默认最长约 10 秒,`QIDEACT` 最长可达 40 秒。当前工程的 7 秒和 500 毫秒等待不能直接用于这些命令,否则会把模块仍在处理的请求误判为超时。一次 `QIOPEN` 超时后必须先完成清理和退避,不能立即重复发送。 |
|||
|
|||
## 8. TCP keepalive 与业务心跳的关系 |
|||
|
|||
```text |
|||
AT+QICFG="tcp/keepalive",1,30,25,3 |
|||
``` |
|||
|
|||
用于 TCP 协议栈探测对端是否仍可达。它不能确认服务器业务程序是否处理了飞控心跳,也不能替代服务器的 MAVLink 心跳。 |
|||
|
|||
`AT+QICFG="passiveclosed",1` 用于处理服务器 FIN/RST 已经到达模块的被动关闭。网络黑洞导致 FIN 没有到达时,仍需依靠 TCP keepalive 或服务器心跳超时。 |
|||
|
|||
## 9. 日志内容 |
|||
|
|||
建议在断连日志中记录: |
|||
|
|||
```text |
|||
断连原因 |
|||
server_rx_bytes |
|||
server_rx_read_events |
|||
age_server_rx |
|||
心跳超时次数 |
|||
当前连接状态 |
|||
重连退避时间 |
|||
UART2 收发字节和错误计数 |
|||
CSQ/CEREG/PDP 状态 |
|||
AT 最后一条命令、结果和耗时 |
|||
``` |
|||
|
|||
这些信息可以初步区分: |
|||
|
|||
- 模块明确报告 TCP 断开; |
|||
- 服务器心跳停止; |
|||
- 网络黑洞导致模块尚未收到 FIN; |
|||
- UART 丢数据或溢出; |
|||
- PDP/注册状态异常; |
|||
- AT 状态机无响应。 |
|||
|
|||
## 10. 内存预算 |
|||
|
|||
第一阶段不解析 MAVLink,只增加计时器、状态和计数器: |
|||
|
|||
```text |
|||
纯状态字段:约 32~64 字节 |
|||
加 UART2 发送互斥对象:通常约 100~300 字节,取决于 RT-Thread 配置 |
|||
Flash:约 1~3 KB |
|||
``` |
|||
|
|||
不新增线程,不新增大块动态内存。 |
|||
|
|||
如果后续只增加一个 MAVLink HEARTBEAT 识别器,而不是解析所有消息,预计额外增加: |
|||
|
|||
```text |
|||
RAM:约 50~100 字节 |
|||
Flash:约 1~2 KB |
|||
``` |
|||
|
|||
## 11. 实施顺序 |
|||
|
|||
1. 确认服务器实际 MAVLink 心跳周期。 |
|||
2. 增加 `passiveclosed` 和 `tcp/keepalive` 配置及查询日志。 |
|||
3. 增加服务器下行数据计时器和超时状态。 |
|||
4. 修正 `NO CARRIER` 分包解析。 |
|||
5. 修正 `QIOPEN` 重复发送问题。 |
|||
6. 实现 `QICLOSE` 优先、复位兜底的恢复流程。 |
|||
7. 实现严格的 `+++` 退出保护。 |
|||
8. 增加重连退避和断连诊断日志。 |
|||
9. 根据现场日志决定是否增加轻量级 MAVLink HEARTBEAT 识别。 |
|||
Loading…
Reference in new issue