mothercup/AGENTS.md

183 lines
18 KiB
Markdown
Raw 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.

# AGENTS.md
## 项目概述
本仓库是 **mothercup(母乳杯)** 产品的完整代码仓库,包含三大部分:
1. **设备固件** — 基于国民技术(Nations)**N32WB031 BLE SoC**(实际型号 **N32WB031KEQ6-2**:Cortex-M0,64MHz HSI,**Flash 512KB**,RAM 48KB+16KB):
- **`mcm-ddc-ble/`** — 唯一活跃的应用固件工程(APP,链接在 APP1 bank `0x01008000`/224KB)。以 SDK rdtss 例程为蓝本,集成 FreeRTOS、UART CLI、BLE 自定义 GATT 服务(CLI 透传 / 设备信息查询 / BLE OTA 双 bank 直写升级)、bootsetting 与 APP_DATA 参数区结构化读写命令。当前版本 **V1.00.13**(`mcm-ddc-ble/inc/app_version.h`)。历史上曾有 `mcm-ddc-04/` 主工程,**已删除**,其功能已全部并入本工程。
- **`Boot/`** — 自写精简 bootloader(链接在 `0x01000000`/16KB):校验 bootsetting 记录自身完整性(magic + 结构体 CRC32)后按 active bank 的 `start_address` 直接跳转;**不校验镜像 CRC(CRC 校验在 OTA 升级过程中完成)**;记录无效或地址越界回退 APP1。
2. **手机 App `SmartAssiter/`** — uni-app **Vue3 + TypeScript** 工程(HBuilderX 项目管理,无 package.json),通过 BLE 连接设备:查看运行参数(温度/电压/转速等)、CLI 终端、OTA 升级页(当前停用,见下)。另有登录/注册/用户信息等云端业务页面。
3. **PC 工具 `tools/`** — 整片烧录包制作/烧录脚本 + bleak 蓝牙测试客户端。
关键文档:
- `docs/开发日志.md` — 固件全程开发日志(33 节,含所有踩坑根因与设计决策,排查问题先查这里)
- `docs/ble_protocol.md` — CAIIC BLE 通信协议 V1.1(帧格式/GATT UUID/三类业务流程/维护命令/手机端开发指南)
- `SmartAssiter/docs/修改记录_*.md` — App 侧每次改造的详细记录
## 仓库顶层结构
```
mothercup/
├── mcm-ddc-ble/ # 应用固件工程(src/ inc/ MDK-ARM/)
├── Boot/ # bootloader 工程(src/ + MDK-ARM/caiic_boot.uvprojx)
├── SmartAssiter/ # 手机 App(uni-app vue3,HBuilderX 工程)
├── tools/ # merge_image.py / make_package.bat / flash_package.bat / ble_cli_test.py 等
├── docs/ # 开发日志.md + ble_protocol.md(仓库级权威文档)
├── nations-tec/ # 厂商资源:SDK V2.0.0、DFP 器件包、STB 开发板资料、官方 PDF。**只读,不要修改**
└── tools/out/ # 出包产物(caiic_ble_full.{hex,bin} + _ota.bin/_ota.json)
```
SDK 源码(固件库、CMSIS、FreeRTOS V9.0.0、BLE 协议栈/profile/ns_library、启动文件)通过相对路径 `..\..\nations-tec\N32WB03x_SDK_V2.0.0` 被 uvprojx 引用,**不复制进工程**;Bootloader 共享代码(`Boot/src/dfu_layout.h`、`boot_crc32.c`)经 `..\..\Boot\src` 被 APP 工程引用。因此各工程目录不能脱离仓库根单独移动。
## Flash / RAM 布局(铁律)
Flash 布局(512KB,`Boot/src/dfu_layout.h` 为唯一权威定义,官方 256KB DFU 布局每区加倍):
| 区域 | 地址 | 大小 |
|---|---|---|
| Bootloader | 0x01000000 | 16KB |
| bootsetting | 0x01004000 | 8KB(用 1 个 4KB 扇区,结构体见 dfu_layout.h) |
| APP_DATA | 0x01006000 | 8KB(区头为 `caiic_params_t` 参数记录,见 app_params.h) |
| APP1 | 0x01008000 | 224KB(0x38000) |
| APP2 | 0x01040000 | 224KB(0x38000) |
- **RAM 铁律**:SRAM 为 48KB+16KB,**低 16KB(0x20000000~0x20003FFF)由芯片 ROM/BLE 子系统占用**(rwip 堆描述符、patch 数组、中断中继表,由 ROM 启动代码预备)。**任何工程的 IRAM 执行区必须从 0x20004000 起**(含 Boot 和任何小工具),否则 .data/.bss 初始化冲掉 ROM 数据,BLE init 必然 HardFault(实测根因,开发日志 §21)。注意:mcm-ddc-ble.uvprojx 里 `<IRAM>` 镜像元素显示 0x20000000 是过期显示值,实际生效的是 OCR_RVCT9=0x20004000/0xC000——以 `Listings/mcm-ddc-ble.map` 的 `RW_IRAM1 (Exec base: 0x20004000)` 为准。
- **VTOR**:Cortex-M0 无 SCB->VTOR,用 `PWR->VTOR_REG`(bit31=EN|[30:0]=基址)。规则:**BLE 初始化之前** VTOR 指向 APP 自身向量表(main 开头设 `0x80000000|0x01008000`,USART1 RX 中断需要);**`ns_ble_stack_init()` 之后 VTOR 必须为 0**,此后所有中断经芯片 ROM 跳板 + RAM 中继。**绝对不要在 BLE init 后重设 VTOR**(实测崩溃根因,开发日志 §18)。
## 固件工程(mcm-ddc-ble)
```
mcm-ddc-ble/
├── src/
│ ├── main.c # 入口:VTOR 预置 → USART+banner → LED → app_ble_init → app_params_init
│ │ # → ns_sleep_lock_acquire(锁睡眠保 SWD) → 建 BLE 调度/LED/CLI 任务 → vTaskStartScheduler
│ ├── bsp_usart.c # USART1(PB6/PB7, 115200 8N1):fputc 重定向 + DMA TX(CH1) + RXDNE 中断字节队列 + TX 互斥锁
│ ├── app_gpio.c # LED1(PB0)/LED2(PA6)
│ ├── app_cli.c # CLI UART 前端:CliTask 行接收/编辑/历史/Tab/Ctrl+Z,提示符 caiic->
│ ├── cli_core.c # CLI 核心(命令表 s_cmds[]/handler/分词执行),输出经可切换 cli_out_fn
│ │ # 命令:help / version / sysinfo / devinfo / blelog / led / appget / appset /
│ │ # bsdump / bsset / reset / factory / uartrst / uartinfo
│ ├── app_ble.c # BLE 栈初始化/广播(名 CAIIC-MCM-20260902)/连接事件 + BLE 调度任务
│ ├── app_ble_proto.c # 0xCA 帧协议:字节流重组、CLI_REQ/RSP、INFO_QUERY/RSP、OTA 帧分发、
│ │ # CLI 读写特征(...e0003) 与只读参数特征(...e0004) 的执行/应答
│ ├── app_info.c # 设备信息:ADC 芯片温度(CH7)/电压(CH6)、运行时长、堆剩余;风扇 weak 数据源
│ ├── app_ota.c # BLE OTA:双 bank 直写(惰性擦扇区,仅 4B 对齐暂存)+ CRC32 校验 + bootsetting 更新 + 复位
│ ├── app_params.c # APP_DATA 参数记录(caiic_params_t,magic+CRC)+ appget/appset 命令(led/pwm)
│ ├── app_bootset.c # bootsetting 结构化读写 bsdump/bsset(自动重算 CRC,防裸写变砖)
│ ├── ble_up.c # CLI 应答的 BLE notify 上行(ke_msg 上下文约束:环形缓冲 + BLE 任务内发送)
│ ├── n32wb03x_it.c # 异常处理(HardFault 栈帧打印)+ USART1_IRQHandler 转发
│ ├── app_usart.c # 遗留文件,已不在工程中编译(rdtss 原透传 FIFO,勿使用)
│ └── app_profile/ # app_rdtss.c(GATT 服务实现,读请求按 att_idx 分发 CLI_VAL/INFO_VAL)等
├── inc/ # 对应头文件 + FreeRTOSConfig.h(heap 20KB)+ app_user_config.h(广播名/连接参数)
└── MDK-ARM/ # mcm-ddc-ble.uvprojx(target "N32WB03x" 为活跃 target;
# OTA_IMG_1/2 是 rdtss 遗产,保留不用)、Objects/、bin/、Listings/
```
工程配置:器件 `N32WB031KEQ6-2`,IROM 0x01008000/0x38000(APP1),IRAM **0x20004000/0xC000**,MicroLIB,全局宏 `N32WB03X, USE_STDPERIPH_DRIVER`;链接器 Misc 附加 BLE ROM 符号表 `symbol_g15.obj`(SDK `middlewares/Nationstech/ble_library/ns_ble_stack/symdef/`)。
## 构建与烧录
工具链:Keil µVision5(ARMCC V5.06 update 6),安装于 `D:\Keil_v5`。
命令行构建(工作目录在对应工程的 `MDK-ARM/`):
```bash
"D:\Keil_v5\UV4\UV4.exe" -b mcm-ddc-ble.uvprojx -j0 -o build.log # APP 增量构建
"D:\Keil_v5\UV4\UV4.exe" -b caiic_boot.uvprojx -j0 -o build.log # Boot 增量构建
```
要求保持 **0 Error(s), 0 Warning(s)**。当前基线(V1.00.13):`Code=38988 RO-data=4524 RW-data=2028 ZI-data=28092`。
**固件版本号约定(重要)**:每次修改固件代码必须递增 `mcm-ddc-ble/inc/app_version.h` 中的 `APP_FW_VERSION` 与 `APP_FW_VERSION_NUM`(格式 `0x00MMmmpp`,通常补丁位 +1),用于识别板上实际运行的固件;工程名与出包文件名保持不变。
**出包约定(重要)**:每次固件修改构建通过后,必须直接运行 `tools\make_package.bat` 重新生成整片包与 OTA 升级包到 `tools/out/`(与代码改动一起交付,不要只交付源码)。
出包与烧录:
1. `tools\make_package.bat` — 一键:`UV4 -r` **全量重建** Boot + APP(出包必须 `-r`,增量构建曾产生栈顶/ZI 不一致的砖包,见开发日志 §24)→ `merge_image.py` 合并。产物在 `tools/out/`:
- `caiic_ble_full.hex/.bin` — 整片包(Boot + 缺省 bootsetting + APP1)
- `caiic_ble_full_ota.bin` + `_ota.json` — OTA 载荷与清单(size/crc32/version;version 自动取 `APP_FW_VERSION_NUM`,手机端 OTA_BEGIN 直接取用)
- 注意:`merge_image.py` 不带参数运行时默认 app 路径仍指向已删除的 `mcm-ddc-04/`,**手动调用必须显式传参**:`python tools/merge_image.py mcm-ddc-ble/MDK-ARM/bin/mcm-ddc-ble.bin caiic_ble_full`
2. 首次/变砖恢复:`tools\flash_package.bat tools\out\caiic_ble_full.hex`(调 SDK 自带 NSpyocd,整片擦除 + 烧录;需 NS-LINK 接 SWD PA4/PA5 + 复位脚,先关闭 Keil)
3. 日常开发调试:Keil F7 编译、F8 下载即可(Boot 不校验镜像 CRC,可直接下载 APP 调试);**Keil 下载选项必须是 "Erase Sectors",整片擦除会杀掉 Boot/bootsetting**(杀掉后需重烧整片包恢复)。板子上烧过其他 0x01000000 起步的程序同样会覆盖 Boot,恢复也是重烧整片包。
4. 日常固件升级设计路径是 BLE OTA(手机 App 或 PC bleak 客户端)。
验证运行:串口助手接 PB6(TX)/PB7(RX),115200 8N1,复位后应看到 banner 与 `caiic->` 提示符(`help` 查看命令);手机应能搜到广播名 `CAIIC-MCM-20260902`。
## BLE 接口与协议(重要:当前双轨状态)
协议权威文档:`docs/ble_protocol.md`(V1.1)。广播名 `CAIIC-MCM-20260902`,自定义 128-bit UUID 服务 `00002760-08c2-11e1-9073-0e8ac72e1001`(SDK rdtss 服务),特征:
| 特征 UUID 尾段 | 属性 | 用途 |
|---|---|---|
| `...c72ee001` | Write Without Response | 0xCA 帧协议下行(CLI_REQ / INFO_QUERY / OTA_*) |
| `...c72ee002` | Notify | 帧协议上行应答(CLI_RSP / INFO_RSP / OTA_RSP) |
| `...c72ee003` | Read + Write(带响应) | **CLI 读写特征**:写原始命令行(≤63B)→ **分包读回**输出文本(每片 ≤att_mtu−2,0 长度包=结束,V1.00.13 起;此前单读 ≤512B),V1.00.02 新增 |
| `...c72ee004` | Read | **只读参数特征**:读出全部信息项 TLV(同 INFO_RSP(all)),V1.00.04 新增 |
- **已知未决问题**:固件 notify 上行链路不通(帧协议应答收不到,下行写入正常),见开发日志 §28 末尾。因此 **App(SmartAssiter)已整体切换为只使用 `...e0003`/`...e0004` 两个读写特征**,删除了 notify/帧协议代码;**App 的 OTA 页当前停用**(OTA 应答依赖 notify)。固件侧帧协议与 OTA 代码仍完整保留,PC 端 `tools/ble_cli_test.py` 两种方式都支持。修复 notify 是本仓库最重要的待办。
- 帧格式:`0xCA | TYPE | SEQ | LEN(LE16) | PAYLOAD | CRC16-CCITT(0x1021/0xFFFF, LE)`;OTA 为双 bank 直写、扇区级 ack 流控、END 整镜像 zlib CRC32 校验后更新 bootsetting 并复位。详见 ble_protocol.md。
- 连接后设备主动发起 MTU=247 交换;失败退化为默认 20B/包,协议按字节流重组,两种情形都正确。
- 信息项 id:0x01 固件版本 u32 / 0x02 芯片温度 i16(0.1°C,ADC CH7) / 0x03 风扇转速 u16(0xFFFF=无硬件,`app_fan_get_rpm()` 弱符号,产品板重写即可) / 0x04 电压 u16(mV,ADC CH6) / 0x05 运行时长 u32(s) / 0x06 剩余堆 u32(B)。
- 调试手段:CLI 命令 `blelog on` 后,串口打印每个收/发协议帧 hex dump、连接/断开、CCCD 订阅事件(走 printf,不经 BLE 通道,避免自激)。
- **维护命令(V1.00.10 起)**:bootsetting 与 APP_DATA 参数区为**结构化**读写(`appget`/`appset`/`bsdump`/`bsset`,不暴露裸读写),UART 与 BLE CLI 读写特征 `...e0003` 均可调用;V1.00.11 起新增 `reset`(复位单板)/`factory`(恢复出厂设置)/`uartrst`(复位串口)/`uartinfo`(查询串口参数)。详见 `docs/ble_protocol.md` §6.5。
## 手机 App(SmartAssiter)
- uni-app **Vue3 + TypeScript**(`manifest.json` vueVersion 3,appid `__UNI__884AC41`),**HBuilderX 工程**(有 `.hbuilderx/`,无 package.json/vite 配置)——开发/运行/打包均在 HBuilderX IDE 内进行(运行→运行到手机或模拟器;发行→原生 App 云打包)。目标平台为 Android/iOS App(BLE 功能仅 App 端有效;manifest 里保留 mp-weixin 配置但蓝牙不依赖它)。
- 由 uni-app x(uvue/uts)+ 第三方蓝牙插件迁移而来,现蓝牙全部用 **uni 内置 BLE API**(vue3 App 端内置),标准基座即可运行(见 `SmartAssiter/docs/修改记录_2026-09-03_迁移uni-app-vue3与蓝牙去插件.md`)。
- 结构:
- `src/BluetoothManager.ts` — 蓝牙管理核心(扫描/连接/服务发现/读写/MTU/RSSI;读请求经 `onBLECharacteristicValueChange` 全局回调 + 内部串行队列 + 3s 超时;连接状态经 `uni.$emit("bleState", state)` 广播,0=已连接可用)
- `src/mcm/` — 设备业务层:`McmCli.ts`(CLI 特征写命令/分包读应答——读到 0 长度包止,Promise 链串行)、`McmInfo.ts`(参数特征 TLV 解析)、`McmCommands.ts`(业务命令封装)
- `pages/tabbar/` — home(设备连接+参数展示)、ota(升级页,**当前停用**并显示原因说明)、my;`pages/bleTest/bluetoothOperation/`(CLI 终端页);login/register/displayUserInfo 为云端账号业务
- `api/` — 云端 HTTP 封装(`httpInstance.ts` 含服务器列表 SERVER_LIST,正式/测试/DEBUG 三地址,token 鉴权);`common/auth.ts`(token 本地存储)、`common/bleInfo.ts`(已连设备名/MAC 记忆)
- `uni_modules/` 仅 uni-icons、uni-scss(官方组件,无第三方插件)
- App 侧错误码约定(BluetoothManager):0=成功,10000=连接失败,10001=已断开,10002=蓝牙未开,10003=无权限,10004/10005=服务/特征缺失,10008=读写/MTU 失败或超时。
## PC 工具(tools/)
- `merge_image.py` — 纯 Python 无三方依赖;合并 boot+bootsetting(缺省记录,脚本生成)+APP 为整片 hex/bin,同时产出 `_ota.bin`/`_ota.json`;自动从 `app_version.h` 取 `APP_FW_VERSION_NUM` 写入清单
- `make_package.bat` / `flash_package.bat` — 一键出包 / NSpyocd 整片烧录(脚本会自动找 Python312 全路径,本机 `python` 可能是商店占位 stub)
- `ble_cli_test.py` + `ble_cli.bat` — PC 端 bleak 蓝牙 CLI 测试客户端(帧协议模式 + `-rw` 读写特征模式,交互模式 `-i`,venv 在 `tools/.venv-ble`,首次运行 bat 自动创建)
- `ble_temp_watch.py` — 温度监测小工具
## 实时架构约定(固件)
- 使用 FreeRTOS V9.0.0 原生 API,**不使用 cmsis_os 封装**。
- 任务:BLE 调度任务(栈 512 字,优先级 2,循环 `rwip_schedule(); vTaskDelay(1ms);`——**ke_msg/ke_timer 只允许在该任务上下文运行**);LED 任务(LED1 闪烁半周期读 APP_DATA 参数 `led1_blink_ms`);CliTask(优先级 3);CLI 输出经环形缓冲由 BLE 任务上下文发 notify(`ble_up.c`)。`configTOTAL_HEAP_SIZE = 20KB`(heap_4)。
- SysTick 由 FreeRTOS port 接管:`main` 中不要手动 `SysTick_Config`,`n32wb03x_it.c` 中不要重复定义 SVC/PendSV/SysTick_Handler。
- USART1_IRQn 优先级为 3(最低),因 ISR 内调用 FreeRTOS FromISR API,必须 ≥ `configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY`(=3)。BLE_SW/FIFO IRQ 优先级 0,其 ISR 内禁止调用 FromISR API。
- 串口输出并发:多任务/CLI 输出分别持有 `bsp_usart_tx_lock()` 互斥锁;调度器启动前为空操作。不要在中断或多个任务里直接 printf。
- **不接 ns_sleep 低功耗**(与 FreeRTOS tick 冲突):`main.c` 里 `ns_sleep_lock_acquire()` 永久锁睡眠,SWD 全程可调试;ns_sleep.c 仍需编译(ns_ble.c 引用其符号)。
## 硬件引脚约束(重要)
- **SWD 调试管脚 SWCLK=PA4 / SWDIO=PA5:应用程序绝对禁止占用**,否则下载/调试失效。
- 板载 LED:LED1=PB0(跳线 J21)、LED2=PA6(跳线 J22),蓝色,4.7K 限流。
- USART1:TX=PB6 / RX=PB7,复用 AF4,经排针 J3 引出。
- PB8/PB9 默认接 32.768K 晶振;PB3 有下拉注意事项(用户手册 5.2.4)。
- 新增 GPIO 前必须核对开发日志第 4 节引脚分配表。
- **寄存器级勘误修复必须先在 SDK 源码交叉验证地址用途**——曾按勘误表写 `0x40011004 |= 0x40`(AFEC 寄存器,与 BLE 协议栈共享)导致 BLE 射频挂死,已撤回(开发日志 §28 教训)。
## 代码风格
- 固件为 C(ARMCC,MicroLIB):文件头/函数头用 Doxygen 注释(`@file`/`@brief`),**注释用英文**;BSP 层函数 `bsp_<module>_<action>`;引脚/时钟等硬件参数集中在头文件顶部宏定义;使用 SDK 标准外设库 API,不要直接操作寄存器(确有例外需交叉验证,见上)。
- App 为 TypeScript/Vue3:注释用中文;BLE 通信统一走 `src/BluetoothManager.ts` 的 `MyApiResult` 回调约定,设备业务封装在 `src/mcm/`;不改 uni_modules 官方组件。
## 测试策略
无自动化测试框架;验证方式为:
1. Keil 命令行构建必须保持 0 Error / 0 Warning;出包必须 `UV4 -r` 全量重建,并核对 map 的 `__initial_sp` 与 bin 向量表初始 SP 一致;
2. 烧录后通过串口输出(banner/`caiic->`/`devinfo`)、LED 行为人工确认;
3. BLE 链路用 `tools/ble_cli_test.py`(PC bleak)或手机 App 实测,配合固件 `blelog on` 串口抓帧对照 `docs/ble_protocol.md` §8.3 示例帧;
4. App 侧改动记录写入 `SmartAssiter/docs/修改记录_日期_主题.md`(沿用现有命名格式)。
## 其他注意事项
- `nations-tec/` 下的 SDK、器件包与 PDF 为第三方只读资料,改动应只发生在 `mcm-ddc-ble/`、`Boot/`、`SmartAssiter/`、`tools/`、`docs/` 内。
- 固件重大改动应同步追加 `docs/开发日志.md` 新章节(现有格式:`## N. 标题(日期)`),协议改动同步 `docs/ble_protocol.md`。
- 每改固件必递增版本号(`mcm-ddc-ble/inc/app_version.h`),否则无法识别板上实际固件。