✨ 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 按需截图工作方式 - 列出错误码表和对接故障排查步骤
229 lines
7.1 KiB
Markdown
229 lines
7.1 KiB
Markdown
# 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) | 上位机侧握手和配置下发操作 |
|