6.8 KiB
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 可正常调用