# TCP 通信模块设计文档 > 文档版本:1.0 · 日期:2026-03-15 · 状态:已发布 --- ## 1. 模块概述 TCP 通信模块(`TcpLogic`)管理与上位机(ConfigServer)的所有网络连接,包括连接建立、握手认证、配置接收与缓存、温度帧发送和断线重连。模块基于 WCHNET 协议栈构建,通过 QDX TLV 协议封装数据。 源文件:`Middle/QDXnetworkStack/qdx_tcp_logic.c` / `qdx_tcp_logic.h` --- ## 2. 双流连接架构 ### 2.1 职责分工 | 流 | 端口 | 方向 | 职责 | |----|------|------|------| | 控制流 | srcport=**5511** | MCU 主动连接 Server | 握手、配置下发、心跳、TEMP_REQ、DetectionResult 上报 | | 数据流 | desport=**5512** | MCU 主动连接 Server | 温度帧数据上报(TYPE_TEMP_FRAME) | 两流独立管理,数据流断开不影响控制流的配置和心跳功能。 ```c /* main.c 中的地址配置 */ u8 IPAddr[4] = {192, 168, 7, 10}; /* MCU IP */ u8 DESIP[4] = {192, 168, 7, 50}; /* Server IP */ u16 desport = 5512; /* 数据流目标端口 */ u16 srcport = 5511; /* 控制流源端口 */ ``` ### 2.2 连接建立时序 ``` TcpLogic_Start() │ ├─ 1. 控制流 TCP Connect → Server:5511 │ 等待 SINT_STAT_CONNECT 事件 │ ├─ 2. 发送 TYPE_HANDSHAKE(Class=CLASS_SYSTEM) │ 含 ProtocolVersion=0x0200,DeviceUUID=MAC 地址(6 字节扩展为 UUID 格式) │ AuthToken=全零(当前不鉴权) │ ├─ 3. 等待服务器握手响应 │ 收到响应后标记控制流"就绪" │ └─ 4. 数据流 TCP Connect → Server:5512 连接成功后数据流"就绪" ``` --- ## 3. 心跳与 Keepalive 机制 ### 3.1 应用层心跳 `TcpLogic` 内部定时通过控制流发送 `TYPE_HEARTBEAT` 帧,包含: ```c typedef struct { uint32_t UpTime; /* 设备运行时间(ms) */ uint8_t CpuLoad; /* CPU 负载(预留,当前填 0) */ uint8_t MemUsage; /* 内存使用率(预留,当前填 0) */ } Heartbeat_t; /* 6 字节 */ ``` ### 3.2 TCP Keepalive 在 `main()` 中配置: ```c struct _KEEP_CFG cfg = { .idle = 20000, /* 空闲 20 秒后开始发送探测包 */ .interval = 15000, /* 每次探测间隔 15 秒 */ .count = 9 /* 最多 9 次无响应后关闭连接 */ }; WCHNET_ConfigKeepLive(&cfg); ``` | 参数 | 值 | 说明 | |------|-----|------| | idle | 20000 ms | 无数据交换后多久开始 Keepalive 探测 | | interval | 15000 ms | 相邻两次探测的间隔 | | count | 9 | 探测无响应的最大次数,超过则断链 | **总体断线判定时间**(最坏情况):20 + 9×15 = **155 秒** --- ## 4. 配置下发与缓存机制 ### 4.1 配置接收流程 ``` Server 控制流发送配置帧(可一次发三种): ├─ TYPE_CONFIG_COMMON(ConfigCommon_t) ├─ TYPE_CONFIG_2D(Config2D_t) └─ TYPE_CONFIG_1D(Config1D_t) │ ↓ TcpLogic 解析后缓存至内部 shadow 寄存器 │ ↓ 触发 ConfigUpdateCallback(OnConfigUpdate) │ ↓ 回调内调用 Preprocess_Settings_Change(cfg2d, cfg1d, common) → 更新预处理模块的 ROI、阈值、目标尺寸等参数 ``` ### 4.2 读取当前配置 业务任务每帧调用: ```c ConfigCommon_t tc; Config2D_t t2; Config1D_t t1; int8_t has_cfg = TcpLogic_GetLatestConfig(&tc, &t2, &t1); ``` 返回值: - `0`:有有效配置,`tc`/`t2`/`t1` 已填充 - `-1`:服务器尚未下发配置 ### 4.3 无配置时的默认行为 当 `TcpLogic_GetLatestConfig` 返回 `-1` 时,`task_business_entry` 跳过 2D/1D 处理,仅响应 TEMP_REQ(如有)。 默认 Burst 参数(代码中 fallback 常量): | 参数 | 默认值 | |------|--------| | `DEFAULT_BURST_COUNT` | 3 帧 | | `DEFAULT_BURST_INTERVAL_MS` | 200 ms | --- ## 5. 数据发送队列与背压处理 ### 5.1 发送接口 ```c int8_t TcpLogic_BuildAndSendTemperatureFrame( TcpTxBuffer_t *tx_buf, PreprocessResult_t *meta, uint8_t socket_type, /* 0x01=数据流,0x02=控制流(TEMP_REQ 响应) */ uint8_t is2d /* 1=2D矩阵,0=1D时序 */ ); ``` 返回值: - `0`:成功入队发送 - `< 0`:失败(连接断开或队列满) ### 5.2 发送失败处理 当前固件对发送失败仅打印 `DBG_ERR`,**不重试**,帧直接丢弃。原因:热像数据具有实时性,重试旧帧无意义。 ### 5.3 双缓冲保证 业务任务通过 `use_buffer_A` 标志交替使用 `g_TxNetBuffer_A` / `g_TxNetBuffer_B`: ``` 帧 N → g_TxNetBuffer_A → BuildAndSend(入队) ↓ 切换 帧 N+1 → g_TxNetBuffer_B → BuildAndSend(入队) ↓ 切换 帧 N+2 → g_TxNetBuffer_A ... ``` 帧 N 入队后立即切换缓冲区,即使 WCHNET 尚未完成实际 TCP 发送,帧 N+1 的填充也不会覆盖帧 N。 --- ## 6. WCHNET 网络栈驱动任务 ### 6.1 任务职责 `task_wchnet_entry`(优先级 6)每 5 ms 执行一次: ```c static void task_wchnet_entry(void *pvParameters) { while (1) { qdx_port_net_lock(); /* 获取互斥量 */ WCHNET_MainTask(); /* 协议栈心跳(TCP 超时检测、重传计时等) */ if (WCHNET_QueryGlobalInt()) WCHNET_HandleGlobalInt(); /* 分发 socket 事件 */ qdx_port_net_unlock(); /* 释放互斥量 */ vTaskDelay(pdMS_TO_TICKS(5)); } } ``` ### 6.2 事件分发路径 ``` WCHNET_HandleGlobalInt() └─ WCHNET_HandleSockInt(socketid, intstat) ├─ SINT_STAT_RECV → qdx_port_sock_recv_notify() ├─ SINT_STAT_CONNECT → WCHNET_ModifyRecvBuf() + qdx_port_sock_connect_notify() ├─ SINT_STAT_DISCONNECT → qdx_port_sock_disconnect_notify() └─ SINT_STAT_TIM_OUT → qdx_port_sock_disconnect_notify()(视为断连) ``` ### 6.3 互斥保护 `qdx_port_net_lock/unlock` 使用 FreeRTOS 互斥量保护所有 WCHNET API 调用,防止 `task_wchnet_entry` 和 `task_business_entry` 并发访问网络栈导致竞态。 > **设计说明**:WCHNET 不是线程安全的,所有 WCHNET 调用(包括业务任务中的发送接口)均须在锁保护下进行。`task_wchnet_entry` 持锁 5 ms,`task_business_entry` 在发送时短暂竞争该锁,实际竞争窗口极短。 --- ## 7. 断线重连 - 控制流或数据流断开(`SINT_STAT_DISCONNECT` / `SINT_STAT_TIM_OUT`)后,`qdx_tcp_logic` 内部状态机自动重置并重新尝试连接 - 重连成功后重新发送握手帧 - 配置 shadow 寄存器在断线期间**保留**,重连后无需服务器重新下发配置即可继续工作 --- ## 8. 相关文档 | 文档 | 内容 | |------|------| | [系统总览.md](系统总览.md) | TcpLogic_Start 在启动序列中的位置 | | [QDX协议设计.md](QDX协议设计.md) | 零拷贝 TX 缓冲区、帧结构 | | [对接集成指南.md](对接集成指南.md) | 上位机侧握手和配置下发操作 |