ch32v307_camera/doc/设计文档/TCP通信模块设计.md
zhoujie b69717b964 📝 docs(design): 新增系统设计文档集
 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 按需截图工作方式
- 列出错误码表和对接故障排查步骤
2026-03-15 19:17:41 +08:00

229 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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_HANDSHAKEClass=CLASS_SYSTEM
│ 含 ProtocolVersion=0x0200DeviceUUID=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_COMMONConfigCommon_t
├─ TYPE_CONFIG_2DConfig2D_t
└─ TYPE_CONFIG_1DConfig1D_t
TcpLogic 解析后缓存至内部 shadow 寄存器
触发 ConfigUpdateCallbackOnConfigUpdate
回调内调用 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) | 上位机侧握手和配置下发操作 |