mothercup/docs/设计说明书.md

239 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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`