merge: v2-on-ui into task/screenlink-bench-serial (wave + screenlink)
This commit is contained in:
@@ -76,7 +76,3 @@
|
||||
- 本地等价脚本:[`../../scripts/ci_local.py`](../../scripts/ci_local.py)
|
||||
- runner 机器的工具链环境要求:[`../环境与部署/项目部署环境要求.md`](../环境与部署/项目部署环境要求.md)
|
||||
- `DTU_*` 工具路径变量机制:[`../环境与部署/本地工具路径环境变量方案.md`](../环境与部署/本地工具路径环境变量方案.md)
|
||||
|
||||
## 变更记录
|
||||
|
||||
> (本文件不再记流水账:改了什么是正文说了算,改动过程查 git log。)
|
||||
|
||||
@@ -1350,9 +1350,3 @@ powershell -ExecutionPolicy Bypass -File scripts\ci_runner_bootstrap.ps1 -DryRun
|
||||
|
||||
> 更早基于 Windows 服务的 `deploy_runner.ps1` / `install_service.ps1` 已删除
|
||||
> —— 那条路走不通(§3.0)。
|
||||
|
||||
---
|
||||
|
||||
## 变更记录
|
||||
|
||||
> (本文件不再记流水账:改了什么是正文说了算,改动过程查 git log。)
|
||||
|
||||
+1
-7
@@ -91,7 +91,7 @@ docs/
|
||||
| [`运行与自检记录设计说明.md`](子系统设计/运行与自检记录设计说明.md) | `/log/run.log`·`selftest.log` 定长记录与待机显示 |
|
||||
| [`看门狗设计说明.md`](子系统设计/看门狗设计说明.md) | IWDG(CubeMX 配置)+ 任务心跳位图:选型与超时推导、掩码与埋点、取证机制、验证记录;已台架闭环(V2/V4/V5)。**§11 = 任务级饥饿的诊断方法与 `[PROF]` 实测基线**(诊断沉淀:判读口径、量化归因、三条脆弱点、明确不做的四条) |
|
||||
| [`ADC采样节拍设计说明.md`](子系统设计/ADC采样节拍设计说明.md) | **ADC 采集链路采样节拍(现状说明)**:TIM3 1 kHz 更新事件同时触发 TPAFE CONVST 与(经 TRGO)STM32 ADC1 + DMA 乒乓缓冲;节拍源为什么是 TIM3、DMA 硬约束、事件驱动消费与就绪门、实现落点、观测计数、性能特征与设计边界 |
|
||||
| [docs/子系统设计/故障录波设计说明.md](子系统设计/故障录波设计说明.md) | **故障录波设计与口径属主**:1 kHz 起步与 80 点口径的偏离登记、存原始码值的理由、四段所有权与三条并发陷阱、段文件字节布局、现场单通道回放显示契约、预算与 R6 前置 |
|
||||
| [docs/子系统设计/故障录波设计说明.md](子系统设计/故障录波设计说明.md) | **故障录波设计与口径属主**:1 kHz 起步与 80 点口径的偏离登记、存原始码值的理由、四段所有权与四条并发陷阱、段文件字节布局、现场单通道回放显示契约、预算与 R6 前置 |
|
||||
| [`IEC104上行设计说明.md`](子系统设计/IEC104上行设计说明.md) | **B4 上行规约**:IEC 60870-5-104 被控站(TCP 2404)范围/点表(V0.1 有效子集)/链路流程(k/w/t1~t3、总召、COV、遥控两段式、定值)/netTask 接入决策/预算与测试方案;协议核心纯逻辑 + 主机侧纯逻辑单测全栈单测 |
|
||||
| [`屏板链路设计说明.md`](子系统设计/屏板链路设计说明.md) | **屏板串口链路(`Drivers/BSP/ScreenLink/`)实现记录**:一句话架构与数据流、`sb_proto`/`sb_link` 全部对外接口、八条关键实现决定(不留影子缓冲/busy 冻结/中断起发等)、资源占用实测(`s_frame` 落 RW_IRAM1 非 CCM)、单测与台架/真屏板冒烟证据链、接线教训(排针丝印视角陷阱)、坑账本、**尚未实测项清单**;任务分解与协议事实源仍在 `docs/任务规划/屏板链路.md` |
|
||||
| [`网络/BSD_Socket_API_使用指南.md`](网络/BSD_Socket_API_使用指南.md) | **上层视图**:BSD Socket API 公开语义、示例、常见问题 |
|
||||
@@ -279,9 +279,3 @@ docs/
|
||||
| ~~`docs/文档规范.md` 未创建~~ | — | ✅ 已创建(2026-09-25):[`文档规范.md`](文档规范.md) |
|
||||
|
||||
> 未闭环的文档类问题**只剩仓库膨胀**(登记簿条目「仓库体积膨胀观察」,已决策暂不处理)。
|
||||
|
||||
---
|
||||
|
||||
## 12. 变更记录
|
||||
|
||||
> (本文件不再记流水账:改了什么是正文说了算,改动过程查 git log。)
|
||||
|
||||
@@ -186,7 +186,7 @@ MCU 端 `Drivers/BSP/dbg_log.h` 会引用 `sys_clock.h`(RTC 时间戳),PC
|
||||
- `LV_USE_THEME_MONO` 是否 = 1 且在 `sim_port_init` 中调了 `lv_theme_mono_init`(1bpp 无主题 = 黑底黑字)
|
||||
- 主循环是否调用 `lv_refr_now(NULL)` 强制首帧输出(PARTIAL 模式下保证)
|
||||
- 是否重复设置 tick:SDL 驱动内部 `lv_tick_set_cb(SDL_GetTicks)`,**不要**再 `SDL_AddTimer` + `lv_tick_inc`
|
||||
2. **中文字体缺字**:`ui_font_cn_12` 是子集字体(当前 218 汉字/符号 + ASCII 0x20~0x7E,共 313 字形;2026-10-28 实测)。**缺字才会显示为空白**——新增汉字必须重生成字体(见下文 6.3)。早期只有 83 字、当时菜单需要 186 字,那是 2026-09-03 的历史快照,不是现状。
|
||||
2. **中文字体缺字**:`ui_font_cn_12` 是子集字体(当前 224 汉字/符号 + ASCII 0x20~0x7E,共 319 字形;2026-10-29 实测)。**缺字才会显示为空白**——新增汉字必须重生成字体(见下文 6.3)。早期只有 83 字、当时菜单需要 186 字,那是 2026-09-03 的历史快照,不是现状。
|
||||
3. **`LV_SDL_RENDER_MODE` 必须为 `PARTIAL`**:1bpp + SDL 若非 PARTIAL,`lv_sdl_window.c` 会 `#error` 编译失败。
|
||||
|
||||
### 6.3 字体生成(如需补全中文字符)
|
||||
@@ -234,7 +234,7 @@ A: `LV_CONF_DIR` 变量未在 `add_subdirectory(lvgl)` 前定义,检查 `simul
|
||||
A: 按 6.2 黑屏排查顺序检查:mono 主题 → `lv_refr_now` → tick 不重复。
|
||||
|
||||
### Q4: 菜单某些中文显示空白?
|
||||
A: 子集字体未含该字(当前字符集 218 汉字/符号 + ASCII 0x20~0x7E,共 313 字形;2026-10-28 实测),见 6.3 重新生成字体。
|
||||
A: 子集字体未含该字(当前字符集 224 汉字/符号 + ASCII 0x20~0x7E,共 319 字形;2026-10-29 实测),见 6.3 重新生成字体。
|
||||
|
||||
### Q5: 修改了 UI 代码但模拟器没变化?
|
||||
A: 确认修改的是 `Drivers/BSP/UI/ui_menu.c` 而非 `simulator/` 内的副本(本工程无副本);然后重新 `cmake --build`。
|
||||
|
||||
@@ -55,7 +55,7 @@ scanned 13 files; unique non-ASCII chars: 78
|
||||
-> D:\Code\DTU Code\STM32F4-Base\ui_cn_chars.txt
|
||||
```
|
||||
|
||||
产物 `ui_cn_chars.txt` 为本工程实际显示的汉字清单(当前 218 字,含 ▶/,/: 等符号;2026-10-28 UI 补齐批「记录 5 页 + 运行报告」+33 字,185→218——本行旧数 183 是未回填的历史值,改前实测 185;其中 60 字为 2026-10-25 按页面扩充规划显示串预置,同日道E 落 SOE 记录显示名映射时新用 采/样/恢/效 4 字;清单里源码暂未在用的字由 font-charset 门禁记 WARN 放行),可留作字符集记录。
|
||||
产物 `ui_cn_chars.txt` 为本工程实际显示的汉字清单(当前 224 字,含 ▶/,/: 等符号;2026-10-29 录波 UI 道 +6 字(218→224);2026-10-28 UI 补齐批「记录 5 页 + 运行报告」+33 字,185→218——本行旧数 183 是未回填的历史值,改前实测 185;其中 60 字为 2026-10-25 按页面扩充规划显示串预置,同日道E 落 SOE 记录显示名映射时新用 采/样/恢/效 4 字;清单里源码暂未在用的字由 font-charset 门禁记 WARN 放行),可留作字符集记录。
|
||||
|
||||
---
|
||||
|
||||
@@ -152,8 +152,8 @@ OK 67325 bytes -> ...\Drivers\BSP\UI\ui_font_cn_12.c
|
||||
1. **1bpp 细笔画发虚**:宋体在 1bpp 下可能丢像素。若上板/客户端中文偏淡,把第 4 节 `--bpp` 改为 `2` 重生成即可(子集小,体积可接受)。
|
||||
2. **字符集变更**:以后新增中文菜单项,须重跑第 3、4 节(重新提取 `ui_cn_chars.txt` 并生成),否则新字显示为方框。
|
||||
3. **编码**:UI 源文件须为 **UTF-8(带 BOM)**,LVGL 按 UTF-8 解码中文串;字体 `.c` 为纯 ASCII,无编码风险。当前 Keil 已加 Misc Controls 抑制项,无需额外 `--locale=english`。
|
||||
4. **字体体积**:12px + 1bpp + 218 个汉字/符号(**不含 ASCII**——ASCII 0x20~0x7E 由 make_font 的 -r 参数一并打进子集,
|
||||
故字形数 = 218 + 95 = **313**,`glyph_dsc` 数组实含 notdef 共 314 条;2026-10-28 实测)源文件 ≈ 65.7KB(2026-10-28 实测 67,325 B;改前 185 字/280 字形/58.2KB,旧文本 183 字/278 字形系未回填);ROM 增量以 `.map` 为准(2026-10-25 扩 60 字实测 `RO-data` +1,528 B、RAM 0;同日 SOE 显示名再用 4 字实测 `RO-data` +108 B、RAM 0——1bpp 12px 一个字约 27 B,含字形描述符);改 bpp 2 约翻倍,仍在 F407 Flash 余量内。
|
||||
4. **字体体积**:12px + 1bpp + 224 个汉字/符号(**不含 ASCII**——ASCII 0x20~0x7E 由 make_font 的 -r 参数一并打进子集,
|
||||
故字形数 = 224 + 95 = **319**,`glyph_dsc` 数组实含 notdef 共 320 条;2026-10-29 录波 UI 道实测)源文件 ≈ 67.1KB(2026-10-29 实测 68,729 B;改前 185 字/280 字形/58.2KB,旧文本 183 字/278 字形系未回填);ROM 增量以 `.map` 为准(2026-10-25 扩 60 字实测 `RO-data` +1,528 B、RAM 0;同日 SOE 显示名再用 4 字实测 `RO-data` +108 B、RAM 0——1bpp 12px 一个字约 27 B,含字形描述符);改 bpp 2 约翻倍,仍在 F407 Flash 余量内。
|
||||
5. **换字体**:黑体用 `simhei.ttf`(单文件免抽取);其余字体同理替换 `--font` 路径后重生成。
|
||||
|
||||
---
|
||||
|
||||
@@ -694,7 +694,7 @@ typedef struct {
|
||||
| 4 | 未标定时页面明确标识(不把码值当伏特) | 目检 + 文本断言(`eng=0` 时带标记) |
|
||||
| 5 | 首帧前显示 `--` 而非 `0.000` | 模拟器:不 publish 直接开页,断言文本 |
|
||||
| 6 | 定值整定全链闭环 | 就地改 → 保存 → 重启 → 值保持 + 校验和自检通过 + 主站 C_RD 一致。**半收口(2026-10-26)**:模拟器侧「改 → 保存 → OK → 回首屏新值已在帧里」已由像素 + 文本断言覆盖(黄金用例 `sparam_save` / `sparam_landed`,越界侧 `sparam_oob`);**重启保持与主站 C_RD 一致只能上板**——模拟器没有 NAND,`apply()` 到 `prot_set_set_sealed()` 就是终点,这条差距已登记在 `docs/测试说明/模拟器差距清单.md`;另注意 40 项里有 13 项 `comm_addr=0`(纯本地项),主站侧根本读不到,不能拿 C_RD 当它们的判据 |
|
||||
| 7 | 像素回归稳定 | `ui-golden` 连续两次运行零差异。**已验(2026-10-26,当时下限为 27 页)**:27 页连跑两次逐字节一致(含整定 9 态)——**集合现已扩至 60 张**,双次一致需按同口径重跑回填;轮询定时器不影响——无头模式不调 `lv_timer_handler()`(§9.2 注 6) |
|
||||
| 7 | 像素回归稳定 | `ui-golden` 连续两次运行零差异。**已验(2026-10-26,当时下限为 27 页)**:27 页连跑两次逐字节一致(含整定 9 态)——**集合现已扩至 66 张**,**双次一致已验(2026-10-29:同一批 66 张连跑三次逐字节一致,池水位 5,448 B;菜单 8 状态连跑三次亦一致,5,368 B)**;轮询定时器不影响——无头模式不调 `lv_timer_handler()`(§9.2 注 6) |
|
||||
| 9 | 「写不进去」与「改了不动作」两条事实互不冒充 | 反向文本断言(`check_content_pages.py` 的 `ABSENT`:查看页与只读态不得出现「未标定」徽标与「保存」行)+ 台架:未制造该态——要它必须改坏 /prot_set.bin(破坏产品配置存储,用户裁定 2026-10-26 不做),故 LOCK 态目前只有代码级证据与三重反证(ENTER 被正常消费、遥信 YX31=OFF、开机 CORRUPT=0),**没有像素证据** |
|
||||
| 8 | 主机单测覆盖数据模块 | `test/host/ui_data` 全绿并挂 pre-commit 钩子 |
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ flowchart TD
|
||||
|---|---|---|---|
|
||||
| C1 | 屏幕 | 160×160,1bpp 单色(`LV_COLOR_FORMAT_I1`),无物理屏(远端客户端显示) | `ui_port.h` |
|
||||
| C2 | 字体 | **唯一**:`ui_font_cn_12`(宋体 12px 1bpp)。汉字 12px/字,ASCII 6px/字,行高 13px。需要其他字号 = 大工程(新字体 + 双端 `lv_conf.h`),默认禁止 | `ui_font_cn_12.c` |
|
||||
| C3 | 字符集 | 子集字体(当前 218 汉字/符号 + ASCII 0x20-0x7E,共 313 字形);**缺字显示空白**;新字必须重生成字体 | `tools/font_gen/` |
|
||||
| C3 | 字符集 | 子集字体(当前 224 汉字/符号 + ASCII 0x20-0x7E,共 319 字形);**缺字显示空白**;新字必须重生成字体 | `tools/font_gen/` |
|
||||
| C4 | LVGL 内存池 | 16KB(`LV_MEM_SIZE`,2026-10-15 由 40KB 收缩;实测峰值 6,568 B = 池的 40%);任一时刻只放"当前导航路径 + 当前内容页" | `Lib/lv_conf.h` |
|
||||
| C5 | 文本 | 一律静态字符串(`lv_label_set_text_static`),禁止动态字符串/strdup | 架构文档 |
|
||||
| C6 | 编码 | `Drivers/BSP/UI/*`、`ui_task.c`、`Lib/lv_conf.h` 为 **UTF-8 带 BOM**;改动只用 Edit 工具,**禁止** PowerShell/cmd 整文件重写(U+FFFD 不可逆) | AGENTS.md 铁律 |
|
||||
|
||||
@@ -26,7 +26,7 @@ cmake --build simulator/build --config Debug # 0) 构建模拟器(须 0 警
|
||||
| 步 | 脚本/命令 | 门禁内容 | 预期输出 |
|
||||
|---|---|---|---|
|
||||
| 1 | `simulator/tests/check_menu_rows.py` | 菜单 8 状态:选中行白带 / 非选行黑底白字 / 框体 1px 边框 / 往返像素一致(MENU-STATE-03==MENU-STATE-01、MENU-STATE-06==MENU-STATE-01、MENU-STATE-07==MENU-STATE-02)+ MENU-STATE-00 池基线 | `PASS: 8 状态全部断言通过(8 图,池基线 5368 B)` |
|
||||
| 2 | `simulator/tests/check_content_pages.py` | ① 文本级断言(字形模板匹配,正向 425 条 + 反向 36 条,独立于 `ref/`)→ ② 60 张截图与 `ref/` 黄金参考**逐字节**比对 + 开页-关页往返池水位 | `PASS: 60 内容页 + 往返池水位全部通过`(文本断言先于像素比对,失败即中止) |
|
||||
| 2 | `simulator/tests/check_content_pages.py` | ① 文本级断言(字形模板匹配,正向 444 条 + 反向 45 条,独立于 `ref/`)→ ② 66 张截图与 `ref/` 黄金参考**逐字节**比对 + 开页-关页往返池水位 | `PASS: 66 内容页 + 往返池水位全部通过`(文本断言先于像素比对,失败即中止) |
|
||||
| 3 | `keil-build` skill(`keil_build.py`) | MCU 端编译(UI 源码双端共用,改一端必须过另一端) | 退出码 0 = BUILD_OK |
|
||||
| 4 | `scripts/check_coding_standard.py` | 代码规范 V1.0 机械检查 | PASS |
|
||||
|
||||
@@ -52,7 +52,7 @@ cmake --build simulator/build --config Debug # 0) 构建模拟器(须 0 警
|
||||
| `POOL_AFTER_ROUNDTRIP` | check_content_pages.py | **5448 B** | 开页-关页往返后水位 = 基线 + 一次性残留 80 B |
|
||||
|
||||
> 水位历史:4784 →(2026-09-14 待机模块常驻 +656)5440 / 5520 →(2026-10-11 裁剪 LVGL 控件类 −72)5368 / 5448。
|
||||
> 后一次漂移已核实为**有意且更优**:像素逐字节未变(**裁剪当时黄金参考只有 11 页**,在裁剪**前**生成、裁剪后全部一致;该集合现已扩至 60 张),
|
||||
> 后一次漂移已核实为**有意且更优**:像素逐字节未变(**裁剪当时黄金参考只有 11 页**,在裁剪**前**生成、裁剪后全部一致;该集合现已扩至 66 张),
|
||||
> 且一次性残留仍是 80 B(5448 − 5368)→ 泄漏特征未变,只是 `lv_theme_apply` 不再为已不存在的控件类登记样式条目。
|
||||
|
||||
**漂移处理**:菜单/页面结构或样式变更导致门禁失败时,先确认新值合理(残留分解见
|
||||
@@ -61,7 +61,7 @@ cmake --build simulator/build --config Debug # 0) 构建模拟器(须 0 警
|
||||
|
||||
## 四、黄金参考(入库)与目检 PNG(本地产物)
|
||||
|
||||
`simulator/tests/ref/*.bin`(像素黄金参考,60 张 × 3200 B)**随仓库入库**;派生的 `.png`
|
||||
`simulator/tests/ref/*.bin`(像素黄金参考,66 张 × 3200 B)**随仓库入库**;派生的 `.png`
|
||||
目检图仍是本地产物(`.gitignore`)。入库的理由:比对是**逐字节**的,基线不入库时任何新克隆
|
||||
或新工作树跑 `ui-golden` 都必然 FAIL(缺基准),这条门禁就只在"有老副本的机器"上真实存在。
|
||||
可复现性实测(2026-10-22):两份各自独立构建的 `lvgl_sim`(不同构建目录、相隔 11 天的代码)
|
||||
@@ -148,7 +148,7 @@ cmake --build simulator/build --config Debug # 0) 构建模拟器(须 0 警
|
||||
### 7.3 用法与门禁档位
|
||||
|
||||
```powershell
|
||||
# 认屏快检:60 张黄金参考(+ 若有台架留档帧),秒级,不需要构建产物
|
||||
# 认屏快检:66 张黄金参考(+ 若有台架留档帧),秒级,不需要构建产物
|
||||
& '.venv\Scripts\python.exe' scripts/board_ui_nav.py --selftest-quick
|
||||
# 完整自检:再加全绑定页闭环导航(需模拟器可执行文件,约 30 s)
|
||||
& '.venv\Scripts\python.exe' scripts/board_ui_nav.py --selftest
|
||||
@@ -200,8 +200,3 @@ cmake --build simulator/build --config Debug # 0) 构建模拟器(须 0 警
|
||||
(两套走法迟早分叉,而分叉的那一边往往是真机)。导航器**默认只过查看密码**:判据需要写
|
||||
路径权限时必须显式传 `modify=True`,**不因「能进去」就自动升格成可写**——只读判据偷偷拿到
|
||||
修改权限,等于把判据的边界让给了实现。
|
||||
|
||||
---
|
||||
## 变更记录
|
||||
|
||||
> (本文件不再记流水账:改了什么是正文说了算,改动过程查 git log。)
|
||||
|
||||
@@ -38,7 +38,7 @@ MCU **无物理屏幕**:LVGL 做 160×160 **1bpp 单色离屏渲染**,帧缓
|
||||
| LVGL 内存池 | 16 KB(`LV_MEM_SIZE`,2026-10-15 由 40 KB 收缩;实测峰值 6,568 B = 池的 40%) | `Lib/lv_conf.h` |
|
||||
| 刷新周期 | 10 ms(`ui_port_step(10)` + `osDelay(10)`) | `ui_task.c` |
|
||||
| 推流端口 | 7003(TCP,与 DTU-RemoteLCD 客户端对齐) | `ui_net_sink.h` |
|
||||
| 默认字体 | `ui_font_cn_12`(12px 1bpp,218 汉字/符号 + ASCII 0x20–0x7E,共 313 字形) | `Lib/lv_conf.h` |
|
||||
| 默认字体 | `ui_font_cn_12`(12px 1bpp,224 汉字/符号 + ASCII 0x20–0x7E,共 319 字形) | `Lib/lv_conf.h` |
|
||||
| uiTask 栈 | 16384 words(BelowNormal) | `Src/freertos.c` |
|
||||
|
||||
### 1.4 硬约束(改 UI 必须遵守)
|
||||
@@ -164,7 +164,7 @@ SDL 键盘 → LVGL SDL 驱动内部 5ms 定时器(sdl_event_handler)
|
||||
|
||||
### 4.2 数据:父子索引表
|
||||
|
||||
- `g_menu_tab[]`:42 节点,每项 = 名称 + parent 下标(`MENU_ROOT`=0xFF 为根);树序即表序
|
||||
- `g_menu_tab[]`:43 节点,每项 = 名称 + parent 下标(`MENU_ROOT`=0xFF 为根);树序即表序
|
||||
- "页" = 对表的一次过滤:节点 N 的页条目 = 全部 `parent == N` 的行(按表序)
|
||||
- 菜单 vs 叶子由"是否有子项"自动推导:`has_children(N)` 非空 → 菜单行(带 ▶),为空 → 叶子(无箭头,ENTER 进空白终点框)
|
||||
|
||||
@@ -236,7 +236,7 @@ ENTER/→ 进子框:
|
||||
|
||||
### 5.3 框按需建/销
|
||||
|
||||
- LVGL 池仅 16KB(`LV_MEM_SIZE`,2026-10-15 由 40KB 收缩),全量预建 42 个节点的所有页面必然爆内存
|
||||
- LVGL 池仅 16KB(`LV_MEM_SIZE`,2026-10-15 由 40KB 收缩),全量预建 43 个节点的所有页面必然爆内存
|
||||
- 只建"当前路径"上的框:行自绘无对象,池内存 = 屏上框体(实测根框 used=5,368 B、最深四级级联 used=6,040 B、网口设置保存态峰值 used=6,568 B = 池的 40%)
|
||||
- 返回即 `lv_obj_delete` 释放,内存随时回落到根框水位
|
||||
|
||||
@@ -288,7 +288,3 @@ ENTER/→ 进子框:
|
||||
- **残留暴露**(刻意不归本票):单个往返自身仍无上界(osMessageQueuePut(osWaitForever)
|
||||
+ xTaskNotifyWait(portMAX_DELAY)),netTask 若被单消息拖 >800ms,UI 位连击照成立——
|
||||
那是「判据抓对了人」,处置在 net 侧,不在心跳侧。
|
||||
|
||||
## 六、变更记录(简表)
|
||||
|
||||
> (本文件不再记流水账:改了什么是正文说了算,改动过程查 git log。)
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
说明:选中行(第 1 行)无 ▶ 箭头;其余行 ▶ 紧跟在 4 字文本后(非右对齐)。行内文字左对齐、左留白 8px。
|
||||
|
||||
## 三、字符集核对(对照当时(2026-09-03)的 ui_font_cn_12:78 汉字 + ASCII 0x20~0x7E;本 mockup 的核对结论只对该时点成立,现值 = 218 汉字/符号 + ASCII,共 313 字形,见 docs/UI设计/UI_中文字体生成与配置.md §7)
|
||||
## 三、字符集核对(对照当时(2026-09-03)的 ui_font_cn_12:78 汉字 + ASCII 0x20~0x7E;本 mockup 的核对结论只对该时点成立,现值 = 224 汉字/符号 + ASCII,共 319 字形,见 docs/UI设计/UI_中文字体生成与配置.md §7)
|
||||
|
||||
- **菜单 7 项**共 22 个唯一汉字:命中 21(装 置 信 息 实 时 数 据 参 定 值 遥 设 维 护 通 讯 记 录 查 询),**新增 1(三)**。
|
||||
- **状态行**"当前模式 : 无模式":**新增 5(当 前 模 式 无)** + **全角冒号 :(U+FF1A,新增)**;空格为 ASCII(已在字库)。
|
||||
|
||||
+1
-1
@@ -453,7 +453,7 @@ extern const content_page_def_t ui_page_device_info_desc; /* 描述符(Flash
|
||||
## 八、验证与回归
|
||||
|
||||
- **门禁**(`ui-verify` skill / `UI_自动化测试流程.md`):
|
||||
0) 模拟器构建 0 警告 → 1) 菜单 8 状态像素回归 + 池基线 → 2) 内容页文本断言 + 60 张黄金参考逐字节比对
|
||||
0) 模拟器构建 0 警告 → 1) 菜单 8 状态像素回归 + 池基线 → 2) 内容页文本断言 + 66 张黄金参考逐字节比对
|
||||
(网口设置 4 态 + 密码页 4 态等)+ 开页-关页往返水位 → 3) Keil 构建 0 错 0 警 → 4) 代码规范检查
|
||||
- **门禁常量**(脚本头部):`MENU_POOL_BASELINE = 5368 B`、`POOL_AFTER_ROUNDTRIP = 5448 B`
|
||||
- **失败处置**:像素不一致 = 代码 bug(修代码,**禁止**刷参考掩盖);**有意**改视觉 →
|
||||
|
||||
+18
-15
@@ -1,6 +1,6 @@
|
||||
# 菜单页面设计
|
||||
|
||||
> **用途**:定义 DTU 主菜单的**内容(42 节点层级树)、视觉规范、三层代码架构**(数据层 / 显示层 / 逻辑层),以及叶子节点进入后的**内容页模块**(§九)。
|
||||
> **用途**:定义 DTU 主菜单的**内容(43 节点层级树)、视觉规范、三层代码架构**(数据层 / 显示层 / 逻辑层),以及叶子节点进入后的**内容页模块**(§九)。
|
||||
> **范围**:菜单层级(节点/父子/层级/进出导航)+ 三个已实现的内容页(装置信息/交流量/直流量,§九);其余叶子的内容页后续按同模式扩展。
|
||||
> **来源**:用户提供的主菜单截图 7 屏(根页 + 实时数据/参数定值/三遥设置/装置维护/通讯参数/记录查询各一级子页 + 参数定值·整定二级)。
|
||||
> **导航模型**:树形**逐级进入**——`ENTER`/`→` 进入子页,`ESC`/`←` 返回上一级;最多 **4 级(主界面 → 三级菜单)**。
|
||||
@@ -37,7 +37,7 @@
|
||||
flowchart TD
|
||||
K(["按键(远端键 / 模拟器键)"]) --> L["逻辑层 ui_menu.c<br/>唯一 17 B 导航状态(path/选择/深度/滚动)<br/>键语义:移动 / 进入 / 退出"]
|
||||
L -- "单向驱动: frame_build / frame_destroy / frame_refresh / focus" --> V["显示层 ui_menu_view.c/h<br/>持全部 LVGL 对象,纯渲染,零导航状态"]
|
||||
L -- "只读查询: children / valid" --> T["数据层 ui_menu_tab.c/h(生成物,只读)<br/>g_menu_tab[42] 父子索引表 + 4 个查询 API"]
|
||||
L -- "只读查询: children / valid" --> T["数据层 ui_menu_tab.c/h(生成物,只读)<br/>g_menu_tab[43] 父子索引表 + 4 个查询 API"]
|
||||
V -- "只读查询: children / has_children / name" --> T
|
||||
```
|
||||
|
||||
@@ -127,7 +127,7 @@ sequenceDiagram
|
||||
|
||||
---
|
||||
|
||||
## 二、菜单内容:42 节点层级树
|
||||
## 二、菜单内容:43 节点层级树
|
||||
|
||||
### 2.1 层级总览
|
||||
|
||||
@@ -193,10 +193,11 @@ sequenceDiagram
|
||||
├─ 遥控记录 [叶子]
|
||||
├─ 自检记录 [叶子]
|
||||
├─ 运行记录 [叶子]
|
||||
└─ 运行报告 [叶子]
|
||||
├─ 运行报告 [叶子]
|
||||
└─ 录波回放 [叶子]
|
||||
```
|
||||
|
||||
**统计**:菜单节点 **9** 个(含根),叶子节点 **33** 个,共 **42** 个节点;最大深度 **4 级**。
|
||||
**统计**:菜单节点 **9** 个(含根),叶子节点 **34** 个,共 **43** 个节点;最大深度 **4 级**。
|
||||
|
||||
### 2.3 节点定义表(逻辑层级定义)
|
||||
|
||||
@@ -236,7 +237,7 @@ sequenceDiagram
|
||||
| 29 | 通讯设置 | 二级菜单 | 叶子 | 28 | 0 |
|
||||
| 30 | 网口设置 | 二级菜单 | 叶子 | 28 | 0 |
|
||||
| 31 | SNTP设置 | 二级菜单 | 叶子 | 28 | 0 |
|
||||
| 32 | 记录查询 | 一级菜单 | 菜单 | 0 | 9 |
|
||||
| 32 | 记录查询 | 一级菜单 | 菜单 | 0 | 10 |
|
||||
| 33 | SOE记录 | 二级菜单 | 叶子 | 32 | 0 |
|
||||
| 34 | 事故记录 | 二级菜单 | 叶子 | 32 | 0 |
|
||||
| 35 | 操作记录 | 二级菜单 | 叶子 | 32 | 0 |
|
||||
@@ -246,12 +247,13 @@ sequenceDiagram
|
||||
| 39 | 自检记录 | 二级菜单 | 叶子 | 32 | 0 |
|
||||
| 40 | 运行记录 | 二级菜单 | 叶子 | 32 | 0 |
|
||||
| 41 | 运行报告 | 二级菜单 | 叶子 | 32 | 0 |
|
||||
| 42 | 录波回放 | 二级菜单 | 叶子 | 32 | 0 |
|
||||
|
||||
---
|
||||
|
||||
## 三、数据层:ui_menu_tab(生成物,只读)
|
||||
|
||||
> **一句话职责**:提供"有什么条目"——一张扁平父子索引表(42 节点,`const` 存 Flash、只读)+ 4 个查询 API,供逻辑层 / 显示层共用。
|
||||
> **一句话职责**:提供"有什么条目"——一张扁平父子索引表(43 节点,`const` 存 Flash、只读)+ 4 个查询 API,供逻辑层 / 显示层共用。
|
||||
> **绝不做**:持有任何状态、依赖 LVGL、被手改(改菜单走 §3.6 生成器)。
|
||||
|
||||
### 3.1 选型:扁平"父子索引表"(邻接表 / 关系表模型)
|
||||
@@ -288,7 +290,7 @@ typedef struct {
|
||||
|
||||
> 实现落在生成器产物 `Drivers/BSP/UI/ui_menu_tab.h`(见 §3.6);字段/语义与此一致。
|
||||
|
||||
### 3.3 完整 42 节点表(按 §2.3 节点定义表落地)
|
||||
### 3.3 完整 43 节点表(按 §2.3 节点定义表落地)
|
||||
|
||||
> 产物 `ui_menu_tab.c`(§3.6 生成):`const ui_menu_node_t g_menu_tab[UI_MENU_TAB_COUNT]`,内容与下表一致。
|
||||
|
||||
@@ -337,10 +339,11 @@ const ui_menu_node_t g_menu_tab[UI_MENU_TAB_COUNT] = {
|
||||
{ 32, "自检记录" }, /* 39 二级菜单叶子 */
|
||||
{ 32, "运行记录" }, /* 40 二级菜单叶子 */
|
||||
{ 32, "运行报告" }, /* 41 二级菜单叶子 */
|
||||
{ 32, "录波回放" }, /* 42 二级菜单叶子 */
|
||||
};
|
||||
```
|
||||
|
||||
> `UI_MENU_TAB_COUNT`(=42)与 `MENU_ROOT` 在 `ui_menu_tab.h` 定义。
|
||||
> `UI_MENU_TAB_COUNT`(=43)与 `MENU_ROOT` 在 `ui_menu_tab.h` 定义。
|
||||
|
||||
### 3.4 查询 API(逻辑层 / 显示层共用)
|
||||
|
||||
@@ -392,14 +395,14 @@ for (uint8_t i = 0; i < cnt; i++) {
|
||||
| `ui_menu_tree.txt` | **人工编辑源**(缩进即层级);改菜单改这里 |
|
||||
| `tools/menu_gen/gen_menu.py` | 生成器(同 `make_font.py` 模式):解析缩进→推导 parent→产出 C 表;含根唯一/缩进对齐/层级上限自检 |
|
||||
| `Drivers/BSP/UI/ui_menu_tab.h` | 产物:`ui_menu_node_t` 定义 + `MENU_ROOT` + `UI_MENU_TAB_COUNT` + `extern g_menu_tab[]` |
|
||||
| `Drivers/BSP/UI/ui_menu_tab.c` | 产物:`g_menu_tab[UI_MENU_TAB_COUNT]` 完整 42 节点表 |
|
||||
| `Drivers/BSP/UI/ui_menu_tab.c` | 产物:`g_menu_tab[UI_MENU_TAB_COUNT]` 完整 43 节点表 |
|
||||
|
||||
重新生成:
|
||||
```
|
||||
python tools/menu_gen/gen_menu.py
|
||||
```
|
||||
|
||||
> 产物 `ui_menu_tab.c/.h` 含 42 节点(9 菜单 + 33 叶子,最深 三级菜单);`ui_menu.c` 不持有本地表,导航/显示一律走 `ui_menu_tab_*` 查询 API(§3.4)。
|
||||
> 产物 `ui_menu_tab.c/.h` 含 43 节点(9 菜单 + 34 叶子,最深 三级菜单;2026-10-29 录波道加两叶后由 42 升到 43);`ui_menu.c` 不持有本地表,导航/显示一律走 `ui_menu_tab_*` 查询 API(§3.4)。
|
||||
|
||||
> **编码陷阱(已踩)**:产物含中文**字符串字面量**,必须 **UTF-8 带 BOM**(同 `ui_menu.c`)。
|
||||
> 无 BOM 时 cl.exe(代码页 936/GBK)会按 GBK 误读 UTF-8 字节 → 字符串解析错乱(C2001/C4819)。`gen_menu.py` 已用 `utf-8-sig` 输出。
|
||||
@@ -421,9 +424,9 @@ python tools/menu_gen/gen_menu.py
|
||||
| 符号 | 定义处 | 内容 | 占用 |
|
||||
|---|---|---|---|
|
||||
| `ui_menu_node_t` | `ui_menu_tab.h` | `{ uint8_t parent; uint8_t pwd; const char *name; }`(32 位 8 B/项) | 类型定义 |
|
||||
| `g_menu_tab[UI_MENU_TAB_COUNT]` | `ui_menu_tab.c`(生成) | 42 节点扁平父子表 | ≈ 42×8 B ≈ 336 B |
|
||||
| 名字字面量 | 同上 | 42 个 `const char[]` | ≈ 400 B |
|
||||
| `UI_MENU_TAB_COUNT` / `MENU_ROOT` | `ui_menu_tab.h` | 节点数 42 / 根哨兵 0xFF(8 位,上限 255 项) | 宏 |
|
||||
| `g_menu_tab[UI_MENU_TAB_COUNT]` | `ui_menu_tab.c`(生成) | 43 节点扁平父子表 | ≈ 43×8 B ≈ 344 B |
|
||||
| 名字字面量 | 同上 | 43 个 `const char[]` | ≈ 400 B |
|
||||
| `UI_MENU_TAB_COUNT` / `MENU_ROOT` | `ui_menu_tab.h` | 节点数 43 / 根哨兵 0xFF(8 位,上限 255 项) | 宏 |
|
||||
|
||||
> 逻辑层/显示层**只读**它(§3.4 的 API 都是对它的过滤/查询),从不修改。合计 ≈ **0.7 KB Flash**。
|
||||
|
||||
@@ -792,7 +795,7 @@ ESC/LEFT : d>0 → menu_back() (根框 d=0 不响
|
||||
1. 本 LVGL v9.3 的 `lv_text_get_width(txt, length, font, letter_space)` **length=0 时返回 0**(不是"整串");必须传 `strlen`——否则框宽计算全 0(根框退化 8 px)。
|
||||
2. 无头模式**不得**调 `lv_timer_handler()` / `lv_refr_now()`:I1 + `LV_DISPLAY_RENDER_MODE_FULL` 全屏刷新会进渲染死循环(截图因此走 `lv_snapshot`);`--keys` 注键是同步处理,无需驱动帧。
|
||||
3. 选中行**保留 ▶**(随反色变黑):参考图 02/04 原图即"选中行箭头仍在、仅随反色变黑",勿实现成"选中隐箭头"(§4.4)。
|
||||
4. 字体缺字形 = 方框:菜单树新增/改名的汉字必须同步加入字符集 `ui_cn_chars.txt`(当前 218 唯一字,2026-10-28 实测)并重生成字体(重跑 `extract_cn.py` + `make_font.py`),否则新字显示为方框(流程见 `UI_中文字体生成与配置.md`)。
|
||||
4. 字体缺字形 = 方框:菜单树新增/改名的汉字必须同步加入字符集 `ui_cn_chars.txt`(当前 224 唯一字,2026-10-29 实测)并重生成字体(重跑 `extract_cn.py` + `make_font.py`),否则新字显示为方框(流程见 `UI_中文字体生成与配置.md`)。
|
||||
5. **参考图保真度**:参考图为手工 mockup,4 个样本(子框顶位置)不满足单一公式;实现采用自洽规则(顶对齐/底对齐上移),实测与参考图偏差:顶位置 2/4/6/1 px(三遥/装置维护/通讯参数/记录查询),框宽 2/8/0/2 px(4字+箭头/4字/3字/2字+箭头)。两端极例(三遥、记录查询)精确吻合;统一规则优于逐屏特调,偏差范围内不影响识读与操作。
|
||||
6. 装饰"浅 V"两腿线宽必须 3(水平线 2):1bpp 下细斜线边缘被阈值吃掉,腿不粗于水平线即消失;且依赖 `LV_DRAW_SW_COMPLEX=1`(见 `UI_设计架构.md` §1.4 约束 7)。
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
已绑定 6 页:`装置信息`(node 1)、`交流量`(3)、`直流量`(4)、`网口设置`(30)、`自检记录`(39)、`运行记录`(40)。
|
||||
|
||||
> ⚠ **本表 = 2026-10-25 立项时快照,按历史冻结不回改。** 2026-10-28 复扫现值:**已绑 28 叶 / 未绑 5 叶**(判据两处互证:`ui_menu_tree.txt` 剔掉文件头注释里的示例行后 `#page=` 实数 = 28,与生成物 `ui_page_registry.h` 的 `UI_PAGE_MAP_COUNT` 一致);未绑 5 叶 = 遥信类型 / 遥信防抖 / 双点遥信 / 手动录波 / SNTP 设置。现状口径见 `docs/任务规划/UI补齐.md` §1 与 `docs/产品需求/产品需求设计文档.md` §8.2 / §8.3。
|
||||
> ⚠ **本表 = 2026-10-25 立项时快照,按历史冻结不回改。** 2026-10-28 复扫现值:**已绑 28 叶 / 未绑 5 叶**;**2026-10-29 再复扫:已绑 30 叶 / 未绑 4 叶**(手动录波与录波回放两叶已绑)(判据两处互证:`ui_menu_tree.txt` 剔掉文件头注释里的示例行后 `#page=` 实数 = 30,与生成物 `ui_page_registry.h` 的 `UI_PAGE_MAP_COUNT` 一致);未绑 5 叶 = 遥信类型 / 遥信防抖 / 双点遥信 / 手动录波 / SNTP 设置。现状口径见 `docs/任务规划/UI补齐.md` §1 与 `docs/产品需求/产品需求设计文档.md` §8.2 / §8.3。
|
||||
|
||||
### 1.2 27 个空叶子清单(按菜单顺序)
|
||||
|
||||
@@ -542,7 +542,7 @@ void ui_w_soe_refresh(ui_w_soe_t *inst, uint16_t row, char *name, char *valu
|
||||
|
||||
## 5. 菜单树改动
|
||||
|
||||
**本批不改菜单树**——27 个空叶子全在现有 42 节点里,`#page=` 注记逐个补上即可(改 `ui_menu_tree.txt` 后重跑 `python tools/menu_gen/gen_menu.py`)。
|
||||
**本批不改菜单树**——当时 27 个空叶子全在现有 42 节点里(节点数现值 43,2026-10-29 录波道加「录波回放」叶),`#page=` 注记逐个补上即可(改 `ui_menu_tree.txt` 后重跑 `python tools/menu_gen/gen_menu.py`)。
|
||||
|
||||
> 【2026-10-26 已改一笔】整定 4 叶(参数 / 定值 / 控制字 / 软压板)已补 `#page=`,
|
||||
> 绑的是与查看列**同一批模块**(一个模块被两个叶子绑定是生成器允许的,`validate_pages()` 按
|
||||
@@ -626,7 +626,7 @@ SNTP 客户端 ──────→ 批4 SNTP设置
|
||||
| 4 | 无源点显示 `--` | 遥信量无效点、直流量直流通道 |
|
||||
| 5 | 定值整定闭环 | 改 → 保存 → 重启 → 值保持 + 校验和自检通过 + 主站 C_RD 一致。**2026-10-26 半收口**:模拟器侧「改 → 保存 → `OK` → 回首屏新值已在帧里」与「越界被拒、值不落盘」已由像素 + 文本断言覆盖(`sparam_save` / `sparam_landed` / `sparam_oob`);**重启保持与 C_RD 一致只能上板**(模拟器无 NAND)。另注意 40 项里 **13 项 `comm_addr = 0`**(投退、返回系数、过频/低频段、全局软压板)主站不可寻址,不能拿 C_RD 当它们的判据 |
|
||||
| 6 | 分层门禁无新增 | `check_layer_deps.py` 退出码 0,基线 6 → 3。**现状:3**(记录 reader 已削 3 条;写路径走注入式 ops 函数表,未新增 include,见 `docs/UI设计/UI_数据供给设计说明.md` §6.2) |
|
||||
| 7 | 像素回归稳定 | `ui-golden` 连续两次零差异。**已验(2026-10-26)**:27 页连跑两次逐字节一致——**该下限此后已扩至 60 张**(新增 clock / reset / clear 系列 13 张,其后 47→53→60),60 张上的双次逐字节一致需按同口径重跑一次再回填本行 |
|
||||
| 7 | 像素回归稳定 | `ui-golden` 连续两次零差异。**已验(2026-10-26)**:27 页连跑两次逐字节一致——**该下限此后已扩至 66 张**(新增 clock / reset / clear 系列 13 张,其后 47→53→60→66,2026-10-29 录波 UI 道 +6 张),66 张上的双次逐字节一致**已验(2026-10-29:任务树重建模拟器后同一批 66 张连跑三次逐字节一致,页面池水位 5,448 B;菜单侧 `check_menu_rows.py` 8 状态连跑三次亦逐字节一致,5,368 B;三次之间未用更新模式写过任何参考图,故这是同口径的传递性证据)** |
|
||||
| 8 | 每个新页有 golden 参考 | `simulator/tests/ref/` 新增对应 `.bin`。**整定 4 页已有 9 张**(含保存/越界/落定/回绕各态);参考图入库,改它 = 改判据,须逐页过目 |
|
||||
|
||||
---
|
||||
|
||||
+9
-7
@@ -1,6 +1,7 @@
|
||||
# UI 页面补齐规划(2026-10-23)
|
||||
|
||||
> **定位**:盘清 42 节点菜单里**还没有内容页的 27 个叶子**,按"数据是否就绪 + 页面形态"归并成可施工的包,给出分批顺序与每页规格。
|
||||
> **定位**:盘清当时 42 节点菜单里**还没有内容页的 27 个叶子**(节点数现值 43 = 9 菜单 + 34 叶,
|
||||
> 2026-10-29 录波道加「录波回放」叶后升级;本文其余数字是 2026-10-23 立项快照,按 §1 的「完成即冻结」不回改),按"数据是否就绪 + 页面形态"归并成可施工的包,给出分批顺序与每页规格。
|
||||
> **前置阅读**:`docs/UI设计/内容页架构.md`(框架机制与新增页面六步)、`docs/UI设计/菜单页面设计.md`(菜单树与几何)、`docs/UI设计/UI_自动化测试流程.md`(像素回归门禁)。
|
||||
> **不重复登记**:页面级待办落地时按语义标识进 `docs/任务规划/登记簿.md`;本文只出规划与规格。
|
||||
> **逐页细化**:每页显示哪些行、数据从哪来、要改哪些代码,见 `docs/UI设计/页面扩充详细方案.md`(本文的落地细化版)。
|
||||
@@ -27,7 +28,7 @@
|
||||
### 2.1 规模
|
||||
|
||||
> ⚠ **本表是 2026-10-23 立项当天快照**(节点 42 / 有内容页叶子 6 / 空叶子 27 / 黄金参考 11 份均为当日实数,按"完成即冻结"不回改)。
|
||||
> 页面扩充落地后现值已变——黄金参考现为 60 份(`simulator/tests/ref/` 入库的 `shot_*.bin` 实数,2026-10-28 记录 5 页与运行报告页落地 +7 张),现状口径见
|
||||
> 页面扩充落地后现值已变——黄金参考现为 66 份(`simulator/tests/ref/` 入库的 `shot_*.bin` 实数,2026-10-28 记录 5 页与运行报告页落地 +7 张;2026-10-29 录波 UI 道 +6 张),现状口径见
|
||||
> `docs/UI设计/页面扩充详细方案.md` 与 `docs/UI设计/UI_数据供给设计说明.md`。
|
||||
|
||||
| 项 | 数 |
|
||||
@@ -77,7 +78,7 @@
|
||||
| 22 | 双点遥信 | 可编辑列表 | 开入量 | ❌ 同上 |
|
||||
| 24 | 时钟设置 | 表单(6 字段) | `sys_clock_get_time/set` | ✅ |
|
||||
| 25 | 强制复归 | 操作页(确认) | `prot_elm_request_reset()` | ✅ |
|
||||
| 26 | 手动录波 | 操作页(确认) | 录波模块(docs/任务规划/故障录波.md 已立项) | 🔶 录波立项未落地 |
|
||||
| 26 | 手动录波 | 操作页(确认) | `wave_ring_request` 手动触发经 `ui_data_wave_ops_t` 注入 | ✅ 已落地(`ui_page_wave_manual.c`,2026-10-29 录波 UI 道;配套新增「录波回放」叶 node 43 = `ui_page_wave_play.c`,不在本表 27 叶之列) |
|
||||
| 27 | 清除记录 | 操作页(选类型 + 确认) | `sys_log`(**缺删除 API**) | 🔶 需补 API |
|
||||
| 29 | 通讯设置 | 可编辑列表(4~6 项) | 104 公共地址/端口/主站(当前固定) | 🔶 需 `comm_cfg` |
|
||||
| 31 | SNTP设置 | 可编辑列表(3 项) | SNTP 客户端 | ❌ 未实现(产品口径亦未定) |
|
||||
@@ -91,7 +92,8 @@
|
||||
|
||||
**统计(2026-10-25 复核)**:本表 27 叶中 **6 叶已落地**(遥信量 / 查看 4 页 / SOE),剩 21 叶 = 数据现成 **8** 项(整定 4 + 时钟 + 复归 + 死区 + 系数)· 需新数据层 **2** 项(清除记录 / 通讯设置)· 数据源不存在 **11** 项(遥信 3 + 手动录波 + SNTP + 记录 5 + 运行报告)。**分批与 DoD 见 `docs/任务规划/UI补齐.md`**——本表只讲逐页形态与数据源,不重复排期。
|
||||
|
||||
**2026-10-28 复核**:本表 27 叶中 **22 叶已落地**(本批 +6:记录 5 页与运行报告,见 docs/任务规划/UI补齐.md §2 与 docs/任务规划/登记簿.md §7);未落地的 5 叶 = 遥信类型 / 遥信防抖 / 双点遥信(无开入硬件)+ 手动录波(无录波模块)+ SNTP设置(产品口径未定),取舍与重开条件见 docs/任务规划/UI补齐.md §5。口径闭合:本表 22 叶 + 立项前就已绑定、不在本表内的 6 叶(装置信息 / 交流量 / 直流量 / 网口设置 / 自检记录 / 运行记录)= 现值已绑 28 叶(= UI_PAGE_MAP_COUNT);本表未落地 5 叶 = 菜单树未绑 5 叶(33 − 28)。复核方法:按缩进判叶子(有更深缩进后继者即非叶子),再按行内 #page= 数已绑。**2026-10-29 补充**:「手动录波」已随故障录波独立立项(docs/任务规划/故障录波.md 与 docs/子系统设计/故障录波设计说明.md),上面那行数字仍是 2026-10-28 当日复核值,未随立项改动
|
||||
**2026-10-28 复核**:本表 27 叶中 **22 叶已落地**(本批 +6:记录 5 页与运行报告,见 docs/任务规划/UI补齐.md §2 与 docs/任务规划/登记簿.md §7);未落地的 5 叶 = 遥信类型 / 遥信防抖 / 双点遥信(无开入硬件)+ 手动录波(无录波模块)+ SNTP设置(产品口径未定),取舍与重开条件见 docs/任务规划/UI补齐.md §5。口径闭合:本表 22 叶 + 立项前就已绑定、不在本表内的 6 叶(装置信息 / 交流量 / 直流量 / 网口设置 / 自检记录 / 运行记录)= 现值已绑 28 叶(= UI_PAGE_MAP_COUNT);本表未落地 5 叶 = 菜单树未绑 5 叶(33 − 28)。复核方法:按缩进判叶子(有更深缩进后继者即非叶子),再按行内 #page= 数已绑。**2026-10-29 补充**:「手动录波」已随故障录波独立立项(docs/任务规划/故障录波.md 与 docs/子系统设计/故障录波设计说明.md),上面那行数字仍是 2026-10-28 当日复核值,未随立项改动。
|
||||
**2026-10-29 二补(录波 UI 道落地)**:本表「手动录波」转已落地(23 叶);菜单树另新增「录波回放」叶(node 43,不在本表立项快照内)——现值 43 节点 / 34 叶 / 已绑 30 / 未绑 4(= 遥信 3 + SNTP 1,UI_PAGE_MAP_COUNT = 30),口径复核方法与上一段相同
|
||||
|
||||
---
|
||||
|
||||
@@ -211,7 +213,7 @@ ui_page_ac / ui_page_yx / ui_page_setlist ...
|
||||
|
||||
12. **三遥设置 5 页**(18~22)——等运行参数段与开入量。
|
||||
13. **事故/操作/告警/启动/遥控 5 页**(34~38)——等记录写入方(每类记录 = 一个写入点 + 一个 `syslog_id_t`)。
|
||||
14. **手动录波**(26)——等录波模块。
|
||||
14. **手动录波**(26):操作页(`ui_page_action` 确认链,受理后回「已请求录波」)——已落地(2026-10-29);同批新增「录波回放」单页(上下键切通道、左右键切段、阶梯线 3px/点、0 线虚线、峰值 mV 经 `wave_store_code_to_milli` 唯一口径、削徽标、空态/坏段显式文案,规格见 docs/子系统设计/故障录波设计说明.md §8.1)。
|
||||
15. **运行报告**(41)——等计数器(上电次数/运行时长/复位原因/104 统计)。
|
||||
|
||||
### 批 4(可选):厂家设置
|
||||
@@ -253,7 +255,7 @@ ui_page_ac / ui_page_yx / ui_page_setlist ...
|
||||
|
||||
> **虚拟注入的价值**:当前送检等标准源(B10),而虚拟注入能让"改一个假值 → 看 UI 是否变 → 看 104 是否上送 → 看 SOE 是否记录"这条链在没有硬件激励的情况下闭环。它是**测试基础设施**,不是产品功能,建议放在厂家菜单并加明显标识(标题后缀"调试")。
|
||||
>
|
||||
> **代价**:菜单树从 42 节点扩到约 48~50 节点,`ui_menu_tree.txt` 改动会触发菜单 8 状态像素回归与 `task-table` 式索引文档同步。**这是需要拍板的项**——见 §8。
|
||||
> **代价**:菜单树从当时 42 节点扩到约 48~50 节点(节点数现值 43,2026-10-29 录波道加「录波回放」叶),`ui_menu_tree.txt` 改动会触发菜单 8 状态像素回归与 `task-table` 式索引文档同步。**这是需要拍板的项**——见 §8。
|
||||
|
||||
---
|
||||
|
||||
@@ -261,7 +263,7 @@ ui_page_ac / ui_page_yx / ui_page_setlist ...
|
||||
|
||||
| # | 问题 | 影响 |
|
||||
|---|---|---|
|
||||
| 1 | 菜单是否扩到 48~50 节点(加厂家设置支)? | 42 是产品需求里的硬数字;扩了要改 `产品需求设计文档.md` §8.2 与菜单像素回归 |
|
||||
| 1 | 菜单是否扩到 48~50 节点(加厂家设置支)? | 节点数以 `产品需求设计文档.md` §8.2 为准(2026-10-29 现值 43,此前 42);扩了要改该节与菜单像素回归 |
|
||||
| 2 | **直流量页怎么办?**(V0.1 没有直流采样通道)三选一:改成"温度 + 备用"页 / 从菜单删掉 / 保留空页显示 `--` | 决定行表与菜单节点数 |
|
||||
| 3 | 定值名用全称还是缩写?(字体子集大小 vs 可读性) | 40 条名 × 平均字数,直接影响字库与 `font-charset` |
|
||||
| 4 | 事故/操作/告警/启动/遥控 5 类记录,是否本轮就要? | 每类 = 一个写入方 + 一个 `syslog_id_t` + 一个页面,是本规划里最大的一块后端工作 |
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,235 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="990" height="784" viewBox="0 0 990 784" font-family="Microsoft YaHei, Segoe UI, PingFang SC, sans-serif">
|
||||
<rect width="990" height="784" fill="#ffffff"/>
|
||||
<text x="28.0" y="40.0" font-size="17" fill="#0f172a" font-weight="bold" text-anchor="start">菜单树总览(层级 · 绑页 · 密码门)</text>
|
||||
<text x="28.0" y="61.0" font-size="11" fill="#475569" font-weight="normal" text-anchor="start">方框 = 菜单(可展开);细线 = 叶(对应一个页面模块,或一处空缺)</text>
|
||||
<rect x="138.0" y="87.0" width="486.0" height="18.0" rx="6" fill="#f8fafc" stroke="none" stroke-width="0"/>
|
||||
<rect x="138.0" y="105.0" width="486.0" height="54.0" rx="6" fill="#ffffff" stroke="none" stroke-width="0"/>
|
||||
<rect x="138.0" y="159.0" width="486.0" height="144.0" rx="6" fill="#f8fafc" stroke="none" stroke-width="0"/>
|
||||
<rect x="138.0" y="303.0" width="486.0" height="90.0" rx="6" fill="#ffffff" stroke="none" stroke-width="0"/>
|
||||
<rect x="138.0" y="393.0" width="486.0" height="72.0" rx="6" fill="#f8fafc" stroke="none" stroke-width="0"/>
|
||||
<rect x="138.0" y="465.0" width="486.0" height="54.0" rx="6" fill="#ffffff" stroke="none" stroke-width="0"/>
|
||||
<rect x="138.0" y="519.0" width="486.0" height="180.0" rx="6" fill="#f8fafc" stroke="none" stroke-width="0"/>
|
||||
<rect x="296.0" y="159.0" width="328.0" height="72.0" rx="5" fill="#f5f3ff" stroke="none" stroke-width="0"/>
|
||||
<rect x="296.0" y="231.0" width="328.0" height="72.0" rx="5" fill="#f5f3ff" stroke="none" stroke-width="0"/>
|
||||
<line x1="128.0" y1="96.0" x2="128.0" y2="609.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="85.0" y1="352.5" x2="128.0" y2="352.5" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="128.0" y1="96.0" x2="153.0" y2="96.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="128.0" y1="132.0" x2="150.0" y2="132.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="128.0" y1="231.0" x2="150.0" y2="231.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="128.0" y1="348.0" x2="150.0" y2="348.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="128.0" y1="429.0" x2="150.0" y2="429.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="128.0" y1="492.0" x2="150.0" y2="492.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="128.0" y1="609.0" x2="150.0" y2="609.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="114.0" x2="284.0" y2="150.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="216.0" y1="132.0" x2="284.0" y2="132.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="114.0" x2="309.0" y2="114.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="132.0" x2="309.0" y2="132.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="150.0" x2="309.0" y2="150.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="195.0" x2="284.0" y2="267.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="216.0" y1="231.0" x2="284.0" y2="231.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="195.0" x2="306.0" y2="195.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="267.0" x2="306.0" y2="267.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="452.0" y1="168.0" x2="452.0" y2="222.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="348.0" y1="195.0" x2="452.0" y2="195.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="452.0" y1="168.0" x2="477.0" y2="168.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="452.0" y1="186.0" x2="477.0" y2="186.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="452.0" y1="204.0" x2="477.0" y2="204.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="452.0" y1="222.0" x2="477.0" y2="222.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="452.0" y1="240.0" x2="452.0" y2="294.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="348.0" y1="267.0" x2="452.0" y2="267.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="452.0" y1="240.0" x2="477.0" y2="240.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="452.0" y1="258.0" x2="477.0" y2="258.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="452.0" y1="276.0" x2="477.0" y2="276.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="452.0" y1="294.0" x2="477.0" y2="294.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="312.0" x2="284.0" y2="384.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="216.0" y1="348.0" x2="284.0" y2="348.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="312.0" x2="309.0" y2="312.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="330.0" x2="309.0" y2="330.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="348.0" x2="309.0" y2="348.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="366.0" x2="309.0" y2="366.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="384.0" x2="309.0" y2="384.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="402.0" x2="284.0" y2="456.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="216.0" y1="429.0" x2="284.0" y2="429.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="402.0" x2="309.0" y2="402.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="420.0" x2="309.0" y2="420.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="438.0" x2="309.0" y2="438.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="456.0" x2="309.0" y2="456.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="474.0" x2="284.0" y2="510.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="216.0" y1="492.0" x2="284.0" y2="492.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="474.0" x2="309.0" y2="474.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="492.0" x2="309.0" y2="492.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="510.0" x2="309.0" y2="510.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="528.0" x2="284.0" y2="690.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="216.0" y1="609.0" x2="284.0" y2="609.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="528.0" x2="309.0" y2="528.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="546.0" x2="309.0" y2="546.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="564.0" x2="309.0" y2="564.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="582.0" x2="309.0" y2="582.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="600.0" x2="309.0" y2="600.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="618.0" x2="309.0" y2="618.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="636.0" x2="309.0" y2="636.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="654.0" x2="309.0" y2="654.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="672.0" x2="309.0" y2="672.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<line x1="284.0" y1="690.0" x2="309.0" y2="690.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<rect x="28.0" y="339.5" width="57.0" height="26.0" rx="5" fill="#eff6ff" stroke="#1d4ed8" stroke-width="1.2"/>
|
||||
<text x="56.5" y="357.2" font-size="13" fill="#1d4ed8" font-weight="bold" text-anchor="middle">主界面</text>
|
||||
<rect x="150.0" y="121.0" width="66.0" height="22.0" rx="5" fill="#ffffff" stroke="#334155" stroke-width="1.2"/>
|
||||
<text x="183.0" y="136.3" font-size="12" fill="#0f172a" font-weight="bold" text-anchor="middle">实时数据</text>
|
||||
<rect x="150.0" y="220.0" width="66.0" height="22.0" rx="5" fill="#ffffff" stroke="#334155" stroke-width="1.2"/>
|
||||
<text x="183.0" y="235.3" font-size="12" fill="#0f172a" font-weight="bold" text-anchor="middle">参数定值</text>
|
||||
<rect x="306.0" y="185.0" width="42.0" height="20.0" rx="5" fill="#ffffff" stroke="#6d28d9" stroke-width="1.2"/>
|
||||
<text x="327.0" y="199.3" font-size="12" fill="#6d28d9" font-weight="bold" text-anchor="middle">整定</text>
|
||||
<rect x="306.0" y="257.0" width="42.0" height="20.0" rx="5" fill="#ffffff" stroke="#6d28d9" stroke-width="1.2"/>
|
||||
<text x="327.0" y="271.3" font-size="12" fill="#6d28d9" font-weight="bold" text-anchor="middle">查看</text>
|
||||
<rect x="150.0" y="337.0" width="66.0" height="22.0" rx="5" fill="#ffffff" stroke="#334155" stroke-width="1.2"/>
|
||||
<text x="183.0" y="352.3" font-size="12" fill="#0f172a" font-weight="bold" text-anchor="middle">三遥设置</text>
|
||||
<rect x="150.0" y="418.0" width="66.0" height="22.0" rx="5" fill="#ffffff" stroke="#334155" stroke-width="1.2"/>
|
||||
<text x="183.0" y="433.3" font-size="12" fill="#0f172a" font-weight="bold" text-anchor="middle">装置维护</text>
|
||||
<rect x="150.0" y="481.0" width="66.0" height="22.0" rx="5" fill="#ffffff" stroke="#334155" stroke-width="1.2"/>
|
||||
<text x="183.0" y="496.3" font-size="12" fill="#0f172a" font-weight="bold" text-anchor="middle">通讯参数</text>
|
||||
<rect x="150.0" y="598.0" width="66.0" height="22.0" rx="5" fill="#ffffff" stroke="#334155" stroke-width="1.2"/>
|
||||
<text x="183.0" y="613.3" font-size="12" fill="#0f172a" font-weight="bold" text-anchor="middle">记录查询</text>
|
||||
<line x1="152.0" y1="96.0" x2="159.0" y2="96.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="164.0" y="100.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">装置信息</text>
|
||||
<text x="222.0" y="99.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">device_info</text>
|
||||
<line x1="308.0" y1="114.0" x2="315.0" y2="114.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="320.0" y="118.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">交流量</text>
|
||||
<text x="366.0" y="117.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">ac</text>
|
||||
<line x1="308.0" y1="132.0" x2="315.0" y2="132.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="320.0" y="136.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">直流量</text>
|
||||
<text x="366.0" y="135.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">dc</text>
|
||||
<line x1="308.0" y1="150.0" x2="315.0" y2="150.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="320.0" y="154.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">遥信量</text>
|
||||
<text x="366.0" y="153.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">yx</text>
|
||||
<line x1="476.0" y1="168.0" x2="483.0" y2="168.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="488.0" y="172.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">参数</text>
|
||||
<text x="522.0" y="171.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">view_param</text>
|
||||
<text x="583.2" y="171.5" font-size="9" fill="#b45309" font-weight="bold" text-anchor="start">P</text>
|
||||
<line x1="476.0" y1="186.0" x2="483.0" y2="186.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="488.0" y="190.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">定值</text>
|
||||
<text x="522.0" y="189.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">view_set</text>
|
||||
<text x="572.8" y="189.5" font-size="9" fill="#b45309" font-weight="bold" text-anchor="start">P</text>
|
||||
<line x1="476.0" y1="204.0" x2="483.0" y2="204.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="488.0" y="208.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">控制字</text>
|
||||
<text x="534.0" y="207.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">view_word</text>
|
||||
<text x="590.0" y="207.5" font-size="9" fill="#b45309" font-weight="bold" text-anchor="start">P</text>
|
||||
<line x1="476.0" y1="222.0" x2="483.0" y2="222.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="488.0" y="226.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">软压板</text>
|
||||
<text x="534.0" y="225.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">view_plate</text>
|
||||
<text x="595.2" y="225.5" font-size="9" fill="#b45309" font-weight="bold" text-anchor="start">P</text>
|
||||
<line x1="476.0" y1="240.0" x2="483.0" y2="240.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="488.0" y="244.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">参数</text>
|
||||
<text x="522.0" y="243.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">view_param</text>
|
||||
<line x1="476.0" y1="258.0" x2="483.0" y2="258.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="488.0" y="262.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">定值</text>
|
||||
<text x="522.0" y="261.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">view_set</text>
|
||||
<line x1="476.0" y1="276.0" x2="483.0" y2="276.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="488.0" y="280.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">控制字</text>
|
||||
<text x="534.0" y="279.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">view_word</text>
|
||||
<line x1="476.0" y1="294.0" x2="483.0" y2="294.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="488.0" y="298.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">软压板</text>
|
||||
<text x="534.0" y="297.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">view_plate</text>
|
||||
<line x1="308.0" y1="312.0" x2="315.0" y2="312.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="320.0" y="316.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">遥测死区</text>
|
||||
<text x="378.0" y="315.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">deadband</text>
|
||||
<text x="428.8" y="315.5" font-size="9" fill="#b45309" font-weight="bold" text-anchor="start">P</text>
|
||||
<line x1="308.0" y1="330.0" x2="315.0" y2="330.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="320.0" y="334.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">遥测系数</text>
|
||||
<text x="378.0" y="333.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">calib</text>
|
||||
<text x="413.1" y="333.5" font-size="9" fill="#b45309" font-weight="bold" text-anchor="start">P</text>
|
||||
<line x1="308.0" y1="348.0" x2="315.0" y2="348.0" stroke="#be123c" stroke-width="1.2" stroke-dasharray="3,2"/>
|
||||
<text x="320.0" y="352.0" font-size="12" fill="#be123c" font-weight="normal" text-anchor="start">遥信类型</text>
|
||||
<text x="377.0" y="351.5" font-size="9" fill="#b45309" font-weight="bold" text-anchor="start">P</text>
|
||||
<line x1="308.0" y1="366.0" x2="315.0" y2="366.0" stroke="#be123c" stroke-width="1.2" stroke-dasharray="3,2"/>
|
||||
<text x="320.0" y="370.0" font-size="12" fill="#be123c" font-weight="normal" text-anchor="start">遥信防抖</text>
|
||||
<text x="377.0" y="369.5" font-size="9" fill="#b45309" font-weight="bold" text-anchor="start">P</text>
|
||||
<line x1="308.0" y1="384.0" x2="315.0" y2="384.0" stroke="#be123c" stroke-width="1.2" stroke-dasharray="3,2"/>
|
||||
<text x="320.0" y="388.0" font-size="12" fill="#be123c" font-weight="normal" text-anchor="start">双点遥信</text>
|
||||
<text x="377.0" y="387.5" font-size="9" fill="#b45309" font-weight="bold" text-anchor="start">P</text>
|
||||
<line x1="308.0" y1="402.0" x2="315.0" y2="402.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="320.0" y="406.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">时钟设置</text>
|
||||
<text x="378.0" y="405.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">clock</text>
|
||||
<text x="413.1" y="405.5" font-size="9" fill="#b45309" font-weight="bold" text-anchor="start">P</text>
|
||||
<line x1="308.0" y1="420.0" x2="315.0" y2="420.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="320.0" y="424.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">强制复归</text>
|
||||
<text x="378.0" y="423.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">reset</text>
|
||||
<text x="413.1" y="423.5" font-size="9" fill="#b45309" font-weight="bold" text-anchor="start">P</text>
|
||||
<rect x="307.0" y="429.5" width="71.0" height="17.0" rx="4" fill="#f0fdf4" stroke="#15803d" stroke-width="0.9"/>
|
||||
<line x1="308.0" y1="438.0" x2="315.0" y2="438.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="320.0" y="442.0" font-size="12" fill="#15803d" font-weight="normal" text-anchor="start">手动录波</text>
|
||||
<text x="378.0" y="441.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">wave_manual</text>
|
||||
<text x="444.4" y="441.5" font-size="9" fill="#b45309" font-weight="bold" text-anchor="start">P</text>
|
||||
<line x1="308.0" y1="456.0" x2="315.0" y2="456.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="320.0" y="460.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">清除记录</text>
|
||||
<text x="378.0" y="459.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">clear</text>
|
||||
<text x="413.1" y="459.5" font-size="9" fill="#b45309" font-weight="bold" text-anchor="start">P</text>
|
||||
<line x1="308.0" y1="474.0" x2="315.0" y2="474.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="320.0" y="478.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">通讯设置</text>
|
||||
<text x="378.0" y="477.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">comm</text>
|
||||
<text x="407.9" y="477.5" font-size="9" fill="#b45309" font-weight="bold" text-anchor="start">P</text>
|
||||
<line x1="308.0" y1="492.0" x2="315.0" y2="492.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="320.0" y="496.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">网口设置</text>
|
||||
<text x="378.0" y="495.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">net_cfg</text>
|
||||
<text x="423.5" y="495.5" font-size="9" fill="#b45309" font-weight="bold" text-anchor="start">P</text>
|
||||
<line x1="308.0" y1="510.0" x2="315.0" y2="510.0" stroke="#be123c" stroke-width="1.2" stroke-dasharray="3,2"/>
|
||||
<text x="320.0" y="514.0" font-size="12" fill="#be123c" font-weight="normal" text-anchor="start">SNTP设置</text>
|
||||
<text x="380.8" y="513.5" font-size="9" fill="#b45309" font-weight="bold" text-anchor="start">P</text>
|
||||
<line x1="308.0" y1="528.0" x2="315.0" y2="528.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="320.0" y="532.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">SOE记录</text>
|
||||
<text x="374.9" y="531.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">soe</text>
|
||||
<line x1="308.0" y1="546.0" x2="315.0" y2="546.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="320.0" y="550.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">事故记录</text>
|
||||
<text x="378.0" y="549.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">accident</text>
|
||||
<line x1="308.0" y1="564.0" x2="315.0" y2="564.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="320.0" y="568.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">操作记录</text>
|
||||
<text x="378.0" y="567.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">oper</text>
|
||||
<line x1="308.0" y1="582.0" x2="315.0" y2="582.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="320.0" y="586.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">保护告警</text>
|
||||
<text x="378.0" y="585.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">alarm</text>
|
||||
<line x1="308.0" y1="600.0" x2="315.0" y2="600.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="320.0" y="604.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">保护启动</text>
|
||||
<text x="378.0" y="603.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">start</text>
|
||||
<line x1="308.0" y1="618.0" x2="315.0" y2="618.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="320.0" y="622.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">遥控记录</text>
|
||||
<text x="378.0" y="621.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">yk</text>
|
||||
<line x1="308.0" y1="636.0" x2="315.0" y2="636.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="320.0" y="640.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">自检记录</text>
|
||||
<text x="378.0" y="639.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">selftest</text>
|
||||
<line x1="308.0" y1="654.0" x2="315.0" y2="654.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="320.0" y="658.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">运行记录</text>
|
||||
<text x="378.0" y="657.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">runlog</text>
|
||||
<line x1="308.0" y1="672.0" x2="315.0" y2="672.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="320.0" y="676.0" font-size="12" fill="#0f172a" font-weight="normal" text-anchor="start">运行报告</text>
|
||||
<text x="378.0" y="675.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">runreport</text>
|
||||
<rect x="307.0" y="681.5" width="71.0" height="17.0" rx="4" fill="#f0fdf4" stroke="#15803d" stroke-width="0.9"/>
|
||||
<line x1="308.0" y1="690.0" x2="315.0" y2="690.0" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="320.0" y="694.0" font-size="12" fill="#15803d" font-weight="normal" text-anchor="start">录波回放</text>
|
||||
<text x="378.0" y="693.5" font-size="9" fill="#94a3b8" font-weight="normal" text-anchor="start">wave_play</text>
|
||||
<rect x="624.0" y="72.0" width="350.0" height="413.0" rx="8" fill="#ffffff" stroke="#cbd5e1" stroke-width="1.2"/>
|
||||
<text x="640.0" y="102.0" font-size="12.5" fill="#0f172a" font-weight="bold" text-anchor="start">本图读数</text>
|
||||
<text x="640.0" y="125.0" font-size="10.5" fill="#475569" font-weight="normal" text-anchor="start">节点 43 = 菜单 9 + 叶 34</text>
|
||||
<text x="640.0" y="143.0" font-size="10.5" fill="#475569" font-weight="normal" text-anchor="start">已绑页 30 · 未绑页 4 · 密码门 16 叶</text>
|
||||
<text x="640.0" y="161.0" font-size="10.5" fill="#475569" font-weight="normal" text-anchor="start">最深 4 级(主界面 → 叶)</text>
|
||||
<text x="640.0" y="193.0" font-size="12.5" fill="#0f172a" font-weight="bold" text-anchor="start">怎么看</text>
|
||||
<rect x="640.0" y="206.0" width="15.0" height="12.0" rx="3" fill="#eff6ff" stroke="#1d4ed8" stroke-width="1.0"/>
|
||||
<text x="662.0" y="216.0" font-size="10.5" fill="#475569" font-weight="normal" text-anchor="start">根:主界面本身,不是一个页面</text>
|
||||
<rect x="640.0" y="224.0" width="15.0" height="12.0" rx="3" fill="#ffffff" stroke="#334155" stroke-width="1.0"/>
|
||||
<text x="662.0" y="234.0" font-size="10.5" fill="#475569" font-weight="normal" text-anchor="start">白框:一级菜单,可展开、不绑页</text>
|
||||
<rect x="640.0" y="242.0" width="15.0" height="12.0" rx="3" fill="#f5f3ff" stroke="#6d28d9" stroke-width="1.0"/>
|
||||
<text x="662.0" y="252.0" font-size="10.5" fill="#475569" font-weight="normal" text-anchor="start">紫底:二级菜单与它那一支的行带</text>
|
||||
<rect x="640.0" y="260.0" width="15.0" height="12.0" rx="3" fill="#f0fdf4" stroke="#15803d" stroke-width="1.0"/>
|
||||
<text x="662.0" y="270.0" font-size="10.5" fill="#475569" font-weight="normal" text-anchor="start">绿底:录波两叶,已绑页面模块</text>
|
||||
<rect x="640.0" y="278.0" width="15.0" height="12.0" rx="3" fill="#ffffff" stroke="#be123c" stroke-width="1.0"/>
|
||||
<line x1="640.0" y1="284.0" x2="655.0" y2="284.0" stroke="#be123c" stroke-width="1.0" stroke-dasharray="3,2"/>
|
||||
<text x="662.0" y="288.0" font-size="10.5" fill="#475569" font-weight="normal" text-anchor="start">红字 + 虚线:未绑页的叶,进去只有菜单</text>
|
||||
<text x="640.0" y="306.0" font-size="10.5" fill="#475569" font-weight="normal" text-anchor="start">灰色小字 = 页面模块名(页面注册表的键)</text>
|
||||
<text x="640.0" y="324.0" font-size="10.5" fill="#475569" font-weight="normal" text-anchor="start">行末的 P = 进这一叶要先过密码</text>
|
||||
<text x="640.0" y="342.0" font-size="10.5" fill="#475569" font-weight="normal" text-anchor="start">整定 与 查看 复用同一批页面模块</text>
|
||||
<text x="640.0" y="374.0" font-size="12.5" fill="#0f172a" font-weight="bold" text-anchor="start">未绑页的 4 叶</text>
|
||||
<text x="640.0" y="397.0" font-size="10.5" fill="#475569" font-weight="normal" text-anchor="start">· 遥信类型(三遥设置 下)</text>
|
||||
<text x="640.0" y="415.0" font-size="10.5" fill="#475569" font-weight="normal" text-anchor="start">· 遥信防抖(三遥设置 下)</text>
|
||||
<text x="640.0" y="433.0" font-size="10.5" fill="#475569" font-weight="normal" text-anchor="start">· 双点遥信(三遥设置 下)</text>
|
||||
<text x="640.0" y="451.0" font-size="10.5" fill="#475569" font-weight="normal" text-anchor="start">· SNTP设置(通讯参数 下)</text>
|
||||
<text x="28.0" y="750.0" font-size="9.5" fill="#94a3b8" font-weight="normal" text-anchor="start">真值 = ui_menu_tree.txt(tools/menu_gen/gen_menu.py 的输入);本图由 tools/arch_diagram/gen_menu_tree_svg.py 生成 —— 改菜单树要同步脚本内的 NODE_SRC 重跑,勿手改 SVG</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 24 KiB |
+28
-24
@@ -201,7 +201,7 @@ flowchart LR
|
||||
| 7 | 开入 KI | `APP/EquipCfg/Const_IO.c` `g_tInputModelTab` | **138 点** | 0(无硬件,X3) | ⬜ |
|
||||
| 8 | 开出 KO | 同上 `g_tOutputModelTab` | **31 点** | 0(无硬件,X3) | ⬜ |
|
||||
| 9 | 动作事件 | `APP/EquipCfg/Const_Rec.c` `g_tActRecTab` | **33 条**(421~453) | 7 类记录(`App/log/sys_log.h`) | 🔶 |
|
||||
| 10 | 录波测量通道 | 同上 `g_tMeasureModelTab` | **65 通道** | 0 | ⬜ |
|
||||
| 10 | 录波测量通道 | 同上 `g_tMeasureModelTab` | **65 通道** | 8(本波口径,2026-10-29 代码面已交付;65 通道仍为 0,参考机口径未改)| 🔶 |
|
||||
| 11 | 软压板 | `APP/EquipCfg/Const_Soft.c` `g_tSoftTab` | **9 面**(表容量 32) | 1 面(`PS_GLOBAL_EN`) | 🔶 |
|
||||
| 12 | 保护元件 | `RelayUnit/*.c` | **45 个模块** | 9 个实例 | 🔶 |
|
||||
| 13 | 记录队列 | `RecUnit/RecFile.c` + `GlobalDef/Const_Sys.h` | **13 类**(128/256 条) | 8 通道(7 文本 + SOE) | 🔶 |
|
||||
@@ -329,7 +329,7 @@ tTimer_NoUI 无压无流判据(CN_
|
||||
|---|---|---|
|
||||
| **外部资源**(标准源、端子变比) | 定值标定、保护判据解卡 | 两点标定(§9.2 第 4 步) |
|
||||
| **硬件缺失**(X3 / X4) | 开入 138、开出 31、电度 8、同期、三相通道 | V0.2 硬件 |
|
||||
| **立项未排** | 多规约、SNTP、定值铺开 | 按 §9.2 顺序;**录波已立项**(2026-10-29):卡片 docs/任务规划/故障录波.md、设计 docs/子系统设计/故障录波设计说明.md,1 kHz 起步与本文 80 点/周波口径的偏离在该设计文档 §2 显式登记 |
|
||||
| **立项未排** | 多规约、SNTP、定值铺开 | 按 §9.2 顺序。**录波最小闭环已交付代码面**(2026-10-29,卡片 docs/任务规划/故障录波.md、设计 docs/子系统设计/故障录波设计说明.md;1 kHz 起步与本文 80 点/周波口径的偏离在该设计文档 §2 显式登记);**4 kHz 全速、多段、COMTRADE、104 文件传输仍未排**,属二期范围 |
|
||||
| **算力 / 形态**(X1 / X2) | 双核分工、VxWorks | 不解除。**屏板链路已从范围外项移入范围内待做**(规格 §5.16,执行规划 docs/任务规划/屏板链路.md):主机侧链路与参考 1:1 同构,不属"替代方案" |
|
||||
|
||||
> **结论**:本产品与参考产品的差距**全部是"进度"而非"范围"**——没有一项是"参考有而我们不做"。
|
||||
@@ -660,7 +660,7 @@ sequenceDiagram
|
||||
|
||||
**FR-UI-2 菜单与内容页**
|
||||
- 需求:42 节点层级菜单(最大 4 级)+ 内容页(装置信息/交流量/直流量等)。
|
||||
- 实现:三层拆分(数据层 `ui_menu_tab` 生成物 / 逻辑层 `ui_menu` 17 B 导航状态 / 显示层 `ui_menu_view` 级联框);内容页框架 + 页面插件描述符。
|
||||
- 实现:三层拆分(数据层 `ui_menu_tab` 生成物 / 逻辑层 `ui_menu` 17 B 导航状态 / 显示层 `ui_menu_view` 级联框);内容页框架 + 页面插件描述符。2026-10-29 实到 43 节点(新增「录波回放」叶,需求原文的 42 是 V0.1 立项数)。
|
||||
- 判据:`UI menu init: OK`;菜单像素回归全 PASS。
|
||||
|
||||
**FR-UI-3 待机屏**
|
||||
@@ -890,7 +890,7 @@ sequenceDiagram
|
||||
上电次数 + 本次复位原因快照)与 iec104_serv 的四个只读观测计数,经 info 帧下发
|
||||
(口径 docs/UI设计/UI_数据供给设计说明.md §4.4)。
|
||||
- 判据:五类记录各有写入点、可翻最近 20 条、空记录明确显示"无记录"、共用 reader——**软件面已满足**
|
||||
(空态与四个范围标签由 60 张像素黄金钉住;模拟器侧这些文件没有写入方,只拍到空态)。
|
||||
(空态与四个范围标签由 66 张像素黄金钉住;模拟器侧这些文件没有写入方,只拍到空态)。
|
||||
真记录翻页、掉电后保持、清除记录后归零、boot_count 自增与四态判定**待台架复核**
|
||||
(docs/任务规划/登记簿.md §7)。
|
||||
|
||||
@@ -942,7 +942,7 @@ sequenceDiagram
|
||||
| 遥控选择 / 撤销 / 执行 | ≤5 s | 同轮应答(ms 级) |
|
||||
| 读定值 / 改定值预置 / 执行 | ≤10 s / ≤5 s | 同轮应答(ms 级) |
|
||||
| 读文件目录 / 文件 | ≤30 s | ⬜ 未实现(文件传输未立项) |
|
||||
| 录波文件存储 | ≤15 s | ⬜ 未实现(**已立项**,见 docs/任务规划/故障录波.md:本波按 1 kHz / 8 路 / 单段做,≤15 s 与 80 点口径属二期) |
|
||||
| 录波文件存储 | ≤15 s | ⬜ 未验收(代码面 2026-10-29 已交付:/wave 段文件 + FTP 取回;本波按 1 kHz / 8 路 / 单段做;≤15 s 时限未测,80 点/周波属二期;卡片见 docs/任务规划/故障录波.md) |
|
||||
|
||||
**FR-IEC104-8 单连接与自愈**
|
||||
- 需求:单连接语义(CH395F 单 socket);断链自动重听;网络重建(改 IP)后服务自愈;协议故障主动拆链。
|
||||
@@ -1807,14 +1807,17 @@ pre-commit run --all-files
|
||||
| 刷新 | `uiTask` 10 ms 循环 |
|
||||
| 绘制缓冲 | I1 draw buffer 需 +8 B palette 头 |
|
||||
|
||||
### 8.2 菜单树(42 节点)
|
||||
### 8.2 菜单树(43 节点)
|
||||
|
||||

|
||||

|
||||
|
||||
**规模**:菜单节点 **9** 个(含根)+ 叶子节点 **33** 个 = **42** 节点;最大深度 **4 级(主界面 / 一级 / 二级 / 三级菜单)**。
|
||||
**绑定现状**(2026-10-28 实测):**已绑内容页 28 叶 / 未绑 5 叶**(页面注册表 `UI_PAGE_MAP_COUNT` = 28,
|
||||
与已绑叶数一致);未绑 5 叶 = 无开入硬件 3 + 手动录波 1 + SNTP 1(取舍与重开条件见
|
||||
docs/任务规划/UI补齐.md §5);原「当前执行 6 项」(记录 5 页 + 运行报告)已于 2026-10-28 落地绑页。
|
||||
> 图里的节点数、绑页与密码门读数由 `tools/arch_diagram/gen_menu_tree_svg.py` 现算自真值 `ui_menu_tree.txt`(改菜单树 → 同步脚本内 `NODE_SRC` 重跑);级联框在屏上怎么摆(几何)→ `docs/UI设计/菜单页面设计.md` §4.1。
|
||||
|
||||
**规模**:菜单节点 **9** 个(含根)+ 叶子节点 **34** 个 = **43** 节点;最大深度 **4 级(主界面 / 一级 / 二级 / 三级菜单)**。
|
||||
**绑定现状**(2026-10-29 复扫):**已绑内容页 30 叶 / 未绑 4 叶**(页面注册表 `UI_PAGE_MAP_COUNT` = 30,
|
||||
与已绑叶数一致);未绑 4 叶 = 无开入硬件 3 + SNTP 1(取舍与重开条件见
|
||||
docs/任务规划/UI补齐.md §5);原「当前执行 6 项」(记录 5 页 + 运行报告)已于 2026-10-28 落地绑页,
|
||||
「手动录波」与「录波回放」两叶于 2026-10-29 随录波道绑页(判据见 docs/子系统设计/故障录波设计说明.md §4.1 与 §8.1)。
|
||||
|
||||
**根页(主界面)7 个一级条目**:装置信息 / 实时数据 / 参数定值 / 三遥设置 / 装置维护 / 通讯参数 / 记录查询。
|
||||
|
||||
@@ -1832,10 +1835,10 @@ docs/任务规划/UI补齐.md §5);原「当前执行 6 项」(记录 5
|
||||
├─ 装置维护 ▶(时钟设置 / 强制复归 / 手动录波 / 清除记录)
|
||||
├─ 通讯参数 ▶(通讯设置 / 网口设置 / SNTP设置)
|
||||
└─ 记录查询 ▶(SOE记录 / 事故记录 / 操作记录 / 保护告警 / 保护启动 /
|
||||
遥控记录 / 自检记录 / 运行记录 / 运行报告)
|
||||
遥控记录 / 自检记录 / 运行记录 / 运行报告 / 录波回放)
|
||||
```
|
||||
|
||||
**三层代码架构**:数据层 `ui_menu_tab`(生成物,`g_menu_tab[42]` 扁平父子索引表,≈0.7 KB Flash)
|
||||
**三层代码架构**:数据层 `ui_menu_tab`(生成物,`g_menu_tab[43]` 扁平父子索引表,≈0.7 KB Flash)
|
||||
+ 逻辑层 `ui_menu`(唯一 **17 B** 导航状态)+ 显示层 `ui_menu_view`(持全部 LVGL 对象,零导航状态)。
|
||||
|
||||
**导航模型**:树形逐级进入——`ENTER`/`→` 进入子页,`ESC`/`←` 返回上一级;页面 = 对表的一次
|
||||
@@ -1848,7 +1851,7 @@ docs/任务规划/UI补齐.md §5);原「当前执行 6 项」(记录 5
|
||||
|
||||
### 8.3 内容页
|
||||
|
||||
**已绑 28 页**(按分组;逐页形态见 [`docs/UI设计/页面补齐规划.md`](../UI设计/页面补齐规划.md)):
|
||||
**已绑 30 页**(按分组;逐页形态见 [`docs/UI设计/页面补齐规划.md`](../UI设计/页面补齐规划.md)):
|
||||
|
||||
| 分组 | 页面 | 形态 |
|
||||
|---|---|---|
|
||||
@@ -1857,21 +1860,22 @@ docs/任务规划/UI补齐.md §5);原「当前执行 6 项」(记录 5
|
||||
| 参数定值 | 查看 4 页(参数 / 定值 / 控制字 / 软压板) | 只读列表 |
|
||||
| 参数定值 | 整定 4 页(参数 / 定值 / 控制字 / 软压板) | 可编辑(写值 + 置脏 + 保存反馈) |
|
||||
| 三遥设置 | 遥测死区 / 遥测系数 | 可编辑(运行参数段,`0x8030~0x804F`) |
|
||||
| 装置维护 | 时钟设置 / 强制复归 / 清除记录 | 操作页(执行类必须出真反馈,不得"点了没效果") |
|
||||
| 装置维护 | 时钟设置 / 强制复归 / 清除记录 / 手动录波 | 操作页(执行类必须出真反馈,不得"点了没效果";手动录波触发后回读同一份计数,判据见 docs/子系统设计/故障录波设计说明.md §8.2) |
|
||||
| 通讯参数 | 通讯设置 / 网口设置 | 可编辑(`[comm]` / `[network]` 段,保存后按各自生效时机) |
|
||||
| 记录查询 | SOE 记录 / 自检记录 / 运行记录 | 记录列表(共用 reader) |
|
||||
| 记录查询 | 事故记录 / 操作记录 / 保护告警 / 保护启动 / 遥控记录 | 记录列表(每记录 2 行、空态显「无记录」;写入点与判据见 App/log/README.md §五类记录) |
|
||||
| 记录查询 | 运行报告 | 只读列表 13 行分 2 页;四个数逐个挂范围标签(自电池周期 / 本次开机),跨开机累计按裁定不做 |
|
||||
| 记录查询 | 录波回放 | 单通道波形页(阶梯线自绘、8 路切换、单位徽标、削顶标记、空态与不可读态显式文案);显示契约见 docs/子系统设计/故障录波设计说明.md §8.1 |
|
||||
|
||||
**未绑 5 叶**(2026-10-28:记录 5 页与运行报告页已落地绑页,原「当前执行 6 项」清零):
|
||||
遥信类型 / 遥信防抖 / 双点遥信 = 等开入硬件(§9.1.1「出口与开入」);手动录波 = 等录波子系统
|
||||
(§9.1.2「录波子系统」);SNTP 设置 = 等 SNTP 对时(§9.1.2「SNTP 对时」)。
|
||||
**未绑 4 叶**(2026-10-28:记录 5 页与运行报告页已落地绑页,原「当前执行 6 项」清零;2026-10-29:
|
||||
录波道落地,「手动录波」叶子随之一并绑页):
|
||||
遥信类型 / 遥信防抖 / 双点遥信 = 等开入硬件(§9.1.1「出口与开入」);SNTP 设置 = 等 SNTP 对时(§9.1.2「SNTP 对时」)。
|
||||
|
||||
- 内容页为**独立全屏屏**,由框架一次性自绘(**零 LVGL 子对象**),`ESC` 返回菜单屏。
|
||||
- 菜单导航状态**不压层**,返回即原样还原;同一时刻至多一个内容页打开。
|
||||
- 节点→页映射在逻辑层 `menu_content_page_for(node)`;未绑叶子进入空白终点框(不伪造数据)。
|
||||
- 数据供给走**注入通道**(rt / par / info / 遥测死区与系数第四表),页面不直接触算法层;
|
||||
像素黄金用例当前 **60 张**(菜单 8 状态另计;2026-10-28 记录 5 页与运行报告 2 页落地,+7 张)。
|
||||
像素黄金用例当前 **66 张**(菜单 8 状态另计;2026-10-28 记录 5 页与运行报告 2 页落地 +7 张;2026-10-29 录波 UI 道 6 张:手动录波 3 态 + 录波回放 3 态)。
|
||||
|
||||
### 8.4 密码与权限
|
||||
|
||||
@@ -1884,7 +1888,7 @@ docs/任务规划/UI补齐.md §5);原「当前执行 6 项」(记录 5
|
||||
|
||||
### 8.5 中文字体
|
||||
|
||||
- 字体 `ui_font_cn_12.c`:宋体 12px 1bpp **子集**(当前 **218 唯一字 / 313 字形**,2026-10-28 实测;
|
||||
- 字体 `ui_font_cn_12.c`:宋体 12px 1bpp **子集**(当前 **224 唯一字 / 319 字形**,2026-10-29 实测;
|
||||
122/217、179/274、185/280 均为历史快照。字形数 = 汉字/符号数 + ASCII 0x20~0x7E 共 95 个)。
|
||||
- 生成流程:`tools/font_gen/extract_cn.py`(扫 UI 源码 → `ui_cn_chars.txt`)→ `tools/font_gen/make_font.py`。
|
||||
- **约束**:任何 UI 文案新增汉字后必须走此流程,否则显示为空白方块。
|
||||
@@ -1927,7 +1931,7 @@ docs/任务规划/UI补齐.md §5);原「当前执行 6 项」(记录 5
|
||||
| **映射铺开** | 3 | 107 项 `0x8820~0x8891` | 40 项局部 | +67 项 |
|
||||
| **元件铺开** | 12 | 45 个模块 | 8 个模块 / 9 个实例 | +37 个模块(过流类 6 / 电压类 5 / 重合闸 5 / 方向功率 4 / 涌流故障 5 / 自动控制 5 / 记录 5 / 录波采样 2) |
|
||||
| **遥测铺开** | 4、5 | 31 点 + 模型 35 行 | 9 点 | +22 点 + 模型表 |
|
||||
| **录波子系统** | 10、15 | 3 类型 / 6 段 / 65 通道 / RAM 16 个 / COMTRADE 64·64·16 | 0 | 整子系统 |
|
||||
| **录波子系统** | 10、15 | 3 类型 / 6 段 / 65 通道 / RAM 16 个 / COMTRADE 64·64·16 | **最小闭环代码面已交付**(2026-10-29):1 kHz / 8 路原始码值 / 单段 320 点 / 轮转段文件 / 手动与保护启动 / 单通道回放页;**板级判据一轮未跑** | 仍差 4 kHz 全速与 80 点/周波、多段与 65 通道、COMTRADE、104 文件传输;口径偏离登记见 docs/子系统设计/故障录波设计说明.md §2 |
|
||||
| **记录体系** | 9、13 | 13 类队列(128/256 条) | 8 类 | +5 类(越限 / 闭锁 / COS / 顺控 / 顺控执行) |
|
||||
| **UI 记录页** | 9、13 | 参考有完整记录页与运行报告 | 六页已绑并纳入像素黄金回归(2026-10-28) | 只剩真机判据(docs/任务规划/登记簿.md §7) |
|
||||
| **多规约栈** | 17 | 12 种 | 1 种(104) | +11 种(101 / 102 / 103 / CDT / ModBus / Whm_GB / 61850 / CAN + 子站侧 3 类) |
|
||||
@@ -1951,14 +1955,14 @@ docs/任务规划/UI补齐.md §5);原「当前执行 6 项」(记录 5
|
||||
|
||||
| 顺序 | 工作 | 类别 | 当前状态 | 开始条件 |
|
||||
|---|---|---|---|---|
|
||||
| 1 | UI 补齐(记录 5 页 → 运行报告) | 规模型 | **清单已清空(2026-10-28)** | 六页已落地;余 5 叶属不做项,重开条件见 docs/任务规划/UI补齐.md §5 |
|
||||
| 1 | UI 补齐(记录 5 页 → 运行报告) | 规模型 | **清单已清空(2026-10-28)** | 六页已落地;余 4 叶属不做项(手动录波与录波回放两叶已随录波道绑页),重开条件见 docs/任务规划/UI补齐.md §5 |
|
||||
| 2 | net 层跨上下文收口 | 平台 | **下一顺位(未开工)** | UI 清单已清空,切换条件已满足;**开工待用户点头** |
|
||||
| 3 | 其余结构与可靠性评估 | 平台 | 排队 | net 收口后 |
|
||||
| 4 | 端子/子板变比确认 → 两点标定 | 阻塞型 | 等外部资源 | 子板实物/原理图、标准源到位可插入 |
|
||||
| 5 | 标准源送检与第三方 104 主站验收 | 阻塞型 | 等标定 | 保护 VALID 置位;送检窗口前 2 日冻结特性 |
|
||||
| 6 | 定值铺开 / 映射铺开 / 遥测铺开 / 软压板铺开 | 规模型 | 等排期 | 标定后(工程量才有意义) |
|
||||
| 7 | 元件铺开与遥测增强 | 规模型 | 等标准源/硬件 | 先解除未标定闭锁;三相类等 V0.2 |
|
||||
| 8 | 录波子系统 → 记录体系 → 多规约栈 | 规模型 | 不排 | 各自重启条件 |
|
||||
| 8 | 录波子系统 → 记录体系 → 多规约栈 | 规模型 | **录波最小闭环已提前插入并交付代码面(用户裁定 2026-10-29 录波先行,见 docs/任务规划/故障录波.md);本行剩下的参考机完整形态(多段 / 65 通道 / COMTRADE / 104 文件传输)仍不排** | 各自重启条件 |
|
||||
| 9 | 验证窗口事项(CI 远端、PC peer、负向注入) | 平台 | 逢条件顺带 | 条件到位即执行 |
|
||||
| 10 | 出口与开入 / 三相与同期 / 电度计量 / 对下采集 | 阻塞型 | 不排 | V0.2 硬件 / 用户决策 |
|
||||
|
||||
@@ -2503,7 +2507,7 @@ docs/任务规划/UI补齐.md §5);原「当前执行 6 项」(记录 5
|
||||
| 元件铺开 | 45 个模块对应 45 个实例;每个实例有:定值项齐全、启动/动作/返回三态可观测、事件码正确、单测覆盖判据边界 |
|
||||
| 遥测铺开 | 31 点全部非 IV(除物理不可达点明确标 IV);线电压与相量满足 `Uab = Ua − Ub` 误差 ≤ 0.5 % |
|
||||
| 开入开出 | 27 路硬件开入可读、31 路开出可驱动;开入防抖可整定;双点遥信四态正确(00/01/10/11) |
|
||||
| 录波 | 4000 Hz 采样;三类录波各生成一份 COMTRADE 且被第三方工具打开;配额 64/64/16 循环覆盖正确 |
|
||||
| 录波 | **(二期口径;本波按 1 kHz / 8 路 / 单段 / 无 COMTRADE,对照表见 §9.1 第 10 行)**4000 Hz 采样;三类录波各生成一份 COMTRADE 且被第三方工具打开;配额 64/64/16 循环覆盖正确 |
|
||||
| 记录体系 | 13 类队列各有落点;每类容量达标;断电不丢已确认记录 |
|
||||
| 多规约 | 每种规约与对应主站/子站工具完成一次完整交互(连接 / 总召 / 变位 / 遥控 / 断链重连) |
|
||||
| 国密 | SM2 签名验签、SM3 摘要与标准测试向量一致 |
|
||||
|
||||
@@ -32,7 +32,7 @@ git commit
|
||||
└─ manual(pre-commit --hook-stage manual;不随 git commit 跑)
|
||||
├─ cppcheck 全量 C 静态分析(自有代码)
|
||||
├─ test-cppcheck test/ 侧静态分析
|
||||
└─ test-coverage 主机单测覆盖率总闸(41 套 + 回退台账)
|
||||
└─ test-coverage 主机单测覆盖率总闸(44 套 + 回退台账)
|
||||
```
|
||||
|
||||
**阶段**:`pre-commit` 阶段拦截代码问题、`commit-msg` 阶段拦截格式问题,任一失败 → commit 中止;另有 `manual` 阶段(`stages: [manual]` 的慢钩子)**不随 `git commit` 跑**,由远端 CI 与 `scripts/ci_local.py` 的 manual 段承担(见下)。一次 `git commit` 实跑 **48** 根 = `pre-commit` 阶段 47 根 + `gitlint` 1 根。
|
||||
@@ -332,7 +332,7 @@ $env:PATH = [Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [Env
|
||||
|
||||
| 文件 | 位置 | 说明 |
|
||||
|---|---|---|
|
||||
| `.pre-commit-config.yaml` | 仓库根 | 钩子配置(**52 个钩子**声明数,一次 `git commit` 实跑 49 根;口径 = YAML 解析后的 hook 条目数,自查命令 → `docs/门禁说明/README.md` §2。声明数与一次提交的实跑数分列,勿混写;计数改动的完整台账只记在 AGENTS.md 提交门禁节与本目录 README §2,本行不重述)。逐项详解在 `docs/门禁说明/`(索引 `docs/门禁说明/README.md`;主机侧单测 **22 根**合一篇,含各套件来历与「19 套无专属钩子」台账 `docs/门禁说明/host-unit-tests.md` §6;UI 侧另有 `font-charset` 与 `ui-golden` 两篇) |
|
||||
| `.pre-commit-config.yaml` | 仓库根 | 钩子配置(**52 个钩子**声明数,一次 `git commit` 实跑 49 根;口径 = YAML 解析后的 hook 条目数,自查命令 → `docs/门禁说明/README.md` §2。声明数与一次提交的实跑数分列,勿混写;计数改动的完整台账只记在 AGENTS.md 提交门禁节与本目录 README §2,本行不重述)。逐项详解在 `docs/门禁说明/`(索引 `docs/门禁说明/README.md`;主机侧单测 **22 根**合一篇,含各套件来历与「22 套无专属钩子」台账(现值 2026-10-29) `docs/门禁说明/host-unit-tests.md` §6;UI 侧另有 `font-charset` 与 `ui-golden` 两篇) |
|
||||
| `.gitlint` | 仓库根 | gitlint 规则(宽松,兼容中文) |
|
||||
| `.cubemx_survival_baseline.json` | 仓库根 | CubeMX 易失定制基线(哈希;`--write` 重建) |
|
||||
| `scripts/check_mojibake.py` | scripts/ | U+FFFD 检测脚本 |
|
||||
|
||||
+8
-7
@@ -32,14 +32,15 @@
|
||||
|
||||
## 1. UI 补齐(执行清单已于 2026-10-28 清空)
|
||||
|
||||
菜单树共 33 叶(节点行合计 42):按行内 #page= 实测**已绑 28 叶、未绑 5 叶**(2026-10-28 复核,
|
||||
判定规则与重跑命令见 docs/任务规划/UI补齐.md §1「叶数判定与复核」)。未绑的 5 叶因缺少开入硬件、
|
||||
录波模块或 SNTP 产品定义而不做(原因与重开条件见 docs/任务规划/UI补齐.md §5)。
|
||||
**口径闭合**:未绑 5 = 待做 0(§1 清单已清空)+ 不做 5(遥信 3 / 手动录波 1 / SNTP 1);**42 是节点行数、不是叶数**(= 9 个菜单节点 + 33 叶)。
|
||||
已绑叶数以生成物 UI_PAGE_MAP_COUNT 为准:不剔 ui_menu_tree.txt 文件头的注释示例行时,按 #page= 文本计数会得 29(= 28 + 1 行示例)。
|
||||
菜单树共 34 叶(节点行合计 43):按行内 #page= 实测**已绑 30 叶、未绑 4 叶**(2026-10-29 复扫,
|
||||
判定规则与重跑命令见 docs/任务规划/UI补齐.md §1「叶数判定与复核」)。未绑的 4 叶因缺少开入硬件
|
||||
或 SNTP 产品定义而不做(原因与重开条件见 docs/任务规划/UI补齐.md §5)——**手动录波与录波回放两叶
|
||||
已随录波道绑页**,「不做」清单里的录波那一项已销。
|
||||
**口径闭合**:未绑 4 = 待做 0(§1 清单已清空)+ 不做 4(遥信 3 / SNTP 1);**43 是节点行数、不是叶数**(= 9 个菜单节点 + 34 叶)。
|
||||
已绑叶数以生成物 UI_PAGE_MAP_COUNT 为准:不剔 ui_menu_tree.txt 文件头的注释示例行时,按 #page= 文本计数会得 31(= 30 + 1 行示例)。
|
||||
|
||||
**UI 补齐执行清单已于 2026-10-28 清空**:记录 5 页(事故 / 操作 / 保护告警 / 保护启动 / 遥控)与
|
||||
运行报告页同日落地并绑页,内容页黄金参考 53 → 60 张(runreport 分 2 页,第 2 页单独拍一张;判据 = simulator/tests/ref/ 入库 shot_*.bin 实数,张数 = 页面个数 + 分页多拍的那一张)。
|
||||
运行报告页同日落地并绑页,内容页黄金参考 53 → 60 张(runreport 分 2 页,第 2 页单独拍一张;判据 = simulator/tests/ref/ 入库 shot_*.bin 实数,张数 = 页面个数 + 分页多拍的那一张;**该集合 2026-10-29 已扩至 66 张**,多出的是录波回放页 6 态)。
|
||||
上板判据(真记录翻页、掉电保持、清除后归零、boot_count 自增、RESTARTED、rst_cause=IWDG、conn_up +1)
|
||||
已登记登记簿 §7「UI 六页真机判据」,六页文件头各留「台架待补」段;模拟器差距见
|
||||
docs/测试说明/模拟器差距清单.md §2.3「开机账本 boot_stats」一行。
|
||||
@@ -66,7 +67,7 @@ docs/测试说明/模拟器差距清单.md §2.3「开机账本 boot_stats」一
|
||||
| **7** | 验证窗口事项 | 逢条件顺带 | CI runner、PC peer、CH340、负向故障注入条件到位时执行 |
|
||||
| **8** | 独立模块与暂缓项 | 当前不排 | 开入开出、SNTP、104 文件传输单独立项;RS-485 与内存优化按各自重启条件 |
|
||||
| **独立** | **屏板链路(对上屏板)** | **规划已出(未开工)** | 独立立项,插在任一顺位之间都能做,不占主序列;**端口已裁定(2026-10-28):屏板占 USART1,日志迁 RS-232 通道**,所以原来的 250 kbps 收发器阻塞已解除;剩下两条前置——**台架串口线挪到 CN1、日志口迁移**(见 docs/任务规划/屏板链路.md §0 与 §3 批 0);**软件可先用 PC + USB 转 TTL 台架验证,不必等屏板实物** |
|
||||
| **独立** | **故障录波(1 kHz · 8 路原始码值 · 单通道回放)** | **设计定稿(代码一行未动)** | 用户裁定 2026-10-29 **录波先行**:数据面最小闭环 → 手动与保护启动触发 → 回放页,卡片判据见 docs/任务规划/故障录波.md,口径与设计见 docs/子系统设计/故障录波设计说明.md;**与 UI 道互斥**(菜单树与中文字库是整文件生成物,同刻只允许一条道写) |
|
||||
| **独立** | **故障录波(1 kHz · 8 路原始码值 · 单通道回放)** | **代码面已交付(板级判据一轮未跑)** | 用户裁定 2026-10-29 **录波先行**:数据面最小闭环 → 手动与保护启动触发 → 回放页。三张卡的**代码侧判据已收口**(主机单测 100 / 170 / 110 全 rc=0、双端编译 0 错误 0 警告、板端编码器与 PC 侧解码器字节级互验、手动录波与录波回放两叶已绑页、内容页黄金参考扩至 66 张);**没跑的是板级那一轮**(注 1 V / 50 Hz、FTP 拉回、与 `meas:` 行和 104 浮点遥测对表、段文件 CRC 不符必须拒收、回放页看真段)。卡片判据见 docs/任务规划/故障录波.md,口径与设计见 docs/子系统设计/故障录波设计说明.md §10;**与 UI 道互斥**(菜单树与中文字库是整文件生成物,同刻只允许一条道写)——本波按此串行执行:UI 道在数据面与接线冻结之后才动生成物 |
|
||||
|
||||
### 2.1 关键依赖
|
||||
|
||||
|
||||
+19
-16
@@ -1,38 +1,41 @@
|
||||
# 当前任务:UI 补齐
|
||||
|
||||
> **执行清单已清空(2026-10-28)**:记录 5 页与运行报告页已落地、绑页并纳入像素黄金回归。
|
||||
> **2026-10-29 录波 UI 道**:「手动录波」由不做转落地(绑操作页),新增「录波回放」叶(节点 43);
|
||||
> 叶数口径同步为 43/34/30/4(下方逐项)。
|
||||
> 本文件保留为 UI 补齐的**范围与判据口径**(§1 叶数、§4 每页统一动作、§5 不做的取舍);
|
||||
> 下一顺位见 docs/任务规划/README.md §2.0(换主线待用户点头),上板待复核项见 docs/任务规划/登记簿.md §7。
|
||||
|
||||
## 1. 目标与范围
|
||||
|
||||
菜单树共 **33 叶**(节点行合计 42,缩进即层级):按行内 `#page=` 实测**已绑 28 叶、未绑 5 叶**,
|
||||
页面映射表 `UI_PAGE_MAP_COUNT` = 28(与已绑叶数一致)。未绑 5 叶 = §5 明确不做的 **5 叶**
|
||||
(遥信 3 / 手动录波 1 / SNTP 1),与下面分类表逐项对得上;2026-10-28 记录 5 页与运行报告页
|
||||
落地后,原「需补配置或写入方」的 6 叶缺口清零并按销项删行(该行内容见本节末与 §3)。
|
||||
菜单树共 **34 叶**(节点行合计 43,缩进即层级):按行内 `#page=` 实测**已绑 30 叶、未绑 4 叶**,
|
||||
页面映射表 `UI_PAGE_MAP_COUNT` = 30(与已绑叶数一致)。未绑 4 叶 = §5 明确不做的 **4 叶**
|
||||
(遥信 3 / SNTP 1),与下面分类表逐项对得上;2026-10-29 录波 UI 道把「手动录波」从不做转为
|
||||
落地并新增「录波回放」叶,绑 +2(手动转绑 + 新叶)/ 叶 +1;2026-10-28 记录 5 页与运行报告页落地后,
|
||||
原「需补配置或写入方」的 6 叶缺口清零并按销项删行(该行内容见本节末与 §3)。
|
||||
|
||||
| 分类 | 数量 | 当前怎么处理 |
|
||||
|---|---:|---|
|
||||
| 无开入硬件 | 3 | 不做:遥信类型、遥信防抖、双点遥信 |
|
||||
| 缺独立模块或产品定义 | 2 | 不做:手动录波(2026-10-29 已随故障录波立项,落地前仍按未绑计)、SNTP 设置 |
|
||||
| 缺独立模块或产品定义 | 1 | 不做:SNTP 设置(手动录波已于 2026-10-29 随故障录波 UI 道落地转绑定,不再列不做) |
|
||||
|
||||
现有基础:`ui_w_editor` / `ui_w_setlist` / `ui_page_action` 已就绪;`ui_data` 已扩到**四通道**
|
||||
(rt / par / info + 遥测死区与系数用的第四张注入表);像素黄金用例与字符集门禁已存在,内容页黄金
|
||||
现有 **60 张**(菜单 8 状态另计)。**装置维护 3 页、遥测死区/系数 2 页、通讯设置页、记录 5 页与
|
||||
现有 **66 张**(菜单 8 状态另计;2026-10-29 录波 UI 道 +6 张:手动录波 3 态 + 录波回放 3 态)。**装置维护 3 页、遥测死区/系数 2 页、通讯设置页、记录 5 页与
|
||||
运行报告页都是把这套基础接上真实消费者做出来的,不另发明一套机制。**
|
||||
逐页形态见 `docs/UI设计/页面补齐规划.md`;数据契约见
|
||||
`docs/UI设计/UI_数据供给设计说明.md`。本文件保留范围、完成判据与不做的取舍口径(执行清单已于 2026-10-28 清空)。
|
||||
|
||||
### 叶数判定与复核(2026-10-28 复核)
|
||||
|
||||
1. **节点行** = `ui_menu_tree.txt` 里非空、非 `#` 开头的行(当前 **42** 行,含根「主界面」)。
|
||||
1. **节点行** = `ui_menu_tree.txt` 里非空、非 `#` 开头的行(当前 **43** 行,含根「主界面」)。
|
||||
2. **缩进即层级**(每级 2 空格;Tab 会被 `gen_menu.py` 直接拒绝):某节点行之后再没有更深缩进的行 = **叶**
|
||||
(当前 **33** 叶);有更深缩进后继者 = 菜单节点(当前 **9** 个)。等价于生成物口径 `ui_menu_tab_has_children(node) == false`。
|
||||
3. **绑定**:叶行行尾带 ` #page=` = 已绑(当前 **28** 叶);不带的 = 未绑(当前 **5** 叶)。
|
||||
4. **闭合**:`未绑 = 待做 + 不做` —— 当前 待做 **0**(§2 清单已清空)+ 不做 **5**(遥信 3 / 手动录波 1 / SNTP 1)= **5**,
|
||||
(当前 **34** 叶);有更深缩进后继者 = 菜单节点(当前 **9** 个)。等价于生成物口径 `ui_menu_tab_has_children(node) == false`。
|
||||
3. **绑定**:叶行行尾带 ` #page=` = 已绑(当前 **30** 叶);不带的 = 未绑(当前 **4** 叶)。
|
||||
4. **闭合**:`未绑 = 待做 + 不做` —— 当前待做 **0**(§2 清单已清空)+ 不做 **4**(遥信 3 / SNTP 1)= **4**,
|
||||
与上面的分类表、§5「当前不做」表逐项对得上。
|
||||
5. **别拿 `grep -c '#page='` 当已绑叶数**:2026-10-28 实测它得 **29**,比真值多 1 —— 文件头第 5 行是规则说明里的
|
||||
` #page=<模块名>` 示例行(不是节点行),必须先剔注释/示例行;剔完的 28 才等于生成物 `UI_PAGE_MAP_COUNT`。
|
||||
` #page=<模块名>` 示例行(不是节点行),必须先剔注释/示例行;剔完的 30 才等于生成物 `UI_PAGE_MAP_COUNT`。
|
||||
|
||||
复核命令(复用生成器自己的解析器 `tools/menu_gen/gen_menu.py` 的 `parse_tree`,不另写一套计数逻辑,免得与生成物脱钩):
|
||||
|
||||
@@ -40,16 +43,16 @@
|
||||
& '.venv\Scripts\python.exe' -c "import io,sys; sys.path.insert(0,'tools/menu_gen'); import gen_menu as g; n,_=g.parse_tree(io.open('ui_menu_tree.txt',encoding='utf-8').read()); leaf=[i for i,x in enumerate(n) if all(y[0]!=i for y in n)]; b=sum(1 for i in leaf if n[i][4]); print('nodes=%d leaves=%d bound=%d unbound=%d' % (len(n),len(leaf),b,len(leaf)-b))"
|
||||
```
|
||||
|
||||
输出 `nodes=42 leaves=33 bound=28 unbound=5`;交叉核对生成物:`ui_menu_tab.h` 的 `UI_MENU_TAB_COUNT` = 42(节点行数)、
|
||||
`ui_page_registry.h` 的 `UI_PAGE_MAP_COUNT` = 28(已绑叶数)——一对 42、一对 28,与上面逐项对得上。
|
||||
输出 `nodes=43 leaves=34 bound=30 unbound=4`(2026-10-29 录波 UI 道落地后实测);交叉核对生成物:`ui_menu_tab.h` 的 `UI_MENU_TAB_COUNT` = 43(节点行数)、
|
||||
`ui_page_registry.h` 的 `UI_PAGE_MAP_COUNT` = 30(已绑叶数)——一对 43、一对 30,与上面逐项对得上。
|
||||
|
||||
三个已踩过的错算法(每种都同时给**当时**与**2026-10-28 重跑**的产物——错法不会自己失效,只是错数跟着已绑叶数一起漂):
|
||||
**把 42 个节点行当叶子**(多算 9 个菜单节点:当时已绑 21 叶 → 得「未绑 21」,2026-10-28 同一错法得「未绑 14」= 42 − 28);
|
||||
**`grep -c '#page='` 当时得 23**(当时已绑 22 叶,多的那 1 正是文件头注释第 5 行的 `#page=<模块名>` 示例字样,必须先剔注释行;
|
||||
2026-10-28 同一命令得 29 = 已绑 28 + 该示例行 1);**按叶子名去重得 29**(`参数`/`定值`/`控制字`/`软压板` 在「整定」「查看」下各一份,
|
||||
2026-10-28 同一命令得 29 = 当时已绑 28 + 该示例行 1;2026-10-29 现值 31 = 已绑 30 + 示例行 1);**按叶子名去重得 29**(`参数`/`定值`/`控制字`/`软压板` 在「整定」「查看」下各一份,
|
||||
4 对同名不能合并;2026-10-28 重跑仍是 29 = 33 叶 − 4 对同名)。
|
||||
(21 / 23 两个错数分属 2026-10-27「已绑 21 叶」与「已绑 22 叶」两个时点的实测,只用来说明错法,不代表现值;
|
||||
去重 29 与上面 grep 现值 29 **只是撞号**:一个是「合并同名叶」、一个是「不剔注释行」,都与真值 28 无关。)
|
||||
去重 29 与上面 grep 现值 29 **只是撞号**:一个是「合并同名叶」、一个是「不剔注释行」,都与真值 30(2026-10-29 现值)无关。)
|
||||
|
||||
---
|
||||
|
||||
@@ -76,6 +79,7 @@
|
||||
|---|---|---|
|
||||
| 通讯设置 | 页面与六态黄金已随 `728d6067` 入库;`[comm]` 段与端口真源在 `App/protocol/iec104/iec104_comm.{c,h}` | 「改后重启即生效」真机判据、配置段数与键数上限核对(台架窗口统一补做并留证) |
|
||||
| 记录 5 页 | 五类记录 ID / 文件 / 写入点已齐(docs/任务规划/登记簿.md §7 与 App/log/README.md §五类记录);reader 注入两端已映射 7 个记录源 | 页面已交付;只剩真机判据(真记录翻页、掉电保持、清除后归零),见 docs/任务规划/登记簿.md §7 |
|
||||
| 录波两页 | 手动录波操作页 + 录波回放页已落地绑页(2026-10-29 录波 UI 道);数据源 = `App/algo/wave_ring`/`wave_store` 真实现经 `ui_data_wave_ops_t` 注入,回放读盘走 `vol_lock` try 锁小窗口 | 页面已交付;真机判据归台架(真实触发落盘的段号连续性、削徽标真值、切段切道实测毫秒与卷锁忙「本轮无段」行为,见 `docs/子系统设计/故障录波设计说明.md` §10 台架判据) |
|
||||
| 运行报告 | boot_stats(SD2506 用户 SRAM 上电次数 + 本次复位原因快照,道G task-12)、iec104_serv 四个只读观测计数、现成 uptime_s | 页面已交付;**跨开机累计不做**(用户裁定只报本次开机)。真机待复核 SRAM 自增与四态判定,见 docs/测试说明/模拟器差距清单.md §2.3 |
|
||||
|
||||
---
|
||||
@@ -108,7 +112,6 @@ UTC 写入,后写者赢 ⇒ 装置墙钟与主机本地时刻恒差 8 小时
|
||||
| 项目 | 不做原因 | 重开条件 |
|
||||
|---|---|---|
|
||||
| 遥信类型 / 防抖 / 双点 3 页 | V0.1 无开入硬件,配置没有消费者 | 开入固件立项后,与开入开出一起做 |
|
||||
| 手动录波 | 录波模块尚未落地;旧口径还挂着「工程量口径未闭环」这道前置,**已被「录波存原始码值」解掉**(docs/子系统设计/故障录波设计说明.md §3.2) | **重开条件已满足**(2026-10-29 立项):随 docs/任务规划/故障录波.md 的「手动触发与保护启动接线」那张卡一起做 |
|
||||
| SNTP 设置 | 当前使用 8888 私有对时协议,SNTP 链路与产品口径均未建立 | SNTP 客户端立项 |
|
||||
| net 层与其他结构债 | 当前只做 UI,避免两条主线互相拖慢 | UI 当前清单完成后,按 README §2 切换 |
|
||||
| RTC 时基统一 | 两套写入口径并存(面板与 8888 写本地钟面、104 写 UTC),恒差 8 小时;统一任一侧都要动 104 上行语义或 UI 判据 | 用户裁定时基方向后,作为跨模块变更单独立项 |
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
# 分工说明:RS-485 解锁与门禁口径对账(2026-10-28)
|
||||
|
||||
**目标**:**A 线**补齐 `Drivers/BSP/RS485/` 两条未修契约缺陷,为 `rs485_task` 解除 **RS-485 接线门禁** 的技术前提;**B 线**把 `AGENTS.md` 与 `docs/门禁说明/README.md` 的 **钩子口径** 对账到实跑。
|
||||
**口径**:本文件只分工、**不改行为**;两条线 **不交叉编辑** 对方文件,跨线接口 **先在本文件登记** 再动手。
|
||||
|
||||
## A 线 · RS-485 驱动契约(负责人 A)
|
||||
|
||||
- **涉及文件**:`Drivers/BSP/RS485/rs485.c`、`Drivers/BSP/RS485/rs485.h`、`App/task/rs485_task.c`(**新建**)、`test/host/rs485/`(**新建**)
|
||||
- **交付物**:
|
||||
1. 修 **单缓冲包撕裂**:RX 改 **双缓冲 + 帧序号**,消费者一次取整帧,对齐 `tpafe5160_snapshot()` 的 **临界区原子快照** 语义(旧的两步取数在两步之间被抢占会混帧);
|
||||
2. 修 **TX 超时拉 DE**:超时路径 **先等 TC 再拉 DE**,避免尾字节被截;错误码走 `Drivers/BSP/bsp_err.h` 通道,返回值 **不得裸丢弃**(`bsp-err` 的 consume-result);
|
||||
3. `[计划] test/host/rs485/run_unit_test.py` 覆盖 **撕裂**、**TX 超时**、**DE 时序** 三例;新增 `.c` 须 **双端注册**(`MDK-ARM/STM32F407-Demo.uvprojx` + `simulator/CMakeLists.txt`,见 `new-source-file` skill);
|
||||
4. 结论回填 `[计划] docs/问题记录/RS485_Trap_Records.md`,并在 `docs/任务规划/暂缓-RS485.md` 写清 **解锁条件是否满足**(接线节奏仍受门禁约束,**不由本线决定**)。
|
||||
- **禁止**:`malloc/calloc/realloc/strdup/free`(`coding-standard` CODE-RULE-20);`osKernelStart` 之前调任何创建类 API;注释里写 **星号形态的路径**(`nested-comment` 9-D)。
|
||||
- **预算**:建任务 **前后各跑一次** `scripts/stack_report.py` 与 `scripts/ram_report.py`;**建任务/抬栈属 Ask first**。
|
||||
|
||||
## B 线 · 门禁与文档口径(负责人 B)
|
||||
|
||||
- **涉及文件**:`AGENTS.md`、`docs/门禁说明/README.md`、`docs/代码规范/pre-commit使用说明.md` §2;`.pre-commit-config.yaml` **只读核对、不改**。
|
||||
- **交付物**:
|
||||
1. **口径 = YAML 解析后的 hook 条目数**:用 `& ".venv\Scripts\python.exe"` 解析 `.pre-commit-config.yaml` 取实数,与 `AGENTS.md` 的 **51** 做 **声明 / 文档 / 实跑** 三数同源核对(**注释掉的候选钩子不计**,直接 grep 声明行会多算 1);
|
||||
2. `docs/门禁说明/README.md` 的 **篇数 ↔ 钩子数** 差集清单,核对 **27 篇 + 1 指针** 是否仍成立;
|
||||
3. 有差异 **只改文档、不加钩子**(Lead 裁定:`test/host/` 41 套里只有 22 根专属钩子,**没有专属钩子 ≠ 没被跑**,余量由 `test-coverage` 总闸兜);新条目标识用 **语义短语**,**不再发字母+数字编号** → `docs/编号规范.md` §1。
|
||||
- **禁止**:手工全局替换改名/挪目录(走 `scripts/rename_ref.py`,先 dry-run);章节引用写成非紧邻形态(`doc-links` 带 `--sections-strict` 拦提交);在配置注释里复述那个 grep 字面量(文本计数再虚高 1)。
|
||||
|
||||
## 共用约束(A/B 都要守)
|
||||
|
||||
- 改代码/改文档 **只用 Edit 精确替换**;**绝不**用 `Get-Content`/`Set-Content`/`cmd` 重写含中文的文件(`U+FFFD` 不可逆);带 BOM 的 `Drivers/BSP/UI/`、`App/cfg/cfg_file.c`、`Lib/lv_conf.h` 改完核对 `EF BB BF`(`bom-guard`)。
|
||||
- **字符串字面量纯 ASCII**,中文只进注释;行尾 **LF**(`.gitattributes` 已写死 `* text=auto eol=lf`);怀疑乱码先数 `EF BF BD` 字节,**不要 `git checkout`**。
|
||||
- 门禁 **只在提交时** 统一跑:`@build` + `& ".venv\Scripts\python.exe" scripts/ci_local.py` + `scripts/check_doc_links.py --all`,**不要中途反复跑**。
|
||||
- `git commit` / `git push` / 烧录 / CubeMX 重生成 / 登记簿删行销项 / 开 `ENABLE_DESTRUCTIVE_TESTS` —— **Ask first**。
|
||||
|
||||
## 验收(合并前)
|
||||
|
||||
| 线 | 判据 | 证据 |
|
||||
|---|---|---|
|
||||
| A | RS485 两条 ❌ 清零,`rs485_task` 的技术门禁解除(**是否接线仍由用户裁定**) | `test/host/rs485` 全绿 + `MDK-ARM/build_log.txt` **0 错误 0 警告** |
|
||||
| B | 声明 / 文档 / 实跑 **三数一致** | 解析计数输出 + `docs/门禁说明/README.md` 差集为空 |
|
||||
| A+B | `registration-check`、`bsp-err`、`nested-comment`、`id-check` 基线 **只减不增** | `scripts/ci_local.py` 输出 + `scripts/archive/id_gate/id_known_backlog.json` 台账 |
|
||||
|
||||
## 交接
|
||||
|
||||
- 两条线各自 **只回报**:**改了哪些文件、跑了哪些自检、剩余风险**;跨线接口(`rs485_frame_take()` 签名)变更 **先在本文件登记**。
|
||||
- `docs/任务规划/README.md` 的 **完成即销项** 由协调者在用户确认后统一做,**A/B 都不得自行删行**。
|
||||
@@ -1,44 +0,0 @@
|
||||
# 分工说明:采集链与上送链台架联调(2026-10-28)
|
||||
|
||||
**目标**:把 **语义取数与有效性→全周傅氏相量→测频与遥测快照** 取数链与 **测频与遥测快照→104/UI** 上送链在同一次台架烧录里对齐,提交门禁 **0 错误 0 警告**。
|
||||
**口径**:本文件只分工,不改行为;任何一条线单独验收通过后合并,**不交叉编辑**对方文件。
|
||||
|
||||
## A 线 · 采集链(负责人 A)
|
||||
|
||||
- **涉及文件**:`App/algo/adc_input.c`、`App/algo/adc_health.c`、`App/algo/sample_ring.c`、`App/algo/phasor.c`、`Src/freertos.c`(**只写 `USER CODE` 区**)
|
||||
- **交付物**:
|
||||
1. `App/algo/README.md` 补 **「快照时序」** 一节:`tpafe5160_snapshot()` 临界区原子性、`adc_tick_irq_notify()` 的「消费者就绪」门(TIM3 比调度器早 ≈100 ms);
|
||||
2. `test/host/adc_input/run_unit_test.py` 增加 **帧序号回绕** 与 **双缓冲半帧** 两个用例;
|
||||
3. `docs/子系统设计/ADC采样节拍设计说明.md` §5 表格与代码实际节拍(**TIM3 PSC 83 / ARR 999 → 1 kHz + TRGO_UPDATE**)核对后回填差异。
|
||||
- **禁止**:`malloc/calloc/realloc/strdup/free`(门禁 CODE-RULE-20);跨转换器做 **相位/功率/功率因数** 运算(V0.1 硬件缺陷);`Drivers/BSP/` 里 include `App/` 的头(`layer-deps`)。
|
||||
- **取数只用** `adc_input_poll()` / `adc_input_raw()` **按语义**取值,**不写死下标**(`buf[2]=IA`、`buf[5]=UN`、`buf[6]=UA` 见 `docs/硬件平台/ADC通道映射说明.md`)。
|
||||
|
||||
## B 线 · 上送链(负责人 B)
|
||||
|
||||
- **涉及文件**:`App/algo/meas.c`、`App/task/iec104_task.c`、`Drivers/BSP/UI/ui_data.c`(**带 UTF-8 BOM:改完核对 `EF BB BF`**)、`test/host/meas/run_unit_test.py`
|
||||
- **交付物**:
|
||||
1. `App/algo/meas.c` 的 **200 ms 双区快照** 写一个 **单写者/多读者** 一致性说明,落到 `docs/架构设计/项目架构总览.md` 的跨层依赖表;
|
||||
2. `Drivers/BSP/UI/ui_data.c` 与 104 上送 **共用同一份上游**:补 `test/host/ui_data/run_unit_test.py` 的 **陈旧代次(generation)** 用例;
|
||||
3. 若新增 `.c`:`MDK-ARM/STM32F4-Base.uvprojx` + `simulator/CMakeLists.txt` **双端注册**(`new-source-file`)。
|
||||
- **禁止**:直接编辑 `Drivers/BSP/UI/` 之外的 `Src/`、`Inc/` 标记区外内容;把 `*.uvprojx` 的 UV4 抖动改动入库;改 `Lib/lv_conf.h` 不同步 `simulator/` 那份(`lv-conf-sync`)。
|
||||
- **UI 侧铁律**:字符串字面量 **纯 ASCII**,中文只进注释;注释里写路径 **不要出现星号形态**(`nested-comment` 9-D),写目录或用尖括号。
|
||||
|
||||
## 共用约束(A/B 都要守)
|
||||
|
||||
- 改代码/改文档 **只用 Edit 精确替换**;**绝不**用 `Get-Content`/`Set-Content`/`cmd` 重写含中文的文件(`U+FFFD` 不可逆)。
|
||||
- 行尾 **LF**(`.gitattributes` 已写死 `* text=auto eol=lf`);怀疑乱码先数 `EF BF BD` 字节,**不要 `git checkout`**。
|
||||
- 门禁只在 **提交时** 统一跑:`@build` + `& '.venv\Scripts\python.exe' scripts/ci_local.py` + `check_doc_links.py --all`;**不要中途反复跑**。
|
||||
- 文档引用章节 **紧邻写法**:`docs/算法/采集与算法层设计说明.md` §10.1;改名/挪目录走 `scripts/rename_ref.py`(先 dry-run)。
|
||||
- `git commit` / `git push` / 烧录 / `CubeMX` 重生成 / 抬栈 —— **须用户明确指示**(抬栈前后各跑 `scripts/stack_report.py`)。
|
||||
|
||||
## 验收(合并前)
|
||||
|
||||
| 线 | 判据 | 证据 |
|
||||
|---|---|---|
|
||||
| A | 语义取数与有效性→全周傅氏相量与 1 kHz 节拍一致,无半帧 | `test/host/adc_input` 全绿 + `docs/子系统设计/ADC采样节拍设计说明.md` |
|
||||
| B | `meas` 双区 **104 与 UI 同源**,无撕裂 | `test/host/meas`、`test/host/ui_data` 全绿 + `docs/编号规范.md` 无新撞号 |
|
||||
| A+B | 台架一次烧录 **`-Rst -Run` + 回读校验**(`No difference found`),串口日志无 `[ERR]` | `@test` 报告 + `MDK-ARM/build_log.txt` |
|
||||
|
||||
## 交接
|
||||
|
||||
- 两条线各自 **只回报:改了哪些文件、跑了哪些自检、剩余风险**;跨线接口(`meas` 快照字段)变更 **先在本文件登记**再动手。
|
||||
+6
-4
@@ -7,7 +7,7 @@
|
||||
|
||||
## 1. 现状一句话
|
||||
|
||||
全仓**没有任何录波代码**:`App/` 下 grep 无实现,`Drivers/BSP/UI/ui_menu_tab.c:41` 那条「手动录波」叶子(菜单第 26 叶)**至今未绑内容页**;产品需求把「录波文件存储」「文件传输(录波)」两行标为未实现/未开始;旧口径把录波挂在「工程量口径实测闭环之后」,本波用**原始码值**解掉这个依赖(`docs/子系统设计/故障录波设计说明.md` §3.2)。
|
||||
**数据面与接线已在仓内,板级判据一轮未跑**(诚实口径,2026-10-29 更新):录波环与段格式编解码在 `App/algo/wave_ring.c` 与 `App/algo/wave_store.c`,压环与落盘与保护启动接线、以及两条 UI 页的代码侧判据已过(三套主机单测 100 / 170 / 110 全 rc=0、双端编译 0 错误 0 警告、板端编码器与 PC 解码器两份独立实现字节级互验通过;「手动录波」第 26 叶与「录波回放」两叶均已绑页,`UI_PAGE_MAP_COUNT` = 30,内容页黄金参考 60 → 66 张含录波 6 态)。**没做完的是板级那一轮**:注 1 V / 50 Hz、FTP 拉回、与 `meas:` 行和 104 浮点 YC 对表、CRC 不符必须拒收的实测、真机上看回放页放一段真波;产品需求把「录波文件存储」「文件传输(录波)」两行的更新排在台架轮次之后。旧口径把录波挂在「工程量口径实测闭环之后」,本波用**原始码值**解掉了这个依赖(`docs/子系统设计/故障录波设计说明.md` §3.2)。
|
||||
|
||||
三条已裁定口径(用户裁定 2026-10-29,理由见`docs/子系统设计/故障录波设计说明.md` §1.2 与 §2):
|
||||
|
||||
@@ -23,11 +23,13 @@
|
||||
|
||||
| 卡 | 内容 | 退出判据 | 资源 | 依赖 |
|
||||
|---|---|---|---|---|
|
||||
| **录波数据面最小闭环** | 新增专用录波环与段格式编解码(`docs/子系统设计/故障录波设计说明.md` §5 到 §7);bench 构建定周期自抓;FTP 拉回;仓内新增一个纯标准库 PC 脚本读段、画图、重算全周傅氏 | 注入 1 V / 50 Hz 正弦 → 拉回段文件 → PC 脚本量出周波数、幅值、极性与注入一致;削顶路数与头里 `clip_mask` 一致;**PC 重算的基波有效值与板上 `meas:` 行、104 浮点 YC 逐个对表通过**;段文件 CRC 不符时脚本必须拒绝而不是画出东西 | 🟡+🟢(需信号发生器与板,不需标准源) | 无(可与固件其他道并行;独占构建锁) |
|
||||
| **手动触发与保护启动接线** | 触发状态机接两路真实来路:UI「手动录波」操作页(第 26 叶绑页,形态沿用已规划好的操作页确认模式)+ `App/algo/prot_elm.c` 的 `picked` 上升沿 | 面板按一次出一段;造一次过流,段号与该时刻 `/log/start.log` 事件能对齐;冷却期内二次触发只加 `ovf` 计数、不重录;冻结窗口内 104 上送与保护判据不受影响(**这条是"丢录波样本不丢采集"的验收**) | 🟡+🟢+UI 道(菜单树与字库是整文件生成物,须单写者) | 上一张卡 |
|
||||
| **现场单通道回放页** | 新增「录波回放」叶子与内容页:单通道 2 周波 40 点、阶梯线、0 线与峰值标注、单位徽标、削顶标记、空态文案(`docs/子系统设计/故障录波设计说明.md` §8) | `ui-verify` 五步全过;回放页入 `ui-golden` 黄金参考;远端看图能拍到此页(只作留证,不当波形通路);**空态与 CRC 失败态绝不允许画成一条直线**;菜单叶数与字库生成物同步重跑且 `generated-fresh` 一致 | 🟢+UI 道(模拟器与黄金参考) | 上一张卡 |
|
||||
| **录波数据面最小闭环**〔代码侧完成 / 板级待台架〕 | 新增专用录波环与段格式编解码(`docs/子系统设计/故障录波设计说明.md` §5 到 §7);bench 构建定周期自抓;FTP 拉回;仓内新增一个纯标准库 PC 脚本读段、画图、重算全周傅氏 | **代码侧判据已完成**:三套主机单测 100 / 170 / 110 全 rc=0(环 100、段格式 170、触发状态机 110)、双端编译 0 错误 0 警告、板端编码器与 PC 侧解码器两份独立实现**字节级互验通过**(同一份字节两边同解)。**下列判据要板子与台架,一轮未跑**:注入 1 V / 50 Hz 正弦 → 拉回段文件 → PC 脚本量出周波数、幅值、极性与注入一致(**绝对相位不可比**,段内相位以点 0 为参考、触发瞬间在段内点 159,与发生器无相位锁定关系,可核对的是相对相位与极性——见 docs/子系统设计/故障录波设计说明.md §4.2 与 §10);钉轨路数与头里 `clip_mask` 的合格判据是「头位图 ⊇ 实测钉轨路数,且差异必须能由注入条件解释」(`clip_mask` 按来源派生、非本段实测,V0.2 后该位恒 0、这条退化为只查实测);**强观察项**:V0.1 下这五路做交流注入时反而没钉轨 → 先查接线或该路未驱动,属告警面不属失败面;**PC 重算的基波有效值与板上 `meas:` 行、104 浮点 YC 逐个对表通过**;段文件 CRC 不符时脚本必须拒绝而不是画出东西 | 🟡+🟢(需信号发生器与板,不需标准源) | 无(可与固件其他道并行;独占构建锁) |
|
||||
| **手动触发与保护启动接线**〔代码侧完成 / 板级待台架〕 | 触发状态机接两路真实来路:UI「手动录波」操作页(第 26 叶绑页,形态沿用已规划好的操作页确认模式)+ 保护启动的元件 picked 上升沿(落点 `App/task/protect_task.c` 的 `s_log_record_edge()`,不是判据核本身) | **代码侧已完成**:保护启动来路与并发语义(同拍多请求只录一段、冷却期内二次触发只加 `ovf`、冻结窗口只丢录波样本不丢采集)已在主机单测里钉住,双端编译 0 错误 0 警告。**下列属板级未完成**(第 26 叶已于 2026-10-29 绑页,模拟器侧手动触发路径已有黄金用例;剩下的必须在真机面板上按):面板按一次出一段;造一次过流,段号与该时刻 `/log/start.log` 事件能对齐;冷却期内二次触发只加 `ovf` 计数、不重录(**同时看 `armed` 与那一刻 `/log/start.log` 的时刻,不要只盯 `ovf` 数字**:这两个计数是跨上下文自增、并发拒绝时可能少计一次,容差见 docs/子系统设计/故障录波设计说明.md §9);冻结窗口内 104 上送与保护判据不受影响(**这条是"丢录波样本不丢采集"的验收**) | 🟡+🟢+UI 道(菜单树与字库是整文件生成物,须单写者) | 上一张卡 |
|
||||
| **现场单通道回放页**〔代码侧完成 / 板级待台架〕 | 新增「录波回放」叶子与内容页:单通道 2 周波 40 点、阶梯线、0 线与峰值标注、单位徽标、削顶标记、空态文案(`docs/子系统设计/故障录波设计说明.md` §8) | **代码侧判据已完成**:两叶绑页(`UI_PAGE_MAP_COUNT` = 30)、`ui-golden` 内容页黄金参考 60 → 66 张(录波 6 态:手动录波 3 态 + 录波回放 3 态),任务树重建模拟器后同一批 66 张连跑三次逐字节一致(页面池水位 5,448 B)、菜单侧 8 状态连跑三次一致(5,368 B),`generated-fresh` 退出码 0(菜单树与中文字库生成物与源一致),双端编译 0 错误 0 警告。**下列判据要板子与台架,一轮未跑**:真机上放一段真波(不是模拟器合成节拍)、远端看图能拍到此页(只作留证,不当波形通路)、**空态与 CRC 失败态绝不允许画成一条直线**要在真机上用坏段复现一次 | 🟢+🟡+UI 道(模拟器与黄金参考) | 上一张卡 |
|
||||
| 二期(不在本波) | 4 kHz 全速与 80 点/周波、突变量启动、COMTRADE、104 文件传输、分段与参考机形态(录波 65 通道、多类型多段) | 不在本波验收面内;重开条件见 §4 | 🔴/独立立项 | — |
|
||||
|
||||
**落盘道的失败留痕名(单板上一律一行 `[WAVE] seg drop: <原因> (idx=… written=…)`,统一打印点 `App/task/default_task.c:816`)**:`crc selftest FAIL` / `mkdir /wave` / `opendir /wave` / `readdir /wave` / `seg_path` / `pack_start` / `f_open` / `pack_next` / `f_write short` / `pack stall` / `f_close` / `len mismatch` / **`ring abandoned`**。最后一条是 docs/子系统设计/故障录波设计说明.md §5.2 第四条陷阱的处置留痕(写完关档后复检环侧身份不过 → 判废本段、`err` 加一、段号不推进),**代码与主机单测面已有、板级未测**;另有一条非失败的慢段留痕 `[WAVE][WARN] seg held <毫秒> ms (idx=…)`(`App/task/default_task.c:831`)——搬得慢不是错,真失败才走 `seg drop`。
|
||||
|
||||
**为什么录波排在信号发生器动态验证之前**(用户裁定):动态验证真正缺的不是信号源,是**样本出口**——录波段文件一旦有了,动态验证就从「比对几个派生标量」升级成「PC 独立重算 vs 板上读数」的对表,同一套台架接线两次都用得上,不必再造一条串口通路。`docs/子系统设计/故障录波设计说明.md` §11 记了因此而变的三处口径。
|
||||
|
||||
---
|
||||
|
||||
+16
-9
@@ -307,16 +307,20 @@ typedef struct {
|
||||
|
||||
#### 4.6.2 判据 D1~D6
|
||||
|
||||
> **分工**:本节定"验什么、过判据是多少";**期望值的算术、接法细节与执行步骤**在
|
||||
> `docs/测试说明/ADC前端注入验证流程.md` §8(同一轮次的手册,两边于 2026-10-29 已对齐)。
|
||||
|
||||
| # | 验什么 | 接法 | 读哪 | 过判据 |
|
||||
|---|---|---|---|---|
|
||||
| **D1** | 基波幅值计量 | UA(R31 / `AIN1`)注 1.000 Vrms、50.000 Hz 正弦 | `meas:` 的 `ua_mv`;或 104 `0x4011` | 读数 = 万用表 AC 档读数,偏差 ≤2 %(与静态同档)。⚠ 别用 `phasor(hb)` 行比幅值——那是 ×0.1 定点,注 1 V 只剩 10 格(§4.6.3) |
|
||||
| **D2** | 读数是否只跟基波走 | 同幅值改方波、三角 | 同上 | 期望值 = **基波分量有效值**(方波基波 = 4/π × 峰值/√2 ≈ 0.90×峰值;三角 = 峰值/√6),**不是**真有效值;偏差 ≤2 %。顺带把"这台仪表读的是基波"这条口径钉进文档——用户拿真有效值表去对会以为差了 10 % |
|
||||
| **D3** | 相位 | UA 与 UN 两路**同片**(都走 TPAFE)注同幅、同相 | `phasor(hb)` 各行 `Re=` / `Im=` | 两路 `atan2(fIm, fRe)` 之差 ≤2°;改变发生器相位 90°,差值跟着走。**只许比同片内**——跨转换器无同刻性(§9),STM32 那五路还有 1 拍乒乓滞后 |
|
||||
| **D2** | 读数是否只跟基波走 | 同幅值改方波、三角 | 同上 | 期望值 = **基波分量有效值**(同峰值下的基波 / 峰值比:方波 ≈ **0.90**,闭式 4/π ÷ √2 = 0.900、20 点整周期 DFT 实算 0.904;三角 ≈ **0.573**,闭式 8/π² ÷ √2 = 0.573、实算 0.578),**不是**真有效值(方波 = 1.000、三角 = 0.583 峰值);偏差 ≤2 %。算术与逐波形对照表见 `docs/测试说明/ADC前端注入验证流程.md` §8.5 的 D2 卡。顺带把"这台仪表读的是基波"这条口径钉进文档——用户拿真有效值表去对会以为差了 10 % |
|
||||
| **D3** | 相位 | UA 与 UN 两路**同片**(都走 TPAFE)注同幅、同相 | **定量档**:录波段文件 `test/host/wave_read.py fft`(浮点重算基波相位;段内表序 `UA` = 0、`UN` = 3);**定性档**:`phasor(hb)` 各行 `Re=` / `Im=` | **定量档**:同段内两路相位差 ≤2°,把发生器相位改 90° 后差值跟到 ≈90°。**定性档只判"跟随"**(差值落进 80°~100°)——`phasor` 出口是 ×0.1 定点,1.000 Vrms 时每格 0.1 V,角度量化最坏 ≈ atan(0.1 / 0.707) ≈ 8°,判不动 2°(§4.6.3)。⚠ 段与发生器**无绝对相位锁定**(触发瞬间钉在段内点 159),只能比**同段内两路**的相对差,跨段比相位或拿发生器相位当绝对基准都不成立。**只许比同片内**——跨转换器无同刻性(§9),STM32 那五路还有 1 拍乒乓滞后 |
|
||||
| **D4** | 测频 | 同 D1 的 1 V/50 Hz | `freq(hb):` 与 104 `0x401D` | **预期就是"不出数"**(幅值门 50 V 在引脚域恒不过,§2.3 #1)→ 这条的判据是"如实报不可测"(`freq_valid=0`、UI `Hz` 显示 `--`、104 上送 IV),**不是**报出一个错误的 50.00。想真验 45~55 Hz 精度(PC 侧判据 0.02 Hz)须临时把 `FREQ_AMP_MIN` 降到引脚域量级(如 0.5 V)单跑一轮 → §7 #8 + §8 风险行 |
|
||||
| **D5** | 削顶与品质路由(**负向用例**) | 给 UB(R52 / `AIN2`)注同幅正弦 | `cal:` 行的 `rail=` / `edge=`;`rail: edge=…` 的 `[ERR]` 行;104 `0x4012` | 负半周钉下轨 → **连续 20 拍(正好一个 50 Hz 周波)后该路贴轨位锁存**、`edge` 起沿、104 上该路 IV 且值清零。⚠ 这条会**故意造出 `[ERR]`**,而 `@test` 的 forbidden 标记含 `[ERR]` → 本轮要么人工判读、要么把这五路排在最后单独一轮(§8 第一行) |
|
||||
| **D6** | 谐波轨 | 基波 + 20 % 二次 + 20 % 五次(IA 上注) | `phasor(hb) C04-IA-F2` / `C05-IA-F5` 两行(`log_phasors()` 逐实例打印,实例表加行即自动覆盖) | 谐波轨读数 = 注入分量(±2 %)。⚠ 这两根轨**目前没有任何下游消费者**(`prot_elm.c` 无引用、`meas` 只算 `harm=1`),所以 D6 只证"算得对",**不证"有人用"**——出口归 §9 的谐波轨立项 |
|
||||
| **D5** | 削顶与品质路由(**负向用例**) | 给 UB(R52 / `AIN2`)注 **DC −1.00 V 并保持 ≥5 s**;或 1.000 Vrms 而频率 **2.0 Hz** 的正弦——两档都能造出"连续贴同一侧轨带"。⚠ **注 50 Hz 同幅正弦造不出锁存,且这是预期而非故障**:1 kHz 下一个周波只 20 点、正半周必落中带,而 `adc_health_rail_watch()` 任何一拍回中带就把计数清零(`App/algo/adc_health.c`),连续贴底最长 ≈ 209/360 × 20 ≈ 11 拍 < 20。TPAFE 侧在 ±2 V 判据上限内造不出这条(轨带 ±32112 码 ≈ ±4.9 V),只有 STM32 那五路能做 | `cal:` 行的 `rail=` / `edge=`;`rail: edge=…` 的 `[ERR]` 行;104 `0x4012`;段文件档另加 `wave_read.py shape` 的三把尺子(`--strict` / 再加 `--clip-superset` / 不带),逐条配法见 `docs/测试说明/ADC前端注入验证流程.md` §8.5 的 D5 卡 | 负半周钉下轨 → **连续 20 拍同侧后该路贴轨位锁存**(`ADC_RAIL_N_RUN = 20`,`App/algo/adc_health.h:174`)、`edge` 起沿、104 上该路 IV 且值清零。锁存另有**释放沿前提**:该通道此前须出现过中带样本 → **先上电见基线摆动、再开发生器输出**,开机就注会测出假不通过。撤掉注入后 `rail` 仍非 0 是 sticky 语义(只有 `adc_health_rail_init()` / 复位清)——**复位后仍不清才是 bug**。⚠ 这条会**故意造出 `[ERR]`**,而 `@test` 的 forbidden 标记含 `[ERR]` → 人工判读、排在最后单独一轮(§8 第一行) |
|
||||
| **D6** | 谐波轨 | 基波 + 20 % 二次 + 20 % 五次(IA 上注)。⚠ 峰值预算:1.000 Vrms 基波 + 两个 20 % 分量的最坏对齐 ≈ 1.98 V 已顶 ±2 V 红线 → 基波用 **0.800 Vrms**、二次与五次各 0.160 Vrms | **定量档**:段文件 `test/host/wave_read.py fft --ch 4 --all`(`IA` = 段内表序 4,直接给基波与 2 / 5 次谐波 RMS,单位 mV);**旁证**:UI 交流量页 `Ia2` / `Ia5`(1 mV)与 `phasor(hb) C04-IA-F2` / `C05-IA-F5`(×0.1 定点,只证这根轨不是恒 0) | 谐波轨读数 = 注入分量(**±2 %,走定量档**;周期行档判不动:0.160 Vrms 在 ×0.1 出口只有 1~2 格)。⚠ 这两根轨**目前没有任何下游消费者**(`prot_elm.c` 无引用、`meas` 只算 `harm=1`),所以 D6 只证"算得对",**不证"有人用"**——出口归 §9 的谐波轨立项 |
|
||||
|
||||
**先做 D1 / D2 / D5**(纯读数、无跨通道约定),D3 / D6 次之,D4 视 §7 #8 的裁定。
|
||||
**先做 D1 / D2 / D5**(纯读数、无跨通道约定),D3 / D6 次之,D4 视 §7 #8 的裁定。每条的两档跑法(周期行标量档 /
|
||||
录波段文件定量档)、触发动作、耗时排布与失败分诊在 `docs/测试说明/ADC前端注入验证流程.md` §8.6。
|
||||
|
||||
#### 4.6.3 读数出口(零固件改动)
|
||||
|
||||
@@ -325,7 +329,8 @@ typedef struct {
|
||||
| 串口每 10 s 心跳(`App/task/adc_task.c` 心跳块) | `adc:`(9 路码值)、`cal:`(三路 mV + `vl`/`cl`/`rail`/`edge` 位图)、`phasor(hb)`(逐实例 `Re` / `Im` / `rms`)、`freq(hb)`、`meas:`(快照轨) | MicroLIB 无 `%f`,全是定点:`phasor` ×0.1(**1 V 注入只剩 10 格**)、`freq` ×0.01 Hz、`cal:` / `meas:` ×1000(1 mV)。10 s 一行的单点瞬时值对 50 Hz 等价于随机相位抽样 |
|
||||
| 104 YC(现成 PC 主站 `test/host/iec104_master.py`) | `0x4011`~`0x4018` 八个电气量 + `0x401D` 频率,**浮点无量化**,还带品质 | UB/UC/IB/IC/IN 恒 IV、值清零 → 那五路只能回读串口码值域 |
|
||||
| UI 交流量页 | `Ua` / `U0` / `Ia` / `Ia2` / `Ia5` / `Hz` / 标定徽标 共 7 行 | 160×160 单色;`--` **同时**表示"没数"和"有数但不可信" → 不能当判据,只能当旁证 |
|
||||
| **板上没有的(本波现状)** | 把窗里 20 / 40 个点导出来的任何出口:无命令控制台、无 dump、当前还不落文件 | 所以现在只能靠**派生标量**证;要看形状就拿示波器直接看注入点(只对照发生器,别拿它当判据)。**这条限制是临时的**:故障录波已立项,段文件就是现成的样本出口,届时判据升级为「PC 独立重算 vs 板上读数」对表(见 `docs/子系统设计/故障录波设计说明.md` §11) |
|
||||
| **段文件样本出口(代码侧已落地,2026-10-29)** | 每次触发一段:`/wave/WAVE00.BIN` 起共 100 个号轮转(FTP 根下可见),8 路 × 320 点原始码值加封存瞬间的标定与品质快照;PC 侧 `test/host/wave_read.py` 提供 dump / fft / shape / plot 四个子命令(bench 工具,纯标准库,自带 `--selftest`) | 「比对派生标量」已可升级成「PC 独立重算 vs 板上读数」对表(判据与执行步骤见 `docs/测试说明/ADC前端注入验证流程.md` §4,格式属主见 `docs/子系统设计/故障录波设计说明.md` §6.2 与 §6.3)。**但板级那一轮还没跑**(注 1 V / 50 Hz、与 `meas:` 与 104 YC 对表、CRC 不符必须拒收的实测,见 `docs/任务规划/故障录波.md` 卡片判据);示波器仍旧只作旁证、不当判据。段内点序:触发瞬间落在段内点 159(预触发 160 点的最后一点),段的绝对相位与发生器无锁定关系,可核对的是相对相位与极性 |
|
||||
| **仍然没有的(2026-10-29 更新)** | 没有命令控制台、也没有「把窗里 20 / 40 个点导出来」的定点 dump 子命令——**但样本出口本身已成立**(上一行的段文件:一次 320 点 / 8 路,比原来规划的 20 / 40 点窗更宽) | 现场取回一律走现成 FTP(21 端口),形状就地看回放页单通道、或在 PC 侧用同一脚本出图;示波器只对照发生器、不当判据。**判据已升级为「PC 独立重算 vs 板上读数」对表**,对表的执行轮次待台架(见 `docs/子系统设计/故障录波设计说明.md` §11) |
|
||||
|
||||
#### 4.6.4 接法与红线(照抄既有红线,不新发明)
|
||||
|
||||
@@ -342,7 +347,7 @@ typedef struct {
|
||||
|---|---|---|
|
||||
| 端子二次值 | 注入点在 ④ 之前,算出来还是引脚域 | §5「端子/子板变比确认」 |
|
||||
| 精度等级(0.5 级 / 1 级) | 发生器自己的幅值误差本身就是要被校的量,不能冒充标准源 | §5「两点标定与精度验收」+ §7 #1 |
|
||||
| 跨转换器相位 / 功率 / 对称分量 | 两片转换器无共同采样触发(V0.1 硬件缺陷)+ STM32 侧 1 拍乒乓滞后。量纲链路口径见 `docs/硬件平台/ADC通道映射说明.md` §7;处置见 §9 |
|
||||
| 跨转换器相位 / 功率 / 对称分量 | 两片转换器无共同采样触发(V0.1 硬件缺陷)+ STM32 侧 1 拍乒乓滞后;量纲链路口径见通道映射说明的链路分段一节 | §9(本波不做矢量类运算) |
|
||||
| THD / 谐波方和根 | 固件里只有两根谐波轨,没有合成出口 | §9(挂谐波轨立项) |
|
||||
| 温升、EMC、长时间漂移 | 单轮台架不覆盖 | 送检与型式试验 |
|
||||
|
||||
@@ -420,6 +425,8 @@ flowchart TD
|
||||
|
||||
## 8. 风险
|
||||
|
||||
> 引用本表某一行时**写行名**(例:「削顶通道被当成可测」行),别写「末行 / 第 N 行」——本表会插行。
|
||||
|
||||
| 风险 | 触发条件 | 缓解 |
|
||||
|---|---|---|
|
||||
| **削顶负向用例被当成固件 bug** | 做 D5 时 STM32 那五路必然钉下轨 → `rail: edge=…` 是 `[ERR]` 行,而 `@test` 的 forbidden 标记含 `[ERR]` → 整轮被判 FAIL | 判读规则写进流程文档:"做 D5 的这一轮 `[ERR] rail:` 属预期,只人工判读、不计入 `@test` 结论",或把这五路排在最后单独一轮并事先声明。同时别忘 `cl=0xE6` 是**来源派生**(§2.6),不是本轮新削出来的 |
|
||||
@@ -443,7 +450,7 @@ flowchart TD
|
||||
| THD / 谐波方和根真有效值、快照 4 点平均 | 挂 `docs/算法/继电保护功能复现规划.md` 的「遥测谐波轨(可选)」一起做;快照保持"基波有效值 + 直取相量"口径(§4.5) |
|
||||
| **谐波轨的消费出口**(C04 / C05 目前无人消费) | D6 只证"算得对";接线到判据或上送属谐波轨立项范围,本波不动 |
|
||||
| 端子级额定电压、绝缘耐压、温升 | 要标准源 / 型式试验条件;本波所有注入都在 `U5` 排针侧 ±2 V 以内 |
|
||||
| 录波(原始码值段文件) | **已独立立项**(2026-10-29):`docs/任务规划/故障录波.md`;本卡「动态波形验证」的样本出口将改由录波段文件承担,排序也随之调整(`docs/子系统设计/故障录波设计说明.md` §11) |
|
||||
| 录波(原始码值段文件) | **已交付代码面**(2026-10-29 立项并当日落地):`docs/任务规划/故障录波.md`;本卡「动态波形验证」的样本出口**已**由录波段文件承担(§4.6.3 出口表已改),排序也随之调整(`docs/子系统设计/故障录波设计说明.md` §11);**没跑的是板级那一轮**(§10) |
|
||||
| 104 文件传输(规约侧读文件) | 仍独立待排;现场与台架取回一律走现成 FTP(21 端口),规约侧文件服务等送检或第三方交接需求再议 |
|
||||
| 等周波调频 | 与标定正交、无标准源时判据不可达,见 `docs/算法/继电保护功能复现规划.md` §3.1 |
|
||||
| 功率 / 相位跨相比较 / 功率因数 / 对称分量 | **V0.1 硬件禁止**:跨转换器无同一时刻性,`docs/硬件平台/ADC通道映射说明.md` §7 通道归属行 |
|
||||
@@ -461,7 +468,7 @@ flowchart TD
|
||||
|---|---|
|
||||
| **`docs/测试说明/ADC前端注入验证流程.md`** | **执行步骤的属主**。本文只写"证到哪、判据是什么、为什么这么排";怎么接表笔、读哪一行、填哪张表一律在那篇里。动态验证的**步骤**同样落那篇(新开"交流"节),本文 §4.6 只留判据 |
|
||||
| **通道映射说明** | `docs/硬件平台/ADC通道映射说明.md` §7.1(①②③④ 链路分段)与 §8.1(静态六项实测)是**量纲与实测记录的属主**;本文 §2.1 / §2.6 是它的**消费者**,不另立口径,动态实测结论也回写该文件 |
|
||||
| **`docs/子系统设计/故障录波设计说明.md`** | 录波段文件是本卡「动态波形验证」的**样本出口**:录波落地后判据从「比对派生标量」升级为「PC 独立重算 vs 板上读数」对表,动态验证的排序也因此让位给录波数据面(用户裁定 2026-10-29,理由与三处口径变更见该文 §11) |
|
||||
| **`docs/子系统设计/故障录波设计说明.md`** | 录波段文件是本卡「动态波形验证」的**样本出口**,数据面代码侧已落地(2026-10-29:环与段格式在 `App/algo/wave_ring.c` / `App/algo/wave_store.c`,PC 侧 `test/host/wave_read.py`);判据从「比对派生标量」升级为「PC 独立重算 vs 板上读数」对表的**执行轮次待台架**,动态验证的排序已因此让位给录波数据面(用户裁定 2026-10-29,理由与三处口径变更见 docs/子系统设计/故障录波设计说明.md §11) |
|
||||
| **`docs/算法/采集与算法层设计说明.md`** | 算法与判据正文(全周傅氏、测频、保护元件);本文只规定"这些算法的信度到什么程度" |
|
||||
| **`docs/子系统设计/IEC104上行设计说明.md`** | 动态验证的**读数出口**(`0x4011`~`0x4018` + `0x401D`);送检验收索引在 `docs/任务规划/登记簿.md` §7 |
|
||||
| **送检验收** | 标准源送检依赖本文「两点标定与精度验收」;顺序不可倒(先变比 → 再标定 → 才解卡 → 才送检,§6) |
|
||||
|
||||
@@ -47,10 +47,10 @@ dhara 失败类 +84;RO 另 +208,全是该失败类名表)→ `ER_IROM1`
|
||||
<!-- MEM_SNAPSHOT:BEGIN generated by scripts/check_mem_numbers.py -->
|
||||
| 区域 | 用量 | 容量 | 占比 |
|
||||
|---|---|---|---|
|
||||
| ER_IROM1 | 268,220 B (261.93 KB) | 1,048,576 B (1024 KB) | 25.6% |
|
||||
| RW_IRAM1 | 85,904 B (83.89 KB) | 131,072 B (128 KB) | 65.5% |
|
||||
| ER_IROM1 | 275,976 B (269.51 KB) | 1,048,576 B (1024 KB) | 26.3% |
|
||||
| RW_IRAM1 | 94,312 B (92.10 KB) | 131,072 B (128 KB) | 72.0% |
|
||||
| RW_CCM | 57,376 B (56.03 KB) | 65,280 B (64 KB) | 87.9% |
|
||||
| **Flash (ROM 合计)** | **270,152 B (263.8 KB)** | 1,048,576 B (1024 KB) | **25.8%** |
|
||||
| **Flash (ROM 合计)** | **278,012 B (271.5 KB)** | 1,048,576 B (1024 KB) | **26.5%** |
|
||||
<!-- MEM_SNAPSHOT:END -->
|
||||
|
||||
各区的容量与常量来源:
|
||||
|
||||
+14
-9
@@ -15,19 +15,19 @@
|
||||
<!-- MEM_BUDGET:BEGIN generated by scripts/ram_baseline.py -->
|
||||
| 区域 | 用量 | 容量 | 占比 | 门禁(≤92%) |
|
||||
|---|---|---|---|---|
|
||||
| ER_IROM1 (Flash) | 268,220 B | 1,048,576 B | 25.6% | 参考 |
|
||||
| ER_IROM1 (Flash) | 275,976 B | 1,048,576 B | 26.3% | 参考 |
|
||||
| RW_CCM | 57,376 B | 65,280 B | 87.9% | PASS |
|
||||
| UNINIT_CCM | 48 B | 256 B | 18.8% | 参考 |
|
||||
| RW_IRAM1 | 85,904 B | 131,072 B | 65.5% | PASS |
|
||||
| RW_IRAM1 | 94,312 B | 131,072 B | 72.0% | PASS |
|
||||
|
||||
| 子系统(静态 RW+ZI;除 RTOS 堆在 CCM 外均在 SRAM1) | 现值 | 配额 | 状态 |
|
||||
|---|---|---|---|
|
||||
| 网络 | 13,702 B | 12 KB | ⚠ 超 1.4 KB |
|
||||
| 存储 | 7,072 B | 12 KB | OK |
|
||||
| UI | 34,657 B | 16 KB | ⚠ 超 17.8 KB |
|
||||
| UI | 36,429 B | 16 KB | ⚠ 超 19.6 KB |
|
||||
| RTOS 堆 | 57,376 B | 56 KB | 堆=配额 |
|
||||
| 应用 | 15,552 B | 8 KB | ⚠ 超 7.2 KB |
|
||||
| 其它 | 14,917 B | — | 参考 |
|
||||
| 应用 | 26,333 B | 8 KB | ⚠ 超 17.7 KB |
|
||||
| 其它 | 10,768 B | — | 参考 |
|
||||
<!-- MEM_BUDGET:END -->
|
||||
|
||||
- **门禁**:pre-commit `mem-budget` 钩子(`scripts/ram_baseline.py --gate`)——
|
||||
@@ -51,8 +51,8 @@ UI 16 KB / RTOS 堆 56 KB / 应用 8 KB**。归集口径(按 `.map` 对象名
|
||||
| 存储 | `gd5f*` `nand_*` `ff*` `diskio*` `vol_lock*` + dhara 裸名(`map/journal/nand/fctl/era.o`) | `cfg_*`(算应用) |
|
||||
| UI | `lv_*` `ui_*`(含 `ui_net_sink`、`ui_task`) | — |
|
||||
| RTOS 堆 | `heap_4.o`(CCM)——配额 = `configTOTAL_HEAP_SIZE` 本身 | 内核对象(`tasks/queue/timers/...` 归"其它") |
|
||||
| 应用 | `App/` 其余:采集 `adc_*`、保护 `prot_*`、相量 `phasor/sample_ring`、配置 `cfg_*`、日志 `sys_/dbg_/console_log`、对时 `time_sync*`、`sys_clock`、`task_watchdog`、`sha256`、`tpafe*`、`sd2506`、`default_task` 等 | — |
|
||||
| 其它 | 内核对象、HAL、CMSIS、启动文件、C 库、链接器填充 | — |
|
||||
| 应用 | `App/` 其余——**前缀清单以 `scripts/ram_baseline.py` 的 `subsystem_of()` 为准**:`adc_*` `tpafe*` `sd2506` `prot_*` `protect_task` `phasor` `sample_ring` `wave_*` `meas` `freq` `run_par` `iec104*` `soe_*` `cfg_*` `sys_*` `dbg_*` `console_log` `time_sync*` `sys_clock` `task_watchdog` `sha256` `default_task` `test_task` `task_prof` `boot_stats` `vol_idle_sync` | `App/task/ui_task*`(首匹配算 UI) |
|
||||
| 其它 | 内核对象、HAL、CMSIS、启动文件、C 库、链接器填充——**不含 `App/` 任何对象**:漏登记会被 `--gate` 的兜底 WARN 逐条点名(2026-10-29 加) | — |
|
||||
|
||||
**现状判读(2026-10-12 建档)**:
|
||||
|
||||
@@ -62,9 +62,12 @@ UI 16 KB / RTOS 堆 56 KB / 应用 8 KB**。归集口径(按 `.map` 对象名
|
||||
**这条 ⚠ 会长期挂着**,判读时按已知挂账处理,别每轮当新问题追;重开条件 → `RAM使用分析与优化方案.md` §4。
|
||||
- **RTOS 堆 = 配额本身**:56 KB 即 `configTOTAL_HEAP_SIZE`(2026-10-12 B5 由 48 KB 扩容,见 §6;
|
||||
`heap_4.o` 另含 32 B 元数据,不计超);**改堆 = 改配额**,必须先过本文件 §6 登记。
|
||||
- **应用 ⚠ 小幅超**:8 KB 为报告规划值;2026-10-10 栈整改把 3 处 `FIL` 从栈搬进 BSS
|
||||
- **应用 ⚠ 超配额**(现值见 §1 受管区):8 KB 为报告规划值;2026-10-10 栈整改把 3 处 `FIL` 从栈搬进 BSS
|
||||
(静态 +4,128 B,见 `docs/内存管理/RAM使用分析与优化方案.md` §4"2026-10-10 复测")——
|
||||
属已评审的"以空间换栈安全",差额在此如实体现。
|
||||
属已评审的"以空间换栈安全";2026-10-29 故障录波落盘道又把 `default_task.o` 推高 1,204 B。
|
||||
**同日修正归集口径**:`subsystem_of()` 此前没有 `wave_` `iec104*` `soe_` `meas` `freq` `run_par`
|
||||
等前缀,12 个 `App/` 对象 9,445 B 被静默算进「其它」(当时「应用」行只有 16,888 B,看着离配额不远);
|
||||
补齐后本行才真含录波环 `wave_ring.o`(约 5.3 KB)。per-file 全貌 → `docs/内存管理/内存内容分配策略.md` §6。
|
||||
|
||||
## 3. CCM 分配台账(谁能用 CCM)
|
||||
|
||||
@@ -96,3 +99,5 @@ UI 16 KB / RTOS 堆 56 KB / 应用 8 KB**。归集口径(按 `.map` 对象名
|
||||
| 2026-10-12 | 建档:三件套落地(本台账 + `scripts/ram_baseline.py` + `scripts/ram_baseline.tsv` + pre-commit `mem-budget` 钩子) | 登记簿 N-27 前半 |
|
||||
| 2026-10-12 | **RTOS 堆配额 48 KB → 56 KB**(`QUOTAS` 同步) | B5 protectTask 立项:iec104Task(2.5KB)+protectTask(2KB)+TCB 入堆后 48KB 池 min_ever 预估跌破 3,072 B 告警线 → `.ioc` 语义取数与有效性参数 `configTOTAL_HEAP_SIZE` 49152→57344(CCM 水位 75.3%→87.9%,仍 <92% 门禁;CCM 空闲降至 ≈8 KB)。连带影响见 §3 迁 CCM 后半链注记 |
|
||||
| 2026-10-12 | **任务栈 +1536 B(堆内用量,配额 56 KB 不变)**:defaultTask 1024→1280 words(+1024 B)、timeSyncTask 512→640 words(+512 B);产品任务栈合计 37,632→39,168 B | 登记簿 N-33 栈收口:B7 定值持久化把 defaultTask 静态链推到 3016 B(余 1080 < 30% 线)、timeSyncTask 链 1264 B(余 784 < ISR 底线 1024);B6 台架背书 min_ever=10000 → 抬后实测 `heap free=16400 / min_ever=8464`(与预算 −1536 完全吻合,>3072 告警线);`stack_report` 9 任务 0 FAIL + `@test` PASS,见 `RAM使用分析与优化方案.md` §1.4 |
|
||||
| 2026-10-29 | **故障录波数据面入册**:新增对象 `wave_ring.o` 5,300 B(ZI 5,256 + RW 44,落 SRAM1、CCM 增量 0);`default_task.o` 静态 2,736 → 3,940 B(+1,204 B,落盘道 `FIL` 528 + 分片缓冲 256 + 段头副本 136 + 段路径 17 + 打包上下文与 `DIR`/`FILINFO`);`RW_IRAM1` 81,536 → 89,936 B(62.2 % → 68.6 %,仍远低于 92 % 门禁);`RW_CCM` 三档恒 57,376 B | 决定人 lead。实测数字出自 lead 的权威构建(本工作树 `MDK-ARM/STM32F407-Demo/STM32F407-Demo.map`,0 错误 0 警告,`scripts/ram_baseline.py --update` 同批入 tsv);预估约 5.9 KB vs 实测数据面 +6,760 B 的差额构成与三档对照见 `docs/内存管理/内存内容分配策略.md` §6;**未抬栈**(`scripts/stack_report.py` 九任务全 PASS),判据出处 `docs/子系统设计/故障录波设计说明.md` §7 |
|
||||
| 2026-10-29 | **归集口径修正(非配额改动)**:`subsystem_of()` 补 `wave_` `iec104*` `soe_*` `meas` `freq` `run_par` `protect_task` `task_prof` `boot_stats` `vol_idle_sync` 等前缀——12 个 `App/` 对象 9,445 B 此前静默落「其它」;「应用」16,888 → 26,333 B、「其它」15,849 → 6,404 B,区域水位与 92% 红线均未变。同脚本加兜底:`App/**/*.c` 的对象落进「其它」时 `--gate` 逐条 WARN(不拦) | 配额表看不见录波/SOE 支路;口径依据本文件 §2「应用 = `App/` 其余」 |
|
||||
|
||||
+21
-3
@@ -110,17 +110,35 @@ CCM 64KB 只能容纳 {FreeRTOS 堆 48KB} 与 {LVGL 集合 ~52.5KB} 之一(两
|
||||
触发条件:测试构建 SRAM 余量不足,**且**已耗尽 `RAM使用分析与优化方案.md` 的帧副本去重(−6.4~9.6KB)与 LVGL 池缩减等低代价手段。
|
||||
流程:改 scatter → 走 §7 完整验证阶梯 → 同步更新本文档、`AGENTS.md`、`.sct` 头注释。在此之前,方案 A 是唯一有效布局。
|
||||
|
||||
## 6. 当前容量台账(2026-10-12,产品构建;2026-09-21 最坏构建=存储套件的历史基线见 `docs/内存管理/RAM预算台账.md` 趋势)
|
||||
## 6. 当前容量台账(2026-10-29,产品构建 task/wave-record 分支终值;2026-09-21 最坏构建=存储套件的历史基线见 `docs/内存管理/RAM预算台账.md` 趋势)
|
||||
|
||||
| 区域 | 总量 | 已用 | 空闲 | 驻留内容 |
|
||||
|---|---|---|---|---|
|
||||
| RW_IRAM1(SRAM) | 131,072B (128KB) | 95,816B (~93.6KB, 73.1%) | 35,256B (~34.4KB) | 全部静态(除堆),含 LVGL 集合 53,805B |
|
||||
| RW_CCM | 65,536B (64KB) | 57,376B (56KB, 87.9%) | 8,160B (~8KB) | **仅** `heap_4.o`(ucHeap 56KB,2026-10-12 B5 扩容) |
|
||||
| RW_IRAM1(SRAM) | 131,072B (128KB) | 89,936B (87.83KB, 68.6%) | 41,136B (~40.2KB) | 全部静态(除堆),含录波环 `wave_ring.o` 5,300B 与 LVGL 池 16,384B(`lv_mem_core_builtin.o` 实测) |
|
||||
| RW_CCM | 65,280B(64KB 减 256B `UNINIT_CCM` 尾,与 `.sct` 一致) | 57,376B (56.03KB, 87.9%) | 7,904B | **仅** `heap_4.o`(ucHeap 56KB,2026-10-12 B5 扩容);256B 尾区现用 48B |
|
||||
|
||||
数字身份:`RW_IRAM1` / `RW_CCM` / `ER_IROM1` 三行取自 lead 2026-10-29 权威构建(本工作树 `MDK-ARM/STM32F407-Demo/STM32F407-Demo.map`,0 错误 0 警告,`scripts/ram_baseline.py --update` 同批入 tsv)。受管快照区在 `docs/内存管理/RAM使用分析与优化方案.md`,子系统配额表在 `docs/内存管理/RAM预算台账.md`,两处由脚本渲染、本卡不手改。
|
||||
|
||||
LVGL 集合明细(均在 SRAM):LVGL 池 16,384B(`lv_mem_core_builtin.o`,`LV_MEM_ADR=0` 内部静态)+ `g_ui_draw_buf` 3,232B(3200+32 保护带)+ `g_ui_fbuf` 3,200B + `g_tx` 3,209B + `g_lcdmem_data` 3,204B。
|
||||
|
||||
产品构建比套件构建少 testTask/测试缓冲(约 40KB 级),SRAM 余量更大。数字以 map 实测为准,布局变更后必须重测并更新本表。
|
||||
|
||||
录波支路静态(2026-10-29 入册,R6 要求;**全部落 RW_IRAM1、无 section 属性,CCM 增量 0**):
|
||||
|
||||
| 归属对象 | 增量 | 构成 |
|
||||
|---|---|---|
|
||||
| `wave_ring.o`(`App/algo/wave_ring.c`) | 5,300 B(ZI 5,256 + RW 44) | 录波环 int16×320 点×8 路 = 5,120 B 主体 + 已封存段头副本 136 B + 状态/索引/观测计数;map 比代码侧手算多 2 B,是链接器对齐 |
|
||||
| `default_task.o`(落盘道,函数内 `static`) | +1,204 B(2,736 → 3,940,同 tsv 的 RW+ZI 口径) | `FIL` 528 B(`FF_FS_TINY=0`,刻意不上栈)+ 分片搬运缓冲 256 B + 段头副本 136 B + 段路径 17 B + 打包上下文/`DIR`/`FILINFO`/状态字节约 267 B(对象级增量,未逐项拆分实测) |
|
||||
| `adc_task.o` 及其余数据面 | 约 256 B | 8 路语义原码暂存与封存瞬间交棒结构(`App/task/adc_task.c`);与上两行相加 = 数据面实测 +6,760 B |
|
||||
| UI 道:`ui_page_wave_play.o` 92 B、`ui_page_wave_manual.o` 28 B、`ui_task.o`、`ui_data.o` | 区级合计 +1,640 B | 两个新页面模块按 map 计 120 B;`ui_task.o`/`ui_data.o` 的增量拆分需要本波之前的 per-file 快照,本卡没有 → **只记区级增量,不猜分项** |
|
||||
|
||||
- **三档对照(SRAM1)**:81,536 B / 62.2 %(`scripts/ram_baseline.tsv` 2026-10-28 行)→ 88,296 B(录波数据面终值)→ **89,936 B / 68.6 %**(含 UI 道终值),累计 **+8,400 B**;`RW_CCM` 三档恒 57,376 B —— 设计文档 `docs/子系统设计/故障录波设计说明.md` §7 的「不进 CCM」落位达成,也没有挤动 CCM。
|
||||
- **预估 vs 实测都要留**:设计文档 §7 原估静态增量约 5.9 KB(环 5,120 + 索引状态 32 + 双缓冲 512 + 读窗 256),实测数据面 +6,760 B。差额构成:`FIL` 528 B、`DIR`/`FILINFO`、段头副本 136 B、打包上下文(内含一份 136 B 段头)原估未记账;反向一项——落盘实际是**单缓冲 256 B**,不是预估的 512 B 双缓冲。只写实测会让下一次估算照着 6.7 KB 走、看不到原估漏了哪几项。
|
||||
- **Flash**:`ER_IROM1` 264,580 → 270,248(数据面 +5,668 B)→ 272,300(UI 道 +2,052 B)→ 272,360(落盘判废复检 +60 B)→ **272,336 B**(cppcheck 返工:把变量声明搬进最小作用域,纯搬声明 −24 B),累计 **+7,756 B**、占 26.0 %;`Total ROM` 274,308 B(26.2 %)、`Code` 243,552 B。RAM 三项(RW 1,972 / ZI 145,388 / RW_IRAM1 89,936 B / 68.6 %)与 CCM 57,376 B / 87.9 % 均未变。
|
||||
- **栈:9 任务全 PASS、未抬栈**(`scripts/stack_report.py` 静态最坏链)——adcTask 1,424 B(余 1,136 B / 44 %)、defaultTask 3,040 B 不变、protectTask 880 B、uiTask 1,336 B(余 15,048 B / 91 %)。R6 三处同步里 `AGENTS.md` 栈表这一处的结论是**核对过、数值未变**。
|
||||
- **为什么比上一版低**:本表 2026-10-12 版记 95,816 B / 73.1 %,高于今天的 89,936 B。原因是此后 LVGL 内部池由 40 KB 缩到 16 KB(`docs/内存管理/RAM预算台账.md` §3「缩池 ✅ 2026-10-15」行;`scripts/ram_baseline.tsv` 2026-10-12 与 2026-10-24 两行的 `top_rwzi` 列可见 `lv_mem_core_builtin.o` 40960 → 16384)——**不是本波回收了什么**。
|
||||
|
||||
- **子系统归集的坑(本卡实测 → 2026-10-29 已修)**:`scripts/ram_baseline.py` 的 `subsystem_of()` 按对象名前缀首匹配,当时表里没有 `wave_` 前缀 → 录波环 `wave_ring.o` 5,300 B 落进 **「其它」(当时 15,853 B,参考值、无配额)**,配额 8 KB 的「应用」行看不见它;落盘道 `default_task.o`(+1,204 B)与 `adc_task.o` 才计入「应用」(当时现值 16,888 B,本波前该行已在配额外,成因见 `docs/内存管理/RAM预算台账.md` §2 的应用条目)。**同日后续**:补齐 12 个 `App/` 对象(9,445 B)的前缀,并加兜底——`App/**/*.c` 编出的对象只要落进「其它」,`python scripts/ram_baseline.py --gate` 就逐条 WARN 点名(软提醒不拦)。结论仍然有效:**子系统配额行不是录波预算的判据**,要按本节 per-file 台账读;差别只在「应用」行现在真含录波支路,两个口径不再互相看不见。
|
||||
## 7. 布局变更验证阶梯(强制执行)
|
||||
|
||||
任何 scatter / CCM / 堆大小变更后,依次通过以下全部关卡方可认定生效:
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
折算层 2026-10-25 落地;二次值等两点标定置 VALID)。槽位值/品质整体透传,本层
|
||||
**不再自行判新旧**(快照 `seq` 仅供 COV 去重)。
|
||||
- 品质映射:快照 `MEAS_QDS_*` 低字节与线上 QDS 同值直传;**CLIPPED → IV**(「削顶通道
|
||||
恒 IV」口径不变、改由品质驱动,docs/任务规划/数据可信.md §8 风险表末行的单测要求);
|
||||
恒 IV」口径不变、改由品质驱动,docs/任务规划/数据可信.md §8 风险表「削顶通道被当成可测」行的单测要求);
|
||||
快照从未发布(开机 <200 ms)→ IV|NT;判定顺序 IV 优先于 NT。
|
||||
- 死区(104 改读快照):从「越死区即报」改为**连续 2 个新测量点越限才确认**——板端测量点 =
|
||||
快照换帧(100 ms 轮询 vs 200 ms 快照按 `seq` 去重,防同一帧把单点噪声重复计满 2 点;
|
||||
|
||||
@@ -481,9 +481,3 @@ D4 否决理由对现状仍逐条成立(115200 发送率低、日志行稀疏
|
||||
| `tx_timeout` 读口接线(STALL 证据行加字段) | §13-O2 | 涉 `App/util/task_watchdog.c` 与被解析证据行的台架判据,非本卡写域;维持 O2“后续项” |
|
||||
| 未注册期裸发互斥 / `printf` 遗留开销 | §13-O1/O3 | 现状 = 纪律已落地,开机日志密度上升再议 |
|
||||
| 日志静默观察项 | 登记簿曾登记(已销项) | 见 A.3:V5 复跑双零后销项(归 lead) |
|
||||
|
||||
---
|
||||
|
||||
## 修订记录
|
||||
|
||||
> (本文件不再记流水账:改了什么是正文说了算,改动过程查 git log。)
|
||||
|
||||
+67
-18
@@ -1,8 +1,8 @@
|
||||
# 故障录波设计说明(1 kHz · 8 路原始码值 · 现场单通道回放)
|
||||
|
||||
> **模块名称**:故障录波——采样源沿用 TIM3 1 kHz 节拍,专用录波环(拟新增 `App/algo/wave_ring.c`)、触发、落盘(defaultTask 是文件系统唯一写者)、取回(FTP 21 端口)、现场回放(UI 单通道页)。
|
||||
> **模块名称**:故障录波——采样源沿用 TIM3 1 kHz 节拍,专用录波环(`App/algo/wave_ring.c`,已落地)、触发、落盘(defaultTask 是文件系统唯一写者)、取回(FTP 21 端口)、现场回放(UI 单通道页)。
|
||||
> **文档定位**:本波的**设计属主**——口径、通道集、数据形态、触发模型、文件格式、预算与所有权边界、显示契约、二期不返工的结构约束在此定稿。**排期与卡片判据在 `docs/任务规划/故障录波.md`**,本文不写排期。
|
||||
> **状态**:P0 设计定稿(2026-10-29),**代码一行未动**。三条已裁定口径见 §1.2。
|
||||
> **状态**:设计已定稿,**数据面 + 触发与落盘接线 + UI 两个页面(手动录波、录波回放)的代码面已交付(2026-10-29)**——主机单测 113 / 170 / 110 全 rc=0、双端编译 0 错误 0 警告、板端编码器与 PC 侧解码器两份独立实现字节级互验通过。**没做完的只有板级判据那一轮**(注量对表、FTP 拉回、与 `meas:` 和 104 浮点 YC 对表、CRC 不符必须拒收的实测、回放页放一段真波、两个待台架核数值),逐条列在 docs/任务规划/故障录波.md 各卡的板级段。三条已裁定口径见 §1.2。
|
||||
> **相关文档**:
|
||||
> `docs/子系统设计/ADC采样节拍设计说明.md`(节拍与时序账的属主;本文 §3 的数据源就是它)
|
||||
> `docs/硬件平台/ADC通道映射说明.md`(网名 `AINn` 不等于板级 `ADCn`,也不等于转换器通道号;链路分段与削顶归属)
|
||||
@@ -106,16 +106,19 @@
|
||||
|
||||
| 触发 | 来源 | 本波 |
|
||||
|---|---|---|
|
||||
| **手动** | UI「手动录波」操作页(该叶子早已在菜单里:`ui_menu_tree.txt` 装置维护组,现未绑页) | 做 |
|
||||
| **保护启动** | `App/algo/prot_elm.c` 的 `picked` 上升沿(元件启动),与 `/log/start.log` 同源,避免两处各自判定 | 做(复用事件点,不新增判据) |
|
||||
| **手动** | UI「手动录波」操作页(叶子在菜单装置维护组,页面模块 `Drivers/BSP/UI/ui_page_wave_manual.c`,2026-10-29 已绑页;确认键在 `App/task/ui_task.c`:582 行调 `wave_ring_request()`,走手动来路、元件号填 0) | 做(已落地) |
|
||||
| **保护启动** | 落点在 `App/task/protect_task.c` 的 `s_log_record_edge()`(函数体自 158 行起,picked 上升沿分支 170 到 177 行,实际调用在 176 行:`wave_ring_request(WAVE_TRIG_PROTECT, 最低位上升元件)`),与 SYSLOG_START 同一条边沿、同一事件点,避免两处各自判定。**刻意不落在 `App/algo/prot_elm.c`**:判据核被三套主机单测源码级纳入编译,往它加录波依赖会一次全破——这条就是「判据核零改动」的前提。多元件同拍启动只录一段(环不重入,后续请求由环计 ovf,不算失败) | 做(复用事件点,不新增判据) |
|
||||
| 定周期自抓 | `DTU_BENCH` 构建下每 N 秒强制一段,供信号发生器对表 | 做,**只在 bench 构建**,产品构建无此路径 |
|
||||
| **突变量启动** | 需要增量化 `Δi` 类算法与定值 | 不做,归二期(`docs/算法/继电保护功能复现规划.md` 的「故障启动(波形启动)」行) |
|
||||
|
||||
### 4.2 段长与冻结语义(RAM 就靠这一条省下来)
|
||||
|
||||
- 一段 = **预触发 8 周波 + 后触发 8 周波 = 320 点/路**(1 kHz 下 320 ms);
|
||||
- **段内点序**(两份实现共同遵守,PC 与回放页都按这条):触发那一拍的样本落在**段内点 159**(预触发 160 点的最后一点),后触发第一拍是**点 160**,两半不重叠,故障时刻就是这条分界。因此段内点 0 相对工频周期边界有任意偏移(触发瞬间在周期内任意落点),**段字节里没有绝对时间参考**——能核对的是相对相位与极性,绝对相位只能以段内点 0 为参考报出(§10 板级判据据此不比绝对相位);
|
||||
- **触发即冻结环**:停止推进录波写指针,defaultTask 直接从已冻结的环落盘,落完解冻;
|
||||
- **冻结期间丢的是录波样本,不是采集**——`sample_ring`、相量、保护判据照常跑(这就是 §2.1 第 3 条要求解耦的原因),冻结不拖慢保护动作,也不让 104 断数;
|
||||
- **解冻的唯一入口是落盘方回执**(`wave_ring_write_done(result)`,只在 defaultTask 上下文调):写成功才推进轮转段号,写失败只计 err 且**下一段重写同一个号**(不留半截文件);冷却期从回执之后才开始计时,回执前新触发一律只加 ovf。「落完解冻」这条原本按时间窗口的假设,实现里改由回执保证,冷却数值只是二次抑制。
|
||||
- 兜底(绝不允许录波把环焊死):封存态滞留超过 `WAVE_SEAL_TIMEOUT_MS`(当前 2000 拍 = 2 s,**待台架核**)就自弃本段、计 err 并解冻——卡在一次落盘上,代价是下一次真故障无波可录。
|
||||
- 代价:一次触发的落盘窗口(约几十 ms)内再来触发只记第一次(冷却期),**不做多段排队**——那是二期「6 段 / RAM 16 个」的形态。
|
||||
|
||||
```mermaid
|
||||
@@ -150,13 +153,14 @@ flowchart TD
|
||||
| **uiTask**(回放页) | 只读窗口取段数据 → 自绘(与 `App/log/soe_store.c` 读侧同构) | 不写文件 |
|
||||
| **netTask / lftpd** | 把 /wave 暴露给 FTP 取回 | 不在 netTask 里读录波环 |
|
||||
|
||||
### 5.2 三条已知陷阱,本波必须绕开
|
||||
### 5.2 四条已知陷阱,本波必须绕开
|
||||
|
||||
| 陷阱 | 事实出处 | 本波处置 | |
|
||||
| ------------- | ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | --------------------------------------------------------- |
|
||||
| **取窗竞态** | `App/algo/sample_ring.c` 的 `sample_ring_window()` 没有临界区(读 `s_head` 后逐点拷),现在只有 adcTask 同任务调用才安全 | 录波**不复用它**:adcTask 在自己的节拍里取「本拍帧」压专用环;跨任务只传递「已封存」标志,杜绝跨任务读活缓冲 | |
|
||||
| **FatFs 追加写** | 该移植 `FA_OPEN_APPEND` 不含 `FA_WRITE`,且 `f_write` 簇分配失败时返回 `FR_OK` 加短写、无错误码(`docs/架构设计/STM32F4-Base存储架构说明.md` §10.1) | 打开一律 `FA_WRITE | FA_OPEN_APPEND`;**判成功必须比对写回字节数**,短写按失败处理(丢段 + 日志),绝不当成功记账 |
|
||||
| **只能 8.3 短名** | 出处同一张存储架构说明的短名限制:`FF_USE_LFN=0`,不得以点开头、不得长名 | 文件名 = WAVE 加两位十进制再加 .BIN,共 100 个名字轮转覆盖;目录 /wave(与 /log 平级,FTP 根下可见) | |
|
||||
| 陷阱 | 事实出处 | 本波处置 |
|
||||
|---|---|---|
|
||||
| **取窗竞态** | `App/algo/sample_ring.c` 的 `sample_ring_window()` 没有临界区(读 `s_head` 后逐点拷),现在只有 adcTask 同任务调用才安全 | 录波**不复用它**:adcTask 在自己的节拍里取「本拍帧」压专用环;跨任务只传递「已封存」标志,杜绝跨任务读活缓冲 |
|
||||
| **FatFs 追加写** | 该移植 `FA_OPEN_APPEND` 不含 `FA_WRITE`,且 `f_write` 簇分配失败时返回 `FR_OK` 加短写、无错误码(`docs/架构设计/STM32F4-Base存储架构说明.md` §10.1) | 打开一律 `FA_WRITE\|FA_OPEN_APPEND`;**判成功必须比对写回字节数**,短写按失败处理(丢段 + 日志),绝不当成功记账 |
|
||||
| **只能 8.3 短名** | 出处同一张存储架构说明的短名限制:`FF_USE_LFN=0`,不得以点开头、不得长名 | 文件名 = WAVE 加两位十进制再加 .BIN,共 100 个名字轮转覆盖;目录 /wave(与 /log 平级,FTP 根下可见) |
|
||||
| **落盘途中环被解冻、甚至已换段**(实现期复核新增第四条,2026-10-29) | adcTask 优先级高于 defaultTask:搬段窗口里 adcTask 可能正好走到 SEALED 滞留 2 s 自弃,甚至已经封出下一段。**数据区 CRC 是对「本道实际读到的字节」算的**,半新半旧的段照样自洽——长度等式照过、两个 CRC 照对,文件骗得过任何读者,也骗过我们自己 | 写完关档后**复检环侧身份**:`wave_ring_sealed()` 仍为 1,且 `wave_ring_get_stat()` 的 `last_t0_ms` 与 `last_seq` 跟本道开始搬时那份段头一致;不符即走既有失败路——unlink 本道开过的文件 + `write_done(-1)`(此时多半回 `E_STATE`,环侧 `err` 已由自弃计过,不重复补账)+ 段号不推进(下一段同号重写覆盖)+ 单条 `[ERR] … seg drop: ring abandoned` 留痕。落点 `App/task/default_task.c`:786 到 796 行。**当前只有代码与单测面,板级未测**;可观察项见 §10 板级行 |
|
||||
|
||||

|
||||
|
||||
@@ -193,16 +197,44 @@ flowchart TD
|
||||
| 14 | t0_ms | 4 | 段首相对上电时刻;配合墙钟还原绝对时刻 |
|
||||
| 18 | wall | 4 | 对时后的 epoch 秒(未对时为 0) |
|
||||
| 22 | eng | 1 | 封存瞬间的折算档位:0 引脚域、1 二次值、2 一次值 |
|
||||
| 23 | flags_seq | 1 | 有效性位图(引 `adc_cal_flags()` 口径) |
|
||||
| 24 | clip_mask | 2 | 削顶归属(V0.1 恒 0xE6,见 `docs/任务规划/数据可信.md` §2.7) |
|
||||
| 23 | flags_seq | 1 | 每路 VALID 压成的位图:bit s = 语义通道 s 的 `ADC_CAL_F_VALID`(电气 8 路恰好占满 1 字节;TEMP 不参与标定,若要带 TEMP 连本行与下一行一起升版本) |
|
||||
| 24 | clip_mask | 2 | 削顶归属位图:bit s = 语义通道 s,与 `App/algo/meas.h` 同名参数同口径(封存瞬间 `ADC_CAL_F_CLIPPED` 快照,V0.1 恒 0xE6 = UB/UC/IB/IC/IN,见 `docs/任务规划/数据可信.md` §2.7)。⚠ **这个位图的本体是「链路可信性标记(按来源派生)」,不是「本段实测饱和标记」**:置位条件一次样本都不看(`App/algo/adc_cal.c` 291 到 296 行,该路 ROM 系数属片内 ADC 侧即置位);「这一段有没有真钉轨」走另一条链——`App/algo/adc_health.c` 的 `adc_health_rail_watch()`(280 行起)与 `adc_health_rail_sticky()`,门限按满量程百分比由 `adc_cal_rail_ths()` 给、须连续 `ADC_RAIL_N_RUN` 拍。V0.2(8 路全接 TPAFE)后本位自动恒 0,届时「与 clip_mask 对表」这条判据退化为只查钉轨实测(§10) |
|
||||
| 26 | frame_seq | 4 | 段首帧序号,可与串口周期行的 frames 对账 |
|
||||
| 30 | 通道表 | 每路 12 | 语义号 1 + 来源转换器 1 + 位宽 1 + 有效位 1 + LSB(µV) 4 + k 2(定点)+ b 2(定点) |
|
||||
| — | CRC16(头) | 2 | 与屏板链路同一张 CRC-16/MODBUS 表,不新造 |
|
||||
| 30 | 通道表 | 每路 12 | 语义号 1 + 来源转换器 1 + 位宽 1 + 可用性 1(= `adc_cal_flags(sem)` 低 8 位原值,不自造位义)+ `k_q16` 4(int32,µV/码 × 65536)+ `b_codes` 4(int32,码值)。**没有独立 LSB 字段**,LSB 就是 `k_q16`,见 §6.3 |
|
||||
| — | CRC16(头) | 2 | CRC-16/MODBUS,**低字节在前**(与全文件小端统一);覆盖 `[0, 30+12×ch_count)`,本字段自身紧随其后 |
|
||||
| — | 数据区 | pts_per_ch × ch_count × 2 | **按通道分列**:一路连续 320 点,单通道回放只读那一路 |
|
||||
| — | CRC16(数据区) | 2 | 长度为 0 或 CRC 不符 → 整段作废,页面必须显示「该段不可读」 |
|
||||
| — | CRC16(数据区) | 2 | 同上字节序;覆盖整个数据区、自身在文件尾(8 路 320 点整段 5250 B);长度为 0、任一 CRC 不符、或 `ver` 与魔数第三字节不等 → 整段作废,页面必须显示「该段不可读」 |
|
||||
|
||||
**段名轮转的呈现语义**(回放页与 PC 侧取「哪一段最新」都按这条):段表按**数值升序**呈现,开屏落点取**数值最大的段号**。回绕(99 之后回到 00)之后「数值最大」不再等于「时间最新」——要真时间序必须逐段读段头 `frame_seq` / `t0_ms`,代价是 100 次开文件,**本波不做**。所以页顶把段号本身显示出来(§8.1 顶部行),让读者自己看见这是第几号,不去伪造一个「最新」的假象。
|
||||
|
||||
### 6.3 字段口径裁定(两份独立实现的共同依据)
|
||||
|
||||
本波段格式有**两份独立实现**:板端编码器 `App/algo/wave_store.c` 与 PC 解码器 `test/host/wave_read.py`,两份必须逐字节同解,所以动工前把 §6.2 的含糊处一次钉死(PC 道九问的逐条答复):
|
||||
|
||||
| 问题 | 裁定 |
|
||||
|---|---|
|
||||
| CRC 字节序 | **低字节在前**,与全文件小端一致。原稿「与屏板链路同一张 CRC-16/MODBUS 表」不成立:全仓**没有**可复用的 CRC-16 表——`App/util/README.md` 记 `crc.c/h` 已于 2026-10-02 删除,屏板链路 `Drivers/BSP/UI/ui_net_sink.c` 的 `remo_crc()` 是单字节异或、不是 CRC-16。本波在 `wave_store.c` 内自带**无表位运算** CRC-16/MODBUS(0x8005 反射、初值 0xFFFF、异或输出 0),单测锚点:串 123456789 的 CRC = 0x4B37 |
|
||||
| CRC 覆盖范围 | 头 CRC 覆盖 `[0, 30+12×ch_count)`、自身在 `30+12×ch_count`;数据区自 `32+12×ch_count` 起;数据 CRC 覆盖整个数据区、自身在文件尾。8 路 320 点整段 5250 B |
|
||||
| LSB 从哪来 | **不设独立 LSB 字段**:通道表的 `k_q16` 就是 LSB(µV/码 × 65536),与 `App/algo/adc_cal.h` 的 `ADC_CAL_K_Q16_TPAFE 10000000` / `ADC_CAL_K_Q16_STM32 52800000` 同口径,Q16 下无舍入(选型依据 `docs/任务规划/数据可信.md` §4.1)。PC 侧 `µV = k_q16 / 65536`,不许再乘一遍 |
|
||||
| k / b 宽度与角色 | `k_q16` int32、`b_codes` int32 = 封存瞬间该路生效的两个标定量。`adc_cal_apply()` 的算式是 `eng = (code + b) × k × 1e-6`,文件里存的正是等号右边两个数加原始 code,PC 照此重算。**必须取 int32 原值**,不得经 `adc_cal_k_uv()` 的 float 通道回算(float 在 5.28e7 量级掉尾数)→ 接线道在 `App/algo/adc_cal.[ch]` 补一个 int32 直读入口 `adc_cal_k_q16()`(与 `adc_cal_k_uv()` 孪生);eng=0 时两者是 ROM 默认值,PC 折出来的单位是**引脚域 µV** 而非二次值——单位一律以头里的 `eng` 为准,PC 不许按当前固件口径猜 |
|
||||
| `flags_seq` 位义 | bit s = 语义通道 s 的 `ADC_CAL_F_VALID`;本波 `ch_count` 固定 8 |
|
||||
| 可用性字段真值表 | 两行,实现期按 `App/algo/adc_cal.c` 280 到 298 行核出(VALID 需文件位图与 k 合法带**同时**成立;CLIPPED 纯由来源派生——该路 ROM 系数属片内 ADC 侧即置位,与样本内容无关):① **未标定**(产品构建,两点标定未做)逐路 availability = UA / UN / IA 取 `0x00`,UB / UC / IB / IC / IN 取 `0x02`,`flags_seq` = `0x00`,`clip_mask` = 0xE6;② **已标定**(电气 8 路系数全部写入且落合法带)逐路 = `0x01`(TPAFE 三路)/ `0x03`(片内 ADC 五路,VALID 与 CLIPPED 同时为真),`flags_seq` = `0xFF`,`clip_mask` 仍是 0xE6。**VALID 与 CLIPPED 是两件独立事实**:写侧如实透传 `adc_cal_flags()` 逐路原值(`App/task/adc_task.c` 548 行),读侧不得据任何品质组合判废,PC 与回放页只给软告警(见下面「判废面与软告警面」一行) |
|
||||
| eng 派生式 | `eng` 不是独立事实,是逐路有效位图的派生量:**电气 8 路全 VALID → 二次值(1),缺任意一路 → 引脚域(0)**。真机两处必须同口径,行号一并登记:判据本体 `App/app/ui_data_feed.c` 226 到 235 行的 `feed_eng()`(屏显侧),段头字段填写 `App/task/adc_task.c` 532 到 553 行(其中 552 到 553 行是段头侧的同一派生)。两处分布在**不同任务里现算**,理论上会撞上配置重载的毫秒级沉降窗而不一致——这是允许态,见下一行 |
|
||||
| 判废面与软告警面 | **完整性判废面自始至终只有这些**:精确尺寸等式、`magic` 与 `ver`(含 `ver` 须等于魔数第三字节)、头 CRC 与数据 CRC、表序 `sem` 等于下标、`ch_count` 上限、`pts_per_cycle` / `pts_per_ch` / `pre_pts` 下限、长度为零、文件短读。**品质组合与单位标签永远不进这道门**。本轮新增的只是**软告警面**:`avail` 同时带 VALID 与 CLIPPED 时 PC 在 NOTE 列打「同时为真,两点标定完成后属正常,非故障」;`eng` 与 `flags_seq` 违反上一条派生式时打 WARN。两者都**不改退出码、不影响出图、不拒渲染**。理由:把「单位标签不一致」当数据损坏,等于让一次改标定文件的沉降窗销毁故障证据 |
|
||||
| 通道表序与列序 | 第 i 个通道表项 ↔ 数据区第 i 列,按语义号**升序**:UA=0 UB=1 UC=2 UN=3 IA=4 IB=5 IC=6 IN=7(`App/algo/adc_input.h` 的 `adc_semantic_t`)。PC 必须校验表内语义号等于下标,不等即整段作废。交叉验证:`clip_mask` 恒 0xE6 = 2+4+32+64+128,恰好是 UB/UC/IB/IC/IN 五个语义号位,这份算术就是这个顺序的证据 |
|
||||
| 样本编码 | int16 小端;TPAFE 侧 16 位补码双极性;STM32 侧 0..4095 原样存正数,**不加中点偏置**——V0.1 单极性无偏置是硬件现状,加偏置等于伪造双极性(`docs/任务规划/数据可信.md` §2.7) |
|
||||
| 三个时间字段 | `t0_ms`(上电毫秒)、`wall`(epoch 秒,未对时 0)、`frame_seq`(段首帧序号)均 u32 无符号小端 |
|
||||
|
||||
**本波 TEMP 不录**(`ch_count` = 8):温度非线性未折算,进录波只多占一路字节、不增加可解释信息(`docs/任务规划/数据可信.md` §7 的「温度不参与线性标定」已定案)。
|
||||
|
||||
**为什么按通道分列而不是按帧交错**:回放页只画一路 → 只需连续读那一路;PC 重算全周傅氏也是逐路独立。交错布局两种用法都要跨步长取数,白付代价。
|
||||
|
||||
**实现期纠正记录(三条,只作追溯,不构成规格)**
|
||||
|
||||
1. `flags_seq` 的 V0.1 真值一度被写成 `0x27`:那是把「按来源派生的 CLIPPED」当成了 VALID。按 `App/algo/adc_cal.c` 280 到 298 行,未标定态就是 `0x00`(见上面真值表第一行)。凡引用这个数字的地方一律以真值表为准。
|
||||
2. 一版互验夹具写成 `eng` = 0 而 `flags_seq` = `0xFF`——违反上面的 eng 派生式,是一串**真机写不出来**的字节。已改为按派生式自洽,并在 `test/host/wave_store` 那套单测里加了夹具自洽断言防复发。教训一句话:**互验夹具的资格来自「真机能写出这串字节」**,一份不可能状态的字节只能验证两个读者对幻觉的一致反应,正好掩盖真分歧。
|
||||
3. 顺带钉一条因果,免得后文写反:PC 侧早期一次 `shape` 子命令在 `--strict` 下 rc=1,与品质位**无关**,那是「实测触轨路数 vs 段头 `clip_mask`」对表不符(合成夹具的波形本来就没真触轨)。那条对表是 `docs/任务规划/数据可信.md` §4.6 与本文 §10 板级判据的本职,不是解码器的判废扩展。
|
||||
|
||||
---
|
||||
|
||||
## 7. 预算(先算后写,R6 是硬前置)
|
||||
@@ -216,12 +248,24 @@ flowchart TD
|
||||
| **合计静态增量** | — | **约 5.9 KB** |
|
||||
|
||||
- **大于 4 KB ⇒ 触发 R6**:`docs/内存管理/内存内容分配策略.md` 的 R6 要求「任何新增静态缓冲 >4 KB 必须先核 §6 台账余量,改后同步 §6 数字、.sct 头注释与 AGENTS 栈表」;加大缓冲本身属 **Ask-first**;
|
||||
- **落位 = SRAM1,不进 CCM**:CCM 受管区已 87.9 %、只剩 7,904 B,SRAM1 为 62.2 %(数字出自 `docs/内存管理/RAM预算台账.md` §1 受管区表);录波环不是 DMA 可见对象,没有「CCM 不可达」的约束,但 CCM 也**没有余量**给它;
|
||||
- **落位 = SRAM1,不进 CCM**:CCM 受管区已 87.9 %、只剩 7,904 B,本波开工时 SRAM1 为 62.2 %(数字出自 `docs/内存管理/RAM预算台账.md` §1 受管区表;录波落地后的终值见本节末「实测回填」);录波环不是 DMA 可见对象,没有「CCM 不可达」的约束,但 CCM 也**没有余量**给它;
|
||||
- **UI 子系统配额早已超**(同一张表的子系统行)→ 回放页的描述符与名表仍要在台账记账,别拿「反正已超」当免检;
|
||||
- 前后各跑一次 `scripts/ram_report.py` 与 `scripts/stack_report.py`(defaultTask 多了落盘链、uiTask 多了读窗与自绘);`mem-budget` 钩子是总量红线,`ram_baseline.py --update` 回填趋势;
|
||||
- **Flash**:段格式编解码 + 状态机 + 回放页 + 一条日志行,粗估 3 到 5 KB(Flash 基线在 25 % 量级,不是瓶颈);
|
||||
- **NAND**:一段约 5.2 KB 数据加头。轮转 100 段约 0.5 MB,对 256 MB 单分区是零头——**瓶颈不是容量,是写次数**(§10 红线)。
|
||||
|
||||
**实测回填(2026-10-29 权威构建,0 错误 0 警告;逐对象台账见 `docs/内存管理/内存内容分配策略.md` §6)**
|
||||
|
||||
| 口径 | 上面的预估 | 实测 |
|
||||
|---|---|---|
|
||||
| SRAM1 静态增量 | 约 5.9 KB | 数据面 **+6,760 B**(81,536 → 88,296);UI 道另 +1,640 B;累计 **+8,400 B** → 终值 **89,936 B / 68.6 %** |
|
||||
| CCM | 0(不得进 CCM) | **0**:`RW_CCM` 三档恒 57,376 B / 87.9 %,既没进 CCM 也没挤动它 |
|
||||
| Flash | 3 到 5 KB | `ER_IROM1` 264,580 → 270,248(数据面 +5,668)→ 272,300(UI 道 +2,052)→ 272,360(落盘判废复检 +60)→ **272,336** B(cppcheck 返工纯搬声明,−24),累计 **+7,756 B**、占 26.0 %;`Total ROM` 274,308 B、`Code` 243,552 B |
|
||||
| 任务栈 | 未估 | 九任务全 PASS、**未抬栈**:adcTask 静态最坏链 1,424 B(余 1,136 B / 44 %)、defaultTask 3,040 B(余 2,080 B / 40 %)、uiTask 1,336 B(余 15,048 B / 91 %) |
|
||||
|
||||
- **差额构成(比预估多 860 B,可对账)**:原估漏记 `FIL` 528 B(`FF_FS_TINY=0`,落盘道刻意不上栈)、`DIR`/`FILINFO`、已封存段头副本 136 B、打包上下文(内部又含一份 136 B 段头);反向少记一项——落盘实际是**单缓冲 256 B**,不是预估的 512 B 双缓冲。**预估与实测都留在本节**:只写实测,下一次估算就看不见原估漏在哪。
|
||||
- **回放页读窗不在数据面那 6,760 B 内**:它计入 UI 道的 +1,640 B;两张表不能相加当总量,逐对象拆分见 `docs/内存管理/内存内容分配策略.md` §6。
|
||||
|
||||
## 8. 现场回放显示契约
|
||||
|
||||
### 8.1 一屏画什么
|
||||
@@ -264,8 +308,9 @@ flowchart TD
|
||||
wave: seg=NN armed=1 src=P pts=320 err=N ovf=N drop=N
|
||||
|
||||
- `err` 是落盘失败或 CRC 自弃次数(**字节数不符就算失败**,见 §5.2);`ovf` 是冷却期丢弃的触发数;`drop` 是冻结窗口丢掉的录波点数;
|
||||
- **实际落地形态(逐字)**:打印点在 `App/task/adc_task.c`:782 行,格式串 `"wave: seg=%lu armed=%u src=%s pts=%u err=%lu ovf=%lu drop=%lu"`——**字段名与顺序就是上面的模板**(台架与 PC 脚本按行名 grep,动它就断脚本);`src` 取 M(手动)/ P(保护)/ T(定时自抓)/ `-`(本次上电还没触发过);`armed` 只在 FREEZE 与 SEALED 为 1(COOL 期只挡新触发不录新段,画进 armed 会被台架误读);`seg` 是累计**成功回执**的段数、不是轮转号;`err` = 落盘失败 + SEALED 滞留超时自弃(含 §5.2 第四条的 ring abandoned 判废),由环内计数收口,落盘道不数第二份账。`err` 与 `ovf` 的**已知容差**(lead 裁定 2026-10-29,不修只入档):这两个计数是跨上下文的读-改-自增(`ovf` 由任意上下文的拒绝路径加、`err` 由 adcTask 的滞留自弃与 defaultTask 的落盘失败分别加),本层双端编译、不许引 FreeRTOS / CMSIS 的临界区内在函数,所以并发拒绝或并发失败时**理论上可能少计一次**。定性为**观测计数的已知容差**:只用于趋势与判读,**不作为任何判据的唯一依据**——要坐实「冷却期内确实来了第二次触发」,同时看 `armed` 与那一刻 `/log/start.log` 的时刻。契约原文见 `App/algo/wave_ring.h` 文件头「观测计数的已知容差」段;
|
||||
- 只在原先静默的黑洞处补锚点,别重复已有步骤——每条 DBG 日志约 90 B Flash 加 216 B 栈(`AGENTS.md` 的日志与工具链节);
|
||||
- 该行落地时同步进 `docs/测试说明/ADC前端注入验证流程.md` 的读数出口表。
|
||||
- 该行已同步进 `docs/测试说明/ADC前端注入验证流程.md` 的读数出口表(2026-10-29;同一张表还登记了段文件出口与 PC 侧读段工具)。
|
||||
|
||||
---
|
||||
|
||||
@@ -274,10 +319,13 @@ flowchart TD
|
||||
| 层 | 内容 |
|
||||
|---|---|
|
||||
| 主机侧纯逻辑单测(新增,进 `test/host/`) | ① 环:预触发与后触发点数、冻结与解冻、冷却丢弃计数;② 段格式编解码往返,含 CRC 不符、零长度、字节数不符三条失败路径;③ 触发状态机三条来路(手动 / 保护 / bench)。**环与格式必须是纯逻辑**(不碰寄存器、不碰 RTOS)才能这样测——这是 `App/algo/` 既有分层纪律 |
|
||||
| 板级 | 信号发生器注 1 V / 50 Hz → 手动一段 → FTP 拉回 → PC 脚本量出周波数、幅值、极性、削顶路数与 `clip_mask` 一致;再把 PC 重算的基波有效值与板上 `meas:` 与 104 浮点 YC 对表 |
|
||||
| PC 侧工具的定性 | `test/host/wave_read.py` 是 **bench 工具**(`test/host/` 下的 loose .py,先例 `test/host/ftp_capture.py`),**不是**主机单测套件 → 不建 `run_unit_test.py`、不加 pre-commit 专属钩子(专属钩子默认不补,按 Lead 裁定 2026-10-27);它自带 `--selftest` 就是它的自带回归,跑法与四个子命令见 `docs/测试说明/ADC前端注入验证流程.md` §4 |
|
||||
| 跨工具链分叉(实证,写进来是为了下一个模块别重踩) | 两份录波 .c 只 include 自身头(链上只有 stdint.h)时,ARMCC 报 22 条 identifier "NULL" is undefined;而主机 MSVC / gcc 会传递性把 stddef.h 拉进来,**主机单测完全照不出这个分叉** → 新增模块需要用 NULL 就自己 include stddef.h(与 `App/algo/sample_ring.c` 同口径,别塞公共头) |
|
||||
| 板级 | 信号发生器注 1 V / 50 Hz → 手动一段 → FTP 拉回 → PC 脚本量出周波数、幅值、极性与注入一致;再把 PC 重算的基波有效值与板上 `meas:` 与 104 浮点 YC 对表。**判据只量四样:周波数、幅值、极性、钉轨路数——不比绝对相位**(理由见 §4.2「段内点序」:触发瞬间在工频周期内任意落点,段字节里没有绝对时间参考;真要比相位必须让发生器给同步触发,本波不做)。**钉轨对表的合格判据 = 头位图 ⊇ 实测钉轨路数,且差异必须能由注入条件解释**——因为 `clip_mask` 是按来源派生的链路可信性标记(§6.2 偏移 24 行),不是本段实测值:只加直流或小幅注入时那五路本就不该钉轨,硬取等式会假红。**同段另起一条强观察项**:V0.1 下这五路若在做**交流注入**时反而没钉轨,先怀疑接线或该路根本没被驱动——这是告警面,不是失败面(等式仍作为默认尺子留在 PC 侧 `shape --strict` 里,因为它有这个信号价值;要放行差异用那条判据的解释权,不靠改尺子)。**§5.2 第四条的板级观察项(代码与单测面已有、板级未测)**:bench 连续自抓期间人为把卷占住 2 s 以上(例如同一段跑 FTP 大文件读),看串口 `wave:` 行的 `err` 是否加一、是否只出现**一条** `[ERR] … seg drop: ring abandoned` 留痕(不是每拍刷屏)、且段号不推进(下一段仍写同号文件) |
|
||||
| UI | `ui-verify` 五步;回放页入 `ui-golden` 黄金参考(**参考图一旦入库只能改代码对齐,禁止刷参考掩盖**);新叶走 `gen_menu.py` 重生成 + 字库链 |
|
||||
| 构建 | `@build` 要求 0 错误 0 警告;新 .c 双端注册走 `new-source-file`(`MDK-ARM/STM32F407-Demo.uvprojx` 与 `simulator/CMakeLists.txt` 两处显式列表) |
|
||||
| 台账 | R6 三处同步 + `scripts/ram_baseline.py --update` + `mem-numbers` 与 `mem-budget` 钩子 |
|
||||
| 板级(读路径耗时,2026-10-29 补) | 进回放页后**连续切段 + 连续切道**,读 `task_prof` 里 uiTask 的单轮工作耗时峰值与 800 ms 窗的余量;**不要为此新加埋点**(现成读数够用)。判读:峰值贴着窗走就是读路径该再加节流(先想缓存与分次,别去动心跳窗) |
|
||||
| 图与生成物 | 本设计文档的配图生成器受 `generated-fresh` 逐字节幂等约束;脚本与产物同一笔提交 |
|
||||
|
||||
**bench 定时自抓的红线**:定周期自抓在 1 kHz / 8 路下每 2 s 一段,每 5 分钟就是一轮 NAND 写。**长时间挂着它白烧写次数**,而 dhara 的坏块记账是持久代价、普通恢复清不掉(`AGENTS.md` 测试构建节,`docs/测试说明/存储维护与容量恢复.md`)→ 定时模式必须**默认关闭 + 有时长上限 + 启动时打一次告警**,用完立刻回产品构建。
|
||||
@@ -303,6 +351,7 @@ flowchart TD
|
||||
| 削顶五路被读成「系统有零序 / 有谐波」 | 现场误判 | 头里 `clip_mask` + 页面「削」徽标 + 空态不许画直线(§8.1) |
|
||||
| 有人把 U 与 I 两段叠图比相位 | 得出**没有物理意义**的相位差 | 回放不做多路叠加;头里写明来源转换器;与 `docs/任务规划/数据可信.md` §9 的 V0.1 禁止行同源 |
|
||||
| 落盘把 defaultTask 拖住 | 日志与配置引擎变慢(defaultTask 是两者唯一写者) | 分次写(256 B 双缓冲)、一次心跳最多一段、`f_write` 前后有耗时观测;不做整段驻留再写 |
|
||||
| **回放读路径把 uiTask 拖住**(2026-10-29 lead 评审补,此前风险表只有写侧没有读侧) | 一次渲染的实码 I/O(`App/task/ui_task.c` 376 到 398 行):段表刷新 1 次 `f_opendir` + 至多 100 次 `f_readdir`;未缓存段的段头装载 = 1 次 `f_open` + 1 次 128 B 头读 + **20 次 256 B 数据区读并边读边算数据 CRC** + 尾 2 B 一次 = **最坏 22 次小读**;已验过则只剩窗装载 = 1 次 `f_open` + 1 次 `f_lseek` + 1 次 80 B 窗读 + 40 点解码与峰值扫描(**一屏只碰一路通道一个窗,不是 8 路 320 点**)。uiTask 在 IWDG `required_mask` 内、窗 800 ms(口径同 `docs/子系统设计/看门狗设计说明.md` §11.3 的解耦心跳)→ **现象先是 LVGL 停摆与远程推流缺席,不是复位**(心跳与画屏解耦) | 卷锁 try 非阻塞(拿不到就显示「存储忙」,不等)+ 256 B 分次读 + 已验段结果缓存(同段同道不重复验)+ 只在首次进页 / 切段 / 切道时读。**单轮耗时上界未实测**:不新加埋点,用现成的 `task_prof` 读数(板级动作见 §10) |
|
||||
| 触发风暴 + 轮转覆盖 | 现场唯一一段有效波形被后到的抖动冲掉 | 冷却期 + `ovf` 计数;「最新段号」进快照;分段优先级属二期 |
|
||||
| 定时自抓忘关 | 白烧 NAND 写次数(持久代价) | 默认关 + 上限 + 告警(§10 红线) |
|
||||
| 标定落地后老文件被解释错 | 同一个系数字段值变了含义漂移 | 头里存**封存瞬间**的 `eng` 与系数快照;PC 脚本按头解释,绝不按当前固件口径解释 |
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
- **菜单树已含目标叶子**:`ui_menu_tree.txt` "记录查询"下已有 **自检记录 = node 39、运行记录 = node 40**(当前为空白终点框,无内容页映射);无需改树。
|
||||
- **密码页** `ui_page_password.c`:3 位数字框 + ↑↓←→/ENTER;输错仅清空重输(R1 缺口)。
|
||||
- **按键流**:物理/远端键 → LVGL keypad → 默认输入组 → 焦点对象事件回调(菜单容器 `menu_key_cb` / 内容页容器 `cp_key_cb`)——空闲检测可在此统一挂钩。
|
||||
- **字体**:子集位图字体 `ui_font_cn_12`,字符集 `ui_cn_chars.txt`(当前 218 汉字/符号 + ASCII 0x20~0x7E,共 313 字形;2026-10-28 实测。122/217 是 2026-09-14 的历史快照,见 §6.1)。
|
||||
- **字体**:子集位图字体 `ui_font_cn_12`,字符集 `ui_cn_chars.txt`(当前 224 汉字/符号 + ASCII 0x20~0x7E,共 319 字形;2026-10-29 实测。122/217 是 2026-09-14 的历史快照,见 §6.1)。
|
||||
|
||||
### 2.2 存储与时间
|
||||
|
||||
|
||||
+5
-8
@@ -264,7 +264,7 @@
|
||||
|
||||
**章节引用(D 类)另有的跳过**:昵称式引用(「内存方案 §2.1」)、非紧邻写法、变更记录小节内的历史指称、外部手册编号(RM0090 等)、目标文档本身不用数字编号标题。
|
||||
|
||||
> 「变更记录小节内的历史指称」这条跳过规则为何还留着:2026-10-28 起新文档不再设该节(见 §5.1),它现在只为**保留变更记录的存量 5 篇**与 `scripts/archive/` 下的归档文档服务——历史行里的编号是「当时那个编号」,既不回改也不校验。
|
||||
> 「变更记录小节内的历史指称」这条跳过规则为何还留着:2026-10-28 起新文档不再设该节(见 §5.1),它现在只为**保留变更记录的 3 篇真台账**与 `scripts/archive/` 下的归档文档服务——历史行里的编号是「当时那个编号」,既不回改也不校验。
|
||||
|
||||
> ⚠️ 状态词按**就近**(±40 字符)判定,不是整行——否则文件名本身含「不存在」「删除」等字样时会误豁免同行的其它真实引用(2026-09-25 实测修正)。
|
||||
|
||||
@@ -318,7 +318,10 @@
|
||||
| **一级标题** | 文档首行为 `# 标题`,标题即主题,不写"文档""说明"等冗余后缀 |
|
||||
| **开篇引言** | 可选 `>` 引用块,写明**适用对象 / 阅读前提 / 相关文档** |
|
||||
| **章节编号** | 多章节文档用 `## 1.` `### 1.1` 编号,便于交叉引用(`§3.2`) |
|
||||
| **变更记录** | **2026-10-28 裁定:新文档不再设「变更记录」节**——文档只写现状、改了什么是正文说了算,改动过程查 `git log`。**例外**(整表保留、被别处当台账或唯一证据出处引用的 5 篇):`docs/子系统设计/看门狗设计说明.md`、`docs/子系统设计/配置文件设计说明.md`、`docs/内存管理/RAM预算台账.md`、`docs/UI设计/内容页架构.md`、`docs/环境与部署/本地工具路径环境变量方案.md` |
|
||||
| **变更记录** | **一律不设该节**(用户裁定 2026-10-28 起新文档、2026-10-29 起老文档也清完;标题变体 `修订记录` / 带编号的 `## 6. 变更记录` / `## 九、变更记录` 同规则)——文档只写现状、改了什么是正文说了算,改动过程查 `git log`。**例外只有 5 篇**(整表保留:表里是真台账、且被别处当唯一证据出处引用):`docs/子系统设计/看门狗设计说明.md`、`docs/子系统设计/配置文件设计说明.md`、`docs/内存管理/RAM预算台账.md`、`docs/UI设计/内容页架构.md`、`docs/环境与部署/本地工具路径环境变量方案.md`;`scripts/archive/` 下的归档文档整片都是历史,不受本条约束 |
|
||||
|
||||
> 数"还剩几篇留着这节"的命令(**别只 grep 裸标题**——带编号的 `## 6. 变更记录`、中文序号的 `## 九、变更记录`、`## 修订记录` 三种写法都要算):
|
||||
> `grep -rn "^## " docs scripts` 再看命中的标题;2026-10-29 实测 **5 篇**真台账(上表那五篇)+ `scripts/archive/` 归档一篇。
|
||||
|
||||
### 5.2 新增文档检查清单
|
||||
|
||||
@@ -373,9 +376,3 @@
|
||||
| 提交 diff 出现整文件行尾变化 | 脚本改写时强制了 LF/CRLF | 改写须按原换行符回写(见 §2) |
|
||||
| 图片不显示 | 文档迁入子目录后未改 `../images/` | 补 `../`(见 §3.2) |
|
||||
| 引用"计划中"文件被拦 | 没加 `[计划] ` 前缀 | 加前缀 |
|
||||
|
||||
---
|
||||
|
||||
## 变更记录
|
||||
|
||||
> (本文件不再记流水账:改了什么是正文说了算,改动过程查 git log。)
|
||||
|
||||
@@ -54,6 +54,22 @@
|
||||
| `gen_data_trust_ladder_svg.py` | `docs/images/数据可信台阶.svg` | `STEPS` 五级台阶(状态 / 问题 / 依据)+ `BAND_LABEL_1` / `GATE_LABEL` / `FOOTNOTE`(台阶状态变了才重画) |
|
||||
| `gen_data_trust_dc_ac_svg.py` | `docs/images/ADC直流标定与交流验证.svg` | `BOXES_A` / `BOXES_B` 两条泳道 + `CHIPS` 六件事 + `NOTES` 红线与"证不到"清单 |
|
||||
| `gen_wave_record_flow_svg.py` | `docs/images/故障录波数据流.svg` | `CHAIN` 主链四段 + `EDGE` 跨边界标签 + `TRAPS` 三条陷阱 + `FORBID` 四条红线(所有权、段形态或红线变了才重画) |
|
||||
| `gen_menu_tree_svg.py` | `docs/images/菜单树总览.svg` | **内嵌 `NODE_SRC`**(= `ui_menu_tree.txt` 的 43 行节点)+ 版面常量;仓库里跑会与真值逐行互验,不一致 exit 1(临时目录里读不到真值 → 用内嵌表,输出逐字节一致) |
|
||||
|
||||
### 2.1 钩子扫不到的图:refgraph 产物与历史手画稿
|
||||
|
||||
`generated-fresh` 的 `docs-svg` 条目只把 `tools/arch_diagram/gen_*.py` 拷进临时目录重跑逐字节比对。
|
||||
上表没列到的 `docs/images/*.svg` 就是下面这几张,**它们全都不在这条钩子的扫描面里**——改了不会有任何
|
||||
人报警,这就是「42 个节点的旧图挂在 43 个节点的标题下」能一路活到今天的原因。
|
||||
|
||||
| 图 | 谁画的 | 用在哪 | 维护口径 |
|
||||
|---|---|---|---|
|
||||
| `docs/images/引用关系图.svg`、`docs/images/引用关系图_模块.svg` | `tools/refgraph/gen_refgraph.py`(graphviz,不在 `gen_*.py` 命名面里) | `docs/架构设计/引用关系图说明.md` 的产品 | 改了代码引用就跑 `tools\refgraph\gen_refgraph.bat` 重生成,**svg 与改动同一笔提交**,别只更新 `.dot`;口径 → `docs/架构设计/引用关系图说明.md` |
|
||||
| `docs/images/级联框总览.svg` | 2026-10-26 手画 | `docs/UI设计/菜单页面设计.md` §4.1(级联框显示几何:根框 + 整定子框) | 只作**显示几何示意**,不承载菜单树事实;树的结构 / 层级 / 绑页 → `docs/images/菜单树总览.svg`(有生成器) |
|
||||
| `docs/images/级联框几何计算.svg` | 同上 | `docs/UI设计/菜单页面设计.md` §5.3(逐框坐标推导) | 同上;坐标公式变了要重算重画,别在 SVG 上描字 |
|
||||
|
||||
新增精确布局图一律走 `tools/arch_diagram/gen_*.py`(`docs-svg` 条目自动发现,**不必登记基线**);上面这几张
|
||||
是这套纪律的**例外面**,再多一张先说清为什么不能用生成器。
|
||||
|
||||
---
|
||||
|
||||
|
||||
+1
-1
@@ -256,7 +256,7 @@ flowchart TB
|
||||
- 内容页为**独立全屏屏**,由框架一次性自绘(**零 LVGL 子对象**),ESC 返回菜单屏。
|
||||
- 菜单受保护叶子(`ui_menu_tree.txt` 行尾 ` #P`):先弹密码页,授权后 `menu_password_ok` **先关页再续进入动作**。
|
||||
- 待机屏:空闲超时(默认 60s)自动切入,仅确认键回菜单;数据源同实时量页。
|
||||
- 字体 `ui_font_cn_12.c` 由 `tools/font_gen/` 生成(宋体 12px 1bpp 子集,**218 字/313 字形**,2026-10-28 实测;字形数 = 字符数 + ASCII 95 个)。
|
||||
- 字体 `ui_font_cn_12.c` 由 `tools/font_gen/` 生成(宋体 12px 1bpp 子集,**224 字/319 字形**,2026-10-29 实测;字形数 = 字符数 + ASCII 95 个)。
|
||||
|
||||
---
|
||||
|
||||
|
||||
+390
-7
@@ -3,13 +3,17 @@
|
||||
> **这篇是什么**:已知电压注入验证的**执行侧**——判据与实测记录在 `docs/硬件平台/ADC通道映射说明.md` §8.1,
|
||||
> 这边写怎么接表笔、读哪一行日志、填哪张表、结果往哪回写。
|
||||
>
|
||||
> **本文只验直流**:零点 / 线性 / 通道映射 / 极性——它证的是"一条水平线的高度"。
|
||||
> **交流(正弦)动态验证不用等标准源**:一台信号发生器接在本文 §3 的同一批注入点上就能跑,
|
||||
> 判据与接法见 `docs/任务规划/数据可信.md` §4.6;等标准源的只是**精度等级**那一步
|
||||
> (`docs/任务规划/数据可信.md` §5 的「两点标定与精度验收」)。V0.1 有五路单极性削顶
|
||||
> (`UB/UC/IB/IC/IN`),它们在交流轮次里只能作"预期削顶"的负向用例。
|
||||
> **本文分两个轮次**:§1~§7 = **直流轮次**(零点 / 线性 / 通道映射 / 极性,2026-10-27 六项 PASS,
|
||||
> 证的是"一条水平线的高度";**不需要**示波器、信号源、标准源,**只需要**一块万用表 + 一个电位器 + 串口日志)。
|
||||
> §8 = **交流(正弦)动态验证轮次**(D1~D6,证的是"给定电压算得对不对、品质报得实不实、节拍稳不稳")——
|
||||
> 一台信号发生器接在本文 §3 的同一批注入点上就能跑,**同样不用等标准源**;
|
||||
> 等标准源的只是**精度等级**那一步(`docs/任务规划/数据可信.md` §5 的「两点标定与精度验收」)。
|
||||
> V0.1 有五路单极性削顶(`UB/UC/IB/IC/IN`),它们在交流轮次里只能作"预期削顶"的负向用例。
|
||||
>
|
||||
> **不需要**示波器、信号源、标准源。**只需要**一块万用表 + 一个电位器 + 串口日志。
|
||||
> **判据的属主是 `docs/任务规划/数据可信.md` §4.6.2**(D1~D6 验什么、过判据是多少),本文 §8 只写**怎么跑**。
|
||||
> 两边于 2026-10-29 对齐;若将来再分叉,分两类裁定:**「验什么、算不算过」从
|
||||
> `docs/任务规划/数据可信.md` §4.6.2**,**「期望值怎么算、怎么接线怎么跑」从本文 §8**。
|
||||
> 这一跳为什么不用等标准源、又证不到什么,见其 §4.6.1 与 §4.6.5,本文不重抄。
|
||||
|
||||
---
|
||||
|
||||
@@ -67,7 +71,7 @@
|
||||
|
||||
## 4. 读数出口(固件只有下面这些周期行,没有命令控制台)
|
||||
|
||||
> **样本出口将变**:故障录波已立项(2026-10-29,docs/任务规划/故障录波.md)。落地后段文件会直接给出原始码值样本,动态验证的判据随之从「比对下表这些派生标量」升级为「PC 独立重算 vs 板上读数」对表,口径变更见 docs/子系统设计/故障录波设计说明.md §11。下表仍是**当前**唯一可读的东西。
|
||||
> **样本出口已落地(代码侧,2026-10-29)**:故障录波的数据面已进仓(立项与卡片见 docs/任务规划/故障录波.md,格式与判据属主见 docs/子系统设计/故障录波设计说明.md §6.2 与 §6.3、口径变更见该文 §11)——每次触发一段,段文件直接给出 8 路 × 320 点原始码值,动态验证的判据因此**可以**从「比对下表这些派生标量」升级为「PC 独立重算 vs 板上读数」对表。下表仍是固件唯一的**周期行**出口(段文件不是周期行,只在触发时产生),两种出口对表用。
|
||||
|
||||
| 日志行 | 频率 | 内容 | 用途 |
|
||||
| ----------------------------------------------------------- | ------ | ------------------------ | ------------------- |
|
||||
@@ -77,6 +81,8 @@
|
||||
| `frames=.. idle=.. adc1_err=.. tgap=..` | 每 10 s | 采集健康计数 | 步骤 4 的节奏判据 |
|
||||
| `phasor(hb) C0x-…: Re=.. Im=.. rms=..`(逐实例)、`freq(hb): f=.. valid=..` | 每 10 s | 基波相量分量与测频读数(×0.1 / ×0.01 定点) | **交流轮次的主读数**(直流轮次只作旁证) |
|
||||
| `meas: seq=.. v=.. ua_mv=.. un_mv=.. ia_mv=.. f=.. fv=..` | 每 10 s | 200 ms 遥测快照轨(基波有效值 mV) | 交流轮次的幅值比对(1 mV 分辨率,比 phasor 行细) |
|
||||
| **段文件** `/wave/WAVE00.BIN` 起共 100 个号轮转(FTP 根下可见,与 /log 平级) | 每次触发一段(手动 / 保护启动 / bench 定时) | 8 路 × 320 点原始码值 + 封存瞬间的标定与品质快照(布局见 docs/子系统设计/故障录波设计说明.md §6.2) | **样本出口**:交流轮次的主对表源——预触发 160 点 + 后触发 160 点,触发瞬间落在段内点 159 |
|
||||
| PC 侧脚本 `test/host/wave_read.py`(不是固件日志,bench 工具,纯标准库) | 手动跑;`--selftest` 是它的自带回归 | 四个子命令:dump(逐字段与双 CRC)/ fft(全周傅氏重算基波有效值与相位)/ shape(削顶与形态判定,可 `--strict`)/ plot(出 SVG 或 PNG,PNG 用 `-o` 落文件) | 把段文件还原成周波数、幅值、相位、削顶判定与图 = 「PC 独立重算」这条判据的执行体;CRC 不符或零长度它必须**拒绝**而不是画出东西 |
|
||||
|
||||
> ⚠ 直流轮次用不到后两行,但**它们一直都在**。交流轮次(判据见 `docs/任务规划/数据可信.md` §4.6)
|
||||
> 必须用 `meas:` 或 104 YC 比幅值,别用 `phasor(hb)` 行——那行是 ×0.1 定点,注 1 V 只剩 10 格。
|
||||
@@ -273,3 +279,380 @@ TPAFE 是双极性、二进制补码,可以注负压;STM32 是单极性,
|
||||
与"加压试保护"是两件事,后者要等端子/子板变比确认(`docs/硬件平台/ADC通道映射说明.md` §7.1 链路分段表 ④ 行)之后单独排。
|
||||
4. **引脚侧注入必须外串 10 k**,且先接线后上电、先断电后拆线。
|
||||
5. 注入源与板子**共地**;电位器一端接 3.3 V、一端接 AGND、中间抽头串 10 k 到注入点。
|
||||
|
||||
---
|
||||
|
||||
## 8. 交流(正弦)动态验证轮次(D1~D6)
|
||||
|
||||
> **判据的属主是 `docs/任务规划/数据可信.md` §4.6.2**(D1~D6 验什么、过判据是多少),本节只写**怎么跑**:
|
||||
> 接哪个点、发生器怎么设、读哪一行的哪个字段、期望值怎么算、结果往哪回写。两边于 2026-10-29 对齐;将来
|
||||
> 若再分叉,按两类裁定——**「验什么、算不算过」从 `docs/任务规划/数据可信.md` §4.6.2,「期望值怎么算、
|
||||
> 怎么接线怎么跑」从本节**。为什么这一跳不用等标准源、以及它证不到什么,看其 §4.6.1 与 §4.6.5,本节不重抄。
|
||||
>
|
||||
> **引用写法**:本节凡引用判据文档的小节,一律写成「文件名 + 小节号」的紧邻形式;只写 §8.x 的是本文自己的节。
|
||||
|
||||
### 8.1 动手前先把出口分辨率算清楚(决定今天能判到哪一档)
|
||||
|
||||
这一轮和直流轮次**不一样:样本出口已经有了**。2026-10-29 故障录波的数据面并入主干,一次触发就是一段
|
||||
`/wave/WAVE<NN>.BIN`(`NN` = 00~99 轮转号;8 路 × 320 点原始码值 + 封存瞬间的标定与品质快照),PC 侧 `test/host/wave_read.py` 把它还原成
|
||||
周波数、幅值、**相位**、谐波与削顶判定。所以本轮每条用例都有两个档:**周期行标量档**(只读串口 / 104 / UI,
|
||||
快,不用 FTP)与**段文件对表档**(多一次触发 + 一次取段 + 跑脚本,判得到位)。各出口的实际分辨率如下——
|
||||
这张表决定每条用例走哪个档:
|
||||
|
||||
| 出口 | 打印处 | 分辨率 | 能判 | 判不动 |
|
||||
|---|---|---|---|---|
|
||||
| `meas: seq=.. v=.. ua_mv=.. un_mv=.. ia_mv=.. f=.. fv=..` | `App/task/adc_task.c:605` | **1 mV**(整数毫伏,只发 UA/UN/IA) | D1、D2 的幅值 ≤2 % | 相位、谐波、其余五路 |
|
||||
| 104 YC `0x4011`~`0x4018` + `0x401D`(短浮点 + 品质) | `App/protocol/iec104/iec104_pts.c:70` | 3 位有效数字 ≈ 0.01 V | 单个静态工作点的幅值交叉读数、品质 IV | **小步进**(每点 0.5 V / 0.005 A 变化死区)、相位、谐波 |
|
||||
| `phasor(hb) C0x-…-F1: Re=.. Im=.. rms=.. (x0.1)` | `App/task/adc_task.c:209` | **0.1 V,且向下截断** | 有数没数、量级、象限 | ⚠ **D3 的 ≤2° 与 D6 的 ±2 %**:注 1.000 Vrms 时 `rms` 只有 10 格,20 % 的谐波只有 2 格 |
|
||||
| `freq(hb): f=.. valid=.. (x0.01)` | `App/task/adc_task.c:224` | 0.01 Hz | D4 的读数与新鲜度 | — |
|
||||
| UI 交流量页 `Ua/U0/Ia/Ia2/Ia5`(3 位小数)、`Hz`(2 位) | `Drivers/BSP/UI/ui_page_ac.c:47` | **1 mV**(人工目检 + 拍照留证) | D6 谐波幅值、D1 交叉旁证、D4 的 `Hz` 显 `--` | 相位(页面上没有角度) |
|
||||
| 录波段文件 `/wave/WAVE<NN>.BIN`(`NN` = 00~99,100 个号轮转;FTP 根下,与 `/log` 平级)+ `test/host/wave_read.py`(`dump` / `fft` / `shape` / `plot`,纯标准库) | **已落地**(2026-10-29 并入 `v2-on-ui`;格式属主 `docs/子系统设计/故障录波设计说明.md` §6.2 与 §6.3) | 一次触发 8 路 × 320 点原始码值;`fft` 给基波 RMS、相位、2 次与 5 次谐波 RMS(mV) | **D3 的 ≤2° 与 D6 的 ±2 % 现在判得动**:PC 独立重算 vs 板上读数对表 | 段与发生器**无绝对相位锁定**(触发点在段内点 159)→ 只能比同段内相对相位;320 ms 快照不等于长时间稳定性 |
|
||||
|
||||
**所以每条用例按两个档摆**(出口从"缺样本"变成"有段文件"的经过与口径变更,见 `docs/任务规划/故障录波.md` §2 末
|
||||
与 `docs/子系统设计/故障录波设计说明.md` §11):
|
||||
|
||||
| 档 | 条目 | 说明 |
|
||||
|---|---|---|
|
||||
| **周期行就判得动** | D1、D2、D4、D5(D5 的接法要按 §8.5 改,原因写在那张卡里) | 判据在 `meas:` / 104 / `freq(hb)` / `rail:` 上分辨率都够,不取段也能收工 |
|
||||
| **段文件档才判到位** | D3、D6 | 段文件已落地 → 浮点重算,≤2° 与 ±2 % 都是**定量**判据;周期行退为旁证,只在没取到段时走定性档。触发动作与命令写在 §8.5 的 D3 / D6 卡 |
|
||||
| **要改代码的退路** | D3 抬倍数、D4 B 档 | 段文件落地后 D3 这条基本不必走;D4 B 档(放宽 `FREQ_AMP_MIN`)仍是唯一路子。两者都要重编 + 烧录 + 按 §8.9 还原,**动手前先问用户** |
|
||||
|
||||
### 8.2 设备清单与开机前置门
|
||||
|
||||
| 项 | 要求 | 为什么 / 怎么核 |
|
||||
|---|---|---|
|
||||
| 信号发生器 | 正弦 / 方波 / 三角,**并有 DC 档**;频率可锁 50.000 Hz、也能设到 2 Hz;幅度 0~3 Vpp | **只要求"波形干净、幅度稳、频率锁得住"**,它的刻度不当基准(`docs/任务规划/数据可信.md` §7 #9)。DC 档是给 D5 改法 A 用的 |
|
||||
| ⚠ 发生器输出端接设置 | 接板子时设成**高阻负载**,不要按 50 Ω 端接 | 按 50 Ω 端接而实际接的是高阻板输入 → 面板值与真实电压差 2 倍;这是台架"差一倍"最常见来源 |
|
||||
| 万用表 AC 档 | 能读到 mV;**记明型号与响应类型**(真 RMS / 均值响应) | 基准就是它;D2 那一步两种表的读数都与基波期望差很多,不记响应类型就说不清是谁错 |
|
||||
| 板子 | 产品构建(`test/board/test_config.h` 四个 `TEST_SUITE_*` 全注释)+ `@build` 0 错误 0 警告 + 烧录 `-Rst -Run` 与回读校验 | → `stlink-flash` skill 与 AGENTS.md「构建与验证」 |
|
||||
| `[adc_cal]` 状态 | **保持未标定**(`eng=0`),别为"读数好看"先写标定值 | 现在 `meas:` / `phasor` 的量纲是 **ADC 引脚电压 V**(`App/algo/meas.h` 文件头的 A-lite 口径);标定一生效就换成二次值,本节全部期望值作废 |
|
||||
| 串口 | 全程抓 RX 落盘:用 `serial-assistant` skill(`open` → `clear` → 跑 → 读日志文件或 `log --tail`) | 日志文件就是证据本体,§8.10 归档归档的就是它;**长跑别用 `@test`**——它绑定一轮启动语义(静默 8 s、总超时 30 s、`max_boot_count` = 1,且 forbidden 含 `[ERR]`,而 D5 故意造 `[ERR]`),约 135 min 的 session 必然超时或误判;daemon 全量写 `state/serial.log`(20 MB 上限自动截头保尾 10 MB)→ `docs/测试说明/自动化测试流程.md` 长时间采集一节 |
|
||||
| 网口(可选) | 要读 104 那一路就插网线、PC 与板同网段(出厂 192.168.1.100),跑现成主站 `test/host/iec104_master.py`(`--ip` / `--port` / `--addr`) | 104 是浮点无量化 + 带品质,是 `meas:` 之外的第二条腿 |
|
||||
| FTP 客户端 | 走现成 21 端口取段文件(出厂 `[ftp]` 账号,连续 5 次失败锁 60 s) | 段文件是 D3 / D6 定量档的样本出口;段文件名 `/wave/WAVE<NN>.BIN`(00~99 轮转),**取完立刻改名归档**,否则下一次触发把它盖掉 |
|
||||
| 录波触发路径 | 产品构建里唯一**免改代码**的路径 = UI 菜单第 26 叶「手动录波」确认页(`Drivers/BSP/UI/ui_page_wave_manual.c` → `App/task/ui_task.c:605`) | 保护启动上升沿也算一次触发,但保护判据现处**未标定闭锁**态(AGENTS.md「现状」),别指望它自动来段;bench 定时自抓在双层编译门 `DTU_BENCH` 且 `WAVE_BENCH_AUTOCAP` 非 0 之内(默认 0,`App/task/adc_task.c:153`),开它就走 §8.9 的还原判据 |
|
||||
| 共地 | 发生器 LO/GND 与板 AGND **单点**相连 | 不共地量到的是两地之差;现象见 §8.8 |
|
||||
|
||||
**开机前置门**——接发生器**之前**日志就该长这样,不满足先回 §5 步骤 5.5 查节奏,别往下做:
|
||||
|
||||
- `adc:` 行 10 s 一行,同一心跳里 `frames` 在涨("9 路全 0"要读成"没数据",§4 尾注);`idle=0`、`adc1_err=0`;
|
||||
- `meas:` 的 `v=1`、`seq` 每 10 s 约 +500(200 ms 一帧;不涨 = 发布闸门停);
|
||||
- `cal:` 的 `cl=0xE6` —— **这是来源派生**(V0.1 那五路本就触底,见 `docs/任务规划/数据可信.md` §2.6),既不是本轮战果也不是本轮故障;
|
||||
- 四个位图 `vl` / `cl` / `rail` / `edge` 同一个位序(语义通道枚举 `App/algo/adc_input.h:38`):bit0 `UA`、bit1 `UB`、
|
||||
bit2 `UC`、bit3 `UN`、bit4 `IA`、bit5 `IB`、bit6 `IC`、bit7 `IN`、bit8 `TEMP` → `0xE6` = bit1/2/5/6/7 = `UB/UC/IB/IC/IN`;
|
||||
- **先上电、在基线里看到 `adc: UB` 有正常摆动,再开发生器输出**:贴轨锁存要求该通道"此前出现过中带样本"(释放沿前提,
|
||||
`App/algo/adc_health.c` 的 `adc_health_rail_watch()`),开机就注大信号会让 D5 的锁存**装不上**,测出假不通过。
|
||||
- 开机各有一条 `first:` 与 `phasor(first)` / `freq(first)` 单发行(`App/task/adc_task.c:478` 与 `App/task/adc_task.c:201`
|
||||
的 `tag` 参数),与 10 s 一轮的 `hb` 行是两拨——数心跳时别把 `first` 计进去;
|
||||
- `phasor` 行**只要有数就打**:打印条件只有 `phasor_get() == 0`,不带任何 valid 位(`App/task/adc_task.c:209`)→
|
||||
「phasor 有数」既不说明标定可用、也不说明这一路没在削顶,判读必须配 `vl` / `cl` / `rail` 三个位图一起看;
|
||||
- 注入正弦**不会**点亮 `health:` 或 `sampling fault:` 那几行:`adc_health` 的位只吃序号差、错误计数增量与 tick 差
|
||||
(`App/algo/adc_health.c:91-189`),与波形幅值无关;它们若亮是节拍 / 丢帧问题,别归因给发生器(§8.8 同一条)。
|
||||
- `wave:` 行(`App/task/adc_task.c:782`)基线:`armed=0`、`err=0`、`ovf=0`、`drop=0`,`seg=` 是本开机以来的成段数(**可以是 0**)。
|
||||
本轮每触发一段就核 `seg` +1 且那三个计数不涨;涨了先按 §8.8 的落盘行分诊,别接着往上下注入。
|
||||
|
||||
### 8.3 接线的四条(与直流轮次比,差别只在第 2、3 条)
|
||||
|
||||
1. **注入点与直流轮次完全相同**:§3 清单的**端子侧**焊盘(`U5` 排针,串阻的 1 脚侧)。③ 段 1:1 已由直流轮次实测
|
||||
(斜率偏差 −0.14 %,§6),所以端子侧电压就是引脚电压,不用再算变比。引脚侧仍须外串 10 k(§7 第 4 条)。
|
||||
2. **幅度按峰值核,别看面板上的 Vrms**:1.000 Vrms 正弦峰值已 1.414 V。
|
||||
|
||||
| 侧 | 判据上限(§7 红线 2) | 允许的最大正弦 Vrms | 本节用量 |
|
||||
|---|---|---|---|
|
||||
| TPAFE(`UA` / `UN` / `IA`) | ±2 V 峰值 | 1.414 Vrms | **1.000 Vrms**(峰值 1.414 V) |
|
||||
| STM32(`UB` / `UC` / `IB` / `IC` / `IN`) | 0~3.3 V 单极性 | 无正向意义 | 只在 D5 用:注交流 = **故意触底**,负半周本就钉 0 |
|
||||
|
||||
3. **一次只注一路**(D3 除外,它要 `UA` 与 `UN` 两路同源),换表笔前先关输出。端子侧串阻是 **1 k**(R31 / R28 / R19 / R52 …),
|
||||
STM32 那五路负半周经**片内**钳位 / ESD 路径灌向 VDDA——网表 `docs/硬件平台/V0.1.tel` :228-241 逐条实证这些节点只有
|
||||
「电容 .2 + 串阻 .2 + MCU 脚」三件,**无外置钳位二极管、无隔直电容**,所以这条电流走的是芯片内部路径;
|
||||
1.000 Vrms 时峰值电流约 (1.414 − 0.3) / 1 k ≈ **1.1 mA**(按片内钳位压降 0.3 V 估、仓内无实测,只用来论证量级),
|
||||
但**别往上加幅度**——这种注入只允许出现在 D5 这类"故意削顶"的用例里。
|
||||
4. **电流通道也是注电压**:`IA` 的注入点同样是电压进 R19 端子侧。这一轮证的是"给定引脚电压算得对不对",
|
||||
不是"一次侧 1 A 怎么办"——后者要变比,属 `docs/任务规划/数据可信.md` §5 的端子 / 子板变比确认。
|
||||
|
||||
### 8.4 记录表抬头(每条用例一份,与日志一起归档)
|
||||
|
||||
```text
|
||||
日期 ____ / 操作人 ____ / 板子序列号 ____
|
||||
固件 commit ________(@build 0 错误 0 警告:是 / 否)
|
||||
发生器:型号 ______ 输出端接 = 高阻 / 50 Ω 波形 ____ 频率设定 ____
|
||||
万用表:型号 ______ AC 响应类型 = 真 RMS / 均值 共地方式 = 单点 / 发生器浮地
|
||||
注入点:路名 ____(端子侧 U5 / 引脚侧外串 ____ Ω)
|
||||
[adc_cal] = 未标定(eng=0)—— 必须是这个状态
|
||||
基线(未注时):meas: ua_mv=____ un_mv=____ ia_mv=____ rail=0x____ cl=0x____
|
||||
段文件(走定量档的用例):文件名 ________ 触发方式 = 手动 / 保护 / bench 取回时刻 ________
|
||||
脚本:test/host/wave_read.py(先跑 --selftest:通过 / 否) fft / shape / dump 输出与 plot 图归档在 ________
|
||||
```
|
||||
### 8.5 逐条执行卡
|
||||
|
||||
**每条卡的通用动作**:接好 → 开输出 → 等 ≥30 s(相量窗 + `meas` 200 ms 轨稳定)→ 取**连续 ≥10 行**心跳 →
|
||||
先确认 `frames` 还在涨、`adc1_err=0`,再核数 → 关输出 → 填表。"连续 ≥10 行"不是保守:`meas:` 是
|
||||
**瞬时基波有效值透传**、200 ms 是上送节拍不是平均窗(`docs/任务规划/数据可信.md` §4.5),
|
||||
单行读数带拍频式跳动,必须看一片才能定中枢。
|
||||
|
||||
#### D1 基波幅值(主用例,先做)
|
||||
|
||||
| 项 | 内容 |
|
||||
|---|---|
|
||||
| 接法 | 发生器 → `UA`(R31 / `AIN1` / U5.A3)端子侧;万用表 AC 档**并同一注入点**——量真实加到板上的电压,不是面板值 |
|
||||
| 设定 | 正弦、50.000 Hz、**1.000 Vrms**(峰值 1.414 V) |
|
||||
| 主读数 | `meas: ua_mv=`(1 mV) |
|
||||
| 期望与判据 | `ua_mv` ≈ 万用表读数 × 1000,偏差 **≤2 %**(与静态同档) |
|
||||
| 交叉读数 | 104 `0x4011`(短浮点)应 ≈ 万用表读数,单位是**引脚电压域**(`eng=0`,不是二次值) |
|
||||
| 坑 ① | **别用 `phasor(hb)` 比幅值**——×0.1 定点,1 V 只剩 10 格(§4 尾注同一条) |
|
||||
| 坑 ② | 104 每点 0.5 V(电流 0.005 A)变化死区,生效值在 `App/algo/run_par.c` 的 `[run_par]` 副本:1.000 → 1.100 V **不会**上报变化,那是死区不是坏了;连续扫幅度只看 `meas:` |
|
||||
| 坑 ③ | **`cal: ua_mv` 与 `meas: ua_mv` 同名不同物**:前者是当拍瞬时码折算(`App/task/adc_task.c:587`),后者是 200 ms 快照里那一周波的基波有效值(`App/task/adc_task.c:605`),50 Hz 下二者可以差很多——`App/task/adc_task.c:595-599` 的原注就是**勿互为判据**,D1 只认 `meas:` |
|
||||
|
||||
记录表(每条 10 行取中枢):
|
||||
|
||||
| 序号 | 万用表 AC (V) | `meas: ua_mv` | 期望 = 万用表 × 1000 | 偏差 % | 结论 |
|
||||
|---|---|---|---|---|---|
|
||||
| 1 | | | | | |
|
||||
| 2 | | | | | |
|
||||
| 3 | | | | | |
|
||||
|
||||
**加做(3 min,非判据)**:0.500 / 0.200 Vrms 两点看是否**等比**——不是验精度,是看有没有隐藏的触底或死区。
|
||||
0.2 Vrms 那点 104 必然被死区吞掉,只读 `meas:`。
|
||||
|
||||
#### D2 读数是否只跟基波走(同峰值改波形)
|
||||
|
||||
按**峰值对齐**(不是按 Vrms 对齐):三者峰值都取 1.414 V,发生器面板 Vrms 分别约 正弦 1.000 V、方波 1.414 V、
|
||||
三角 0.816 V。期望的**基波有效值**(全周傅氏基波口径:`App/algo/phasor.c:3` 的系数已预乘 √2/N、`fAmSQ` 直接就是
|
||||
有效值;下表的 20 点整周期 DFT 值就是按固件同一个窗算的):
|
||||
|
||||
| 波形 | 基波有效值 / 峰值 | 峰值 1.414 V 时的期望 `ua_mv` | 真有效值 / 峰值(对照) |
|
||||
|---|---|---|---|
|
||||
| 正弦 | 0.707 | 1000 | 0.707 |
|
||||
| 方波 | 0.904(闭式 4/π/√2 = 0.900) | ≈1278 | 1.000 |
|
||||
| 三角 | 0.578(闭式 8/π²/√2 = 0.573) | ≈817 | 0.583 |
|
||||
|
||||
- 判据:读数 = **基波**期望 ±2 %,**不是**真有效值。方波那栏最直观——真 RMS 表会读 ≈1414 mV、
|
||||
均值响应表读 ≈1570 mV,而板上读 ≈1278 mV,**这正是"这台仪表读的是基波"的证据,不是 bug**;
|
||||
所以抬头里必须写清万用表响应类型(判据文档同一条:拿真有效值表去对会以为差了 10 %)。
|
||||
- 系数的来路:方波基波幅值 = 4/π × 峰值、三角 = 8/π² × 峰值,再除 √2 得基波有效值 → 闭式 **0.900 / 0.573**,
|
||||
20 点整周期 DFT 实算 **0.904 / 0.578**;`docs/任务规划/数据可信.md` §4.6.2 的 D2 行与本节同值,算术以本节为准。
|
||||
|
||||
记录表:
|
||||
|
||||
| 波形 | 峰值设定 (V) | 面板 Vrms | 万用表 AC 实测 | `ua_mv` | 期望 | 偏差 % | 结论 |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| 方波 | 1.414 | | | | ≈1278 | | |
|
||||
| 三角 | 1.414 | | | | ≈817 | | |
|
||||
|
||||
#### D3 相位(只许比同片内)
|
||||
|
||||
| 项 | 内容 |
|
||||
|---|---|
|
||||
| 接法 | `UA`(R31)与 `UN`(R28)**都走 TPAFE**,同幅 1.000 Vrms、同相——发生器单路输出分两路即天然同相;双通道机型则两通道都设 0° |
|
||||
| 读数 | `phasor(hb) C02-UA-F1: Re=.. Im=..` 与 `C03-UN-F1: Re=.. Im=..`,各取 `atan2(Im, Re)` 再比差值 |
|
||||
| 判据(§4.6.2) | **定量档**:同相时同段内两路相位差 ≤2°,把发生器(或 B 通道)改 90° 后差值跟到 ≈90°;**定性档只判跟随**(差值落进 80°~100°,容差写进记录表) |
|
||||
| ⚠ 分辨率 | 出口只有 ×0.1 且向下截断:1.000 Vrms 时 Re/Im 各只有 ±10 格,**一格就是 0.1 V** → 角度量化误差最坏 ≈ atan(0.1 / 0.707) ≈ 8°,**≤2° 今天用串口判不出来** |
|
||||
| 三个档 | ① **段文件定量档(首选,零改代码)**:同一次注入触发一段,`test/host/wave_read.py fft` 重算基波相位,比**同段内** `UA`(表序 0)与 `UN`(表序 3)的相位差——浮点重算,不受 ×0.1 量化限制,≤2° 判得动,动作见下面第 2 段;② **定性档**:没取到段时退而用,同相 ≈0°、改 90° 后差值落进 80°~100° 即算跟随,容差写进记录表;③ **抬倍数退路**:临时把 `log_phasors()` 的倍数改成 ×1000 并改掉行尾 `(x0.1)`,跑完按 §8.9 还原——段文件档已落地,这条基本不必走,要走仍**先问用户** |
|
||||
| 红线 | **只许比同片内**:跨转换器无同刻性(V0.1 硬件缺陷)+ STM32 那五路另有 1 拍乒乓滞后 → `docs/硬件平台/ADC通道映射说明.md` §7 |
|
||||
|
||||
记录表(定性档;定量档记脚本输出,归档口径见 §8.10 第 1 条):
|
||||
|
||||
| 发生器相位设定 | C02-UA `Re` / `Im` | C03-UN `Re` / `Im` | 两路 `atan2` 之差 | 结论 |
|
||||
|---|---|---|---|---|
|
||||
| 0° / 0° | | | | |
|
||||
| 0° / 90° | | | | |
|
||||
|
||||
**段文件定量档的具体动作(D3 首选,零改代码)**
|
||||
|
||||
1. `UA`(R31)与 `UN`(R28)两路接同一发生器输出(同相),注 **1.000 Vrms / 50.000 Hz**;
|
||||
2. 稳定 ≥30 s 后,在 UI「手动录波」确认页触发一次;成段有**秒级**延迟(落盘在 defaultTask,卷空闲后一次心跳搬完整段)
|
||||
→ 等串口 `wave:` 行的 `seg=` +1、`armed` 回 0 再去取文件;
|
||||
3. FTP 取 `/wave/WAVE<NN>.BIN`(本轮那一段的确切号),**取完立刻改名**——100 个号轮转会被覆盖;
|
||||
4. 主机侧跑:`& '.venv\Scripts\python.exe' test/host/wave_read.py fft WAVE<NN>.BIN --all`
|
||||
—— 每个整周波给一行:基波 RMS、相位、2 次与 5 次谐波 RMS(单位 mV,系数镜像 `App/algo/phasor.c`);
|
||||
5. 判据:`UA`(`--ch 0`)与 `UN`(`--ch 3`)在**同一周波**内的相位差——同相注入应 ≈0°,把发生器(或 B 通道)改 90° 后应 ≈90°,
|
||||
容差 ±2°(`docs/任务规划/数据可信.md` §4.6.2 D3);
|
||||
6. ⚠ 段的**绝对**相位与发生器没有锁定关系(触发瞬间固定落在段内点 159),所以**只能比同段内两路的相对差**;
|
||||
跨段比相位、或拿发生器相位当绝对基准都不成立(段内点序见 `docs/子系统设计/故障录波设计说明.md` §6.2);
|
||||
7. 交叉旁证:同一段先 `dump`(逐字段 + 双 CRC16,看封存瞬间的标定与品质快照),再 `plot --ch 0`(CRC 不符或零长度它
|
||||
**必须拒收**而不是画出半张图);板上 `phasor(hb)` 的 `Re` / `Im` 象限应与脚本给的象限一致(×0.1 只够核象限)。
|
||||
|
||||
#### D4 测频(默认 A 档 = 判"如实报不可测")
|
||||
|
||||
| 项 | 内容 |
|
||||
|---|---|
|
||||
| 接法与设定 | 同 D1(`UA`,1.000 Vrms / 50.000 Hz) |
|
||||
| 读数 | `freq(hb): f=.. valid=..`;UI 交流量页 `Hz`;104 `0x401D` |
|
||||
| 期望(A 档 = 现状) | **就是不出数**:幅值门 `FREQ_AMP_MIN 50.0f`(`App/algo/freq.h:62`,`App/algo/freq.c:231` 拿它与基波有效值比)在引脚电压域恒不过 → `valid=0`、`f=0`、UI `Hz` 显 `--`、104 `0x401D` 上送 IV |
|
||||
| 判据 | **如实报不可测**,而不是报一个看起来对的 50.00。若门限没改却报出 50.00 → 反而是 bug,停下查 `App/algo/freq.c` |
|
||||
| B 档(要用户先点头) | 临时把 `FREQ_AMP_MIN` 由 `50.0f` 降到 `0.5f` → 重编(`@build`,要 build 锁)+ 重烧 → 扫 45.000 / 50.000 / 55.000 Hz 三点,PC 侧判据 0.02 Hz → 跑完**必须还原**,收尾判据见 §8.9 |
|
||||
| 坑 | 非整 50 Hz 时 `meas:` 会拍频式跳动,属预期 → **扫频读 `freq(hb)`,别读 `meas:`**(`docs/任务规划/数据可信.md` §8 风险表同一条);测频的取源顺序是先 `UA`(相量实例 C02)再退 `IA`(C01)(`App/algo/freq.c:47`)——本卡注 `UA` 走的就是 UA 源;若哪天只注 `IA`,测频会跟着 IA 走,别以为它锁在 UA |
|
||||
|
||||
记录表(A 档):
|
||||
|
||||
| 频率设定 (Hz) | `freq(hb)` f | valid | UI `Hz` | 104 `0x401D` 品质 | 结论 |
|
||||
|---|---|---|---|---|---|
|
||||
| 50.000 | | | | | |
|
||||
|
||||
#### D5 触底与品质路由(负向用例)
|
||||
|
||||
- **判据**(`docs/任务规划/数据可信.md` §4.6.2 D5):给 `UB`(R52 / `AIN2` / U5.B7)注 **DC −1.00 V 保持 ≥5 s**
|
||||
或 **1.000 Vrms / 2.0 Hz** 的正弦 → 负半周钉下轨 → 连续 20 拍同侧后该路贴轨位锁存、`edge` 起沿、104 该路 IV 且值清零。
|
||||
- ⚠ **注 50 Hz 同幅正弦造不出这个锁存,这是实现约束不是固件缺功能**:锁存条件是"连续 `ADC_RAIL_N_RUN = 20` 拍
|
||||
贴同一侧轨带"(`App/algo/adc_health.h:174`),而 `adc_health_rail_watch()` 里**任何一拍回到中带就把两侧计数清零**;
|
||||
1 kHz 下一个 50 Hz 周波只有 20 个点、正半周必然落在中带 → 连续贴底最长 ≈ 209°/360° × 20 ≈ **11 拍 < 20**。
|
||||
- **轨带数值**(`App/algo/adc_cal.c:452` 的 `adc_cal_rail_ths()`,TEMP 不监视):STM32 侧贴底 = 码 ≤ **81**(2 % FS ≈ 65 mV)、
|
||||
贴顶 = 码 ≥ 4013;TPAFE 侧 = ±32112 码(≈ ±4.9 V)→ **TPAFE 侧这一条在 ±2 V 判据上限内根本造不出来**,
|
||||
只有 STM32 那五路能做。
|
||||
- **改法 A(首选,零固件改动)**:发生器切 **DC 输出 −1.00 V** 注 `UB` 端子侧,保持 ≥5 s。期望:`cal:` 的 `rail=0x002`、
|
||||
`edge=0x002`、一条 `[ERR] rail: edge=0x2 sticky=0x2 (code-domain, 20-run+release)`(`App/task/adc_task.c:428`)、
|
||||
104 `0x4012` 该路 IV 且值清零、`adc: UB` 码值贴 0。撤掉注入后 **sticky 位不随输入恢复而清**(锁存语义,
|
||||
只有 `adc_health_rail_init()` / 复位清)→ 复位一次并把"是否随复位清"记进表:这条实测行为是本轮的产出之一。
|
||||
- **改法 B**:发生器 1.000 Vrms 但**频率设 2.0 Hz** → 负半周 250 ms = 250 拍贴底 ≥ 20 → 锁存;
|
||||
顺带证"贴轨检测与工频无关"这条口径。
|
||||
- **50 Hz 档照跑,判据就是"不锁存"**:记下 `adc: UB` 负半周钉 0 而 `rail` 仍 `0x000` —— 这一档证的是
|
||||
"锁存要连续 20 拍同侧"这条实现约束本身,不是失败,也不是战果。
|
||||
- **反向假阳性**:反过来注一个峰值 <65 mV(<46 mVrms)的 50 Hz 小信号,会让 `UB` 一路贴底而**锁存**——
|
||||
那是"信号小到进不了中带",不是削顶。读 `rail` 时要把这条一起排除。
|
||||
- **与 `cl` 区分**:`cl=0xE6` 是**来源派生**的静态触底掩码(`docs/任务规划/数据可信.md` §2.6),D5 要的是动态
|
||||
`rail=` / `edge=`;别拿 `cl` 当本轮战果。
|
||||
|
||||
记录表:
|
||||
|
||||
| 步 | 设定 | `rail` | `edge` | `[ERR] rail:` 行数 | 104 `0x4012` | 复位后 `rail` | 结论 |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| 1 | 50.000 Hz / 1.000 Vrms 正弦 | | | | | 不适用 | |
|
||||
| 2 | DC −1.00 V(改法 A) | | | | | | |
|
||||
| 3 | 2.0 Hz / 1.000 Vrms(改法 B) | | | | | | |
|
||||
|
||||
**段文件档的两把尺子(现在能把"来源派生 vs 实测"一次核清)**
|
||||
|
||||
`shape` 拿**实测**贴轨判定与段头 `clip_mask` 对表;而段头那一位**来自通道来源、从不实测**(`test/host/wave_read.py`
|
||||
文件头的实证与本卡上面的 `cl=0xE6` 同源,两处互证)→ 三种注入分别配三把尺子:
|
||||
|
||||
| 注入 | 命令 | 期望 |
|
||||
|---|---|---|
|
||||
| 改法 A(`UB` 注 DC −1.00 V 保持 ≥5 s) | `shape WAVE<NN>.BIN --strict` | 实测贴底落进 bit1;段头静态已含 bit1 → 等式成立。**实测冒出段头没有的位**才算失败 = 有别的路被推到轨上,先查接线 |
|
||||
| 极小注入 / 未驱动通道 | 同上再加 `--clip-superset` | 换成"段头覆盖实测"这把尺子:容忍"封存了但本轮没贴轨";实测有、段头没有仍然失败 |
|
||||
| 原接法(50 Hz 正弦注 `UB`) | `shape WAVE<NN>.BIN`(不带 `--strict`) | 只读逐通道贴轨游程:正弦过零必回中带,`--min-run` 默认 4 也可能判不出贴轨——**别把"没判"读成 bug** |
|
||||
|
||||
`--min-run`(连续几点算贴轨)与固件的"连续 20 拍"是**两把不同的尺子**,别互相换算;固件侧结论仍以 `rail:` / `edge=`
|
||||
位图为准(本卡上半段)。
|
||||
|
||||
#### D6 谐波轨(**段文件 `fft` 定量档 + UI 目检旁证**)
|
||||
|
||||
| 项 | 内容 |
|
||||
|---|---|
|
||||
| 接法 | 发生器 → `IA`(R19 / `AIN8` / U5.B5)端子侧 |
|
||||
| 设定 | 基波 + 20 % 二次 + 20 % 五次(发生器有谐波叠加 / ARB 模式就用它) |
|
||||
| ⚠ 峰值预算 | 1.000 Vrms 基波 + 两个 20 % 分量的最坏对齐峰值 ≈ 1.414 + 0.283 + 0.283 = **1.98 V,已顶到 ±2 V 判据上限**。所以基波改 **0.800 Vrms**、二次与五次各 0.160 Vrms,最坏峰值 ≈ 1.58 V 留余量;期望值随之换算 |
|
||||
| 主读数 | UI 交流量页 `Ia2` / `Ia5` 两行——**3 位小数 = 1 mV**(`Drivers/BSP/UI/ui_page_ac.c:47`),目检 + 拍照;远端可走 7003 看图截屏 |
|
||||
| 期望与判据 | 期望 ≈ 各分量注入值(0.160 Vrms)±2 % |
|
||||
| 旁证 | `phasor(hb) C04-IA-F2` / `C05-IA-F5` 的 `rms=`:×0.1 只有 1~2 格,**只能证明这根轨不是恒 0**,判不了 ±2 %(§8.1) |
|
||||
| 没有谐波叠加功能时 | 分三次单注:只注 0.160 Vrms / 100 Hz → `Ia2` 有数、`Ia5` 应 ≈0;只注 0.160 Vrms / 250 Hz → `Ia5` 有数、`Ia2` 应 ≈0;再注纯基波 → 两行都 ≈0。这一档证的是"两根轨各认各的次",**不证叠加工况**,结论里要写明 |
|
||||
| 口径 | 这两根轨**目前没有任何下游消费者**(`App/algo/prot_elm.c` 无引用、`meas` 只算基波)→ D6 只证"算得对",不证"有人用";出口归属 `docs/任务规划/数据可信.md` §9 的谐波轨立项 |
|
||||
|
||||
记录表:
|
||||
|
||||
| 注入分量 | 发生器设定 | UI 读数 (V) | 期望 (V) | 偏差 % | `phasor` 旁证 | 结论 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 基波 0.800 Vrms + 二次 0.160 + 五次 0.160 | | `Ia2=` / `Ia5=` | 0.160 / 0.160 | | | |
|
||||
|
||||
**段文件定量档(D6 的谐波现在判得到位)**
|
||||
|
||||
同一次注入(基波 0.800 Vrms + 二次 0.160 + 五次 0.160,峰值预算见上表)触发一段、FTP 取回后跑:
|
||||
|
||||
```text
|
||||
& '.venv\Scripts\python.exe' test/host/wave_read.py fft WAVE<NN>.BIN --ch 4 --all
|
||||
```
|
||||
|
||||
`fft` 逐整周波给**基波 RMS + 2 次与 5 次谐波 RMS**(mV,浮点重算),±2 % 在这条档是定量判据;`--ch` 是段内通道表序,
|
||||
`IA` = 4(表序 `UA UB UC UN IA IB IC IN`,TEMP 不录,`App/algo/wave_ring.h:216`)。UI 目检与 7003 截图降为**旁证**——
|
||||
它证的是"板上 `Ia2` / `Ia5` 与脚本算的是同一件事"(差值应在显示位数之内),不是替代判据。THD 与方和根仍不在本轮,
|
||||
口径见 `docs/任务规划/数据可信.md` §4.6.5。
|
||||
|
||||
### 8.6 顺序与耗时(一次台架 session 跑完)
|
||||
|
||||
| 序 | 做什么 | 预计 | 备注 |
|
||||
|---|---|---|---|
|
||||
| 0 | 前置门 + 基线 30 s | 10 min | §8.2,不满足就停 |
|
||||
| 1 | D1(含 0.5 / 0.2 Vrms 加做) | 15 min | 主用例 |
|
||||
| 2 | D2(方波 / 三角,峰值对齐) | 15 min | 抬头里记万用表响应类型 |
|
||||
| 3 | D6:段文件 `fft` 定量档 + UI 目检旁证(同一次注入触发一段) | 25 min | 命令见 §8.5 的 D6 卡 |
|
||||
| 4 | D3:段文件相对相位档(`UA` / `UN` 同源,再移 90°) | 20 min | 定性档只在没取到段时退用 |
|
||||
| 5 | D4 A 档 | 5 min | 判"如实报不可测" |
|
||||
| 6 | D5:50 Hz 档 + 改法 A + 改法 B + 复位复观(每档各触发一段) | 30 min | **单独一份日志**,判读规则见 §8.7 |
|
||||
| 7 | 同一份接线下把 104 交叉读数复跑一遍 | 15 min | `test/host/iec104_master.py` |
|
||||
| 8 | 取段与脚本产物归档(FTP `get` + `dump` / `fft` / `shape` / `plot`) | 15 min | 每段取完立刻改名,100 号轮转会覆盖 |
|
||||
| — | (需用户点头)D4 B 档 / D3 抬倍数档 | +40 min | 各含一次重编、烧录与还原;段文件落地后 D3 这条基本不必走 |
|
||||
|
||||
合计约 **135 min**(不含"需用户点头"那两档)。取段与跑脚本集中在末尾第 8 行统一做,中间各条只负责"触发 + 让
|
||||
`seg=` +1",免得一次 session 里反复插拔网线。
|
||||
|
||||
### 8.7 `[ERR]` 的判读规则(D5 单独跑、单独归档)
|
||||
|
||||
- D5 会**故意造出** `[ERR] rail: edge=… sticky=… (code-domain, 20-run+release)`,而 `@test` 的 forbidden 标记含
|
||||
`[ERR]`(AGENTS.md「构建与验证」)→ **这一轮不要把 `@test` 的标记校验当结论**:改人工判读,并在归档文件名与
|
||||
抬头里写明「预期 [ERR]:贴轨锁存负向用例」;§8.6 已把它排在最后单独一轮(`docs/任务规划/数据可信.md` §8 风险表「削顶负向用例被当成固件 bug」行同一条)。
|
||||
- 除这一条 `[ERR] rail:` 之外,**任何 `[ERR]` 都是不通过**;四个 Fault 的崩溃日志也以 `[ERR]` 开头 →
|
||||
出现 Fault 立即停线取现场(`docs/子系统设计/看门狗设计说明.md` §10),别再继续注。
|
||||
- 每次开机 `rail:` 边沿只打一条、`SYSLOG` 也只留痕一次("adc code rail fault" 进 `selftest.log`)——这是设计不是漏报;
|
||||
要看第二次边沿就复位一次。
|
||||
|
||||
### 8.8 失败分诊(先查这一列,别急着改固件)
|
||||
|
||||
| 现象 | 先查 | 依据 |
|
||||
|---|---|---|
|
||||
| 与万用表差约 2 倍 | 发生器输出端接设成了 50 Ω | §8.2 表第 2 行 |
|
||||
| 差约 5.3 倍,或数字带 6553.6 / 1241.2 的痕迹 | 拿错刻度,或把 `adc:` 的码值当 mV 读 | §2 两把尺子、§4「码是什么」 |
|
||||
| `phasor` 行 `rms` 只有 10 格量级 | 正常(×0.1),不是 bug | §4 尾注、§8.1 |
|
||||
| 非整 50 Hz 时 `meas:` 来回跳 | 预期:瞬时透传、200 ms 不是平均窗 → 改读 `freq(hb)` | `docs/任务规划/数据可信.md` §8 风险表 |
|
||||
| 104 读数不动 | 每点 0.5 V / 0.005 A 变化死区(生效值 `App/algo/run_par.c`) | §8.5 的 D1 坑 ② |
|
||||
| 50 Hz 正弦注 `UB` 但 `rail` 不锁存 | **预期**(连续贴底不足 20 拍)→ 改法 A / B | §8.5 的 D5 卡 |
|
||||
| 改 DC 也不锁存 | 释放沿前提没满足:开机后该通道没出现过中带样本 → 先建基线再注入 | `App/algo/adc_health.c`、§8.2 前置门末条 |
|
||||
| 撤掉注入后 `rail` 仍非 0 | 锁存语义(sticky),只 `adc_health_rail_init()` / 复位清 → 复位后仍不清**才是** bug | §8.5 的 D5 改法 A |
|
||||
| 读数带与幅度无关的偏置或漂移 | 共地 / 地环 | §8.2 末行 |
|
||||
| `meas: seq` 不涨 | 发布闸门停 → 先查采集链,别判交流 | §8.2 前置门 |
|
||||
| `health:` 或 `sampling fault:` 亮 | 与注入的波形无关:`adc_health` 的位只吃序号差、错误计数增量与 tick 差(`App/algo/adc_health.c:91-189`)→ 查节拍 / 丢帧,别查发生器 | §8.2 前置门 |
|
||||
| 9 路全 0 | 读作"没数据",不是"输入为零" | §4 尾注 |
|
||||
| `wave_read.py` 报错退出 / 拒绝出图 | **这是正确行为**:CRC 不符或零长度它必须拒收而不是画出东西 → 重取一份、核对是不是搬到一半的半成品;仍拒收就 `dump` 看两处 CRC16 哪个不符 | `test/host/wave_read.py` 文件头 |
|
||||
| `shape --strict` 说实测与段头不等 | 先分清尺子:段头 `CLIPPED` 位来自**通道来源、从不实测**;DC 偏置 / 极小注入 / 未驱动通道应改用 `--clip-superset` | §8.5 的 D5 段文件档 |
|
||||
| 触发后 `seg=` 不涨或 `drop` / `ovf` 涨 | 落盘道在 defaultTask 卷空闲后才搬段,先等几秒;仍不涨查 `wave:` 行三计数与 `/wave` 目录可写(`[ftp]` 写权限) | `App/task/adc_task.c:782` |
|
||||
|
||||
### 8.9 收尾判据(走过临时改动的一条都不许留)
|
||||
|
||||
| 临时改动 | 收尾判据 |
|
||||
|---|---|
|
||||
| D4 B 档:`FREQ_AMP_MIN` 50.0f → 0.5f(`App/algo/freq.h:62`) | 还原 + `@build` 0 错误 0 警告 + **`git diff` 里 `App/algo/freq.h` 必须为空** + 在 `docs/任务规划/数据可信.md` §7 #8 那行留一句"本轮台架已还原" |
|
||||
| D3 改倍数:`log_phasors()` 的 `* 10.0f` → `* 1000.0f`(`App/task/adc_task.c:209`) | 同上,`git diff` 里 `App/task/adc_task.c` 必须为空 |
|
||||
| 为 bench 定时自抓开过编译门(`DTU_BENCH` + `WAVE_BENCH_AUTOCAP` 非 0,`App/task/adc_task.c:153`) | 还原成默认 0 + `@build` 0 错误 0 警告 + `git diff` 里 `App/task/adc_task.c` 必须为空(产品镜像里这段必须零存在) |
|
||||
| 只动接线与发生器、没动代码 | `git status` 除归档目录外干净 |
|
||||
| 全程 | `test/board/test_config.h` 四个套件宏保持全注释(产品构建);烧录仍须 `-Rst -Run` + 回读校验 |
|
||||
|
||||
### 8.10 归档与回写(跑完必做,缺一算没收尾)
|
||||
|
||||
1. **证据归档** → `docs/测试说明/boot_log_data/`,沿用现有命名惯例(日期_主题_类型.txt):
|
||||
`20261104_ac_d1_meas_log.txt`、`20261104_ac_d5_rail_log.txt`、`20261104_ac_iec104_log.txt`;UI 目检照片同目录
|
||||
(该目录若不收图,就在抬头里写清照片存放位置)。**走段文件定量档的用例另加两样**:取回的段原件(原始字节,
|
||||
`20261104_ac_d3_wave<nn>.BIN`)与脚本输出(`fft` / `shape` / `dump` 三份文本 + `plot` 的图)——定量档的证据本体是
|
||||
**那一段原始码值**,日志只是旁证;段原件一旦覆盖就再也拿不回来,先改名再触发下一段。
|
||||
2. **实测结论回写** → `docs/硬件平台/ADC通道映射说明.md`,在 §8.1(直流轮次)之后**新开一节**——
|
||||
任务卡 `docs/任务规划/数据可信.md` §5 的 DoD 就是这么分的。本文只留"怎么跑",**不抄实测数**。
|
||||
3. **本文回写** → 只在 §8.1 那张表下加一行指针级别的句子("YYYY-MM-DD 已按本节跑通,实测见 …");
|
||||
不在本文建第二份结论表,否则两份必然漂移(`docs/文档规范.md` 同一事实只在一处详述)。
|
||||
4. **判据文档的一致性维护** → 本文 §8 的期望值算术、接法与出口分档已写进
|
||||
`docs/任务规划/数据可信.md` §4.6.2(2026-10-29:D2 的逐波形系数、D5 的 DC / 2 Hz 接法与 50 Hz 档的
|
||||
"不锁存属预期"、D3 与 D6 的"定量档走段文件、定性档走 `phasor(hb)`")。今后两边若再分叉,按开头引导块的
|
||||
两类裁定处理(语义从那节、算术与步骤从本文),**别在本文另立第二份判据表**。
|
||||
5. **销项** → `docs/任务规划/数据可信.md` §2.7 与 §6 卡片表里这一条按登记簿「完成即销项」处理,属 Ask first,
|
||||
须用户明确指示后再做。
|
||||
|
||||
### 8.11 这一轮证不到(别让读数长得像证据)
|
||||
|
||||
`docs/任务规划/数据可信.md` §4.6.5 那张五行表整条适用(端子二次值 / 精度等级 / 跨转换器相位与功率与对称分量 /
|
||||
THD 与谐波方和根 / 温升 EMC 长时间漂移)只适用,本节按出口已落地改三条现状(2026-10-29 录波数据面并入主干之后):
|
||||
**样本出口已成立**(`/wave/WAVE<NN>.BIN` + `test/host/wave_read.py`)→ D3 / D6 走定量档时结论是**形状级**,不再只是标量级;
|
||||
但**板级那一轮对表本身还没跑过**(卡片判据见 `docs/任务规划/故障录波.md`),本轮跑出来的就是第一批实测;
|
||||
段与发生器**没有绝对相位锁定**(触发瞬间只钉在段内点 159)→ 能核的是同段内两路的**相对**相位与极性,
|
||||
全局相角基准仍证不到;一次触发只有 320 点 = 320 ms,**不等于长时间稳定性**。示波器仍旧只作旁证、不进判据。
|
||||
|
||||
再补一条「别把台架做成功能性重复」的边界:**算法本体的精度已经在纯数字域钉住了**——`test/host/phasor/phasor_test.c`
|
||||
的 TC-PHASOR-003 与 TC-PHASOR-004(基波 = 峰值 / √2 容差 1 %、注入相角容差 0.5°)和 TC-PHASOR-006(2 / 3 / 5 次
|
||||
谐波 1 %),以及 `test/host/freq/freq_test.c` 的扫频判据 J1(45~55 Hz 内 ≤0.02 Hz),都是把已知正弦**直接喂进
|
||||
`sample_ring`**,绕过了 `adc_cal` 的折算(那里的幅值是工程量口径,不是引脚 µV)。所以 §8 这一轮真正要证的只有
|
||||
「信号走到 `sample_ring` 之前」那一段:发生器刻度与输出端接、前端串阻与滤波电容的幅频、两片转换器的同刻性、
|
||||
码到 mV 的折算、出口的量化。这一轮过了**不等于**「算法精度已实测验证」,结论里别那么写。
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
## 3. 怎么跑
|
||||
|
||||
```powershell
|
||||
# 全量:33 套单测逐套"编译(带 PDB)→ 插桩运行 → 解析 Cobertura",最后并集 + 比基线
|
||||
# 全量:44 套单测逐套"编译(带 PDB)→ 插桩运行 → 解析 Cobertura",最后并集 + 比基线
|
||||
& '.venv\Scripts\python.exe' scripts/check_test_coverage.py
|
||||
|
||||
# 只跑一套(调试用;子集会跳过"在测文件消失"类回退判定,见 §5)
|
||||
@@ -77,7 +77,9 @@
|
||||
退出码:`0` 全过且无回退 / `1` 有单测失败或覆盖率回退 / `2` 环境错误(无 cl、无 mscoverage、
|
||||
编译失败、XML 缺失)/ `3` 用法错误。全量实测约 **67 s**(33 套 × 编译 + 插桩运行;
|
||||
2026-10-25 实测;16 套时约 25 s、28 套时约 45 s,套件数涨了耗时就涨,别拿旧数当预算)。最新一次实测:
|
||||
2026-10-28 = 41 套 **~105 s**(该钩子同日移入 `stages: [manual]`,由远端 CI 与 `ci_local.py` 的 manual 段强制)。
|
||||
2026-10-28 = 41 套 **~105 s**(该钩子同日移入 `stages: [manual]`,由远端 CI 与 `ci_local.py` 的 manual 段强制);
|
||||
套件数现值 **44 套**(2026-10-29 实测,台账见 `docs/门禁说明/host-unit-tests.md` §6 第 4 条),**44 套这一轮的总闸耗时未重测**,
|
||||
上面那三个耗时都是当时值,别当现值预算。
|
||||
套件数的现值与逐个来历见 `docs/门禁说明/host-unit-tests.md` §6 第 4 条。
|
||||
|
||||
中间产物(exe / PDB / Cobertura XML)一律落 `%TEMP%\dtu_host\<工作树哈希>\coverage\<模块>`
|
||||
@@ -154,7 +156,7 @@
|
||||
宁可红,也不给可疑的数字。
|
||||
6. **只覆盖跑到的进程树。** 一次 `collect` 只看一次运行;没跑到的套件不进分母
|
||||
(全量跑时以"模块未跑到"判 REGRESS),子集运行明确降级(§5)。
|
||||
7. **头文件里的代码归 `.h`。** 统计面含 `.h`(静态内联与被展开的行落在头文件上);当前 33 套
|
||||
7. **头文件里的代码归 `.h`。** 统计面含 `.h`(静态内联与被展开的行落在头文件上);当前 44 套
|
||||
几乎没触及 `.h`,表里看不到它们——不要以为头文件"天生 100%"。
|
||||
8. **依赖 `Microsoft.CodeCoverage.Console.exe`。** 探测顺序:`DTU_MS_COVERAGE`(设了就必须
|
||||
有效、**不静默回退**)→ 各 VS 安装根的 `Common7\IDE\Extensions\Microsoft\CodeCoverage.Console` →
|
||||
@@ -713,7 +715,7 @@ uint16_t ch395f_link_change_count(void);
|
||||
| 类别 | 体量 | 为什么不做 | 那它靠什么把关 |
|
||||
|---|---|---|---|
|
||||
| 芯片驱动(寄存器/时序) | `ch395f.c`(801)、`gd5f2gq5ue.c`(689)、`sd2506.c`(264)、`tpafe5160.c`(157)、`rs485.c`(79) = **1,990 行** | 把 HAL 与寄存器假到底 ≈ **重写一遍驱动**,测的是自己的桩而不是硬件行为(SPI 分频必须 8、DMA 流、I2C 时序在桩里怎么编都"对") | 板级套件(`board-test-suite` skill)+ `@test` 真机日志 + 4 个 Fault 现场;陷阱逐条登记在 `docs/问题记录/CH395F_Trap_Records.md`、`docs/问题记录/GD5F2GQ5UE_Trap_Records.md`、`docs/问题记录/SD2506_Trap_Records.md` |
|
||||
| UI 侧 | 17 个 `.c` = **1,942 行** | 与 PC 模拟器是**同一份源码**,行为回归已由 `ui-golden`(菜单 8 状态 + 内容页 60 张像素黄金参考)覆盖;再写单测是第三份重复投资 | `ui-verify` skill 五步 + `docs/UI设计/UI_自动化测试流程.md` |
|
||||
| UI 侧 | 17 个 `.c` = **1,942 行** | 与 PC 模拟器是**同一份源码**,行为回归已由 `ui-golden`(菜单 8 状态 + 内容页 66 张像素黄金参考)覆盖;再写单测是第三份重复投资 | `ui-verify` skill 五步 + `docs/UI设计/UI_自动化测试流程.md` |
|
||||
| 任务编排 | `default_task.c`(281)、`adc_task.c`(171)、`net_task.c`(123)、`protect_task.c`(90)、`ui_task.c`(71)、`rs485_task.c`(11) = **747 行** | 每个只有 4~5 个函数,主体是"按顺序调别人";真逻辑在被调模块里(那些已测或在 P1/P2)。给编排层写单测最容易写成"断言我调了几次"的自证 | 真机启动锚点计数 + IWDG `required_mask`(`@test`)+ `docs/架构设计/项目启动顺序管理.md` |
|
||||
| 内核前装配 | `app_main.c`(135) | 被测对象本身就是"`osKernelStart` 之前不许调内核 API"的时序,主机侧无法忠实复现(PC 上没有那个约束) | 同上 + `cubemx-survival` 审计 |
|
||||
|
||||
|
||||
@@ -70,8 +70,9 @@
|
||||
| `TC-BOOTSTAT-030c` | init 后连读 100 次,三类 I2C 调用计数**纹丝不动** | "任意上下文可读"不是口头承诺 |
|
||||
|
||||
> ⚠ 这些号是**主机侧用例号**,不是板端用例号,也不是需求号;族口径沿用
|
||||
> `docs/编号规范.md` 的 TC 族(默认 `check_dangling`),所以**本文就是定义位**:
|
||||
> 新增/删除用例必须同步改本表,否则 `id-check` 校验 3 会报悬空、校验 7 会报孤儿。
|
||||
> `docs/编号规范.md` 的 TC 族(既有号只读),所以**本文就是定义位**:
|
||||
> 新增/删除用例必须同步改本表——`id-check` 已于 2026-10-28 退役,悬空与孤儿**不再有机器警报**,只靠评审;
|
||||
> 新增用例本身不再配号(`docs/编号规范.md` §4.1 一律停发),用语义化测试函数名。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
|
||||
- **初始化回归**:`App/task/ui_task.c` 已有 `UI port init: OK` / `UI menu init: OK` / `UI net sink: started`
|
||||
打印(见 `@test` 命令示例);将其加入 `-Required` 即可经串口自动回归 UI 初始化。
|
||||
- **屏幕内容回归**:由 LVGL 模拟器像素回归覆盖(文本级断言 + 60 张黄金参考 + 池水位门禁,
|
||||
- **屏幕内容回归**:由 LVGL 模拟器像素回归覆盖(文本级断言 + 66 张黄金参考 + 池水位门禁,
|
||||
见 `docs/UI设计/UI_自动化测试流程.md`);上机屏幕仍需人工目检(见 `测试开发标准流程.md` §1)。
|
||||
|
||||
## 扩展用法
|
||||
@@ -136,7 +136,3 @@
|
||||
`--forbidden "FAIL;HardFault"`(`[FAIL]` 仍会拦截真实断言失败);
|
||||
例:GD5F 只读 `--required "=== GD5F2GQ5UE Tests: 16/16 PASSED"`,破坏性 `68/68`。
|
||||
- **长时间采集**:daemon 全量持续写入 `state/serial.log`(20MB 上限自动截头保尾 10MB),直接读文件即可;或用 `log --grep <标记>` 过滤(2026-10-10 起先过滤后截尾,不必再配 `--tail 0`)。
|
||||
|
||||
## 变更记录
|
||||
|
||||
> (本文件不再记流水账:改了什么是正文说了算,改动过程查 git log。)
|
||||
|
||||
@@ -277,9 +277,3 @@ if (s_encode(p_key, ..., v, sizeof(v)) >= 0) {
|
||||
(现有板端套件只测了"文件缺失 → 重建"路径,是本缺陷长期漏网的直接原因)。
|
||||
- 检查是否存在同类"返回长度却按 `== 0` 判成功"的调用点(本次已全库核对 `s_encode`
|
||||
的 4 处调用点,除本缺陷外其余正确)。
|
||||
|
||||
---
|
||||
|
||||
## 6. 变更记录
|
||||
|
||||
> (本文件不再记流水账:改了什么是正文说了算,改动过程查 git log。)
|
||||
|
||||
@@ -650,9 +650,3 @@ $env:DTU_KEIL_UV4 = 'D:\NotExist\UV4.exe' # 仅当前会话,不动用户级
|
||||
| 引用关系图(文件引用) | `docs/架构设计/引用关系图说明.md`(生成工具 `tools/refgraph`;渲染依赖 Graphviz,§2.8) |
|
||||
| 各模块测试指南 | `docs/测试说明/CH395F_Test_Guide.md`、`GD5F2GQ5UE_Test_Guide.md`、`SD2506_Test_Guide.md`、`FTP_Test_Guide.md` |
|
||||
| 已知硬件陷阱 | `docs/问题记录/CH395F_Trap_Records.md` 等 |
|
||||
|
||||
---
|
||||
|
||||
## 变更记录
|
||||
|
||||
> (本文件不再记流水账:改了什么是正文说了算,改动过程查 git log。)
|
||||
|
||||
+116
-101
@@ -1,35 +1,41 @@
|
||||
# 编号规范:默认**不**用编号
|
||||
|
||||
> **一句话:语义标识是唯一默认形态,编号是例外。** 例外只留给**有脚本按字面量匹配**的那几种
|
||||
> (§4.1 的「允许继续发号」一栏);同一张表里还有一栏是**已停发、存量待清**的族(`编号治理历史.md` §9.1 给清点与批次)。
|
||||
> 除此之外一律写语义短语(§3.3)。
|
||||
> **一句话:语义标识是唯一形态,编号一律停发。** 2026-10-29 用户裁定:**任何族都不再新增编号**,
|
||||
> 连 §4.1 那五个「有脚本按字面量匹配」的存量族也一样——既有号只读引用,族里新增内容写语义行名(§3.3)。
|
||||
> §4.1.1 另列更早停发、存量待清的族(清点见 `编号治理历史.md` §9.1)。
|
||||
>
|
||||
> 这条不是洁癖,是用户 2026-10-27 的明确要求:**「不要用字母加数字的编号,简直太难以理解了,语义标识是最好的」**。
|
||||
> 这条不是洁癖,是用户 2026-10-27 的明确要求:**「不要用字母加数字的编号,简直太难以理解了,语义标识是最好的」**,
|
||||
> 2026-10-29 又收一句:**「啥号都不发」**。
|
||||
> 依据也很硬:规划 / 待办 / 审计 / 差距 / 阶段这些给人看的东西,历史上全发过号,也全都变成了没人认得的代号。
|
||||
> 2026-10-26 起两批清理把编号字面量从 **10,956 压到 8,230 处**,2026-10-27 复测为 **7,828 处**(`编号治理历史.md` §8.1 有口径说明);
|
||||
> 而清掉的号里绝大多数从来没被任何脚本读过一次。沿革与教训留在 `编号治理历史.md` §8.3 与 git log,正文不复述。
|
||||
>
|
||||
> **机器面才是事实源**:现行门禁 `scripts/check_ids_new.py` 的两张**前缀级白名单**(`KNOWN_DASH` / `KNOWN_BARE`)
|
||||
> 是 §4.1 的机器投影;本文与白名单冲突时以白名单为准,回来改本文(详解 `docs/门禁说明/id-check-new.md`)。
|
||||
> 旧的族注册表 / 别名表 / 八项校验脚本已随全库审计退役进 `scripts/archive/id_gate/`,只在手工复查存量时用。
|
||||
> **本文就是唯一事实源**:两道编号门禁已分别于 2026-10-28(全库八项校验)与 2026-10-29(只查新增行)
|
||||
> 退役,脚本、两张前缀白名单与族语料都在 `scripts/archive/id_gate/`,**不再进提交门禁**。
|
||||
> 形态判据只剩本文 §1 的默认答案(一律不发)+ §4.1 存量族表 + 人工评审;留档 `docs/门禁说明/id-check-new.md`
|
||||
> 与 `docs/门禁说明/id-check.md`,手工普查命令与恢复机器面的成本见 §8.5。归档脚本随时能重扫一批改动的形态(`--range A..B`)。
|
||||
|
||||
---
|
||||
|
||||
> **本文范围**:这里只留**现在还生效**的口径。跳号的节(`编号治理历史.md` §2 八条原则 / `编号治理历史.md` §4.2 / `编号治理历史.md` §4.5 / `编号治理历史.md` §6 模块码表 /
|
||||
> `编号治理历史.md` §7 改号与迁移 / `编号治理历史.md` §8.1 基线 / `编号治理历史.md` §8.3 批次 / `编号治理历史.md` §8.4 台账 / `编号治理历史.md` §9 存量清点与换算表)是编号治理的**过程记录**,
|
||||
> 2026-10-28 已整体移入 `scripts/archive/id_gate/编号治理历史.md`——要查历史判据、批次流水、
|
||||
> 「数据可信」任务卡号换算表,去那里;**改现在的做法只看本文**。
|
||||
> 节号沿用旧编号,故意不重排:外部文档与脚本引的是 `§4.1` / `§8.5` 这些号,重排等于制造一批假链接。
|
||||
> **本文范围**:这里只留**现在还生效**的口径。编号治理的**过程记录**(八条设计原则、基线数字、批次流水、
|
||||
> 存量清点与逐号换算表)2026-10-28 已整体移入 `scripts/archive/id_gate/编号治理历史.md`,下文简称
|
||||
> **`编号治理历史.md`**;它的节号沿用旧编号、故意不重排(外部文档与脚本引的是 `§4.1` / `§8.5` 这类号,
|
||||
> 重排等于制造一批假链接)。要查历史判据、批次流水、「数据可信」任务卡号换算表,去那篇;
|
||||
> **改现在的做法只看本文**。
|
||||
|
||||
## 1. 决定要不要发号之前,先问三句
|
||||
## 1. 默认答案:不发号
|
||||
|
||||
| 问自己 | 答"否"的结论 |
|
||||
**2026-10-29 用户裁定:新条目一律不配编号。** 这里原本是三句自问(「有脚本按字面量匹配就允许发」),
|
||||
现在这条路也关掉了——判「能不能发号」不再看形态,答案恒为否。剩下的只是既有号怎么用:
|
||||
|
||||
| 场景 | 怎么做 |
|
||||
|---|---|
|
||||
| 有脚本 / CI / 回归测试要按这个字面量做匹配吗? | **不发号**,写语义短语(§3.3) |
|
||||
| 现有文档或登记表里已经能指代这件事吗? | 引用它,别再发第二个号指同一件事 |
|
||||
| 一年后别人还能在属主登记表查到它的定义吗? | 查不到就别发——"先记着,以后再说"是编号失控的唯一来源 |
|
||||
| 想给新需求 / 新踩坑 / 新用例 / 新待办配个号 | 不发,写语义行名(§3.3);登记表那一行的行名就是标识 |
|
||||
| 新东西确实要被脚本按字面量匹配(比如新的回归脚本键) | **先问用户**(Ask first)。批下来才算例外,顺序见 §4.1 末条 |
|
||||
| 现有文档或登记表里已经能指代这件事 | 引用它,别再发第二个号指同一件事 |
|
||||
| 碰到查不到定义的号 | 删号留事实,不是补一个定义(§10) |
|
||||
|
||||
三条硬规矩(对确实要发的号):
|
||||
三条硬规矩(管既有号的引用与处置):
|
||||
|
||||
- **号不承载语义**:严重度、优先级、模块名、轮次都不写进号里。事实一变,号就开始撒谎。
|
||||
- **号不回收、不复用**:销项 = 删登记行 + 清掉所有引用 + 别名表标 `void`(§5.5)。历史上"销掉的号被
|
||||
@@ -42,7 +48,7 @@
|
||||
|---|---|---|
|
||||
| ① 最好 | **语义短语** | 规划 / 待办 / 缺陷 / 风险 / 决策 / 差距 / 文档内步骤与阶段——**默认形态** |
|
||||
| ② 其次 | **文档名 + 章节号** | 指某篇文档的某节(`docs/网络/网络自愈架构设计.md` §4.10,紧邻写法) |
|
||||
| ③ 最后 | **编号** | 只有 §4.1「允许继续发号」那一栏,且必须能反查到定义 |
|
||||
| ③ 最后 | **编号** | 只指 §4.1 五个存量族的**既有号**(只读),且必须能反查到定义;新条目不在此列 |
|
||||
|
||||
### 3.1 判定口诀
|
||||
**机器读 → 发号;人读 → 写短语。** 拿不准就写短语:短语看不懂还能靠上下文猜,号看不懂只能去查表。
|
||||
@@ -65,62 +71,62 @@
|
||||
|
||||
## 4. 编号空间
|
||||
|
||||
### 4.1 允许用号的族(**穷举**——这张表以外一律不许发号)
|
||||
### 4.1 存量族(**穷举**——2026-10-29 起连这五个族也不再发新号)
|
||||
|
||||
**允许继续发号**——**恰好下面 5 行**,判据 = 有脚本按字面量匹配它(现状实测 2026-10-27 见 `编号治理历史.md` §9.1)。
|
||||
`TC-*` **不在本表**:它的发号已按用户裁定 2026-10-27 停掉(别把那句裁定读成「暂缓」——防误读的三条对照在
|
||||
本节末的框里,清点的来龙去脉在 `编号治理历史.md` §9.1 批次三)。
|
||||
下表**恰好 5 行**,是仓库里仅剩还带编号的族:既有号继续被脚本按字面量匹配、继续被引用,**但族里新增
|
||||
内容不再配号**(写语义行名)。「有脚本按字面量匹配它」这个旧判据自 2026-10-29 起作废——这五族的号是
|
||||
历史遗留的机器把手,不是发号许可。`TC-*` 早两天(2026-10-27)已按同一逻辑停发,清点与来龙去脉在
|
||||
`编号治理历史.md` §9.1 批次三。
|
||||
|
||||
| 族 | 形态 | 属主登记处 | 用途 |
|
||||
| 族 | 形态 | 属主登记处 | 既有号被谁读 / 新写怎么办 |
|
||||
|---|---|---|---|
|
||||
| `TRAP-*` | `TRAP-<域>-<nn>` | `docs/问题记录/*_Trap_Records.md` | 踩坑证词的永久锚点,代码注释反查 |
|
||||
| `FR-*` | 需求 | `docs/产品需求/产品需求设计文档.md` §5 | 需求↔测试追溯 |
|
||||
| `CODE-RULE-<nn>` | 代码规范条款 | `scripts/check_coding_standard.py` | 门禁按条款号报错并统计存量 |
|
||||
| `MENU-STATE-<nn>` | UI 状态机键 | `simulator/tests/check_menu_rows.py` | 像素回归脚本按它取状态行 |
|
||||
| `P-<n>` | **本文的设计原则** | 本文 `编号治理历史.md` §2 | 就是本文自己的条目 |
|
||||
| `TRAP-*` | `TRAP-<域>-<nn>` | `docs/问题记录/*_Trap_Records.md` | 代码注释按号反查踩坑证词;**新踩坑**在域文件里写语义行名,不再顺延号段 |
|
||||
| `FR-*` | 需求 | `docs/产品需求/产品需求设计文档.md` §5 | 需求↔测试追溯的既有键;**新需求**用 §5 表格的行名(语义短语)指代,追溯按既有号跑存量 |
|
||||
| `CODE-RULE-<nn>` | 代码规范条款 | `scripts/check_coding_standard.py` | 门禁按条款号报错并统计存量;**新条款先问用户**——脚本要按号统计,破例得由用户批 |
|
||||
| `MENU-STATE-<nn>` | UI 状态机键 | `simulator/tests/check_menu_rows.py` | 像素回归脚本按它取状态行;**新状态同样先问用户** |
|
||||
| `P-<n>` | 编号治理的设计原则 | `scripts/archive/id_gate/编号治理历史.md` §2(2026-10-28 随沿革归档,本文不再列条目) | **只读存量**:原则已归档,新写条目按 §3.3 写语义短语 |
|
||||
|
||||
> ⚠ **「批次三不做了」只有一层意思:不去清这个族,同时把它的发号口关死。** 它**不是**「TC 族维持原状、
|
||||
> 新用例照旧配号」——维持原状的是**存量号**,关掉的是**发号口**。三条对照,防止往任何一边读过头:
|
||||
> ⚠ **停发只有一层意思:不去清存量号,但发号口关死。2026-10-29 起这句话适用于全部族,不只 `TC-*`。**
|
||||
> 维持原状的是**存量号**,关掉的是**发号口**。四条对照,防止往任何一边读过头:
|
||||
>
|
||||
> - ❌「不做 = 维持原状 = 还能发」——**错**。新用例一律用**语义化测试函数名 + 文档用例表的行名**(§3.3),
|
||||
> 不再配 TC 号;指认**既有**用例仍可引用现存号(旧号只读,不是许可新配)。
|
||||
> - ❌「停发 = 这族要废了,顺手清掉、把号腾出来复用」——**也错**。现存号与它在 `scripts/archive/id_gate/id_registry.json`
|
||||
> 里的登记,是 `check_test_traceability.py` 与 41 套 `run_unit_test.py` **按字面量读的追溯把手**,
|
||||
> 清它等于换机制(`编号治理历史.md` §9.1);号不回收、不复用是 §1 的硬规矩。
|
||||
> - ❌「registry 里 TC 族还带着活游标,所以门禁允许我发」——**不成立:这条缺口已于 2026-10-27 同日关掉**。
|
||||
> 37 个 TC 类族现在**全部** `frozen: true`,其中 **34 个 `TC-HOST-*` 子族的 `cursor` 冻结在裁定日该套件存量
|
||||
> 最高号**(5 个游标低于存量的已抬到水位:`TC-PROTELEM-013→015`、`TC-SYSLOG-108→137`、`TC-ADCHEALTH-011→023`、
|
||||
> `TC-ADCCAL-017→023`、`TC-I104SRV-041→053`;**游标必须是字符串形态**,整型比较会静默不生效)→ 在套件
|
||||
> 登记处写一个比游标更高的 TC 号就是 §8 第 5 项「冻结族越游标」**错误级**,而 `id_known_backlog.json` 台账
|
||||
> 0 条指纹 → 增量拦截等于全量拦提交。探针实测(`check_ids` 的 Checker `_check_frozen`):在 `TC-PROTSET-`
|
||||
> 段存量最高号之上再加一号 → 命中 1 条校验 5;写存量最高号本身 → 零误伤。
|
||||
> **还剩一处空白,别把这条机械化读成无死角**:主族 `TC`(没有专属子族的模块码,如 `TC-ADCIN-*`)的 `cursor`
|
||||
> 仍为 `null`——一个游标表达不了每个模块码的水位,写全族最高号反而放行低号,所以按空白登记(探针实测:
|
||||
> 给无专属子族的模块码(如 `TC-ADCIN-` 段)写一个新号,门禁不响)。这一面由三条兜:① §8 校验 3——新号没进属主登记处 = 悬空引用(错误级);
|
||||
> ② `编号治理历史.md` §9.1 末段的**冻结水位**(只减不增,涨了就要问「这号是谁在停发之后发的」);③ 评审。**所以给这些模块
|
||||
> 补号,即使在文档表格里一并补了定义行,一样违反本裁定。** 要把这面也钉死(按模块码克隆子族,或给族级加
|
||||
> 字面量上限)与「真要清退」同属追溯机制改造,按 `编号治理历史.md` §7.3 单独开卡,别夹在本批里顺手做。
|
||||
> - **唯一的重启入口**:先由用户裁定 → 再回到本节把族放回上面那 7 行、并指出按它做字面量匹配的脚本 →
|
||||
> 才谈得上发号。顺序倒过来就是 `编号治理历史.md` §1.2 那四类事故的由来。
|
||||
> - ❌「§4.1 里的族没被点名停发,所以还能发」——**错**。五族一样不发,新条目写语义行名(§3.3);
|
||||
> 指认**既有**需求 / 踩坑 / 用例仍可引用现存号(旧号只读,不是新配的许可)。
|
||||
> - ❌「停发 = 这族要废了,顺手清掉、把号腾出来复用」——**也错**。现存号是脚本与追溯机制认的把手
|
||||
> (`scripts/check_test_traceability.py` 2026-10-29 实测**只手工跑**:不在任何钩子、`scripts/ci_local.py`
|
||||
> 与远端 CI 里),清它等于换机制(`编号治理历史.md` §9.1);号不回收、不复用是 §1 的硬规矩。
|
||||
> - ❌「`id_registry.json` 里 TC 族带着游标,所以那边允许我发」——**不成立**。37 个 TC 类族 2026-10-27 全部
|
||||
> 登记 `frozen: true`,34 个 `TC-HOST-*` 子族的游标钉在当日各套件存量最高号(5 个低于存量的抬到水位:
|
||||
> `TC-PROTELEM-013→015`、`TC-SYSLOG-108→137`、`TC-ADCHEALTH-011→023`、`TC-ADCCAL-017→023`、
|
||||
> `TC-I104SRV-041→053`;**游标必须是字符串形态**,整型比较会静默不生效)。那是那次裁定的**登记留痕**:
|
||||
> 两道编号门禁退役后没有任何东西再读这份登记——**别把「不报错」读成「允许发号」**。
|
||||
> - **已知空白面(当年登记时就写着)**:主族 `TC`(没有专属子族的模块码,如 `TC-ADCIN-` 段)的 `cursor`
|
||||
> 为 `null`——一个游标表达不了每个模块码的水位,写全族最高号反而放行低号。机器面在的时候它就不响,
|
||||
> 现在连壳都没有:**给这类模块码补号,即使在文档表格里一并补了定义行,一样违反裁定**,评审专门盯。
|
||||
> 要钉死它(按模块码克隆子族)与「真要清退」同属追溯机制改造,按 `编号治理历史.md` §7.3 单独开卡。
|
||||
> - **唯一的例外入口**:先由用户裁定 → 再回到 §4.1 把该族写清「哪个脚本按字面量匹配它」 → 才谈得上
|
||||
> 发号。顺序倒过来就是 `编号治理历史.md` §1.2 那四类事故的由来。
|
||||
|
||||
**已停发、存量待清**(一律**不得再新增引用**;下表除 `TC-*` 外,登记未删只是为了让历史行不报「未登记前缀」,
|
||||
清点见 `编号治理历史.md` §9.1。`TC-*` 是这一栏的**特例**:登记与现存号都要留着,它是机器把手而不是待清对象,见 `编号治理历史.md` §9.1 批次三):
|
||||
**已停发、存量待清**(§4.1 那五族 2026-10-29 起同样停发,区别只在存量保留、不去清;本表这些族连存量引用也要清掉,一律**不得再新增引用**;下表除 `TC-*` 外,`id_registry.json` 里剩的登记只是归档普查的
|
||||
语料残留,**不再当"登记处"读**——那份登记自 2026-10-28 起没有机器读者。清点见 `编号治理历史.md` §9.1。
|
||||
`TC-*` 是这一栏的**特例**:登记与现存号都要留着,现存号仍被追溯脚本按字面量读,不是待清对象
|
||||
(见 `编号治理历史.md` §9.1 批次三):
|
||||
|
||||
| 族 | 状态 | 依据 |
|
||||
|---|---|---|
|
||||
| `TC-*` | **保留现存号、即日停发(机器已冻结)**:34 个 `TC-HOST-*` 子族 `frozen: true`、游标钉在 2026-10-27 存量水位,越游标即 §8 校验 5 错误级;现存号只减不增,新用例改用语义化测试函数名 + 文档表格行名(主族 `TC` 的空白面见上方框) | 用户裁定 2026-10-27「批次三,不坐」;本族是 §4.1 判据唯一真被脚本按字面量读的族,清它等于换追溯机制,详见 `编号治理历史.md` §9.1 批次三 |
|
||||
| `TC-*` | **保留现存号、即日停发**:`id_registry.json` 里 37 个 TC 类族登记 `frozen: true`、34 个 `TC-HOST-*` 子族游标钉在 2026-10-27 存量水位(**该登记 2026-10-29 起无机器读者,只是裁定留痕**);现存号只减不增,新用例改用语义化测试函数名 + 文档表格行名(主族 `TC` 的空白面见上方框) | 用户裁定 2026-10-27「批次三,不坐」;本族是 §4.1 判据唯一真被脚本按字面量读的族,清它等于换追溯机制,详见 `编号治理历史.md` §9.1 批次三 |
|
||||
|
||||
| 族 | 形态 | 存量 | 为什么该清 |
|
||||
|---|---|---|---|
|
||||
| `L<n>-<nn>` | 保护功能号 | **批次二已整族转功能名,即日停发**:活引用 0,只剩一处**原始串口日志**(冻结证据、永久保留)与本文/技能文档的形态举例;属主文档表首格写功能名,不再配号 | 用户 2026-10-27 定调「语义标识是最好的」+ 本轮指令「把能清的族清掉一批」;探针(Checker _check_dangling):写一个新号(字母 L + 段号 + 连字符 + 两位数、从未定义过的形态)→ §8 校验 3 悬空引用**错误级** → 发号口已机器关闭。**不冻结数值游标**:L1/L2/…各段最高号不同,单一数字游标反而放行低号 |
|
||||
| `F-<MOD>-<nn>` | 网络设计条目 | **批次一已转「`编号治理历史.md` §7 条目名」,即日停发**:代码与测试侧 0 处;属主文档 `编号治理历史.md` §7 编号列 13 条仅作历史对照(定义行不算引用) | 同上;探针:写一个新号(F 前缀 + 模块码 + 从未出现过的序号)→ 校验 3 **错误级**;引用旧号命中小写别名表 retired-to-phrase = **只读**,不构成发号许可 |
|
||||
| `L<n>-<nn>` | 保护功能号 | **批次二已整族转功能名,即日停发**:活引用 0,只剩一处**原始串口日志**(冻结证据、永久保留)与本文/技能文档的形态举例;属主文档表首格写功能名,不再配号 | 用户 2026-10-27 定调「语义标识是最好的」+ 本轮指令「把能清的族清掉一批」;发号口此前由"悬空引用"校验关着,**2026-10-29 起只由本表与评审关**。**数值游标不冻结**:L1/L2/…各段最高号不同,单一数字游标反而放行低号 |
|
||||
| `F-<MOD>-<nn>` | 网络设计条目 | **批次一已转「`编号治理历史.md` §7 条目名」,即日停发**:代码与测试侧 0 处;属主文档 `编号治理历史.md` §7 编号列 13 条仅作历史对照(定义行不算引用) | 同上;引用旧号命中别名表 `retired-to-phrase` = **只读**,不构成发号许可 |
|
||||
| `N-*` | 登记簿 `N-<nn>` | 4 处 / 3 个字面量 | 登记簿已于 2026-10-26 全面改语义短语,残留的是漏网的旧引用 |
|
||||
| `TM-*` | 阶段/里程碑 `TM-<code>-<nn>` | 1 处 | 阶段号本就属 §3.3 明令不许写号的那类 |
|
||||
| `T-TEST` | 台架阶段 **裸形**(字母 T 紧跟一位数字) | 活引用 0(批次一清零;余下是本文自述与技能文档的形态举例) | 裸形最危险(同字母多义),且改「台架阶段一」即可 |
|
||||
| `F-*` | 网络设计条目 `F-<MOD>-<nn>` | 动手前 38 处 / 12 个 → **2026-10-27 批次一收口**:正文 9 处(含一个从来没有定义行的 DRV 段孤儿号,删号)+ 主机侧单测注释 1 处改「条目名」,仅属主文档 `编号治理历史.md` §7 历史对照表留 12 条编号 | 代码注释按号回指设计条目,但没有任何脚本匹配它 |
|
||||
|
||||
- **新增族的唯一正当条件**:有脚本要按字面量匹配它。顺序固定:先改 `id_registry.json`(含属主登记处)
|
||||
→ 再写属主文档 → 最后才允许在别处引用。反过来做必然造出悬空号。
|
||||
- **新增族:2026-10-29 起一律不许**,先问用户。真批下来,顺序固定:先改本文 §4.1(写清哪个脚本按字面量
|
||||
匹配它)→ 再写属主文档 → 届时有机器面才动 `scripts/archive/id_gate/id_registry.json` → 最后才允许在别处
|
||||
引用。反过来做必然造出悬空号。
|
||||
- 模块码是既定缩写,事实源 = registry 的族 pattern 与属主文档标题行,**别自创**(`编号治理历史.md` §6)。
|
||||
|
||||
### 4.1.1 已停发的族(别再指,更别再"复用"这些号)
|
||||
@@ -129,36 +135,41 @@
|
||||
|---|---|---|
|
||||
| 登记簿 `N-x` / `S-x` / `T-x`、专项 `A-x`、已删报告的 UI 簇 `U1~U5`(2026-10-26 方案 B) | 语义短语——**登记簿表首格本身就是短语**,如「双转换器无共同采样触发」「CI 远端闭环未验证」 | `scripts/archive/id_gate/id_aliases.json` 标 `retired-to-phrase` |
|
||||
| 网络设计条目 `F-NET/F-DRV/F-MS-<nn>`(12 个,2026-10-27 批次一) | 「`编号治理历史.md` §7 + 条目名」短语,如 `(`编号治理历史.md` §7「全局读即清搁浅事件」)`;条目名的权威清单 = `docs/网络/网络自愈架构设计.md` `编号治理历史.md` §7「条目名」列;那个 DRV 段孤儿号按本节末句**删号留事实**、未补定义 | `scripts/archive/id_gate/id_aliases.json` 标 `retired-to-phrase`(13 条)+属主文档 `编号治理历史.md` §7 编号列仅作历史对照 |
|
||||
| 「数据可信」任务卡号(中文前缀「卡」+ 数字,形态见 `编号治理历史.md` §9.3;2026-10-27 批次五) | §5 表的**标识列直接写任务名**(「端子/子板变比确认」「两点标定与精度验收」),代码注释与文档写语义短语(「标定折算落地」「未标定闭锁」「遥测快照发布」…);**逐号换算表见本文 `编号治理历史.md` §9.3** | ⚠ **机器面空白**:中文前缀不进 `scripts/archive/id_gate/check_ids.py` 语料(族 pattern 全是拉丁形态)→ 门禁咬不到,今天只有本表 + `编号治理历史.md` §9.3 + 评审三条兜;`id_aliases.json` 刻意不登记(登记了机器也看不见,只多一张没人核的表) |
|
||||
| 测试验证层级号(`L0`、`L0.5`、`L1~L3` 这一族,**注意与 UI 设计令牌层 L0、硬件位号 L1~L3、采集链旧层名等同形族无关**;2026-10-28 批次六) | 文档与 CI 步骤名写语义名(静态门禁 / 主机侧纯逻辑单测 / 板端测试套件 / 主机侧回归 / 人工目检);ASCII 短码(static / preflight / commitmsg / size / host-unit / coverage)**只进**日志标签、命令行旗标、CI job id、日志文件名 | ⚠ **同形族警示**:逐号换算表与判族表见 `scripts/archive/id_gate/编号治理历史.md` §10 与 §10.1(撞族六个,动手前先判族);本族虽是拉丁形态但**门禁咬不到**——`id-check` 同日退役、现行 `id-check-new` 只看新增行里的「字母+数字」形态,停发只靠本表 + 归档换算表 + 评审 |
|
||||
| 「数据可信」任务卡号(中文前缀「卡」+ 数字,形态见 `编号治理历史.md` §9.3;2026-10-27 批次五) | §5 表的**标识列直接写任务名**(「端子/子板变比确认」「两点标定与精度验收」),代码注释与文档写语义短语(「标定折算落地」「未标定闭锁」「遥测快照发布」…);**逐号换算表见本文 `编号治理历史.md` §9.3** | ⚠ **这一族从来没有机器面**:两道门禁的语料族 pattern 全是拉丁形态,中文前缀本就不在其中,何况两道都已退役 → 只有本表 + `编号治理历史.md` §9.3 + 评审三条兜;`id_aliases.json` 刻意不登记(没有机器读者,登记等于多一张没人核的表) |
|
||||
| 测试验证层级号(`L0`、`L0.5`、`L1~L3` 这一族,**注意与 UI 设计令牌层 L0、硬件位号 L1~L3、采集链旧层名等同形族无关**;2026-10-28 批次六) | 文档与 CI 步骤名写语义名(静态门禁 / 主机侧纯逻辑单测 / 板端测试套件 / 主机侧回归 / 人工目检);ASCII 短码(static / preflight / commitmsg / size / host-unit / coverage)**只进**日志标签、命令行旗标、CI job id、日志文件名 | ⚠ **同形族警示**:逐号换算表与判族表见 `scripts/archive/id_gate/编号治理历史.md` §10 与 §10.1(撞族六个,动手前先判族);本族虽是拉丁形态但**门禁咬不到**——两道编号门禁已退役(全库校验 2026-10-28、新增行检查 2026-10-29),停发只靠本表 + 归档换算表 + 评审 |
|
||||
| `E-xx` 审计发现、`P0-x`~`P3-x` 审计条目、报告六族 `D/R/F/N/U/S`、复审残号 `S1~S14`/`A-x`/`B1~B10`/`T-x`、模拟器差距 `H-x`/`L-x`、`TM-*` 阶段号、`DP-*`、`gen`/`round`/会话临时号 | 写条目本身("原子快照取数"、"队头阻塞"、"台架日志代次 288"、"第 3 轮台架") | 别名表标 `void`;**部分死号故意不进别名表**,好让门禁继续咬残留引用 |
|
||||
| 规范曾规划却从未启用的前缀族(`DEF`/`WI`/`DR`/`OQ`/`RSK`/`GAP`/`SC`/`GEN`/`MS`/`UL`/`LAT`/`CS` 等) | 同上,写事实 | 无定义,本就不该存在 |
|
||||
|
||||
> 想知道某个号还活着吗:跑 `scripts/archive/id_gate/check_ids.py --top 0`,或直接查 `id_aliases.json`——命中 `void` /
|
||||
> `retired-to-phrase` 就是死号。**看到查不到的号,正确动作是删号留事实,不是补一个定义。**
|
||||
> 想知道某个号还活着吗:查 `id_aliases.json`(命中 `void` / `retired-to-phrase` 就是死号),或手工跑
|
||||
> `scripts/archive/id_gate/check_ids.py --top 0`——**报告制,不影响任何退出码**。**看到查不到的号,
|
||||
> 正确动作是删号留事实,不是补一个定义。**
|
||||
|
||||
### 4.3 冻结前缀(历史快照,正文不回改)
|
||||
族还在注册表里、但属主登记处已删的:**只为让冻结历史行不报"未登记前缀"而保留登记**,游标一律冻结,
|
||||
不得新增、不得复用。
|
||||
族还在 `scripts/archive/id_gate/id_registry.json` 里、属主登记处已删的那批:登记留着只为让归档普查
|
||||
不报"未登记前缀",游标一律冻结,**不得新增、不得复用**。⚠ 2026-10-29 起这份登记**没有机器读者**,
|
||||
它是档案不是闸门——别指望写一个冻结族的号会有人来拦。
|
||||
|
||||
### 4.4 这些**不是**编号——别顺手清,也别当门禁漏洞
|
||||
### 4.4 这些**不是**编号——别顺手清
|
||||
元器件位号 `U1`/`C12`/`R3`/`L5`/`D7`(硬件语料按目录整体排除)、数学与协议记号(`N-1`、测频的正序与
|
||||
负序分量 `S1`/`S2`、`SHA-256`、`RS-485`、`ADC1_IN14`、手册页码)、活表代号 `E0~E19`(网络自愈 §5.2,
|
||||
**无连字符**,与死号 `E-nn` 只差一个连字符)、Socket 状态组合 `U1~U15`(网络自愈 §1.1)、档位词 `P0~P3`。
|
||||
判据只有一条:**带连字符、且能在属主登记表查到定义**才叫编号;查不到的就是普通文本,不是「漏登记的号」。
|
||||
|
||||
> 2026-10-27 补两条实测口径:① **元器件位号目录整体排除**——`tools/netlist_semantics/` 是硬件知识库
|
||||
> (字母 T 紧跟数字在那里是网络变压器位号),已进 `id_registry.json` 的 `excluded_paths`,与 `docs/硬件平台/` 同口径;
|
||||
> ② **唯一已知误判**:`docs/算法/傅氏算法详解.md` 里的数学记号 `N-1`(「一个周波 N 个点」的求和上界)会被
|
||||
> `N-x` 族命中,属可判定引用、不影响两根护栏,**不清**——清了反而破坏公式。
|
||||
> 两条口径来自当年的语料审计,今天判"是不是编号"照它想:① **元器件位号整目录排除**——
|
||||
> `tools/netlist_semantics/` 是硬件知识库(字母 T 紧跟数字在那里是网络变压器位号),与 `docs/硬件平台/`
|
||||
> 同口径(归档普查把它写在 `id_registry.json` 的 `excluded_paths`);② **唯一已知误判**:
|
||||
> `docs/算法/傅氏算法详解.md` 里的数学记号 `N-1`(「一个周波 N 个点」的求和上界)形似 `N-x` 族,
|
||||
> 属可判定的普通文本,**不清**——清了反而破坏公式。
|
||||
|
||||
## 5. 分配、引用、销项
|
||||
|
||||
### 5.1 新增编号
|
||||
先过 §1 三问。确实要发号:① 在 `id_registry.json` 确认族与游标 ② 在属主登记处写定义行 ③ 才允许在
|
||||
别处引用。**没有属主登记处的号不许存在**——门禁的校验 3 就是照这句实现的。
|
||||
**族不在 §4.1 那 5 行之内的,第 ① 步就该走不通**(`TC-*` 已停发:即使在 registry 里查得到它、游标还是活的,
|
||||
也不构成"能发号"的理由,见 §4.1 末框)。
|
||||
### 5.1 新增编号:默认答案是没有
|
||||
|
||||
一律不发(§1、§4.1)。新条目写语义短语(§3.3),登记处的行名就是标识;引用既有号必须能反查到定义、
|
||||
旁边必须带人话(§1 三条硬规矩)。**唯一入口是用户裁定**:某样新东西确实要被脚本按字面量匹配时先问,
|
||||
批下来再按 §4.1 末条的顺序落文档。
|
||||
`scripts/archive/id_gate/id_registry.json` 的族与游标登记**只在恢复机器面时才动**(§8.5):没有脚本读它,
|
||||
写进去也拦不住任何人——**「registry 里查得到」从来不是发号许可**,许可只来自用户裁定。
|
||||
|
||||
### 5.3 代码注释
|
||||
**优先写短语**(`FTP 鉴权`、`监听生命周期模块化`),别写字母号;确需引用活号时必须带属主文档名。
|
||||
@@ -167,7 +178,13 @@
|
||||
|
||||
### 5.5 销项与归档
|
||||
删登记行 + **同步清掉全仓引用**(清引用是销项的一部分,不是"以后再说")+ 别名表标 `void`。
|
||||
冻结的历史(变更记录行、`[示例]` / `[计划]` 行)不回改,门禁对它们已豁免。**现状补充**:2026-10-28 起新文档一律不再设「变更记录」节(`docs/文档规范.md` §5.1),所以这条冻结规则只对**仍保留变更记录表的 5 篇**(同一份清单)与 `scripts/archive/id_gate/` 下的归档文档生效——不是「以后还能往变更记录里写」的理由。**唯一例外**(用户裁定 2026-10-28):这类行里**已停发 / 作废族的示例编号**可改成形态描述(写成「字母紧跟数字」这类说法)——改的是示例的写法,不是历史事实;**保留现存号**族的游标数字与硬件位号举例不在例外内,形态化等于毁证据。
|
||||
冻结的历史(`[示例]` / `[计划]` 行、仍保留变更记录表的文档)不回改。**2026-10-28 起新文档一律不再设
|
||||
「变更记录」节**(`docs/文档规范.md` §5.1——例外清单以那一节为准,本文不复制份数,抄一份就会漂一次)。
|
||||
所以"冻结历史行"只对清单里的文档与 `scripts/archive/id_gate/` 下的归档文档生效,不是「以后还能往变更
|
||||
记录里写」的理由。**唯一例外**(用户裁定 2026-10-28):这类行里**已停发 / 作废族的示例编号**可改成形态
|
||||
描述(写成「字母紧跟数字」这类说法)——改的是示例的写法,不是历史事实;**保留现存号**族的游标数字与
|
||||
硬件位号举例不在例外内,形态化等于毁证据。原先那句「门禁对它们已豁免」随门禁一起失效:
|
||||
现在没有任何门禁会去看这些行。
|
||||
|
||||
### 5.7 语义标识的登记与别名
|
||||
短语就是登记处的行名,不需要别名表;**只有"号转短语"**时才在别名表留一条 `retired-to-phrase`,
|
||||
@@ -175,43 +192,41 @@
|
||||
|
||||
---
|
||||
|
||||
## 8. 门禁(2026-10-28 起:只有一道)
|
||||
## 8. 机器面:2026-10-29 起一道也没有
|
||||
|
||||
**现行门禁 = `id-check-new`**(钩子同名):只查 `git diff` 的**新增行**里有没有未登记形态的
|
||||
「字母+数字」标识;零语料、零维护。判据、白名单与盲区 → `docs/门禁说明/id-check-new.md`。
|
||||
**现行没有编号门禁**:2026-10-29 用户裁定把最后那道只查新增行的 `id-check-new` 也摘了(钩子口径
|
||||
52 → 51,脚本与白名单移入 `scripts/archive/id_gate/check_ids_new.py`,留档 `docs/门禁说明/id-check-new.md`,
|
||||
理由与手工跑法都在那篇)。判据回到本文 §1 的默认答案(一律不发)、§4.1 存量族表与人工评审。
|
||||
|
||||
本节以下(`编号治理历史.md` §8.1~`编号治理历史.md` §8.4)是**已退役**的全库语料审计(`id-check`,八项校验)的留档:
|
||||
脚本与两份语料已整体移入 `scripts/archive/id_gate/`,不再进提交门禁,
|
||||
只在你手工复查「存量编号现状」时才跑。退役理由与判据替换见 §8.5;
|
||||
八项校验一句话版(历史口径):① 未登记前缀 ② 形态不合规 ③ 悬空引用 ④ 重复定义
|
||||
⑤ 冻结族越游标 ⑥ 编号未紧邻文档名 ⑦ 孤儿条目(告警)⑧ 可判定比例 + 两根护栏。
|
||||
全库八项校验(未登记前缀 / 形态不合规 / 悬空引用 / 重复定义 / 冻结族越游标 / 未紧邻文档名 / 孤儿告警 /
|
||||
可判定比例 + 两根护栏)2026-10-28 退役:它查过什么、为什么退、当年清点数字 → `docs/门禁说明/id-check.md`
|
||||
与 `scripts/archive/id_gate/编号治理历史.md`。**本文不抄第二份口径**——那份口径已经数错过一次了。
|
||||
|
||||
### 8.5 门禁退役路线(2026-10-28 裁定)
|
||||
### 8.5 手工普查与恢复机器面
|
||||
|
||||
目标不是"关掉检查",而是把成本从**养 99 族语料**降到**禁止新编号**。三步,每步可独立回滚:
|
||||
**没有门禁不等于没有工具**,两份脚本都还在,随时能跑(它们退成了工具,不是消失了):
|
||||
|
||||
| 步 | 内容 | 状态 |
|
||||
|---|---|---|
|
||||
| ① | 两根护栏(比例基线 / 不可判定绝对数上限)**转报告制**:照打数字,不再影响退出码 | **已完成 2026-10-28** |
|
||||
| ② | 用 **diff 级新号拦截**替换语料审计:只看新增行里命中"字母+数字"形态、且不在白名单里的字面量,FAIL 并提示改成语义短语;白名单 = 前缀级两张表(活族 11 + 器件/协议/点号约 90),基本不增长 | **已完成 2026-10-28**(`scripts/check_ids_new.py` + 钩子 `id-check-new`,与 `id-check` **双跑观察期**;详解 `docs/门禁说明/id-check-new.md`) |
|
||||
| ③ | 退役语料:99 族语料+脚本整体移入 `scripts/archive/id_gate/`(保留可复现性,不再进提交门禁);`check_ids.py` 降为手工报告工具,钩子摘除(口径 52 → 51) | **已完成 2026-10-28**(用户裁定跳过观察期直接做;`docs/门禁说明/id-check-new.md` 是唯一现役编号门禁) |
|
||||
```text
|
||||
scripts/archive/id_gate/check_ids_new.py --range A..B # 只看一段提交的新增行里有没有自造形态
|
||||
scripts/archive/id_gate/check_ids.py --top 0 # 全库存量普查(报告制,不影响退出码)
|
||||
```
|
||||
|
||||
**在 ② 落地之前,校验 1~6 仍是唯一的机械牙**:别因为"两根线不拦了"就顺手写号——
|
||||
新增的未登记前缀照样当场 FAIL(实测:在一个新文件里写一个自造前缀 + 数字,校验 1 与增量拦截双拦)。
|
||||
- **恢复机器面的成本**:把脚本放回 `scripts/`、在 `.pre-commit-config.yaml` 重挂一条钩子、口径 +1,
|
||||
并同批改 `AGENTS.md` 与 `docs/门禁说明/README.md` 两处计数——三处一起做,只挂钩子会在别人提交里露馅。
|
||||
- **为什么走到"一道也没有"**:2026-10-28 退全库八项校验(99 族语料养不起,成本落在每次碰文档的提交上),
|
||||
2026-10-29 退最后那道新增行拦截(用户裁定:它咬形态不咬语义,白名单本身成了维护面)。两道各自拦下过
|
||||
什么、退役当日那次误拦(录波段文件名 `WAVE00.BIN`)→ `docs/门禁说明/id-check-new.md` 与
|
||||
`docs/门禁说明/id-check.md`;四步流水与当时的探针数字 → `scripts/archive/id_gate/编号治理历史.md`。
|
||||
|
||||
---
|
||||
|
||||
## 10. 速查
|
||||
- 看到一个不认识的号 → 先查 `id_aliases.json` 与属主登记表;查不到就**删号留事实**,不要补定义。
|
||||
- 想给待办 / 缺陷 / 差距 / 风险发号 → 不许,写短语(§3.3)。
|
||||
- 想给任何新条目发号(含需求 `FR-*`、踩坑 `TRAP-*`、用例 `TC-*`、待办与风险)→ 不许,写语义行名(§3.3 / §4.1)。
|
||||
- 想知道「还有多少号可清」→ 看 `编号治理历史.md` §9 的存量表与三批计划。
|
||||
- 想给文档内步骤或测试阶段发号 → 不许,写「步骤 3」「阶段 7」(§3.3)。
|
||||
- 想新增前缀族 → 先回答"哪个脚本要按字面量匹配它"(§4.1);答不出就别建。
|
||||
- 想新增前缀族 → 先问用户(Ask first);「有脚本要按字面量匹配它」这个旧判据自 2026-10-29 起不再构成许可(§1)。
|
||||
- 要改号 → `scripts/rename_ids.py` + `编号治理历史.md` §7.3 五步。
|
||||
- 门禁报错读不懂 → `docs/门禁说明/id-check.md`。
|
||||
|
||||
---
|
||||
|
||||
## 变更记录
|
||||
|
||||
> (本文件不再记流水账:改了什么是正文说了算,改动过程查 git log。)
|
||||
- 编号形态拿不准 → 本文 §1 的默认答案 + §4.1 那张表;**没有任何机器会替你兜**。两道门禁的历史与退役理由 →
|
||||
`docs/门禁说明/id-check.md`、`docs/门禁说明/id-check-new.md`。
|
||||
- 想让机器帮你扫一批改动,或要恢复机器面 → §8.5。
|
||||
|
||||
+2
-2
@@ -20,7 +20,7 @@
|
||||
| `TRAP-NET-nn` | **陷阱记录**条目 | 同上 |
|
||||
| `N-nn` | `docs/任务规划/登记簿.md` 的**任务/发现编号**(⚠ 已销项的号不再可查,本文引用处即其最终事实描述) | 该登记簿 |
|
||||
| `D1`~`D7` | 本文**决策记录** | §10 |
|
||||
| `自愈收敛阶段 N` | 2026-10 的分阶段实施标签,**只存在于历史文档与归档**(2026-10-28 清理流水后全仓仅剩 5 篇保留的变更记录)(代码注释已全部改为平实语言);勾选清单已归档(§12)——**勿用它叙述设计,也勿再写回注释** | §12 |
|
||||
| `自愈收敛阶段 N` | 2026-10 的分阶段实施标签,**只存在于历史文档与归档**(2026-10-29 起全仓仅剩 5 篇保留的变更记录真台账)(代码注释已全部改为平实语言);勾选清单已归档(§12)——**勿用它叙述设计,也勿再写回注释** | §12 |
|
||||
| `TSL` / `TSC` / `TSD` | SPI 命令与数据之间的**时序间隔**要求 | `docs/芯片手册/CH395F.md` §7.4 |
|
||||
| `n30` | 压测脚本 `n30_repro.py`(:21 背靠背 STOR 30 轮),自愈回归的**主判据** | `test/host/` |
|
||||
| 沉降窗 / 隔离期 | 释放会话后、重建监听前的**最短等待**(GRACEFUL 100 ms / QUARANTINE 400 ms) | §4.3 |
|
||||
@@ -868,5 +868,5 @@ accept 走 `handle_connect_event`),且 `NET_RECON_STABLE_DEATH` 两边共用
|
||||
`git log --oneline -- docs/网络/N34-自愈审计/`;
|
||||
- 监听生命周期(本文 §1.1~§1.4 / §4.9 / §9~§11 的来源,含 P0~P3 勾选清单与台架验收记录):
|
||||
`git log --oneline -- docs/子系统设计/网络Socket监听生命周期设计说明.md`;
|
||||
- `自愈收敛阶段 N` 只出现在历史文档与归档里(变更记录节已清理,仅 5 篇保留)(代码注释已清理为平实语言)——
|
||||
- `自愈收敛阶段 N` 只出现在历史文档与归档里(变更记录节已清理,全仓只剩 5 篇真台账)(代码注释已清理为平实语言)——
|
||||
**勿再引入**,设计含义一律以本文 §2~§4 为准。
|
||||
|
||||
+13
-11
@@ -1,7 +1,7 @@
|
||||
# 门禁逐项说明(每种门禁一篇)
|
||||
|
||||
> 本目录逐项说明各门禁:**声明的 52 个钩子到底在干什么、拦谁、放谁、什么时候会骗人**——其中 3 根慢钩子带
|
||||
> `stages: [manual]`,一次 `git commit` 只实跑 49 根(口径见下条)。
|
||||
> 本目录逐项说明各门禁:**声明的 51 个钩子到底在干什么、拦谁、放谁、什么时候会骗人**——其中 3 根慢钩子带
|
||||
> `stages: [manual]`,一次 `git commit` 只实跑 48 根(口径见下条)。
|
||||
> 每个门禁一篇,八段固定结构:查什么 / 为什么要它 / 触发面 / 报错怎么读 / 好处 /
|
||||
> **限制与盲区** / 豁免与基线 / 改门禁本身要注意什么。**最后一节是这套文档存在的理由**——
|
||||
> 一份只看"拦了什么"的门禁文档,会让人以为绿就是对的。
|
||||
@@ -9,10 +9,12 @@
|
||||
- 配置事实源:`.pre-commit-config.yaml`。**钩子数的唯一口径 = YAML 解析后的 hook 条目数**,不是文件里的文本行数。
|
||||
自查(打印声明数;加/删一条钩子后,这个数要与 **AGENTS.md 的「共 N 个钩子」**、**本目录 §2 标题**同时对齐):
|
||||
`& '.venv\Scripts\python.exe' -c "import yaml; d=yaml.safe_load(open('.pre-commit-config.yaml', encoding='utf-8')); print(sum(len(r['hooks']) for r in d['repos']))"`
|
||||
→ **52**(2026-10-26:49 → 50 加 `generated-fresh`;2026-10-27:50 → 51 加 `nested-comment`;
|
||||
2026-10-28:51 → 52 加 `id-check-new`、随即 52 → 51 摘掉 `id-check`(退役全库语料审计);2026-10-29:51 → 52 加 `skill-size`(SKILL.md 写侧上限与 reference 指针,详见 [`skill-size.md`](skill-size.md)))。
|
||||
→ **51**(2026-10-26:49 → 50 加 `generated-fresh`;2026-10-27:50 → 51 加 `nested-comment`;
|
||||
2026-10-28:51 → 52 加 `id-check-new`、随即 52 → 51 摘掉 `id-check`(退役全库语料审计);2026-10-29:51 → 52 加 `skill-size`(SKILL.md 写侧上限与 reference 指针,详见 [`skill-size.md`](skill-size.md));
|
||||
同日 52 → **51** 退役 `id-check-new`——只查新增行的编号门禁整体退场,脚本与白名单移入
|
||||
`scripts/archive/id_gate/`,此后**编号形态没有机器面**(留档 [`id-check-new.md`](id-check-new.md)))。
|
||||
⚠ **别用 `grep -c` 去数配置里的声明行**:该文件里有一条**注释掉的**候选钩子(clang-format,第 65 行),
|
||||
文本 grep 会多算 1 = 52——「声明 52 / 文档 51 / 实跑 51」这种三个数不同源的争执就是这么来的。真要 grep,
|
||||
文本 grep 会多算 1(当前口径 51 会数成 52)——「声明 52 / 文档 51 / 实跑 51」这种三个数不同源的争执就是这么来的。真要 grep,
|
||||
用**锚定行首缩进**的模式(它天然跳过以 # 开头的注释行)2026-10-28 实测直接得 **51**(当时口径),与 YAML 口径一致;
|
||||
会多算 1(比口径多 1)的是**不锚定行首、按子串**匹配声明行的写法(那条被注释掉的候选也被它算进去)。
|
||||
⚠ 反过来的坑也真踩过(2026-10-27):在配置**注释里复述那个 grep 字面量**,会让文本 grep 再虚高 1——
|
||||
@@ -39,12 +41,12 @@
|
||||
| **改写型** | 不报错,直接改你的文件 | `trailing-whitespace`、`end-of-file-fixer` | 重新 `git add` 被改的文件再提交(它改的是工作区,不是索引) |
|
||||
| **硬拦截** | 违反即失败,没有存量豁免 | `cppcheck`、`coding-standard`、`doc-links`、`no-mojibake`、`mem-budget`、`ui-golden`、`font-charset`、`lv-conf-sync`、`task-table`、`mem-numbers`、`registration-check`、`cubemx-survival`、`test-suite-switch`、22 个主机单测、官方 5 个、`gitlint` | 只能改代码或改文档;**不要**找豁免开关 |
|
||||
| **增量拦截** | 规则恒生效,但存量钉在基线/台账里,只许减不许增 | `layer-deps`(3 条,2026-10-25 还清 UI 记录 3 条)、`bsp-err`(38 条)、`generated-fresh`(5 处 `docs/images/` 配图存量,脚本内 `BASELINE`)、`nested-comment`(2 处主机侧假件头,`test/host/common/`,脚本内 `BASELINE`) | 报错先分清是**新增**还是**存量搬家**:`--verbose` 看归类,`--prune` 看已还清 |
|
||||
| **只查新增** | 只看本次改动的增量,没有存量基线,也没有台账 | `id-check-new` | 改成语义短语,或把设备名/协议名登记进脚本白名单(行内 `[编号豁免]` 是最后手段) |
|
||||
| **只查新增** | 只看本次改动的增量,没有存量基线,也没有台账 | ~~`id-check-new`~~(**2026-10-29 退役**,脚本在 `scripts/archive/id_gate/`;这一姿态已无现役门禁) | 手工复查时才谈得上:改成语义短语(门禁不再跑,行内 `[编号豁免]` 也随之失效) |
|
||||
|
||||
⚠ 增量拦截最容易误会的一点:**绿灯不等于没问题**,只等于"没有比上次更差"。
|
||||
每个增量拦截门禁的基线数字都写进它自己的文档,读那篇时第一眼看的就是"现在在册多少条"。
|
||||
|
||||
## 2. 索引(52 个 hook → 29 篇,其中 1 篇是已退役门禁的留档 + 1 根只有本表指针(专篇待补)+ 1 根详解在 docs/测试说明/)
|
||||
## 2. 索引(51 个 hook → 29 篇,其中 2 篇是已退役门禁的留档 + 1 根只有本表指针(专篇待补)+ 1 根详解在 docs/测试说明/)
|
||||
|
||||
> 带 `stages: [manual]` 的三根(`cppcheck` / `test-cppcheck` / `test-coverage`)**提交期不跑**,只在远端 CI 的
|
||||
> 「手动阶段门禁」步与 `scripts/ci_local.py` 的 manual 段跑;下表对应两行的「文档」列已标注。
|
||||
@@ -53,8 +55,8 @@
|
||||
|---|---|---|---|---|
|
||||
| [`bsp-err.md`](bsp-err.md) | `bsp-err` | BSP 的对外 API 面:错误通道类型、超时宏命名、必须写返回值、返回值不得裸丢弃 | `Drivers/BSP/**` 或门禁自身 | 已写 |
|
||||
| [`layer-deps.md`](layer-deps.md) | `layer-deps` | 分层方向:`Drivers/BSP/**` 不得 include `App/**` | `Drivers/BSP/**` | 已写 |
|
||||
| [`id-check.md`](id-check.md) | ~~`id-check`~ | **已退役(2026-10-28)**:全库语料的八项校验,留档备查;现行编号门禁见下一行 | 在时有:几乎所有文本文件 | 已写(退役留档) |
|
||||
| [`id-check-new.md`](id-check-new.md) | `id-check-new` | **只查新增行**有没有新造编号(零语料前缀白名单,已停发族只告警) | 任意 md/c/h/py/yaml/txt | 已写 |
|
||||
| [`id-check.md`](id-check.md) | ~~`id-check`~ | **已退役(2026-10-28)**:全库语料的八项校验,留档备查;接班件也在下一行 | 在时有:几乎所有文本文件 | 已写(退役留档) |
|
||||
| [`id-check-new.md`](id-check-new.md) | ~~`id-check-new`~ | **已退役(2026-10-29,用户裁定)**:只查新增行的编号门禁,留档备查(含退役理由与手工跑法);**编号形态此后无机器面** | 在时有:任意 md/c/h/py/yaml/txt | 已写(退役留档) |
|
||||
| [`doc-links.md`](doc-links.md) | `doc-links` | 文档里的路径引用是否存在;`--sections-strict` 另查章节号是否还存在 | 任意 `.md` | 已写 |
|
||||
| [`cppcheck.md`](cppcheck.md) | `cppcheck`、`test-cppcheck` | 静态分析(真机侧与 `test/` 侧两套范围与抑制项) | C/H 源文件 | 已写(`stages: [manual]`) |
|
||||
| [`coding-standard.md`](coding-standard.md) | `coding-standard` | 编码规范 V1.0 的可机械检查子集(命名、头文件保护宏、模块头注释块…) | C/H 源文件 | 已写 |
|
||||
@@ -70,12 +72,12 @@
|
||||
| [`cubemx-survival.md`](cubemx-survival.md) | `cubemx-survival` | CubeMX 重生成会不会把定制静默抹掉(人工目检审计兜底) | `.ioc`、`Src/`、`Inc/` | 已写 |
|
||||
| [`test-suite-switch.md`](test-suite-switch.md) | `test-suite-switch` | 板级套件开关必须互斥;全注释 = 产品构建 | `test/board/test_config.h` | 已写 |
|
||||
| [`font-charset.md`](font-charset.md) | `font-charset` | UI 用到的汉字是否都在子集字体里(缺字 = 白框) | `Drivers/BSP/UI/**`、字体脚本 | 已写 |
|
||||
| [`ui-golden.md`](ui-golden.md) | `ui-golden` | UI 像素回归:菜单 8 状态 + 内容页 60 张黄金参考图比对 | UI 源码、模拟器 | 已写 |
|
||||
| [`ui-golden.md`](ui-golden.md) | `ui-golden` | UI 像素回归:菜单 8 状态 + 内容页 66 张黄金参考图比对 | UI 源码、模拟器 | 已写 |
|
||||
| [`bom-guard.md`](bom-guard.md) | `bom-guard` | 带 BOM 的文件被编辑工具剥掉 BOM(ARMCC 换解码 → 假语法错) | `Drivers/BSP/UI/**` 等名单内文件 | 已写 |
|
||||
| [`setview-check.md`](setview-check.md) | `setview-check` | 定值查看行表与 `prot_set` 枚举序 / `g_prot_set_meta` 上下限是否同一份口径 | `tools/setview_check/**`、`ui_w_setview.*` | 已写 |
|
||||
| (专篇待补,档位与限度正文在 [`../UI设计/UI_自动化测试流程.md`](../UI设计/UI_自动化测试流程.md) §7.3) | `uinav-selftest` | 板端 UI 导航器认屏快检(黄金参考帧分类;完整闭环档=合入前/上板前手工跑,快检不互替) | `scripts/board_ui_nav.py`、`simulator/tests/ref/*.bin` | 指针 |
|
||||
| [`host-unit-tests.md`](host-unit-tests.md) | 22 个 `*-unit-test` | 主机侧单测(同一机制 22 个实例):逻辑层在无硬件的 PC 上编译并跑断言 | 各自被测模块与其测试目录 | 已写 |
|
||||
| 详解在 [`../测试说明/主机单测覆盖率口径.md`](../测试说明/主机单测覆盖率口径.md)(口径 / 分母 / 基线 / 盲区都在那篇,本目录不重复) | `test-coverage` | **覆盖率总闸**:跑全部 41 套主机单测 + 已覆盖行只增不减的回退台账 | `App/`、`Drivers/BSP/`、`test/host/`、脚本与基线 | 已写(在 `docs/测试说明/`;`stages: [manual]`) |
|
||||
| 详解在 [`../测试说明/主机单测覆盖率口径.md`](../测试说明/主机单测覆盖率口径.md)(口径 / 分母 / 基线 / 盲区都在那篇,本目录不重复) | `test-coverage` | **覆盖率总闸**:跑全部 44 套主机单测 + 已覆盖行只增不减的回退台账 | `App/`、`Drivers/BSP/`、`test/host/`、脚本与基线 | 已写(在 `docs/测试说明/`;`stages: [manual]`) |
|
||||
| [`trailing-whitespace.md`](trailing-whitespace.md) | `trailing-whitespace` | 行尾空白(改写型;CubeMX/Keil 生成文件豁免) | 全部 | 已写 |
|
||||
| [`end-of-file-fixer.md`](end-of-file-fixer.md) | `end-of-file-fixer` | 文件末尾必须恰好一个换行(改写型;同豁免) | 全部 | 已写 |
|
||||
| [`check-added-large-files.md`](check-added-large-files.md) | `check-added-large-files` | 别把大文件(日志/镜像/二进制)误提进仓库 | 全部 | 已写 |
|
||||
|
||||
@@ -140,7 +140,3 @@ BSP 约定:命中 38(在册 38 / 新增 0),基线共 38
|
||||
- 加新的 must-use HAL 族:改 `HAL_STATUS_RE`,同时补一条正反例自测。
|
||||
- 改标签名:脚本与基线一次改完(§6 第 9 条),随后 `--emit-baseline` 复核数量不变。
|
||||
- 门禁自己的注释里不要写只有本次会话懂的代号;要引用规范就写`文件.md` + 紧邻编号。
|
||||
|
||||
## 9. 变更记录
|
||||
|
||||
> (本文件不再记流水账:改了什么是正文说了算,改动过程查 git log。)
|
||||
|
||||
@@ -88,6 +88,16 @@ Drivers/BSP/X/x.c:42 [CODE-RULE-09] 函数 foo_bar 缺少函数注释(应含
|
||||
但写成 `Malloc(` 就绕过了(同形后缀也一样:`buf_free(` 因词边界不成立而不算违规)。
|
||||
8. CODE-RULE-20 **只管堆分配函数名**:`alloca` 与变长数组(VLA)是**栈**上的坑,不归它;
|
||||
分配不释放(泄漏)、释放后继续用(UAF)也不归它——本条只判"别碰 C 堆"这一件事。
|
||||
9. **CODE-RULE-09 的回看窗口只有 25 行**:脚本 `scripts/check_coding_standard.py:194` 取的是函数定义行
|
||||
往前 25 行(`window = lines[idx-26:idx-1]`),在里面找「函数功能」关键词。于是**函数头注释块一旦写
|
||||
到 25 行以上,关键词就被挤出窗口**——注释本身完全合规,也照样报「函数缺少函数注释块」。2026-10-29
|
||||
一次真实触发(lead 复跑抓到 6 处、已改 3 个生产文件,全部是**纯注释重排、无一行逻辑改动**):录波
|
||||
落盘道与 UI 道上四个带长口径注释的函数(`wave_store_drain`、`s_log_record_edge`、`App/task/ui_task.c`
|
||||
的录波按键 helper、`simulator/main.c` 的合成喂拍 helper)各撞一到两处。**写法上的规避**:把长口径
|
||||
另起一块放在函数注释块**之前**(两块分开),或把细节搬进函数体内——别让「函数功能」那一行离定义行超过 24 行。
|
||||
10. **不带文件参数就是空跑**:脚本 `:321` 是逐 `sys.argv[1:]` 处理的,**不给文件参数时一个字节都不查、
|
||||
直接返回 0**。手工复现这条门禁时把那个 RC=0 读成「过了」是错的——必须显式列出要查的路径(pre-commit
|
||||
里由框架喂 staged 文件,所以钩子本身不会空跑)。同族坑见 `docs/代码规范/pre-commit使用说明.md` §2。
|
||||
|
||||
补录(判据细节,迁移自原手册):
|
||||
|
||||
|
||||
@@ -85,7 +85,3 @@ D 类刻意只校验**紧邻写法**:文档名与 `§` 之间只允许空白
|
||||
|
||||
- 放宽匹配(例如允许裸名引用)前先想清楚:**误报压到 0 是靠"只认紧邻写法"换来的**。
|
||||
- 新增一类豁免,必须同时新增一类误报;把豁免写在 `docs/文档规范.md` 与本节里,别只写进代码。
|
||||
|
||||
## 9. 变更记录
|
||||
|
||||
> (本文件不再记流水账:改了什么是正文说了算,改动过程查 git log。)
|
||||
|
||||
@@ -98,7 +98,3 @@ A 通过 + B 通过 ⟹ 字体覆盖"源码在用"与"刻意保留"的每一个
|
||||
|
||||
- 放宽"必需集"来源(比如不再扫某个目录)前先确认该目录的字最终确实会进生成链;
|
||||
- 与 `ui-golden` 是互补关系:本门管"有没有字形",golden 管"像素对不对"。
|
||||
|
||||
## 9. 变更记录
|
||||
|
||||
> (本文件不再记流水账:改了什么是正文说了算,改动过程查 git log。)
|
||||
|
||||
@@ -88,30 +88,32 @@
|
||||
3. `include_dirs` 与源文件清单是**手写**的:新依赖一个目录就会假失败(见 §4 第 2 类),反过来,
|
||||
漏了某个真实依赖可能让测试**编过却少编了一个翻译单元**(少测而不自知)。
|
||||
4. **专属钩子不是唯一防线,而「没有专属钩子」也不等于「没被跑」**。2026-10-26 按 git 历史与实测重新
|
||||
清点(2026-10-28 复点:下列数字已按复点值更新;上一版写「16 个模块有专属钩子、另有 12 套、总闸跑 28 套」——三个数都随 2026-10-25 的
|
||||
清点(2026-10-28 复点、2026-10-29 录波三套入库后再复点:下列数字已按复点值更新;上一版写「16 个模块有专属钩子、另有 12 套、总闸跑 28 套」——三个数都随 2026-10-25 的
|
||||
六根新钩子与后续新增套件过期了,正是本目录反复在防的"文档与机器面不同码"):
|
||||
- **22** 根专属钩子 = 有独立 `files:` 触发面、需要**秒级归因**的那个子集;
|
||||
- `test/host/` 下带 `run_unit_test.py` 的套件实测 **41** 套(43 个目录,除 `common` 与
|
||||
`__pycache__`)⇒ **没有专属钩子的是 19 套**:`boot_stats`、`cfg_file_store_mcu`、`console_log`、
|
||||
- `test/host/` 下带 `run_unit_test.py` 的套件实测 **44** 套(46 个目录,除 `common` 与
|
||||
`__pycache__`;两个数分别来自 `check_test_coverage.py --list` 与 `ls -d test/host/*/`,2026-10-29 实测)
|
||||
⇒ **没有专属钩子的是 22 套**:`boot_stats`、`cfg_file_store_mcu`、`console_log`、
|
||||
`ftp_cfg`、`iec104_serv`、`lftpd`、`lftpd_inet`、`lftpd_io`、`net_cfg`、`net_events`、
|
||||
`net_listener`、`net_pending`、`net_select`、`net_socket`、`prot_set_store`、`soe_store`、
|
||||
`sys_log_mcu`、`task_prof`、`ui_sink`;
|
||||
- 这 19 套每次 CI 与 `scripts/ci_local.py` 都由 `test-coverage` **总闸**真跑(该钩子带 `stages: [manual]`:
|
||||
`sys_log_mcu`、`task_prof`、`ui_sink`、`wave_ring`、`wave_store`、`wave_trig`(末三套 2026-10-29 随
|
||||
故障录波入库,按同一条 Lead 裁定不补专属钩子;22 = 44 套 − 22 根专属钩子,逐点数与两处机器源互证);
|
||||
- 这 22 套每次 CI 与 `scripts/ci_local.py` 都由 `test-coverage` **总闸**真跑(该钩子带 `stages: [manual]`:
|
||||
`git commit` 阶段不跑它,这一根与 `cppcheck` / `test-cppcheck` 同属 CI 与 `ci_local.py` 的 manual 段);
|
||||
发现规则是
|
||||
`HOST_TEST_DIR.rglob("run_unit_test.py")`(与 `scripts/ci_local.py` 的主机侧纯逻辑单测同一口径),
|
||||
退出码语义写死「0 = 全部单测通过且覆盖率相对基线没回退 / 1 = 有单测失败或覆盖率回退」⇒
|
||||
**失败照样拦(CI 与 `ci_local.py` 的 manual 段)**。差的只是归因粒度(要在总闸输出里认出是哪套)与耗时(41 套全量比单根慢得多);
|
||||
**失败照样拦(CI 与 `ci_local.py` 的 manual 段)**。差的只是归因粒度(要在总闸输出里认出是哪套)与耗时(44 套全量比单根慢得多);
|
||||
- 要不要给某套补第 23 根,判据现成:pre-commit 4.x 没有 `always: true`,**该模块有没有自己的
|
||||
`files:` 触发面**决定补了会不会真跑;只为凑数加一根,等于把「快归因面」和「全量把关」两件事混成
|
||||
一件,还要让钩子计数再改一次;
|
||||
- **裁定(2026-10-27,Lead):这批无专属钩子套件(裁定当时 18 套,2026-10-28 现值 19 套;含 `test/host/ui_sink`)不补专属钩子,差异按设计说明记录。**
|
||||
- **裁定(2026-10-27,Lead):这批无专属钩子套件(裁定当时 18 套,2026-10-28 为 19 套,2026-10-29 现值 22 套;含 `test/host/ui_sink` 与新增的 `wave_ring` / `wave_store` / `wave_trig`)不补专属钩子,差异按设计说明记录。**
|
||||
理由不是省事:22 根专属钩子存在的唯一意义是**秒级归因**;而 `ui_sink` 改动面小,它的失败面全部
|
||||
落在 `test-coverage` 总闸的必跑路径里,坏了照样在 CI / `ci_local.py` 拦下。再加一根只是多一个必须「声明数 / 文档数 /
|
||||
实跑数」三处同源同步的计数点——本仓 2026-10-26 到 27 一天之内就为 40 / 50 / 51 这三个数不同源
|
||||
返工过两轮。**要读「这套跑没跑」,读总闸输出,不要来数钩子。** 两个方向的空头账一起堵住:
|
||||
① 别把没接线的套件算进钩子账(原写「23 个 / 含 ui-sink」正是这么错的;2026-10-27 复核的准数是
|
||||
22 根 / 40 套 / 18 套无专属钩子——第 41 套 `boot_stats` 当日 11:29 才入库,此后两数是 41 / 19,以本条上面的实测行为准);② 也别把总闸的绿读成「每套都被单独归因过」——它只保证
|
||||
22 根 / 40 套 / 18 套无专属钩子(三个数都是当时值)——第 41 套 `boot_stats` 当日 11:29 才入库,此后两数当时是 41 / 19,现值 44 / 22 以本条上面的实测行为准);② 也别把总闸的绿读成「每套都被单独归因过」——它只保证
|
||||
「全跑过 + 覆盖率没回退」。将来确实要给某套补专属钩子,先过上一条判据,并在**同一笔**里改
|
||||
AGENTS 与门禁索引的计数(口径 = YAML 解析条目数,见 `docs/门禁说明/README.md` §2 首条)。
|
||||
- 总闸的触发面是 `App/`、`Drivers/BSP/`、`test/host/`、覆盖率脚本与基线,**外加门禁自身**
|
||||
@@ -129,8 +131,8 @@
|
||||
- 用例号段:`TC-HOST-<模块码>` 以 `test/host/<目录>/*` 为属主登记处(`docs/编号规范.md` §4.1);
|
||||
**该号段 2026-10-27 起停发新号**(用户裁定「批次三,不坐」):新增用例**不配号**,写语义化测试函数名,
|
||||
现存号只读、不清、不复用。追溯器只双向比对已有集合,**不会**因为新用例没号而报错——别把它当"要带号"。
|
||||
**机器口径同日已落地**:`scripts/archive/id_gate/id_registry.json` 37 个 TC 类族全部 `frozen: true`,34 个子族游标冻结在 2026-10-27 存量最高号,
|
||||
在号段上再加新号 = `id-check` 校验 5 错误级;无专属子族的模块码落在主族 `TC`(游标仍为空),那一面由校验 3 + 冻结水位 + 评审兜住
|
||||
**当时的机器口径**(2026-10-27 落地,如今只剩留痕):`scripts/archive/id_gate/id_registry.json` 37 个 TC 类族登记 `frozen: true`、34 个子族游标冻结在当日存量最高号,
|
||||
当年在号段上再加新号 = `id-check` 校验 5 错误级;无专属子族的模块码落在主族 `TC`(游标仍为空)。**两道编号门禁已退役(2026-10-28 / 29),这些校验都不再跑**,那一面如今只由规范与评审兜住
|
||||
→ `docs/编号规范.md` §4.1 末框与 `scripts/archive/id_gate/编号治理历史.md` §9.1 末段。
|
||||
|
||||
## 8. 改这套门禁本身(新增一个模块的宿主单测)
|
||||
|
||||
+58
-79
@@ -1,102 +1,81 @@
|
||||
# id-check-new(编号门禁·新增行)
|
||||
# `id-check-new` — 编号门禁·新增行(零语料)——**已退役(2026-10-29)**
|
||||
|
||||
> 一句话:**只查这次改动新增的行里有没有新造的编号**,不维护任何族清单。
|
||||
> 它是 `id-check` 全库语料审计的接班件(退役路线见 `docs/编号规范.md` §8.5)。
|
||||
> ⚠ **本文是退役留档,不要照着它去改门禁。**
|
||||
> 2026-10-29 用户裁定:这道门禁整体去掉——钩子从 `.pre-commit-config.yaml` 摘除(YAML 解析口径
|
||||
> 52 → 51),脚本移入 `scripts/archive/id_gate/check_ids_new.py`(仍可手工跑,`--self-test` 保留)。
|
||||
> **此后编号形态没有任何机器面**:判据只剩 `docs/编号规范.md` §1 的默认答案(一律停发)、§4.1 存量族
|
||||
> (穷举)与人工评审。前辈 `id-check`(全库八项校验)已于 2026-10-28 退役 → `docs/门禁说明/id-check.md`;
|
||||
> 两步合起来的路线 → `docs/编号规范.md` §8.5。
|
||||
> 下面 §1~§6 是退役前的原样描述,只在手工复查「这批改动 / 这段历史里有没有野生编号」时用得上。
|
||||
|
||||
## 1. 它在查什么
|
||||
## 1. 它当初在查什么
|
||||
|
||||
拿 `git diff` 的**新增行**,只做三件事:
|
||||
|
||||
| 形态 | 例子(形态描述,不是本仓号) | 判据 |
|
||||
|---|---|---|
|
||||
| 破折形态 | 两字母前缀 + 连字符 + 数字 | 首段不在白名单 → **FAIL**;在「已停发族」→ 只 WARN |
|
||||
| 裸形态 | 大写字母串紧跟数字(外设/器件/点号写法) | 前缀不在白名单 → **FAIL** |
|
||||
| 单字母 + 数字 | 元件位号与层次号同形的那些 | **一律放行**(见 §6 盲区) |
|
||||
| 破折形态 | 两字母前缀 + 连字符 + 数字 | 首段不在 `KNOWN_DASH` → **FAIL**;在 `RETIRED_DASH`(已停发族)→ 只 WARN |
|
||||
| 裸形态 | 大写字母串紧跟数字(外设 / 器件 / 点号写法) | 前缀不在 `KNOWN_BARE` → **FAIL** |
|
||||
| 单字母 + 数字 | `C12` / `U15` / `L3` / `R3` 这类元件位号与层次号同形 | **一律放行**(已知盲区,与旧门禁的"裸形盲区"同源) |
|
||||
|
||||
判据全文只有两张前缀表(`KNOWN_DASH` ≈ 11 条、`KNOWN_BARE` ≈ 90 条)与一张算术排除表
|
||||
(`SIZE`/`LEN`/`MAX` 之类后面跟 `-数字` 是减法不是编号)。**没有族形态正则、没有游标、
|
||||
没有属主登记处、没有比例基线**——这就是它相对 `id-check` 的全部区别。
|
||||
判据全文只有两张前缀表(退役时 `KNOWN_DASH` 11 条、`KNOWN_BARE` 90 余条)与一张算术排除表
|
||||
(`SIZE` / `LEN` / `MAX` 之类后面跟 `-数字` 是减法不是编号)。**没有族形态正则、没有游标、没有属主
|
||||
登记处、没有比例基线**——这就是它相对 `id-check` 的全部区别,也是它当初被选为接班件的理由。
|
||||
|
||||
## 2. 为什么要它(与 id-check 的分工)
|
||||
豁免三档:行内含 `[示例]` / `[计划]` 按冻结口径跳过;确需保留的字面量(如冻结的现场日志)在同一行
|
||||
写 `[编号豁免]`;脚本自身、`scripts/archive/`、`docs/芯片手册/`、`docs/硬件平台/`、`Lib/`、
|
||||
`Middlewares/` 等在排除清单里。**加白名单是唯一的放宽手段**——没有"整库豁免"入口,也没有 `--write`
|
||||
现状洗白(与旧门禁同一条纪律)。
|
||||
|
||||
`id-check` 需要养 99 族语料(`id_registry.json` 87.6 KB + `id_aliases.json` 187 KB);
|
||||
实测它的**单次运行只有 1.8 s**,贵的是"每笔提交都要维持语料自洽"——近 80 笔提交里 61 笔
|
||||
改了语料/门禁/规范。而它真正有用的那部分(拦住"新写一个自造编号")不需要语料:
|
||||
只要知道"这个前缀我从没见过"就够了。
|
||||
## 2. 为什么当初要它
|
||||
|
||||
所以两者的分工是:**`id-check` 管存量一致性(逐步退役),`id-check-new` 管增量不许新增**。
|
||||
观察期内两条**同时跑**,互相兜底;观察期结束后按 `docs/编号规范.md` §8.5 摘掉 `id-check`。
|
||||
`id-check` 要养 99 族语料(`id_registry.json` 87.6 KB + `id_aliases.json` 187 KB):单次运行只有
|
||||
**1.8 s**,贵的是"每笔提交都要维持语料自洽"——近 80 笔提交里 **61 笔**动了语料 / 门禁 / 规范。
|
||||
而它真正有用的那一小块(拦住"新写一个自造编号")根本不需要语料:只要知道"这个前缀我从没见过"。
|
||||
所以 2026-10-28 的分工是:`id-check` 管存量一致性(当日退役),`id-check-new` 管增量不许新增。
|
||||
|
||||
## 3. 触发面
|
||||
落地前测过噪声:拿最近 **80 笔真实提交**回放,未知形态只有 15 种,其中 12 种是设备 / 协议名
|
||||
(已进白名单)、3 种是已停发族(只告警)→ 白名单调好后**回放 0 误报**。
|
||||
|
||||
- `files:` = 任意 `md` / `c` / `h` / `py` / `yaml` / `txt` 或本配置文件本身;`pass_filenames: false`
|
||||
(脚本自己读 `git diff`,不靠钩子传文件名)。
|
||||
- 只读**新增行**:删行、改行里的旧编号不查(那是存量,归 `id-check`;退役后不再有人管,
|
||||
但这正是用户裁定接受的代价)。
|
||||
- 默认查**暂存区**(`git diff --cached`)。手工自查:`--worktree`(未暂存改动)/ `--range A..B`(一段提交)。
|
||||
- 排除面与旧门禁对齐:第三方库、HAL/CMSIS、`docs/芯片手册/`、`docs/硬件平台/`、`docs/images/`、
|
||||
`simulator/tests/ref/`、`ci-artifacts/`、`.dsh/skills/`、`scripts/rename_maps/`、
|
||||
以及二进制/生成物后缀(`.svg` `.png` `.bin` `.map` `.json` 等)。
|
||||
## 3. 退役的理由(这一节是本文的重点)
|
||||
|
||||
## 4. 报错怎么读
|
||||
1. **它咬的是形态,不是语义**:白名单是"形态"级不是"号"级——前缀合法则 `TIM3` 放行、`TIM99` 同样
|
||||
放行;同形多义(历史上 `S3` 三义那类撞车)它照不出来。这与旧门禁 `id-check.md` §6 记的盲区同源,
|
||||
只是范围缩到新增行。
|
||||
2. **白名单就是它的维护面**:每遇到一类合法字面量(新型器件、协议名、固件生成的产物文件名)就要加
|
||||
一条;不加就误拦,加了就把该前缀后头的所有数字永久放宽。2026-10-29 当天就撞过一次:文档里写
|
||||
录波段文件名 `WAVE00.BIN` 被拦,先改写成 `WAVE<NN>.BIN` 绕行、再登记 `WAVE` 前缀(`KNOWN_BARE`
|
||||
最后一次改动)。这类"合法新词撞形态门"是常态,不是意外。
|
||||
3. **默认形态早就是语义短语**(`docs/编号规范.md` §1 与 §3.3;登记簿新条目一律写语义短语,
|
||||
`docs/任务规划/README.md` §0),新造号在评审里本来就看得见,机器面的边际收益低于误拦成本。
|
||||
4. 与 2026-10-28 摘掉全库审计是**同一条判断的延续**:编号体系不再产生价值。留着这道门只让"要不要
|
||||
再登记一个前缀"变成反复出现的小额开销。
|
||||
5. 别往"轻量版"方向找补:改成只告警(退出码恒 0)等于把形态判断变成没人看的滚屏;转
|
||||
`stages: [manual]` 又因为它是 diff 型脚本、脱离提交时机基本扫不到东西。两条都是留着成本、
|
||||
去掉收益,所以整体退役。
|
||||
|
||||
```text
|
||||
[FAIL] 新增行里有 2 处**未登记形态**的字母+数字标识:
|
||||
docs/xxx.md:3 ZZ-9 [示例]
|
||||
→ 语义标识是默认形态:改写成短语(docs/编号规范.md §1);
|
||||
确属设备名/协议名/位号,就把前缀登记进 scripts/check_ids_new.py 的白名单。
|
||||
## 4. 退役后手工怎么用
|
||||
|
||||
```
|
||||
& '.venv\\Scripts\\python.exe' scripts/archive/id_gate/check_ids_new.py --self-test # 正反例自检(5 正例 / 29 反例)
|
||||
& '.venv\\Scripts\\python.exe' scripts/archive/id_gate/check_ids_new.py --range A..B # 复扫一段提交的新增行
|
||||
& '.venv\\Scripts\\python.exe' scripts/archive/id_gate/check_ids_new.py --worktree # 查未提交的改动
|
||||
```
|
||||
|
||||
三种处理:① 改成语义短语(默认);② 确实是设备名/协议名(如新的芯片型号)→ 把前缀加进
|
||||
`KNOWN_BARE` / `KNOWN_DASH`;③ 这一行必须保留字面(如冻结的现场日志)→ 行内写 `[编号豁免]`。
|
||||
⚠ `[示例]` / `[计划]` 行按既有冻结口径**整行跳过**,这也是本门禁的已知口子(§6)。
|
||||
⚠ 上面报错样例那行带 `[示例]`:两条门禁都认这个冻结标记、认不出「这段是文档举例」,
|
||||
所以**在文档里举反例必须带 `[示例]`**,否则举例自己就会被拦(这条就是被自己拦过一次之后补的)。
|
||||
退出码:0 = 通过 / 仅告警;1 = 有新增编号;2 = 环境错误(git 不可用、不在仓库内)。
|
||||
跑不跑都不影响提交。真正还用得上它的场合是**编号清退批次**:拿它当"形态普查"的尺子,比自己临时
|
||||
写正则省事(做法 → `.dsh/skills/id-family-semantic-migration/SKILL.md`)。
|
||||
|
||||
## 5. 好处
|
||||
## 5. 此后靠什么守着
|
||||
|
||||
- **零维护**:加一个设备型号是改一行白名单,不需要登记族、游标、属主文档、基线比例。
|
||||
- **判据窄**:只对"新增"负责,所以不必解释"为什么这个历史号还在"——那类争论在旧门禁里占了大半时间。
|
||||
- **自证成本低**:`--self-test` 内置 5 个正例 + 29 个反例(含 `TC-NET-204`、`TRAP-ADC-01`、
|
||||
`TPAFE5160`、`GD5F2GQ5UE`、`C12`、`SIZE-2`、`GPIO_PIN_5` 等),改脚本后一条命令验证没把牙弄掉。
|
||||
- **落地前测过噪声**:拿最近 80 笔真实提交回放,未知形态只有 15 种,其中 12 种是设备/协议名
|
||||
(已进白名单)、3 种是已停发族(只告警)→ 白名单调好后回放 **0 误报**。
|
||||
- `docs/编号规范.md` §1「默认答案:不发号」+ §4.1 存量族(穷举)+ §3.3 禁发范围——**新增族不再需要
|
||||
登记机器白名单**,那个"唯一口子"随门禁一起消失;答不出"哪个脚本要按字面量匹配它"就别建族。
|
||||
- 评审与销项纪律:`docs/任务规划/README.md` §0(已随销项消失的号永久作废、不得复用)。
|
||||
- ⚠ 要认下丢了什么:**"销项删行后号被重新取走"这类事故当初正是靠机械牙发现的**(2026-10-14 撞号
|
||||
事故 → 语义标识裁定)。此后提交期不再有这类警报,只剩规范与人工核。
|
||||
|
||||
## 6. 限制与盲区(这一节请当正文读)
|
||||
## 6. 改这个脚本本身要注意什么(历史留笔)
|
||||
|
||||
1. **单字母 + 数字一律放行**:元件位号(`C12`/`U15`/`R3`/`D7`)与层次号、裸形族号同形,
|
||||
机械区分不出来 → 新写一个单字母+数字的号**不会**被拦。这是本门禁最大的洞,与旧门禁的
|
||||
「裸形盲区」同源,属显式接受的代价。
|
||||
2. **只查新增行**:把旧编号从 A 行搬到 B 行、或整段重排,算"新增"→ 会拦(因为形态未登记);
|
||||
反之,只要形态在白名单里,新写的也放行——白名单是"形态"级,不是"号"级。
|
||||
3. **`[示例]`/`[计划]` 整行跳过**:想绕过本门禁,写个 `[示例]` 就行。这靠评审纪律,不靠机器。
|
||||
4. **未跟踪文件不在扫描面**(`git diff` 语义):手工在 `git add` 之前跑 `--worktree` 看不到新文件;
|
||||
提交时必已进暂存区,所以门禁场景不受影响。
|
||||
推论:**在 `pre-commit run --all-files`(`ci_local.py` 的静态门禁)下它是空转的**——
|
||||
那种跑法把文件当"全量"传进来,而本脚本只读暂存区 → 暂存区空 → 打印通过。
|
||||
它只在**真实提交**时才有牙;别拿静态门禁全绿当"没有新编号"的证明。
|
||||
5. **算术白名单是启发式**:`SIZE-2`/`LEN-1` 这类被排除;但若某处写着一个「不在白名单的前缀 +
|
||||
连字符 + 数字」,就会误报一次——把前缀加进白名单即可,不构成误拦风险。
|
||||
6. **不校验语义**:白名单里的前缀可以拿来写任何东西(`TIM3` 合法,`TIM99` 也放行)。
|
||||
它只回答"这是不是新造的前缀",不回答"这个号该不该存在"。
|
||||
|
||||
## 7. 豁免与白名单口径
|
||||
|
||||
| 类别 | 放行方式 | 维护动作 |
|
||||
|---|---|---|
|
||||
| 设备 / 芯片 / 模块型号(`TPAFE5160`、`CH395F`、`SD2506`、`GD5F2GQ5UE`) | `KNOWN_BARE` 前缀 | 新器件时加一条 |
|
||||
| 协议 / 标准(`IEC104`、`SHA-256`、`RS-485`、`UTF-8`) | `KNOWN_DASH` / `KNOWN_BARE` | 基本不增长 |
|
||||
| 遥信/遥控点号(`YX`/`YK`/`YT`/`YH`)与保护元件代号(`OC`/`UV`/`OV`/`CP`…) | `KNOWN_BARE` | 协议数据,不是标识符 |
|
||||
| 活族编号(`FR-*`、`TRAP-*`、`TC-*`、`CODE-RULE-*`、`MENU-STATE-*`) | `KNOWN_DASH` | 新增族要先在此登记 |
|
||||
| 已停发族(登记簿/专项/层次/原则等旧族) | `RETIRED_DASH` → **只 WARN** | 不拦提交,提示改语义短语 |
|
||||
| 一次性保留 | 行内 `[编号豁免]` | 提交说明里要交代原因 |
|
||||
|
||||
## 8. 改这个门禁本身要注意什么
|
||||
|
||||
- 改完必跑 `python scripts/check_ids_new.py --self-test`(正例漏拦 / 反例误拦都会红)。
|
||||
- 加白名单是**唯一**放宽手段;没有"整库豁免"入口,也没有 `--write` 现状洗白(与旧门禁同一条纪律)。
|
||||
- 改完必跑 `--self-test`(正例漏拦 / 反例误拦都会红);退役后这条纪律只对手工复查生效。
|
||||
- 别把白名单做成"按字面量枚举"的账本——那就退化成 `id_aliases.json` 的老路(187 KB 维护负担),
|
||||
前缀级枚举才是它便宜的原因。
|
||||
- 与 `id-check` 的关系变更(摘掉旧的)要同批改:本页、`docs/编号规范.md` §8.5、
|
||||
`docs/门禁说明/README.md` 的索引与计数、`AGENTS.md` 的钩子数。
|
||||
- 归档位置的 `REPO_ROOT` 与原位不同(深两级,取 `parents[3]`);再挪目录要一起改。
|
||||
|
||||
@@ -3,13 +3,15 @@
|
||||
> ⚠ **本文是退役留档,不要照着它去改门禁。**
|
||||
> 2026-10-28 用户裁定:编号体系本身不再产生价值,全库语料审计的维护成本高过收益
|
||||
> → 钩子摘除(52 → 51),脚本与两份语料整体移入 `scripts/archive/id_gate/`;
|
||||
> **现行编号门禁 = `id-check-new`**(只查新增行、零语料)→ `docs/门禁说明/id-check-new.md`。
|
||||
> **接班件 `id-check-new` 也已于 2026-10-29 退役**(只查新增行那道,用户裁定)→ `docs/门禁说明/id-check-new.md`。
|
||||
> 两道编号门禁自此全部退场:**编号形态没有机器面**,判据回到 `docs/编号规范.md` §1 三句自问 + §4.1
|
||||
> 族总表 + 人工评审;归档脚本 `scripts/archive/id_gate/check_ids_new.py` 可随时手工普查形态。
|
||||
> 退役路线与判据替换 → `docs/编号规范.md` §8.5。下面保留退役前的原样描述与实测基线,
|
||||
> 只在手工复查「存量编号现状」时还用得上。
|
||||
|
||||
> 一句话:它管**"号"这个东西不许野生**——每个编号必须属于一个已登记的族、形态合法、
|
||||
> 有定义处、有人引用、引用它的时候说清是哪篇文档的号。
|
||||
> 规范正文 = `docs/编号规范.md`(§1 先问三句、§4.1 允许用号的族〔穷举〕、§8 门禁与实测基线),本门禁是那八项的机械执行。
|
||||
> 规范正文 = `docs/编号规范.md`(§1 默认答案(一律停发)、§4.1 存量族〔穷举〕、§8 门禁与实测基线),本门禁是那八项的机械执行。
|
||||
|
||||
- 配置:`entry: python scripts/archive/id_gate/check_ids.py --strict`,`pass_filenames: false`,
|
||||
`files:` 覆盖 `.md/.c/.h/.py/.yaml/.json/.txt` 与配置文件本身。
|
||||
@@ -205,7 +207,7 @@
|
||||
要指代就写全号并紧邻属主文档名(写法口径见 `docs/文档规范.md` §3.5,判它的是校验 6)。
|
||||
3. ⚠ **反向错误更贵**:为了「少占余量」而把编号改写成语义短语/散文——那正是 §7.6 与这根护栏的动机要防的
|
||||
稀释(比值会被清号动作稀释,绝对数不会)。2026-10-27 凌晨 Lead 给三条道下过这样一条错指令,已撤回;
|
||||
正确口径是:按 `docs/编号规范.md` §1 先问三句,属允许族就用号,**需要新母号时由 Lead 改 `id_registry.json` 游标**。
|
||||
当时的口径是:按 `docs/编号规范.md` §1 先问三句,属允许族就用号(该判据 2026-10-29 作废,全族一律停发),**需要新母号时由 Lead 改 `id_registry.json` 游标**。
|
||||
|
||||
**每批自证没吃余量(可复制的做法,五项式)**:
|
||||
|
||||
@@ -236,8 +238,3 @@
|
||||
3. 更省事的正解是**写注释与文档时一开始就别用裸形**:改用语义短语,或写全号 + 紧邻属主文档名。同日还有一
|
||||
次反向教训:为「省余量」把在册族的号改成散文,那才是真把护栏当敌人(见 §7.7)。
|
||||
4. 附带收益常比余量值钱:这次顺带消掉一个**同形两义**的撞号源(同一裸形既像自造状态号又撞已登记族)。
|
||||
|
||||
|
||||
## 9. 变更记录
|
||||
|
||||
> (本文件不再记流水账:改了什么是正文说了算,改动过程查 git log。)
|
||||
|
||||
@@ -94,7 +94,3 @@
|
||||
|
||||
- 往 `ALLOW` 加条目要写理由,并想清楚会不会变成"给上层开后门";能进基线就别进 `ALLOW`。
|
||||
- 还掉一条债就跑 `--prune` 并删掉那一行;基线只减不增,加行等于放弃约束。
|
||||
|
||||
## 9. 变更记录
|
||||
|
||||
> (本文件不再记流水账:改了什么是正文说了算,改动过程查 git log。)
|
||||
|
||||
@@ -89,6 +89,15 @@
|
||||
但不会指出模板——那段链由 `generated-fresh` 保证「脚本与产物同一笔提交」。
|
||||
5. 编译器侧的真实警告仍以 `@build` 为准:本闸只拦「会让 ARMCC 报 9-D 的那一类」,
|
||||
编译日志里其他诊断一概不管。
|
||||
6. **仓库根探测必须兼容 linked worktree**:脚本原先用「`.git` 是不是目录」定位仓库根,而 `git worktree`
|
||||
出来的任务工作树里 `.git` 是**一个文件**(写着 `gitdir: …`)不是目录 → 本闸在任何任务树里恒
|
||||
退出码 2「仓库根定位失败」,**静默不可用**。这不是「放过了真问题」,是**根本没跑**——比放过更坏,
|
||||
因为调用方看到红字会以为环境有问题、看到跳过会以为干净。2026-10-29 已把该判据从 `isdir` 改成
|
||||
`exists`(`scripts/check_nested_comment.py:342`,修复归当日提交)。全仓 `scripts/` 只有它这么探根,
|
||||
其余只读闸在任务树里一直正常。**后果要说清楚**:门禁修好之前那批录波改动没被它扫过,lead 手工对
|
||||
改动面逐文件扫了一遍、嵌套命中 0,所以没有放过真问题——但那是**人工兜底,不是门禁功劳**。
|
||||
通用教训:**门禁脚本按 `isdir(.git)` 探根 = 在 worktree 里自杀**;新增只读闸要么走
|
||||
`git rev-parse --show-toplevel`,要么同时接受 `.git` 的文件形态。
|
||||
|
||||
## 7. 豁免与基线(只减不增)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# `ui-golden` — UI 像素回归(菜单 8 状态 + 内容页 60 张黄金参考)
|
||||
# `ui-golden` — UI 像素回归(菜单 8 状态 + 内容页 66 张黄金参考)
|
||||
|
||||
> 一句话:改 UI 源码时,把模拟器增量重编 + 两条 golden 回归串成一次提交门禁,**像素对不上就拦**。
|
||||
> 它是包装器:真正的判据在被包装的两条脚本与参考图里。
|
||||
@@ -11,7 +11,7 @@
|
||||
## 1. 它在查什么
|
||||
|
||||
- 菜单侧:整棵菜单树的行渲染结果(8 个状态)与参考图逐像素比对;
|
||||
- 内容页侧:60 张黄金参考(= 60 个截图态条目,同一内容页的多个状态各一张,其中 2 张是分页页多拍的第 2 屏),逐张与参考图比对;
|
||||
- 内容页侧:66 张黄金参考(= 66 个截图态条目,同一内容页的多个状态各一张:分页页多拍的第 2 屏与确认链/录波的各态都单独计条目),逐张与参考图比对;
|
||||
- 参考图 `simulator/tests/ref/*.bin` **就是判据本身**。
|
||||
|
||||
## 2. 为什么要它(有牙的实测)
|
||||
@@ -57,7 +57,7 @@
|
||||
|
||||
1. **参考图即判据**:刷新参考图 = 修改判据。评审时必须盯 `simulator/tests/ref/` 的 diff;
|
||||
一旦"顺手更新",此后所有回归都只在和错的基线比。**门禁无法阻止这件事**,只能靠评审。
|
||||
2. 只覆盖 8 个菜单状态 + 60 张内容页黄金参考:未列入的状态(密码错误态、超长文本、缺字渲染、
|
||||
2. 只覆盖 8 个菜单状态 + 66 张内容页黄金参考:未列入的状态(密码错误态、超长文本、缺字渲染、
|
||||
无 SD 卡 / 挂载失败的降级显示)**不会有任何回归**。
|
||||
3. 跑的是**模拟器那份配置**,不是固件那份 —— 两份 `lv_conf.h` 漂移时,回归结论不能外推到固件
|
||||
(所以 `lv-conf-sync` 是本门有效性的前提)。
|
||||
@@ -76,7 +76,3 @@
|
||||
|
||||
- 加新页面 / 新状态时,要同时扩参考图集合,否则新页面**完全没有回归**(不会报错,只是没覆盖);
|
||||
- 触发面 `files:` 每加一类能改像素的入口就补一行,漏一类 = 那一类改动静默不跑回归。
|
||||
|
||||
## 9. 变更记录
|
||||
|
||||
> (本文件不再记流水账:改了什么是正文说了算,改动过程查 git log。)
|
||||
|
||||
@@ -4,7 +4,7 @@ ADC1 采样链路(TIM3 1 kHz 节拍 → ADC1 九通道扫描 → DMA2_Stream4
|
||||
语义映射)的实证陷阱:现象、判读陷阱、定案根因、修复与回归判据。**动 ADC 采样、通道映射或
|
||||
诊断代码之前先读本文。**
|
||||
|
||||
> 编号口径:按 `docs/编号规范.md` 采用 `TRAP-ADC-<nn>`,本域自 01 起连续。编号不复用、不重排。
|
||||
> 编号口径:本域既有条目按 `TRAP-ADC-<nn>` 自 01 起连续编号,**只读引用**;2026-10-29 起**不再新增 TRAP 号**(`docs/编号规范.md` §4.1 一律停发),新踩坑在本文写语义行名。编号不复用、不重排。
|
||||
> 状态图例:✅ 已修复定案 · ⏳ 待修。
|
||||
> 设计侧口径(采样节拍、寄存器配置、铁律)不在本文,见
|
||||
> `docs/子系统设计/ADC采样节拍设计说明.md`;本文只记「踩过的坑」与「怎么判断踩到了」。
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
CH395F 以太网驱动与 NET 层的实证陷阱:现象、定案根因、修复、回归判据。改驱动/NET 层前先读本文。
|
||||
|
||||
> 编号口径:按 `docs/编号规范.md` 采用 `TRAP-NET-<nn>`,连续 01~21。编号沿革(2026-10-13 全库重排):
|
||||
> 编号口径:本域既有条目 `TRAP-NET-<nn>` 连续 01~21,**只读引用**;2026-10-29 起**不再新增 TRAP 号**(`docs/编号规范.md` §4.1 一律停发),新踩坑在本文写语义行名。编号沿革(2026-10-13 全库重排):
|
||||
> 旧 01~11 不变;旧 14→12、15→13、16→14、17→12(并入)、18→15、20→16、22→17、23→18、24→19、
|
||||
> 25→20、26→21;旧 12/13/19/21 已移出/并入/删除,无条目。旧形 `Trap NN` 为违规裸形已全库迁移;
|
||||
> 旧号只存在于历史提交与旧日志。编号不复用、不重排。
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
| 链 | 现状 | 缺什么 |
|
||||
|---|---|---|
|
||||
| **测量链(遥测)** | 104 每 100 ms 直接读相量瞬时值 | 工程量折算、谐波方和根、平均/死区/零漂、品质位 |
|
||||
| **记录链(录波)** | 只有 64 B 定长 SOE 文本记录 | 波形数据面(**2026-10-29 已按 1 kHz 立项**,docs/任务规划/故障录波.md)、COMTRADE 文件、104 文件服务 |
|
||||
| **记录链(录波)** | SOE 文本记录(64 B 定长)**加上**录波段文件:1 kHz / 8 路原始码值 / 单段 320 点、`/wave` 下轮转、PC 侧读段脚本与现场单通道回放页——**代码面 2026-10-29 已交付,板级判据一轮未跑**(docs/任务规划/故障录波.md) | COMTRADE 文件、104 文件服务;以及 4 kHz 全速与 80 点/周波——本波按 1 kHz 起步,该偏离已按 docs/子系统设计/故障录波设计说明.md §2 显式登记,**不是已补齐** |
|
||||
| **就地闭环(开入开出)** | 固件完全没有 | 开入量采集与防抖、遥信变位、遥控出口、跳闸出口 |
|
||||
|
||||
**四个阻断级短板**(不补则送检必挂):
|
||||
@@ -24,7 +24,7 @@
|
||||
1. **工程量折算缺失**——遥测上送的是 ADC 原始码值(数千~数万),点表要求"短浮点、系数 = 1"的工程量;保护定值(A/V)也在跟码值比较,量纲不成立。
|
||||
2. **遥测链缺失**——没有 200 ms 测量轨:无谐波方和根、无 4 点平均、无死区确认、无零漂、无畸变率;死区做在 104 层(架构错位)。
|
||||
3. **运行参数段 0x8020~0x8058 缺失**——死区、变比、零漂门槛、三级负荷报警、录波投退与定值,主站读写全部回"未知地址"。
|
||||
4. **录波与 104 文件传输缺失**——点表明确要求"录波文件存储 ≤ 15 s""104 读文件目录/文件 ≤ 30 s"。
|
||||
4. **录波已按 1 kHz 口径落地(2026-10-29 代码面),104 文件传输仍缺**——点表明确要求"录波文件存储 ≤ 15 s"(该时限未测,见 §4.4)与"104 读文件目录/文件 ≤ 30 s"(未做)。
|
||||
|
||||
**建议顺序**:先做"数据可信"(1 + 2 + 3 + 频率点,纯软件、可主机单测),再做"精度与安全网"(等周波 + 削顶检测 + 派生量),最后单独立项"录波与文件"(最大单块)。开入开出与功率/电度需硬件与产品先拍板,软件先建接口不使能。
|
||||
|
||||
@@ -36,12 +36,12 @@
|
||||
|
||||
| 环节 | 参考实现 | 本项目 | 差距 |
|
||||
|---|---|---|---|
|
||||
| **采样节拍** | 内总线 4 kHz(80 点/周波),保护取 1/4 → 1 kHz;交流板本地插值对齐 | TIM3 1 kHz 单节拍,无过采样通路 | 录波无数据源;等周波未闭环 |
|
||||
| **采样节拍** | 内总线 4 kHz(80 点/周波),保护取 1/4 → 1 kHz;交流板本地插值对齐 | TIM3 1 kHz 单节拍,无过采样通路 | 录波已有 1 kHz 数据源(2026-10-29 交付代码面,见 docs/子系统设计/故障录波设计说明.md §2),**但仍无 4 kHz 过采样通路**;等周波未闭环 |
|
||||
| **预处理** | 码值 × 每通道系数(定点 2^10)→ 浮点工程量;自产零序 `3I0=Ia+Ib+Ic`;插值异常闭锁 | 码值直通(系数 = 1),无标定、无自产零序 | **量纲缺失**;零序只能靠外部通道 |
|
||||
| **保护相量** | 全周傅氏 15 基波 + 3 二次 + 1 五次,每 1 ms 重算 | 5 实例(IA/UA/UN 基波 + IA 二/五次),每 1 ms 重算 | 实例数按 V0.1 有效通道裁剪(合理),但**无派生量层** |
|
||||
| **测量遥测** | 15 通道 × k=1~9 DFT → 方和根 → 4 点平均 → 死区 2 点确认 → 零漂置零 → 微调 TLV10 → 变比;22 交流 + 2 直流 + 7 功率 | 无遥测链;104 直读相量瞬时值 | **整链缺失** |
|
||||
| **派生量** | 线电压 / 负序 / 正序 / 零序 / 差分 / 直流 / 同期量(`Calf*Vec` 系列 + `CalfAnaDC/Dif`) | 无 | 整层缺失 |
|
||||
| **录波** | 80 点/周波 × 8 周波,突变量启动,COMTRADE 输出(`Wave.c` + `WaveComtrade.c` 共 7 582 行) | 无 | **整链缺失** |
|
||||
| **录波** | 80 点/周波 × 8 周波,突变量启动,COMTRADE 输出(`Wave.c` + `WaveComtrade.c` 共 7 582 行) | 1 kHz × 8 路原始码值单段(2026-10-29 代码面交付,含段文件与 PC 侧读段工具)| 部分补齐:口径偏离(无过采样、无突变量启动、无 COMTRADE),见 docs/子系统设计/故障录波设计说明.md §2 与 §13 |
|
||||
| **记录** | SOE / COS / 跳闸 / 遥测 / 冻结 / 异常(`RecUnit` + `HistoryFile`) | SOE + 动作记录(B9) | 缺 COS/遥测/冻结/异常 |
|
||||
| **上送** | 101/103/104/61850/ModBus,含文件服务与电度 | 104 子集:M_SP/M_DP/M_SP_TB/M_ME_NC/C_SE/C_RD/C_IC/C_CS | 无文件服务、无电度、无定值区 |
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
|
||||
### 3.3 完全空白
|
||||
|
||||
遥测链 · 派生量(线/序/差分/直流) · 录波与 COMTRADE · 104 文件服务 · 开入量采集 · 遥控出口 · 跳闸出口 · 功率与电度 · 同期 · 小电流选线 · 运行参数段 · 标定 · 等周波 · 削顶检测。
|
||||
遥测链 · 派生量(线/序/差分/直流) · COMTRADE 与 104 文件服务(录波本身已于 2026-10-29 落地 1 kHz 口径)· 开入量采集 · 遥控出口 · 跳闸出口 · 功率与电度 · 同期 · 小电流选线 · 运行参数段 · 标定 · 等周波 · 削顶检测。
|
||||
|
||||
---
|
||||
|
||||
@@ -161,11 +161,11 @@
|
||||
- 地址、类型、默认值以参考表为准逐项对照,**不要凭想象填**。
|
||||
- 规模:**M**(表驱动,机械但量大;104 侧 `set_read/set_write` 已是通用接口,不用改协议)。
|
||||
|
||||
### 4.4 录波与 104 文件传输缺失
|
||||
### 4.4 录波已按 1 kHz 口径落地,COMTRADE 与 104 文件传输仍缺失
|
||||
|
||||
**现状与证据**
|
||||
|
||||
- 全库无录波、无 COMTRADE(关键词扫描零命中)。
|
||||
- 录波已于 2026-10-29 落地(1 kHz / 8 路 / 段文件:`App/algo/wave_ring.c` 与 `App/algo/wave_store.c`);**COMTRADE 与 104 文件传输仍零命中**(本波不做,见 docs/子系统设计/故障录波设计说明.md §13)。本节原写「全库无录波(关键词扫描零命中)」是落地前的现状句,下面几条里 4 kHz 过采样与文件面的差距仍然成立。
|
||||
- 104 只实现 8 种 ASDU,**无文件传输类型**(120~122 及读文件目录扩展),无定值区类型。
|
||||
- 采样通路只有 1 kHz 一条,没有 4 倍过采样。
|
||||
|
||||
@@ -333,7 +333,7 @@
|
||||
| 等周波 | 同 §3.1 的「等周波采样(软件测频 + 调频闭环)」(⬜) | 补三条实施约束(ARR 联动、开环先行、过渡处理) |
|
||||
| 遥测链 | 复现规划 §3.2(「遥测谐波轨(可选)」,标"可选") | **建议从"可选"升为"必做"**——它是遥测、电度、越限、畸变率的共同底座 |
|
||||
| 派生量 | 复现规划 §3.2(「线/负序/零序合成」,V0.1 不适用) | 建议代码与单测先就绪,V0.2 只改映射 |
|
||||
| 录波 | 复现规划 §3.4(「故障录波(可选)」,⬜) | 补"104 文件服务"这一半(原登记只写录波) |
|
||||
| 录波 | 复现规划 §3.4(「故障录波(可选)」,⬜;2026-10-29 已按 1 kHz 落地代码面,4 kHz 与 COMTRADE 仍 ⬜)| 补"104 文件服务"这一半(原登记只写录波)|
|
||||
| 运行参数段 | 未登记 | **新发现**,建议按语义标识登记("运行参数段 0x8020~0x8058") |
|
||||
| 开入开出 | 未登记 | **新发现**,建议登记("开入量采集与遥信"、"遥控与出口") |
|
||||
| 削顶检测 | 复现规划 §3.5(「采样通道自检」残余,"码值越界待做") | 给出两条具体判据 |
|
||||
|
||||
Reference in New Issue
Block a user