✨ feat(system-overview): 创建系统总览文档 - 描述项目背景与硬件平台配置 - 提供 FreeRTOS 任务拓扑表(任务优先级、栈大小、职责) - 详细说明系统启动序列和初始化依赖关系 - 绘制 2D/1D 状态机完整流程图 - 解释 TEMP_REQ 辅助通道工作机制 - 说明任务间同步机制(Frame_Ready_Flag、双缓冲 TX) ✨ feat(dvp-module-design): 创建 DVP 模块设计文档 - 提供 DVP 硬件连接引脚映射表 - 描述 DVP 时序配置(信号极性、工作模式) - 解释 DMA ping-pong 行缓冲机制和切换逻辑 - 说明 DVP IRQ 帧组装流程(STR_FRM/ROW_DONE) - 定义 FrameBuffer 数据格式和像素访问方式 - 说明 TMP 模式温度换算公式和字节序要求 ✨ feat(qdx-protocol-design): 创建 QDX 协议设计文档 - 描述完整 TLV 帧结构(FrameHeader + TLV + CRC) - 列出所有 Class/Type 映射表和用途说明 - 解释零拷贝 TX 缓冲区架构(HeadOffset 机制) - 说明分片机制和最大载荷限制 - 定义 Flags 字段各位含义和使用场景 ✨ feat(tcp-module-design): 创建 TCP 通信模块设计文档 - 描述双流连接架构(控制流 5511 / 数据流 5512) - 说明握手流程和连接建立时序 - 解释心跳机制和 TCP Keepalive 配置 - 描述配置下发与缓存机制 - 说明数据发送队列和背压处理策略 - 解释 WCHNET 网络栈驱动任务工作机制 ✨ feat(integration-guide): 创建对接集成指南 - 提供网络接入参数表(IP、端口、协议) - 详细说明握手流程和配置下发格式 - 提供 2D/1D 温度帧解析方法和示例代码 - 说明检测结果上报和 NG 响应机制 - 解释 TEMP_REQ 按需截图工作方式 - 列出错误码表和对接故障排查步骤
7.1 KiB
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) |
两流独立管理,数据流断开不影响控制流的配置和心跳功能。
/* 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 帧,包含:
typedef struct {
uint32_t UpTime; /* 设备运行时间(ms) */
uint8_t CpuLoad; /* CPU 负载(预留,当前填 0) */
uint8_t MemUsage; /* 内存使用率(预留,当前填 0) */
} Heartbeat_t; /* 6 字节 */
3.2 TCP Keepalive
在 main() 中配置:
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 读取当前配置
业务任务每帧调用:
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 发送接口
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 执行一次:
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 | TcpLogic_Start 在启动序列中的位置 |
| QDX协议设计.md | 零拷贝 TX 缓冲区、帧结构 |
| 对接集成指南.md | 上位机侧握手和配置下发操作 |