# EC800K TCP 透传模式优化方案 ## 1. 适用范围 当前工程使用 Quectel EC800K,通过 UART2 连接模块,通过 `AT+QIOPEN` 的透传模式承载 TCP 数据: ```text AT+QIOPEN=1,0,"TCP",,,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:,` 后再决定成功或失败,不能在一个循环条件中重复发送同一条 `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 识别。