nuttx实战项目:多路串口合并功能之九主app需求(copilot版本)

多端口智能串口网关程序需求说明书

版本: 1.0
日期: 2025-10-11
作者: a10747029 + Copilot

1. 目的与范围

  • 目的

    • 定义一个运行在 NuttX 上的多端口串口网关程序的功能与非功能需求,用于与上位机(MAIN 串口)以及四个设备端口进行数据交互、设备类型自动识别、热插拔管理与状态上报。
    • 本说明书将作为后续实现、测试与维护的依据,确保一致性与可追踪性。
  • 范围

    • 涉及 1 路 MAIN 串口(上位机接口)与 4 路设备串口(传感器/探头接口)。
    • 支持设备类型自动探测与绑定:BIS、BRAIN_O2、MUSCLE、BLOOD。
    • 支持设备->MAIN 数据上行封装,MAIN->设备按类型下发。
    • 支持热插拔拔出判定与自动重新探测。
    • 支持周期性状态上报与终端日志打印。

不在本版本范围内:

  • dev_id=0xFF 的本地控制指令行为(保留接口,暂不实现)
  • 安全与权限控制
  • 大规模参数动态下发与固件升级

2. 系统概述

  • 硬件/串口拓扑

    • MAIN 串口: /dev/ttyS1(与上位机连接)
    • 设备串口: /dev/ttyS2, /dev/ttyS3, /dev/ttyS4, /dev/ttyS5(四个物理端口)
  • 并发模型

    • main_rx_thread: 解析 MAIN 下行帧并按设备类型转发给已绑定端口。
    • detect_thread: 设备类型探测、BRAIN_O2 心跳、热拔出检测、状态上报。
    • 主线程: poll 已绑定端口,读取设备数据并打包上送 MAIN。
  • 关键设计点

    • MAIN 写操作使用全局互斥与“完整写”策略避免帧交织。
    • 探测使用“方案A”:空闲快速窗口 + 正常窗口 + brain 探针,显著加速无设备时的首轮检测。
    • 内存极度受限(NuttX ~128KB),线程栈 4KB;大缓冲采用静态全局区。

3. 串口参数与平台约束

  • 串口设备与波特率

    • MAIN: /dev/ttyS1, 460800 波特(若系统不支持 B460800,应回退到 115200)
    • 设备端: /dev/ttyS2~S5, 115200 波特
    • 模式: 原始模式(cfmakeraw),8N1,无硬件流控(CRTSCTS 关闭),O_NONBLOCK 非阻塞
  • 平台与内存

    • 操作系统: NuttX
    • 限制: 线程栈 4096 字节;避免大栈对象;大缓冲全部静态全局
    • 典型缓冲:
      • 探测缓冲: 3000 字节(全局)
      • MAIN 接收缓冲与临时包缓冲: 各 512 字节(全局)
      • 设备接收缓冲与临时包缓冲: 各 512 字节(全局)

4. 协议定义(MAIN 串口)

  • 帧格式(大端长度)

    • 头: 3 字节,固定 AA AA AA
    • 长度: 2 字节,大端,表示 dev_id(1) + payload(N) 的总长度
    • 数据区: dev_id(1) + payload(N)
    • CRC: 1 字节,对 [lenH, lenL, dev_id, payload…] 共 (2 + plen) 字节逐字节相加取低 8 位
    • 尾: 3 字节,固定 FF FF FF

    示例:

    • HEADER(3) + LEN(2) + dev_id(1) + payload(N) + CRC(1) + TAIL(3)
  • 语义

    • MAIN -> 设备(下行):
      • dev_id 表示“设备类型”(非端口号)。
      • 程序应将 payload 原样转发到所有“已绑定为该类型”的设备端口(广播)。
      • MAIN 外层头/尾/CRC 不转发给设备端。
    • 设备 -> MAIN(上行):
      • 程序将设备端的 payload 封装成 MAIN 帧上送,dev_id 为该端口绑定的设备类型。
  • 本地控制(保留)

    • 当 dev_id == 0xFF 时,为本机控制/查询指令预留(如运行时配置、日志级别、统计查询等)。
    • 本版本不实现具体指令行为。
  • 校验要求

    • 必须对每一帧校验头、长度、CRC、尾;校验失败丢弃该起始位并继续滑动查找帧头。
    • 解析修正: 总帧长=3(头)+2(长)+plen(dev_id+payload)+1(CRC)+3(尾)。

5. 设备类型与特征

  • 类型枚举

    • DEV_BIS = 0
    • DEV_BRAIN_O2 = 1
    • DEV_MUSCLE = 2
    • DEV_BLOOD = 3
    • DEV_UNKNOWN = 0xFF
  • 特征判据(滑动匹配)

    • BIS: 出现头 bis_header = 66 66 66
    • BLOOD: 出现头 blood_header = FA FA FA,且偏移 +7/+8 字节为 BLOOD_MID = 00 17
    • MUSCLE: 完整匹配 MUSCLE_HEADER = FA 0C 19 04 00 00 00 00 00 01(10 字节)
    • BRAIN_O2: 探针响应中出现 BRAIN_RESP = EF EF EF 11 11 25(6 字节)
  • BRAIN_O2 探针帧

    • BRAIN_PROBE(19 字节)= EF EF EF 0C 11 25 01 41 52 46 4C 41 4C 46 4C 7B FE FE FE

6. 设备探测流程(方案A)

  • 触发时机

    • 端口未绑定(device_present=false)时由 detect_thread 对该端口进行探测。
    • 端口绑定后若被判定为“拔出”(长时间无数据),将解绑并重新探测。
  • 步骤

    1. 空闲快速窗口(DETECT_IDLE_WINDOW_MS,默认 100ms)
      • 在该窗口内对端口执行 poll/读,若读到任意字节则转入“正常窗口”;若未读到任何字节,立即发起 brain 探针。
    2. 正常窗口(DETECT_WINDOW_MS,默认 1100ms)
      • 持续收集数据(poll 步进 DETECT_POLL_STEP_MS,默认 20ms),窗口结束后对累积缓冲做滑动判别 BIS/BLOOD/MUSCLE。
    3. brain 探针
      • 当空闲窗口无任何字节时,发送 BRAIN_PROBE,等待 DETECT_BRAIN_PROBE_RESP_TIMEOUT_MS(默认 200ms)。
      • 若响应中匹配 BRAIN_RESP 则判定为 BRAIN_O2 并绑定;否则继续下一个端口或下一轮。
  • 绑定行为

    • 一旦判定出设备类型,设置 device_present=true,dev_type=对应类型,并刷新 last_recv。
    • 对已绑定为 BRAIN_O2 的端口,detect_thread 每秒(1Hz)发送一次 BRAIN_PROBE 心跳。
  • 读写行为

    • 探测期间的读取只发生在 detect_thread;端口绑定后主线程才会读该端口(避免并发读)。

7. 数据转发与状态上报

  • 设备 -> MAIN(上行)

    • 主线程对所有“已绑定”端口 poll 可读。
    • 读取到设备数据后,立即刷新该端口 last_recv。
    • 将 payload 封装为 MAIN 帧:HEADER + LEN(dev_id+payload) + dev_id + payload + CRC + TAIL,发送至 MAIN。
    • main_fd 写入必须通过带锁的完整写(防止帧交织)。
  • MAIN -> 设备(下行)

    • main_rx_thread 解析 MAIN 帧,校验成功后按 dev_id(设备类型)广播到所有已绑定为该类型的端口。
    • 对 dev_id==0xFF 的本地控制帧,当前版本忽略(预留)。
  • 状态上报(周期性)

    • 周期: STATUS_REPORT_INTERVAL_SEC(默认 1s)。
    • 内容:
      • dev_id=0xFF(本地)
      • 子命令=0x00
      • 随后 4 字节为四个端口的设备类型(若未绑定则 DEV_UNKNOWN=0xFF)
    • 帧格式: HEADER + LEN(0x0006) + FF + 00 + [dev_type0…3] + CRC + TAIL
    • 终端日志: 每次上报同时打印一行 [STATUS],显示各端口的名称与类型值。

8. 热插拔(拔出)判定

  • 判据
    • 若已绑定端口在 HOTPLUG_INACTIVE_UNBIND_SEC(默认 3s)内未收到任何设备数据(由主线程接收路径更新 last_recv),判定为“拔出”。
    • detect_thread 打印 [HOTPLUG] 日志,解绑该端口(device_present=false,dev_type=UNKNOWN)。
    • 随后该端口在后续周期自动进入探测流程。

9. 并发控制与线程安全

  • 写入 MAIN 的帧必须通过全局互斥锁(main_tx_lock)+ 循环完整写(处理 EAGAIN/短写),确保“整帧原子性”,避免来自不同线程的写入交错。
  • 每个设备端口均有独立互斥锁,保护以下操作的原子性:
    • device_present/dev_type/last_recv/last_brain_probe 的读写
    • 向设备端口写入数据(如 BRAIN_PROBE 或 MAIN 下发 payload)
  • MAIN 与设备 fd 均为非阻塞;读写通过 poll/select 控制等待,上层逻辑不应长时间阻塞线程。

10. 运行时参数与默认值

  • 常量/宏(可编译期调优)

    • STATUS_REPORT_INTERVAL_SEC: 1 秒
    • HOTPLUG_INACTIVE_UNBIND_SEC: 3 秒
    • DETECT_BRAIN_PROBE_RESP_TIMEOUT_MS: 200 ms
    • DETECT_BRAIN_PROBE_GAP_MS: 1 ms
    • DETECT_IDLE_WINDOW_MS: 100 ms
    • DETECT_WINDOW_MS: 1100 ms
    • DETECT_POLL_STEP_MS: 20 ms
    • PROBE_BUF_SIZE: 3000 字节
    • MAIN_RX_BUF_SIZE: 512 字节
    • PORT_RX_BUF_SIZE: 512 字节
  • 设备特征常量

    • bis_header: 66 66 66
    • blood_header: FA FA FA
    • BLOOD_MID: 00 17(要求位于 blood_header 起始处的 +7/+8 偏移)
    • MUSCLE_HEADER: FA 0C 19 04 00 00 00 00 00 01(10 字节)
    • BRAIN_PROBE: EF EF EF 0C 11 25 01 41 52 46 4C 41 4C 46 4C 7B FE FE FE(19 字节)
    • BRAIN_RESP: EF EF EF 11 11 25(6 字节)

11. 日志与调试

  • 固定日志

    • [STATUS] 每次状态上报打印
    • [HOTPLUG] 拔出解绑事件打印
  • 可选调试宏(编译期开关)

    • DEBUG_MAIN_RX: 打印 MAIN 下行接收帧(建议仅限短时排查)
    • DEBUG_MAIN_TX: 打印 MAIN 写入统计(可能影响性能)
    • DEBUG_DEVICE_RX: 打印设备上行原始数据(限短时)
    • DEBUG_DETECT: 打印探测过程细节(探针响应、判别结果等)
  • 注意

    • 调试打印可能显著影响时间行为与 CPU 占用;生产环境建议关闭。

12. 健壮性与错误处理

  • MAIN 帧解析必须容错:当 CRC/尾校验失败时,滑动 1 字节继续搜寻帧头,不得卡死。
  • 写操作失败(除 EAGAIN 外)应不中断主循环(可记录错误计数,继续尝试后续帧)。
  • 打开串口/设置属性失败时,启动阶段应报错并退出。
  • 对未知设备数据/无法判别的窗口,不应绑定;等待下一轮或选择 brain 探针路径。

13. 性能与时序要求(默认参数下)

  • 无设备场景的首轮探测耗时
    • 单端口:空闲窗口(≤100ms)+ brain 探针等待(≤200ms)≈ ≤300ms
    • 四端口串行:≈ ≤1.2s 完成一轮无设备判定
  • BRAIN_O2 心跳频率
    • 绑定后每端口约 1Hz 发起探针
  • 上行帧完整性
    • 在设备高频上报、状态上报并行的情况下,MAIN 上位机接收的每一帧必须满足协议完整(头/长度/CRC/尾),不得出现帧交织导致的格式破坏。

14. 功能性用例与验收标准

  • 用例 A:四个端口均无设备
    • 期望:detect_thread 每 ≤1.2s 完成一轮扫描;状态上报显示四端口均为 UNKNOWN(0xFF)
  • 用例 B:插入 BRAIN_O2 设备
    • 期望:在一次空闲窗口后的 200ms 探针等待内识别并绑定;随后每秒发起心跳;主线程接收心跳数据可持续刷新 last_recv;状态上报显示对应端口类型=1
  • 用例 C:插入 BIS/MUSCLE/BLOOD 设备
    • 期望:在正常窗口(≤1.1s)内滑动匹配后绑定;状态上报显示对应类型
  • 用例 D:拔出已绑定设备
    • 期望:在 HOTPLUG_INACTIVE_UNBIND_SEC(3s)后自动解绑并打印 [HOTPLUG];状态上报同步变为 UNKNOWN
  • 用例 E:MAIN 与设备并发大流量
    • 期望:MAIN 上位机所有接收帧保持协议完整;不得出现帧头/尾错位或 CRC 错误

15. 测试建议

  • 协议一致性测试
    • 构造合法/非法 MAIN 帧(CRC 错、尾错、长度不符),验证解析器能跳过非法片段并继续同步
  • 并发写完整性测试
    • 打开状态上报(1s)、同时让四设备以中高频率上报,抓 MAIN 口裸流,使用脚本验证每帧完整性
  • 探测时序测试
    • 无设备:测量完整扫描耗时(应 ≤1.2s)
    • 单设备逐类插入:测绑定延迟(BRAIN_O2 ≈ ≤300ms;其他 ≤1.1s)
  • 热插拔测试
    • 插入设备后断开:确认 3s 超时解绑、状态上报变化
  • 性能/资源测试
    • 监测 CPU 占用与堆栈使用,确认 4KB 栈足够、无溢出风险

16. 可扩展性

  • 本地控制(dev_id=0xFF)命令集
    • 支持运行时调整参数(如上报周期、拔出阈值、探测窗口等)
    • 支持查询统计(帧计数、错误计数、探测成功/失败次数)
  • 设备类型判据增强
    • 增加长度/校验/尾等更严格规则,降低误判
  • 端口数量可配置
    • 通过编译期宏扩展 PORT_NUM,设备路径数组随之扩展

17. 术语表

  • MAIN: 上位机串口(/dev/ttyS1)
  • 设备端口: /dev/ttyS2~S5
  • dev_id: 设备类型编号,用于 MAIN 协议中的设备识别与广播
  • 绑定: 端口被识别为某设备类型并进入正常转发路径
  • 拔出: 已绑定端口超过阈值时间未收到数据,视为设备移除

18. 约束与假设

  • 假设设备对无关帧(如 BRAIN_PROBE)容忍,不会导致异常行为。
  • 假设上位机具备 MAIN 协议解析能力,能根据长度与 CRC 正确重组帧。
  • 若操作系统不支持 460800 波特,MAIN 口将回退到 115200;需在系统集成时确认带宽影响。

19. 交付物

  • 源代码(含宏与注释)
  • 编译配置(NuttX 目标、栈/内存说明)
  • 测试脚本(可选,至少提供 MAIN 帧解析校验脚本思路)
  • 本需求说明书(Markdown)

20. 变更记录

  • v1.0(2025-10-11)
    • 初版:定义多线程模型、MAIN 协议、方案A探测流程、热插拔与状态上报、内存约束与性能目标
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值