## 1. 构建系统与 FreeRTOS 集成

- [x] 1.1 将 FreeRTOS 内核源文件（tasks.c、queue.c、list.c、timers.c）和内存管理（MemMang/heap_4.c）复制或链接到 TCPClient 工程目录
- [x] 1.2 将 RISC-V 移植文件（portable/GCC/RISC-V/port.c、portASM.S、portmacro.h）加入工程
- [x] 1.3 将 `FreeRTOSConfig.h` 从 `prj/FreeRTOS_Core/User/` 复制到 `prj/TCPClient/User/` 并适配：确认 `configTICK_RATE_HZ=500`、`configTOTAL_HEAP_SIZE=12288`、`configCPU_CLOCK_HZ=SystemCoreClock`
- [x] 1.4 更新 TCPClient 工程 makefile/构建配置，添加 FreeRTOS 源文件和 include 路径，确保编译通过

## 2. net_config.h 双 Socket 配置

- [x] 2.1 修改 `net_config.h` 中 `WCHNET_NUM_TCP` 从 1 改为 2
- [x] 2.2 验证 `WCHNET_MAX_SOCKET_NUM`、`WCHNET_NUM_POOL_BUF`、`WCHNET_NUM_TCP_SEG`、`WCHNET_MEM_HEAP_SIZE` 等联动宏自动调整正确
- [x] 2.3 扩展 `main.c` 中 `SocketRecvBuf` 数组尺寸为 `[2][RECE_BUF_LEN]`，`socket` 数组为 `[2]`

## 3. TIM2 重构——共享 FreeRTOS Tick 与 WCHNET Timer

- [x] 3.1 修改 `TIM2_Init` 将定时周期从 10ms 改为 2ms（`TIM_Period = 2000 - 1`）
- [x] 3.2 修改 `TIM2_IRQHandler`：每次调用 `xPortSysTickHandler()` 驱动 FreeRTOS tick，并用静态计数器每 5 次调用一次 `WCHNET_TimeIsr(WCHNETTIMERPERIOD)`
- [x] 3.3 维护 `sys_tick_ms` 每次 +2 替代原来 +10

## 4. qdx_port.c 核心实现——时间、延时、互斥、线程

- [x] 4.1 新建 `prj/TCPClient/Middle/QDXnetworkStack/qdx_port.c`（基于 template），include FreeRTOS headers
- [x] 4.2 实现 `qdx_port_get_tick_ms()`：返回 `xTaskGetTickCount() * portTICK_PERIOD_MS`
- [x] 4.3 实现 `qdx_port_delay_ms()`：调用 `vTaskDelay(pdMS_TO_TICKS(ms))`
- [x] 4.4 实现 `qdx_port_mutex_create/lock/unlock/delete`：封装 `xSemaphoreCreateMutex`、`xSemaphoreTake(portMAX_DELAY)`、`xSemaphoreGive`、`vSemaphoreDelete`
- [x] 4.5 实现 `qdx_port_thread_create`：调用 `xTaskCreate` 映射 name、entry、arg、stack_size、priority

## 5. qdx_port.c Socket 层实现——映射与桥接

- [x] 5.1 定义 `SocketCtx_t` 结构体（wchnet_sock_id、connected、rx_ring、rx_sem、connect_sem）和静态数组 `g_sock_ctx[2]`
- [x] 5.2 实现环形缓冲 `RxRingBuf_t` 的 init/write/read/available 操作（容量 2920 字节）
- [x] 5.3 实现 `qdx_port_tcp_connect`：分配空闲 SocketCtx → 填充 SOCK_INF（PROTO_TYPE_TCP、目标 IP/Port）→ `WCHNET_SocketCreat` → `WCHNET_SocketConnect` → `xSemaphoreTake(connect_sem, 5000ms)` 阻塞等待连接完成
- [x] 5.4 实现 `qdx_port_tcp_send`：校验句柄有效性 → 互斥锁保护 → `WCHNET_SocketSend(ctx->wchnet_sock_id, data, &len)`
- [x] 5.5 实现 `qdx_port_tcp_recv`：检查 rx_ring 有数据直接读取返回；否则 `xSemaphoreTake(rx_sem, 100ms)` 阻塞 → 唤醒后再次检查 rx_ring → 返回数据或 0（超时）或 <0（连接断开）
- [x] 5.6 实现 `qdx_port_tcp_close`：`WCHNET_SocketClose(ctx->wchnet_sock_id, 0)` → 清空 rx_ring → 标记 ctx 为空闲

## 6. WCHNET 中断回调改造

- [x] 6.1 修改 `WCHNET_HandleSockInt` 的 `SINT_STAT_RECV` 分支：通过 wchnet_sock_id 查找对应 SocketCtx → `WCHNET_SocketRecv` 读数据写入 rx_ring → `xSemaphoreGive(rx_sem)` 通知接收线程
- [x] 6.2 修改 `SINT_STAT_CONNECT` 分支：查找对应 SocketCtx → 标记 `connected = 1` → `xSemaphoreGive(connect_sem)` 唤醒等待线程
- [x] 6.3 修改 `SINT_STAT_DISCONNECT` 和 `SINT_STAT_TIM_OUT` 分支：标记 `connected = 0` → `xSemaphoreGive(rx_sem)` 确保阻塞中的 recv 能被唤醒退出

## 7. main.c 重构为 RTOS 多任务

- [x] 7.1 新增 `task_wchnet_entry` 函数：循环调用 `WCHNET_MainTask()` + `WCHNET_QueryGlobalInt` / `WCHNET_HandleGlobalInt`，周期约 5ms
- [x] 7.2 新增 `task_business_entry` 函数：将原 `while(1)` 中的 DVP_Task + Frame 触发判定 + 预处理 + 封包发送逻辑迁入
- [x] 7.3 修改 `main()` 函数：保留硬件初始化（SystemCoreClockUpdate、USART、DVP_Init、TIM2_Init、ETH_LibInit）→ Preprocess_Init → TcpLogic_Init → TcpLogic_RegisterCallbacks → `xTaskCreate(task_wchnet)` → `xTaskCreate(task_business)` → `vTaskStartScheduler()`
- [x] 7.4 删除 `main()` 中的 `while(1)` 裸机主循环

## 8. 回调逻辑补全

- [x] 8.1 补全 `OnConfigUpdate`：内部调用 `Preprocess_Settings_Change(cfg2d, cfg1d, common)` 将新参数同步至预处理模块
- [x] 8.2 补全 `OnDetectionResult`：当 `isOK == 0` 时拉高 NG DO GPIO 引脚，启动 FreeRTOS 软件定时器（`xTimerCreate`）延时 `NGioDelay` ms 后在回调中拉低复位
- [x] 8.3 初始化 NG DO GPIO 引脚为推挽输出（在 main 硬件初始化阶段添加）

## 9. 验证与调试

- [ ] 9.1 编译整个 TCPClient 工程，修复链接错误
- [ ] 9.2 使用 `uxTaskGetStackHighWaterMark` 验证各任务栈余量，防止溢出
- [ ] 9.3 连接上位机测试控制流(5511)与数据流(5512)双连接建立、心跳和重连
- [ ] 9.4 触发一帧图像，验证完整链路：DVP 采集 → 触发判定 → 预处理提取 → TCP 封包发送 → 上位机收到数据
- [ ] 9.5 测试上位机下发参数更新，验证 Preprocess 参数热更新生效
