13 KiB
13 KiB
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) +
appswCRC 校验 - 主机兜底: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.chooseFileApp 端不存在- 现行方案: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 命令
mcm-ddc-ble/src/cli_core.c的s_cmds[]加{name, help, handler},实现 handler (输出经cli_printf,自动同时可用 UART 与 BLE e0003)- 递增版本号 → 出包 → 烧录验证
- App 侧如需业务封装,在
McmCommands.ts加函数(命令名常量集中在顶部)
10.2 加一个信息项(温度/转速类遥测)
- 固件
app_info.c加数据源,app_ble_proto.c的 TLV 组装加一项(新 id) - 协议文档 §5 表格登记;App
McmInfo.ts的parseTlv加分支 +DeviceInfo加字段(旧 App 会按 len 跳过未知 id,天然兼容) - 版本号 + 出包 + 修改记录
10.3 加一个 GATT 特征
- 固件
app_rdtss.c的app_rdts_att_db加声明+值条目(注意RDTSS_IDX_NB), UUID 取...e0006起顺延;读写回调在app_ble_proto.c按 att_idx 分发 - App
BluetoothManager.ts加 UUID 常量与读写封装;scanServices校验清单 按需更新(注意:校验清单变严会让旧固件连不上,考虑兼容性) - 手机端 GATT 缓存注意:特征表变更后若手机行为异常,系统蓝牙关开/ 忽略设备清缓存
10.4 加一条 OTA 传输通道
设备侧 OTA 引擎与通道解耦:新通道只需①把收到的字节流喂给帧重组器、
②注册应答 sink。参考 UART 通道(ota 命令模式切换)与 BLE e0005 通道
(写帧→读应答轮询)。主机端参考 tools/ble_ota_update.py 与
SmartAssiter/src/mcm/McmOta.ts。
10.5 加 APP_DATA 参数字段
app_params.h的caiic_params_t加字段(保持 magic+CRC 结构;reserved 有余量,优先占用 reserved 保持记录长度 52B 不变)appget/appset命令加 key;JSON 模式同步- App
McmCommands.ts的AppParams类型与解析同步
10.6 App 加一个页面/业务
- BLE 一律走
BluetoothManager的MyApiResult回调约定;设备业务封装进src/mcm/;不改uni_modules官方组件;页面注意缩进用 tab - HBuilderX 运行调试;云端接口走
api/httpInstance.ts(SERVER_LIST 三地址)
11. 验证与排障手段
- Keil 命令行构建 0 Error/0 Warning;出包核对 map 的
__initial_sp与 bin 向量表初始 SP 一致 - 串口 banner/
caiic->/devinfo人工确认;blelog on抓 BLE 帧(走 printf 不经 BLE,避免自激) - BLE 链路对照:PC
ble_cli_test.py/ble_ota_update.py与手机 App 互验 - App 侧控制台日志体系:
[MCM](连接/tx/rx hex/超时/重试)、[CLI]、[INFO]、[OTA](帧)、[OTA-PAGE](选包/升级流程)、[HOME] - 变砖恢复:SWD 重烧整片包
12. 铁律清单(变更前必读)
- IRAM 从 0x20004000 起;BLE init 后 VTOR 必须为 0 且不再重设
- PA4/PA5(SWD)禁止占用;不用 cmsis_os 封装;SysTick 由 FreeRTOS port 接管
- USART1_IRQn 优先级 3(ISR 内调 FromISR API 的硬性要求);BLE_SW/FIFO IRQ 优先级 0 且禁止 FromISR API
- ke_msg/ke_timer 只允许在 BLE 调度任务上下文运行;CLI 输出经环形缓冲由 BLE 任务发上行
- 出包必须 UV4 -r 全量;Keil 下载只能 Erase Sectors;每改固件必升版本号
- 帧 CRC16 覆盖 4+payLen 字节;OTA 逐帧锁步;END 应答送达后才复位
- 安卓 BLE:初始化先 MTU 后读写;10007 重试;通道隔离;OTA 期间不开轮询
- 固件重大改动追加
docs/开发日志.md;协议改动同步docs/ble_protocol.md; App 改动写SmartAssiter/docs/修改记录_日期_主题.md;同步更新AGENTS.md