mothercup/docs/设计说明书.md

13 KiB
Raw Permalink Blame History

mothercup(母乳杯)设计说明书

V1.0 / 2026-09-05

本文整合当前系统的架构、协议、约定与扩展指南,供后续功能扩展时查阅。 细则以 docs/ble_protocol.md(协议权威)、docs/开发日志.md(踩坑根因)、 AGENTS.md(工程约定)为准;本文是三者 + 真机联调经验的汇总索引。


1. 系统组成

┌─────────────┐   BLE (GATT)    ┌──────────────────────┐
│ 手机 App     │ ◄─────────────► │ 设备 N32WB031        │
│ SmartAssiter│                 │  Boot + 双bank APP   │
└─────────────┘                 │  USART1 (PB6/PB7)    │
┌─────────────┐   BLE / UART    │   ↑                  │
│ PC 工具      │ ◄─────────────► │   └─ SWD (PA4/PA5)   │
│ tools/      │                 └──────────────────────┘
└─────────────┘
端 位置 技术栈 职责
Bootloader Boot/ C / ARMCC / 16KB @0x01000000 校验 bootsetting 记录 → 按 active bank 跳转
应用固件 mcm-ddc-ble/ C / FreeRTOS V9.0.0 原生 API BLE GATT 服务、CLI、参数、OTA
手机 App SmartAssiter/ uni-app Vue3 + TS(HBuilderX 工程) 参数展示、CLI 终端、参数读写、OTA
PC 工具 tools/ Python(无三方依赖的出包脚本 + bleak/pyserial 测试客户端) 出包、烧录、OTA/CLI 参考实现

厂商 SDK/PDF 在 nations-tec/(只读)。SDK 源码经相对路径被工程引用, 各工程目录不能脱离仓库根单独移动。

2. 硬件平台与资源约束

  • SoC:国民技术 N32WB031(板载硅片实测 256KB Flash,Cortex-M0 64MHz, RAM 48KB+16KB)
  • RAM 铁律:低 16KB(0x20000000~0x20003FFF)被芯片 ROM/BLE 子系统占用, 任何工程 IRAM 执行区必须从 0x20004000 起(否则 BLE init 必 HardFault)
  • SWD 引脚 SWCLK=PA4 / SWDIO=PA5,应用程序绝对禁止占用
  • 板载 LED:LED1=PB0、LED2=PA6;USART1:TX=PB6 / RX=PB7(AF4,115200 8N1)
  • 新增 GPIO 前核对开发日志 §4 引脚分配表
  • 不要直接写寄存器;勘误修复必须先在 SDK 源码交叉验证地址用途 (曾按勘误表写 AFEC 寄存器导致 BLE 射频挂死,开发日志 §28)

3. Flash 布局与启动

区域 地址 大小 说明
Bootloader 0x01000000 16KB 只校验 bootsetting 记录自身(magic+CRC32)后跳转
bootsetting 0x01004000 8KB active bank、双 bank 的 addr/size/crc32/version
APP_DATA 0x01006000 8KB 区头 caiic_params_t 参数记录(magic 0xCA12DA7A+CRC32)
APP1 0x01008000 112KB bank1
APP2 0x01024000 112KB bank2
  • Boot 不校验镜像 CRC(CRC 在 OTA 过程中完成);记录无效/地址越界回退 APP1
  • VTOR:Cortex-M0 无 SCB->VTOR,用 PWR->VTOR_REG。BLE init 前指向 APP 自身 向量表(0x80000000|0x01008000);ns_ble_stack_init() 之后必须为 0, 绝对不要在 BLE init 后重设 VTOR(开发日志 §18)
  • 固件不接 ns_sleep 低功耗(与 FreeRTOS tick 冲突),main 里永久锁睡眠保 SWD

4. 版本号与出包约定

  • 每改固件必递增 mcm-ddc-ble/inc/app_version.h 的 APP_FW_VERSION / APP_FW_VERSION_NUM(0x00MMmmpp,补丁位 +1)
  • 构建:Keil µVision5(ARMCC V5.06u6),要求 0 Error 0 Warning
  • 出包必须 UV4 -r 全量重建(增量构建产生过砖包,开发日志 §24), 一键 tools\make_package.bat,产物在 tools/out/:
    • mothercup_ble_prod.hex/.bin — 生产整片包(Boot + 缺省 bootsetting + APP1)
    • mothercup_ble_ota.bin — OTA 发布单文件(52B 头 + 双 bank 载荷,格式见 ble_protocol.md §7)
  • 烧录:tools\flash_package.bat(NSpyocd 整片);Keil 调试下载必须 Erase Sectors(整片擦除会杀掉 Boot)
  • merge_image.py 手动调用必须显式传参(默认路径指向已删除的旧工程)

5. BLE 接口(详见 ble_protocol.md §1/§2/§5)

广播名 CAIIC-MCM-20260902;服务 00002760-08C2-11E1-9073-0E8AC72E1001:

特征尾段 属性 通道定位
e0001 Write NoRsp 帧协议下行(0xCA 字节流)
e0002 Notify 帧协议上行(V1.00.19 修复后可用)
e0003 Read+Write CLI 通道:写命令行(≤63B) → 分包读回文本(0 长度包=结束,上限 1024B)
e0004 Read 参数通道:全信息项 TLV(同 INFO_RSP all)
e0005 Read+Write OTA 通道:写一传输帧 → 轮询读回 OTA_RSP(至非空)
  • MTU:连接后设备主动发起 247 交换;单次写入上限 = att_mtu − 3
  • 帧格式:CA | TYPE | SEQ | LEN(LE16) | PAYLOAD | CRC16-CCITT(LE), CRC 覆盖 TYPE..PAYLOAD 共 4+payLen 字节(新旧实现必须统一)
  • 信息项:0x01 版本 / 0x02 温度(0.1℃) / 0x03 风扇 / 0x04 电压(mV) / 0x05 运行时长(s) / 0x06 堆剩余(B) / 0x07 当前 bank(OTA 选包依据)

6. CLI 命令集(UART 与 BLE e0003 完全一致)

help / version / sysinfo / devinfo / blelog / led / appget [json] / appset / bsdump / bsset / appsw [1|2] / ota / reset / factory / uartrst / uartinfo

  • 维护区(bootsetting / APP_DATA)只暴露结构化命令,无裸读写
  • appsw 切 bank 前校验目标镜像 CRC 与记录一致,不匹配拒绝
  • ota 命令使 UART 进入二进制 OTA 模式(握手标记行 [ota] binary mode ON)
  • reset/factory/appsw 均先应答、延时后复位(保证应答送达)

7. OTA 设计(详见 ble_protocol.md §6/§6.6/§7)

  • 双 bank 直写,无中转区;惰性擦扇区;仅 4B 对齐暂存
  • 传输层通道无关:同一 0xCA 帧会话(BEGIN/DATA/END/ABORT → OTA_RSP) 可跑在 BLE e0005 / UART 二进制模式 / 旧帧协议通道;设备侧 OTA 引擎经 通道注册的 sink 出口应答,会话全程只允许一个通道占用
  • 逐帧锁步:每帧等 ack(ack.offset = 设备期望的下一字节);ack 超时直接 重发同一帧(≤3 次);重复帧回 BAD_STATE+期望 offset,恰好等于本帧结束位置 则视为 ack(丢 ack 容错);status=2 按其 offset 重发即再同步
  • END 可靠送达(V1.00.20):设备先发 ok 应答,等主机取走 + 300ms 宽限 才复位,2s 兜底
  • 选包规则:读 CUR_BANK → 目标 = 对侧 bank → 从头取对应载荷;三重防呆: 客户端向量表预检 + 固件 OTA_END bank_mismatch(status=6) + appsw CRC 校验
  • 主机兜底:END 应答丢失不等于失败,复位后重连复核 CUR_BANK+FW_VERSION 定论

8. 手机 App 设计(SmartAssiter)

8.1 分层

pages/                页面(home / ota / my / bleTest 终端 / 云端账号页)
src/mcm/              设备业务层(只碰业务,不碰 BLE 细节)
  McmCli.ts           CLI 通道(Promise 链串行;写命令→分包读回)
  McmInfo.ts          参数通道(TLV 解析,含 CUR_BANK)
  McmOta.ts           OTA 通道(combo 包解析 + 锁步会话 + 重发/再同步/中止)
  McmCommands.ts      业务命令封装(sysinfo/devinfo/appget/appset…)
src/BluetoothManager.ts  蓝牙管理(扫描/连接/服务发现/读写/MTU)
common/  api/         token、已连设备记忆、云端 HTTP

8.2 通道隔离约定(重要)

  • 每个特征值一条独立通道:读请求按 UUID 分键排队/超时(3s)/分发; 写无跨特征阻塞;CLI 与参数轮询与 OTA 可并行,一路故障不扩散
  • 安卓兼容(实测踩坑):服务发现后 300ms 稳定期;读/写被误报 10007 "property not support" 时各延时 1600ms 重试一次;连接初始化 先 setMtu 再发起读写(并发 GATT 操作会被安卓无声丢弃)
  • home 页参数轮询由 Auto refresh 开关控制,缺省关闭(避免干扰 OTA)
  • App 侧错误码:0 成功;10000 连接失败;10001 断开;10002 蓝牙未开; 10003 无权限;10004/10005 服务/特征缺失;10008 读写/MTU/超时

8.3 OTA 页文件读取(Android 10+ 分区存储)

  • /sdcard/Download 直读被禁(targetSdk≥29);uni.chooseFile App 端不存在
  • 现行方案:SAF 选择器(plus.android ACTION_GET_CONTENT,免权限)→ ContentResolver 流 → Scanner 整流读 String(ISO-8859-1 字节 1:1)→ magic 自验,不过则自动逐字节 read() 直读(二进制精确兜底)
  • plus 桥注意:byte[] 参数按值拷贝,Java 侧写入不会回传 JS; Java 对象方法一律用 plus.android.invoke(obj, name, args...) 调用; App 端 vue3 无 window,plus 挂在 globalThis.plus
  • 备用:adb push 到 _doc/(应用私有目录)后走手动路径

9. PC 工具(tools/)

工具 用途
make_package.bat 一键出包(UV4 -r 全量重建 Boot+APP → merge_image.py)
merge_image.py 合并整片包 + 生成 OTA 发布件(自动取版本号);手动调用必须显式传参
flash_package.bat NSpyocd 整片烧录(需 NS-LINK,先关 Keil)
ble_ota_update.py / ble_ota.bat OTA 参考实现(BLE 默认,--uart COMx 串口);锁步/重发/回连复核的标准实现,新主机端照此移植
ble_cli_test.py / ble_cli.bat BLE CLI 测试客户端(帧协议 + -rw 读写特征两种模式)
ble_temp_watch.py 温度监测

Python 环境:tools/.venv-ble(bleak/pyserial);本机 python 可能是商店占位 stub,脚本内已处理全路径查找。

10. 扩展指南

10.1 加一条 CLI 命令

  1. mcm-ddc-ble/src/cli_core.c 的 s_cmds[] 加 {name, help, handler},实现 handler (输出经 cli_printf,自动同时可用 UART 与 BLE e0003)
  2. 递增版本号 → 出包 → 烧录验证
  3. App 侧如需业务封装,在 McmCommands.ts 加函数(命令名常量集中在顶部)

10.2 加一个信息项(温度/转速类遥测)

  1. 固件 app_info.c 加数据源,app_ble_proto.c 的 TLV 组装加一项(新 id)
  2. 协议文档 §5 表格登记;App McmInfo.ts 的 parseTlv 加分支 + DeviceInfo 加字段(旧 App 会按 len 跳过未知 id,天然兼容)
  3. 版本号 + 出包 + 修改记录

10.3 加一个 GATT 特征

  1. 固件 app_rdtss.c 的 app_rdts_att_db 加声明+值条目(注意 RDTSS_IDX_NB), UUID 取 ...e0006 起顺延;读写回调在 app_ble_proto.c 按 att_idx 分发
  2. App BluetoothManager.ts 加 UUID 常量与读写封装;scanServices 校验清单 按需更新(注意:校验清单变严会让旧固件连不上,考虑兼容性)
  3. 手机端 GATT 缓存注意:特征表变更后若手机行为异常,系统蓝牙关开/ 忽略设备清缓存

10.4 加一条 OTA 传输通道

设备侧 OTA 引擎与通道解耦:新通道只需①把收到的字节流喂给帧重组器、 ②注册应答 sink。参考 UART 通道(ota 命令模式切换)与 BLE e0005 通道 (写帧→读应答轮询)。主机端参考 tools/ble_ota_update.py 与 SmartAssiter/src/mcm/McmOta.ts。

10.5 加 APP_DATA 参数字段

  1. app_params.h 的 caiic_params_t 加字段(保持 magic+CRC 结构;reserved 有余量,优先占用 reserved 保持记录长度 52B 不变)
  2. appget/appset 命令加 key;JSON 模式同步
  3. App McmCommands.ts 的 AppParams 类型与解析同步

10.6 App 加一个页面/业务

  • BLE 一律走 BluetoothManager 的 MyApiResult 回调约定;设备业务封装进 src/mcm/;不改 uni_modules 官方组件;页面注意缩进用 tab
  • HBuilderX 运行调试;云端接口走 api/httpInstance.ts(SERVER_LIST 三地址)

11. 验证与排障手段

  1. Keil 命令行构建 0 Error/0 Warning;出包核对 map 的 __initial_sp 与 bin 向量表初始 SP 一致
  2. 串口 banner/caiic->/devinfo 人工确认;blelog on 抓 BLE 帧(走 printf 不经 BLE,避免自激)
  3. BLE 链路对照:PC ble_cli_test.py / ble_ota_update.py 与手机 App 互验
  4. App 侧控制台日志体系:[MCM](连接/tx/rx hex/超时/重试)、[CLI]、 [INFO]、[OTA](帧)、[OTA-PAGE](选包/升级流程)、[HOME]
  5. 变砖恢复:SWD 重烧整片包

12. 铁律清单(变更前必读)

  1. IRAM 从 0x20004000 起;BLE init 后 VTOR 必须为 0 且不再重设
  2. PA4/PA5(SWD)禁止占用;不用 cmsis_os 封装;SysTick 由 FreeRTOS port 接管
  3. USART1_IRQn 优先级 3(ISR 内调 FromISR API 的硬性要求);BLE_SW/FIFO IRQ 优先级 0 且禁止 FromISR API
  4. ke_msg/ke_timer 只允许在 BLE 调度任务上下文运行;CLI 输出经环形缓冲由 BLE 任务发上行
  5. 出包必须 UV4 -r 全量;Keil 下载只能 Erase Sectors;每改固件必升版本号
  6. 帧 CRC16 覆盖 4+payLen 字节;OTA 逐帧锁步;END 应答送达后才复位
  7. 安卓 BLE:初始化先 MTU 后读写;10007 重试;通道隔离;OTA 期间不开轮询
  8. 固件重大改动追加 docs/开发日志.md;协议改动同步 docs/ble_protocol.md; App 改动写 SmartAssiter/docs/修改记录_日期_主题.md;同步更新 AGENTS.md