## ADDED Requirements ### Requirement: 系统时间获取 `qdx_port_get_tick_ms()` 必须返回自系统启动以来的毫秒级单调递增时间戳,精度不低于 FreeRTOS tick 周期(2ms)。 #### Scenario: 获取系统运行时间 - **WHEN** 任意任务或模块调用 `qdx_port_get_tick_ms()` - **THEN** 返回值为基于 `xTaskGetTickCount()` 转换的毫秒数,且数值不会回绕至 0(在 uint32_t 溢回之前) ### Requirement: 任务级阻塞延时 `qdx_port_delay_ms()` 必须让当前 FreeRTOS 任务挂起指定毫秒数,期间让出 CPU 给其他任务。 #### Scenario: 延时期间 CPU 让出 - **WHEN** 后台线程调用 `qdx_port_delay_ms(100)` - **THEN** 该任务进入阻塞态约 100ms,其余就绪任务在此期间获得调度 ### Requirement: 互斥锁创建与操作 `qdx_port_mutex_create/lock/unlock/delete` 必须基于 FreeRTOS 互斥信号量实现,支持跨任务的临界区保护和优先级继承。 #### Scenario: 并发访问配置结构体 - **WHEN** `tcp_rx_c` 线程正在更新 `ConfigCommon_t` 且 `task_business` 同时读取该结构体 - **THEN** 互斥锁确保同一时刻仅一个任务可访问,防止数据撕裂 #### Scenario: 互斥锁删除 - **WHEN** 调用 `qdx_port_mutex_delete` 并传入有效句柄 - **THEN** FreeRTOS 信号量资源被释放,句柄失效 ### Requirement: 线程(任务)创建 `qdx_port_thread_create` 必须通过 `xTaskCreate` 创建 FreeRTOS 任务,并正确映射名称、入口函数、栈大小和优先级参数。 #### Scenario: TcpLogic_Start 创建三个后台任务 - **WHEN** `TcpLogic_Start()` 依次调用 `qdx_port_thread_create` 创建 `tcp_mgr`、`tcp_rx_c`、`tcp_rx_d` - **THEN** 三个 FreeRTOS 任务被成功创建并开始调度执行 ### Requirement: TCP Socket 连接建立 `qdx_port_tcp_connect` 必须创建 WCHNET TCP socket、配置目标 IP/端口,发起连接并阻塞等待三次握手完成(或超时 5 秒返回 NULL)。 #### Scenario: 成功连接至上位机 - **WHEN** 调用 `qdx_port_tcp_connect("192.168.1.50", 5511)` 且上位机正在监听 - **THEN** WCHNET 完成 TCP 三次握手后,`SINT_STAT_CONNECT` 中断释放连接信号量,函数返回有效的 `qdx_socket_t` 句柄 #### Scenario: 连接超时 - **WHEN** 调用 `qdx_port_tcp_connect` 但目标主机不可达 - **THEN** 阻塞等待 5 秒后超时,释放已分配的 WCHNET socket 资源,返回 NULL ### Requirement: TCP 数据发送 `qdx_port_tcp_send` 必须将指定缓冲区数据通过 `WCHNET_SocketSend` 写入 TCP 发送队列,并返回实际发送的字节数。 #### Scenario: 发送温度帧数据 - **WHEN** `TcpLogic_BuildAndSendTemperatureFrame` 组装完成后调用 `qdx_port_tcp_send` 发送到数据流 socket - **THEN** 数据被提交至 WCHNET 发送缓冲,函数返回已发送的字节数 #### Scenario: 连接已断开时发送 - **WHEN** 对一个已断开的 socket 调用 `qdx_port_tcp_send` - **THEN** 函数返回 < 0 表示错误 ### Requirement: TCP 数据接收(信号量阻塞模式) `qdx_port_tcp_recv` 必须从 socket 关联的接收环形缓冲中读取数据。若缓冲为空,则阻塞等待信号量通知(最长 100ms 超时),超时返回 0。 #### Scenario: 接收上位机配置指令 - **WHEN** 上位机通过 5511 端口发送配置报文,WCHNET 中断触发将数据写入环形缓冲并释放信号量 - **THEN** `tcp_rx_c` 线程从阻塞中唤醒,`qdx_port_tcp_recv` 返回实际读取的字节数和数据 #### Scenario: 无数据超时 - **WHEN** 100ms 内未收到任何数据 - **THEN** 函数返回 0,调用方继续执行心跳或重连检查逻辑 #### Scenario: 对端关闭连接 - **WHEN** WCHNET 检测到对端断开(`SINT_STAT_DISCONNECT`) - **THEN** 函数返回 < 0,通知调用方连接已失效 ### Requirement: TCP Socket 关闭 `qdx_port_tcp_close` 必须调用 `WCHNET_SocketClose` 释放 WCHNET socket 资源,清空关联的环形缓冲,并将 `SocketCtx_t` 标记为空闲。 #### Scenario: 正常关闭 - **WHEN** 连接管理线程检测到超时并调用 `qdx_port_tcp_close` - **THEN** WCHNET socket 被关闭,环形缓冲清零,`SocketCtx_t.connected = 0`,该槽位可被后续连接复用 ### Requirement: WCHNET 协议栈周期驱动 系统必须在独立的高优先级 FreeRTOS 任务 `task_wchnet` 中周期调用 `WCHNET_MainTask()` 和 `WCHNET_HandleGlobalInt()`,确保以太网帧收发和 TCP 状态机正常运转。 #### Scenario: 协议栈持续驱动 - **WHEN** FreeRTOS 调度器启动后 - **THEN** `task_wchnet` 以约 5~10ms 周期持续驱动 WCHNET 协议栈,socket 中断事件被及时处理 ### Requirement: Socket 映射与上下文管理 系统必须维护静态 `SocketCtx_t` 数组(容量 = 2),管理 WCHNET socket ID 到 `qdx_socket_t` 不透明句柄的映射,以及每个 socket 关联的环形接收缓冲和信号量。 #### Scenario: 双流同时活跃 - **WHEN** 控制流 (5511) 和数据流 (5512) 同时建立连接 - **THEN** 两个 `SocketCtx_t` 槽位被分别占用,各自拥有独立的 WCHNET socket ID、接收缓冲和信号量 ### Requirement: net_config.h 双 Socket 配置 `WCHNET_NUM_TCP` 必须从 1 修改为 2,以支持控制流和数据流两个并发 TCP 连接,相关宏(`WCHNET_MAX_SOCKET_NUM`、`WCHNET_NUM_POOL_BUF`、`WCHNET_MEM_HEAP_SIZE` 等)随之联动更新。 #### Scenario: 两个 TCP socket 可同时创建 - **WHEN** 系统初始化后依次创建控制流和数据流 socket - **THEN** 两个 `WCHNET_SocketCreat` 调用均成功返回不同的 socket ID ### Requirement: TIM2 共享 FreeRTOS Tick 与 WCHNET Timer TIM2 必须配置为 2ms 周期,ISR 中每次调用 FreeRTOS tick handler,并以软件计数器每 5 次(10ms)调用一次 `WCHNET_TimeIsr()`。 #### Scenario: 双定时源正常工作 - **WHEN** 系统运行中 - **THEN** FreeRTOS 以 500Hz 频率获得 tick 中断,WCHNET 以 100Hz 频率获得定时服务,两者互不干扰 ### Requirement: main 函数重构为 RTOS 启动模型 `main()` 在完成硬件初始化和 WCHNET 初始化后,必须创建 `task_wchnet` 和 `task_business` 两个初始任务,然后调用 `vTaskStartScheduler()` 启动调度器,不再使用裸机 `while(1)` 主循环。 #### Scenario: 调度器启动 - **WHEN** `main()` 完成 ETH_LibInit、DVP_Init、Preprocess_Init、TcpLogic_Init 后 - **THEN** 调用 `vTaskStartScheduler()` 进入 RTOS 调度,所有业务逻辑在任务上下文中执行 ### Requirement: FreeRTOS 内核集成 TCPClient 工程必须链接 FreeRTOS 内核源文件(tasks.c、queue.c、list.c、timers.c、port.c、heap_4.c)和 RISC-V 移植文件,并配置 `FreeRTOSConfig.h` 适配 CH32V307 时钟和中断。 #### Scenario: 工程编译通过 - **WHEN** 将 FreeRTOS 源文件和 include 路径加入 TCPClient 构建配置 - **THEN** 工程编译无错误,FreeRTOS API 可正常调用