mcm-ddc-ble V1.00.18:发布命名整理(生产整包mothercup_ble_prod,OTA单文件发布件mothercup_ble_ota);合并OTA包头扩为52B(新增hdr_len/total_size/payload_crc,原json清单信息全部收进头部,单文件发布);merge_image.py新增--combo-name;ble_ota_update.py/ble_ota.bat PC端BLE OTA升级器(实验性:CUR_BANK选包/扇区擦除避让节流/复位检测,实机调通中);SWD单bank升级流程实测通过(bin\@基址部分烧录+bsset修记录+appsw切入);格式与升级流程写入ble_protocol.md §7供App/UART升级开发;开发日志40~41
This commit is contained in:
parent
a546dc5f46
commit
266fcec731
19
AGENTS.md
19
AGENTS.md
@ -5,14 +5,14 @@
|
|||||||
本仓库是 **mothercup(母乳杯)** 产品的完整代码仓库,包含三大部分:
|
本仓库是 **mothercup(母乳杯)** 产品的完整代码仓库,包含三大部分:
|
||||||
|
|
||||||
1. **设备固件** — 基于国民技术(Nations)**N32WB031 BLE SoC**(Cortex-M0,64MHz HSI,**板载硅片实测 256KB Flash**(0x01000000~0x0103FFFF,开发日志 §37),RAM 48KB+16KB):
|
1. **设备固件** — 基于国民技术(Nations)**N32WB031 BLE SoC**(Cortex-M0,64MHz HSI,**板载硅片实测 256KB Flash**(0x01000000~0x0103FFFF,开发日志 §37),RAM 48KB+16KB):
|
||||||
- **`mcm-ddc-ble/`** — 唯一活跃的应用固件工程(APP,链接在 APP1 bank `0x01008000`/112KB)。以 SDK rdtss 例程为蓝本,集成 FreeRTOS、UART CLI、BLE 自定义 GATT 服务(CLI 透传 / 设备信息查询 / BLE OTA 双 bank 直写升级)、bootsetting 与 APP_DATA 参数区结构化读写命令。当前版本 **V1.00.17**(`mcm-ddc-ble/inc/app_version.h`)。历史上曾有 `mcm-ddc-04/` 主工程,**已删除**,其功能已全部并入本工程。
|
- **`mcm-ddc-ble/`** — 唯一活跃的应用固件工程(APP,链接在 APP1 bank `0x01008000`/112KB)。以 SDK rdtss 例程为蓝本,集成 FreeRTOS、UART CLI、BLE 自定义 GATT 服务(CLI 透传 / 设备信息查询 / BLE OTA 双 bank 直写升级)、bootsetting 与 APP_DATA 参数区结构化读写命令。当前版本 **V1.00.18**(`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。
|
- **`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 升级页(当前停用,见下)。另有登录/注册/用户信息等云端业务页面。
|
2. **手机 App `SmartAssiter/`** — uni-app **Vue3 + TypeScript** 工程(HBuilderX 项目管理,无 package.json),通过 BLE 连接设备:查看运行参数(温度/电压/转速等)、CLI 终端、OTA 升级页(当前停用,见下)。另有登录/注册/用户信息等云端业务页面。
|
||||||
3. **PC 工具 `tools/`** — 整片烧录包制作/烧录脚本 + bleak 蓝牙测试客户端。
|
3. **PC 工具 `tools/`** — 整片烧录包制作/烧录脚本 + bleak 蓝牙测试客户端。
|
||||||
|
|
||||||
关键文档:
|
关键文档:
|
||||||
|
|
||||||
- `docs/开发日志.md` — 固件全程开发日志(39 节,含所有踩坑根因与设计决策,排查问题先查这里)
|
- `docs/开发日志.md` — 固件全程开发日志(41 节,含所有踩坑根因与设计决策,排查问题先查这里)
|
||||||
- `docs/ble_protocol.md` — CAIIC BLE 通信协议 V1.1(帧格式/GATT UUID/三类业务流程/维护命令/手机端开发指南)
|
- `docs/ble_protocol.md` — CAIIC BLE 通信协议 V1.1(帧格式/GATT UUID/三类业务流程/维护命令/手机端开发指南)
|
||||||
- `SmartAssiter/docs/修改记录_*.md` — App 侧每次改造的详细记录
|
- `SmartAssiter/docs/修改记录_*.md` — App 侧每次改造的详细记录
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ mothercup/
|
|||||||
├── tools/ # merge_image.py / make_package.bat / flash_package.bat / ble_cli_test.py 等
|
├── tools/ # merge_image.py / make_package.bat / flash_package.bat / ble_cli_test.py 等
|
||||||
├── docs/ # 开发日志.md + ble_protocol.md(仓库级权威文档)
|
├── docs/ # 开发日志.md + ble_protocol.md(仓库级权威文档)
|
||||||
├── nations-tec/ # 厂商资源:SDK V2.0.0、DFP 器件包、STB 开发板资料、官方 PDF。**只读,不要修改**
|
├── nations-tec/ # 厂商资源:SDK V2.0.0、DFP 器件包、STB 开发板资料、官方 PDF。**只读,不要修改**
|
||||||
└── tools/out/ # 出包产物(caiic_ble_full.{hex,bin} + _ota.bin/_ota.json)
|
└── tools/out/ # 出包产物(mothercup_ble_prod.{hex,bin} 生产整包 + mothercup_ble_ota.bin 单文件升级包 + 调试用 _ota.bin/_ota_app2.bin 及 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 工程引用。因此各工程目录不能脱离仓库根单独移动。
|
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 工程引用。因此各工程目录不能脱离仓库根单独移动。
|
||||||
@ -95,7 +95,7 @@ mcm-ddc-ble/
|
|||||||
"D:\Keil_v5\UV4\UV4.exe" -b caiic_boot.uvprojx -j0 -o build.log # Boot 增量构建
|
"D:\Keil_v5\UV4\UV4.exe" -b caiic_boot.uvprojx -j0 -o build.log # Boot 增量构建
|
||||||
```
|
```
|
||||||
|
|
||||||
要求保持 **0 Error(s), 0 Warning(s)**。当前基线(V1.00.17):`Code=47896 RO-data=4752 RW-data=2060 ZI-data=28612`。
|
要求保持 **0 Error(s), 0 Warning(s)**。当前基线(V1.00.18):`Code=47896 RO-data=4752 RW-data=2060 ZI-data=28612`。
|
||||||
|
|
||||||
**固件版本号约定(重要)**:每次修改固件代码必须递增 `mcm-ddc-ble/inc/app_version.h` 中的 `APP_FW_VERSION` 与 `APP_FW_VERSION_NUM`(格式 `0x00MMmmpp`,通常补丁位 +1),用于识别板上实际运行的固件;工程名与出包文件名保持不变。
|
**固件版本号约定(重要)**:每次修改固件代码必须递增 `mcm-ddc-ble/inc/app_version.h` 中的 `APP_FW_VERSION` 与 `APP_FW_VERSION_NUM`(格式 `0x00MMmmpp`,通常补丁位 +1),用于识别板上实际运行的固件;工程名与出包文件名保持不变。
|
||||||
|
|
||||||
@ -103,11 +103,11 @@ mcm-ddc-ble/
|
|||||||
|
|
||||||
出包与烧录:
|
出包与烧录:
|
||||||
|
|
||||||
1. `tools\make_package.bat` — 一键:`UV4 -r` **全量重建** Boot + APP(出包必须 `-r`,增量构建曾产生栈顶/ZI 不一致的砖包,见开发日志 §24)→ `merge_image.py` 合并。产物在 `tools/out/`:
|
1. `tools\make_package.bat` — 一键:`UV4 -r` **全量重建** Boot + APP1 + APP2 target(出包必须 `-r`,增量构建曾产生栈顶/ZI 不一致的砖包,见开发日志 §24)→ `merge_image.py` 合并。产物在 `tools/out/`:
|
||||||
- `caiic_ble_full.hex/.bin` — 整片包(Boot + 缺省 bootsetting + APP1)
|
- `mothercup_ble_prod.hex/.bin` — 生产整片包(Boot + 缺省 bootsetting + APP1,只含一个 APP)
|
||||||
- `caiic_ble_full_ota.bin` + `_ota.json` — APP1 链接的 OTA 载荷与清单(size/crc32/version/target_bank=1;version 自动取 `APP_FW_VERSION_NUM`);`make_package.bat` 同时构建 APP2 target 并出 `caiic_ble_full_ota_app2.bin`/`_ota_app2.json`(target_bank=2)。**客户端按信息项 0x07 CUR_BANK 选对侧 bank 的载荷**;固件 OTA_END 有向量表防呆(status=6 bank_mismatch)
|
- `mothercup_ble_ota.bin` — **OTA 单文件发布件**(52B 头含 version/总大小/总 CRC + 双 bank 载荷索引,格式见 ble_protocol.md §7);调试用单 bank 载荷 `mothercup_ble_prod_ota.bin`(bank1)/ `_ota_app2.bin`(bank2)+ json 也保留。**客户端按信息项 0x07 CUR_BANK 选对侧 bank 的载荷**;固件 OTA_END 有向量表防呆(status=6 bank_mismatch)
|
||||||
- 注意:`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`
|
- 注意:`merge_image.py` 不带参数运行时默认 app 路径仍指向已删除的 `mcm-ddc-04/`,**手动调用必须显式传参**:`python tools/merge_image.py mcm-ddc-ble/MDK-ARM/bin/mcm-ddc-ble.bin mothercup_ble_prod`
|
||||||
2. 首次/变砖恢复:`tools\flash_package.bat tools\out\caiic_ble_full.hex`(调 SDK 自带 NSpyocd,整片擦除 + 烧录;需 NS-LINK 接 SWD PA4/PA5 + 复位脚,先关闭 Keil;target 用 DFP pack 的 `n32wb031keq6_2` + `-O smart_flash=false`,内置 `n32wb031` target 只有 256KB 映射)
|
2. 首次/变砖恢复:`tools\flash_package.bat tools\out\mothercup_ble_prod.hex`(调 SDK 自带 NSpyocd,整片擦除 + 烧录;需 NS-LINK 接 SWD PA4/PA5 + 复位脚,先关闭 Keil;target 用 DFP pack 的 `n32wb031keq6_2` + `-O smart_flash=false`)
|
||||||
- **双 APP 整包(appsw 测试)**:`tools\make_dual_package.bat` 出 `caiic_ble_dual.{hex,bin}`(Boot+bootsetting 双 bank 记录+APP_DATA 缺省记录+APP1/APP2 **同版本**双镜像,APP2 由 uvprojx target "APP2" 链接 0x01024000 构建;运行 bank 用信息项 0x07 CUR_BANK 识别);`flash_package.bat tools\out\caiic_ble_dual.hex` 烧录后可用 `appsw` 在两 bank 间切换(已实测双向切换)。
|
- **双 APP 整包(appsw 测试)**:`tools\make_dual_package.bat` 出 `caiic_ble_dual.{hex,bin}`(Boot+bootsetting 双 bank 记录+APP_DATA 缺省记录+APP1/APP2 **同版本**双镜像,APP2 由 uvprojx target "APP2" 链接 0x01024000 构建;运行 bank 用信息项 0x07 CUR_BANK 识别);`flash_package.bat tools\out\caiic_ble_dual.hex` 烧录后可用 `appsw` 在两 bank 间切换(已实测双向切换)。
|
||||||
- **OTA 双 bank 选包**:OTA 写对侧 bank,载荷必须链接在目标 bank 地址;两份载荷见上,客户端按 CUR_BANK 选包(详见开发日志 §39)。
|
- **OTA 双 bank 选包**:OTA 写对侧 bank,载荷必须链接在目标 bank 地址;两份载荷见上,客户端按 CUR_BANK 选包(详见开发日志 §39)。
|
||||||
3. 日常开发调试:Keil F7 编译、F8 下载即可(Boot 不校验镜像 CRC,可直接下载 APP 调试);**Keil 下载选项必须是 "Erase Sectors",整片擦除会杀掉 Boot/bootsetting**(杀掉后需重烧整片包恢复)。板子上烧过其他 0x01000000 起步的程序同样会覆盖 Boot,恢复也是重烧整片包。
|
3. 日常开发调试:Keil F7 编译、F8 下载即可(Boot 不校验镜像 CRC,可直接下载 APP 调试);**Keil 下载选项必须是 "Erase Sectors",整片擦除会杀掉 Boot/bootsetting**(杀掉后需重烧整片包恢复)。板子上烧过其他 0x01000000 起步的程序同样会覆盖 Boot,恢复也是重烧整片包。
|
||||||
@ -151,6 +151,7 @@ mcm-ddc-ble/
|
|||||||
- `make_package.bat` / `flash_package.bat` — 一键出包 / NSpyocd 整片烧录(脚本会自动找 Python312 全路径,本机 `python` 可能是商店占位 stub)
|
- `make_package.bat` / `flash_package.bat` — 一键出包 / NSpyocd 整片烧录(脚本会自动找 Python312 全路径,本机 `python` 可能是商店占位 stub)
|
||||||
- `make_dual_package.bat` — 双 APP 整包(Boot+bootsetting 双 bank+APP_DATA+APP1+APP2,APP2 升一版链接 0x01024000),用于 appsw 切换测试
|
- `make_dual_package.bat` — 双 APP 整包(Boot+bootsetting 双 bank+APP_DATA+APP1+APP2,APP2 升一版链接 0x01024000),用于 appsw 切换测试
|
||||||
- `ble_cli_test.py` + `ble_cli.bat` — PC 端 bleak 蓝牙 CLI 测试客户端(帧协议模式 + `-rw` 读写特征模式,交互模式 `-i`,venv 在 `tools/.venv-ble`,首次运行 bat 自动创建)
|
- `ble_cli_test.py` + `ble_cli.bat` — PC 端 bleak 蓝牙 CLI 测试客户端(帧协议模式 + `-rw` 读写特征模式,交互模式 `-i`,venv 在 `tools/.venv-ble`,首次运行 bat 自动创建)
|
||||||
|
- `ble_ota_update.py` + `ble_ota.bat` — BLE OTA 升级器(解析单文件升级包 `mothercup_ble_ota.bin`、按 CUR_BANK 选对侧 bank 载荷、节流发送避开扇区擦除窗口、复位检测+重连校验)。**实验性:实机跑通中,notify 上行不通拿不到 OTA_RSP,定位见开发日志 §40**
|
||||||
- `ble_temp_watch.py` — 温度监测小工具
|
- `ble_temp_watch.py` — 温度监测小工具
|
||||||
|
|
||||||
## 实时架构约定(固件)
|
## 实时架构约定(固件)
|
||||||
|
|||||||
@ -130,13 +130,12 @@ flash 擦除单位 = 4KB 扇区。设备侧**直写 flash,不做扇区级 RAM
|
|||||||
注意:flash 擦写期间设备关中断数十 ms/扇区(Qflash 算法在 RAM 执行),BLE 链路靠
|
注意:flash 擦写期间设备关中断数十 ms/扇区(Qflash 算法在 RAM 执行),BLE 链路靠
|
||||||
5s supervision timeout 维持,属正常现象;但请避免在 OTA 期间主动断开。
|
5s supervision timeout 维持,属正常现象;但请避免在 OTA 期间主动断开。
|
||||||
|
|
||||||
**OTA 载荷必须链接在目标 bank 地址**(Cortex-M0 代码位置相关)。出包脚本同时产出
|
**OTA 载荷必须链接在目标 bank 地址**(Cortex-M0 代码位置相关)。发布件为单文件
|
||||||
两份 bank 匹配的载荷:`<包名>_ota.bin`(target_bank=1,链接 0x01008000)与
|
`mothercup_ble_ota.bin`(52B 头含双载荷索引与全部 CRC,格式见 §7)。**客户端选包
|
||||||
`<包名>_ota_app2.bin`(target_bank=2,链接 0x01024000),清单 json 内含
|
规则**:先读信息项 0x07 CUR_BANK(当前运行 bank),OTA 目标 = 对侧 bank,从头里取
|
||||||
`target_bank` 字段。**客户端选包规则**:先读信息项 0x07 CUR_BANK(当前运行 bank),
|
对应载荷。固件侧兜底:OTA_END 整镜像 CRC 通过后,还会校验镜像向量表 Reset 地址
|
||||||
OTA 目标 = 对侧 bank,选用对应的载荷。固件侧兜底:OTA_END 整镜像 CRC 通过后,
|
落在目标 bank 范围内,不符则回 OTA_RSP(status=6 bank_mismatch) 并中止、不切换
|
||||||
还会校验镜像向量表 Reset 地址落在目标 bank 范围内,不符则回
|
(V1.00.17 起)。
|
||||||
OTA_RSP(status=6 bank_mismatch) 并中止、不切换(V1.00.17 起)。
|
|
||||||
|
|
||||||
## 6.5 维护命令:bootsetting 与 APP_DATA 参数区(V1.00.09 起,结构化访问;V1.00.10 起参数命令为 appget/appset;V1.00.11 起新增 reset/factory/uartrst/uartinfo)
|
## 6.5 维护命令:bootsetting 与 APP_DATA 参数区(V1.00.09 起,结构化访问;V1.00.10 起参数命令为 appget/appset;V1.00.11 起新增 reset/factory/uartrst/uartinfo)
|
||||||
|
|
||||||
@ -171,10 +170,35 @@ blob 偏移不下发应用层,协议栈会切错窗口),**读到 0 长度
|
|||||||
|
|
||||||
- 出厂/首次:SWD 烧录整包(bootloader + bootsetting 缺省配置 + APP1),
|
- 出厂/首次:SWD 烧录整包(bootloader + bootsetting 缺省配置 + APP1),
|
||||||
由 `tools\merge_image.py` / `make_package.bat` 生成。
|
由 `tools\merge_image.py` / `make_package.bat` 生成。
|
||||||
- OTA 镜像:每次出整包时 `merge_image.py` 同时输出 `<包名>_ota.bin`
|
- OTA 发布文件(**单文件发布**,V1.00.18 起):`tools\make_package.bat` 产出
|
||||||
(OTA 载荷,即 APP bin 本体)和 `<包名>_ota.json`(清单:size / crc32 /
|
`mothercup_ble_ota.bin` = **52B 头 + bank1 载荷 + bank2 载荷**,头已包含原清单
|
||||||
version,手机端 OTA_BEGIN 直接取这三个值;version 可用第三个命令行参数
|
json 的全部信息(version/总大小/总 CRC),无需伴随 json。格式(全小端):
|
||||||
指定,如 `0x00010001`,缺省 0)。
|
|
||||||
|
| 偏移 | 字段 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| 0 | magic u32 | `0xCA10BA11` |
|
||||||
|
| 4 | hdr_len u32 | = 52(头部字节数,前向兼容扩展用) |
|
||||||
|
| 8 | version u32 | 固件版本号(`0x00MMmmpp`,写进 OTA_BEGIN 与新 bank 记录) |
|
||||||
|
| 12 | total_size u32 | 整文件字节数(自检) |
|
||||||
|
| 16 | payload_crc u32 | CRC32(hdr_len .. 文件尾),即两份载荷整体 |
|
||||||
|
| 20 | count u32 | = 2 |
|
||||||
|
| 24 | b1_off/b1_size/b1_crc u32×3 | bank1(APP1 链接,0x01008000)载荷索引 |
|
||||||
|
| 36 | b2_off/b2_size/b2_crc u32×3 | bank2(APP2 链接,0x01024000)载荷索引 |
|
||||||
|
| 48 | hdr_crc u32 | CRC32(头 0..47) |
|
||||||
|
|
||||||
|
CRC32 均为 IEEE(zlib 多项式,与固件 `caiic_crc32` 一致)。
|
||||||
|
**升级流程(APP/UART/PC 通用)**:① 校验 magic + hdr_len + hdr_crc +
|
||||||
|
total_size + payload_crc;② 读设备信息项 0x07 CUR_BANK 得当前运行 bank N;
|
||||||
|
③ 取对侧 bank(3−N)的载荷(offset/size/crc 取自头部);④ OTA_BEGIN
|
||||||
|
{size, crc32, version} → OTA_DATA 流 → OTA_END{crc32};⑤ 设备自动复位到
|
||||||
|
新 bank,重连后复核 CUR_BANK 与 FW_VERSION。PC 参考实现:
|
||||||
|
`tools\ble_ota_update.py`(`ble_ota.bat`)。
|
||||||
|
调试用的单 bank 载荷(`mothercup_ble_prod_ota.bin` / `_ota_app2.bin` + json)
|
||||||
|
仍在 tools/out/ 生成,但不作为发布件。
|
||||||
|
- **SWD 单 bank 升级**(不动运行中的 bank,V1.00.18 实测通过):
|
||||||
|
`NSpyocd load ... "mcm-ddc-ble.bin@0x01008000"`(bin 后用 `@基址` 指定写入
|
||||||
|
位置,只擦写涉及扇区)→ CLI `bsset` 修正该 bank 的 size/crc/ver →
|
||||||
|
`appsw` 切入。详见开发日志 §40。
|
||||||
- OTA 失败变砖恢复:SWD 重烧即可(bootloader 不做串口 DFU)。
|
- OTA 失败变砖恢复:SWD 重烧即可(bootloader 不做串口 DFU)。
|
||||||
- Keil 调试下载必须用**扇区擦除**,整片擦除会删掉 bootloader。
|
- Keil 调试下载必须用**扇区擦除**,整片擦除会删掉 bootloader。
|
||||||
|
|
||||||
@ -228,8 +252,8 @@ def parse_stream(buf: bytearray):
|
|||||||
```
|
```
|
||||||
|
|
||||||
镜像 CRC32(OTA_BEGIN / OTA_END 用):标准 zlib/IEEE CRC32,
|
镜像 CRC32(OTA_BEGIN / OTA_END 用):标准 zlib/IEEE CRC32,
|
||||||
`zlib.crc32(open('xxx_ota.bin','rb').read()) & 0xFFFFFFFF`,
|
对 `mothercup_ble_ota.bin` 中取出的目标 bank 载荷计算
|
||||||
也可直接从 `<包名>_ota.json` 清单里读。
|
(`zlib.crc32(payload) & 0xFFFFFFFF`),也可直接读头部的 bN_crc 字段。
|
||||||
|
|
||||||
### 8.3 字节级完整示例(均含 SOF 与 CRC16,SEQ 自取)
|
### 8.3 字节级完整示例(均含 SOF 与 CRC16,SEQ 自取)
|
||||||
|
|
||||||
|
|||||||
39
docs/开发日志.md
39
docs/开发日志.md
@ -996,3 +996,42 @@ APP2 `Code=48004`(同源码、不同链接地址/版本号,体积差 300B
|
|||||||
`cur bank: APP2`(两 bank 同为 V1.00.17)→ e0004 TLV 含 `cur_bank` →
|
`cur bank: APP2`(两 bank 同为 V1.00.17)→ e0004 TLV 含 `cur_bank` →
|
||||||
`appsw 1` 切回。构建 0 Error/0 Warning(双 target),整包/双包/双 OTA 载荷
|
`appsw 1` 切回。构建 0 Error/0 Warning(双 target),整包/双包/双 OTA 载荷
|
||||||
均已重新生成。
|
均已重新生成。
|
||||||
|
|
||||||
|
## 40. SWD 单 bank 升级流程实测 + BLE OTA 待定(2026-09-04,V1.00.18)
|
||||||
|
|
||||||
|
**SWD 部分烧录升级(不动运行中的 bank)实测通过**,步骤:
|
||||||
|
|
||||||
|
1. 正常出包:`tools\make_package.bat`(构建 APP1/APP2 双 target,出整包 +
|
||||||
|
bank1/bank2 两份 OTA 载荷 + 合并包 `*_ota_dual.bin`);
|
||||||
|
2. 只写非活动 bank(假设当前跑 APP2,升级 APP1 区):
|
||||||
|
`NSpyocd load --pack <DFP> -M under-reset -f 1000000 -t n32wb031keq6_2
|
||||||
|
-O smart_flash=false mcm-ddc-ble.bin@0x01008000`
|
||||||
|
—— bin 后用 `@地址` 指定基址,pyocd 只擦写涉及的 14 个扇区,运行中的
|
||||||
|
APP2 不受影响(烧完复位仍回 active bank);
|
||||||
|
3. BLE/串口 CLI 修正该 bank 记录:`bsset b1size <size>` / `bsset b1crc <crc>`
|
||||||
|
/ `bsset b1ver <ver>`(值取 merge_image 输出或 _ota.json 清单);
|
||||||
|
4. `appsw 1` → 目标镜像 CRC 复算通过 → 复位切入新版本。
|
||||||
|
|
||||||
|
实测:bank1 SWD 写入 V1.00.18 → 修记录 → `appsw 1` → `devinfo` 报
|
||||||
|
**APP1 / V1.00.18**;bank2 仍保留 V1.00.17 可回切。此路径可作为 BLE OTA
|
||||||
|
修复前的生产升级手段,也是 OTA 链路的地面参照。
|
||||||
|
|
||||||
|
**BLE OTA 当前状态(未决)**:`tools/ble_ota_update.py`(合并包解析、
|
||||||
|
CUR_BANK 选包、扇区擦除窗口避让的节流发送、双次重试)已写好并实机试跑,
|
||||||
|
但设备端在 OTA_END 后未复位(中途应有帧丢失/状态拒绝,notify 上行不通
|
||||||
|
拿不到 OTA_RSP,定位需要 UART blelog)。该脚本标记为实验性,待 notify
|
||||||
|
修复或 UART 抓帧后再调通。
|
||||||
|
|
||||||
|
## 41. 发布命名整理 + OTA 单文件包(2026-09-04,工具链,固件 V1.00.18 不变)
|
||||||
|
|
||||||
|
- 生产整片包改名 **`mothercup_ble_prod.{hex,bin}`**(Boot+bootsetting+APP_DATA
|
||||||
|
缺省记录+APP1);`flash_package.bat` 缺省镜像同步改名。
|
||||||
|
- OTA 发布件改名 **`mothercup_ble_ota.bin`**,头部从 40B 扩到 **52B**:
|
||||||
|
新增 hdr_len、total_size(整文件字节数)、payload_crc(两载荷整体 CRC32)——
|
||||||
|
原清单 json 的信息全部收进头部,**只发这一个文件**(单 bank 载荷与 json
|
||||||
|
仍生成,仅供调试)。格式表写入 ble_protocol.md §7(供 App/UART 升级开发)。
|
||||||
|
- `merge_image.py` 新增 `--combo-name`,`make_package.bat` 传
|
||||||
|
`--combo-name mothercup_ble_ota`;`ble_ota_update.py` 按新头解析并校验
|
||||||
|
hdr_len/total_size/payload_crc/各 bank crc,实包解析验证通过
|
||||||
|
(V1.00.18,bank1 54204B / bank2 54504B,total=108760B 与文件一致)。
|
||||||
|
- 旧命名 caiic_ble_full_* 产物已从仓库删除;双 APP 测试包仍叫 caiic_ble_dual。
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@ -9,12 +9,12 @@
|
|||||||
#define __APP_VERSION_H__
|
#define __APP_VERSION_H__
|
||||||
|
|
||||||
#ifndef APP_FW_VERSION
|
#ifndef APP_FW_VERSION
|
||||||
#define APP_FW_VERSION "V1.00.17"
|
#define APP_FW_VERSION "V1.00.18"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Numeric form used by the BLE info query / OTA records: 0x00MMmmpp */
|
/* Numeric form used by the BLE info query / OTA records: 0x00MMmmpp */
|
||||||
#ifndef APP_FW_VERSION_NUM
|
#ifndef APP_FW_VERSION_NUM
|
||||||
#define APP_FW_VERSION_NUM 0x00010011u
|
#define APP_FW_VERSION_NUM 0x00010012u
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __APP_VERSION_H__ */
|
#endif /* __APP_VERSION_H__ */
|
||||||
|
|||||||
35
tools/ble_ota.bat
Normal file
35
tools/ble_ota.bat
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
@echo off
|
||||||
|
rem ============================================================
|
||||||
|
rem ble_ota.bat - BLE OTA updater for CAIIC-MCM devices
|
||||||
|
rem
|
||||||
|
rem ble_ota.bat [combo_pkg]
|
||||||
|
rem default: tools\out\mothercup_ble_ota.bin
|
||||||
|
rem
|
||||||
|
rem The combined package holds both bank-linked payloads; the script
|
||||||
|
rem reads the current bank (info item 0x07 CUR_BANK) and downloads
|
||||||
|
rem the payload for the opposite bank, then verifies the reboot.
|
||||||
|
rem Requires tools\.venv-ble (created automatically on first run).
|
||||||
|
rem ============================================================
|
||||||
|
setlocal
|
||||||
|
set TOOLS=%~dp0
|
||||||
|
set PYEXE=%TOOLS%.venv-ble\Scripts\python.exe
|
||||||
|
|
||||||
|
if not exist "%PYEXE%" (
|
||||||
|
echo [setup] creating venv %TOOLS%.venv-ble ...
|
||||||
|
set PYREAL=
|
||||||
|
if exist "%LOCALAPPDATA%\Programs\Python\Python312\python.exe" set PYREAL="%LOCALAPPDATA%\Programs\Python\Python312\python.exe"
|
||||||
|
if not defined PYREAL (
|
||||||
|
py -3 --version >nul 2>&1 && set PYREAL=py -3
|
||||||
|
)
|
||||||
|
if not defined PYREAL set PYREAL=python
|
||||||
|
%PYREAL% -m venv "%TOOLS%.venv-ble" || goto :fail
|
||||||
|
"%PYEXE%" -m pip install --quiet bleak || goto :fail
|
||||||
|
)
|
||||||
|
|
||||||
|
"%PYEXE%" "%TOOLS%ble_ota_update.py" %1
|
||||||
|
goto :eof
|
||||||
|
|
||||||
|
:fail
|
||||||
|
echo.
|
||||||
|
echo *** setup failed - check python installation ***
|
||||||
|
exit /b 1
|
||||||
241
tools/ble_ota_update.py
Normal file
241
tools/ble_ota_update.py
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
ble_ota_update.py - PC-side BLE OTA updater for CAIIC-MCM devices.
|
||||||
|
|
||||||
|
Takes the combined OTA package (mothercup_ble_ota.bin: 52-byte header + both
|
||||||
|
bank-linked payloads, see tools/merge_image.py), reads the device's current
|
||||||
|
bank from the read-only info characteristic ...e0004 (info item 0x07
|
||||||
|
CUR_BANK), and downloads the payload linked for the OPPOSITE bank over the
|
||||||
|
framed protocol downlink (characteristic ...e0001).
|
||||||
|
|
||||||
|
usage: ble_ota.bat [combo_pkg]
|
||||||
|
default pkg: out/mothercup_ble_ota.bin
|
||||||
|
|
||||||
|
Flow-control note: the notify uplink is currently broken (dev log section
|
||||||
|
28), so OTA_RSP acks cannot be received. The script therefore paces writes:
|
||||||
|
a short gap per frame and a longer gap at every 4KB sector boundary (the
|
||||||
|
device erases sectors lazily with interrupts off - writes during the erase
|
||||||
|
window would be lost). Success is detected by the device resetting after
|
||||||
|
OTA_END (link drops), then re-checking CUR_BANK/version after reconnect.
|
||||||
|
The firmware independently rejects a payload linked for the wrong bank
|
||||||
|
(OTA_RSP status 6, no switch), so a wrong pick never bricks the device.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import os
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
import zlib
|
||||||
|
|
||||||
|
from bleak import BleakClient, BleakScanner
|
||||||
|
|
||||||
|
NAME_PREFIX = "CAIIC-MCM-20260902"
|
||||||
|
WRITE_UUID = "00002760-08c2-11e1-9073-0e8ac72e0001" # Write Without Response
|
||||||
|
INFO_RD_UUID = "00002760-08c2-11e1-9073-0e8ac72e0004" # Read-only info TLV
|
||||||
|
|
||||||
|
TYPE_OTA_BEGIN = 0x10
|
||||||
|
TYPE_OTA_DATA = 0x11
|
||||||
|
TYPE_OTA_END = 0x12
|
||||||
|
|
||||||
|
COMBO_MAGIC = 0xCA10BA11
|
||||||
|
COMBO_HDR_LEN = 52
|
||||||
|
|
||||||
|
FRAME_GAP_S = 0.008 # between WWR frames
|
||||||
|
SECTOR_GAP_S = 0.25 # at 4KB boundaries (lazy sector erase, IRQs off)
|
||||||
|
REBOOT_WAIT_S = 20.0
|
||||||
|
SECTOR = 0x1000
|
||||||
|
|
||||||
|
|
||||||
|
def crc32(data):
|
||||||
|
return zlib.crc32(data) & 0xFFFFFFFF
|
||||||
|
|
||||||
|
|
||||||
|
def crc16_ccitt(data):
|
||||||
|
crc = 0xFFFF
|
||||||
|
for b in data:
|
||||||
|
crc ^= b << 8
|
||||||
|
for _ in range(8):
|
||||||
|
crc = ((crc << 1) ^ 0x1021) & 0xFFFF if crc & 0x8000 else (crc << 1) & 0xFFFF
|
||||||
|
return crc
|
||||||
|
|
||||||
|
|
||||||
|
_seq = [0]
|
||||||
|
|
||||||
|
|
||||||
|
def encode_frame(ftype, payload):
|
||||||
|
out = bytearray([0xCA, ftype & 0xFF, _seq[0] & 0xFF,
|
||||||
|
len(payload) & 0xFF, (len(payload) >> 8) & 0xFF])
|
||||||
|
out += bytes(payload)
|
||||||
|
crc = crc16_ccitt(out[1:])
|
||||||
|
out += bytes([crc & 0xFF, (crc >> 8) & 0xFF])
|
||||||
|
_seq[0] = (_seq[0] + 1) & 0xFF
|
||||||
|
return bytes(out)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_combo(path):
|
||||||
|
"""Parse the combined OTA package; returns (version, {bank: payload}).
|
||||||
|
|
||||||
|
Header (52B LE): magic | hdr_len | version | total_size | payload_crc |
|
||||||
|
count(=2) | b1_off/size/crc | b2_off/size/crc | hdr_crc."""
|
||||||
|
data = open(path, "rb").read()
|
||||||
|
if len(data) < COMBO_HDR_LEN:
|
||||||
|
raise SystemExit("bad package: too small")
|
||||||
|
(magic, hdr_len, version, total_size, payload_crc, count,
|
||||||
|
b1o, b1s, b1c, b2o, b2s, b2c, hcrc) = \
|
||||||
|
struct.unpack_from("<IIIIIIIIIIIII", data, 0)
|
||||||
|
if magic != COMBO_MAGIC or count != 2 or hdr_len != COMBO_HDR_LEN:
|
||||||
|
raise SystemExit("bad package: magic/hdr_len/count mismatch")
|
||||||
|
if crc32(data[:48]) != hcrc:
|
||||||
|
raise SystemExit("bad package: header crc mismatch")
|
||||||
|
if len(data) != total_size:
|
||||||
|
raise SystemExit("bad package: file size %d != header total_size %d"
|
||||||
|
% (len(data), total_size))
|
||||||
|
if crc32(data[hdr_len:]) != payload_crc:
|
||||||
|
raise SystemExit("bad package: payload crc mismatch")
|
||||||
|
banks = {}
|
||||||
|
for bank, off, size, crc in ((1, b1o, b1s, b1c), (2, b2o, b2s, b2c)):
|
||||||
|
blob = data[off:off + size]
|
||||||
|
if len(blob) != size or crc32(blob) != crc:
|
||||||
|
raise SystemExit("bad package: bank%d payload crc mismatch" % bank)
|
||||||
|
banks[bank] = blob
|
||||||
|
return version, banks
|
||||||
|
|
||||||
|
|
||||||
|
async def read_info_tlv(client):
|
||||||
|
"""Read ...e0004 and decode the TLV into {item_id: raw_bytes}."""
|
||||||
|
data = bytes(await client.read_gatt_char(INFO_RD_UUID))
|
||||||
|
items = {}
|
||||||
|
i = 0
|
||||||
|
while i + 2 <= len(data):
|
||||||
|
iid, ilen = data[i], data[i + 1]
|
||||||
|
if i + 2 + ilen > len(data):
|
||||||
|
break
|
||||||
|
items[iid] = data[i + 2:i + 2 + ilen]
|
||||||
|
i += 2 + ilen
|
||||||
|
return items
|
||||||
|
|
||||||
|
|
||||||
|
def fmt_ver(v):
|
||||||
|
return "V%d.%02d.%02d" % (v >> 16, (v >> 8) & 0xFF, v & 0xFF)
|
||||||
|
|
||||||
|
|
||||||
|
async def find_device():
|
||||||
|
print("scanning for %s* ..." % NAME_PREFIX)
|
||||||
|
while True:
|
||||||
|
dev = await BleakScanner.find_device_by_filter(
|
||||||
|
lambda d, ad: d.name and d.name.startswith(NAME_PREFIX),
|
||||||
|
timeout=10.0)
|
||||||
|
if dev is not None:
|
||||||
|
return dev
|
||||||
|
print(" not found, retrying (device advertising?)")
|
||||||
|
|
||||||
|
|
||||||
|
async def ota_session(pkg_path):
|
||||||
|
version, banks = parse_combo(pkg_path)
|
||||||
|
print("package: version %s, bank1 %dB / bank2 %dB"
|
||||||
|
% (fmt_ver(version), len(banks[1]), len(banks[2])))
|
||||||
|
|
||||||
|
dev = await find_device()
|
||||||
|
print("connecting %s (%s) ..." % (dev.name, dev.address))
|
||||||
|
|
||||||
|
disconnected = asyncio.Event()
|
||||||
|
|
||||||
|
def on_disconnect(_c):
|
||||||
|
disconnected.set()
|
||||||
|
|
||||||
|
async with BleakClient(dev, disconnected_callback=on_disconnect) as client:
|
||||||
|
print("connected, mtu=%d" % client.mtu_size)
|
||||||
|
await asyncio.sleep(0.5) # let the device's MTU exchange finish
|
||||||
|
|
||||||
|
items = await read_info_tlv(client)
|
||||||
|
cur_bank = items.get(0x07, b"\x01")[0]
|
||||||
|
cur_ver = int.from_bytes(items.get(0x01, b"\x00" * 4), "little")
|
||||||
|
print("device: running APP%d, firmware %s" % (cur_bank, fmt_ver(cur_ver)))
|
||||||
|
|
||||||
|
target = 3 - cur_bank # OTA always writes the inactive bank
|
||||||
|
blob = banks[target]
|
||||||
|
print("target bank: APP%d (%d bytes, crc32=0x%08X)"
|
||||||
|
% (target, len(blob), crc32(blob)))
|
||||||
|
if cur_ver == version:
|
||||||
|
print("note: same version already on the device, updating anyway")
|
||||||
|
|
||||||
|
max_data = min(client.mtu_size - 3 - 4 - 7, 233) # offset u32 + frame overhead
|
||||||
|
disconnected.clear()
|
||||||
|
|
||||||
|
async def send(ftype, payload):
|
||||||
|
await client.write_gatt_char(WRITE_UUID, encode_frame(ftype, payload),
|
||||||
|
response=False)
|
||||||
|
await asyncio.sleep(FRAME_GAP_S)
|
||||||
|
|
||||||
|
for attempt in (1, 2):
|
||||||
|
sector_gap = SECTOR_GAP_S * attempt
|
||||||
|
print("OTA_BEGIN ... (attempt %d)" % attempt)
|
||||||
|
await send(TYPE_OTA_BEGIN, struct.pack("<III", len(blob), crc32(blob), version))
|
||||||
|
|
||||||
|
sent = 0
|
||||||
|
t0 = asyncio.get_event_loop().time()
|
||||||
|
while sent < len(blob):
|
||||||
|
first_of_sector = (sent % SECTOR) == 0
|
||||||
|
n = min(max_data, len(blob) - sent, SECTOR - (sent % SECTOR))
|
||||||
|
await send(TYPE_OTA_DATA, struct.pack("<I", sent) + blob[sent:sent + n])
|
||||||
|
sent += n
|
||||||
|
if sent % SECTOR == 0 or sent == len(blob):
|
||||||
|
print(" %d / %d bytes (%.0f%%)"
|
||||||
|
% (sent, len(blob), 100.0 * sent / len(blob)))
|
||||||
|
# the first frame touching a NEW sector triggers its lazy
|
||||||
|
# erase (IRQs off, tens of ms) - frames sent during the erase
|
||||||
|
# are lost, so wait right after that first frame
|
||||||
|
if first_of_sector and sent < len(blob):
|
||||||
|
await asyncio.sleep(sector_gap)
|
||||||
|
|
||||||
|
print("OTA_END (crc32=0x%08X), waiting for device reboot ..."
|
||||||
|
% crc32(blob))
|
||||||
|
await send(TYPE_OTA_END, struct.pack("<I", crc32(blob)))
|
||||||
|
|
||||||
|
try:
|
||||||
|
await asyncio.wait_for(disconnected.wait(), REBOOT_WAIT_S)
|
||||||
|
break
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
if attempt == 2:
|
||||||
|
print("FAIL: device did not reboot - OTA rejected "
|
||||||
|
"(crc/bank mismatch?). Check UART with 'blelog on'.")
|
||||||
|
return 1
|
||||||
|
print(" no reboot; retrying the whole image "
|
||||||
|
"(frames were probably lost in an erase window)")
|
||||||
|
else:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
dt = asyncio.get_event_loop().time() - t0
|
||||||
|
print("device rebooted (transfer %.1fs). verifying new bank ..." % dt)
|
||||||
|
|
||||||
|
dev = await find_device()
|
||||||
|
async with BleakClient(dev) as client:
|
||||||
|
await asyncio.sleep(0.5)
|
||||||
|
items = await read_info_tlv(client)
|
||||||
|
new_bank = items.get(0x07, b"\x00")[0]
|
||||||
|
new_ver = int.from_bytes(items.get(0x01, b"\x00" * 4), "little")
|
||||||
|
|
||||||
|
if new_bank == target and new_ver == version:
|
||||||
|
print("PASS: now running APP%d, firmware %s" % (new_bank, fmt_ver(new_ver)))
|
||||||
|
return 0
|
||||||
|
print("FAIL: after reboot running APP%d, firmware %s (expected APP%d, %s)"
|
||||||
|
% (new_bank, fmt_ver(new_ver), target, fmt_ver(version)))
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
root = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
pkg = sys.argv[1] if len(sys.argv) > 1 else os.path.join(
|
||||||
|
root, "out", "mothercup_ble_ota.bin")
|
||||||
|
if not os.path.isfile(pkg):
|
||||||
|
print("package not found: %s (run tools\\make_package.bat first)" % pkg)
|
||||||
|
return 1
|
||||||
|
return asyncio.run(ota_session(pkg))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
sys.exit(main())
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
pass
|
||||||
@ -2,7 +2,7 @@
|
|||||||
rem ============================================================
|
rem ============================================================
|
||||||
rem flash_package.bat [image] - erase the chip and program the
|
rem flash_package.bat [image] - erase the chip and program the
|
||||||
rem merged package via NS-LINK (NSpyocd).
|
rem merged package via NS-LINK (NSpyocd).
|
||||||
rem [image] optional, default: tools\out\caiic_full.hex
|
rem [image] optional, default: tools\out\mothercup_ble_prod.hex
|
||||||
rem Connect NS-LINK to SWD (PA4/PA5) and the reset pin first,
|
rem Connect NS-LINK to SWD (PA4/PA5) and the reset pin first,
|
||||||
rem and CLOSE Keil (it holds the probe).
|
rem and CLOSE Keil (it holds the probe).
|
||||||
rem ============================================================
|
rem ============================================================
|
||||||
@ -15,7 +15,7 @@ rem "n32wb031keq6_2" maps the full 512KB of the KEQ6-2 we actually use.
|
|||||||
set PACK="%ROOT%\nations-tec\N32WB03x_DFP.1.4.0.pack"
|
set PACK="%ROOT%\nations-tec\N32WB03x_DFP.1.4.0.pack"
|
||||||
set TARGET=n32wb031keq6_2
|
set TARGET=n32wb031keq6_2
|
||||||
set IMAGE=%~1
|
set IMAGE=%~1
|
||||||
if "%IMAGE%"=="" set IMAGE=out\caiic_full.hex
|
if "%IMAGE%"=="" set IMAGE=out\mothercup_ble_prod.hex
|
||||||
if not "%IMAGE:~0,1%"=="\" if not "%IMAGE:~1,1%"==":" set IMAGE=%~dp0%IMAGE%
|
if not "%IMAGE:~0,1%"=="\" if not "%IMAGE:~1,1%"==":" set IMAGE=%~dp0%IMAGE%
|
||||||
|
|
||||||
if not exist "%IMAGE%" (
|
if not exist "%IMAGE%" (
|
||||||
|
|||||||
@ -1,14 +1,16 @@
|
|||||||
@echo off
|
@echo off
|
||||||
rem ============================================================
|
rem ============================================================
|
||||||
rem make_package.bat - build bootloader + APP, then merge into
|
rem make_package.bat - build bootloader + APP1/APP2, then merge
|
||||||
rem one flash package (tools/out/caiic_ble_full.*)
|
rem into the PRODUCTION package:
|
||||||
|
rem tools/out/mothercup_ble_prod.{hex,bin} (APP1 only)
|
||||||
|
rem tools/out/mothercup_ble_ota.bin (OTA release)
|
||||||
rem Run from anywhere: tools\make_package.bat
|
rem Run from anywhere: tools\make_package.bat
|
||||||
rem ============================================================
|
rem ============================================================
|
||||||
setlocal
|
setlocal
|
||||||
set ROOT=%~dp0..
|
set ROOT=%~dp0..
|
||||||
set UV4="D:\Keil_v5\UV4\UV4.exe"
|
set UV4="D:\Keil_v5\UV4\UV4.exe"
|
||||||
|
|
||||||
echo [1/3] Building bootloader...
|
echo [1/4] Building bootloader...
|
||||||
%UV4% -r "%ROOT%\Boot\MDK-ARM\caiic_boot.uvprojx" -j0 -o "%ROOT%\Boot\MDK-ARM\build.log"
|
%UV4% -r "%ROOT%\Boot\MDK-ARM\caiic_boot.uvprojx" -j0 -o "%ROOT%\Boot\MDK-ARM\build.log"
|
||||||
if errorlevel 1 goto :fail
|
if errorlevel 1 goto :fail
|
||||||
findstr /C:"0 Error(s), 0 Warning(s)" "%ROOT%\Boot\MDK-ARM\build.log" >nul || goto :fail
|
findstr /C:"0 Error(s), 0 Warning(s)" "%ROOT%\Boot\MDK-ARM\build.log" >nul || goto :fail
|
||||||
@ -38,11 +40,12 @@ if not defined PYEXE (
|
|||||||
rem --ota-app2: emit a second OTA payload linked for the APP2 bank
|
rem --ota-app2: emit a second OTA payload linked for the APP2 bank
|
||||||
rem (OTA writes the bank opposite to the running one, so both link
|
rem (OTA writes the bank opposite to the running one, so both link
|
||||||
rem variants must ship; the client picks by info item 0x07 CUR_BANK).
|
rem variants must ship; the client picks by info item 0x07 CUR_BANK).
|
||||||
%PYEXE% "%~dp0merge_image.py" "%ROOT%\mcm-ddc-ble\MDK-ARM\bin\mcm-ddc-ble.bin" caiic_ble_full --ota-app2 "%ROOT%\mcm-ddc-ble\MDK-ARM\bin\mcm-ddc-ble-app2.bin" || goto :fail
|
%PYEXE% "%~dp0merge_image.py" "%ROOT%\mcm-ddc-ble\MDK-ARM\bin\mcm-ddc-ble.bin" mothercup_ble_prod --ota-app2 "%ROOT%\mcm-ddc-ble\MDK-ARM\bin\mcm-ddc-ble-app2.bin" --combo-name mothercup_ble_ota || goto :fail
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo Package ready: tools\out\caiic_ble_full.hex / caiic_ble_full.bin
|
echo Package ready: tools\out\mothercup_ble_prod.hex / mothercup_ble_prod.bin
|
||||||
echo OTA payloads: caiic_ble_full_ota.bin (bank1) / caiic_ble_full_ota_app2.bin (bank2)
|
echo OTA payloads: mothercup_ble_prod_ota.bin (bank1) / mothercup_ble_prod_ota_app2.bin (bank2)
|
||||||
|
echo OTA release: mothercup_ble_ota.bin (single file, header carries version/size/CRC)
|
||||||
goto :eof
|
goto :eof
|
||||||
|
|
||||||
:fail
|
:fail
|
||||||
|
|||||||
@ -36,12 +36,14 @@ Outputs (written to tools/out/):
|
|||||||
|
|
||||||
Usage: python tools/merge_image.py [app_bin] [out_name] [version]
|
Usage: python tools/merge_image.py [app_bin] [out_name] [version]
|
||||||
[--app2 app2_bin [--app2-version N]] [--with-appdata]
|
[--app2 app2_bin [--app2-version N]] [--with-appdata]
|
||||||
[--ota-app2 app2_linked_bin]
|
[--ota-app2 app2_linked_bin] [--combo-name name]
|
||||||
Defaults: app_bin = mcm-ddc-04/MDK-ARM/bin/embeddedSrc.bin, out_name = caiic_full,
|
Defaults: app_bin = mcm-ddc-04/MDK-ARM/bin/embeddedSrc.bin, out_name = caiic_full,
|
||||||
version = 0
|
version = 0
|
||||||
--app2 merges the APP2-linked image into the package; --ota-app2 only emits
|
--app2 merges the APP2-linked image into the package; --ota-app2 only emits
|
||||||
an extra OTA payload <name>_ota_app2.bin/.json (target_bank=2) without
|
an extra OTA payload <name>_ota_app2.bin/.json (target_bank=2) without
|
||||||
merging. OTA manifests carry "target_bank" - the client must pick the payload
|
merging. Both payloads also produce the combined single-file release
|
||||||
|
(<combo-name>.bin, default <name>_ota_dual.bin): 52B header carrying
|
||||||
|
version/total size/total CRC + per-bank entries. The client picks the payload
|
||||||
matching the bank the device is NOT running (info item 0x07 CUR_BANK).
|
matching the bank the device is NOT running (info item 0x07 CUR_BANK).
|
||||||
Run from anywhere; paths are resolved relative to this script.
|
Run from anywhere; paths are resolved relative to this script.
|
||||||
"""
|
"""
|
||||||
@ -75,6 +77,14 @@ OUT_DIR = "out"
|
|||||||
|
|
||||||
HEX_REC_LEN = 16
|
HEX_REC_LEN = 16
|
||||||
|
|
||||||
|
# Combined OTA package (release name: mothercup_ble_ota.bin): 52-byte header
|
||||||
|
# + both bank-linked payloads. The header carries everything the old sidecar
|
||||||
|
# .json had (version / total size / total CRC), so a single file is released.
|
||||||
|
# Parsed by tools/ble_ota_update.py, which picks the payload for the bank the
|
||||||
|
# device is NOT running (info item 0x07 CUR_BANK).
|
||||||
|
OTA_COMBO_MAGIC = 0xCA10BA11
|
||||||
|
OTA_COMBO_HDR_LEN = 52
|
||||||
|
|
||||||
|
|
||||||
def crc32(data):
|
def crc32(data):
|
||||||
"""IEEE CRC32 - same value as Boot/src/boot_crc32.c caiic_crc32()."""
|
"""IEEE CRC32 - same value as Boot/src/boot_crc32.c caiic_crc32()."""
|
||||||
@ -95,6 +105,33 @@ def default_bootsetting(app_blob, app2_blob=None, version=0, app2_version=0):
|
|||||||
return body + struct.pack("<I", crc32(body))
|
return body + struct.pack("<I", crc32(body))
|
||||||
|
|
||||||
|
|
||||||
|
def combo_ota_package(b1_blob, b2_blob, version):
|
||||||
|
"""Combined OTA package: 52-byte LE header + bank1 payload + bank2 payload.
|
||||||
|
|
||||||
|
Header (docs/ble_protocol.md section 7):
|
||||||
|
0 magic u32 = 0xCA10BA11
|
||||||
|
4 hdr_len u32 = 52
|
||||||
|
8 version u32 (APP_FW_VERSION_NUM)
|
||||||
|
12 total_size u32 (whole file)
|
||||||
|
16 payload_crc u32 (CRC32 over [hdr_len, EOF))
|
||||||
|
20 count u32 = 2
|
||||||
|
24 b1_off/size/crc u32 x3
|
||||||
|
36 b2_off/size/crc u32 x3
|
||||||
|
48 hdr_crc u32 (CRC32 over bytes 0..47)"""
|
||||||
|
b1_off = OTA_COMBO_HDR_LEN
|
||||||
|
b2_off = b1_off + len(b1_blob)
|
||||||
|
payload = b1_blob + b2_blob
|
||||||
|
total = OTA_COMBO_HDR_LEN + len(payload)
|
||||||
|
hdr = struct.pack(
|
||||||
|
"<IIIIIIIIIIII",
|
||||||
|
OTA_COMBO_MAGIC, OTA_COMBO_HDR_LEN, version,
|
||||||
|
total, crc32(payload), 2,
|
||||||
|
b1_off, len(b1_blob), crc32(b1_blob),
|
||||||
|
b2_off, len(b2_blob), crc32(b2_blob),
|
||||||
|
)
|
||||||
|
return hdr + struct.pack("<I", crc32(hdr)) + payload
|
||||||
|
|
||||||
|
|
||||||
def default_appdata():
|
def default_appdata():
|
||||||
"""Build the 52-byte default APP_DATA parameter record
|
"""Build the 52-byte default APP_DATA parameter record
|
||||||
(caiic_params_t: magic/layout_ver/led/flags/pwm/reserved[8]/crc32)."""
|
(caiic_params_t: magic/layout_ver/led/flags/pwm/reserved[8]/crc32)."""
|
||||||
@ -157,6 +194,7 @@ def main():
|
|||||||
app2_rel = None
|
app2_rel = None
|
||||||
ota_app2_rel = None
|
ota_app2_rel = None
|
||||||
app2_version = None
|
app2_version = None
|
||||||
|
combo_name = None
|
||||||
with_appdata = "--with-appdata" in opts
|
with_appdata = "--with-appdata" in opts
|
||||||
if "--app2" in opts:
|
if "--app2" in opts:
|
||||||
i = opts.index("--app2")
|
i = opts.index("--app2")
|
||||||
@ -167,6 +205,9 @@ def main():
|
|||||||
if "--app2-version" in opts:
|
if "--app2-version" in opts:
|
||||||
i = opts.index("--app2-version")
|
i = opts.index("--app2-version")
|
||||||
app2_version = int(opts[i + 1], 0)
|
app2_version = int(opts[i + 1], 0)
|
||||||
|
if "--combo-name" in opts:
|
||||||
|
i = opts.index("--combo-name")
|
||||||
|
combo_name = opts[i + 1]
|
||||||
|
|
||||||
# positional args minus the values consumed by the --flags
|
# positional args minus the values consumed by the --flags
|
||||||
pos = []
|
pos = []
|
||||||
@ -175,7 +216,7 @@ def main():
|
|||||||
if skip_next:
|
if skip_next:
|
||||||
skip_next = False
|
skip_next = False
|
||||||
continue
|
continue
|
||||||
if a in ("--app2", "--app2-version", "--ota-app2"):
|
if a in ("--app2", "--app2-version", "--ota-app2", "--combo-name"):
|
||||||
skip_next = True
|
skip_next = True
|
||||||
continue
|
continue
|
||||||
if a == "--with-appdata":
|
if a == "--with-appdata":
|
||||||
@ -264,6 +305,7 @@ def main():
|
|||||||
|
|
||||||
# second OTA payload linked for the APP2 bank (when built)
|
# second OTA payload linked for the APP2 bank (when built)
|
||||||
ota_app2_bin_path = None
|
ota_app2_bin_path = None
|
||||||
|
combo_path = None
|
||||||
if ota_app2_blob:
|
if ota_app2_blob:
|
||||||
ota_app2_bin_path = os.path.join(out_dir, out_name + "_ota_app2.bin")
|
ota_app2_bin_path = os.path.join(out_dir, out_name + "_ota_app2.bin")
|
||||||
with open(ota_app2_bin_path, "wb") as f:
|
with open(ota_app2_bin_path, "wb") as f:
|
||||||
@ -277,6 +319,13 @@ def main():
|
|||||||
"version": version,
|
"version": version,
|
||||||
}, f, indent=2)
|
}, f, indent=2)
|
||||||
|
|
||||||
|
# combined single-file OTA package (52B header + both payloads;
|
||||||
|
# header carries version/size/CRCs - no sidecar .json needed)
|
||||||
|
combo = combo_ota_package(app_blob, ota_app2_blob, version)
|
||||||
|
combo_path = os.path.join(out_dir, (combo_name or (out_name + "_ota_dual")) + ".bin")
|
||||||
|
with open(combo_path, "wb") as f:
|
||||||
|
f.write(combo)
|
||||||
|
|
||||||
print("")
|
print("")
|
||||||
print("package written:")
|
print("package written:")
|
||||||
print(" %s" % hex_path)
|
print(" %s" % hex_path)
|
||||||
@ -287,6 +336,7 @@ def main():
|
|||||||
if ota_app2_bin_path:
|
if ota_app2_bin_path:
|
||||||
print(" %s (%d bytes, crc32=0x%08X, target bank2)"
|
print(" %s (%d bytes, crc32=0x%08X, target bank2)"
|
||||||
% (ota_app2_bin_path, len(ota_app2_blob), crc32(ota_app2_blob)))
|
% (ota_app2_bin_path, len(ota_app2_blob), crc32(ota_app2_blob)))
|
||||||
|
print(" %s (combined OTA package, 52B header+both payloads)" % combo_path)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@ -125,8 +125,8 @@
|
|||||||
:1007B000096A012211430322920611627047000068
|
:1007B000096A012211430322920611627047000068
|
||||||
:1007C000D00700010040002038080000D4040001D8
|
:1007C000D00700010040002038080000D4040001D8
|
||||||
:1040000011C011CA0100000000800001BCD30000F3
|
:1040000011C011CA0100000000800001BCD30000F3
|
||||||
:1040100053A0D5081100010000400201E8D40000BF
|
:104010007B5AA0F01200010000400201E8D4000029
|
||||||
:0C402000CBA8292211000100571C042B22
|
:0C402000E3525CDA12000100F374300C73
|
||||||
:106000007ADA12CA01000000F4010000000000006A
|
:106000007ADA12CA01000000F4010000000000006A
|
||||||
:106010000000000000000000000000000000000080
|
:106010000000000000000000000000000000000080
|
||||||
:106020000000000000000000000000000000000070
|
:106020000000000000000000000000000000000070
|
||||||
@ -770,7 +770,7 @@
|
|||||||
:10A7C00034A003F025FA03E029463AA003F0BAF9D1
|
:10A7C00034A003F025FA03E029463AA003F0BAF9D1
|
||||||
:10A7D00009F08CF87D21C900FDF7D4FC014639A0B1
|
:10A7D00009F08CF87D21C900FDF7D4FC014639A0B1
|
||||||
:10A7E00003F0B0F908F07CFC01463AA003F0AAF9A6
|
:10A7E00003F0B0F908F07CFC01463AA003F0AAF9A6
|
||||||
:10A7F000F8BD00001100010056312E30302E3137E7
|
:10A7F000F8BD00001200010056312E30302E3138E5
|
||||||
:10A80000000000006669726D776172653A202573F9
|
:10A80000000000006669726D776172653A202573F9
|
||||||
:10A81000202830782530386C58290D0A00000000B7
|
:10A81000202830782530386C58290D0A00000000B7
|
||||||
:10A820006375722062616E6B3A2041505025750D40
|
:10A820006375722062616E6B3A2041505025750D40
|
||||||
@ -855,7 +855,7 @@
|
|||||||
:10AD10002C20727820717565756520666C75736876
|
:10AD10002C20727820717565756520666C75736876
|
||||||
:10AD200065640D0A0000000010B506A108A002F03D
|
:10AD200065640D0A0000000010B506A108A002F03D
|
||||||
:10AD300009FF0DA002F06CFF1948016819A002F08C
|
:10AD300009FF0DA002F06CFF1948016819A002F08C
|
||||||
:10AD400001FF10BD56312E30302E3137000000008B
|
:10AD400001FF10BD56312E30302E3138000000008A
|
||||||
:10AD50006669726D776172652076657273696F6E70
|
:10AD50006669726D776172652076657273696F6E70
|
||||||
:10AD60003A2025730D0A00006D636D2D6464632D18
|
:10AD60003A2025730D0A00006D636D2D6464632D18
|
||||||
:10AD7000626C653A20424C452872647473732920D2
|
:10AD7000626C653A20424C452872647473732920D2
|
||||||
@ -2021,7 +2021,7 @@
|
|||||||
:10F5F0001049884201D1022000E0012069460874C8
|
:10F5F0001049884201D1022000E0012069460874C8
|
||||||
:10F600000120009004AB22460799069800F014F8F8
|
:10F600000120009004AB22460799069800F014F8F8
|
||||||
:10F6100009B0F0BD079809B0F0BD0000FFFF000081
|
:10F6100009B0F0BD079809B0F0BD0000FFFF000081
|
||||||
:10F62000110001000008024084470020FF7F000015
|
:10F62000120001000008024084470020FF7F000014
|
||||||
:10F63000000020410040020130B4029C42540546C3
|
:10F63000000020410040020130B4029C42540546C3
|
||||||
:10F64000491C88B22C54401C002180B2002C07D9E0
|
:10F64000491C88B22C54401C002180B2002C07D9E0
|
||||||
:10F650005A5C2A54401C491CC9B280B2A142F7D35B
|
:10F650005A5C2A54401C491CC9B280B2A142F7D35B
|
||||||
@ -2081,7 +2081,7 @@
|
|||||||
:10F9B0003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D77
|
:10F9B0003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D77
|
||||||
:10F9C0003D0A0000206D636D2D6464632D626C65DB
|
:10F9C0003D0A0000206D636D2D6464632D626C65DB
|
||||||
:10F9D0003A20424C45202B204672656552544F53C5
|
:10F9D0003A20424C45202B204672656552544F53C5
|
||||||
:10F9E000202B20434C490A0056312E30302E31371F
|
:10F9E000202B20434C490A0056312E30302E31381E
|
||||||
:10F9F00000000000204669726D77617265207665AF
|
:10F9F00000000000204669726D77617265207665AF
|
||||||
:10FA00007273696F6E2025730A00000000400020A9
|
:10FA00007273696F6E2025730A00000000400020A9
|
||||||
:10FA10002053797374656D436F7265436C6F636BCC
|
:10FA10002053797374656D436F7265436C6F636BCC
|
||||||
@ -4179,7 +4179,7 @@
|
|||||||
:1068F00025FA03E029463AA003F0BAF909F08CF82A
|
:1068F00025FA03E029463AA003F0BAF909F08CF82A
|
||||||
:106900007D21C900FDF73EFC014639A003F0B0F936
|
:106900007D21C900FDF73EFC014639A003F0B0F936
|
||||||
:1069100008F07CFC01463AA003F0AAF9F8BD00009B
|
:1069100008F07CFC01463AA003F0AAF9F8BD00009B
|
||||||
:106920001100010056312E30302E313700000000AA
|
:106920001200010056312E30302E313800000000A8
|
||||||
:106930006669726D776172653A2025732028307818
|
:106930006669726D776172653A2025732028307818
|
||||||
:106940002530386C58290D0A00000000637572204C
|
:106940002530386C58290D0A00000000637572204C
|
||||||
:1069500062616E6B3A2041505025750D0A000000AF
|
:1069500062616E6B3A2041505025750D0A000000AF
|
||||||
@ -4264,7 +4264,7 @@
|
|||||||
:106E400020717565756520666C75736865640D0ADB
|
:106E400020717565756520666C75736865640D0ADB
|
||||||
:106E50000000000010B506A108A002F009FF0DA077
|
:106E50000000000010B506A108A002F009FF0DA077
|
||||||
:106E600002F06CFF1948016819A002F001FF10BD83
|
:106E600002F06CFF1948016819A002F001FF10BD83
|
||||||
:106E700056312E30302E3137000000006669726DB9
|
:106E700056312E30302E3138000000006669726DB8
|
||||||
:106E8000776172652076657273696F6E3A2025733B
|
:106E8000776172652076657273696F6E3A2025733B
|
||||||
:106E90000D0A00006D636D2D6464632D626C653AAC
|
:106E90000D0A00006D636D2D6464632D626C653AAC
|
||||||
:106EA00020424C4528726474737329202B2046724B
|
:106EA00020424C4528726474737329202B2046724B
|
||||||
@ -5429,7 +5429,7 @@
|
|||||||
:10B7100029F809B0F0BD13E0FDF77EFB104988421F
|
:10B7100029F809B0F0BD13E0FDF77EFB104988421F
|
||||||
:10B7200001D1022000E00120694608740120009048
|
:10B7200001D1022000E00120694608740120009048
|
||||||
:10B7300004AB22460799069800F014F809B0F0BD52
|
:10B7300004AB22460799069800F014F809B0F0BD52
|
||||||
:10B74000079809B0F0BD0000FFFF000011000100E4
|
:10B74000079809B0F0BD0000FFFF000012000100E3
|
||||||
:10B750000008024084470020FF7F000000002041D5
|
:10B750000008024084470020FF7F000000002041D5
|
||||||
:10B760000040020130B4029C42540546491C88B294
|
:10B760000040020130B4029C42540546491C88B294
|
||||||
:10B770002C54401C002180B2002C07D95A5C2A545A
|
:10B770002C54401C002180B2002C07D95A5C2A545A
|
||||||
@ -5490,7 +5490,7 @@
|
|||||||
:10BAE0003D3D3D3D3D3D3D3D3D3D3D3D3D0A000033
|
:10BAE0003D3D3D3D3D3D3D3D3D3D3D3D3D0A000033
|
||||||
:10BAF000206D636D2D6464632D626C653A20424C49
|
:10BAF000206D636D2D6464632D626C653A20424C49
|
||||||
:10BB000045202B204672656552544F53202B20430D
|
:10BB000045202B204672656552544F53202B20430D
|
||||||
:10BB10004C490A0056312E30302E313700000000DB
|
:10BB10004C490A0056312E30302E313800000000DA
|
||||||
:10BB2000204669726D776172652076657273696F00
|
:10BB2000204669726D776172652076657273696F00
|
||||||
:10BB30006E2025730A000000004000202053797316
|
:10BB30006E2025730A000000004000202053797316
|
||||||
:10BB400074656D436F7265436C6F636B203D202598
|
:10BB400074656D436F7265436C6F636B203D202598
|
||||||
|
|||||||
Binary file not shown.
@ -2,6 +2,6 @@
|
|||||||
"file": "caiic_ble_dual_ota.bin",
|
"file": "caiic_ble_dual_ota.bin",
|
||||||
"target_bank": 1,
|
"target_bank": 1,
|
||||||
"size": 54204,
|
"size": 54204,
|
||||||
"crc32": "0x08D5A053",
|
"crc32": "0xF0A05A7B",
|
||||||
"version": 65553
|
"version": 65554
|
||||||
}
|
}
|
||||||
Binary file not shown.
@ -2,6 +2,6 @@
|
|||||||
"file": "caiic_ble_dual_ota_app2.bin",
|
"file": "caiic_ble_dual_ota_app2.bin",
|
||||||
"target_bank": 2,
|
"target_bank": 2,
|
||||||
"size": 54504,
|
"size": 54504,
|
||||||
"crc32": "0x2229A8CB",
|
"crc32": "0xDA5C52E3",
|
||||||
"version": 65553
|
"version": 65554
|
||||||
}
|
}
|
||||||
BIN
tools/out/caiic_ble_dual_ota_dual.bin
Normal file
BIN
tools/out/caiic_ble_dual_ota_dual.bin
Normal file
Binary file not shown.
@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"file": "caiic_ble_full_ota.bin",
|
|
||||||
"target_bank": 1,
|
|
||||||
"size": 54204,
|
|
||||||
"crc32": "0x08D5A053",
|
|
||||||
"version": 65553
|
|
||||||
}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"file": "caiic_ble_full_ota_app2.bin",
|
|
||||||
"target_bank": 2,
|
|
||||||
"size": 54504,
|
|
||||||
"crc32": "0x2229A8CB",
|
|
||||||
"version": 65553
|
|
||||||
}
|
|
||||||
BIN
tools/out/mothercup_ble_ota.bin
Normal file
BIN
tools/out/mothercup_ble_ota.bin
Normal file
Binary file not shown.
Binary file not shown.
@ -125,8 +125,8 @@
|
|||||||
:1007B000096A012211430322920611627047000068
|
:1007B000096A012211430322920611627047000068
|
||||||
:1007C000D00700010040002038080000D4040001D8
|
:1007C000D00700010040002038080000D4040001D8
|
||||||
:1040000011C011CA0100000000800001BCD30000F3
|
:1040000011C011CA0100000000800001BCD30000F3
|
||||||
:1040100053A0D508110001000000000000000000BE
|
:104010007B5AA0F012000100000000000000000028
|
||||||
:0C4020000000000000000000647B8C1514
|
:0C4020000000000000000000B4273BE995
|
||||||
:10800000D0B70020698100017181000141B00001F9
|
:10800000D0B70020698100017181000141B00001F9
|
||||||
:108010000000000000000000000000000000000060
|
:108010000000000000000000000000000000000060
|
||||||
:1080200000000000000000000000000005B4000196
|
:1080200000000000000000000000000005B4000196
|
||||||
@ -766,7 +766,7 @@
|
|||||||
:10A7C00034A003F025FA03E029463AA003F0BAF9D1
|
:10A7C00034A003F025FA03E029463AA003F0BAF9D1
|
||||||
:10A7D00009F08CF87D21C900FDF7D4FC014639A0B1
|
:10A7D00009F08CF87D21C900FDF7D4FC014639A0B1
|
||||||
:10A7E00003F0B0F908F07CFC01463AA003F0AAF9A6
|
:10A7E00003F0B0F908F07CFC01463AA003F0AAF9A6
|
||||||
:10A7F000F8BD00001100010056312E30302E3137E7
|
:10A7F000F8BD00001200010056312E30302E3138E5
|
||||||
:10A80000000000006669726D776172653A202573F9
|
:10A80000000000006669726D776172653A202573F9
|
||||||
:10A81000202830782530386C58290D0A00000000B7
|
:10A81000202830782530386C58290D0A00000000B7
|
||||||
:10A820006375722062616E6B3A2041505025750D40
|
:10A820006375722062616E6B3A2041505025750D40
|
||||||
@ -851,7 +851,7 @@
|
|||||||
:10AD10002C20727820717565756520666C75736876
|
:10AD10002C20727820717565756520666C75736876
|
||||||
:10AD200065640D0A0000000010B506A108A002F03D
|
:10AD200065640D0A0000000010B506A108A002F03D
|
||||||
:10AD300009FF0DA002F06CFF1948016819A002F08C
|
:10AD300009FF0DA002F06CFF1948016819A002F08C
|
||||||
:10AD400001FF10BD56312E30302E3137000000008B
|
:10AD400001FF10BD56312E30302E3138000000008A
|
||||||
:10AD50006669726D776172652076657273696F6E70
|
:10AD50006669726D776172652076657273696F6E70
|
||||||
:10AD60003A2025730D0A00006D636D2D6464632D18
|
:10AD60003A2025730D0A00006D636D2D6464632D18
|
||||||
:10AD7000626C653A20424C452872647473732920D2
|
:10AD7000626C653A20424C452872647473732920D2
|
||||||
@ -2017,7 +2017,7 @@
|
|||||||
:10F5F0001049884201D1022000E0012069460874C8
|
:10F5F0001049884201D1022000E0012069460874C8
|
||||||
:10F600000120009004AB22460799069800F014F8F8
|
:10F600000120009004AB22460799069800F014F8F8
|
||||||
:10F6100009B0F0BD079809B0F0BD0000FFFF000081
|
:10F6100009B0F0BD079809B0F0BD0000FFFF000081
|
||||||
:10F62000110001000008024084470020FF7F000015
|
:10F62000120001000008024084470020FF7F000014
|
||||||
:10F63000000020410040020130B4029C42540546C3
|
:10F63000000020410040020130B4029C42540546C3
|
||||||
:10F64000491C88B22C54401C002180B2002C07D9E0
|
:10F64000491C88B22C54401C002180B2002C07D9E0
|
||||||
:10F650005A5C2A54401C491CC9B280B2A142F7D35B
|
:10F650005A5C2A54401C491CC9B280B2A142F7D35B
|
||||||
@ -2077,7 +2077,7 @@
|
|||||||
:10F9B0003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D77
|
:10F9B0003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D77
|
||||||
:10F9C0003D0A0000206D636D2D6464632D626C65DB
|
:10F9C0003D0A0000206D636D2D6464632D626C65DB
|
||||||
:10F9D0003A20424C45202B204672656552544F53C5
|
:10F9D0003A20424C45202B204672656552544F53C5
|
||||||
:10F9E000202B20434C490A0056312E30302E31371F
|
:10F9E000202B20434C490A0056312E30302E31381E
|
||||||
:10F9F00000000000204669726D77617265207665AF
|
:10F9F00000000000204669726D77617265207665AF
|
||||||
:10FA00007273696F6E2025730A00000000400020A9
|
:10FA00007273696F6E2025730A00000000400020A9
|
||||||
:10FA10002053797374656D436F7265436C6F636BCC
|
:10FA10002053797374656D436F7265436C6F636BCC
|
||||||
Binary file not shown.
7
tools/out/mothercup_ble_prod_ota.json
Normal file
7
tools/out/mothercup_ble_prod_ota.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"file": "mothercup_ble_prod_ota.bin",
|
||||||
|
"target_bank": 1,
|
||||||
|
"size": 54204,
|
||||||
|
"crc32": "0xF0A05A7B",
|
||||||
|
"version": 65554
|
||||||
|
}
|
||||||
Binary file not shown.
7
tools/out/mothercup_ble_prod_ota_app2.json
Normal file
7
tools/out/mothercup_ble_prod_ota_app2.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"file": "mothercup_ble_prod_ota_app2.bin",
|
||||||
|
"target_bank": 2,
|
||||||
|
"size": 54504,
|
||||||
|
"crc32": "0xDA5C52E3",
|
||||||
|
"version": 65554
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user