多端口智能串口网关程序需求说明书
版本: 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 为该端口绑定的设备类型。
- MAIN -> 设备(下行):
-
本地控制(保留)
- 当 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 对该端口进行探测。
- 端口绑定后若被判定为“拔出”(长时间无数据),将解绑并重新探测。
-
步骤
- 空闲快速窗口(DETECT_IDLE_WINDOW_MS,默认 100ms)
- 在该窗口内对端口执行 poll/读,若读到任意字节则转入“正常窗口”;若未读到任何字节,立即发起 brain 探针。
- 正常窗口(DETECT_WINDOW_MS,默认 1100ms)
- 持续收集数据(poll 步进 DETECT_POLL_STEP_MS,默认 20ms),窗口结束后对累积缓冲做滑动判别 BIS/BLOOD/MUSCLE。
- brain 探针
- 当空闲窗口无任何字节时,发送 BRAIN_PROBE,等待 DETECT_BRAIN_PROBE_RESP_TIMEOUT_MS(默认 200ms)。
- 若响应中匹配 BRAIN_RESP 则判定为 BRAIN_O2 并绑定;否则继续下一个端口或下一轮。
- 空闲快速窗口(DETECT_IDLE_WINDOW_MS,默认 100ms)
-
绑定行为
- 一旦判定出设备类型,设置 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探测流程、热插拔与状态上报、内存约束与性能目标
418

被折叠的 条评论
为什么被折叠?



