docs: 按 humanizer 重写项目文档并同步 RMIC::2026 现状
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
# 改动记录
|
||||
|
||||
记录面向使用者和维护者的主要变化。历史条目依据 Git 提交整理,日期为提交日期,尚未对应正式发布版本;详细历史见 `git log`。
|
||||
|
||||
## 未发布
|
||||
|
||||
### 文档
|
||||
|
||||
- 重组根 README,补充 ESP Rust 入门、跨平台编译与标准烧录指南。
|
||||
- 将硬件限制、开发说明与改动记录分别整理为独立文档。
|
||||
- 修正 JPEG 质量与数据大小的说明,区分历史性能记录和当前验证。
|
||||
- 补充桌面端 Windows x64 / NSIS 构建、测试与产物路径说明。
|
||||
|
||||
### 构建
|
||||
|
||||
- 固定使用命名工具链 `esp-1.97.0.0`,避免较新预览版标准库的 ESP-IDF 兼容问题。
|
||||
- 移除 S3 构建配置中的个人 macOS SDK 路径,默认 ESP-IDF v5.5.5,支持环境变量覆盖。
|
||||
- 新增从 `.env` 读取配置的 PowerShell 构建脚本。
|
||||
- 图传构建脚本使用 `--locked`,忽略 SDK 缓存和生成配置。
|
||||
- 分区表复制到生成的 CMake 工程,不再依赖 Cargo 输出层级;支持 Windows 使用较短的外部构建目录。
|
||||
|
||||
### 修复
|
||||
|
||||
- 增加运行中 Wi-Fi 断线恢复、关联和 DHCP 超时退避;取址后重建 UDP socket,清理订阅目标与旧帧,保留相机状态和帧序号。
|
||||
- 桌面端向已发现的图传板 IP 定向续订,修复 VPN / 多网卡把全局广播发往虚拟接口后“设备在线但无画面”的问题。
|
||||
- 修正丢帧统计:计入未收齐就被替换、超时及帧号缺口,重复包和等待分片不计作丢帧;拒绝迟到旧帧覆盖新帧。
|
||||
- 校验分片数量、长度与同帧元数据,处理帧号回绕及设备重启。
|
||||
|
||||
### 图传性能
|
||||
|
||||
- 根据距离收益有限、拥塞增加的实测反馈,将交付 Wi-Fi 最大发射功率上限从 17 dBm 回退到 15 dBm,实板驱动回读 15.00 dBm;启动、重连均应用同一设置,拥塞和温控逻辑不自动降功率。保留此前 14/17 dBm 的原始记录,新增功率与拥塞分析。
|
||||
- 阻塞恢复时非阻塞取最新完整 JPEG,返回被替换的旧采集缓冲;保留三块采集内存,不增加待发送 FIFO。
|
||||
- 每帧增加采集帧龄和绝对发送期限,重试预算默认缩短至 8 ms;`UDP_RETRY_BUDGET_US=0` 可在回压时立即放弃剩余分片。
|
||||
- 客户端通过本机帧时间标记拒绝 WebView 积压和慢解码的过期画面;本地 JPEG 二进制头保持 16 字节兼容。
|
||||
- 根据长程运行的峰值丢帧反馈,当前交付恢复三缓冲;双缓冲的短测数据保留为历史对照。
|
||||
- 新增可选 OV5640 `CAM_AE_LEVEL` 细调:`-1` 将亮度目标从 55 调至 45,保留 AEC/AGC 与曝光上限,供轻微过亮时调整。
|
||||
- 增加完整 OV5640 `vga30` PLL 配置与可选双缓冲;保持默认行、帧时序与彩色读出窗口,配套调整自动曝光行数上限。
|
||||
- Windows 客户端增加裁判端 `--latency-report` 校准模式,通过屏幕标记和实际视频画布测量首次可解码回显时间,保存本地 NDJSON;区分画布刷新估计与物理面板响应。
|
||||
- 固件直接读取 PSRAM 中的 JPEG,复用单个数据报缓冲,减少每帧分片复制与分配。
|
||||
- 视频 socket 使用 IP precedence 4,映射至保留 AMPDU 的 Wi-Fi 视频队列 AC_VI。
|
||||
- 对临时 UDP 发送拥塞进行有时限的让出调度重试,统计实际提交帧、失败次数与丢弃帧。
|
||||
- Windows UDP 接收缓冲请求增至 1 MiB;界面视频通道和解码队列保留最新待处理帧,避免慢端持续积压。
|
||||
- 新客户端使用随机会话 ID;固件更新同一会话的源端口,避免 NAT / TUN 端口变化产生重复推流目标,旧固定 ID 客户端继续按地址区分。
|
||||
- 新增可选编译参数 `WIFI_TX_POWER_DBM`(2–20 dBm);未设置时保留 SDK 默认上限,按实际板卡和网络测量调节。
|
||||
- 新增 `scripts/perf_probe.py`,测量完整帧率、帧损失、接收间隔和分片组装耗时。
|
||||
- 新增 `CAM_MAX_FPS`(默认 0,不限帧),可限制取帧和发送节拍,过载后不追赶补发。
|
||||
- 新增 `CAM_GRAYSCALE`,通过传感器灰度效果保留硬件 JPEG;增加可配置的芯片温度减载和 5°C 恢复回差。
|
||||
- 增加芯片内部温度、采集错误与复位原因日志,以及串口和原生客户端视频通道的长测记录脚本。
|
||||
- 新增 OV5640 曝光目标偏置与固定快门行数配置,保留自动增益;记录实际曝光行数,避免将降低亮度等同于缩短快门。
|
||||
- 新增 OV5640 水平总长试验参数 `CAM_HTS`;过短消隐会出现绿紫闪烁,几何约束通过不代表画质稳定,必须在板上验证。
|
||||
- 新增可配置 UDP 分片间隔及有界帧发送时间,支持按五分钟窗口比较突发发送与让出调度发送。
|
||||
- 新增可选 JPEG 压缩回压调节 `CAM_QUALITY_MAX`,拥塞时快速减小彩色帧,连续稳定后缓慢恢复画质;记录实际压缩档位和传感器增益。
|
||||
- 新增 `CAM_EXPOSURE_MAX_LINES`,保留自动曝光和增益联动,以曝光上限控制拖影;固定短快门不再作为室内亮度优化的默认方案。
|
||||
- 新增 OV5640 自动增益上限 `CAM_GAIN_CEILING`,为室内短曝光提供增益余量,保留运行时增益读数供验证。
|
||||
|
||||
### 硬件配置
|
||||
|
||||
- 显式设置 `CONFIG_CAMERA_CORE1=y`;仅关闭 `CAMERA_CORE0` 时,Kconfig 的 choice 仍会默认选择 CPU0。
|
||||
- 按当前 Wi-Fi 配置的镜像核对 Factory 偏移与原测试模组 `0xFADE7` 坏字节的可写性;后续重编译仍需重新检查,以 `partitions.csv` 为准。
|
||||
|
||||
## 2026-10-15
|
||||
|
||||
### 持续集成
|
||||
|
||||
- 新增 Windows、Linux、macOS 客户端构建工作流。
|
||||
- 调整制品上传版本及缓存行为,适配 Gitea runner。
|
||||
- 修复 Windows runner 的 shell、临时目录和低完整性环境适配。
|
||||
- 使用 npm 安装的 JS 版 pnpm,处理安装目录残留与 `EEXIST`。
|
||||
|
||||
对应提交:`98dc87e` 至 `4794bed`。
|
||||
|
||||
## 2026-10-14
|
||||
|
||||
### 新增
|
||||
|
||||
- 引入 Tauri v2 + React 队伍端和裁判端,网络逻辑拆分到 `desktop/core`。
|
||||
- 加入 ESP32-C3 一主三从装甲板:四路受击检测、灯带及血量广播。
|
||||
- 保存早期 C 版装甲板工程到 `reference/armor/`。
|
||||
- 桌面端加入双方血条、归零胜负提示与裁判端队名编辑。
|
||||
|
||||
### 调整与修复
|
||||
|
||||
- 移除旧 Slint 客户端。
|
||||
- 修复演示模式命中节奏与设置文字显示,移除受击画面抖动。
|
||||
|
||||
对应提交:`a89d7ae`、`4f7a142`、`7fdebe3`、`a30eb32`、`fd71b83`、`a93ae06`。
|
||||
|
||||
## 2026-10-05
|
||||
|
||||
### 新增
|
||||
|
||||
- 建立摄像头固件、共享 UDP 协议与初代桌面客户端。
|
||||
- 支持多端发现、订阅、设备绑定及队伍端 / 裁判端视图。
|
||||
- 加入滚轮缩放、拖动平移与启动最大化。
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复探测脚本重组状态未按帧隔离导致的坏帧误报,以及 FPS 窗口计算错误。
|
||||
- 修复裁判端两格宽度不一致,槽位按队伍语义分配。
|
||||
- 队伍端 release 接收路径限制到已绑定图传板。
|
||||
|
||||
早期对重复分片的协议归因已被后续提交更正,不能将当时的坏帧直接归为协议缺陷。对应提交:`4f893ce`、`1c65eaa`、`7be8d7d`、`c7f42a1`、`a16ad85`、`cd8344c`、`3631a03`。
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,236 @@
|
||||
# 固件维护页:实现说明
|
||||
|
||||
## 范围
|
||||
|
||||
本次只做 **USB 现场更新**(用户确认的 OTA 语义 = A),不做设备联网自升级。
|
||||
|
||||
- **不做** SSID 动态修改(用户已放弃该功能),App 镜像逐字节原样写入;
|
||||
- **不做** 网络 OTA;当前固件没有 OTA 分区、没有 `esp_ota` 接收端、没有控制通道;
|
||||
- **不改固件源码、不重编译**:使用当前已构建的官方 bundle,客户端只 patch 分区表的
|
||||
factory 偏移/大小;
|
||||
- 目标芯片以 ESP32-S3 为当前实现,`chip` 字段与 `espflash` 的芯片探测已经为 C3 预留,
|
||||
但 C3 的 bundle/布局尚未验收。
|
||||
|
||||
## 为什么坏块规避不需要重编译
|
||||
|
||||
App 镜像不包含自己的分区偏移;偏移只在 `0x8000` 的分区表里。所以同一份 App 可以
|
||||
写到旧 App 之后的空闲槽位,只需要改分区表里的 factory 偏移,不需要重新构建。
|
||||
|
||||
旧 `scripts/flash.sh` 之所以重编,是因为它把新偏移写回 `partitions.csv` 再重建。
|
||||
客户端改为直接 patch 已构建的 `partition-table.bin`:
|
||||
|
||||
1. 从设备读当前分区表(0xC00 字节);
|
||||
2. 解析条目,找到 factory;
|
||||
3. 把 factory 的 offset/size 改成目标槽位;
|
||||
4. 重算分区表 MD5(本仓库实测在表内 `0x70`,不是 `0xC00` 末尾);
|
||||
5. 写回并整段回读。
|
||||
|
||||
## 烧录顺序与坏块检测
|
||||
|
||||
```
|
||||
探测设备 → 读当前分区表/App 描述 → 选候选槽位(旧 App 之后)
|
||||
→ 备份旧分区表 + 旧 App
|
||||
→ 对每个候选槽位:
|
||||
写 App → 整段回读逐字节比较
|
||||
通过 → 选中;失败 → 记录坏字节/坏扇区,换下一个
|
||||
→ 只有选中槽位通过,才写 patch 后的分区表
|
||||
→ 回读分区表 → 复位 → 抓启动日志
|
||||
```
|
||||
|
||||
- 候选槽位按 64 KiB 对齐,优先 `>= 0x200000`,并跳过与旧 App 重叠的区间;
|
||||
- 当前布局(factory `0x70000`,size `0x120000`)下,第一个候选是 `0x200000`,
|
||||
新分区 size `0x140000`;旧 App 保留在 `0x70000`,可回滚;
|
||||
- 实际镜像写读校验是最终判据:图案扫描会误报“当前镜像恰好可写”的槽位;主流程
|
||||
写真实镜像再回读;
|
||||
- 不使用 merged image:填充区的坏字节也会让整包失败;只写 App 和分区表;
|
||||
- 分区表只在 App 回读通过后才切换;切换失败/启动失败可用备份恢复旧表,旧 App 未覆盖。
|
||||
|
||||
### 已知坏点
|
||||
|
||||
- `0xFADE7`:bit 5–7 无法正确编程(已确认);
|
||||
- `0x10863`:bit 6 读回为 1(`HARDWARE.md` 中尚未确认是否永久)。
|
||||
|
||||
两个地址都在 `0x100000` 以下;`0x200000` 槽位天然避开它们。客户端仍会对写入的
|
||||
App 整段回读,不依赖“已知坏点表”。
|
||||
|
||||
## 官方 .zip 固件包
|
||||
|
||||
编译完成后由 [`scripts/package_firmware.py`](../scripts/package_firmware.py) 打成单文件
|
||||
`.zip`,客户端直接读取,不需要先解压。旧目录包仍兼容。
|
||||
|
||||
zip 根目录:
|
||||
|
||||
```text
|
||||
bundle.json
|
||||
esp32s3-app.bin
|
||||
partition-table.bin # 0xC00 字节
|
||||
bootloader.bin # 可选;客户端默认不写
|
||||
BUILD-INFO.json # 可选;展示版本/构建信息
|
||||
```
|
||||
|
||||
客户端读取 zip 时的硬限制:
|
||||
|
||||
- 条目数 ≤ 32;只接受根目录单层文件名,拒绝 `..`、绝对路径、盘符、`/`、`\`;
|
||||
- `bundle.json` ≤ 64 KiB;分区表必须正好 `0xC00`;App 不得超过 `appPartitionSize`;
|
||||
- zip CRC + `appSha256` / `partitionTableSha256` 双重校验;
|
||||
- 只解压到 app cache 下的临时目录,读完立即删除;不把 zip 内容写进用户目录;
|
||||
- `BundleInfo` 会显示 `sourceKind=zip`、整包 SHA256 与条目数。
|
||||
|
||||
`bundle.json` 示例(由 [`scripts/make_bundle.py`](../scripts/make_bundle.py) 生成):
|
||||
|
||||
```json
|
||||
{
|
||||
"format": 1,
|
||||
"name": "ESP32-S3 图传固件",
|
||||
"version": "vga30-fb3-realtime-tx15+4794bed",
|
||||
"chip": "esp32s3",
|
||||
"app": "esp32s3-app.bin",
|
||||
"appSha256": "…",
|
||||
"partitionTable": "partition-table.bin",
|
||||
"partitionTableSha256": "…",
|
||||
"bootloader": "bootloader.bin",
|
||||
"bootloaderSha256": "…",
|
||||
"appPartitionSize": "0x140000",
|
||||
"flashSize": "16mb",
|
||||
"flashMode": "dio",
|
||||
"flashFrequency": "40mhz",
|
||||
"notes": "…"
|
||||
}
|
||||
```
|
||||
|
||||
客户端会校验 `format`、`chip`、`flashSize`、`appSha256`、`partitionTableSha256`;
|
||||
不匹配就拒绝,不接受任意 `.bin`。当前示例在
|
||||
[`target/firmware/bundle.json`](../target/firmware/bundle.json)。
|
||||
|
||||
编译后打包:
|
||||
|
||||
```powershell
|
||||
# 只打包(会先调用 make_bundle.py 刷新 bundle.json)
|
||||
python scripts/package_firmware.py --firmware target/firmware
|
||||
|
||||
# 构建完成后自动打包
|
||||
scripts/build.ps1 -Package
|
||||
scripts/build.sh --package
|
||||
```
|
||||
|
||||
产物:
|
||||
|
||||
```text
|
||||
target/firmware/camfw-<chip>-<variant>-<rev>-<yyyymmdd>.zip
|
||||
target/firmware/camfw-...zip.sha256
|
||||
```
|
||||
|
||||
zip 使用固定条目顺序、固定 mtime 与 deflate level 9,同一个输入应得到同一个整包
|
||||
SHA256,便于核对“两个 U 盘里的包是不是同一版”。`package_firmware.py` 会复用
|
||||
`make_bundle.py`,不维护第二套 manifest 逻辑。
|
||||
|
||||
> 注意:bundle 里的 `partition-table.bin` 是参考模板;客户端实际写的是设备当前
|
||||
> 分区表的 patch 版本,以保留设备的 NVS/PHY 布局。bundle 的分区表 SHA 仍会校验。
|
||||
|
||||
## 界面
|
||||
|
||||
入口有三处,不要求先选身份或绑定摄像头:
|
||||
|
||||
- 首次启动的身份选择页:`固件维护 / 烧录(不进入身份选择)`;
|
||||
- 用户端设置密码页:同上;
|
||||
- 主界面右上角:`固件维护`。
|
||||
|
||||
页面流程:
|
||||
|
||||
1. 自动列出串口并选中 Espressif 设备;
|
||||
2. `读取设备` 显示芯片、MAC、Flash、安全启动/加密状态、当前 App、分区表、空闲区间;
|
||||
3. `选择 .zip 固件包` 选择编译后打包的单文件;`选目录(兼容旧包)` 仍可用;
|
||||
4. `生成计划` 显示目标槽位、候选槽位、切换后的 factory、警告;
|
||||
5. 勾选是否备份旧 App;`开始烧录` 二次确认后执行;
|
||||
6. 进度条 + 运行日志 + 结果;失败时显示坏字节/坏扇区、备份目录,并可 `恢复旧分区表`。
|
||||
|
||||
读取设备和烧录都会复位一次;开始前应停止录制,视频流会短暂中断。
|
||||
|
||||
## 代码位置
|
||||
|
||||
| 层 | 文件 |
|
||||
| --- | --- |
|
||||
| 后端:探测/分区表/候选槽位/写入/回读/备份/恢复 | [`desktop/src-tauri/src/maintenance.rs`](../desktop/src-tauri/src/maintenance.rs) |
|
||||
| Tauri 命令注册、`--maintenance-probe`/`--maintenance-bundle`/`--maintenance-plan` | [`desktop/src-tauri/src/main.rs`](../desktop/src-tauri/src/main.rs) |
|
||||
| 前端 IPC 与 DTO | [`desktop/src/lib/maintenance.ts`](../desktop/src/lib/maintenance.ts) |
|
||||
| 维护页 | [`desktop/src/pages/MaintenancePage.tsx`](../desktop/src/pages/MaintenancePage.tsx) |
|
||||
| 样式 | [`desktop/src/styles/maintenance.css`](../desktop/src/styles/maintenance.css) |
|
||||
| manifest 生成 | [`scripts/make_bundle.py`](../scripts/make_bundle.py) |
|
||||
| zip 打包 | [`scripts/package_firmware.py`](../scripts/package_firmware.py) |
|
||||
|
||||
后端使用 `espflash` 4.6 库(`default-features = false, features = ["serialport"]`)、
|
||||
`serialport` 4.10 和 `zip` 2.6(只开 `deflate`);Tauri 用 `tauri-plugin-dialog` 选文件/目录。
|
||||
|
||||
## 构建与验证
|
||||
|
||||
Windows x64:
|
||||
|
||||
```powershell
|
||||
cd desktop
|
||||
pnpm install
|
||||
pnpm check
|
||||
pnpm build
|
||||
cd src-tauri
|
||||
cargo check --target x86_64-pc-windows-msvc --config 'unstable.build-std=[]'
|
||||
cargo test --target x86_64-pc-windows-msvc --config 'unstable.build-std=[]' maintenance::tests
|
||||
```
|
||||
|
||||
固件侧打包:
|
||||
|
||||
```powershell
|
||||
python scripts/package_firmware.py --firmware target/firmware
|
||||
# 或:scripts/build.ps1 -Package / scripts/build.sh --package
|
||||
```
|
||||
|
||||
运行 GUI:
|
||||
|
||||
```powershell
|
||||
cd desktop
|
||||
pnpm tauri dev --target x86_64-pc-windows-msvc -- --config 'unstable.build-std=[]'
|
||||
```
|
||||
|
||||
> `desktop/.cargo/config.toml` 里的 `build.target` 是 macOS ARM 的默认值;Windows
|
||||
> 需要上面的 `--target` 覆盖。`tauri.conf.json` 的 bundle targets 是 `"all"`,
|
||||
> 各平台打包时使用自己的默认 bundle 类型。
|
||||
|
||||
无窗口诊断(仍会复位设备):
|
||||
|
||||
```powershell
|
||||
cd desktop/src-tauri
|
||||
.\target\x86_64-pc-windows-msvc\debug\cam-desktop.exe --maintenance-probe COM8
|
||||
# 只校验 zip/目录包,不连设备
|
||||
.\target\x86_64-pc-windows-msvc\debug\cam-desktop.exe --maintenance-bundle C:\path\to\camfw-*.zip
|
||||
.\target\x86_64-pc-windows-msvc\debug\cam-desktop.exe --maintenance-plan COM8 C:\path\to\camfw-*.zip
|
||||
# 只写 App + 回读,不切分区表;设备仍从旧 App 启动
|
||||
.\target\x86_64-pc-windows-msvc\debug\cam-desktop.exe --maintenance-write-test COM8 C:\path\to\camfw-*.zip 0x200000
|
||||
```
|
||||
|
||||
## 已验证 / 未验证
|
||||
|
||||
已在当前连接板(`COM8`,ESP32-S3 v0.2,MAC `90:70:69:f8:f2:14`,16 MB,
|
||||
Secure Boot / Flash Encryption 均未启用)上验证:
|
||||
|
||||
- `--maintenance-probe`:读取芯片、MAC、分区表、App 描述;
|
||||
- `--maintenance-plan`:选中 `0x200000` / `0x140000`,patch 后 factory 为
|
||||
`0x200000`,旧 App 保留;
|
||||
- `--maintenance-write-test COM8 … 0x200000`:实机写入 App 并整段回读,
|
||||
`writeOk=true`、`verifyOk=true`、0 处不一致;分区表未动,设备仍从旧 App 启动;
|
||||
- `.zip` 打包与读取:`camfw-…zip` 5 项、758,149 字节,`--maintenance-bundle` 校验通过,
|
||||
`sourceKind=zip`、整包 SHA256 与条目数正确;
|
||||
- 离线单元测试:分区表解析、MD5 重算、候选槽位、尺寸解析、zip 路径白名单,共 7 个;
|
||||
- 前端 `tsc --noEmit`、`vite build`,后端 `cargo check` 通过。
|
||||
|
||||
**尚未执行**完整实机切换(写 patch 后分区表 → 复位 → 启动日志)。App 写入/回读
|
||||
已经在同一块板上验证;切换步骤的风险集中在 0x8000 的 3 KiB 分区表写入,写入后会
|
||||
回读,失败会尝试恢复旧表。建议在维护页点一次;如果新 App 启动失败,页面会给出
|
||||
备份目录和 `恢复旧分区表` 按钮。
|
||||
|
||||
## 边界
|
||||
|
||||
- 不做运行时坏块重映射/FTL;ESP32 ROM bootloader 按分区线性读取,不能在 App 镜像
|
||||
中间跳过坏扇区。这里的“屏蔽”= 选一个实际镜像写读校验通过的整槽位。
|
||||
- 不写 bootloader、不碰 NVS/PHY;bundle 里的 bootloader 只做展示/校验。
|
||||
- 分区表写入是单点风险:写入后会回读;失败会尝试恢复旧表;极端断电情况下可用
|
||||
ROM 下载模式重新写入,备份在 `%APPDATA%/com.simbarobotics.rmic2026/backups/`(Windows)或
|
||||
对应平台的 app data 目录。
|
||||
- 网络 OTA 仍需要一次性改固件(OTA 分区 + `esp_ota` 接收端 + 控制通道),不在本次范围。
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,39 @@
|
||||
id,category,priority,precondition,steps,expected,pass_criteria,evidence,tools,est_minutes
|
||||
"N-01","正常","P0","健康板;新模板;工具版本锁定","分段写 Bootloader/分区表/App;逐段 verify;复位;串口与 UDP 验收","3 段 verify OK;启动日志正常;15 s 内收到完整帧","verify 全通过;无 panic/brownout;perf 帧率>=15 fps 且丢帧<=5%","verify 日志;serial.log;perf.json","esptool;perf_probe;serial_soak","20"
|
||||
"N-02","正常","P0","健康板;已 provision;同布局","只写新 App;verify;复位;检查 config 保留","App 版本更新;原 SSID 配置仍生效","App hash 与 manifest 一致;config seq 不变;联网正常","verify;serial;perf","esptool;perf_probe","15"
|
||||
"N-03","正常","P0","健康板;已 provision;模板支持 config","只 patch config(换 SSID);不写 App;复位","新 SSID 生效;App SHA-256 不变","app-readback SHA-256 与 manifest 一致;serial 显示 config source=partition;联网正常","app hash;serial;perf","esptool;provision.py;perf_probe","10"
|
||||
"N-04","正常","P1","健康板","连续 provisioning 3 次(相同输入)","幂等;无 brick;报告一致","3/3 通过;设备身份一致;无重复写入错误","3 份 result.json","provision.py","20"
|
||||
"N-05","正常","P1","健康板;归档镜像","写 merged image 并 verify(对照)","记录是否通过;不用于坏板","结果记录;不改变坏板策略","verify 日志","esptool","10"
|
||||
"B-01","坏板","P0","故障板;E1 备份已验证","牺牲板 E2 写读表征;生产板定向读 0xFADE7/0x10863 + 扫描模板写入区","E2 复现缺陷;生产板地图正确;恢复 verify","至少识别两个已知地址;恢复后关键区 verify OK","scan.json;verify;backup hash","esptool;provision.py","30"
|
||||
"B-02","坏板","P0","故障板;新布局;模板镜像","分段写新 App/表;verify;复位","写入区不含坏地址;App 实际镜像 verify OK;启动","3 段 verify OK;serial live;UDP 有帧","verify;serial;perf","esptool;perf_probe","25"
|
||||
"B-03","坏板","P0","故障板;强制 App 槽包含坏字节","写实际镜像;读回比较","若镜像字节不可写则 verify 失败;工具换槽或拒绝;不 brick","失败可定位到地址;设备仍可进下载模式;报告不报成功","verify;scan;report","esptool;provision.py","25"
|
||||
"B-04","坏板","P0","故障板;config 一个槽含坏扇区","写 config 多副本;复位","跳过坏槽;至少一个副本有效;联网","serial 显示有效 seq;报告记录 skipped 槽;App hash 不变","scan;serial;report","esptool;provision.py","20"
|
||||
"B-05","坏板","P1","故障板;merged 镜像","写 merged image(对照)","预期失败或高风险;工具默认禁止","记录失败地址/错误;后续流程仍走分段","verify 日志;report","esptool","15"
|
||||
"B-06","坏板","P1","故障板;疑似间歇坏字节","同一扇区扫描 3 次;不同温度/供电","标记 SUSPECT;隔离;不用于 App","3 次结果一致或明确记录间歇;SUSPECT 不进 App 槽","scan.json","esptool;provision.py","30"
|
||||
"B-07","坏板","P2","故障板;全片备份","全片扫描 + 恢复","得到全片地图;恢复关键区;不丢数据","恢复后关键区 verify OK;时间记录","scan.json;backup hash","esptool","60"
|
||||
"O-01","OTA","P1","OTA-ready;Bootloader rollback","写 ota_0;切换;复位","新版本启动;分区日志正确","serial 显示 ota_0;版本正确;联网","serial;otatool","otatool.py;perf_probe","30"
|
||||
"O-02","OTA","P1","OTA-ready;当前槽有效","写损坏镜像/错误 SHA;复位","Bootloader 拒绝;旧槽仍启动","旧版本启动;无 brick;serial 有拒绝原因","serial","otatool.py;esptool","20"
|
||||
"O-03","OTA","P1","OTA-ready;USB 继电器","OTA 写入 25/50/75% 时断电;恢复","至少一个槽可启动;无需整片擦","3 个断点均能启动;版本/分区符合预期","serial;relay log","otatool.py;relay","45"
|
||||
"O-04","OTA","P1","OTA-ready;目标槽含坏区","OTA 到坏槽;复位","安全失败;旧槽不受影响","旧版本启动;无 brick;报告记录坏槽","serial;scan","otatool.py;esptool","25"
|
||||
"O-05","OTA","P2","启用 anti-rollback","OTA 降级;复位","按策略拒绝或接受;不 brick","策略与日志一致;设备可启动","serial","otatool.py","20"
|
||||
"H-01","热插拔","P0","1 块板;驱动已装","插拔 20 次;记录发现时间","20/20 发现;P95<=2 s","无漏检;无端口残留;无错板","discovery.json","serialport;provision.py","20"
|
||||
"H-02","热插拔","P0","2 块板同时插入","按 MAC 选择;执行 patch/verify","0 次错板;端口/MAC 正确","两块设备报告 MAC 与操作一致","report","serialport;provision.py","20"
|
||||
"H-03","热插拔","P1","写入进行中","拔掉 USB","报错;设备可恢复;不报成功","错误码明确;重插后可进下载模式","log;report","provision.py","15"
|
||||
"H-04","热插拔","P1","扫描进行中","拔掉 USB","报错;备份可恢复;不半写成功","重插后恢复;关键区 verify OK","log;backup","provision.py","20"
|
||||
"H-05","热插拔","P1","串口监视器占用端口","执行 provisioning","明确端口占用;不挂死","错误码/提示;进程退出","log","provision.py;espflash monitor","10"
|
||||
"H-06","热插拔","P0","错固件/错芯片","选择不兼容 manifest","写入前拒绝;设备不变","App hash 前后一致;错误码 3","report","provision.py","10"
|
||||
"P-01","断电","P0","健康板/坏板;可恢复","App 写入 50% 断电;上电;重刷","可进下载模式;重刷后启动;不 brick","BOOT 恢复;verify OK;serial live","serial;verify","esptool;relay","20"
|
||||
"P-02","断电","P0","config 已有一个有效副本","config 写入时断电;上电","旧副本有效;启动","serial 显示旧 seq;联网正常","serial","esptool;relay","15"
|
||||
"P-03","断电","P1","分区表迁移中","分区表写入时断电;上电;重刷","BOOT 恢复;重刷表/App;不 brick","可进下载模式;重刷后启动","serial;verify","esptool;relay","25"
|
||||
"P-04","断电","P2","Bootloader 更新中(最高风险)","Bootloader 写入时断电;上电;BOOT 恢复","可恢复;不 permanent brick","BOOT 可进下载;重刷后启动","serial;verify","esptool;relay","30"
|
||||
"P-05","断电","P2","扫描/恢复中","拔 USB/断电;恢复","备份可用;关键区不丢","关键区 verify OK;无半写成功","backup hash","esptool","30"
|
||||
"S-01","安全","P0","正常 provision","检查日志、报告、命令行历史","无密码明文;只有 SSID/hash/seq","grep 不到密码;报告字段合规","grep;report","provision.py","10"
|
||||
"S-02","安全","P1","Secure Boot/加密板(如有)","espefuse summary;尝试未签名 patch","检测 eFuse;拒绝未签名/未加密 patch","工具退出码 10;设备不变","espefuse 输出;report","espefuse;espsecure","20"
|
||||
"S-03","安全","P1","篡改 manifest/App","校验 SHA-256 后烧录","拒绝烧录","错误码 3;设备不变","report","provision.py","10"
|
||||
"S-04","安全","P2","伪造 VID/PID 设备","主动探测 chip/MAC/Flash","识别不匹配;拒绝","不写入;报告记录","report","serialport;esptool","20"
|
||||
"R-01","回归","P0","host 环境","pytest 全部 host tests","100% 通过","0 failed;覆盖 config/分区/manifest/选择逻辑","JUnit/HTML","pytest","10"
|
||||
"R-02","回归","P1","硬件在环","20 次循环(N/B/H 子集)","首次通过率>=95%;0 brick;0 错板","统计达标;失败可定位","summary.json","pytest;provision.py","120"
|
||||
"R-03","回归","P0","锁定工具版本","重复执行同一命令 3 次","同输入同命令/同结果","版本/哈希/输出一致","versions.txt;report","all","15"
|
||||
"R-04","回归","P1","报告 schema","用 jsonschema 校验 result/scan/manifest","全部通过","0 schema error","schema 校验日志","pytest;jsonschema","10"
|
||||
"M-01","迁移","P1","旧布局 0x70000 板","备份;写新 App→新表→可选 Bootloader;保留 NVS/PHY;复位","新布局启动;NVS/PHY 保留;config 可用","serial live;MAC 不变;Wi-Fi 校准未丢","serial;report","esptool;provision.py","30"
|
||||
"M-02","迁移","P0","旧布局板","尝试只 patch config","工具拒绝并提示迁移","错误码 3/提示明确;设备不变","report","provision.py","10"
|
||||
|
Reference in New Issue
Block a user