274 lines
12 KiB
Markdown
274 lines
12 KiB
Markdown
# Banban OTA-ready 工厂基线
|
||
|
||
## 1. 目标和边界
|
||
|
||
本基线用于尚未量产的 `EG800AKCN_11LG` 设备。目标是在不改变现有对话、音频、
|
||
MQTT、NFC、GNSS、按键、休眠和 LED 业务流程的前提下,一次性固定后续本地暂存式
|
||
OTA 所依赖的底层条件。
|
||
|
||
本基线完成:
|
||
|
||
- 将 HX_GNSS 的 `customer_fs` 从 256 KiB 扩大到 576 KiB;
|
||
- 将 `customer_app` 从 460 KiB 调整为 384 KiB;
|
||
- 将 APP 物理/XIP 地址固定为 `0x002E5000` / `0x802E5000`;
|
||
- 保留 SDK 已有的 `QUEC_APP_FULL_FOTA` 与 FULLOTA2 公共 API;
|
||
- 将现有 OTA 命令切换为最小本地暂存式 FULLOTA2;
|
||
- 为设备和构建产物加入唯一布局身份;
|
||
- 在构建前后执行 fail-closed 校验。
|
||
|
||
本基线暂不完成:
|
||
|
||
- 不增加签名 manifest、SHA-256 下载校验、断点续传或后台灰度;
|
||
- 不提供 A/B APP 分区,也不承诺自动版本回滚;
|
||
- 不在线更新 kernel、分区表或 `customer_fs`。
|
||
|
||
这版保留现有后端的 `version + url` 命令格式,只改变设备端执行方式。网络包会完整写入
|
||
`U:/FotaFile.bin`,通过 SDK FBF 校验并设置升级标志后才重启。
|
||
|
||
> 生产门禁:完成本文的真机 FULLOTA2 正向、失败注入和断电测试前,后端不得向生产设备
|
||
> 下发 OTA 命令。验收通过后可继续使用原协议下发;这条门禁针对测试状态,不再是因为
|
||
> 设备仍调用 FULLOTA1。
|
||
|
||
## 2. 固定身份与 Flash 布局
|
||
|
||
设备布局身份:
|
||
|
||
```text
|
||
eg800akcn_11lg-hxgnss-fs576-app2e5000
|
||
```
|
||
|
||
构建 profile:
|
||
|
||
```text
|
||
ota_ready_hxgnss_fs576
|
||
```
|
||
|
||
4 MiB 内部 Flash 的尾部分区固定如下:
|
||
|
||
| 分区 | 起始地址 | 结束地址 | 大小 |
|
||
| --- | ---: | ---: | ---: |
|
||
| reserved(按当前镜像估算) | `0x002D0000` | `0x002E5000` | 84 KiB |
|
||
| customer_app | `0x002E5000` | `0x00345000` | 384 KiB |
|
||
| customer_fs | `0x00345000` | `0x003D5000` | 576 KiB |
|
||
| nvm | `0x003D5000` | `0x003F5000` | 128 KiB |
|
||
| erase_rd | `0x003F5000` | `0x003F7000` | 8 KiB |
|
||
| fota_param | `0x003F7000` | `0x003FA000` | 12 KiB |
|
||
| factory_a | `0x003FA000` | `0x00400000` | 24 KiB |
|
||
|
||
`customer_app` 是单槽。FULLOTA2 能保护下载阶段:文件未下载完整或 SDK FBF 校验
|
||
失败时不会设置升级标志;但 updater 开始擦写 `customer_app` 后,没有旧 APP 槽可供回滚。
|
||
|
||
## 3. 本次修改
|
||
|
||
### 3.1 分区和链接地址
|
||
|
||
- `CRANELRH_QUEC_FLASH_LAYOUT_SS_04M_HX_GNSS.json`:当前 `CC11XXW_GPS` 构建实际选择的
|
||
分区表,`customer_app = 384KiB`、`customer_fs = 576KiB`;
|
||
- `CRANELRH_QUEC_FLASH_LAYOUT_SS_04M_OPEN.json`:同步保持 `customer_fs = 640KiB`,避免
|
||
无 GNSS variant 回退到旧布局;
|
||
- `app_linkscript.ld`:ROM 起始地址改为 `0x802E5000`,最大 ROM 大小收紧为 `0x60000`;
|
||
- `customer_fs.bin`:从原 256 KiB LittleFS 中提取全部 14 个音频文件,以 4096 字节块、
|
||
144 个块重新生成 576 KiB LittleFS;
|
||
- 新文件系统镜像 SHA-256:
|
||
`45350804d65fc6ded24caf9b215b71e89f9160d10d4998c5d57d4f4496d6000d`。
|
||
|
||
### 3.2 运行身份
|
||
|
||
`ota_baseline.h` 固定布局身份、APP/FS 地址和分区大小。应用启动时打印:
|
||
|
||
```text
|
||
[OTA-BASELINE] layout=eg800akcn_11lg-hxgnss-fs576-app2e5000 ... slot=single
|
||
[OTA-BASELINE] U: total=... free=... fota2_reserve=65536
|
||
```
|
||
|
||
该日志用于产线和联调确认设备没有混入旧的 fs256 或错误的 fs640 OPEN 基线,不改变任何业务状态。
|
||
|
||
### 3.3 构建保护
|
||
|
||
`build_rel.bat` 在构建前运行源码校验,在生成 APP 后运行容量校验。任何一项不满足都会中止:
|
||
|
||
- HX_GNSS `customer_fs` 必须为 576 KiB;
|
||
- APP 必须为 384 KiB,地址必须为 `0x002E5000`;
|
||
- LittleFS 必须为 4096 字节块、144 块且镜像哈希一致;
|
||
- 当前 kernel、DSP、RF 和 GNSS 镜像到 APP 之间必须至少保留 64 KiB;
|
||
- kernel 必须继续定义 `QUEC_APP_FULL_FOTA`;
|
||
- FULLOTA2 所需的 SDK API 必须存在;
|
||
- `app.bin + 8192` 不得超过 384 KiB。
|
||
- MQTT OTA 入口必须调用 `banban_fullfota2_start()`,不得回退到
|
||
`ql_fullfota_app_start()`。
|
||
|
||
可独立执行:
|
||
|
||
```powershell
|
||
ql-cross-tool\win32\owtoolchain\Python\python.exe tools\verify_ota_ready_baseline.py
|
||
ql-cross-tool\win32\owtoolchain\Python\python.exe tools\verify_ota_ready_baseline.py `
|
||
--app-bin ql-application\threadx\build\app.bin `
|
||
--kernel-bin ql-kernel\threadx\build\release_kernel.bin
|
||
```
|
||
|
||
### 3.4 最小 FULLOTA2 执行路径
|
||
|
||
`ota_fullfota2.c` 使用独立任务完成同步 HTTP 下载。现有 MQTT 工作线程只负责参数校验、
|
||
保存目标版本、回复 `accepted` 和启动任务,不会承担长时间网络读取。
|
||
|
||
执行顺序:
|
||
|
||
1. 删除上一次残留的 `U:/FotaFile.bin`;
|
||
2. HTTP GET 必须返回 200 和非零 `Content-Length`;
|
||
3. FBF 必须大于 8 KiB 且不超过 384 KiB;
|
||
4. `U:` 空闲空间必须不小于 `Content-Length + 64 KiB`;
|
||
5. 设置内部 Flash 固定暂存路径,初始化 FOTA context;
|
||
6. 以 4096 字节缓冲顺序读取并调用 `ql_fota_image_write()`;
|
||
7. 实际接收字节数必须严格等于 `Content-Length`;
|
||
8. 调用 `ql_fota_image_flush()`,再用 `ql_stat()` 复核落盘文件长度;
|
||
9. 调用 `ql_fota_image_verify()` 校验 FBF 并设置升级标志;
|
||
10. deinit 后重启,由 updater 写入单槽 `customer_app`。
|
||
|
||
任一步在设置升级标志前失败,都会关闭 HTTP/FOTA context、删除暂存包、撤销固定升级模式、
|
||
清除 pending 状态并把 `fota_start` 恢复为 0。旧 APP 未被擦写,可继续运行并接受下一次命令。
|
||
|
||
旧实现会在 OTA 前删除服务器管理的提示音。fs576 基线有足够空间后,这版不再主动删除
|
||
业务资源;若空间不足则明确失败,不通过牺牲业务文件强行升级。
|
||
|
||
`http_aofei.c` 中未被当前业务调用的旧 HTTP 轮询 OTA 包装函数原本仍可进入 FULLOTA1,
|
||
本基线将其显式禁用。生产固件只有 MQTT `version + url` 命令可以启动 OTA,避免两个入口
|
||
使用不同的升级语义。
|
||
|
||
## 4. 构建和生产烧录
|
||
|
||
在 Windows SDK 构建环境中执行:
|
||
|
||
```bat
|
||
build_rel.bat <生产版本号>
|
||
```
|
||
|
||
量产必须烧录该构建产生的完整 `*-fac.zip`,不能只烧 `customer_app`。完整工厂包需要同时
|
||
携带新 `partition.bin`、新 `customer_fs.bin`、11LG kernel/system 和新地址 APP。
|
||
|
||
量产前冻结并记录:
|
||
|
||
- 源码 Git commit;
|
||
- 工厂 ZIP 文件名、字节数和 SHA-256;
|
||
- `customer_fs.bin` SHA-256;
|
||
- `customer_app.bin` 字节数和 SHA-256;
|
||
- `partition.bin` 字节数和 SHA-256;
|
||
- 编译器、Aboot/arelease 和 FBFMake 版本;
|
||
- 首台、末台抽检设备串口中的 OTA baseline 日志。
|
||
|
||
不要把 `EG800AKCN_91LC` 的 `cp.bin`、工厂包或射频/GNSS 制品复制给本项目。两个项目同为
|
||
ASR1605/CRANELRH,但量产包必须由 `EG800AKCN_11LG` 配置生成。
|
||
|
||
## 5. 生产前测试
|
||
|
||
### 5.1 静态和产物测试
|
||
|
||
1. 运行 `verify_ota_ready_baseline.py`,结果必须通过。
|
||
2. 解包工厂 ZIP,确认其中 `customer_fs.bin` 为 589824 字节且哈希一致。
|
||
3. 使用 Aboot 工具检查 `partition.bin`,确认 APP/FS 地址与本文件一致。
|
||
4. 确认 `customer_app.bin + 8192 <= 393216`。
|
||
5. 确认 FBF 的目标物理地址是 `0x002E5000`,不能是旧地址 `0x00322000`、
|
||
也不能是错误基线地址 `0x002C2000`。
|
||
|
||
### 5.2 全擦工厂烧录测试
|
||
|
||
至少准备 3 台板执行完整擦除和工厂烧录:
|
||
|
||
1. 下载器无越界、校验或 partition 错误。
|
||
2. USB 重新枚举,`AT`/`ATI` 正常。
|
||
3. 串口打印正确 layout、地址和 576 KiB 文件系统容量。
|
||
4. 14 个预置音频均可读取和播放。
|
||
5. IMEI、SIM、驻网、数据连接和 GNSS 正常。
|
||
6. MQTT 注册、命令收发、心跳和状态上报正常。
|
||
7. 唤醒、对话、打断、录音、播放、音量和休眠正常。
|
||
8. NFC、按键、LED、电池检测和低电关机正常。
|
||
9. 连续冷启动、软重启和断电启动各不少于 20 次。
|
||
10. 连续运行至少 8 小时,观察 watchdog、内存、文件系统和网络重连。
|
||
|
||
### 5.3 文件系统压力测试
|
||
|
||
1. 启动后记录 `ql_fs_size('U')` 和 `ql_fs_free_size('U')`。
|
||
2. 写入一个与计划 FBF 等大的测试文件,关闭、重启并逐字节回读。
|
||
3. 删除测试文件,确认空间恢复。
|
||
4. 在写入 10%、50%、90% 时分别断电,重启后确认业务 APP 仍可运行并可清理残留文件。
|
||
5. 验证正常业务文件占用后,仍满足 `FBF size + 64 KiB` 空闲门槛。
|
||
|
||
### 5.4 最小 FULLOTA2 验收测试
|
||
|
||
正式量产前至少做一次 A 到 B 的本地暂存升级。B 可以只修改版本号:
|
||
|
||
1. 后端按现有协议下发 B 版 `version + url`;
|
||
2. 串口必须看到 HTTP 长度、下载进度、FBF verify 成功和重启日志;
|
||
3. 重启后确认 updater 安装 B,且 `U:/FotaFile.bin` 被正确处理;
|
||
4. 确认 NVM、设备身份、业务配置和 14 个预置音频未损坏;
|
||
5. 分别测试 404、无 Content-Length、空间不足、传输中断、截断 FBF、损坏 FBF 和旧地址
|
||
FBF,确认旧 APP 保持可运行且下一次 OTA 可以重新开始;
|
||
6. 在下载 10%、50%、90% 时断电,确认旧 APP 启动后清理残留状态并可再次升级;
|
||
7. 在 `ql_fota_image_verify()` 成功后的 updater 擦写阶段断电,记录底层 updater 的实际恢复
|
||
行为;当前单槽设计不能承诺该阶段自动回滚。
|
||
|
||
## 6. 后续 OTA 加固
|
||
|
||
后续 APP 版本建议按以下顺序加固,不再改变本基线分区:
|
||
|
||
1. 后端增加 size、SHA-256、layout ID 和单调递增 release sequence;
|
||
2. 下载过程中计算 SHA-256,完成后重新打开本地文件复核;
|
||
3. manifest 增加数字签名、公钥轮换和允许的 HTTPS host;
|
||
4. 将单 pending 文件升级为双时隙、CRC 和递增 generation;
|
||
5. 增加下载进度、稳定失败码和升级阶段上报;
|
||
6. 增加按设备灰度、暂停和失败率熔断;
|
||
7. 若未来硬件 Flash 扩容,再评估真正 A/B APP。
|
||
|
||
建议使用两个带 CRC 和递增 generation 的状态文件,例如 `U:/ota_state.a`、
|
||
`U:/ota_state.b`。这能抵抗状态文件写入中断,但不构成固件 A/B 回滚。
|
||
|
||
## 7. 后端联调契约
|
||
|
||
最小 FULLOTA2 继续兼容现有 URL 和版本协议,不要求后端立即修改。完成首轮生产验收后,
|
||
建议后端增加:
|
||
|
||
```json
|
||
{
|
||
"product": "EG800AKCN_11LG",
|
||
"layout_id": "eg800akcn_11lg-hxgnss-fs576-app2e5000",
|
||
"version": "1.9.0",
|
||
"release_seq": 10900,
|
||
"min_release_seq": 10800,
|
||
"url": "https://ota.example/releases/1.9.0/customer_app.fbf",
|
||
"size": 212992,
|
||
"sha256": "64-lowercase-hex",
|
||
"signature": "optional-first-stage"
|
||
}
|
||
```
|
||
|
||
设备校验顺序:产品、layout、版本序号、URL host、大小、SHA-256,最后才允许设置升级标志。
|
||
|
||
当前最小版本保留原服务器
|
||
`http://101.35.224.118:8080/assets/firmware/`,并允许 `talkingq.com` 根域及任意合法
|
||
子域名通过 HTTP/HTTPS 提供 `.bin` 文件,例如 `ota.talkingq.com` 和
|
||
`cdn.cn.talkingq.com`。校验基于解析出的完整 host 边界,`eviltalkingq.com`、
|
||
`talkingq.com.evil.example`、userinfo 绕过、非法端口和路径穿越均会被拒绝。
|
||
|
||
设备状态建议至少包含:
|
||
|
||
- `ACCEPTED`:命令和布局校验通过;
|
||
- `DOWNLOADING`:带下载字节数或百分比;
|
||
- `VERIFIED`:本地文件 SHA-256 和 FBF 校验通过;
|
||
- `REBOOTING`:升级标志已设置;
|
||
- `UPDATED`:目标 APP 已启动并通过健康检查;
|
||
- `FAILED`:带稳定错误码和失败阶段。
|
||
|
||
联调测试矩阵必须覆盖:同版本、降级、错误 layout、大小不符、SHA 不符、404、超时、下载
|
||
中断、下载阶段断电、verify 前断电、重启后无法确认,以及后台重复下发同一命令。
|
||
|
||
如果暂时没有动态 OTA 后端,也可以用“不可变 FBF 对象 + 签名 current.json”实现;但灰度、
|
||
设备级进度和失败统计需要后台服务。
|
||
|
||
## 8. 发布和回退策略
|
||
|
||
- 新生产设备只允许使用 HX_GNSS fs576 工厂包和 `0x002E5000` APP/FBF。
|
||
- 禁止向 fs576 设备发布旧地址 `0x00322000` 或错误地址 `0x002C2000` 的 FBF。
|
||
- 如生产前验证失败,可回退源码分支和工厂包重新全擦烧录;不得混烧新旧布局制品。
|
||
- 量产后若只是业务问题,可通过 APP OTA 修复;若分区或 kernel 基线有问题,需要返厂或有线
|
||
完整烧录,不能假定业务 APP OTA 能安全修改分区表。
|
||
- 当前为单槽。发布新版本必须先小批量灰度,并保持可用的有线恢复工厂包。
|