chore(编号): 存量编号全量转语义短语,门禁识别面与语料同批重打
登记簿、文档与代码注释里的存量字母加数字编号(N-x / S-x / T-x / E-x / A-x / 卡号) 一律改写为语义短语,净删 2,028 处引用;删除基线与待确认、并行分道方案、排期详述、 采集保护收尾 4 篇(内容已并入 docs/任务规划/README 与登记簿)。 门禁机器与三张账同批重打:check_ids.py 新增变更记录行豁免与第二根护栏 undecidable_total_ceiling;check_test_traceability.py 只加 stdout/stderr UTF-8 reconfigure(TC_RE 未动);check_cubemx_survival.py 的 --write 固定 newline=LF; id_registry / id_aliases(+19 条 retired-to-phrase)/ id_known_backlog 重打。 test/ 56 个文件同步 TC 标签语义化,其中 18 个 TU 改了 CHECK / printf 里的标签文字, 是本批唯一改变构建产物的文件集合。 为什么合成一笔、不拆四笔(实测撞闸,非偏好):pre-commit 跑钩子前会 stash 未 staged 部分,拆开后中间提交必然是「新规则 + 旧语料」——实跑可判定 85.15% < 基线 86.00%、 不可判定 1,453 > 上限 1,166,编号门禁直接拦下。编号识别面与它描述的语料只能同码移动。 实跑基线(工作区全量):754 文件 / 8,230 处编号字面量 / 可判定 7,079 = 86.01% (基线 86.0%,容差 0.1pp)/ 不可判定绝对数 1,151(上限 1,166)/ 校验 1-6 错误级 0 / 告警 = 悬空 2(App/algo/freq.c 的 S2,属 §4.4 同号不同义)+ 孤儿 50。 基线从 84.0 抬到 86.0 的理由见 docs/门禁说明/id-check.md §7.6:本批真删了 2,028 处 引用,可判定面随真实内容上升,不是把分母做小。同批新增排除 docs/硬件平台/ 语料,使 识别面少 264 处——芯片手册位号与网表料号不属编号空间(registry 有 excluded_paths_note)。 ⚠ 余量只剩 0.11pp(约 10 处)与绝对数 15 处:把「可判定的引用」改成散文会立刻撞第二 根护栏。另遗留一项:id_aliases 里 retired 的 N / S / T / A 别名没有 scope(U1~U5 有), 今后有人新写一个 A-4,校验 3 不会响,只能靠人,建议下批补 scope。 固件不变证据:115 个 .c/.h 剥注释并归一字符串后与 HEAD 逐字节全等,残留代码差异 0; App / Src / Drivers 的字符串字面量零改动。@build 0 错误 0 警告;40/40 主机套件、2,889 断言全通过;覆盖率 line 89.2% / func 92.6%;pre-commit 48 钩子 --all-files 全绿; check_doc_links --all 通过(176 文档,章节引用无法判定 0);逐字节卫生核过:14 个带 BOM 文件与 HEAD 一致、0 个 CR、0 个 U+FFFD,字符串字面量纯 ASCII。 .cubemx_survival_baseline.json 的 watchdog-module 哈希 56bf27 变 2bb051 属合法: Src/freertos.c 的 USER CODE 区内只有注释文字随编号改写,代码未变。 同批带上体积同码凭证与 RAM 台账行(@build 之后盖戳):RW_IRAM1 79,008 B / 60.3%, RW_CCM 57,376 B / 87.9%,阈值 92%。
This commit is contained in:
+1
-1
@@ -23,7 +23,7 @@
|
||||
| 想干什么 | 去看 |
|
||||
|---|---|
|
||||
| 先搞清 CI 需要哪三样东西就位、本机拓扑、部署前置清单 | §0 / §0.1 / §0.2 |
|
||||
| **CI 体积门禁现在怎么守**(同码凭证强制,S14 盲区已关闭;gitlint 空转仍在) | §0.0 + §7 排障表"钩子条数对不上"行 |
|
||||
| **CI 体积门禁现在怎么守**(同码凭证强制,「只声明不执行」那处盲区已关闭;gitlint 空转仍在) | §0.0 + §7 排障表"钩子条数对不上"行 |
|
||||
| 服务端开启 Actions、`DEFAULT_ACTIONS_URL` 到底管什么 | §1(含 §1.2.1,**这条最容易搞反**) |
|
||||
| 下载 / 注册 runner(`--instance` 用回环、labels 必须精确匹配 `runs-on`) | §2.2 |
|
||||
| `config.yaml` 各字段语义(capacity / timeout / labels / 日志目录…) | §2.3 |
|
||||
|
||||
+5
-5
@@ -36,9 +36,9 @@
|
||||
|
||||
---
|
||||
|
||||
## 0.0 ⚠️ CI 体积门禁:从盲区到同码凭证强制(必读,S14 → A-5 残余已销项)
|
||||
## 0.0 ⚠️ CI 体积门禁:从盲区到同码凭证强制(必读,「体积门禁 CI 强制路径」残余已销项)
|
||||
|
||||
> **曾经的盲区已关闭为强制路径(2026-10-25,A-5 残余销项,`task/A5-size-gate`→564715c)。**
|
||||
> **曾经的盲区已关闭为强制路径(2026-10-25,「体积门禁 CI 强制路径」残余销项,`task/A5-size-gate`→564715c)。**
|
||||
> `mem-numbers` 钩子的事实源是 Keil 构建产物 `MDK-ARM/**/*.map`(已 gitignore),CI 刻意不跑
|
||||
> `@build` → 该钩子在远端只会被跳过(现以 `SKIP` 名单诚实显示 Skipped,不再伪装 Passed)。
|
||||
> 补上的强制路径 = **同码凭证**:本地 `@build` 0/0 后 `ram_baseline.py --update` 顺手盖
|
||||
@@ -797,7 +797,7 @@ Get-ChildItem 'C:\ProgramData\anaconda3\Lib\site-packages' -Filter 'cfgv*'
|
||||
|
||||
#### 4.1.2 ⚠️ 关键坑:`doc-links` 钩子「本地过、CI 挂」= 引用了 gitignore 的运行时文件
|
||||
|
||||
**现象**:`文档链接存在性 (D-3/D-7)` 钩子在**本地** `pre-commit run --all-files` 通过,
|
||||
**现象**:`文档链接存在性` 钩子在**本地** `pre-commit run --all-files` 通过,
|
||||
一上 CI 就 `Failed`(exit 1),报的行/路径你在本地明明存在。
|
||||
|
||||
**根因**:CI 的 `actions/checkout@v4` 拉的是**干净克隆**,而钩子校验的是
|
||||
@@ -955,7 +955,7 @@ github.com 会在 checkout 步骤卡住/失败。三种处置:
|
||||
|
||||
**建议**:**先按原样试一次**。若 checkout 步骤报网络错误,再换成上面的零依赖写法(方案 3)。
|
||||
|
||||
### 5.4 产物存档与结果汇总(S3,2026-10-02)
|
||||
### 5.4 产物存档与结果汇总(2026-10-02 起)
|
||||
|
||||
**目标**:CI 失败时**不查 MySQL / 不翻 runner 磁盘**,在 Gitea 页面即可看到完整输出与摘要。
|
||||
|
||||
@@ -1210,7 +1210,7 @@ runner 的日志走 **stderr**,于是上面两个日志文件都栽在这两
|
||||
`commit-msg` stage 的钩子(gitlint)不在其中,靠 `ci_gitlint_range.ps1` 单独守(见 §7);
|
||||
- **`@build` / L1 / L2**:永远留在本地,不要往 CI 加(需 Keil 授权与真机);
|
||||
- **runner 长时间不可用**时:CI 只是"多一道网",**提交前的本地 `ci_local.py` 仍是 L0 的唯一保障**,
|
||||
不能因"已经配了 CI"放宽(见 [docs/任务规划/登记簿.md](../任务规划/登记簿.md) 的 T-7「CI 远端闭环未验证(runner 本机已就绪)」条)。
|
||||
不能因"已经配了 CI"放宽(见 [docs/任务规划/登记簿.md](../任务规划/登记簿.md) 的条目「CI 远端闭环未验证」)。
|
||||
|
||||
---
|
||||
|
||||
|
||||
+15
-15
@@ -11,7 +11,7 @@
|
||||
```
|
||||
docs/
|
||||
├── README.md 本索引(阅读顺序 + 全量清单)
|
||||
├── 任务规划/ 统一待办登记簿(README 排序权威 + 8 个拆分文件)
|
||||
├── 任务规划/ 统一待办(README 单一入口 + 5 个职责文件)
|
||||
├── 产品需求/ 产品需求设计文档(面向产品的需求基线)
|
||||
├── 架构设计/ 全局架构与设计方法论
|
||||
├── 子系统设计/ 各功能子系统的设计说明
|
||||
@@ -31,7 +31,7 @@ docs/
|
||||
```
|
||||
|
||||
> ⚠️ `docs/芯片手册/`(约 120 MB / 1754 张图)为**只读外部输入资料**,与代码演进无关;
|
||||
> 后续按原报告 D-1 建议拆分独立仓库或降采样(登记簿 **N-29**,已决策暂不处理)。
|
||||
> 后续拆分独立仓库或降采样(登记簿条目「仓库体积膨胀观察」,已决策暂不处理)。
|
||||
|
||||
---
|
||||
|
||||
@@ -89,7 +89,7 @@ docs/
|
||||
| [`系统墙钟时间维护说明.md`](子系统设计/系统墙钟时间维护说明.md) | `sys_clock`:RTC 基准、tick 回绕防护、30 天惰性再基准化 |
|
||||
| [`控制台单写者日志设计说明.md`](子系统设计/控制台单写者日志设计说明.md) | 控制台日志单写者模型(避免多任务交错输出) |
|
||||
| [`运行与自检记录设计说明.md`](子系统设计/运行与自检记录设计说明.md) | `/log/run.log`·`selftest.log` 定长记录与待机显示 |
|
||||
| [`看门狗设计说明.md`](子系统设计/看门狗设计说明.md) | IWDG(CubeMX 配置)+ 任务心跳位图:选型与超时推导、掩码与埋点、取证机制、验证记录;已台架闭环(V2/V4/V5)。**§11 = 任务级饥饿的诊断方法与 `[PROF]` 实测基线**(Task #32 沉淀:判读口径、量化归因、三条脆弱点、明确不做的四条) |
|
||||
| [`看门狗设计说明.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 硬约束、事件驱动消费与就绪门、实现落点、观测计数、性能特征与设计边界 |
|
||||
| [`IEC104上行设计说明.md`](子系统设计/IEC104上行设计说明.md) | **B4 上行规约**:IEC 60870-5-104 被控站(TCP 2404)范围/点表(V0.1 有效子集)/链路流程(k/w/t1~t3、总召、COV、遥控两段式、定值)/netTask 接入决策/预算与测试方案;协议核心纯逻辑 + L0.5 全栈单测 |
|
||||
| [`网络/BSD_Socket_API_使用指南.md`](网络/BSD_Socket_API_使用指南.md) | **上层视图**:BSD Socket API 公开语义、示例、常见问题 |
|
||||
@@ -105,7 +105,7 @@ docs/
|
||||
|---|---|
|
||||
| [`傅氏算法详解.md`](算法/傅氏算法详解.md) | 全周波傅氏(单频 DFT)原理与工程实现:正交性、梳状带通、滑动窗、系数表折算有效值;保护/遥测双轨有效值的算法基础 |
|
||||
| [`采集与算法层设计说明.md`](算法/采集与算法层设计说明.md) | **`App/algo/` 的现状设计说明**:L1 语义取数与有效性判定、L2 采样环/相量/测频、L3 定值模型与元件框架的契约、关键机制(双区原子切换、乒乓半区、自适应测频窗、定值封存-自检-闭锁)、精度判据 J1~J6 与资源足迹 |
|
||||
| [`继电保护功能复现规划.md`](算法/继电保护功能复现规划.md) | **保护功能复现规划**:把参考系统(CLS100)保护链路映射到本项目(STM32F4)的分层功能/性能/参数清单、平台适配(N-18 等)与分阶段路线图 |
|
||||
| [`继电保护功能复现规划.md`](算法/继电保护功能复现规划.md) | **保护功能复现规划**:把参考系统(CLS100)保护链路映射到本项目(STM32F4)的分层功能/性能/参数清单、平台适配(「双转换器无共同采样触发」等)与分阶段路线图 |
|
||||
| [`采样有效性校验设计说明.md`](算法/采样有效性校验设计说明.md) | **`App/algo/adc_health.c` 单文件深设计**:四类判据(静默 / 丢帧 / 序号倒退 / 错误计数增量)的判据推导与 100 ms 门限依据、电平-锁存-事件三种位语义与位号对齐、闭锁与看门狗兜底的责任划分、观测盲区、主机侧验证分工与现场判读手册(含三张配图生成器) |
|
||||
|
||||
---
|
||||
@@ -133,7 +133,7 @@ docs/
|
||||
| [`ADC输入层单元测试说明.md`](测试说明/ADC输入层单元测试说明.md) | adc_input 语义通道映射 / ADC1 顺序扫描(**Rank↔通道判据**)/ poll 契约 / HAL 故障路径,70 用例 |
|
||||
| [`相量层单元测试说明.md`](测试说明/相量层单元测试说明.md) | phasor 全周傅氏系数表 / 幅值·相位 / 谐波抑制与提取 / 频偏 / 采样环 / 双区交换,57 用例 |
|
||||
| [`卷锁单元测试说明.md`](测试说明/卷锁单元测试说明.md) | vol_lock 创建 / 获取 / 释放契约(**fail-open 不变量**:创建失败仍返回 1 且零阻塞)/ 幂等 / 超时透传,33 断言点 |
|
||||
| [`时间同步单元测试说明.md`](测试说明/时间同步单元测试说明.md) | time_sync 分片喂狗延时 / 监听退避 / 时间包重组 / 任务主循环(**N-17 的全部逻辑贡献者**),80 断言点 |
|
||||
| [`时间同步单元测试说明.md`](测试说明/时间同步单元测试说明.md) | time_sync 分片喂狗延时 / 监听退避 / 时间包重组 / 任务主循环(探针窗口心跳缺口的全部逻辑贡献者),80 断言点 |
|
||||
| [`主机单测覆盖率口径.md`](测试说明/主机单测覆盖率口径.md) | **跨全部 16 套 L0.5 的覆盖率**:`scripts/check_test_coverage.py` 用法 / 统计面与生成物例外 / 基线增量门禁(只拦回退)/ **为什么本机拿不到分支覆盖** / 九条限制与盲区 / 未挂 pre-commit 的三条理由与待粘 YAML |
|
||||
|
||||
**模块测试指南**(动手写测试前先读)
|
||||
@@ -183,7 +183,7 @@ docs/
|
||||
| [`RAM使用分析与优化方案.md`](内存管理/RAM使用分析与优化方案.md) | **内存主文档**:占用分析、优化方案、定栈规则 |
|
||||
| [`内存内容分配策略.md`](内存管理/内存内容分配策略.md) | 各内存区(SRAM/CCM)的分配策略 |
|
||||
| [`存储栈RAM优化调研.md`](内存管理/存储栈RAM优化调研.md) | 存储栈 RAM 优化调研与结论 |
|
||||
| [`RAM预算台账.md`](内存管理/RAM预算台账.md) | **预算台账**:子系统配额、CCM 分配、趋势基线与 92% 门禁(N-27 三件套,2026-10-12) |
|
||||
| [`RAM预算台账.md`](内存管理/RAM预算台账.md) | **预算台账**:子系统配额、CCM 分配、趋势基线与 92% 门禁(登记簿条目「缩堆迁 CCM 后半(暂缓)」,2026-10-12) |
|
||||
| `data/` | `ram_report_*.md` / `stack_report_*.md` 快照数据(由 `scripts/` 生成) |
|
||||
|
||||
### 7.3 问题记录(**改驱动前必读**)
|
||||
@@ -225,7 +225,7 @@ docs/
|
||||
> 未闭环项 → [`任务规划/登记簿.md`](任务规划/登记簿.md);内存与 Flash 结论(含整簇暂缓的**重开条件**)
|
||||
> → [`内存管理/RAM使用分析与优化方案.md`](内存管理/RAM使用分析与优化方案.md) §2.5 / §2.6.4 / §4;
|
||||
> UI 侧硬约束 → [`UI设计/UI_设计架构.md`](UI设计/UI_设计架构.md) §1.4;
|
||||
> 六个自有编号族 → [`编号规范.md`](编号规范.md) §4.3(属主文档已删,存量冻结)。
|
||||
> 六个自有编号族 → [`编号规范.md`](编号规范.md) §4.5(属主文档已删,只能删号留事实,别再引用那些号)。
|
||||
### 9.2 环境与部署
|
||||
|
||||
| 文档 | 内容 |
|
||||
@@ -238,7 +238,7 @@ docs/
|
||||
|
||||
| 位置 | 内容 |
|
||||
|---|---|
|
||||
| [`任务规划/`](任务规划/README.md) | **统一待办登记簿(文件夹)**——`README.md` = 排序权威(推进顺序 + 波次语义名)+ 编号空间 + 维护约定;`UI补齐.md` = **当前波次**(21 叶补齐,7 张卡);`数据可信.md` = 收口态(软件侧已 100%,剩 3 张台架/外部卡);`采集保护收尾.md` = 「采集保护收尾」剩余(只剩 M3 送检);`登记簿.md` = N/S/T-x 长期观察;`排期详述.md` / `暂缓-RS485.md` / `测试与架构专项.md` = 波内详表 / 冻结簇 / 专项;`基线与待确认.md` = 待确认(开放问题,OQ 族属主);**`并行分道方案.md` = 待办横向归道(写域 域1~域8 + 道E~道H + 批次 + 合并次序)**;只保留未闭环项,完成即删 |
|
||||
| [`任务规划/`](任务规划/README.md) | **统一待办入口(6 个文件)**:`README.md` = 现在做什么与全项目顺序;`UI补齐.md` = 当前唯一执行清单;`登记簿.md` = 后续任务、外部窗口与长期观察;`数据可信.md` = 三项阻塞任务及代码引用的设计约束;`暂缓-RS485.md` 与 `测试与架构专项.md` = 两个专项。完成即删,重复内容只保留一个归属 |
|
||||
| `硬件平台/` | 网表详细分析报告与语义图(V0.0 / V0.1);**[`ADC通道映射说明.md`](硬件平台/ADC通道映射说明.md)——V0.1 十七路 ADC 语义/网名/通道号权威映射表(固件取数、UI 显示、自检注入以此为准)** |
|
||||
| `芯片手册/` | 外部芯片数据手册转录(CH395F / GD5F2GQ5UE / SD2506 / TPAFE5160 / RTL8305NBI 等) |
|
||||
| `images/` | 文档技术配图(`.svg` 产物,由 `tools/arch_diagram/`、`tools/refgraph/` 生成) |
|
||||
@@ -254,26 +254,26 @@ docs/
|
||||
5. **配图**:走 [`架构设计/图形绘制流程.md`](架构设计/图形绘制流程.md)(`draw-diagram` skill),产物统一放 `images/`,脚本与 `.svg` 一并提交。
|
||||
6. **门禁**:文档提交同样过 pre-commit(乱码 / 行尾空白 / gitlint + **文档链接存在性 `doc-links` / 任务表一致性 `task-table`**,见 [`文档规范.md`](文档规范.md) §4 与 [`代码规范/pre-commit使用说明.md`](代码规范/pre-commit使用说明.md))。
|
||||
|
||||
> **目录/文件名一律不含空格**(D-6,2026-09-25 起强制):空格会迫使脚本、链接、CI 处处加引号,
|
||||
> **目录/文件名一律不含空格**(2026-09-25 起强制):空格会迫使脚本、链接、CI 处处加引号,
|
||||
> 且 URL 编码形态(`UI%20设计`)易被漏改。现全库已无含空格目录。
|
||||
|
||||
---
|
||||
|
||||
## 11. 已知文档问题(待清理)
|
||||
|
||||
> 来源:原报告 D-3/D-7(两条已销项,正文已移入 [`文档规范.md`](文档规范.md) 与 pre-commit 门禁)。
|
||||
> **原报告 D-3 / D-6 / D-7 已处理完毕**(2026-09-25):全库链接存在性检查通过(66 文档 0 失效)、任务表与
|
||||
> 来源:原审查报告两条已销项(正文已移入 [`文档规范.md`](文档规范.md) 与 pre-commit 门禁)。
|
||||
> **原报告三条已处理完毕**(2026-09-25):全库链接存在性检查通过(66 文档 0 失效)、任务表与
|
||||
> `Src/freertos.c` 一致、文档规范已建立。下表保留**仍需跟踪**的项。
|
||||
|
||||
| 问题 | 位置 | 说明 |
|
||||
|---|---|---|
|
||||
| ~~指向未实现工具~~ | ~~`UI_界面制作流程.md`、`UI_自动化测试流程.md` → `tools/ui_mock/`~~ | ✅ 已改指(2026-10-14 核实):两份 UI 文档正文已无该路径(仅存变更记录里的历史提及);golden 回归落在 `simulator/tests/`(四脚本) |
|
||||
| ~~产物缺失~~ | ~~`内存管理/RAM使用分析与优化方案.md` → `scripts/ram_baseline.tsv`~~ | ✅ 已建(2026-10-12,N-27 前半):`ram_baseline.py` + `ram_baseline.tsv` + [`RAM预算台账.md`](内存管理/RAM预算台账.md) + `mem-budget` 钩子 |
|
||||
| ~~目录名含空格~~ | ~~`UI 设计/`~~ | ✅ 已修复(2026-09-25,D-6):改名为 `UI设计/`,全仓库 67 处引用同步;命名约定见 [`文档规范.md`](文档规范.md) §1 |
|
||||
| ~~缺一致性门禁~~ | — | ✅ 已落地(2026-09-25/26,D-7 三档齐):`scripts/check_doc_links.py`(存在性)+ `scripts/gen_task_table.py`(数值)+ `scripts/check_mem_numbers.py`(体积),接入 pre-commit `doc-links` / `task-table` / `mem-numbers` 钩子 |
|
||||
| ~~产物缺失~~ | ~~`内存管理/RAM使用分析与优化方案.md` → `scripts/ram_baseline.tsv`~~ | ✅ 已建(2026-10-12,「缩堆迁 CCM 后半(暂缓)」的前半):`ram_baseline.py` + `ram_baseline.tsv` + [`RAM预算台账.md`](内存管理/RAM预算台账.md) + `mem-budget` 钩子 |
|
||||
| ~~目录名含空格~~ | ~~`UI 设计/`~~ | ✅ 已修复(2026-09-25):改名为 `UI设计/`,全仓库 67 处引用同步;命名约定见 [`文档规范.md`](文档规范.md) §1 |
|
||||
| ~~缺一致性门禁~~ | — | ✅ 已落地(2026-09-25/26,文档门禁三档齐):`scripts/check_doc_links.py`(存在性)+ `scripts/gen_task_table.py`(数值)+ `scripts/check_mem_numbers.py`(体积),接入 pre-commit `doc-links` / `task-table` / `mem-numbers` 钩子 |
|
||||
| ~~`docs/文档规范.md` 未创建~~ | — | ✅ 已创建(2026-09-25):[`文档规范.md`](文档规范.md) |
|
||||
|
||||
> 未闭环的文档类问题**只剩原报告 D-1 仓库膨胀**(登记簿 **N-29**,已决策暂不处理)。
|
||||
> 未闭环的文档类问题**只剩仓库膨胀**(登记簿条目「仓库体积膨胀观察」,已决策暂不处理)。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ cmake --build simulator/build --config Debug # 0) 构建模拟器(须 0 警
|
||||
| 多页大面积像素差异 | 字体重生成(`ui_font_cn_12.c` 变化)→ 确认字形正确后 `--update` 刷参考 |
|
||||
| 单行/单字差异 | 几何或文案变更 → 先判断是否有意修改;无意 = bug |
|
||||
| 池水位门禁失败但像素一致 | 样式/结构变更(如动态样式转常量、增删框体)→ 确认新值合理后更新常量并登记 |
|
||||
| **只有 `netcfg_save` 一页失败**(保存行值列是 `ERR` 而非 `OK`),其余 10 页全过 | **不是代码回归,是工作目录被污染**:模拟器按**当前工作目录**读写 `sim_config.ini`,而 `--cfgtest` 的 E-01 场景 2 会伪造一份 4000 B 纯注释"雷"文件、并断言"拒写后原文件不动"——**连通过路径也会把它留在原地**。之后每次运行都加载它 → 外科手术保存要在 4000 B 注释后补写受管段 → 输出必超 `CFG_FILE_MAX_LEN` → 引擎**按设计拒写** → 保存行显示 ERR,与"工厂默认态"的黄金参考对不上。处置:两套回归已改为**在空临时目录里跑**(传 `cwd=tmp`),`--cfgtest` 已加外壳无论成败一律删除伪造档;手工跑 `lvgl_sim` 时删掉当前目录的 `sim_config.ini` 即恢复。**禁止为此刷黄金参考**(参考是对的) |
|
||||
| **只有 `netcfg_save` 一页失败**(保存行值列是 `ERR` 而非 `OK`),其余 10 页全过 | **不是代码回归,是工作目录被污染**:模拟器按**当前工作目录**读写 `sim_config.ini`,而 `--cfgtest` 超长守卫的场景 2 会伪造一份 4000 B 纯注释"雷"文件、并断言"拒写后原文件不动"——**连通过路径也会把它留在原地**。之后每次运行都加载它 → 外科手术保存要在 4000 B 注释后补写受管段 → 输出必超 `CFG_FILE_MAX_LEN` → 引擎**按设计拒写** → 保存行显示 ERR,与"工厂默认态"的黄金参考对不上。处置:两套回归已改为**在空临时目录里跑**(传 `cwd=tmp`),`--cfgtest` 已加外壳无论成败一律删除伪造档;手工跑 `lvgl_sim` 时删掉当前目录的 `sim_config.ini` 即恢复。**禁止为此刷黄金参考**(参考是对的) |
|
||||
| `找不到 lvgl_sim.exe` | 模拟器未构建或 build/ 被删 → 先按 §一 重建 |
|
||||
| 终端输出中文乱码 | PowerShell 代码页渲染问题,不影响判定(看 PASS/FAIL 与退出码) |
|
||||
|
||||
|
||||
@@ -64,13 +64,13 @@ MCU **无物理屏幕**:LVGL 做 160×160 **1bpp 单色离屏渲染**,帧缓
|
||||
`lv_display_set_theme()` + 对**活动屏幕**再 `lv_theme_apply()`(实测 `bg_before=F5F5F5` → `bg_after=000000`)。
|
||||
另外 I1 缓冲头 8 B 调色板 LVGL 不替调用方初始化(上电全 0 = 两项透明黑),须显式写 `[0]=黑 [1]=白`;
|
||||
渲染器本身按亮度阈值置位(`lv_draw_sw_blend_to_i1.c`:亮 → 位=1),与客户端"位=1 即亮"的约定一致。
|
||||
10. **两份 `lv_conf.h` 必须是同一特性子集(2026-10-11 定;F-1/F-2/F-3 落地时暴露的漂移)**:`Lib/lv_conf.h`(MCU)与 `simulator/lv_conf.h`(PC)是**两份独立文件**,此前已漂移——模拟器早已 I1-only,MCU 端却让 11 个 `LV_DRAW_SW_SUPPORT_*`、5 个未用控件类、`LV_USE_THEME_SIMPLE`、`LV_USE_FLEX/GRID` 全靠 `lv_conf_internal` 默认值隐式生效,把用不到的代码整份链进镜像 = **实测 64,576 B 死代码(旧镜像的 23.5%)**。现两端对齐为同一子集:
|
||||
10. **两份 `lv_conf.h` 必须是同一特性子集(2026-10-11 定;裁剪 LVGL 死代码时暴露的漂移)**:`Lib/lv_conf.h`(MCU)与 `simulator/lv_conf.h`(PC)是**两份独立文件**,此前已漂移——模拟器早已 I1-only,MCU 端却让 11 个 `LV_DRAW_SW_SUPPORT_*`、5 个未用控件类、`LV_USE_THEME_SIMPLE`、`LV_USE_FLEX/GRID` 全靠 `lv_conf_internal` 默认值隐式生效,把用不到的代码整份链进镜像 = **实测 64,576 B 死代码(旧镜像的 23.5%)**。现两端对齐为同一子集:
|
||||
* 绘制核只留 `LV_DRAW_SW_SUPPORT_I1`(显示是 1bpp;字形 A8 位图是作为 **mask** 传入、混合按**目的**格式分派,故不需要 A8/L8/AL88);
|
||||
* 控件全关(`label`/`button`/`buttonmatrix`/`bar`/`textarea`/`image`/`keyboard`)——全仓(`Drivers/BSP/UI`、`App`、`simulator`)**零控件构造函数**,只用 `lv_obj_create` + `lv_theme_mono_init`;
|
||||
* `LV_USE_THEME_SIMPLE 0`:它是把上述控件类拉进镜像的**锚点**(`lv_display_create()` 会强链 `lv_theme_simple_init`);⚠ 9.3 **没有** `LV_USE_THEME_BASIC`,旧配置里那条是无效项,已删;
|
||||
* `LV_USE_FLEX 0` / `LV_USE_GRID 0`:全仓无 `lv_obj_set_flex_*` / `lv_obj_set_grid_*` 调用。
|
||||
⚠ 裁剪后 ARMCC 报 `#177-D`(上游 9.3.0 在 `lv_draw_sw_blend_to_i1.c` 漏了 `lv_color16_from_u16` 的定义处守卫)→ 本仓已按使用点补 `#if LV_DRAW_SW_SUPPORT_RGB565_SWAPPED`(原型 + 定义两处),升级 LVGL 时若上游已修可去掉。
|
||||
⚠ 将来引入控件型页面(U2 原型库)时**两端同步**逐项打开并复跑 `ui-verify`。量化与验证记录见 `../内存管理/RAM使用分析与优化方案.md` §2.6.4。
|
||||
⚠ 将来引入控件型页面(原型库)时**两端同步**逐项打开并复跑 `ui-verify`。量化与验证记录见 `../内存管理/RAM使用分析与优化方案.md` §2.6.4。
|
||||
✅ **已入门禁**(2026-10-11):`scripts/check_lv_conf_sync.py` = pre-commit 钩子 `lv-conf-sync`。比对的是**生效值**(文件未定义则取 `lv_conf_internal.h` 兜底默认),并抓"写了 LVGL 不认的宏名"与同文件重复定义。首次跑即揪出两端共 **26 个 9.3 不存在的选项**(LVGL 8 / 9.4 模板残留,与 `LV_USE_THEME_BASIC` 同类)、**3 处同文件重复定义**、**10 项 MCU 端靠默认值隐式生效的开关**(含默认 =1 的 `LV_USE_OBSERVER` / `LV_USE_DRAW_PXP` / `LV_USE_IMAGEBUTTON`)——已全部清理/显式固化。
|
||||
✅ **门禁触发范围**(2026-10-11):`lv-conf-sync` 的 `files:` 同时匹配 `Lib/lv_conf.h`、**`simulator/lv_conf.h`** 与脚本自身 → **两端任一改动都会跑**。此前顶层 `exclude` 整目录挡掉 `simulator/`,模拟器侧改动拦不到;已删该条并把 `simulator/` 下自研代码整体纳入 pre-commit(cppcheck 当天即揪出 `sim_syslog.c` 一处真实空指针解引用),详见 `../代码规范/pre-commit使用说明.md` §5.5。
|
||||
|
||||
@@ -277,7 +277,7 @@ ENTER/→ 进子框:
|
||||
accept / recv_nb / send / close / 重建三件套的**返回处**调用钩子,uiTask 注册
|
||||
`task_wd_beat(TASK_WD_UI)`。效果 = 心跳间隔从「整轮往返之和」收敛到「单个往返」;
|
||||
只要每次往返都会回来,UI 就不该被记停摆。往返本身**不改**(有界化/请求序号 =
|
||||
`docs/任务规划/README.md` 的 E-27/E-28 跨上下文收口,批 3;§11.6 否决过的
|
||||
`docs/任务规划/README.md` 的跨上下文收口条目,批 3;§11.6 否决过的
|
||||
「给 net_* 裸加超时」不重演)。
|
||||
- **分层**:Drivers/BSP 不得 include App 头(layer-deps),故心跳经回调注入而非直调;
|
||||
钩子内只做置位类动作、不阻塞(契约写在 `Drivers/BSP/UI/ui_net_sink.h`)。
|
||||
@@ -287,7 +287,7 @@ ENTER/→ 进子框:
|
||||
护栏不变)。
|
||||
- **残留暴露**(刻意不归本票):单个往返自身仍无上界(osMessageQueuePut(osWaitForever)
|
||||
+ xTaskNotifyWait(portMAX_DELAY)),netTask 若被单消息拖 >800ms,UI 位连击照成立——
|
||||
那是「判据抓对了人」,处置在 net 侧(E-27/E-28),不在心跳侧。
|
||||
那是「判据抓对了人」,处置在 net 侧,不在心跳侧。
|
||||
|
||||
## 六、变更记录(简表)
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
| 日志 | `syslog_count/get_record` | ✅ 真 | 仅运行、自检 2 类 |
|
||||
| SOE | **无读取 API**(只有 `soe_store_post/drain`) | ❌ 需新增 | `/log/soe.log` 二进制 64 B |
|
||||
| 元件状态 | `prot_elm_state/active_mask/name` | ✅ 真 | 当前态,无历史 |
|
||||
| 功率/电度 | — | ❌ 禁止 | N-18:跨转换器不同步,V0.1 不得算功率 |
|
||||
| 功率/电度 | — | ❌ 禁止 | 双转换器无共同采样触发:跨转换器不同步,V0.1 不得算功率 |
|
||||
| 直流通道 | — | ❌ 无硬件 | `ADC_SEM` 只有 8 电气 + 温度 |
|
||||
| 开入/开出 | — | ❌ 无代码 | 固件完全没有开入开出实现 |
|
||||
|
||||
@@ -379,7 +379,7 @@ int run_par_set_deadband(uint8_t yc_idx, float v); /* 范围校验 */
|
||||
| 1 | `104端口` | `IEC104_PORT`(App 侧常量) |
|
||||
| 2 | `公共地址` | `iec104_serv` 的 CA(当前固定 1) |
|
||||
| 3 | `显示端口` | RemoDispBus 端口常量 |
|
||||
| 4 | `FTP用户` | FTP 配置(`admin`,N-19 鉴权后) |
|
||||
| 4 | `FTP用户` | FTP 配置(`admin`,鉴权启用后) |
|
||||
|
||||
- 需要在 `ui_data_rt_t` **尾部追加**一个 `comm` 子结构(`port`/`ca`/`disp_port` + 8 B 用户名),按 `docs/UI设计/UI_数据供给设计说明.md` §4.3 的扩展规则升 `UI_DATA_VER`。
|
||||
- 规模:**S**(快照 +4 字段,页面 60 行)。
|
||||
|
||||
+1
-1
@@ -266,6 +266,6 @@ ui_page_ac / ui_page_yx / ui_page_setlist ...
|
||||
|
||||
## 9. 与既有规划的关系
|
||||
|
||||
- 本文替代"剩余页面尚未规划"的状态(原 `docs/任务规划/README.md` §2.0 中「UI 扩展」的 U5 条目按"暂缓、未规划"记载)。
|
||||
- 本文替代"剩余页面尚未规划"的状态(原 `docs/任务规划/README.md` §2.0 中「UI 扩展」的剩余 21 叶页面落地项按"暂缓、未规划"记载)。
|
||||
- 页面工作**不应独立于数据层推进**:批 1 的第 1 项(快照层)与采集/遥测链共享同一批数据,建议与"测量子系统"同波次排期。
|
||||
- 与 `docs/问题记录/采集与数据处理短板评测.md` 的对应:该文的标定(`docs/问题记录/采集与数据处理短板评测.md` §4.1)与遥测链(同文 §4.2)落地后,交流量/直流量/遥测系数三页才有真实数据可显示。
|
||||
|
||||
@@ -69,8 +69,8 @@
|
||||
<rect x="26" y="718.0" width="690" height="120.0" rx="10" fill="#fff1f2" stroke="#e11d48" stroke-opacity="0.45"/>
|
||||
<text x="42" y="740.0" font-size="15" font-weight="700" fill="#e11d48">⑤ 传达员被按在椅子上</text>
|
||||
<text x="211" y="740.0" font-size="11.5" fill="#64748b">队头阻塞</text>
|
||||
<rect x="42" y="750.0" width="477" height="34" rx="7" fill="#ffffff" stroke="#e11d48" stroke-opacity="0.55"/>
|
||||
<text x="280" y="771.5" font-size="13" fill="#1e293b" text-anchor="middle">症状:FTP banner 迟到 25~30 s(E-02 实测),netTask 频繁冻结半秒</text>
|
||||
<rect x="42" y="750.0" width="465" height="34" rx="7" fill="#ffffff" stroke="#e11d48" stroke-opacity="0.55"/>
|
||||
<text x="274" y="771.5" font-size="13" fill="#1e293b" text-anchor="middle">症状:FTP banner 迟到 25~30 s(台架实测),netTask 频繁冻结半秒</text>
|
||||
<rect x="42" y="792.0" width="468" height="34" rx="7" fill="#ffffff" stroke="#e11d48" stroke-opacity="0.55"/>
|
||||
<text x="276" y="813.5" font-size="13" fill="#1e293b" text-anchor="middle">机制:30 s 阻塞收 + 500 ms 盲等忙等,而 netTask 是全楼唯一传达员</text>
|
||||
<rect x="844" y="718.0" width="690" height="120.0" rx="10" fill="#f0fdf4" stroke="#16a34a" stroke-opacity="0.45"/>
|
||||
@@ -101,8 +101,8 @@
|
||||
<rect x="26" y="1038.0" width="690" height="120.0" rx="10" fill="#fff1f2" stroke="#e11d48" stroke-opacity="0.45"/>
|
||||
<text x="42" y="1060.0" font-size="15" font-weight="700" fill="#e11d48">⑦ 只会礼貌送客不会轰人</text>
|
||||
<text x="226" y="1060.0" font-size="11.5" fill="#64748b">close 无 RST(手册定案)</text>
|
||||
<rect x="42" y="1070.0" width="440" height="34" rx="7" fill="#ffffff" stroke="#e11d48" stroke-opacity="0.55"/>
|
||||
<text x="262" y="1091.5" font-size="13" fill="#1e293b" text-anchor="middle">症状:FIN_WAIT_2 长尾,监听恢复受限于对端 close(E-02 定案)</text>
|
||||
<rect x="42" y="1070.0" width="429" height="34" rx="7" fill="#ffffff" stroke="#e11d48" stroke-opacity="0.55"/>
|
||||
<text x="256" y="1091.5" font-size="13" fill="#1e293b" text-anchor="middle">症状:FIN_WAIT_2 长尾,监听恢复受限于对端 close(台架定案)</text>
|
||||
<rect x="42" y="1112.0" width="483" height="34" rx="7" fill="#ffffff" stroke="#e11d48" stroke-opacity="0.55"/>
|
||||
<text x="283" y="1133.5" font-size="13" fill="#1e293b" text-anchor="middle">机制:芯片 close 只发 FIN;对端内核存活但应用挂死 = 回 ACK 却不起身</text>
|
||||
<rect x="844" y="1038.0" width="690" height="120.0" rx="10" fill="#f0fdf4" stroke="#16a34a" stroke-opacity="0.45"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
@@ -17,7 +17,7 @@
|
||||
<rect x="136" y="214" width="268" height="148" rx="10" fill="#f0fdfa" stroke="#0d9488" stroke-opacity="0.45"/>
|
||||
<text x="149" y="244" font-size="12" font-weight="700" fill="#0d9488">tpafe5160.c 的 BUSY EXTI</text>
|
||||
<text x="149" y="270" font-size="11" fill="#334155">s_frame_seq++:每读完一帧 +1</text>
|
||||
<text x="149" y="292" font-size="11" fill="#334155">s_frstdata_err++:无跳变帧累计(E-44)</text>
|
||||
<text x="149" y="292" font-size="11" fill="#334155">s_frstdata_err++:无跳变帧累计计数</text>
|
||||
<text x="149" y="314" font-size="11" fill="#334155">ISR 内只加计数,不打日志</text>
|
||||
<line x1="404" y1="288.0" x2="415" y2="288.0" stroke="#0d9488" stroke-width="2.2"/>
|
||||
<path d="M 424.0 288.0 L 413.0 282.5 L 413.0 293.5 z" fill="#0d9488"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@@ -446,10 +446,10 @@ sequenceDiagram
|
||||
### 5.9 ADC 采集(FR-ADC)🔶 采集链路已实现(B1);保护/遥测算法与上行待实现
|
||||
|
||||
- **需求(B0 已确认,2026-10-10)**:**持续采集** 8 路电气量(Ua/Ub/Uc/U0、Ia/Ib/Ic/I0,**1000 Hz / 20 点/周波**),经保护/遥测算法后**上送 IEC 60870-5-104**(以太网 TCP 2404;遥测上送短浮点、采集上传系数 = 1)。
|
||||
- **现状(采集链路 B1 + L1 已实现,2026-10-10)**:启动序列调用一次 `tpafe5160_init()`;**运行期周期 CONVST 重触发已由 TIM6 更新中断(1 kHz)接管**(`Src/main.c` 的 `HAL_TIM_PeriodElapsedCallback`,2026-10-10)+ `adcTask` 经 L1 层 `adc_input_poll()` 消费(`tpafe5160_snapshot()` 8 通道 + STM32 ADC1 9 通道扫描)+ 帧统计,台架 `@test` 确认 `frame_seq` 严格 1000 Hz 递增、`frst_err=0`、`adc1_rc=0` / `adc1_err=0`;STM32 侧 ADC1 **消费者已落地**(`App/algo/adc_input.c` 的 `stm32_scan()`,L1-3/L1-4,2026-10-10),按 N-18 仅逐通道独立监视。
|
||||
- **现状(采集链路 B1 + L1 已实现,2026-10-10)**:启动序列调用一次 `tpafe5160_init()`;**运行期周期 CONVST 重触发已由 TIM6 更新中断(1 kHz)接管**(`Src/main.c` 的 `HAL_TIM_PeriodElapsedCallback`,2026-10-10)+ `adcTask` 经 L1 层 `adc_input_poll()` 消费(`tpafe5160_snapshot()` 8 通道 + STM32 ADC1 9 通道扫描)+ 帧统计,台架 `@test` 确认 `frame_seq` 严格 1000 Hz 递增、`frst_err=0`、`adc1_rc=0` / `adc1_err=0`;STM32 侧 ADC1 **消费者已落地**(`App/algo/adc_input.c` 的 `stm32_scan()`,L1-3/L1-4,2026-10-10),受双转换器无共同采样触发所限,仅逐通道独立监视。
|
||||
- **后果**:上电后仅采集 1 个样本,此后数据永久陈旧。
|
||||
- **B0 结论**(2026-10-10,详见 `docs/算法/继电保护功能复现规划.md` §1.5):① 持续采集 ② 1000 Hz(20 点/周波),通道 = 4U+4I(点表 `4011~4018`)③ 上行 **IEC 60870-5-104**(2404,非 ModBus RTU 上行)④ ADC 采集链路为遥测/保护的必需来源 → **常驻编译**;原 `APP_ADC_ENABLE` 占位宏零消费点,已于 2026-10-22 删除(将来若要裁剪,需在真实初始化点接入门控并登记进 `App/app/app_cfg.h`)。
|
||||
- **实现约束**(见 §9):周期 CONVST 重触发 + `adc_task` 消费 `tpafe5160_snapshot()`;**原子快照 API 已就位**(2026-10-10 修 E-44 / E-45 / E-58,旧的 `get_buf` / `data_ready` / `clear_ready` 已删 → 取数不再撕裂、重触发不再丢帧、芯片不驱动总线会被 `init()` 首帧自检抓到);栈预算核算;V0.1 通道映射已固化 → `docs/硬件平台/ADC通道映射说明.md`(13/17 路置换;语义 UA/UB/UC/UN、IA/IB/IC/IN、V_ZL2=温度,其余备用;网名 ADC17 = PC4 用 `ADC_CHANNEL_14`,**不是** `ADC_CHANNEL_12`)。⚠ **8 路电气量分属 TPAFE / STM32 两片转换器属 V0.1 硬件缺陷**(跨转换器无同一时刻性、精度与量程不一致,登记簿 N-18,V0.2 改版要求全部走 TPAFE)→ 在 V0.1 上主板侧只做**逐通道独立监视**,功率 / 功率因数 / 相角 / 矢量类量一律取子板计量模块结果,不得由主板混算。
|
||||
- **实现约束**(见 §9):周期 CONVST 重触发 + `adc_task` 消费 `tpafe5160_snapshot()`;**原子快照 API 已就位**(2026-10-10 修三条采集契约缺陷,旧的 `get_buf` / `data_ready` / `clear_ready` 已删 → 取数不再撕裂、重触发不再丢帧、芯片不驱动总线会被 `init()` 首帧自检抓到);栈预算核算;V0.1 通道映射已固化 → `docs/硬件平台/ADC通道映射说明.md`(13/17 路置换;语义 UA/UB/UC/UN、IA/IB/IC/IN、V_ZL2=温度,其余备用;网名 ADC17 = PC4 用 `ADC_CHANNEL_14`,**不是** `ADC_CHANNEL_12`)。⚠ **8 路电气量分属 TPAFE / STM32 两片转换器属 V0.1 硬件缺陷**(跨转换器无同一时刻性、精度与量程不一致,登记簿条目「双转换器无共同采样触发」,V0.2 改版要求全部走 TPAFE)→ 在 V0.1 上主板侧只做**逐通道独立监视**,功率 / 功率因数 / 相角 / 矢量类量一律取子板计量模块结果,不得由主板混算。
|
||||
|
||||
### 5.10 RS-485 采集(FR-RS485)⬜ 待实现
|
||||
|
||||
@@ -513,7 +513,7 @@ sequenceDiagram
|
||||
|
||||
- **实现**:lftpd(轻量 FTP 服务器),root = `/`(FatFS 卷根),端口 21,**单客户端**。
|
||||
- **支持命令**:登录 / TYPE I / PASV / STOR / RETR / LIST / DELE / QUIT。
|
||||
- **鉴权**(已鉴权 · 2026-10-11,N-19):口令登录(`[ftp]` 段 `user` / `pwd_hash` = SHA-256(user‖password) / `write`);未登录仅 USER/PASS/QUIT/FEAT/SYST/NOOP 放行,其余一律 530;`write=0` 可禁 STOR/DELE;连续 5 次失败锁 60 s;出厂默认 `admin`/`admin`,默认口令在用有启动告警。口径详见 `docs/子系统设计/网络配置说明.md` §3.4。
|
||||
- **鉴权**(已鉴权 · 2026-10-11):口令登录(`[ftp]` 段 `user` / `pwd_hash` = SHA-256(user‖password) / `write`);未登录仅 USER/PASS/QUIT/FEAT/SYST/NOOP 放行,其余一律 530;`write=0` 可禁 STOR/DELE;连续 5 次失败锁 60 s;出厂默认 `admin`/`admin`,默认口令在用有启动告警。口径详见 `docs/子系统设计/网络配置说明.md` §3.4。
|
||||
- **启动门**:`ftpTask` 必须等 `NET_READY` **且** `STORAGE_READY`(两位 `NoClear`)才 `lftpd_start`。
|
||||
- **注意**:同一时刻只服务 1 个会话,旧会话异常断开后约 30 s 恢复监听;测试脚本须内置连接重试,**不要用裸 TCP 工具探测 21 端口**。
|
||||
- **实测**:128 KB 上传下载逐字节一致(约 49/60 KB/s)。
|
||||
@@ -680,7 +680,7 @@ cfg-file-unit-test、test-suite-switch、gitlint。
|
||||
|
||||
| 项 | 现状 |
|
||||
|---|---|
|
||||
| FTP 鉴权 | **已鉴权**(2026-10-11,N-19):口令登录(`[ftp]` 段存 SHA-256 摘要,不存明文)+ 连续 5 次失败锁 60 s + `write=0` 可选只读;出厂默认 `admin`/`admin`,默认口令在用有启动告警。边界:FTP 明文传口令,挡未授权访问、不挡网络嗅探(详见 `docs/子系统设计/网络配置说明.md` §3.4) |
|
||||
| FTP 鉴权 | **已鉴权**(2026-10-11):口令登录(`[ftp]` 段存 SHA-256 摘要,不存明文)+ 连续 5 次失败锁 60 s + `write=0` 可选只读;出厂默认 `admin`/`admin`,默认口令在用有启动告警。边界:FTP 明文传口令,挡未授权访问、不挡网络嗅探(详见 `docs/子系统设计/网络配置说明.md` §3.4) |
|
||||
| UI 菜单权限 | 受保护叶子(行尾 `#P`)先经密码页;密码**仅编译期写入**(查看 `000` / 修改 `123`),不落 Flash、无运行期设置页 |
|
||||
| 远程显示 | 无鉴权,单连接;现场同网段部署 |
|
||||
|
||||
@@ -772,7 +772,7 @@ cfg-file-unit-test、test-suite-switch、gitlint。
|
||||
|
||||
| 缺口 | 现状 | 影响 |
|
||||
|---|---|---|
|
||||
| **ADC 采集链路** | ✅ **采集链路已实现(B1 + L1,2026-10-10)**:采样节拍由 TIM6 更新中断(1 kHz)硬件触发;`adcTask` 经 L1 层 `adc_input_poll()` 消费(TPAFE 8 通道快照 + **STM32 ADC1 9 通道扫描**),台架 `@test` 闭环(1000 Hz、`adc1_rc=0`);取数按语义(L1-3/L1-4,N-18 逐通道独立监视) | 数据路径已通;剩余为上层保护/遥测算法与 104 上行 |
|
||||
| **ADC 采集链路** | ✅ **采集链路已实现(B1 + L1,2026-10-10)**:采样节拍由 TIM6 更新中断(1 kHz)硬件触发;`adcTask` 经 L1 层 `adc_input_poll()` 消费(TPAFE 8 通道快照 + **STM32 ADC1 9 通道扫描**),台架 `@test` 闭环(1000 Hz、`adc1_rc=0`);取数按语义(L1-3/L1-4,双转换器无共同采样触发下逐通道独立监视) | 数据路径已通;剩余为上层保护/遥测算法与 104 上行 |
|
||||
| **RS-485 采集链路** | `rs485_task.c` 空桩;`App/protocol/` 仅 README | 无 RS-485 数据收发(B0 定:**对下 ModBus RTU 采集**) |
|
||||
| **DTU 核心转发职责** | **B0 已定(2026-10-10)**:上行 **IEC 60870-5-104**(以太网 TCP 2404,遥测短浮点系数 1);RS-485 对下 ModBus RTU 采集 | 转发目标已明确,待实现 |
|
||||
|
||||
@@ -790,7 +790,7 @@ cfg-file-unit-test、test-suite-switch、gitlint。
|
||||
|
||||
| 开关 | 位置 | 现状 |
|
||||
|---|---|---|
|
||||
| 功能裁剪开关 | `App/app/app_cfg.h`(当前无宏) | **没有任何生效的裁剪开关**:原三个 `APP_*_ENABLE` 占位宏因全库零消费点已于 2026-10-22 删除(报告 S-4),各模块一律编译进产品——B0 已确认 ADC / RS-485 均为必需链路(ADC=遥测/保护来源,RS-485=对下 ModBus RTU 采集)。将来确需裁剪时在真实初始化点接入门控,并同步登记回该文件 |
|
||||
| 功能裁剪开关 | `App/app/app_cfg.h`(当前无宏) | **没有任何生效的裁剪开关**:原三个 `APP_*_ENABLE` 占位宏因全库零消费点已于 2026-10-22 删除,各模块一律编译进产品——B0 已确认 ADC / RS-485 均为必需链路(ADC=遥测/保护来源,RS-485=对下 ModBus RTU 采集)。将来确需裁剪时在真实初始化点接入门控,并同步登记回该文件 |
|
||||
| `TEST_SUITE_*` | `test/board/test_config.h` | 测试套件**互斥**,一次构建只开一个;全注释 = 正常产品固件 |
|
||||
|
||||
---
|
||||
@@ -836,7 +836,7 @@ cfg-file-unit-test、test-suite-switch、gitlint。
|
||||
| V2 | 任务饿死 → IWDG 复位 | ✅ 800 ms 声明 stall,≤2.5 s 复位(`reset cause: IWDG`) |
|
||||
| V4 | 关中断死循环 → IWDG 复位 | ✅ 每 ~4.9 s 稳定复位(IWDG 独立于中断) |
|
||||
| V5 | 30 min 真实负载长跑 | ✅ 120/120 FTP PASS,零 IWDG 复位 |
|
||||
| P0-1 | 配置引擎堆分配改造(真机) | ✅ `[CFG] load: OK`(经 FreeRTOS 堆);FTP 改 IP 复位即生效 |
|
||||
| 堆分配改造 | 配置引擎堆分配改造(真机) | ✅ `[CFG] load: OK`(经 FreeRTOS 堆);FTP 改 IP 复位即生效 |
|
||||
| 存储/网络套件 | 16/16 PASS | ✅ |
|
||||
|
||||
---
|
||||
|
||||
+10
-10
@@ -18,23 +18,23 @@ git commit
|
||||
├─ cppcheck C 静态分析(自有代码)
|
||||
├─ no-mojibake 阻止 U+FFFD 乱码文件
|
||||
├─ coding-standard C 代码规范检查(规范V1.0 可机械校验项)
|
||||
├─ doc-links 文档链接存在性(D-3/D-7,.md)
|
||||
├─ task-table FreeRTOS 任务表一致性(D-2/D-7)
|
||||
├─ mem-numbers 内存/Flash 数字一致性(D-7 体积档)
|
||||
├─ doc-links 文档链接存在性(.md)
|
||||
├─ task-table FreeRTOS 任务表一致性
|
||||
├─ mem-numbers 内存/Flash 数字一致性(体积档)
|
||||
├─ lv-conf-sync 两份 lv_conf.h 特性子集一致性(比对生效值)
|
||||
├─ cubemx-survival CubeMX 重生成存活审计(易失定制清单 + 基线漂移)
|
||||
├─ watchdog-unit-test 看门狗判定状态机主机侧单测(L0.5)
|
||||
├─ test-suite-switch 测试套件开关=产品构建(防测试固件静默提交)
|
||||
├─ registration-check 双端注册反向校验(uvprojx + CMakeLists,N-23;含 UI 页面描述符表接线,U4)
|
||||
├─ mem-budget RAM 预算 92% 阈值门禁(N-27 三件套,2026-10-12)
|
||||
└─ font-charset UI 字符集差集检查(防缺字白框,U4,2026-10-15)
|
||||
├─ registration-check 双端注册反向校验(uvprojx + CMakeLists,登记簿「rs485_task 白名单缺口」;含 UI 页面描述符表接线,「UI 字符集与像素回归门禁」)
|
||||
├─ mem-budget RAM 预算 92% 阈值门禁(登记簿条目「缩堆迁 CCM 后半(暂缓)」,2026-10-12)
|
||||
└─ font-charset UI 字符集差集检查(防缺字白框,「UI 字符集与像素回归门禁」,2026-10-15)
|
||||
└─ commit-msg(.git/hooks/commit-msg)
|
||||
└─ gitlint 校验 commit message 格式
|
||||
```
|
||||
|
||||
**两阶段钩子**:`pre-commit` 阶段拦截代码问题,`commit-msg` 阶段拦截格式问题。任一失败 → commit 中止。
|
||||
|
||||
> **CI 侧的同一套门禁(2026-10-01 T-6)**:Gitea Actions(`.gitea/workflows/ci.yml`)在 push / PR 时
|
||||
> **CI 侧的同一套门禁(2026-10-01 起)**:Gitea Actions(`.gitea/workflows/ci.yml`)在 push / PR 时
|
||||
> 以 `pre-commit run --all-files` 复跑**全部上述钩子**(`mem-numbers` 在无 Keil `.map` 的 runner 上自适应跳过)。
|
||||
> 本地提交前想跑同一套判定:`& '.venv\Scripts\python.exe' scripts/ci_local.py`。详见 `../测试说明/测试开发标准流程.md` §9。
|
||||
|
||||
@@ -241,9 +241,9 @@ $env:PATH = [Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [Env
|
||||
| `.cubemx_survival_baseline.json` | 仓库根 | CubeMX 易失定制基线(哈希;`--write` 重建) |
|
||||
| `scripts/check_mojibake.py` | scripts/ | U+FFFD 检测脚本 |
|
||||
| `scripts/check_coding_standard.py` | scripts/ | 代码规范检查脚本(规范 V1.0 可机械校验项) |
|
||||
| `scripts/check_doc_links.py` | scripts/ | 文档链接存在性检查(D-3/D-7) |
|
||||
| `scripts/gen_task_table.py` | scripts/ | FreeRTOS 任务表生成/校验(D-2/D-7) |
|
||||
| `scripts/check_mem_numbers.py` | scripts/ | 内存/Flash 数字一致性(D-7 体积档) |
|
||||
| `scripts/check_doc_links.py` | scripts/ | 文档链接存在性检查 |
|
||||
| `scripts/gen_task_table.py` | scripts/ | FreeRTOS 任务表生成/校验 |
|
||||
| `scripts/check_mem_numbers.py` | scripts/ | 内存/Flash 数字一致性(体积档) |
|
||||
| `scripts/check_cubemx_survival.py` | scripts/ | CubeMX 重生成存活审计 |
|
||||
| `scripts/check_lv_conf_sync.py` | scripts/ | 两份 `lv_conf.h` 特性子集一致性(比对生效值 + 无效宏名 + 重复定义) |
|
||||
| `scripts/check_test_suite.py` | scripts/ | 测试套件开关门禁(防测试固件静默提交) |
|
||||
|
||||
+69
-134
@@ -1,158 +1,93 @@
|
||||
# 任务规划(统一待办登记簿 · 索引与排序权威)
|
||||
# 任务规划
|
||||
|
||||
> **这个文件夹是什么**:全项目唯一的未闭环事项清单 + 全项目唯一权威的工作先后顺序。
|
||||
> 2026-10-12 按「变更频率 + 职责」解耦成多文件——并行任务写范围互不相交,各改各的文件。
|
||||
>
|
||||
> **文件地图(谁改哪个)**:
|
||||
>
|
||||
> | 文件 | 内容 | 变更频率 / 写者 |
|
||||
> |---|---|---|
|
||||
> | `README.md`(本文件) | 编号空间(§0)· 未闭环一览(§1)· **推进顺序权威(§2)** · 维护约定(§3) | 低频;仅主工作树 |
|
||||
> | `采集保护收尾.md` | 「采集保护收尾」剩余:只剩 M3 送检(B10) | 低频——送检窗口前后改 |
|
||||
> | `UI补齐.md` | **当前波次(2026-10-25 用户定项)**:菜单树剩 21 叶未绑,按数据源就绪度分三梯队;含现状核对、三梯队、**7 张任务卡** | **高频**——开工后状态流转只改它 |
|
||||
> | `数据可信.md` | **收口态**:软件侧已 100%,只剩卡 0 / 0b / 12 三张台架与外部卡;含事实基线、折算模型、前置决策(**代码头注释引用其 §2/§4/§7/§8/§9/§10 为口径出处**) | 低频——只在上机或外部资源到位时改 |
|
||||
> | `排期详述.md` | 「结构债」/「验证常态」波内详表 | 低频 |
|
||||
> | `并行分道方案.md` | **待办横向归道**:文件级写域(域1~域8)· 四条道(道E~道H)· 批次与合并次序 · 不能并行的事项 | 低频——分道或批次变化时改;**明细不复制**,只做归道 |
|
||||
> | `暂缓-RS485.md` | B2 RS-485 整簇冻结清单(用户决定) | 极少 |
|
||||
> | `登记簿.md` | N-x / S-x / T-x 长期登记(网络 / 存储 / 硬件 / 测试 / 报告并轨) | 中频——新发现进对应表 |
|
||||
> | `测试与架构专项.md` | S1x / A-x 专项**未闭环项** | 低频 |
|
||||
> | `基线与待确认.md` | **只放还没答案的问题**(OQ 族属主登记处);基线类内容已移出到模块文档 | 参考,少改 |
|
||||
>
|
||||
> **怎么用**:想知道"现在该做什么、按什么顺序" → 本文件 **§2**;想知道"当前波次任务卡状态 / 验收判据 / 并行道" → `UI补齐.md`;
|
||||
> 想知道"某条待办的来龙去脉" → 按编号查 `登记簿.md` / `测试与架构专项.md`;想知道"还差哪些验证" → `排期详述.md` §2。
|
||||
>
|
||||
> **只保留待办**:已完成条目直接删除,不留变更记录(历史见 `git log` 与各模块文档);
|
||||
> 已闭环项的**结论与证据沉淀进对应模块文档/问题记录**,本文件夹不再重复。
|
||||
> **消化即销项**:事项修复/关闭后,直接删除对应条目,并同步清理其它文档对本编号的引用。
|
||||
>
|
||||
> **不在本文件夹范围**:`../测试说明/实机测试实施指南.md`(执行流程)。
|
||||
> **现在只做 UI 补齐。第一项是实现 `param_request` 写路径,然后做整定 4 页。**
|
||||
> 详细任务与验收见 `UI补齐.md`;UI 完成后的第一项是 net 层跨上下文收口。
|
||||
|
||||
## 怎么用这份规划
|
||||
|
||||
| 你想知道什么 | 只看哪个文件 |
|
||||
|---|---|
|
||||
| 现在做什么、接下来做什么 | 本文件 |
|
||||
| 当前任务怎么做、怎样算完成 | `UI补齐.md` |
|
||||
| UI 之后还有什么、哪些事在等条件 | `登记簿.md` |
|
||||
| ADC 标定为什么没做、保护为什么不动作 | `数据可信.md` |
|
||||
| RS-485 为什么冻结、重启要满足什么 | `暂缓-RS485.md` |
|
||||
| 测试与架构还剩什么约束 | `测试与架构专项.md` |
|
||||
|
||||
**一件事只有一个归属。** 本文件只负责导航与顺序,不复制各任务的验收明细;
|
||||
`登记簿.md` 不再复制当前 UI 任务,`数据可信.md` 的其余章节是被代码引用的设计约束,
|
||||
不是额外待办。
|
||||
|
||||
---
|
||||
|
||||
## 0. 编号空间与来源
|
||||
## 0. 条目与引用规则
|
||||
|
||||
| 编号 | 含义 | 备注 |
|
||||
|---|---|---|
|
||||
| **语义标识**(**2026-10-14 起新条目唯一形式**) | `#` 列填一行短语直接说清是什么事,如 `沉降窗 800ms 上限只留痕`、`RS485 采集接线` | **新条目一律用它,不再新增字母+数字编号**;同一表内语义天然不重复 → 结构上防号;引用时带文档名 |
|
||||
| `P0-x`~`P3-x` | 审计缺陷/改进项(2026-09-15/09-21 审计) | P0=功能 bug、P1=疑似 bug/健壮性、P2=改进、P3=卫生 |
|
||||
| `N-x` / `S-x` / `T-x` | 台架/审计观察登记项 / 存储·日志管线 / 测试与工具链 | **存量冻结沿用、不再新增**(新条目见上一行);`N-x` 含硬件改版项(需下一版硬件,固件侧只记口径,如 N-18) |
|
||||
| `S1~S14` / `A-1~A-7` | 2026-10-02 复审的测试充分性与架构专项 | 编号**不回收** |
|
||||
| `E-xx` | 错误码传播审计发现(**历史族**) | 属主文档已于 2026-10-15 删除;编号冻结(`docs/编号规范.md` §4.1 / §4.3),存量引用仅作历史指称,新发现一律 `DEF` |
|
||||
| `B` 前缀 | 功能主线排期条目 `B0`~`B10`(见 §2) | 存量冻结、不再新增。原 `C`(结构债)/ `D`(验证窗口)两族 **2026-10-25 废止**,条目改语义名——它们与 UI 设计约束、设计决策记录同字母不同义 |
|
||||
| 报告 `N-x`/`R-x`/`F-x`/`S-x`/`U-x`/`D-x` | 《项目审查与优化建议报告》**自有编号**(**该报告 2026-10-25 已删除**) | ⚠ 曾与本登记簿**同名不同义**(报告 N-16 = 日志逐条开关,登记簿 N-16 = A2/A4 负向台架)。其未闭环项已于 2026-10-11 并入本登记簿(`N-19`~`N-29` + U 簇),**现存引用只是历史指称,不再新增** |
|
||||
|
||||
> ⚠ **为什么 2026-10-14 改用语义标识**(一条实测失效案例):原规则写着"编号**不回收**",但
|
||||
> 销项 = **删行**,删完仓库里就不留任何痕迹——登记簿 `N-31`(2026-10-11 的 Phase 7 复跑项)
|
||||
> 销项后,2026-10-14 新建条目按"现存最大值 +1"又取了 `N-31`,与 `CH395F_Test_Guide.md`、
|
||||
> `自动化测试流程.md` 里那两处历史引用**撞号**。"不回收"要靠人先想起去翻 `git log`
|
||||
> = 不可执行的规则。语义标识自带唯一性(重名一眼可见);**已随销项消失的字母+数字号一律作废**,
|
||||
> 不得作为新条目候选,历史引用(如上述两处 `N-31`)指向的是当年的旧条目。
|
||||
|
||||
**严重度定义**(沿用审计口径):P0 = 确认功能 bug|P1 = 疑似 bug 或健壮性风险|P2 = 改进|P3 = 卫生。
|
||||
**置信度**:high = 代码级确证|medium = 依赖外部条件(手册/硬件/产品定义)。
|
||||
- **新条目使用语义短语**,一行直接说清是什么事,不再新增字母加数字编号。
|
||||
- 旧编号只用于追溯历史,不复用、不重新发号;编号族与冻结规则见 `docs/编号规范.md`。
|
||||
- 引用条目时写清所在文档和语义名,例如:`docs/任务规划/登记簿.md` 的
|
||||
「net 层跨上下文收口」。不要只写一个短号让读者猜。
|
||||
- 任务状态只维护在任务所属文件;本文件不另建一套状态表。
|
||||
|
||||
---
|
||||
|
||||
## 1. 未闭环一览(按类别)
|
||||
## 1. 当前执行:UI 补齐
|
||||
|
||||
| 类别 | 数量 | 条目 |
|
||||
菜单树共 33 叶,已绑 12 叶,剩 21 叶。其中 **16 叶纳入当前执行**,另外 5 叶因缺少
|
||||
开入硬件、录波模块或 SNTP 产品定义而不做。唯一执行清单见 `UI补齐.md`。
|
||||
|
||||
| 顺序 | 要做的事 | 交付结果 |
|
||||
|---|---|---|
|
||||
| 网络 | 4 | N-3(L5 基线重验)· N-16(A2/A4 负向台架)· N-30(relisten 沉降段统一受阻,观察)· **reconcile 突发饿死 uiTask**(🟦并档 E-27/28,批 4 评估)——2026-10-25 台架两轮分箱定案的饿死型签名,详 `登记簿.md` §1 |
|
||||
| 存储 / 日志 | 3 | **S-3(USART1 TX-only 根治)** · S-4(dhara 重试自旋)· S-5(可选全序列卷锁) |
|
||||
| 结构 / 健壮性 | 3 | N-23(注册校验残余白名单)· N-25(性能/语义簇)· N-28(uvprojx 空 TU 观察) |
|
||||
| 仓库 | 1 | N-29(`.git` **233 MB**,**已决策暂不处理、登记观察**) |
|
||||
| 硬件 | 1 | N-18(V0.2 改版项) |
|
||||
| 测试 / 基础设施 | 3 | T-7(CI 远端两 job 闭环 + 第二机交叉验证)· A-4(采集链路测试约束,RS485 侧随 B2 暂缓)· 串口助手 A6/A7 补验(待 CH340) |
|
||||
| **UI**(当前波次) | 1 簇 · **21 叶** | **U5 页面落地**——33 叶已绑 12、剩 **21**(不是原口径的 4 叶):第一梯队 9 叶(整定 4 + 维护 3 + 遥测 2,数据源全就绪)· 第二梯队 4 叶(通讯设置 + 遥信 3 页)· 第三梯队 6 叶(记录 5 + 运行报告)· 不排 2 叶(手动录波缺模块 / SNTP 缺口径)。组件层三件套已落地但**零消费者**,详表 `UI补齐.md` |
|
||||
| **暂缓** | 2 簇 | **B2 RS-485 整簇**(`暂缓-RS485.md`)· **N-27 内存优化簇剩余**(R-2 后半 / R-3 / R-4 / R-6;重开条件见 `../内存管理/RAM使用分析与优化方案.md` §4)。⚠ 已落地的 R-9 与 `mem-budget` 门禁/台账/趋势**不回退** |
|
||||
| **数据可信**(收口态) | 1 簇 · 剩 3 张外部卡 | **软件侧已 100%**,只剩 🔴 已知电压注入(卡 0,一块万用表即可)· 🟡 端子变比(0b)· 🟡 标准源两点标定(12),详表 `数据可信.md` §5。⚠ **保护现处于未标定闭锁态**——`protect_task.c:98` 要求 UA/UN/IA 的 `ADC_CAL_F_VALID` 全置位,而 VALID 只在标定写入 `[adc_cal] valid` 后才置位;用户裁定(2026-10-25)**保持闭锁到标准源到位**,不缩短解锁路径 |
|
||||
| 1 | **`param_request` 写路径** | UI 能安全提交参数修改,并收到成功或失败状态 |
|
||||
| 2 | 整定 4 页 | 参数、定值、控制字、软压板可修改并持久化 |
|
||||
| 3 | 装置维护 3 页 | 时钟设置、强制复归、清除记录 |
|
||||
| 4 | 遥测死区与系数 2 页 | 修改既有 `run_par` / `adc_cal`,不新增第二份真源 |
|
||||
| 5 | 通讯设置 | 新增 `[comm]` 配置段并接入 104 |
|
||||
| 6 | 记录 5 页 | 事故、操作、保护告警、保护启动、遥控记录有写入方并可查看 |
|
||||
| 7 | 运行报告 | 上电次数、运行时长、复位原因、104 统计 |
|
||||
|
||||
> **网络侧 E-xx 存量项**(历史编号族,属主文档已于 2026-10-15 删除,编号冻结见
|
||||
> `docs/编号规范.md` §4.3):E-27 / E-28 挂「net 层跨上下文收口」(见 `排期详述.md` §1);
|
||||
> E-47 待 CH395F 驱动侧定案;E-12 为 `FF_FS_LOCK` / 单写者纪律记录项;E-31 后续与 E-62
|
||||
> 为回归监督项(纪律已固化于 `AGENTS.md`,无需改动)。
|
||||
> UI 标准化只剩 U5 页面落地(21 叶),见 §2「UI 补齐」;lftpd 主机测试缺口为整簇排期项。
|
||||
|
||||
### 1.1 结构性判断(排序依据)
|
||||
|
||||
1. **功能主线优先(用户决定 2026-10-12)**:把"采集→相量→保护→上送"链路收口到"台架闭环 + 功能面完整 + 可送检"。前两项已达成,「采集保护收尾」只剩 M3 送检(`采集保护收尾.md`)。**RS-485 对下采集(B2)暂缓**(`暂缓-RS485.md`),主线不等它。
|
||||
2. **产品功能面在 V0.1 已到顶**(2026-10-25 复核):保护元件的三相类(B/C 相过流、零序过流、PT/CT 断线、方向/功率类)**全部被 N-18 硬件缺陷挡住**(跨转换器无同一时刻性 + STM32 侧削顶),剩余可行的只有 A 相涌流制动 / 突变量启动 / 无压无流闭锁 / 元件级校验和 4 项,而它们**没有标准源就无法验证**。加上**保护当前整条链处于未标定闭锁态**(`protect_task.c:98`),保护侧的工作在标准源到位前**没有可闭环的增量**。
|
||||
3. **数据可信软件侧已尽**:剩下的卡 0 / 0b / 12 三张全是台架或外部资源(万用表 / 子板 / 标准源),软件道插不上手。
|
||||
4. **内存预算红线已机械化**:`mem-budget` 钩子拦 RW_IRAM1/RW_CCM >92%,子系统配额 / CCM 台账 / 趋势基线 → `docs/内存管理/RAM预算台账.md`。**R-2 后半与 R-3 / R-4 / R-6 整簇暂缓**(CCM 只剩 **7,904 B**,重开条件见 `../内存管理/RAM使用分析与优化方案.md` §4)——**门禁与台账继续常开,它们正是"何时该重开"的传感器**。
|
||||
5. **验证债仅剩窗口性事项**(L5 基线重锁 / A2-A4 负向台架 / 串口助手补验 / T-7 CI 两 job),不单独排期、逢机顺手做。
|
||||
|
||||
> **结论(2026-10-25 重排的实质)**:第 1~3 条说明**高优先级波次全部被外部资源或硬件代次卡住**,
|
||||
> 而 UI 补齐是唯一"数据源已就绪、不依赖台架、能整波闭环"的工作。故本轮**只做 UI**,
|
||||
> 结构债押后——不是它不重要,是它没有外部依赖、随时能捡起来,而 UI 的 21 叶一直压着产品可见度。
|
||||
**执行纪律:单道串行。** 菜单树与页面注册表是生成物,字库也是整文件生成物;
|
||||
不要同时开多条 UI 页面分支。上板验证可累积成一批,但保存、重启、主站读回等判据不能删除。
|
||||
|
||||
---
|
||||
|
||||
## 2. 统一推进顺序(全项目唯一权威)
|
||||
## 2. 全项目推进顺序
|
||||
|
||||
> **本节是全项目所有工作流唯一的权威顺序**:`产品需求设计文档.md` §9.2、`../算法/继电保护功能复现规划.md`、
|
||||
> 各模块文档里的路线图均为局部视图,**顺序变更只改本节,其它文档只留指针**。
|
||||
> 排序原则:**安全风险 > 产品功能主线 > 数据正确性 > 预算/结构债 > 验证常态 > UI 扩展 > 仓库决策**(当前无未闭环安全项)。
|
||||
> **但优先级只在"能开工"的项之间比较**:高优先级波次若全部被外部资源(标准源 / 子板 / 台架 / runner)
|
||||
> 或硬件代次卡住,波次表按"**现在能整波闭环**"重排,阻塞原因写进「为什么在这」列——
|
||||
> 2026-10-25 的重排就是这种情况(保护元件被 N-18 挡、数据可信被标准源挡 → UI 补齐顶上)。
|
||||
> 波内详表在挂接文件里(`采集保护收尾.md` / `UI补齐.md` / `排期详述.md` / `暂缓-RS485.md`),但**波次增删与先后只改 §2.0**。
|
||||
> 本节是全项目唯一的顺序权威。模块文档只描述局部设计,不另排一套路线图。
|
||||
|
||||
### 2.0 波次总览
|
||||
### 2.0 顺序表
|
||||
|
||||
> **波次不带编号**(2026-10-25 起):波次名本身就是标识。原先的 `W1`~`W8` 已废止——它们看着像
|
||||
> 执行顺序,实际 `W8` 排在 `W3`/`W4` 之前,读者必须先查表才知道谁先谁后。现在**执行顺序就是
|
||||
> 本表从上到下**,不再多一层映射。
|
||||
| 顺序 | 工作 | 当前状态 | 开始或切换条件 |
|
||||
|---|---|---|---|
|
||||
| **1** | **UI 补齐** | **当前执行** | 已开始;按 §1 的 1→7 顺序推进 |
|
||||
| **2** | **net 层跨上下文收口** | 下一步 | UI 当前清单完成后;裸指针收口与 reconcile 突发饿死 uiTask 同批评估 |
|
||||
| **3** | 其余结构与可靠性评估 | 排队 | net 收口后;逐项见 `登记簿.md`,观察项不为了“清清单”而强做 |
|
||||
| **4** | 数据可信剩余三项 | 等待台架或外部资源 | 已知电压注入 → 端子变比 → 标准源两点标定;资源到位可插入优先处理 |
|
||||
| **5** | 标准源送检与第三方 104 主站验收 | 等待标定完成 | 两点标定完成且保护 VALID 已置位;送检窗口前 2 日冻结特性 |
|
||||
| **6** | 保护元件与采集增强 | 等待标准源或硬件改版 | 保护先解除未标定闭锁;三相同时刻类功能等 V0.2 硬件 |
|
||||
| **7** | 验证窗口事项 | 逢条件顺带 | CI runner、PC peer、CH340、负向故障注入条件到位时执行 |
|
||||
| **8** | 独立模块与暂缓项 | 当前不排 | 开入开出、故障录波、SNTP 单独立项;RS-485 与内存优化按各自重启条件 |
|
||||
|
||||
| 波次 | 内容 | 为什么在这 |
|
||||
|---|---|---|
|
||||
| **采集保护收尾** | **只剩 M3 送检**(B10,Fixed Date)——任务卡与判据见 `采集保护收尾.md` | 收口目标"台架闭环 + 功能面完整 + 可送检"的前两项已达成;**真约束只剩送检窗口**,窗口一到全道让路、窗口前 2 日特性冻结。⚠ B10 的「L1-5 标定复核」依赖卡 12,而卡 12 要标准源;保护现处于未标定闭锁态(`protect_task.c:98`),送检前必须先解卡 |
|
||||
| **数据可信**(收口态) | **软件侧已 100%**:**只剩 3 张台架与外部卡**——卡 0 已知电压注入(万用表)· 卡 0b 端子变比(子板)· 卡 12 标准源两点标定。详表 `数据可信.md` | **用户决定(2026-10-23):通道标定先于 UI 与结构债**——它是唯一"改一处、全链受益"的入口(`App/task/adc_task.c:335` 是码值→工程量的唯一位置)。⚠ **剩下的三张卡没有软件道可做**:0 要万用表与台架、0b 要子板、12 要标准源。**台架不在手边(2026-10-25 确认)→ 本波整体顺延**,不占编码道 |
|
||||
| **UI 补齐**(当前) | 菜单树剩 **21 叶未绑**(33 叶已绑 12):第一梯队 9 叶零依赖 · 第二梯队 4 叶需新配置段 · 第三梯队 6 叶需写入方或计数器;7 张任务卡见 `UI补齐.md` | **用户决定(2026-10-25):下一波只做 UI 补齐,结构债押后**。判据是"能开工"——产品功能面被 N-18 挡、数据可信被标准源挡,而结构债无外部依赖、随时能捡;UI 是唯一**数据源已就绪、不依赖台架、能整波闭环**的工作,且 21 叶一直压着产品可见度。组件层三件套(编辑器 / 定值表 / 操作页)已落地但**零消费者**,不写页面等于白做 |
|
||||
| **结构债**(押后) | **net 层跨上下文收口(含 2026-10-25 台架实证的 reconcile 饿死签名)→ 注册校验白名单清理 → 性能语义簇 / 空 TU**;USART1 改为只发不收**单独独占一轮**(CubeMX 重生成,需清空全部工作树)。详表 `排期详述.md` §1 | **无人在等、无外部依赖 → 随时能捡起来**,故排在 UI 之后。其中 net 收口优先于 USART1:饿死签名是台架**实测捕获**的可用性缺陷(8 连窗 UI 缺席 800 ms+,v1.1 判据下 3 事件 8 行、漏检与误报均为零),而 USART1 那条只是 IWDG 误复位的机制根源、且已有 250 ms drain 预算 + 300 ms 冷却的缓解 |
|
||||
| **预算与内存** | ⏸ **整簇暂缓**:R-2 后半(缩堆 56→32 KB → 29.5 KB 迁 CCM)· R-3 · R-4 · R-6;R-5 已判定不可行 | **不再排期**:没有功能在等这块预算,而搬迁要动 scatter、要逐条过 DMA 可达性清单、缩堆还要上板复测。重开条件 → `../内存管理/RAM使用分析与优化方案.md` §4 |
|
||||
| **验证常态** | T-7 CI · L5 基线重锁 · A2/A4 负向台架 · 串口助手 A6/A7(详表 `排期详述.md` §2) | 窗口性,逢机顺带,不单独排期 |
|
||||
| **仓库决策** | **N-29** `.git` **233 MB** + 图片 36.3 MB | **已决策(2026-10-11):暂不处理、登记观察**——推送/协作前重评(`git filter-repo` 历史重写影响未推送提交与协作者) |
|
||||
| **暂缓** | **B2 RS-485 整簇**(`暂缓-RS485.md`) | **用户决定(2026-10-12):当前不处理 RS-485** |
|
||||
| **硬件改版** | N-18 8 路电气量全接 TPAFE(V0.2) | 下一版硬件;固件侧已用语义映射隔离,改版只动映射表 |
|
||||
### 2.1 关键依赖
|
||||
|
||||
### 2.1 顺序一图
|
||||
|
||||
```
|
||||
采集保护收尾 只剩 B10 送检(M3, Fixed Date) 详表 采集保护收尾.md
|
||||
↓ ⚠ 送检的「L1-5 标定复核」依赖卡 12(标准源),且保护要先解卡
|
||||
数据可信 ⏸ 软件侧已 100%(只剩台架与外部卡)
|
||||
只剩 卡 0(万用表)→ 0b(子板变比)→ 12(标准源) 详表 数据可信.md
|
||||
台架不在手边(2026-10-25)→ 整体顺延,不占编码道
|
||||
↓
|
||||
UI 补齐 21 叶:第一梯队 9(零依赖)→ 第二梯队 4(新配置段)
|
||||
→ 第三梯队 6(写入方 / 计数器) 详表 UI补齐.md
|
||||
单道串行(菜单树与页面注册表是单写者生成物)
|
||||
↓
|
||||
结构债 net 收口(含 reconcile 饿死签名)→ 白名单 → 性能簇 / 空 TU
|
||||
USART1 只发不收 = 单独独占一轮(需清空全部工作树)
|
||||
↓
|
||||
预算与内存 ⏸ 整簇暂缓(重开条件见 `../内存管理/RAM使用分析与优化方案.md` §4)
|
||||
验证常态 T-7 CI · L5 基线重锁 · A2/A4 负向台架 · 串口助手
|
||||
仓库决策 N-29 .git 233MB(已决策暂不处理) 硬件:N-18 V0.2
|
||||
暂缓 B2 RS-485 整簇(见 暂缓-RS485.md)
|
||||
```
|
||||
- **UI**:`param_request` 写路径 → 整定 4 页;其余页面按 §1 串行推进。
|
||||
- **送检**:已知电压注入 → 端子变比确认 → 标准源两点标定 → 保护解除闭锁 → 送检。
|
||||
- **保护扩展**:标准源未到位前不新增无法验证的判据;跨转换器相位、功率、对称分量类
|
||||
功能必须等 V0.2 硬件。
|
||||
- **结构债**:UI 完成后先做 net 收口;RS-485 白名单、内存优化、仓库体积等观察项不抢占
|
||||
当前编码道。
|
||||
|
||||
---
|
||||
|
||||
## 3. 维护约定
|
||||
|
||||
- 本文件夹是**全项目唯一的未闭环事项登记簿**——"盘点 + 排序 + 明细"三合一,明细按职责拆进本文件夹各文件(2026-10-12 解耦),不再分散到其它文档。
|
||||
- **并行写纪律**:任务分支(worktree)**不改本文件夹任何文件**;任务卡状态列(⬜/🟦)与销项一律由 Lead 在主工作树更新。解耦的收益 = 不同波次 / 不同登记之间互不冲突,**不是**任务分支可以写。
|
||||
- **任一项完成后直接删除对应条目**(先销本文件夹条目,再清理其它文档对本编号的引用);**不留变更记录**,历史见 `git log` 与各模块文档。
|
||||
- 已闭环条目的**结论与证据沉淀进模块文档**,本文件夹不再重复。
|
||||
- **2026-10-14 起新条目用「语义标识」**:`#` 列填一行短语(如 `沉降窗 800ms 上限只留痕`),
|
||||
**不再新增字母+数字编号**(规则见 `docs/任务规划/README.md` §0 表首行);存量编号
|
||||
(P-x / N-x / S-x / T-x / S1x / A-x / B 前缀)**冻结沿用**,而**已随销项消失的号永久作废**、
|
||||
不得作为新条目候选——"不回收"在只写规则、不留痕迹的情况下不可执行(撞号实测见
|
||||
`docs/任务规划/README.md` §0 注);E-xx(历史编号族)冻结于 `docs/编号规范.md` §4.3。
|
||||
- **引用审查报告编号一律带文档名**(报告 N-16 ≠ 登记簿 N-16、报告 S-3 ≠ 登记簿 S-3);
|
||||
报告并轨项用本登记簿新编号(N-19~N-29 + U 簇),出处列保留报告编号。
|
||||
- **§2 是全项目唯一的推进顺序权威**:`产品需求设计文档.md` 等文档中的路线图只留指针,顺序变更只改 §2.0(详表文件跟着挪,不改顺序)。
|
||||
- **暂缓不是销项**:条目仍在簿,只是不占波次。有独立清单文件的(`暂缓-RS485.md` = B2)重启或关闭时更新该文件与 §1/§2.0;**只在原处标注的**(N-27 内存优化簇,2026-10-15 用户裁定,理由与重开条件在 `../内存管理/RAM使用分析与优化方案.md` §4)重启时改 `登记簿.md` 该行 + 本文件 §1/§2.0 三处。
|
||||
- 新增发现按既有惯例分流:能立即修的进 §2 波次(结构债);需排期的进 `登记簿.md` / `测试与架构专项.md` 对应编号空间;跨版本观察的进 `登记簿.md`。
|
||||
- 上游引用关系:`测试说明/实机测试实施指南.md`(执行流程)——不在本文件夹合并范围。
|
||||
1. **完成即删除待办条目**,同时清理其他文档对它的引用;结论和证据写入模块文档,
|
||||
历史由 `git log` 保留。
|
||||
2. **当前任务只改 `UI补齐.md`,后续事项只改 `登记簿.md`**;顺序变化才改本文件 §2。
|
||||
3. `数据可信.md` 的 §2、§4、§7~§10 仍被代码头注释引用为设计依据,不能按“已完成”
|
||||
删掉;其待办只认 §5 的三项。
|
||||
4. `测试与架构专项.md` 的断言与体积门禁章节仍是代码和门禁的规格锚点,即使事项已完成
|
||||
也不能删;当前未闭环的只有 RS-485 侧采集链路测试约束。
|
||||
5. 任务分支不直接修改 `docs/任务规划/**`;状态更新与销项由主工作树统一处理。
|
||||
6. 并行开发机制、工作树和锁的使用见 `docs/环境与部署/并行任务工作树方案.md`。
|
||||
本文件夹不再另维护一份分道、批次和写域方案。
|
||||
7. 暂缓不是完成:条目必须保留重启条件;没有重启条件的“以后再说”应写成观察项或删除。
|
||||
|
||||
+77
-112
@@ -1,124 +1,89 @@
|
||||
# UI 补齐(U5 页面落地 · 当前波次)
|
||||
# 当前任务:UI 补齐
|
||||
|
||||
> **一句话**:菜单树 33 个叶子已绑 12、剩 **21**;组件层三件套(数值编辑器 / 定值表 / 操作页)
|
||||
> 已落地但**零消费者**。本波按**数据源就绪度**把 21 叶分三梯队,先做零依赖的 9 叶。
|
||||
>
|
||||
> **本文定位**:本波次的任务卡与验收判据。**排序权威在 `docs/任务规划/README.md` §2**。
|
||||
> 逐页行表与代码改动量见 `docs/UI设计/页面扩充详细方案.md`;清单与就绪度见
|
||||
> `docs/UI设计/页面补齐规划.md`;数据供给契约见 `docs/UI设计/UI_数据供给设计说明.md`。
|
||||
>
|
||||
> **修订**:2026-10-25 建档(用户决定:下一波只做 UI 补齐,结构债押后;台架不在手边,
|
||||
> 卡 0 顺延)。统计口径 = **按菜单树叶计**(不按页面批次计),当前 33 叶已绑 12、剩 21。
|
||||
> **从第 1 项 `param_request` 写路径开始。完成它以后再绑定整定 4 页。**
|
||||
> 本文件是当前唯一执行清单;全项目顺序见 `docs/任务规划/README.md` §2。
|
||||
|
||||
## 1. 目标与范围
|
||||
|
||||
菜单树 33 叶,已绑 12 叶,未绑 21 叶:
|
||||
|
||||
| 分类 | 数量 | 当前怎么处理 |
|
||||
|---|---:|---|
|
||||
| 数据源已就绪 | 9 | 当前执行:整定 4 + 装置维护 3 + 遥测死区/系数 2 |
|
||||
| 需补配置或写入方 | 7 | 当前执行:通讯设置 1 + 记录 5 + 运行报告 1 |
|
||||
| 无开入硬件 | 3 | 不做:遥信类型、遥信防抖、双点遥信 |
|
||||
| 缺独立模块或产品定义 | 2 | 不做:手动录波、SNTP 设置 |
|
||||
|
||||
现有基础:`ui_w_editor` / `ui_w_setlist` / `ui_page_action` 已就绪;
|
||||
`ui_data` 的 rt / par / info 三通道已接线;像素黄金用例与字符集门禁已存在。
|
||||
**这些基础当前没有完整页面消费者,本任务就是把它们真正用起来。**
|
||||
|
||||
逐页形态见 `docs/UI设计/页面补齐规划.md`;数据契约见
|
||||
`docs/UI设计/UI_数据供给设计说明.md`。本文件只维护执行顺序和完成判据。
|
||||
|
||||
---
|
||||
|
||||
## 1. 现状(2026-10-25 代码级核对)
|
||||
## 2. 执行清单
|
||||
|
||||
| 项 | 数 | 说明 |
|
||||
> 状态只在这里维护。完成一项就删除对应行,并同步调整后续顺序;不要在本文件留完成史。
|
||||
|
||||
| 顺序 | 任务 | 完成判据 | 主要写范围 | 状态 |
|
||||
|---|---|---|---|---|
|
||||
| **1** | **`param_request` 写路径** | 实现 `ui_data_param_request/state`:深度 4 环形队列,满返 -1;状态含 `OK` / `ERR_RANGE` / `ERR_LOCKED` / `ERR_BUSY`;`ui_data_feed_tick()` 取出后调用 `prot_set_set_sealed()` 并置脏;主机单测覆盖满队列、越界、闭锁、正常往返 | `Drivers/BSP/UI/ui_data.*`、`App/app/ui_data_feed.*` | 未开始 |
|
||||
| **2** | **整定 4 页** | 参数、定值、控制字、软压板 4 叶绑定页面;就地修改并保存后,重启值保持且校验和通过;主站 `C_RD` 读到同值;越界行高亮且值不落盘;黄金用例入库 | `Drivers/BSP/UI/`、`ui_menu_tree.txt`、生成物 | 未开始 |
|
||||
| **3** | **装置维护 3 页** | 时钟设置写入 `sys_clock_set_unix()` 并回读;强制复归确认后动作位复归且有 SOE;清除记录先补 `sys_log` 删除 API,覆盖删后重建、计数归零、不存在时幂等 | `Drivers/BSP/UI/`、`App/log/sys_log.*` | 未开始 |
|
||||
| **4** | **遥测死区与系数 2 页** | 修改死区能改变 104 上送门限;修改 `k` 后页面值按比例变化;两页只走既有 `[run_par]` / `[adc_cal]` 落盘链,不新增真源 | `Drivers/BSP/UI/`、`ui_menu_tree.txt` | 未开始 |
|
||||
| **5** | **通讯设置** | 新建 `[comm]` 段承载公共地址、端口、主站地址;修改并重启后连接与公共地址生效;核对配置段数和键数上限 | `App/cfg/`、`App/protocol/iec104/`、`Drivers/BSP/UI/` | 未开始 |
|
||||
| **6** | **记录 5 页** | 事故、操作、保护告警、保护启动、遥控各有一个写入点和记录类型;可翻最近 20 条;空记录明确显示“无记录”;共用 reader | `App/log/`、`Drivers/BSP/UI/` | 未开始 |
|
||||
| **7** | **运行报告** | 展示上电次数、运行时长、复位原因、104 统计;复用 info 通道的已有数据;新计数器明确“掉电保持”或“本次运行”,不得含糊 | `App/log/` 或 `App/app/`、`Drivers/BSP/UI/` | 未开始 |
|
||||
|
||||
### 依赖关系
|
||||
|
||||
- 1 → 2 是硬依赖;3、4 虽可独立开发,但当前仍按表序单道执行。
|
||||
- 3 的“清除记录”包含 `sys_log` 删除 API,不允许只做一个没有实际效果的按钮。
|
||||
- 5 可先完成配置层再接页面,但最终必须作为一整项验收。
|
||||
- 6、7 先补真实写入方或计数器,再做页面;不允许用静态演示数据充数。
|
||||
|
||||
---
|
||||
|
||||
## 3. 数据源对照
|
||||
|
||||
| 页面 | 现有数据源 | 还缺什么 |
|
||||
|---|---|---|
|
||||
| 菜单树叶总数 | **33** | `ui_menu_tree.txt` 实际叶子(不含 9 个父节点) |
|
||||
| 已绑页面 | **12** | 装置信息 / 交流量 / 直流量 / 遥信量 / 查看 4 页 / 网口设置 / SOE / 自检记录 / 运行记录(明细见 `docs/UI设计/页面补齐规划.md`) |
|
||||
| 未绑叶子 | **21** | 见 §2 三梯队 |
|
||||
| 组件层 | **3 就绪** | `ui_w_editor` / `ui_w_setlist` / `ui_page_action` 均已落地,**当前无任何页面消费**——写了不用等于没写 |
|
||||
| 数据供给 | 3 通道 | `ui_data` 的 rt / par / info 三通道 + `ui_data_feed` 已接线 |
|
||||
| 黄金用例 | 18 页 | `ui-golden` 像素基线 + 字符集差集检查均已挂 pre-commit |
|
||||
|
||||
> ⚠ **未绑叶子 ≠ 空菜单项**:未绑的叶子按菜单树规则是"无内容页",进得去但只显示空框架。
|
||||
> 21 叶里 8 叶(整定 4 + 维护 3 + 通讯设置)**数据源已就绪**,只是没写页面;
|
||||
> 6 叶(遥信三页 + 记录 5 页中的 5 叶)**缺数据层或写入方**;1 叶(手动录波)缺模块。
|
||||
| 整定 4 页 | `prot_set` 31 项、`ui_w_editor` | 第 1 项写路径 |
|
||||
| 时钟设置 | `sys_clock_set_unix()` | 页面与回读校验 |
|
||||
| 强制复归 | `prot_elm_request_reset()`、`ui_page_action` | 页面与 SOE 留痕 |
|
||||
| 清除记录 | `sys_log` | 删除 API、确认交互 |
|
||||
| 遥测死区 / 系数 | `run_par`、`adc_cal` | 可编辑页面 |
|
||||
| 通讯设置 | 网口配置保存范式可复用 | `[comm]` 段及 104 消费 |
|
||||
| 记录 5 页 | SOE、自检、运行记录已有 reader 先例 | 五类写入方与记录类型 |
|
||||
| 运行报告 | `uptime_s`、复位原因已有 | 上电次数与 104 统计 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 三梯队(按数据源就绪度分,不按菜单顺序)
|
||||
## 4. 每页的统一完成动作
|
||||
|
||||
### 2.1 第一梯队:数据源已就绪(9 叶,可立即开工)
|
||||
1. 新增 `ui_page_xxx.c/.h`,优先复用现有组件。
|
||||
2. 在 `ui_menu_tree.txt` 对应叶子增加 ` #page=xxx`。
|
||||
3. 运行 `python tools/menu_gen/gen_menu.py`,检查生成物差异。
|
||||
4. 新文案先过字符集提取和字库生成,不能显示方块。
|
||||
5. 加像素黄金用例与必要的主机单测。
|
||||
6. 涉及保存、重启、主站读回的项目,台架可用后统一补做实机判据并留证。
|
||||
|
||||
| 叶 | 数据源 | 为什么现在能做 |
|
||||
**单写者约束**:`ui_menu_tree.txt`、页面注册表、字库生成物不得由多个分支同时修改。
|
||||
`MDK-ARM/*.uvprojx` 的新源文件注册按双端注册规则处理。
|
||||
|
||||
**保护闭锁必须可见**:整定页可以修改定值,但当前产品在 UA/UN/IA 未标定时保护判据闭锁。
|
||||
页面应显示该状态,不能让用户误以为“修改定值后保护就会动作”。口径见
|
||||
`docs/任务规划/数据可信.md` §4.3。
|
||||
|
||||
---
|
||||
|
||||
## 5. 当前不做
|
||||
|
||||
| 项目 | 不做原因 | 重开条件 |
|
||||
|---|---|---|
|
||||
| 参数 / 定值 / 控制字 / 软压板(整定 4 页) | `prot_set` 31 项 + `ui_w_editor` | 编辑器已落地;只缺**写路径**(UI 只投递 → `prot_set_set_sealed` → 置脏 → defaultTask 落盘) |
|
||||
| 时钟设置 | `sys_clock_set_unix()` | API 就绪,6 字段表单 + 回读校验 |
|
||||
| 强制复归 | `prot_elm_request_reset()` | 单字标志,任意上下文可投;`ui_page_action` 直接套 |
|
||||
| 清除记录 | `sys_log` | ⚠ **缺删除 API**(按 ID 删文件 + 重建 + 计数归零),需先补 ~40 行 |
|
||||
| 遥测死区 / 遥测系数(2 页) | `run_par`(9 键死区,卡 10)+ `adc_cal`(k/b,卡 2) | 两个数据层都已落地,页面只做可编辑列表 |
|
||||
|
||||
### 2.2 第二梯队:需先补数据层(4 叶,但只立 1 张卡)
|
||||
|
||||
> 遥信类型 / 防抖 / 双点这 3 叶**不立卡**——V0.1 没有开入硬件,三类配置没有可配的对象,
|
||||
> 做出来只是"改一组没人读的参数"。随开入固件(独立立项)一起做,见 §5。
|
||||
|
||||
| 叶 | 缺什么 |
|
||||
|---|---|
|
||||
| 通讯设置 | `[comm]` 段(104 公共地址 / 端口 / 主站地址)——当前编译期固定。照 `net_cfg` 的"RAM 副本 + 保存请求交接"范式 |
|
||||
| 遥信类型 / 遥信防抖 / 双点遥信(3 页) | 开入量本身不存在(V0.1 无开入硬件),三类遥信配置**没有可配的对象**。⚠ 这三页做出来只能是"改一组没人读的参数" |
|
||||
|
||||
### 2.3 第三梯队:需先立模块或补写入方(6 叶)
|
||||
|
||||
| 叶 | 缺什么 |
|
||||
|---|---|
|
||||
| 事故 / 操作 / 保护告警 / 保护启动 / 遥控记录(5 页) | 每类记录 = 一个写入点 + 一个 `syslog_id_t`。当前只有 SOE 与 selftest/run 三类有写入方 |
|
||||
| 运行报告 | 计数器:上电次数 / 104 统计;`uptime_s` 与复位原因**已有**(`ui_data_feed` 的 info 通道 + `app_main` 锁存) |
|
||||
|
||||
---
|
||||
|
||||
## 3. 任务卡(五字段;完成即销项删行)
|
||||
|
||||
> 资源图例:🔴 台架(COM6/ST-LINK,`bench.lock` 独占)· 🟡 外部 · 🟢 纯软件。
|
||||
> 状态:⬜ 未开始 · 🟦 进行中。**条目用语义标识,不新增字母+数字编号**
|
||||
> (规则见 `docs/任务规划/README.md` §0)。序栏只为阅读顺序。
|
||||
|
||||
| 序 | 任务 | DoD(可验证验收判据) | 硬依赖 | 资源 | 写范围 | 状态 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 1 | **`param_request` 写路径** | `ui_data_param_request/state` 落地:小环形队列(深度 4,满返 -1)+ 状态四值 `OK` / `ERR_RANGE` / `ERR_LOCKED` / `ERR_BUSY`;`ui_data_feed_tick()` 侧取出后调 `prot_set_set_sealed()` + 置脏;**主机单测覆盖**:满队列、越界拒绝(`bad_mask` 指出越界项)、闭锁态拒绝、正常往返 | `ui_data` 三通道(已落) | 🟢 | `Drivers/BSP/UI/ui_data.*` + `App/app/ui_data_feed.*` | ⬜ |
|
||||
| 2 | **整定 4 页** | 4 叶绑页面;就地改一条定值 → 保存 → **掉电重启后值保持且校验和自检通过**;主站 `C_RD` 读到同一值;越界时高亮越界行、页脚"越界"、值不落盘;黄金用例入库 | 1、`ui_w_editor`(已落) | 🟢 | `Drivers/BSP/UI/` + `ui_menu_tree.txt` + 生成物 | ⬜ |
|
||||
| 3 | **装置维护 3 页** | ① 时钟设置:写 `sys_clock_set_unix()` 后回读校验(RTC 慢墙钟 8 h 的现象要在证据里说明);② 强制复归:确认后 YX 动作位复归、SOE 有复归记录;③ 清除记录:选类型 → 确认 → 计数归零且文件重建(**先补 `sys_log` 删除 API**,单测覆盖删后重建/计数归零/不存在时幂等) | `ui_page_action`(已落);③ 需 `sys_log` 删除 API | 🟢 | `Drivers/BSP/UI/` + `App/log/sys_log.*` | ⬜ |
|
||||
| 4 | **遥测死区 / 系数 2 页** | 改死区 → 104 上送门限随之变化(PC 主站读回核对);改 `k` → 页面显示值按比例变化;两页都走 `[run_par]` / `[adc_cal]` 的既有落盘链,**不新增第三份真源** | `run_par` / `adc_cal`(均已落) | 🟢 | `Drivers/BSP/UI/` + `ui_menu_tree.txt` | ⬜ |
|
||||
| 5 | **通讯设置(`[comm]` 段)** | 新建 `[comm]` 段(公共地址 / 端口 / 主站地址);改后重启,主站仍能连上且公共地址生效;`CFG_FILE_MAX_KEYS` / 段数上限核对(当前 5/8 段) | — | 🟢 | `App/cfg/` + `App/protocol/iec104/` + `Drivers/BSP/UI/` | ⬜ |
|
||||
| 6 | **记录 5 页** | 每类记录一个写入点 + 一个 `syslog_id_t`;页面能翻到最近 20 条,空记录显示"无记录"而非空白;5 页共用一份 reader | — | 🟢 | `App/log/` + `Drivers/BSP/UI/` | ⬜ |
|
||||
| 7 | **运行报告** | 4 组:上电次数 / 运行时长 / 复位原因 / 104 统计;前两组与 info 通道一致,后两组新建计数器(掉电不丢则需落盘,否则页面标注"本次运行") | — | 🟢 | `App/log/` 或 `App/app/` + `Drivers/BSP/UI/` | ⬜ |
|
||||
|
||||
> **遥信三页(类型/防抖/双点)不立卡**:V0.1 无开入硬件,三类配置没有可配对象——
|
||||
> 做出来只是"改一组没人读的参数"。随开入固件(独立立项)一起做,见 §5。
|
||||
|
||||
---
|
||||
|
||||
## 4. 顺序与并行
|
||||
|
||||
```
|
||||
1 param_request 写路径 ─→ 2 整定 4 页
|
||||
3 装置维护 3 页(独立;③ 先补 sys_log 删除 API)
|
||||
4 遥测死区/系数 2 页(独立)
|
||||
↓ 第一梯队 9 叶
|
||||
5 通讯设置([comm] 段)→ 6 记录 5 页 → 7 运行报告
|
||||
```
|
||||
|
||||
- **单道串行**(2026-10-25 用户决定:本波只做 UI):`ui_menu_tree.txt` 与
|
||||
`ui_page_registry.c` 是**单写者生成物**,两条道并行会在菜单树与注册表上互相覆盖。
|
||||
一条道 = 零冲突;需要并行度时优先拆"数据层"与"页面层"(如 `[comm]` 段可先行)。
|
||||
- **每页标准动作**(已被生成器收敛成 3 处人工 + 1 条命令):写 `ui_page_xxx.c/.h` →
|
||||
菜单树加 ` #page=xxx` → 跑 `python tools/menu_gen/gen_menu.py` → 登记黄金用例。
|
||||
- **字符集**:新文案的汉字必须先过 `tools/font_gen/extract_cn.py` → `make_font.py`,
|
||||
否则显示方块(`font-charset` 门禁会拦)。40 条定值名建议沿用 2~4 字缩写
|
||||
("过流Ⅰ段定值"→"Ⅰ段定值")。
|
||||
- **台架**:本波 21 叶里只有整定 4 页与遥测 2 页需要上板验证(保存/重启/C_RD 回读)。
|
||||
台架不在手边时先做页面 + 黄金用例,**把上板项累积成一批,下次上机一次过**。
|
||||
|
||||
---
|
||||
|
||||
## 5. 范围边界(本波不做)
|
||||
|
||||
| 不做 | 理由 / 归属 |
|
||||
|---|---|
|
||||
| 遥信类型 / 防抖 / 双点(3 叶) | V0.1 无开入硬件;随开入固件独立立项(`docs/任务规划/并行分道方案.md` §4.2 的 L4-1~L4-3 同批) |
|
||||
| 手动录波(1 叶) | 录波模块未立项;且录波通道必须先有工程量(`docs/任务规划/数据可信.md` §9) |
|
||||
| SNTP 设置(1 叶) | 当前对时走 8888 端口私有协议,SNTP 是另一条链;产品口径亦未定。只做页面 = 又一个"看着能用其实不生效"的页 |
|
||||
| 结构债 / net 收口 | 用户决定(2026-10-25):本波只做 UI,结构债押后(`docs/任务规划/README.md` §2) |
|
||||
|
||||
---
|
||||
|
||||
## 6. 与其它波次的关系
|
||||
|
||||
| 波次 | 关系 |
|
||||
|---|---|
|
||||
| **数据可信** | 本波消费其产出:`ui_data` 的 `eng` 字段由 `adc_cal_flags()` 决定(现 `eng=0` = 引脚电压,卡 0b 拿到变比后才升 1);遥测死区页直接改 `run_par`。**保护当前处于未标定闭锁态**(`protect_task.c:98`),整定页可改定值但判据不会动作——页面须显示闭锁原因,不能让用户以为"改了没用" |
|
||||
| **采集保护收尾** | B10 送检不依赖 UI 页面;无交集 |
|
||||
| **结构债** | 押后;`sys_log` 删除 API 与日志管线同域,本波只补这一个 API,不动管线 |
|
||||
| 遥信类型 / 防抖 / 双点 3 页 | V0.1 无开入硬件,配置没有消费者 | 开入固件立项后,与开入开出一起做 |
|
||||
| 手动录波 | 录波模块不存在,且工程量口径尚未完成实测闭环 | 故障录波独立立项 |
|
||||
| SNTP 设置 | 当前使用 8888 私有对时协议,SNTP 链路与产品口径均未建立 | SNTP 客户端立项 |
|
||||
| net 层与其他结构债 | 当前只做 UI,避免两条主线互相拖慢 | UI 当前清单完成后,按 README §2 切换 |
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
# 待确认(开放问题清单)
|
||||
|
||||
> 本文件是 **OQ 族(待确认 / 开放问题)的属主登记处**,见 `docs/编号规范.md` §4.2。
|
||||
> **只放还没有答案的问题**——有答案的立刻删行,答案落进对应模块文档。
|
||||
> ⚠ 文件名沿用旧称「基线与待确认」,但**基线类内容已全部移出**:设计基线在模块文档里
|
||||
> (net pending 化 → `docs/网络/Net层阻塞模型架构设计.md` §10;错误码四要素 →
|
||||
> `docs/产品需求/产品需求设计文档.md` §7.1),内存数字的权威在 `docs/内存管理/RAM预算台账.md`。
|
||||
|
||||
## 1. 待确认
|
||||
|
||||
1. **功能裁剪门控是否要在真实初始化点接入**——原 `APP_ADC_ENABLE` / `APP_RS485_ENABLE` 占位宏
|
||||
已于 2026-10-22 删除(零消费点),当前没有任何开关。要确认的是**是否需要**在真实初始化点
|
||||
接入门控;B1 取数不依赖它。RS-485 侧随 B2 暂缓(`暂缓-RS485.md`)。
|
||||
|
||||
> RS-485 PD0 DE 的半双工方向语义确认不在此列——已登记在 `暂缓-RS485.md`「待确认-3」,随 B2 重启时一并做。
|
||||
@@ -1,238 +0,0 @@
|
||||
# 并行分道方案(待办归道 · 写域 · 合并次序)
|
||||
|
||||
> **本文只做三件事**:把未闭环待办**归到道**、划**文件级写域**、定**合并次序**。
|
||||
> **明细不复制**——DoD / 硬依赖 / 验收判据仍在 `docs/任务规划/登记簿.md`、
|
||||
> `docs/任务规划/UI补齐.md`、`docs/任务规划/数据可信.md`、`docs/任务规划/采集保护收尾.md`、
|
||||
> `docs/算法/继电保护功能复现规划.md`。机制(worktree / 两把锁 / `done` 流程)见
|
||||
> `docs/环境与部署/并行任务工作树方案.md`。
|
||||
>
|
||||
> **为什么需要它**:待办分散在 5 个文件、编号体系有 6 套,但"能不能并行"只取决于一件事——
|
||||
> **写域是否相交**。这个判断原先只散在每条任务卡的"写范围"列里,没有人横向拉通看过一遍。
|
||||
>
|
||||
> 修订:2026-10-23 建档(用户要求:把保护、ADC、UI、结构债的全部待办做并行分工)。
|
||||
|
||||
---
|
||||
|
||||
## 1. 一句话结论
|
||||
|
||||
> **当前只有一条编码道**:道E UI 补齐(21 叶,单道串行)。
|
||||
> 道F 结构债排批 4;道G 保护元件与道H 采集增强排批 5(等标准源 / 标定)。
|
||||
> 台架道空转(台架不在手边);外部窗口 = 卡 0 / 0b / 12、N-16、N-3、B10。
|
||||
|
||||
```
|
||||
批 3 道E UI 补齐(21 叶,单道串行) ← 当前
|
||||
↓
|
||||
批 4 结构债:net 收口(含饿死签名)∥ 白名单 ∥ 性能簇
|
||||
→ 「USART1 改为只发不收」独占一轮(CubeMX 重生成,清空全部工作树)
|
||||
↓
|
||||
批 5 道G 保护元件 V0.1 子集 ∥ 道H 采集增强 ← 等标准源 / V0.2 硬件
|
||||
台架/外部窗口:卡 0 / 0b / 12、N-16、N-3、B10
|
||||
```
|
||||
|
||||
**道名对照**(全文只用这 4 个标签):
|
||||
|
||||
| 道 | 名称 | 批 | 写域 |
|
||||
|---|---|---|---|
|
||||
| **道E** | UI 页面(21 叶补齐) | **3(当前)** | 域5 |
|
||||
| **道F** | 结构债与网络(net 收口 / 白名单 / 性能簇 / USART1) | 4 | 域6+域7 |
|
||||
| **道G** | 保护元件扩展(V0.1 子集) | 5(等标准源) | 域3+域2 |
|
||||
| **道H** | 采集增强(等周波/零序/谐波轨) | 5(等标定) | 域1+域3 |
|
||||
|
||||
**关键判断**:用户最关心的"保护待做"**大部分不能与标定并行**——因为保护元件的判据全是
|
||||
"与定值比",而定值是工程单位(10 A / 120 V),标定没落地时新元件写出来就是"码值比二次值",
|
||||
和现在 `prot_elm` 的错配是同一个病。真正能提前的只有**比值类判据**(涌流制动、CT 断线、
|
||||
突变量启动),但它们要往 `prot_set` 里加定值项 → 改 `PS_ID_COUNT` 与 blob VER → 与「数据可信」
|
||||
的落盘/闭锁卡互斥。**所以保护整簇排在「数据可信」之后**(批 5,等标准源),逐项归道见 §4.2。
|
||||
|
||||
---
|
||||
|
||||
## 2. 硬约束(决定"最多能切多细")
|
||||
|
||||
| # | 约束 | 出处 | 对分道的含义 |
|
||||
|---|---|---|---|
|
||||
| 1 | **同时最多 3 棵工作树** | `docs/环境与部署/并行任务工作树方案.md` §4 | 并发上限 3,不是想切几条切几条 |
|
||||
| 2 | **`@build` 必须串行**(UV4 不能两个实例同时 `-b`) | `并行任务工作树方案.md` §7.2 | 三条道能**同时编码**,构建排队;增量 4~5 s,不是瓶颈 |
|
||||
| 3 | **台架必须串行**(COM6 / ST-LINK / 192.168.1.100 各一份) | `并行任务工作树方案.md` §7.1 | 真正的瓶颈。台架道单列,跑在主工作树、不占工作树名额 |
|
||||
| 4 | **单写者文件**:`docs/任务规划/**`、`AGENTS.md` 任务表块、`MDK-ARM/*.uvprojx`、`.pre-commit-config.yaml`、内存快照 | `并行任务工作树方案.md` §6.1 | 任务分支不碰登记簿;uvprojx 手工并;内存数字合并后重生成 |
|
||||
| 5 | **分支存活 ≤2 天、绿即合** | `并行任务工作树方案.md` §7.3 规则 3 | 一条道不是一条长分支,是**连续若干个短分支** |
|
||||
| 6 | **`done` 只能在主工作树、必须串行** | `.dsh/skills/task-worktree/SKILL.md` 铁律 1 | 合并不是并行的,只能排队 |
|
||||
| 7 | **CubeMX 重生成会打回手工定制**(需跑 `check_cubemx_survival.py`) | `docs/任务规划/排期详述.md` §1「USART1 改为只发不收」 | 该任务**独占**,不能与任何分支并存 |
|
||||
| 8 | **`check_layer_deps.py` 基线只减不增** | `scripts/check_layer_deps.py` | 谁减基线谁写这个文件——只能有一条道写 |
|
||||
|
||||
> 约束 1 与 3 合起来给出真正的并行度:**3 条编码道 + 1 条台架道**,台架道跑在主工作树里,
|
||||
> 不额外占工作树名额(它验证的是已合入的镜像)。
|
||||
|
||||
---
|
||||
|
||||
## 3. 写域划分(域1~域8)
|
||||
|
||||
> 划道的唯一依据。**同一域同时只能有一条道在写**;跨域任务必须拆成两张卡或声明合并次序。
|
||||
|
||||
| 域 | 文件(glob) | 典型归属 |
|
||||
|---|---|---|
|
||||
| **域1 采集与算法** | `App/algo/*`(`adc_cal.*` / `meas.*` 新增)、`App/task/adc_task.c`、`test/host/adc_*/` | 标定、遥测快照、采集增强 |
|
||||
| **域2 定值与配置** | `App/algo/prot_set.*`、`App/algo/run_par.*`(新增)、`App/cfg/*`、`test/host/cfg_file/` | 定值表、配置引擎、运行参数段 |
|
||||
| **域3 保护元件与出口** | `App/algo/prot_elm.*`、`App/algo/freq.*`、`App/task/protect_task.c`、`App/algo/prot_do.*`(新增) | 保护判据、出口、闭锁 |
|
||||
| **域4 104 上行** | `App/protocol/iec104/*`、`App/task/iec104_serv.c`、`test/host/iec104/` | 点表、死区、频率点、运行参数映射 |
|
||||
| **域5 UI** | `Drivers/BSP/UI/*`、`ui_menu_tree.txt`、`tools/menu_gen/*`、`tools/font_gen/*`、`ui_cn_chars.txt`、`App/app/ui_data_feed.*`(新增) | 页面、组件、数据供给、字库 |
|
||||
| **域6 存储与日志** | `App/log/*`、`App/fs/*`、`Lib/dhara/*` | 写回 flush、日志管线、卷锁 |
|
||||
| **域7 网络** | `Drivers/BSP/NET/*`、`Drivers/BSP/NETCFG/*`、`App/task/net_task.c`、`App/sync/*` | net 收口、探针缺口、PHY |
|
||||
| **域8 工具链与门禁** | `test/host/**`(各道新增子目录除外)、`scripts/*`、`.gitea/*`、`.pre-commit-config.yaml` | 单测、CI、断言宏、门禁 |
|
||||
|
||||
**跨域但必须独占的两个文件**:
|
||||
|
||||
| 文件 | 为什么独占 | 处理 |
|
||||
|---|---|---|
|
||||
| `MDK-ARM/STM32F407-Demo.uvprojx` | 每条新增 `.c` 都要注册,UV4 构建时还会自动改写 | 任务分支照常加 `<File>`,`done` 时**手工并条目** → 跑 `registration-check` → `@build` |
|
||||
| `docs/内存管理/RAM使用分析与优化方案.md` | `mem-numbers` 快照 | **绝不手工合数字**;每次 `done` 后 `scripts/check_mem_numbers.py --write` 重生成 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 全量待办归道
|
||||
|
||||
> 覆盖 `docs/任务规划/` 全部未闭环项 + 保护复现规划 L 项 + UI 两篇规划。
|
||||
> "批"列 = 第几轮开工;`—` = 现在不排(理由见 §8)。
|
||||
|
||||
### 4.1 数据可信(剩 3 卡)
|
||||
|
||||
| 条目 | 写域 | 道 | 批 |
|
||||
|---|---|---|---|
|
||||
| 卡 0 已知电压注入验证 | 台架 + 文档 | **台架道** | 顺延(等台架) |
|
||||
| 卡 0b 端子/子板变比确认 | 台架 + 文档(🟡 外部) | **台架道** | 顺延(等子板) |
|
||||
| 卡 12 8 通道两点标定 | 台架(🟡 标准源) | **台架道** | 顺延(等标准源) |
|
||||
|
||||
> 三张全是台架或外部资源,**不占编码道**;台架不在手边 → 整体顺延
|
||||
> (`docs/任务规划/数据可信.md` §5)。顺序:0 → 0b → 12。
|
||||
|
||||
### 4.2 保护待做(L 项)
|
||||
|
||||
| 条目 | 判据是否依赖工程量 | 写域 | 道 | 批 |
|
||||
|---|---|---|---|---|
|
||||
| L3-7 涌流制动(二次谐波占比) | **否**(比值) | 域3 + 域2(加定值) | **道G 保护** | 5(等标准源) |
|
||||
| L3-9 CT 断线(电流不平衡) | **否**(比值) | 域3 + 域2 | **道G 保护** | 5(等标准源) |
|
||||
| L3-11 故障启动(突变量) | **否**(相对量) | 域3 + 域2 + 新 `prot_start.*` | **道G 保护** | 5(等标准源) |
|
||||
| L3-8 PT 断线 | **是**(电压阈值) | 域3 + 域2 | **道G 保护** | 5(等标准源) |
|
||||
| L3-12 无压/无流闭锁 | **是** | 域3 + 域2 | **道G 保护** | 5(等标准源) |
|
||||
| L3-10 母线接地告警 | **是** | 域3 + 域2 | **道G 保护** | 5(等标准源) |
|
||||
| L5-1 残余(元件级校验和常量表) | 否 | 域2 + 域3 | **道G 保护** | 5(等标准源) |
|
||||
| L5-3 硬件自检 | 否(但需出口硬件) | 域3 | **道G 保护** | 5(等标准源) |
|
||||
| L4-1 跳闸出口 / L4-2 告警出口 / L4-3 出口自检 | 否 | 新模块 `prot_do.*` | **独立立项** | — |
|
||||
| L1-7 等周波调频 | 是(依赖标定后幅值) | 域1 + 域3 | **道H 采集增强** | 5(等标定) |
|
||||
| L1-8 零序通道接入 | 是 | 域1 | **道H 采集增强** | 5(等标定) |
|
||||
| L2-8 遥测谐波轨 | 是 | 域1(`phasor`) | **道H 采集增强** | 5(等标定) |
|
||||
| L3-2 零序过流 / L2-5 线·负序·零序合成 | — | 域1 + 域3 | **V0.2 硬件** | — |
|
||||
| L4-6 故障录波 | — | 新子系统 | **独立立项** | — |
|
||||
|
||||
> **为什么 L4-1~L4-3 是独立立项而不是一条道**:固件里**完全没有开入/开出代码**
|
||||
> (`docs/问题记录/采集与数据处理短板评测.md` 登记),出口要驱动 U18 桥 + 继电器,
|
||||
> 是一整个模块(GPIO 安全默认电平 + 出口保持/脉冲 + 回读自检),量级与"加一个元件"不同。
|
||||
|
||||
> **为什么道G 整簇押后到批 5(2026-10-25 复核)**:表里 10 项只有 4 项在 V0.1 上可行
|
||||
> (L3-7 A 相涌流制动 / L3-11 突变量启动 / L3-12 无压无流闭锁 / L5-1 元件级校验和)——
|
||||
> L3-8 PT 断线、L3-9 CT 断线要三相同时刻,被 N-18 硬件缺陷挡死;L3-10 母线接地只有电压侧可判;
|
||||
> L5-3 硬件自检要出口硬件。而这 4 项**没有标准源就无法验证**,加上保护现处于未标定闭锁态,
|
||||
> 写出来只能"建接口不使能"。**等标准源到位或 V0.2 硬件改版后再开**。
|
||||
|
||||
### 4.3 UI(批 3 唯一在跑的道)
|
||||
|
||||
**剩余 21 叶按数据源就绪度分三梯队**(明细与 DoD 见 `docs/任务规划/UI补齐.md`):
|
||||
|
||||
| 梯队 | 条目 | 叶数 | 写域 | 前置 |
|
||||
|---|---|---|---|---|
|
||||
| **一** | `param_request` 写路径 → 整定 4 页 · 装置维护 3 页(时钟/复归/清除记录)· 遥测死区/系数 2 页 | 9 | 域5 + `App/app/` + `App/log/`(仅补删除 API) | 组件层已就绪;清除记录需 `sys_log` 删除 API |
|
||||
| **二** | 通讯设置(`[comm]` 段)· 遥信类型/防抖/双点 3 页 | 4 | 域2 + 域4 + 域5 | `[comm]` 段不存在;遥信三页**无开入硬件,不立卡** |
|
||||
| **三** | 记录 5 页(事故/操作/告警/启动/遥控)· 运行报告 | 6 | 域6 + 域5 | 记录写入方 / 计数器不存在 |
|
||||
| **不排** | 手动录波(缺录波模块)· SNTP(对时是另一条链) | 2 | — | — |
|
||||
|
||||
> **为什么批 3 只有一条道**:`ui_menu_tree.txt` 与 `ui_page_registry.c` 是**单写者生成物**,
|
||||
> 两条道并行会在菜单树与注册表上互相覆盖;`uvprojx` 也要逐条手工并。单道串行 = 零冲突,
|
||||
> 而 UI 是当前唯一在跑的波次,并行度换来的收益抵不过合并成本。
|
||||
|
||||
### 4.4 结构债、验证与其它
|
||||
|
||||
| 条目 | 写域 | 道 | 批 |
|
||||
|---|---|---|---|
|
||||
| **net 层跨上下文收口**(E-27 / E-28 裸指针收口 + reconcile 饿死签名) | 域7 | **道F 结构债** | 4 |
|
||||
| N-25 性能与语义簇(PASV / PHY / SOCKETS) | 域7 | **道F 结构债** | 4 |
|
||||
| S-4 dhara 重试自旋 · S-5 全序列卷锁评估 | 域6 | **道F 结构债** | 4 |
|
||||
| N-23 注册校验白名单清理(只剩 `rs485_task.c`,随 B2) | 域8 | **道F 结构债** | 4(或随 B2) |
|
||||
| **USART1 改为只发不收**(S-3) | `.ioc` + `Src/*`(重生成) | **独占** | 4(清空全部工作树后单独一轮) |
|
||||
| **L5 队列往返基线重锁**(N-3) | 无码(需 PC peer) | **台架道** | 窗口 |
|
||||
| **A2/A4 负向台架**(N-16) | 无码 | **台架道** | 窗口 |
|
||||
| **串口助手 A6/A7 补验** | 无码(需 CH340) | **台架道** | 待硬件 |
|
||||
| B10 送检(标准源 + 第三方主站) | 无码 | **外部窗口** | Fixed Date |
|
||||
| T-7 CI runner | 外部基础设施 | **外部** | 待 runner |
|
||||
| 道G 保护元件 V0.1 子集 · 道H 采集增强 | 域1+域3 | **道G / 道H** | 5(等标准源 / 标定) |
|
||||
| N-30 relisten 收口 / N-28 空 TU / N-29 `.git` / N-18 V0.2 / N-27 内存簇 / B2 RS-485 / 开入开出 / 录波 | — | **不排** | — |
|
||||
|
||||
---
|
||||
|
||||
## 5. 每次 `done` 的固定动作
|
||||
|
||||
1. `done <ID> --dry-run` 预演(`git merge-tree`,rc≠0 就先在任务分支解冲突)
|
||||
2. `done <ID>`:合入 → 并集残留审计(三方对比,不用 `tail` 目测)→ 重生成产物 → 门禁
|
||||
3. 主工作树补:销项删行(`docs/任务规划/` 各文件)→ `AGENTS.md` 任务表重生成 → 内存快照重生成
|
||||
4. `@build` 0/0 + 台架 `@test`(若该道改了行为)
|
||||
|
||||
---
|
||||
|
||||
## 6. 三件"看起来能并行、实际不能"的事
|
||||
|
||||
| 事项 | 为什么不能并行 | 正确做法 |
|
||||
|---|---|---|
|
||||
| **USART1 改为只发不收**(S-3) | 改 `.ioc` → CubeMX 重生成会**打回 5 处手工定制**(IWDG 延迟启动、Fault Handler、FreeRTOSConfig 加固区等),且重写 `Src/*` 大片生成文件 → 与任何分支必冲突 | **独占一轮**:清空所有工作树 → 在主工作树做 → `check_cubemx_survival.py` 全过 → 台架闭环 |
|
||||
| **字库重生成** | `make_font.py` 重写 `ui_font_cn_12.c`(整文件生成物),两人同时扩字会互相覆盖 | 归道E 一个分支独占;后续加字必须重新走一次 |
|
||||
| **往 `prot_set` 加定值项** | 改 `PS_ID_COUNT` → blob VER 2→3 → 影响落盘格式、104 定值段、UI 整定页分组 | 只在**没有任何定值卡在飞**的时候做(批 5 的道G);⚠ 整定 4 页(批 3)会改 `prot_set` 的读写路径,**道G 必须在它之后** |
|
||||
|
||||
---
|
||||
|
||||
## 7. 执行清单(批 3 起步)
|
||||
|
||||
```powershell
|
||||
$PY = ".venv\Scripts\python.exe"
|
||||
$WT = ".dsh\skills\task-worktree\scripts\task_worktree.py"
|
||||
|
||||
# 先确认没有残骸占名额(当前有一棵:D:/Code/DTU Code/_wt/v5tool2-v11,分支已合入)
|
||||
& $PY $WT list
|
||||
|
||||
# 批 3 道E:单道串行,一次只开一棵工作树(菜单树/注册表是单写者生成物)
|
||||
& $PY $WT new UI-param write # param_request 写路径(无页面,先落通道)
|
||||
& $PY $WT new UI-set edit # 整定 4 页
|
||||
& $PY $WT new UI-maint pages # 装置维护 3 页(含 sys_log 删除 API)
|
||||
& $PY $WT new UI-cal par # 遥测死区 / 系数 2 页
|
||||
```
|
||||
|
||||
> ⚠ **`new` 必须给两个参数**(`<ID> <slug>`),少一个直接 rc=3;**ID 不能重复**——
|
||||
> 台账是 `.state/<ID>.json`,同 ID 第二次 `new` 会报"任务已存在"。分支名是
|
||||
> `task/<ID>-<slug>`(上面四段即 `task/UI-param-write` / `task/UI-set-edit` / …)。
|
||||
>
|
||||
> ⚠ **活跃任务数按"台账 + 目录是否存在"统计**,不是按 git 注册表。遗留目录会让名额被白占——
|
||||
> 开工前先 `list` 确认没有 `<ID>` 显示 `? ?`(那是分支已删、目录还在的残骸)。
|
||||
> 处置:`& $PY $WT abort <ID>`;若该目录的 `.git` 已失效,`abort` 会停在
|
||||
> `失败:移除工作树失败:fatal: '<path>' is not a working tree`(git 已不认识它),
|
||||
> 此时脚本**不会**替你 `rmtree`,退化为"删目录 + 删 `.state/<ID>.json`"两件事,
|
||||
> 删完补一条 `git worktree prune`。
|
||||
> **删前先确认目录里没有联接**(`.venv` / `simulator/SDL2`)——直接删会把主工作树的 `.venv` 带走。
|
||||
|
||||
> 分支 ID 用语义 slug(`UI-set-edit` / `cal-scale-doc`),与 `docs/任务规划/README.md` §0 的
|
||||
> "新条目用语义标识"一致;存量编号(N-x / S-x)仍可直接当 ID 用。
|
||||
|
||||
---
|
||||
|
||||
## 8. 现在不排的(避免误以为漏了)
|
||||
|
||||
| 项 | 状态 | 重开条件 |
|
||||
|---|---|---|
|
||||
| B2 RS-485 整簇(含 E-49/E-50、A-4 RS485 侧、N-25 DE 项、待确认-3) | ⏸ 用户决定 2026-10-12 暂缓 | 见 `docs/任务规划/暂缓-RS485.md` |
|
||||
| N-27 内存优化簇剩余(原报告 R-2 后半 / R-3 / R-4 / R-6) | ⏸ 用户裁定 2026-10-15 | `docs/内存管理/RAM使用分析与优化方案.md` §4 |
|
||||
| N-29 `.git` 233 MB | 决策:登记观察 | 推送/协作前重评 |
|
||||
| N-18 V0.2 硬件改版 | 下一版硬件 | 硬件改版立项 |
|
||||
| **道G 保护元件 V0.1 子集**(A 相涌流制动 / 突变量启动 / 无压无流闭锁 / 元件级校验和) | ⏸ 等标准源(2026-10-25 复核) | 标准源到位 **或** V0.2 硬件改版;且保护须先解卡(当前未标定闭锁,`protect_task.c:98`) |
|
||||
| **道H 采集增强**(L1-7 等周波 / L1-8 零序 / L2-8 谐波轨) | ⏸ 等标定 | 卡 12 两点标定完成(幅值类判据依赖工程量) |
|
||||
| **遥信类型 / 防抖 / 双点 3 页** | ⏸ 无开入硬件 | 开入固件立项(与 L4-1~L4-3 出口同批) |
|
||||
| **SNTP 设置页** | ⏸ 对时是另一条链 | SNTP 客户端立项(当前走 8888 私有协议) |
|
||||
| N-30 relisten 收口 | 观察(原语版实测回退) | 三条语义前置满足后 |
|
||||
| 原报告 F-5 空 TU(N-28 簇) | 观察 | 有全量构建耗时痛点时 |
|
||||
| T-7 CI runner | 外部基础设施 | runner 就绪 |
|
||||
| 串口助手 A6/A7 补验 | 待硬件 | CH340 到位 |
|
||||
| 开入/开出固件、故障录波 + 104 文件传输 | 独立立项 | 产品定义 / 单独立项 |
|
||||
@@ -1,35 +0,0 @@
|
||||
# 结构债与验证常态
|
||||
|
||||
> 波次总览与顺序权威在 `docs/任务规划/README.md` §2;当前波次任务卡在 `UI补齐.md`,
|
||||
> 「数据可信」已转收口态(`数据可信.md`),「采集保护收尾」只剩 M3 送检(`采集保护收尾.md`)。
|
||||
> 本文件只放**已排期但非当前波次**的详述表——低频改动,随窗口更新。
|
||||
>
|
||||
> **结构债整体押后**(2026-10-25 用户决定:下一波只做 UI 补齐)。押后不等于降级:
|
||||
> 它**没有外部依赖、随时能捡起来**,这正是它让位给 UI 的原因——UI 那 21 叶一旦等台架就卡死,
|
||||
> 结构债不会。
|
||||
>
|
||||
> **条目一律用语义名**(2026-10-25 起):原先「C 组短码」(结构债 1/3/5/6)与「D 组短码」
|
||||
> (验证窗口 2/5/6/7)已废止。原因是它们**同字母不同义**——`C` 组在
|
||||
> `docs/UI设计/UI_界面制作流程.md` 里是 UI 设计约束(屏幕/字符集/文本/编码),`D` 组在
|
||||
> `docs/子系统设计/控制台单写者日志设计说明.md` 与 `docs/子系统设计/配置文件设计说明.md`
|
||||
> 里是决策记录。同一个短码在三处指三件事,读的人只能猜。
|
||||
|
||||
## 1. 结构债(按性价比排序)
|
||||
|
||||
> 顺序 = 先灭实测缺陷,后可靠性根治,再大体量重构;评估簇随窗口。
|
||||
|
||||
| 条目 | 内容 | 出处 |
|
||||
|---|---|---|
|
||||
| **net 层跨上下文收口(含 reconcile 饿死签名)** | 两件事同批做:① 裸指针收口为状态查询 API(E-27 / E-28);② **对时 reconcile/relisten 突发把 uiTask 压成 800 ms+ 单串缺席**——2026-10-25 台架两轮分箱定案:同负载换 `:7003` churn 2200 周期 stall=0(阻塞型已被 F3 治愈),探针轮 3 事件 8 行全为该签名(漏检零、误报零)。处置两案并评:优先级矩阵复核 ∥ reconcile 突发分片让路 | E-27 / E-28;`../网络/网络自愈架构设计.md` §4.6;`../子系统设计/看门狗设计说明.md` §11.3 |
|
||||
| **USART1 改为只发不收**(独占一轮) | 灭 ORE 僵尸机制根源(2026-10-02 台架 IWDG 误复位的机制根源):改 `.ioc` 令 USART1 不使能 RX / PA10 不复用为 `USART1_RX` → CubeMX 重生成 → 跑 `check_cubemx_survival.py`。结构性改动,**需清空全部工作树后独占一轮** + 复跑台架闭环 | S-3 |
|
||||
| **注册校验白名单清理** | 剩余动作:清 `KNOWN_GAPS` 白名单(现只剩 `App/task/rs485_task.c`,见 `登记簿.md`)。**RS-485 DE 收尾已移入 `暂缓-RS485.md`** | N-23 残余 |
|
||||
| **性能与语义簇 · 空 TU 观察** | 两项随窗口评估,逐项见 `登记簿.md` 对应行 | N-25 / N-28 |
|
||||
| **dhara 重试自旋 · 全序列卷锁** | 两项低优先,先确认是否真有第二写者/是否再出"存储侧喂狗饥饿" | S-4 / S-5 |
|
||||
|
||||
## 2. 验证常态(逢窗口顺带,不单独排期)
|
||||
|
||||
| 条目 | 内容 | 出处 |
|
||||
|---|---|---|
|
||||
| **L5 队列往返基线重锁** | 下次 Phase 13 窗口顺带做(低风险:阈值余量 >8×;**需 PC peer**) | N-3 |
|
||||
| **A2/A4 负向台架窗口** | PHY 拔线(需断 DTU 侧 / 关受管交换机端口)、A2 芯片级 `net_init` 失败(SPI 故障注入)、A4 短写压测 | N-16 |
|
||||
| **串口助手 A6/A7 正路径补验** | 需 CH340 硬件接入后补验(`../测试说明/串口助手设计说明.md` 状态行 A1–A5/A8 已过) | — |
|
||||
+15
-14
@@ -1,10 +1,11 @@
|
||||
# 数据可信(通道标定 → 遥测链 → 运行参数)
|
||||
# 数据可信(等待台架与外部资源)
|
||||
|
||||
> **一句话结论**:软件侧已收口,**只剩三张卡**——卡 0 已知电压注入(万用表)→ 卡 0b 端子变比
|
||||
> (子板)→ 卡 12 标准源两点标定。三张全是台架或外部资源,**没有软件道可做**。
|
||||
> **台架不在手边(2026-10-25 确认)→ 本波整体顺延**,不占编码道,当前波次在 `UI补齐.md`。
|
||||
> **只想知道要做什么:直接看 §5。** 当前只剩三项:卡 0 已知电压注入(万用表)→
|
||||
> 卡 0b 端子变比(子板)→ 卡 12 标准源两点标定。它们都等待台架或外部资源,
|
||||
> **当前不占编码道;现在做 UI,见 `UI补齐.md`。**
|
||||
>
|
||||
> **本文定位**:本波次剩余的验收判据 + **设计权威**。**排序权威在 `docs/任务规划/README.md` §2**。
|
||||
> **本文同时是设计约束的归属文件,不是纯任务卡。** 排序只看
|
||||
> `docs/任务规划/README.md` §2;后续事项统一索引在 `登记簿.md` §7。
|
||||
> ⚠ §2.1 / §2.3 / §2.6 / §4.1~§4.5 / §7 / §8 / §9 / §10 与卡 0 / 0b / 12 都被**代码头注释**引用为
|
||||
> 口径出处(`adc_cal.*` / `meas.*` / `cfg_file.*` / `prot_elm` / `protect_task.c` / `ui_data*`)——
|
||||
> 它们是现行规范、不是"已完成记录",不要当历史删掉。上游分析见
|
||||
@@ -124,8 +125,8 @@ int32 上限 2.15×10⁹,`k` 最大可表达 32767 µV/码,远大于实际
|
||||
|
||||
### 4.2 三态可用性:标定 ≠ 可测
|
||||
|
||||
`k` 默认值是**板级理论系数**,此时工程量单位是"**端子电压**",不是二次值——因为还缺
|
||||
互感器/子板变比。所以通道状态必须能区分三档,不能让消费者把端子电压当二次值:
|
||||
`k` 默认值是**板级理论系数**,此时工程量单位是"**ADC 引脚电压**",不是二次值——因为还缺
|
||||
互感器/子板变比。所以通道状态必须能区分三档,不能让消费者把引脚电压当二次值:
|
||||
|
||||
```c
|
||||
#define ADC_CAL_F_VALID 0x01u /* 该通道 k 已按变比标定 → 工程量为二次值 */
|
||||
@@ -143,7 +144,7 @@ UI 快照的 `qds`)。
|
||||
|
||||
### 4.3 未标定即闭锁(本波唯一的行为变更)
|
||||
|
||||
保护判据拿"端子电压"跟"二次值定值"比,必然误动作。所以 M4 必须让
|
||||
保护判据拿"ADC 引脚电压"跟"二次值定值"比,必然误动作。所以 M4 必须让
|
||||
`protect_task` 多一个闭锁源:**UA/UN/IA 的 `VALID` 位未全置位 → 判据停走**。
|
||||
|
||||
- 与 L5-4 采样故障闭锁同构(`PROT_HF_LOCK_MASK` 那一套),不新增机制。
|
||||
@@ -184,7 +185,7 @@ typedef struct {
|
||||
uint32_t tick_ms;
|
||||
uint8_t valid; /* 整帧有效 */
|
||||
uint8_t rsv[3];
|
||||
float yc[9]; /* 工程量(二次值或端子电压,由 flags 决定) */
|
||||
float yc[9]; /* 工程量(二次值或 ADC 引脚电压,由 flags 决定) */
|
||||
uint16_t qds[9]; /* 每点品质:IV / NT / OV / CLIPPED */
|
||||
uint8_t freq_valid;
|
||||
float freq_hz;
|
||||
@@ -280,11 +281,11 @@ typedef struct {
|
||||
|
||||
---
|
||||
|
||||
## 10. 与其它波次的关系
|
||||
## 10. 与其它工作的关系
|
||||
|
||||
| 波次 | 关系 |
|
||||
| 工作 | 关系 |
|
||||
|---|---|
|
||||
| **采集保护收尾** | 该波的 B10 送检卡里"L1-5 标定复核"依赖本波卡 12;本波是 B10 的前置 |
|
||||
| **UI 扩展** | 本波交付 `meas_snap_t` + `adc_cal_flags()` → 「UI 扩展」的 `ui_data_rt_t` 才能填 `eng`:现为 0 = 引脚电压,卡 0b 拿到变比后才升 1 = 二次值,交流量页"标定状态"才有真值。**「UI 扩展」已开工**(当前波次 `UI补齐.md`),不必等卡 0b |
|
||||
| **送检验收** | 标准源送检的标定复核依赖本波卡 12;验收索引见 `登记簿.md` §7 |
|
||||
| **UI 补齐** | 已交付的 `meas_snap_t` + `adc_cal_flags()` 供 `ui_data_rt_t` 填 `eng`:现为 0 = 引脚电压,卡 0b 拿到变比后才升 1 = 二次值,交流量页"标定状态"才有真值。当前 UI 任务见 `UI补齐.md`,不必等卡 0b |
|
||||
| **结构债** | 无交集 |
|
||||
| **N-18(V0.2 硬件改版)** | 本波的 `CLIPPED` 位就是 N-18 在软件里的可见形态;V0.2 改版后该位恒 0,页面与 104 绑定零改动 |
|
||||
| **双转换器无共同采样触发(V0.2 硬件改版)** | 本波的 `CLIPPED` 位就是「双转换器无共同采样触发」在软件里的可见形态;V0.2 改版后该位恒 0,页面与 104 绑定零改动 |
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# 暂缓:RS-485 整簇(用户决定,2026-10-12)
|
||||
|
||||
> **当前没有处理 RS-485 的打算**,以下条目整体冻结、不占波次;**重启 B2 时先回本文件评估前置,勿直接开工**。
|
||||
> 本文件**不是销项**:条目仍在簿,只是不占波次(`docs/任务规划/README.md` §3 维护约定)。
|
||||
> **当前没有处理 RS-485 的打算**,以下条目整体冻结、不占执行队列;**重启 B2 时先回本文件评估前置,勿直接开工**。
|
||||
> 本文件**不是销项**:条目仍在簿,只是暂缓(`docs/任务规划/README.md` §3 维护约定)。
|
||||
|
||||
| 项 | 内容 | 重启时的前置 |
|
||||
|---|---|---|
|
||||
| **B2** | **RS-485 采集链路实现**(消化 E-50、E-49):双缓冲 + 序号(防包撕裂)+ DE 收尾(超时路径等 TC)+ ModBus RTU 状态机(`App/protocol/` 正是为此预留) | **E-59 门禁尚未满足**:先修 E-50(单缓冲包撕裂)、E-49(TX 超时拉 DE 未等 TC),修完驱动契约才允许接消费者 |
|
||||
| E-49 | RS485 DE 收尾(原属结构债一档剩余,已移出) | 同上 |
|
||||
| A-4 RS485 侧 | 采集链路测试可验证性约束(双缓冲 + 序号、DE 超时路径覆盖,`测试与架构专项.md` §2.2) | 随 B2 设计文档落地 |
|
||||
| **B2** | **RS-485 采集链路实现**:双缓冲 + 序号(防包撕裂)+ DE 收尾(超时路径等 TC)+ ModBus RTU 状态机(`App/protocol/` 正是为此预留) | **RS-485 接线门禁尚未满足**:先修单缓冲包撕裂、TX 超时拉 DE 未等 TC 两条,修完才允许接消费者 |
|
||||
| RS485 DE 收尾 | RS485 DE 收尾(原属结构债一档剩余,已移出) | 同上 |
|
||||
| 采集链路测试可验证性约束 · RS485 侧 | 双缓冲 + 序号、DE 超时路径覆盖,`测试与架构专项.md` §2.2) | 随 B2 设计文档落地 |
|
||||
| 待确认-3 | RS-485 PD0 DE 半双工方向语义硬件实测确认(本次仅静态审查) | 需硬件实测窗口 |
|
||||
| N-25 中 DE 项 | `HAL_Delay(1)` 阻塞 DE | 随 B2 |
|
||||
| 网络性能资源建议簇中 DE 项 | `HAL_Delay(1)` 阻塞 DE | 随 B2 |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 测试与架构改进专项(P1 收尾 / S1x / A-x)
|
||||
|
||||
> 编号空间见 `docs/任务规划/README.md` §0;排期位置见 `docs/任务规划/README.md` §2「验证常态」。
|
||||
> **S1~S14 / T-1~T-5 / A-1~A-7** 是 2026-10-02 版复审的**条目编号**——编号**不随条目删除而回收**;
|
||||
> 编号空间见 `docs/任务规划/README.md` §0;排期位置见 `docs/任务规划/README.md` §2 顺序表。
|
||||
> **`S` 裸形 / `T-x` / `A-x` 三族**是 2026-10-02 版复审的**条目编号**——编号**不随条目删除而回收**(现存有效条目 = 「采集链路测试可验证性约束」「体积门禁 CI 强制路径」与「CI 远端闭环未验证」);
|
||||
> 其他文档若引用这些编号,其证据见对应模块文档与 `git log`。已完成事项的证据沉淀:
|
||||
> `../测试说明/系统时钟单元测试说明.md`(S1-a)、`../测试说明/配置文件单元测试说明.md`(S1-b)、
|
||||
> `../测试说明/测试开发标准流程.md` §4.2.1(L0.5 适格台账)、`../测试说明/模拟器差距清单.md`(S13)、
|
||||
@@ -9,12 +9,12 @@
|
||||
> `../测试说明/主机单测覆盖率口径.md` §9「P1 落地」与「P2 落地」(S1-c:`sys_log_mcu` 106 例、
|
||||
> `time_sync` 既有 4 例,两套均已被 `test-coverage` 总闸覆盖)。
|
||||
>
|
||||
> **本文件只剩 1 项未闭环**(A-4,且 RS485 侧随 B2 暂缓)。2026-10-25 复核时把已销项条目
|
||||
> **本文件只剩 1 项未闭环**(「采集链路测试可验证性约束」,且 RS485 侧随 B2 暂缓)。2026-10-25 复核时把已销项条目
|
||||
> 压缩成证据指针——原来的详述与「完成即销项」规则冲突,留着会让读者以为还有活。
|
||||
|
||||
## 1. P1 收尾(0 项)
|
||||
|
||||
**P1-10 测试固件静态 RAM 预算** 已于 2026-10-25 销项(`task/P1-10-test-fw`→73f9e10):
|
||||
**测试固件静态 RAM 预算** 已于 2026-10-25 销项(`task/P1-10-test-fw`→73f9e10):
|
||||
CH395F 套件 5 档构建全部链接通过,最坏态 `RW_IRAM1` 91,088 B / 69.5%(距 92% 线余 29,498 B);
|
||||
`@test` f3 轮 VERDICT PASS(Phase 1/12/15 = 9/9、1/1、21/21)。**数字与规范正文的唯一出处**是
|
||||
`test/board/ch395f_test.h` 的开关区注释,本文件不再重复。
|
||||
@@ -27,7 +27,7 @@ CH395F 套件 5 档构建全部链接通过,最坏态 `RW_IRAM1` 91,088 B / 69
|
||||
|
||||
| 编号 | 事项 | 状态 | 详述 |
|
||||
|---|---|---|---|
|
||||
| **A-4** | ADC / RS485 采集链路的**测试可验证性约束** | ⏸ ADC 侧随 B1 闭环;**RS485 侧随 B2 暂缓(`暂缓-RS485.md`)** | §2.2 |
|
||||
| **采集链路测试可验证性约束** | ADC / RS485 采集链路的**测试可验证性约束** | ⏸ ADC 侧随 B1 闭环;**RS485 侧随 B2 暂缓(`暂缓-RS485.md`)** | §2.2 |
|
||||
|
||||
### 2.1 S12:模块级轻量断言宏(✅ 2026-10-25 销项)
|
||||
|
||||
@@ -35,7 +35,7 @@ CH395F 套件 5 档构建全部链接通过,最坏态 `RW_IRAM1` 91,088 B / 69
|
||||
的理由 = layer-deps 方向约束**,载于该头注释与提交正文。生产构建 `APP_ASSERT_ENABLE` 关闭时
|
||||
宏展开为 `((void)0)`,零符号零开销——口径唯一正文 = 该头文件注释。
|
||||
|
||||
### 2.2 A-4:ADC / RS485 采集链路的测试可验证性约束 ⏸
|
||||
### 2.2 采集链路测试可验证性约束:ADC / RS485 ⏸
|
||||
|
||||
**背景**:`adc_task.c` 已实现(B1,2026-10-10),`rs485_task.c` 仍是空桩,`App/protocol/` 只有 README 与 `.gitkeep`。
|
||||
本项不是"缺陷",而是**对上游 B2 的设计约束**(B1 已完成;**B2 暂缓中,见 `暂缓-RS485.md`——重启 B2 动手前必须先落实本约束**,否则后续无法补测)。
|
||||
@@ -51,7 +51,7 @@ CH395F 套件 5 档构建全部链接通过,最坏态 `RW_IRAM1` 91,088 B / 69
|
||||
|
||||
**完成判据**:B2 设计文档体现上述三条;协议解析函数有对应 L0.5 单测。(B1 侧:ADC 无协议解析面,其"同一时刻性"由原子快照保证、已闭环。)
|
||||
|
||||
### 2.3 A-5 残余:CI 体积门禁盲区(✅ 2026-10-25 销项)
|
||||
### 2.3 「体积门禁 CI 强制路径」残余:CI 体积门禁盲区(✅ 2026-10-25 销项)
|
||||
|
||||
同码凭证 + CI 复核→564715c、跨树稳定修复→7c4628b。**口径唯一正文** = `scripts/check_size_gate.py`
|
||||
的 docstring(含"CI 侧跳过 `mem-numbers` 的边界"与本地强制路径)。`docs/内存管理/RAM预算台账.md`
|
||||
|
||||
+65
-25
@@ -1,49 +1,89 @@
|
||||
# 登记簿(长期观察项;存量 `N-x / S-x / T-x`,**新条目用语义标识**)
|
||||
# 后续待办与长期观察登记簿
|
||||
|
||||
> 编号空间与"不回收"规则见 `docs/任务规划/README.md` §0;排期位置见 `docs/任务规划/README.md` §2 波次总览;
|
||||
> 当前波次任务卡(带 DoD / 写范围 / 状态)在 `UI补齐.md`(`数据可信.md` 已转收口态)——**「采集保护收尾」的 M1/M2 已收口,只剩 M3 送检**;
|
||||
> 并行归道(写域 / 道 / 合并次序)见 `并行分道方案.md`。
|
||||
> **本文件是低频文件**:新发现按类别进对应表;销项 = 删行 + 清引用(`docs/任务规划/README.md` §3)。
|
||||
> **2026-10-14 起新条目的 `#` 列填「语义标识」**——一行短语直接说清是什么事(如
|
||||
> `沉降窗 800ms 上限只留痕`、`RS485 采集接线`),**不再新增字母+数字编号**;存量编号冻结沿用,
|
||||
> **已随销项消失的号永久作废**、不得复用(原因与撞号实测见 `docs/任务规划/README.md` §0)。
|
||||
> **这里不放当前 UI 任务。** 当前执行只看 `UI补齐.md`;本文件登记 UI 之后的工作、
|
||||
> 等待外部条件的事项、独立立项和长期观察。推进顺序只看 `docs/任务规划/README.md` §2。
|
||||
>
|
||||
> 条目一律用语义短语标识;完成后删行并清理引用。§6~§9 是由原排期、送检、分道和
|
||||
> 开放问题文件合并而来的唯一归属,不再在多处复制同一事项。
|
||||
|
||||
## 1. 网络(CH395F / net 层)
|
||||
|
||||
| # | 事项 | 发现 | 证据与现状 | 出处 |
|
||||
|---|---|---|---|---|
|
||||
| N-3 | **L5 队列往返基线(1223/988µs)的 L3 后重验**——L5 测 DONTWAIT 队列全程;L3 对该路径逐位不变 → 机制上无影响,但基线数值属分片时代,严格重锁需跑一轮 Phase 13(需 PC peer) | 2026-09-22(L3 收尾留档) | 低风险:10ms/100ms 阈值余量 >8×;下次 Phase 13 窗口顺带重锁即可 | `链路延迟测试说明.md` §6.4 L5 注¹ |
|
||||
| N-16 | **A2/A4 专项场景台架验证待办**(正常路径已实测零回归):① PHY 拔线负向测试——断链需断 **DTU 侧**线缆或关**受管交换机端口**;② A2 芯片级 `net_init` 失败分支(需 SPI 故障注入);③ A4 短写压测(需远显客户端 + UI 推流压力) | 2026-10-03(台架拓扑 = CH395↔交换机,拔线操作受限) | 待专项台架窗口 | `实机测试实施指南.md` §10 |
|
||||
| reconcile 突发饿死 uiTask | **对时 reconcile/relisten 突发(0~4s 窗)把唯一 BelowNormal 的 uiTask 压成同一任务 800ms+ 单串缺席(饿死型,非等待型——F3 返回点喂位射程外)**:8 连窗级 UI 缺席期间喂狗面本身未断(cf=0 seg=1)、uisn=0(不在 sink 段内)、uip 在途 307→1083ms 而 uis 峰仅 183ms——被拖的 1s 在 feed/port 纯计算段墙钟。**2026-10-25 台架两轮分箱定案**:同负载换 :7003 churn 2200 周期 stall=0(阻塞型已被 F3 治愈),探针轮 3 事件 8 行全为该签名(漏检零、误报零,v1.1 口径 FAIL 面精确收缩)。处置方向 = 自愈设计 §11.3 脆弱点 1 实测样本并档 **E-27/28**:优先级矩阵复核 与 reconcile 突发分片让路 两案并评;**排期 = 批 4(结构债)**,与 E-27/E-28 裸指针收口同批 | 2026-10-25(F2/F3 验收轮②,v1.1 判据下捕获) | `docs/测试说明/boot_log_data/f3rounds_r2_probe_30min.log.gz`(3 事件 8 行 + STALL 证据行 + 同行 PROF);对照轮 `f3rounds_r1_7003_churn_30min.log.gz`;机理归档 `../网络/网络自愈架构设计.md` §4.6、`../子系统设计/看门狗设计说明.md` §11.3、`../UI设计/UI_设计架构.md` §5.8 | `../算法/继电保护功能复现规划.md`(E-27/28 属主文档指针) |
|
||||
| N-30 | **relisten 沉降段统一到驱动 `sock_reset` 原语受阻**——"去重复实现"的收口已实测回退:原语版 `ftp_abort_probe` RST **0/10**、FIN **0/5**(中止后首笔复连仍被截断到 ≤2048B),另新增 `sock_reset_sync timeout (600ms)` 与 `close: sock_reset not done` 两条 `[ERR]`;同场 net 层自建序列 **10/10 + 5/5** | 2026-10-14(同一块板 A/B,判据 `test/host/ftp_abort_probe.py`;快复连 50/50、背靠背 30/30 两版都过 → 失效面精确落在"中止后首笔复连") | **现状 = `net_listener.c` 保留自建排渣序列**(排空 + CLOSE + 排事件 + 等 CLOSED,30 ms 重试轮持续清)。重开前置三条语义:① 隔离窗内**持续**排空/关闭(残渣在 CLOSE 之后才落进 RX,一次排空接不住)② **复用让位**(复位机不得拆上层刚在同一芯片 Socket 上重建的监听)③ `net_sock_reset_sync` 改"已在运行 = 加入等待"(`begin` 返 -1 ≠ 失败) | `../网络/网络自愈架构设计.md` §8 延后项 1、§5.2 E16;`../问题记录/CH395F_Trap_Records.md` TRAP-NET-18 |
|
||||
| L5 队列往返基线待重验 | **L5 队列往返基线(1223/988µs)的 L3 后重验**——L5 测 DONTWAIT 队列全程;L3 对该路径逐位不变 → 机制上无影响,但基线数值属分片时代,严格重锁需跑一轮 Phase 13(需 PC peer) | 2026-09-22(L3 收尾留档) | 低风险:10ms/100ms 阈值余量 >8×;下次 Phase 13 窗口顺带重锁即可 | `链路延迟测试说明.md` §6.4 L5 注¹ |
|
||||
| 网络负向场景台架验证 | **负向场景台架验证待办**(拔线断链 / 芯片级 `net_init` 失败分支 / 短写压测;正常路径已实测零回归):① PHY 拔线负向测试——断链需断 **DTU 侧**线缆或关**受管交换机端口**;② 芯片级 `net_init` 失败分支(需 SPI 故障注入);③ 短写压测(需远显客户端 + UI 推流压力) | 2026-10-03(台架拓扑 = CH395↔交换机,拔线操作受限) | 待专项台架窗口 | `实机测试实施指南.md` §10 |
|
||||
| reconcile 突发饿死 uiTask | **对时 reconcile/relisten 突发(0~4s 窗)把唯一 BelowNormal 的 uiTask 压成同一任务 800ms+ 单串缺席(饿死型,非等待型——F3 返回点喂位射程外)**:8 连窗级 UI 缺席期间喂狗面本身未断(cf=0 seg=1)、uisn=0(不在 sink 段内)、uip 在途 307→1083ms 而 uis 峰仅 183ms——被拖的 1s 在 feed/port 纯计算段墙钟。**2026-10-25 台架两轮分箱定案**:同负载换 :7003 churn 2200 周期 stall=0(阻塞型已被 F3 治愈),探针轮 3 事件 8 行全为该签名(漏检零、误报零,v1.1 口径 FAIL 面精确收缩)。处置方向 = 自愈设计 §11.3 脆弱点 1 实测样本并档「net 层跨上下文收口」项:优先级矩阵复核与 reconcile 突发分片让路两案并评;**排期 = UI 完成后的第一项**,与裸指针收口同批 | 2026-10-25(F2/F3 验收轮②,v1.1 判据下捕获) | `docs/测试说明/boot_log_data/f3rounds_r2_probe_30min.log.gz`(3 事件 8 行 + STALL 证据行 + 同行 PROF);对照轮 `f3rounds_r1_7003_churn_30min.log.gz`;机理归档 `../网络/网络自愈架构设计.md` §4.6、`../子系统设计/看门狗设计说明.md` §11.3、`../UI设计/UI_设计架构.md` §5.8 | `../算法/继电保护功能复现规划.md`(裸指针收口项属主文档指针) |
|
||||
| relisten 沉降段原语化受阻 | **relisten 沉降段统一到驱动 `sock_reset` 原语受阻**——"去重复实现"的收口已实测回退:原语版 `ftp_abort_probe` RST **0/10**、FIN **0/5**(中止后首笔复连仍被截断到 ≤2048B),另新增 `sock_reset_sync timeout (600ms)` 与 `close: sock_reset not done` 两条 `[ERR]`;同场 net 层自建序列 **10/10 + 5/5** | 2026-10-14(同一块板 A/B,判据 `test/host/ftp_abort_probe.py`;快复连 50/50、背靠背 30/30 两版都过 → 失效面精确落在"中止后首笔复连") | **现状 = `net_listener.c` 保留自建排渣序列**(排空 + CLOSE + 排事件 + 等 CLOSED,30 ms 重试轮持续清)。重开前置三条语义:① 隔离窗内**持续**排空/关闭(残渣在 CLOSE 之后才落进 RX,一次排空接不住)② **复用让位**(复位机不得拆上层刚在同一芯片 Socket 上重建的监听)③ `net_sock_reset_sync` 改"已在运行 = 加入等待"(`begin` 返 -1 ≠ 失败) | `../网络/网络自愈架构设计.md` §8 延后项 1、§5.2 E16;`../问题记录/CH395F_Trap_Records.md` TRAP-NET-18 |
|
||||
|
||||
## 2. 存储 / 日志管线
|
||||
|
||||
| # | 事项 | 发现 | 证据与现状 | 出处 |
|
||||
|---|---|---|---|---|
|
||||
| S-3 | **USART1 TX-only 结构根治(灭 ORE 僵尸机制)**——ORE 锁存在外设软复位后毫秒级重锁(PA10 悬空 + RX 使能),是 2026-10-02 台架"背靠背 drain 拉长主循环 → 喂狗节奏饥饿 → IWDG 误复位"的**机制根源**。现仅有缓解(单次 drain 250ms 预算 + 发送故障后 300ms 冷却),**未根治** | 2026-10-02(台架 gen-288) | **待办**:改 `.ioc` 令 USART1 为 TX-only → CubeMX 重生成 → 跑 `scripts/check_cubemx_survival.py`。结构性改动,需单开一轮并复跑台架闭环 | `../子系统设计/控制台单写者日志设计说明.md` §12(含 O4) |
|
||||
| S-4 | **dhara 重试自旋残留**——`try_recover()` 的 `DHARA_MAX_RETRIES`(8) 自旋在坏块密集时仍可能长时间占用 defaultTask(喂狗点) | 2026-10-02 | 低优先:现有 `vol_lock` + 喂狗节奏缓解;若台架再出"存储侧喂狗饥饿"再排期 | `Lib/dhara/map.c` |
|
||||
| S-5 | **可选全序列卷锁**——现卷锁仅覆盖 `syslog` / `cfg` / `lftpd` 三条路径(`vol_lock_wait(0)` try 语义),其它潜在访问点(如 UI 读日志)未纳入 | 2026-10-02 | 待评估:先确认是否真有第二写者;无则关闭本项 | `App/fs/vol_lock.{c,h}` |
|
||||
| dhara 重试自旋残留 | **dhara 重试自旋残留**——`try_recover()` 的 `DHARA_MAX_RETRIES`(8) 自旋在坏块密集时仍可能长时间占用 defaultTask(喂狗点) | 2026-10-02 | 低优先:现有 `vol_lock` + 喂狗节奏缓解;若台架再出"存储侧喂狗饥饿"再排期 | `Lib/dhara/map.c` |
|
||||
| 可选全序列卷锁 | **可选全序列卷锁**——现卷锁仅覆盖 `syslog` / `cfg` / `lftpd` 三条路径(`vol_lock_wait(0)` try 语义),其它潜在访问点(如 UI 读日志)未纳入 | 2026-10-02 | 待评估:先确认是否真有第二写者;无则关闭本项 | `App/fs/vol_lock.{c,h}` |
|
||||
|
||||
## 3. 硬件(V0.1 缺陷 → V0.2 改版项)
|
||||
|
||||
| # | 事项 | 发现 | 证据与现状 | 出处 |
|
||||
|---|---|---|---|---|
|
||||
| N-18 | **8 路电气量分属两片转换器(V0.1 硬件缺陷,需下一版硬件修改)**——UA/UN/IA 走 TPAFE5160(16 位、8 通道同步、±5 V 双极性),UB/UC/IB/IC/IN 走 STM32 ADC(12 位、顺序扫描、0~3.3 V 单极性):① 两片转换器无共同采样触发 + STM32 侧顺序扫描(9 通道一轮 ≈ 67 µs)→ 跨转换器通道**无同一时刻性、相位关系不确定**,主板侧功率/功率因数/相角/对称分量类运算不成立;② 同族电气量精度与量程不一致(LSB ≈ 152.6 µV vs ≈ 806 µV,且 STM32 侧前端无中点偏置、负半周削顶);③ 语义与硬件归属交叉,固件映射/UI 通道序/自检注入须逐通道查表绕开 | 2026-10-10 定性更正(**撤销** 2026-10-09 建档时"有意分配、不要修正"的说法) | **V0.2 改版要求**:8 路电气量 UA/UB/UC/UN/IA/IB/IC/IN **全部接 TPAFE5160**,与 TPAFE 上 5 路备用路(AIN5/13/7/15/12)对调串联电阻在转换器一侧的目的地——元件数量与料号不变,属走线级改动。**V0.1 现板软件口径**:主板侧只做逐通道独立监视,禁止跨转换器做相位/功率/功率因数/矢量类运算(此类量取子板计量模块结果)。固件侧消费者已落地(B1,2026-10-10,按语义映射表取数)→ V0.2 改版只改映射表内容,上层语义与代码不动 | `../硬件平台/ADC通道映射说明.md` §1/§7;`../硬件平台/V0.1_网表详细分析报告.md` §1.4 V10、§6-3 |
|
||||
| 双转换器无共同采样触发 | **8 路电气量分属两片转换器(V0.1 硬件缺陷,需下一版硬件修改)**——UA/UN/IA 走 TPAFE5160(16 位、8 通道同步、±5 V 双极性),UB/UC/IB/IC/IN 走 STM32 ADC(12 位、顺序扫描、0~3.3 V 单极性):① 两片转换器无共同采样触发 + STM32 侧顺序扫描(9 通道一轮 ≈ 67 µs)→ 跨转换器通道**无同一时刻性、相位关系不确定**,主板侧功率/功率因数/相角/对称分量类运算不成立;② 同族电气量精度与量程不一致(LSB ≈ 152.6 µV vs ≈ 806 µV,且 STM32 侧前端无中点偏置、负半周削顶);③ 语义与硬件归属交叉,固件映射/UI 通道序/自检注入须逐通道查表绕开 | 2026-10-10 定性更正(**撤销** 2026-10-09 建档时"有意分配、不要修正"的说法) | **V0.2 改版要求**:8 路电气量 UA/UB/UC/UN/IA/IB/IC/IN **全部接 TPAFE5160**,与 TPAFE 上 5 路备用路(AIN5/13/7/15/12)对调串联电阻在转换器一侧的目的地——元件数量与料号不变,属走线级改动。**V0.1 现板软件口径**:主板侧只做逐通道独立监视,禁止跨转换器做相位/功率/功率因数/矢量类运算(此类量取子板计量模块结果)。固件侧消费者已落地(B1,2026-10-10,按语义映射表取数)→ V0.2 改版只改映射表内容,上层语义与代码不动 | `../硬件平台/ADC通道映射说明.md` §1/§7;`../硬件平台/V0.1_网表详细分析报告.md` §1.4 V10、§6-3 |
|
||||
|
||||
## 4. 测试与验证基础设施
|
||||
|
||||
| # | 事项 | 优先级 | 问题与证据 | 处置方向 | 出处 |
|
||||
|---|---|---|---|---|---|
|
||||
| T-7 | **CI 远端闭环未验证**(runner 本机已就绪) | 中 | **剩余两件**:③ 推送远端跑一次两 job 闭环验证(**跑通证据尚无留档**,故仍按"未验证"对待);④ 第二机交叉验证(不同工具安装路径,验 `DTU_*` 环境变量方案,→ `../环境与部署/本地工具路径环境变量方案.md` 变更记录 TODO)。①② 已就绪,见 `../CI/远程CI完整指南.md` §0 仓库状态行 | 完成前**提交前仍须在本地跑 `scripts/ci_local.py` 或 `pre-commit run --all-files` 自查**(L0 唯一保障,不能因"已配 CI"而放宽) | `.gitea/workflows/ci.yml`;`../CI/远程CI完整指南.md`;`../测试说明/测试开发标准流程.md` §9 |
|
||||
| CI 远端闭环未验证 | **CI 远端闭环未验证**(runner 本机已就绪) | 中 | **剩余两件**:③ 推送远端跑一次两 job 闭环验证(**跑通证据尚无留档**,故仍按"未验证"对待);④ 第二机交叉验证(不同工具安装路径,验 `DTU_*` 环境变量方案,→ `../环境与部署/本地工具路径环境变量方案.md` 变更记录 TODO)。①② 已就绪,见 `../CI/远程CI完整指南.md` §0 仓库状态行 | 完成前**提交前仍须在本地跑 `scripts/ci_local.py` 或 `pre-commit run --all-files` 自查**(L0 唯一保障,不能因"已配 CI"而放宽) | `.gitea/workflows/ci.yml`;`../CI/远程CI完整指南.md`;`../测试说明/测试开发标准流程.md` §9 |
|
||||
|
||||
## 5. 审查报告并轨(2026-10-11;⚠ 报告编号与本登记簿同名不同义,出处列保留报告编号,引用一律带文档名)
|
||||
## 5. RS-485、内存与仓库观察
|
||||
|
||||
| # | 事项 | 影响 / 现状 | 处置方向 | 波次 | 出处 |
|
||||
| # | 事项 | 影响 / 现状 | 处置方向 | 状态 | 出处 |
|
||||
|---|---|---|---|---|---|
|
||||
| N-23 残余 | **KNOWN_GAPS 白名单清理**——现存唯一缺口 = `App/task/rs485_task.c`(E-59 门禁下刻意不接线,随 B2 暂缓,见 `暂缓-RS485.md`) | 白名单不清 = "写了不编译"盲区仍在 | 随 B2 一并出白名单(`--strict` 供审计复跑) | 结构债 | 报告 N-06 残余 |
|
||||
| N-25 | 性能/资源建议簇:PASV 每次新建监听;PHY 强制 100M 无自协商回退;`NET_MAX_SOCKETS 8` 与单连接语义不符;`HAL_Delay(1)` 阻塞 DE(**DE 项随 B2 暂缓,见 `暂缓-RS485.md`**) | 次级性能/语义一致性 | 随窗口评估,逐项机理见 `../网络/Net层阻塞模型架构设计.md` 与 `Drivers/BSP/NET/README.md` | 结构债 | 报告 N-09/PHY/P3-x/rs485(报告已删,仅作历史指称) |
|
||||
| N-27 | **内存优化簇剩余**:原报告 R-2 后半(缩堆 56→32 KB → 迁 CCM)· R-3 · R-4 · R-6 | ⏸ **整簇暂缓**(2026-10-15 用户裁定):没有功能在等这块预算,而搬迁要动 scatter、要逐条过 DMA 可达性清单、缩堆还要上板复测。⚠ 代价落在"以后加任务 / 抬栈 / 加堆"那一刻——CCM 只剩 7,904 B、FreeRTOS 堆 `min_ever` 8,464 B,届时 `mem-budget` 会先报警 | 重开条件见 `../内存管理/RAM使用分析与优化方案.md` §4。⚠ **原报告 R-5 已判定不可行**(CMSIS-RTOS2 `freertos_os2.h` 有 `#if (configMAX_PRIORITIES != 56) #error`,改小直接编译失败),不再列入 | **暂缓** | 报告 R-2 剩余/R-3/R-4/R-6/§5.5 |
|
||||
| N-28 | **报告 F-5:uvprojx 里 127 个空 TU**(201 个 LVGL `.c` 中 127 个 `.map` 零产出) | 增量构建实测 4~5 s、远程 CI 刻意不跑 `@build` → **非产品指标**;报告原"编译时长 −40%"无基线记录 | 🟡 观察:等有实测的全量构建耗时痛点再做——用 Keil 原生 `<IncludeInBuild>0</IncludeInBuild>`(可逆)而非删条目,且排在任何 `lv_conf.h` 改动之后;动手前先补一次全量构建计时做基线 | 结构债 | 报告 F-5 |
|
||||
| N-29 | **仓库膨胀**:`.git` **233 MB**(2026-10-25 实测)+ 手册图片 36.3 MB(受控文件合计仅 79.3 MB,`.git` 已是它的 3 倍) | clone/备份慢,且持续恶化 | 降采样 / 拆 submodule / LFS 三选一 **+ 一次 `git filter-repo` 历史重写**(三项都不解决历史膨胀)。**已决策(2026-10-11):暂不处理、登记观察**——推送/协作前重评 | **仓库决策** | 报告 D-1 |
|
||||
| U 簇 | **U5 页面落地**——33 叶已绑 **12**、剩 **21**("27 页"是目标数、不是差集;`ui_page_registry.c` 是生成物不算页面)。组件层三件套(`ui_w_editor` / `ui_w_setlist` / `ui_page_action`)已落地但**零消费者** | 地基已齐(U1~U4 落地;`ui-golden` 与字符集差集检查均已挂 pre-commit),新增一页 = 3 处人工 + 1 条生成器命令 | **当前波次**(2026-10-25 用户决定:下一波只做 UI 补齐、结构债押后)。21 叶按数据源就绪度分三梯队,第一梯队 9 叶零依赖——明细与 DoD 见 `UI补齐.md` | UI 扩展 | `../UI设计/页面补齐规划.md` |
|
||||
| rs485_task 白名单缺口 | **KNOWN_GAPS 白名单清理**——现存唯一缺口 = `App/task/rs485_task.c`(RS-485 接线门禁未满足、刻意不接线,随 B2 暂缓,见 `暂缓-RS485.md`) | 白名单不清 = "写了不编译"盲区仍在 | 随 B2 一并出白名单(`--strict` 供审计复跑) | 结构债 | 报告 N 族残余(报告已删) |
|
||||
| 缩堆迁 CCM 后半(暂缓) | **内存优化簇剩余**:原报告缩堆建议的后半(缩堆 56→32 KB → 迁 CCM)· 同类三项 | ⏸ **整簇暂缓**(2026-10-15 用户裁定):没有功能在等这块预算,而搬迁要动 scatter、要逐条过 DMA 可达性清单、缩堆还要上板复测。⚠ 代价落在"以后加任务 / 抬栈 / 加堆"那一刻——CCM 只剩 7,904 B、FreeRTOS 堆 `min_ever` 8,464 B,届时 `mem-budget` 会先报警 | 重开条件见 `../内存管理/RAM使用分析与优化方案.md` §4。⚠ **原报告另有一条已判定不可行**(CMSIS-RTOS2 `freertos_os2.h` 有 `#if (configMAX_PRIORITIES != 56) #error`,改小直接编译失败),不再列入 | **暂缓** | 报告 R 族剩余/§5.5(报告已删) |
|
||||
| 仓库体积膨胀观察 | **仓库膨胀**:`.git` **233 MB**(2026-10-25 实测)+ 手册图片 36.3 MB(受控文件合计仅 79.3 MB,`.git` 已是它的 3 倍) | clone/备份慢,且持续恶化 | 降采样 / 拆 submodule / LFS 三选一 **+ 一次 `git filter-repo` 历史重写**(三项都不解决历史膨胀)。**已决策(2026-10-11):暂不处理、登记观察**——推送/协作前重评 | **仓库决策** | 报告 D 族 |
|
||||
|
||||
---
|
||||
|
||||
## 6. UI 完成后的编码队列
|
||||
|
||||
| 顺序 | 条目 | 要做什么 | 完成或关闭判据 |
|
||||
|---|---|---|---|
|
||||
| 1 | **net 层跨上下文收口** | 同批处理两件事:裸指针收口为状态查询 API;对时 reconcile/relisten 突发导致 uiTask 800 ms 以上连续缺席,评估优先级矩阵与突发分片让路 | 同类台架负载下不再出现目标饿死签名;网络与 UI 回归通过;证据写入网络与看门狗模块文档 |
|
||||
| 2 | **网络性能资源建议簇** | 分别评估 PASV 重复建监听、PHY 强制 100M 无回退、`NET_MAX_SOCKETS` 与单连接语义不一致;DE 项随 RS-485,不在本项做。机理见 `../网络/Net层阻塞模型架构设计.md` 与 `Drivers/BSP/NET/README.md` | 每项形成“修改并验证”或“有理由不做”的结论;不为了清清单做无收益重构 |
|
||||
| 3 | **dhara 重试自旋与卷锁评估** | 先确认是否仍出现存储侧喂狗饥饿、是否确有第二写者,再决定是否修改 | 有新证据才排修改;无第二写者则关闭全序列卷锁项 |
|
||||
| 4 | **uvprojx 空 TU 观察** | 201 个 LVGL `.c` 中 127 个在 `.map` 零产出,但当前增量构建仅 4~5 秒;有全量构建耗时痛点时先补计时基线,再用 Keil 原生 `<IncludeInBuild>0</IncludeInBuild>` 可逆排除 | 有实测收益才保留改动;否则继续观察 |
|
||||
|
||||
> RS-485 白名单随 `暂缓-RS485.md` 整簇处理,不列为 UI 后的独立编码任务。
|
||||
> 并行写域、工作树与合并纪律统一见 `docs/环境与部署/并行任务工作树方案.md`。
|
||||
|
||||
## 7. 等台架或外部资源的事项
|
||||
|
||||
| 条目 | 需要条件 | 要做的事 | 去向 |
|
||||
|---|---|---|---|
|
||||
| **数据可信三项** | 台架与万用表;子板实物或原理图;标准源 | 已知电压注入 → 端子变比 → 8 通道两点标定 | 唯一任务卡与验收在 `数据可信.md` §5 |
|
||||
| **标准源送检与第三方 104 验收** | 两点标定完成、保护 VALID 置位、第三方主站 | 标准源注入判据全部通过;总召、周期、变位、遥控全流程通过;证据归档。送检窗口前 2 日冻结特性 | `../子系统设计/IEC104上行设计说明.md` §7/§8 |
|
||||
| **L5 队列往返基线待重验** | 台架 + PC peer | 下次 Phase 13 窗口重锁基线 | 本文件 §1 |
|
||||
| **网络负向场景台架验证** | 拔线、SPI 故障注入、远显压力条件 | PHY 拔线、芯片级 `net_init` 失败、短写压测 | 本文件 §1 |
|
||||
| **串口助手正路径补验** | CH340 接入 | 补齐尚未覆盖的正路径 | `../测试说明/串口助手设计说明.md` |
|
||||
| **CI 远端闭环未验证** | runner 与第二台机器 | 验证远端两 job 闭环和不同工具路径 | 本文件 §4 |
|
||||
|
||||
**送检顺序不可倒过来**:产品构建当前要求 UA/UN/IA 的标定 VALID 全部置位才走保护判据。
|
||||
未完成标准源标定就送检,保护会表现为不动作。保持该闭锁,不用非标准源标定走捷径。
|
||||
|
||||
## 8. 等立项或硬件代次的事项
|
||||
|
||||
| 条目 | 当前不做的原因 | 重开条件 |
|
||||
|---|---|---|
|
||||
| **保护元件 V0.1 可行子集** | A 相涌流制动、突变量启动、无压无流闭锁、元件级校验和虽能设计,但没有标准源就无法验收,且保护仍在闭锁 | 标准源到位,且标定与闭锁验证完成 |
|
||||
| **采集增强** | 等周波调频、零序通道、遥测谐波轨依赖可信工程量 | 标定完成后单独立项 |
|
||||
| **跨转换器三相与功率类功能** | 两片转换器无共同采样触发,V0.1 上相位、功率、对称分量不成立 | V0.2 硬件改版 |
|
||||
| **开入开出与遥信配置 3 页** | 固件和 V0.1 硬件均无可配开入对象;出口还涉及 GPIO 安全电平、保持/脉冲和回读自检 | 开入开出作为独立模块立项,再与 UI 页面同批 |
|
||||
| **故障录波与 104 文件传输** | 是独立子系统,不是补一个页面 | 产品定义与工程量口径明确后立项 |
|
||||
| **SNTP 设置** | 当前对时走 8888 私有协议,SNTP 客户端与产品口径未定 | SNTP 客户端立项 |
|
||||
| **RS-485 整簇** | 用户决定暂缓 | `暂缓-RS485.md` |
|
||||
|
||||
## 9. 开放问题
|
||||
|
||||
| 问题 | 为什么还没答案 | 处理时机 |
|
||||
|---|---|---|
|
||||
| **是否在真实初始化点接入功能裁剪门控** | 旧占位宏没有消费者且已删除;是否需要真实门控属于产品定义,不是单纯代码问题 | 产品提出按配置裁剪需求时决定;决定前不新增空开关 |
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
# 采集 + 保护收尾(只剩 M3 送检)
|
||||
|
||||
> **本波只剩余一项未开工的事**:M3 可送检(B10)。台架闭环与功能面完整这两项已闭环,本文件
|
||||
> 不保留其任务卡与证据链(证据在模块文档与 `git log`)。
|
||||
> 排序权威(波次总览)在 `docs/任务规划/README.md` §2;并行 / 工作树 / 两把锁的机制见
|
||||
> `docs/任务规划/并行分道方案.md`。
|
||||
|
||||
## 1. 本波目标(用户决定 2026-10-12)
|
||||
|
||||
把"采集→相量→保护→上送"链路从"代码落地"收口到**台架闭环 + 功能面完整 + 可送检**。
|
||||
前两项已达成,**本文件只剩"可送检"**。
|
||||
|
||||
## 2. 里程碑
|
||||
|
||||
| 里程碑 | 退出判据(全部满足才算完成,随后销项) | 服务分类 |
|
||||
|---|---|---|
|
||||
| **M3 可送检** | B10 注入判据 + 第三方主站全流程通过,证据归档 | **Fixed Date**(送检窗口一到全道让路;窗口前 2 日特性冻结,只修稳定——Zephyr RC 语义) |
|
||||
|
||||
## 3. 任务卡(五字段:DoD / 硬依赖 / 资源 / 写范围 / 状态;完成即销项删行)
|
||||
|
||||
> 资源图例:🔴 台架(COM6/ST-LINK,`bench.lock` 独占)· 🟡 外部(标准源/第三方主站)· 🟢 纯软件(可并行)。
|
||||
> 状态:⬜ 未开始 · 🟦 进行中(销项行直接删除,见 `docs/任务规划/README.md` §3 维护约定)。
|
||||
|
||||
| 序 | 任务 | DoD(可验证验收判据) | 硬依赖 | 资源 | 写范围 | 状态 | 出处 |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| **B10** | **标准源注入 + 第三方 104 主站往返(送检窗口)** | 标准源注入:L1-5 标定复核 / L1-7 等周波 / P1 过流·过负荷 / P2 电压 + 频率类判据全通过;第三方主站总召/周期/变位/遥控全流程(`../子系统设计/IEC104上行设计说明.md` §7/§8 核对单);证据归档 | 卡 12(「数据可信」,标准源) | 🟡 | —(窗口内缺陷修复走 Expedite 类) | ⬜ | 保护规划 §7 P1/P2 验收;`../子系统设计/IEC104上行设计说明.md` §7/§8 |
|
||||
|
||||
> ⚠ **B10 与「数据可信」的依赖**:B10 的"L1-5 标定复核"依赖「数据可信」的通道标定卡(卡 12),
|
||||
> 即 **「数据可信」是 B10 的前置**。该依赖已在 `docs/任务规划/数据可信.md` §10 登记,两边不要
|
||||
> 各写一套;送检窗口若早于卡 12,先按卡 0 的注入结果对齐口径。
|
||||
>
|
||||
> ⚠ **送检前必须先解保护闭锁**(2026-10-25 复核):产品构建下 `protect_task.c:98` 要求
|
||||
> UA/UN/IA 的 `ADC_CAL_F_VALID` 全置位才走判据,而 VALID 只在标定写入 `[adc_cal] valid`
|
||||
> 后才置位——**当前保护不动作**。B10 要验"过流/过负荷/电压+频率类判据全通过",
|
||||
> 必须先完成卡 12 把 VALID 置起来,否则送检现场所有保护判据都表现为"不动作"。
|
||||
> 用户裁定(2026-10-25):**保持闭锁到标准源到位**,不用万用表标定走捷径。
|
||||
+22
-22
@@ -3,9 +3,9 @@
|
||||
> 版本:v1.3 日期:2026-10-22(v1.2 2026-09-21)
|
||||
> 变更:v1.3 §4 的阶段子项改为**层级编号**(见下"编号约定");同步 2026-10-22 现状数字与
|
||||
> `data/ram_report_20261022.md` / `data/stack_report_20261022.md` 两份新快照。
|
||||
> 变更:2026-10-23 补 `data/ram_report_20261023.md` 快照(S-5 试点:RS485 改报 `bsp_err_t`,
|
||||
> `Code` 213,436 → **213,648**(S-5 全波 +212:契约试点 +48、C3 SD2506 +44、C1 GD5F/TPAFE +36、
|
||||
C2 dhara 失败类 +84;RO 另 +208,全是 C2 的失败类名表)→ `ER_IROM1` 当日 **227.1 KB / 22.2%**(字节值见 `data/ram_report_20261023.md`,正文不留会过期的裸 B 值);
|
||||
> 变更:2026-10-23 补 `data/ram_report_20261023.md` 快照(BSP 错误码契约试点:RS485 改报 `bsp_err_t`,
|
||||
> `Code` 213,436 → **213,648**(该契约全波 +212:RS485 试点 +48、SD2506 +44、GD5F/TPAFE +36、
|
||||
dhara 失败类 +84;RO 另 +208,全是该失败类名表)→ `ER_IROM1` 当日 **227.1 KB / 22.2%**(字节值见 `data/ram_report_20261023.md`,正文不留会过期的裸 B 值);
|
||||
> **RAM 全部字段零增量**;受管表已由
|
||||
> `check_mem_numbers.py --write` 同步,配图常量同步)。
|
||||
> 变更:2026-10-24 合入 `task/cov-host-line-coverage`(覆盖率口径 §9 的 P1 全批)——RAM **+8 B**
|
||||
@@ -29,7 +29,7 @@ C2 dhara 失败类 +84;RO 另 +208,全是 C2 的失败类名表)→ `ER_IR
|
||||
- F407 另有 **64KB CCM RAM**:**已于 2026-09-21 启用**并把 FreeRTOS 堆迁入(§4.1.2)
|
||||
- 起步时没有任何运行时测量手段:不知道每个任务实际用了多少栈,改栈全靠拍脑袋
|
||||
|
||||
当前状态(**以 §2.1 受管快照为准**,由 `.map` 自动生成;2026-10-24 `@build`):RW_IRAM1 **75,632 / 131,072 B(57.7%)**、RW_CCM **57,376 / 65,280 B(87.9%)**。✅ **任务栈:`stack_report.py` 9/9 PASS**(2026-10-22 静态最坏链 + 同日真机 `[STACK]` 水位,`defaultTask` 最坏 3024B/5120(余 40%)、`protectTask` 872B/2048(余 57%),见 `data/stack_report_20261022.md`);**卡点已从 SRAM1 移到 CCM**(余 7,904 B)。历史:`defaultTask` 曾于 2026-10-04 达 3664B/4096 ≈10%,登记为 S-1,2026-10-10 削链后销项(详见"2026-10-10 复测"小节)。
|
||||
当前状态(**以 §2.1 受管快照为准**,由 `.map` 自动生成;2026-10-24 `@build`):RW_IRAM1 **75,632 / 131,072 B(57.7%)**、RW_CCM **57,376 / 65,280 B(87.9%)**。✅ **任务栈:`stack_report.py` 9/9 PASS**(2026-10-22 静态最坏链 + 同日真机 `[STACK]` 水位,`defaultTask` 最坏 3024B/5120(余 40%)、`protectTask` 872B/2048(余 57%),见 `data/stack_report_20261022.md`);**卡点已从 SRAM1 移到 CCM**(余 7,904 B)。历史:`defaultTask` 曾于 2026-10-04 达 3664B/4096 ≈10%,曾登记在案,2026-10-10 削链后销项(详见"2026-10-10 复测"小节)。
|
||||
|
||||
本方案三个目标:
|
||||
|
||||
@@ -109,9 +109,9 @@ C2 dhara 失败类 +84;RO 另 +208,全是 C2 的失败类名表)→ `ER_IR
|
||||
> **同日 L1-6 有效性校验后抬栈 512→640 words**:`adc_health_report`→`syslog_post` 控制台回显尾把静态
|
||||
> 最坏链推到 **1080 B**(512 words 时余 968 B < 1024 B ISR 底线)→ 抬至 2.5 KB,余 **1480 B / 57%**;
|
||||
> 堆 `min_ever` 7152 → **6640 B**(-512 B,符合预算)。
|
||||
> 此前 2026-10-04 的 V5 30 min 重采曾把 defaultTask 推到 **3664B/4096(余量 432B ≈ 10%,登记 S-1)**;
|
||||
> 2026-10-10 的栈整改(**未抬栈**,见 §4 阶段 0 的"2026-10-10 复测")把它压回 **2152B/4096**,S-1 已销项。
|
||||
> **2026-10-12 N-33 栈收口(登记簿销项,「采集保护收尾」M1)**:B7 定值持久化把 defaultTask 静态链推到 **3016 B**
|
||||
> 此前 2026-10-04 的 V5 30 min 重采曾把 defaultTask 推到 **3664B/4096(余量 432B ≈ 10%,曾登记在案)**;
|
||||
> 2026-10-10 的栈整改(**未抬栈**,见 §4 阶段 0 的"2026-10-10 复测")把它压回 **2152B/4096**,该项已销项。
|
||||
> **2026-10-12 栈余量收口(登记簿销项,「采集保护收尾」M1)**:B7 定值持久化把 defaultTask 静态链推到 **3016 B**
|
||||
> (storage_bring_up→cfg 写→f_rename→dhara GC→控制台回显尾),1024 words 余 1080 B < 30% 线;
|
||||
> timeSyncTask 链 **1264 B**(同一控制台回显尾),512 words 余 784 B < ISR 底线 → **抬栈**
|
||||
> defaultTask 1024→**1280**、timeSyncTask 512→**640**(堆 +1536 B,台账 §6 已登记);
|
||||
@@ -124,8 +124,8 @@ C2 dhara 失败类 +84;RO 另 +208,全是 C2 的失败类名表)→ `ER_IR
|
||||
| netTask | `960*4` | 3.75KB | CH395F 轮询(DMA 搬运,栈压力小) | **1116 B(余 70%)**/ 静态 **1912 B**(2026-10-14 E19 `force open` 降级后复测,链尾经 net_listener_tick→net_relisten_locked;前值 **1920 B** = 同日 E17 单一所有者收口后、**1944 B** = SEND pending 台架复测(含 `net_send_pending_tick` 新增栈帧),更早 920 B 为一期 recv 挂起时实测;FTP 传输期实测峰 **1164 B**) |
|
||||
| ftpTask | `1024*4` | 4KB | lftpd FTP 服务 | 740 B(余 81%)/ 静态 1216 B |
|
||||
| testTask | `2048*4` | 8KB | 测试套件(产品构建不创建;存储套件深链需要) | 未创建 / 静态 496 B |
|
||||
| defaultTask | `1280*4` | 5KB | FatFS 挂载/探针 + 配置引擎 + syslog + 栈水位探针 | 2152 B(余 41%)/ 静态 **3016 B**(N-33 抬栈 1024→1280,2026-10-12) |
|
||||
| timeSyncTask | `640*4` | 2.5KB | TCP 时间同步 | 616 B(余 50%)/ 静态 **1264 B**(N-33 抬栈 512→640,2026-10-12) |
|
||||
| defaultTask | `1280*4` | 5KB | FatFS 挂载/探针 + 配置引擎 + syslog + 栈水位探针 | 2152 B(余 41%)/ 静态 **3016 B**(栈余量收口时抬栈 1024→1280,2026-10-12) |
|
||||
| timeSyncTask | `640*4` | 2.5KB | TCP 时间同步 | 616 B(余 50%)/ 静态 **1264 B**(栈余量收口时抬栈 512→640,2026-10-12) |
|
||||
| adcTask | `640*4` | 2.5KB | TPAFE5160 采样消费 + L2 相量 + L1-6 有效性校验(TIM3 1 kHz 节拍,B1→L2→L1-6 2026-10-11) | **952 / 2560**(余 1608 B / 62%,台架 `@test` 实测 2026-10-11);静态 **1320 B**(2026-10-12 复测,L3 接线后) |
|
||||
| iec104Task | `640*4` | 2.5KB | IEC104 上行服务(2404 监听 + link 状态机,B4 2026-10-12) | 未上板 / 静态 **1456 B**(拆链→重建监听→net_bind→SPI 故障→日志尾,日志主导;512 words 时余 592 B < ISR 底线 → 抬至 640,余 1104 B / 43%) |
|
||||
| protectTask | `512*4` | 2KB | 保护判据节拍(prot_elm_run 消费者 + L5-4 采样闭锁,B5 2026-10-12) | 未上板 / 静态 **872 B**(float 判据 + phasor 快照 + 日志尾,余 1176 B / 57%) |
|
||||
@@ -224,7 +224,7 @@ C2 dhara 失败类 +84;RO 另 +208,全是 C2 的失败类名表)→ `ER_IR
|
||||
> 本表随代码变化;权威数字与占比见 §2.1 受管快照(`ER_IROM1` / **Flash (ROM 合计)** 行)。
|
||||
> 历史快照:2026-09-21 为 Code 234,976 / RO 13,824 / 合计 ROM 249,432(23.8%);2026-10-10 为 Code 258,516 / RO 16,208 / 合计 ROM 275,604(26.3%)。
|
||||
|
||||
> **2026-10-11 裁剪 LVGL 死代码(原审查报告 F-1/F-2/F-3,已销项)**:`Lib/lv_conf.h` 显式关掉 10 个 `LV_DRAW_SW_SUPPORT_*`(只留 I1)、5 个未用控件类(label / button / buttonmatrix / bar / textarea)、`LV_USE_THEME_SIMPLE`、`LV_USE_FLEX` / `LV_USE_GRID` → **`ER_IROM1` 274,724 → 210,148 B(省 64,576 B = 旧镜像的 23.5%)**,Flash 占比 26.3% → **20.1%**。
|
||||
> **2026-10-11 裁剪 LVGL 死代码(原审查报告的三条裁剪建议,已销项)**:`Lib/lv_conf.h` 显式关掉 10 个 `LV_DRAW_SW_SUPPORT_*`(只留 I1)、5 个未用控件类(label / button / buttonmatrix / bar / textarea)、`LV_USE_THEME_SIMPLE`、`LV_USE_FLEX` / `LV_USE_GRID` → **`ER_IROM1` 274,724 → 210,148 B(省 64,576 B = 旧镜像的 23.5%)**,Flash 占比 26.3% → **20.1%**。
|
||||
> 对象级对照(`.map` 组件表,Code+RO+RW):`blend_to_*` 40,582 → 1,338(其中 `blend_to_i1` 自身 5,272 → 1,338——它按**源**格式的分支也一并消失);控件类 13,397 → 0;`lv_theme_simple` 866 → 0;`lv_draw_sw_transform` 4,340 → 598;`lv_theme_mono` 1,400 → 1,036;镜像内对象数 227 → 212。实测比原报告估算(54,630 B)多省约 10 KB,差额正是这些"锚点消失后连带消失的分支"。
|
||||
> ⚠ **配套本地补丁**:`lv_draw_sw_blend_to_i1.c` 的 `lv_color16_from_u16` 上游 9.3.0 漏了定义处守卫(唯一使用点全在 `#if LV_DRAW_SW_SUPPORT_RGB565_SWAPPED` 内)→ 关掉该格式后 ARMCC 报 `#177-D declared but never referenced`(破坏"0 警告"门禁)。已按使用点补同一守卫,升级 LVGL 时若上游已修可去掉。
|
||||
> 验证:ui-verify 五步全过——**11 页内容黄金参考在裁剪前生成、裁剪后逐字节一致**,菜单 8 状态像素一致,LVGL 池水位 5,440 → 5,368 B(−72 B,样式表更小,一次性残留仍 80 B);`@build` 0 错 0 警;`@test` 真机 PASS。详见 `../UI设计/UI_设计架构.md` §4.1.4 第 10 条。
|
||||
@@ -420,9 +420,9 @@ void vApplicationMallocFailedHook(void)
|
||||
- testTask 在产品构建里只是 `osDelay` 空循环(168 B);2048 words 是给**存储套件构建**(`TEST_SUITE_STORAGE`)预留的,测套件时应重跑本脚本看该构建的静态值。
|
||||
- **测 ftpTask 的复现配方**:设备就绪后跑 `& '.venv\Scripts\python.exe' test/host/ftp_speed_test.py --size 128`(STOR 128KB + RETR + 逐字节比对),再按上面命令叠加串口日志出报告。**不要用裸 TCP 工具探测 21 端口**——CH395F 单客户端复用,探测会占掉唯一会话(见 `docs/测试说明/FTP_Test_Guide.md` §8.9)。
|
||||
|
||||
#### 2026-10-10 复测:**不抬栈**把 defaultTask 从 FAIL 拉回 PASS(S-1 销项)
|
||||
#### 2026-10-10 复测:**不抬栈**把 defaultTask 从 FAIL 拉回 PASS(该项销项)
|
||||
|
||||
触发点:登记簿 S-1(2026-10-04 实测 defaultTask 3664B/4096,余量 10%)。叠加静态链后判据更严——
|
||||
触发点:2026-10-04 实测 defaultTask 3664B/4096(余量 10%)的登记项。叠加静态链后判据更严——
|
||||
**静态最坏链已涨到 5312 B > 配置 4096 B(margin −1216 B)**。本次刻意**不动栈值**,改为削链:
|
||||
|
||||
| 任务 | 配置 (B) | 静态最坏 改前 → 改后 | 实测峰值 改前 → 改后 | 判定 |
|
||||
@@ -445,7 +445,7 @@ void vApplicationMallocFailedHook(void)
|
||||
`FIL` 内含 `buf[FF_MAX_SS]` = 512 B。落点 `App/log/sys_log_mcu.c`(3 处)、
|
||||
`App/cfg/cfg_file_store_mcu.c`(2 处)、`App/task/default_task.c` 探针宏(1 处)。
|
||||
安全性依据:整个 FIL 生命周期都在 `vol_lock_wait()/release()` 区间内(跨任务被卷锁串行化)
|
||||
+ 配置引擎/syslog 写者单任务属主(P1-3)。先例 = 2026-09-21 lftpd 9 处大局部缓冲静态化。
|
||||
+ 配置引擎/syslog 写者单任务属主(单写者契约)。先例 = 2026-09-21 lftpd 9 处大局部缓冲静态化。
|
||||
3. **日志行缓冲按模块收紧 + 时间戳缓冲并入行缓冲**(每个日志调用点原内联 `192 + 32 = 224 B`):
|
||||
`dbg_log.h` 新增 `DBG_LINE_BUF_MAX`(默认仍 = `DBG_CON_LINE_MAX` 192),深链模块
|
||||
(`nand_ftl.c`/`gd5f2gq5ue.c`/`cfg_file.c`/`net_cfg.c`/`net_socket.c`/`ch395f.c`/`time_sync.c`/
|
||||
@@ -609,15 +609,15 @@ ISR 余量:该任务运行期间可能被中断打断的最深中断链(SPI/
|
||||
|
||||
| 步骤 | 内容 | 验证 | 状态 |
|
||||
|---|---|---|---|
|
||||
| S1 | 0.1 + 0.2(溢出钩子 + `stack_probe_poll` 栈水位探针,`Src/freertos.c` USER CODE 区) | `@build` 0错0警;`@test` 串口出现每任务 `[STACK]` 报告 | ✅ 2026-09-21 |
|
||||
| S2 | 0.3 `ram_report.py` + 基线 | 脚本输出与 map 人工核对一致 | ✅ 2026-09-21(`data/ram_report_20260921.md`) |
|
||||
| S3 | 全功能回归跑数(菜单/FTP/网络/格式化/浸泡 1h) | 拿到各任务 `free_min` 与堆 free 底值 | ◐ boot + FTP 路径已实测(09-21);全菜单遍历 + 1h 浸泡待补 |
|
||||
| S4 | §4.1.4 lftpd 静态化 + §4.2.1 malloc 修复 | FTP STOR/RETR 大文件 + 长路径回归 | ✅(§4.2.1 于 2026-09-10、§4.1.4 于 2026-09-21 完成) |
|
||||
| S5 | §4.1.1 LVGL 池 40K→16K | UI 全量回归(模拟器 + 实机),无断言失败 | ✅ **2026-10-15**(11 页黄金参考 + 池水位 5,448 B + `@test` 真机 `used=3192`;实测峰值 6,568 B = 池的 40%,§2.6.2) |
|
||||
| S6 | §4.1.2 CCM(scatter + section + 门禁宏) | map 显示 `RW_CCM`;关 `APP_CCM_ENABLE` 也能编译通过 | ⏸ **暂缓(2026-10-15 裁定)**;已完成部分仅 `RW_CCM` + 堆迁入(09-21),缓冲 section 迁移与门禁宏不再排期 |
|
||||
| S7 | §4.1.3 栈缩减(按 S3 数据)+ 复测 | 每任务 `free_min ≥ 新栈×30%`,无溢出钩子触发 | ⏸ **暂缓(2026-10-15 裁定)**(目标值已按 09-21 实测修正,重开时可直接用) |
|
||||
| S8 | §4.2.2 堆 48K→32K + 复测 | 全负载 `heap free ≥ 8KB` | ⏸ **暂缓(2026-10-15 裁定)**;⚠ 2026-10-12 B5 反向扩容至 56 KB,重开时须重跑 `stack_report.py` + 上板 `min_ever` |
|
||||
| S9 | §4.1.5 小项 + 台账/门禁/AGENTS.md | `@build` + `@test` 全绿 | ◐ AGENTS.md 内存条目已增补(09-21);台账 / 趋势 / `mem-budget` 三件套 ✅ 2026-10-12(**常开,不受暂缓影响**) |
|
||||
| 步骤 1 | 0.1 + 0.2(溢出钩子 + `stack_probe_poll` 栈水位探针,`Src/freertos.c` USER CODE 区) | `@build` 0错0警;`@test` 串口出现每任务 `[STACK]` 报告 | ✅ 2026-09-21 |
|
||||
| 步骤 2 | 0.3 `ram_report.py` + 基线 | 脚本输出与 map 人工核对一致 | ✅ 2026-09-21(`data/ram_report_20260921.md`) |
|
||||
| 步骤 3 | 全功能回归跑数(菜单/FTP/网络/格式化/浸泡 1h) | 拿到各任务 `free_min` 与堆 free 底值 | ◐ boot + FTP 路径已实测(09-21);全菜单遍历 + 1h 浸泡待补 |
|
||||
| 步骤 4 | §4.1.4 lftpd 静态化 + §4.2.1 malloc 修复 | FTP STOR/RETR 大文件 + 长路径回归 | ✅(§4.2.1 于 2026-09-10、§4.1.4 于 2026-09-21 完成) |
|
||||
| 步骤 5 | §4.1.1 LVGL 池 40K→16K | UI 全量回归(模拟器 + 实机),无断言失败 | ✅ **2026-10-15**(11 页黄金参考 + 池水位 5,448 B + `@test` 真机 `used=3192`;实测峰值 6,568 B = 池的 40%,§2.6.2) |
|
||||
| 步骤 6 | §4.1.2 CCM(scatter + section + 门禁宏) | map 显示 `RW_CCM`;关 `APP_CCM_ENABLE` 也能编译通过 | ⏸ **暂缓(2026-10-15 裁定)**;已完成部分仅 `RW_CCM` + 堆迁入(09-21),缓冲 section 迁移与门禁宏不再排期 |
|
||||
| 步骤 7 | §4.1.3 栈缩减(按步骤 3 数据)+ 复测 | 每任务 `free_min ≥ 新栈×30%`,无溢出钩子触发 | ⏸ **暂缓(2026-10-15 裁定)**(目标值已按 09-21 实测修正,重开时可直接用) |
|
||||
| 步骤 8 | §4.2.2 堆 48K→32K + 复测 | 全负载 `heap free ≥ 8KB` | ⏸ **暂缓(2026-10-15 裁定)**;⚠ 2026-10-12 B5 反向扩容至 56 KB,重开时须重跑 `stack_report.py` + 上板 `min_ever` |
|
||||
| 步骤 9 | §4.1.5 小项 + 台账/门禁/AGENTS.md | `@build` + `@test` 全绿 | ◐ AGENTS.md 内存条目已增补(09-21);台账 / 趋势 / `mem-budget` 三件套 ✅ 2026-10-12(**常开,不受暂缓影响**) |
|
||||
|
||||
每步都必须 `@build` 通过(0 错误 0 警告)后再进入下一步;涉及 UI 的步骤用 `simulator` 先过一遍再上实机。
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# RAM 预算台账(配额 · 趋势 · 门禁)
|
||||
|
||||
> **定位**:`docs/内存管理/RAM使用分析与优化方案.md` §8.2 模板与
|
||||
> 内存治理三件套的**落地件**(2026-10-12,登记簿 N-27 前半)。
|
||||
> 内存治理三件套的**落地件**(2026-10-12,登记簿条目「缩堆迁 CCM 后半(暂缓)」的已落地前半)。
|
||||
> 回答三个问题:**每个子系统还能用多少 RAM**(配额)、**总量趋势往哪走**(基线 TSV)、
|
||||
> **超了怎么拦**(92% 门禁)。
|
||||
>
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
- **门禁**:pre-commit `mem-budget` 钩子(`scripts/ram_baseline.py --gate`)——
|
||||
RW_IRAM1 / RW_CCM 任一 >92% 即拦提交,并打印 Top-10 RW+ZI 对象定位增量;
|
||||
无 `.map` 时自适应跳过(CI 盲区登记在 `docs/任务规划/测试与架构专项.md` A-5 残余)。
|
||||
无 `.map` 时自适应跳过(CI 盲区登记在 `docs/任务规划/测试与架构专项.md`「体积门禁 CI 强制路径」残余)。
|
||||
- **阈值依据**:92% 由 2026-09 体系评审提出、2026-10-12 落地为门禁(提出时的报告条目已随销项删除,闭环说明见 `RAM使用分析与优化方案.md` §4 阶段 3「长效机制」与本文)——留 ~8% 给突发缓冲与栈抬升,
|
||||
触线即触发排期,而不是静默逼近溢出。
|
||||
- **软提醒**(不拦提交):tsv 末行落后于 `.map`(忘跑 `--update`)、`.map` 早于最新源码(忘 `@build`)。
|
||||
@@ -56,9 +56,9 @@ UI 16 KB / RTOS 堆 56 KB / 应用 8 KB**。归集口径(按 `.map` 对象名
|
||||
|
||||
**现状判读(2026-10-12 建档)**:
|
||||
|
||||
- **UI ⚠ 超配额 = 已知长期挂账,不是新增违规**:LVGL 池 16 KB(R-9 已于 2026-10-15 落地,由 40 KB 收缩)+
|
||||
帧/远显缓冲 ≈12.8 KB,实测 30,412 B。配额 16 KB 描述的是 **R-2 把 UI 侧缓冲迁进 CCM 之后的目标态**,
|
||||
而 **R-2 后半已按用户裁定 2026-10-15 整簇暂缓**(`docs/任务规划/README.md` §2「预算与内存」已标暂缓)→
|
||||
- **UI ⚠ 超配额 = 已知长期挂账,不是新增违规**:LVGL 池 16 KB(2026-10-15 落地,由 40 KB 收缩)+
|
||||
帧/远显缓冲 ≈12.8 KB,实测 30,412 B。配额 16 KB 描述的是 **把 UI 侧缓冲迁进 CCM 之后的目标态**,
|
||||
而 **该搬迁的后半已按用户裁定 2026-10-15 整簇暂缓**(`docs/任务规划/登记簿.md` §5 保留重启条件)→
|
||||
**这条 ⚠ 会长期挂着**,判读时按已知挂账处理,别每轮当新问题追;重开条件 → `RAM使用分析与优化方案.md` §4。
|
||||
- **RTOS 堆 = 配额本身**:56 KB 即 `configTOTAL_HEAP_SIZE`(2026-10-12 B5 由 48 KB 扩容,见 §6;
|
||||
`heap_4.o` 另含 32 B 元数据,不计超);**改堆 = 改配额**,必须先过本文件 §6 登记。
|
||||
@@ -72,9 +72,9 @@ UI 16 KB / RTOS 堆 56 KB / 应用 8 KB**。归集口径(按 `.map` 对象名
|
||||
|---|---|---|
|
||||
| CCM 容量 | `RW_CCM` Max 见受管区 | scatter `RW_CCM`;**仅 CPU 可达,DMA 不可达**(RM0090 §3.1.1) |
|
||||
| 现占用 | 仅 FreeRTOS 堆 `heap_4`(56 KB,2026-09-21 迁入;2026-10-12 B5 扩容 48→56 KB) | 其余候选全部仍在 SRAM1 |
|
||||
| 现余量 | 受管区 RW_CCM 容量 − 占用 = **7,904 B** | **不够** R-2 后半的 UI 侧待迁体量(R-9 后 **29,570 B**)——⏸ 该搬迁已暂缓,见下行 |
|
||||
| R-2 后半解锁链 | ⏸ **整簇暂缓(用户裁定 2026-10-15)**,本行保留作重开时的现状基线:① **R-9 ✅ 2026-10-15**:`LV_MEM_SIZE` 40→16 KB → 待迁体量 54,146 → **29,570 B**(SRAM1 74.9% → **56.1%**,实测池峰值 6,568 B)→ ② ~~现在卡在这一步~~:堆 56→32 KB(`docs/内存管理/RAM使用分析与优化方案.md` §4.2.2(阶段 2 第 2 项"缩堆"),再腾 24 KB;⚠ 2026-10-12 B5 反向扩容至 56 KB——9 任务栈 + 队列实测需要,缩回 32 KB 前必须重跑 `stack_report.py` + 上板 min_ever 复测)→ ③ CCM 余 ≈31.9 KB ≥ 29,570 B → 迁入 | **暂缓期间不启动**;重开条件 → `RAM使用分析与优化方案.md` §4。**若重开,顺序不可颠倒**;每步前后跑 `stack_report.py` / `ram_report.py`(铁律) |
|
||||
| 迁入前置 | 目标缓冲必须过 DMA 可达性清单(`内存内容分配策略.md`) | 违例 = 静默传错(N-11 同类坑);克隆芯片 CCM 可靠性风险见 `docs/内存管理/RAM使用分析与优化方案.md` §7 |
|
||||
| 现余量 | 受管区 RW_CCM 容量 − 占用 = **7,904 B** | **不够** 迁 CCM 后半的 UI 侧待迁体量(缩池后 **29,570 B**)——⏸ 该搬迁已暂缓,见下行 |
|
||||
| 迁 CCM 后半解锁链 | ⏸ **整簇暂缓(用户裁定 2026-10-15)**,本行保留作重开时的现状基线:① **缩池 ✅ 2026-10-15**:`LV_MEM_SIZE` 40→16 KB → 待迁体量 54,146 → **29,570 B**(SRAM1 74.9% → **56.1%**,实测池峰值 6,568 B)→ ② ~~现在卡在这一步~~:堆 56→32 KB(`docs/内存管理/RAM使用分析与优化方案.md` §4.2.2(阶段 2 第 2 项"缩堆"),再腾 24 KB;⚠ 2026-10-12 B5 反向扩容至 56 KB——9 任务栈 + 队列实测需要,缩回 32 KB 前必须重跑 `stack_report.py` + 上板 min_ever 复测)→ ③ CCM 余 ≈31.9 KB ≥ 29,570 B → 迁入 | **暂缓期间不启动**;重开条件 → `RAM使用分析与优化方案.md` §4。**若重开,顺序不可颠倒**;每步前后跑 `stack_report.py` / `ram_report.py`(铁律) |
|
||||
| 迁入前置 | 目标缓冲必须过 DMA 可达性清单(`内存内容分配策略.md`) | 违例 = 静默传错(越界不校验的同类坑);克隆芯片 CCM 可靠性风险见 `docs/内存管理/RAM使用分析与优化方案.md` §7 |
|
||||
|
||||
## 4. 趋势基线(`scripts/ram_baseline.tsv`)
|
||||
|
||||
@@ -94,5 +94,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` L1 参数 `configTOTAL_HEAP_SIZE` 49152→57344(CCM 水位 75.3%→87.9%,仍 <92% 门禁;CCM 空闲降至 ≈8 KB)。连带影响见 §3 R-2 后半链注记 |
|
||||
| 2026-10-12 | **RTOS 堆配额 48 KB → 56 KB**(`QUOTAS` 同步) | B5 protectTask 立项:iec104Task(2.5KB)+protectTask(2KB)+TCB 入堆后 48KB 池 min_ever 预估跌破 3,072 B 告警线 → `.ioc` L1 参数 `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 |
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
> 版本:v1.0 日期:2026-09-21
|
||||
> 适用工程:STM32F4-Base(STM32F407ZGTx @168MHz,FreeRTOS V10.3.1 + CMSIS-RTOS2,Keil MDK v5 / ARMCC)
|
||||
> 状态:**当前有效策略**(台架验证:产品构建 gen68 干净启动 61 行;存储套件 20/20 PASSED;恢复跑 3/3 PASSED)
|
||||
> 状态:**当前有效策略**(台架验证:产品构建台架日志代次 68 干净启动 61 行;存储套件 20/20 PASSED;恢复跑 3/3 PASSED)
|
||||
> 关联文档:`RAM使用分析与优化方案.md`(**内存管理主文档**:容量审计 + 优化方案 + 观测工具 + 基线数据)
|
||||
> 布局实现:`MDK-ARM/STM32F407-Demo/STM32F407-Demo.sct`
|
||||
|
||||
@@ -91,7 +91,7 @@ CCM 64KB 只能容纳 {FreeRTOS 堆 48KB} 与 {LVGL 集合 ~52.5KB} 之一(两
|
||||
1. **致命类优先**:方案 B 把 48KB 调度内存放回 SRAM,与全部潜在溢出源(含 FatFS、dhara 两个有实证事故史的第三方组件)同处一域;本项目实证过的故障族正是 1 字节类越界。
|
||||
2. **DMA 不可达对堆是防护**:任何 DMA 野地址/错地址传输都无法落入 CCM(静默不落地,发起方表现为可检测的"数据未到"),调度器因此免疫 DMA 类故障;方案 B 中该防护失效。
|
||||
3. **LVGL 残余风险已被现有手段兜住**:32B 保护带 + canary 实证 + `configCHECK_FOR_STACK_OVERFLOW=2` + malloc 失败钩子;已发生的 1 字节越界被完整 containment。
|
||||
4. **"UI bug 最多弄坏屏幕、弄不死系统"是台架既成事实**:越界发生时 CCM 中的调度器毫发无伤(gen68 干净启动、存储套件 20/20),这正是方案 A 的直接收益。
|
||||
4. **"UI bug 最多弄坏屏幕、弄不死系统"是台架既成事实**:越界发生时 CCM 中的调度器毫发无伤(台架日志代次 68 干净启动、存储套件 20/20),这正是方案 A 的直接收益。
|
||||
|
||||
### 5.4 方案 B 的胜出点(如实记录,不足以翻盘)
|
||||
|
||||
@@ -107,7 +107,7 @@ CCM 64KB 只能容纳 {FreeRTOS 堆 48KB} 与 {LVGL 集合 ~52.5KB} 之一(两
|
||||
|
||||
### 5.6 若未来确需改判
|
||||
|
||||
触发条件:测试构建 SRAM 余量不足,**且**已耗尽 `RAM使用分析与优化方案.md` 的 R-4 帧副本去重(−6.4~9.6KB)与 LVGL 池缩减等低代价手段。
|
||||
触发条件:测试构建 SRAM 余量不足,**且**已耗尽 `RAM使用分析与优化方案.md` 的帧副本去重(−6.4~9.6KB)与 LVGL 池缩减等低代价手段。
|
||||
流程:改 scatter → 走 §7 完整验证阶梯 → 同步更新本文档、`AGENTS.md`、`.sct` 头注释。在此之前,方案 A 是唯一有效布局。
|
||||
|
||||
## 6. 当前容量台账(2026-10-12,产品构建;2026-09-21 最坏构建=存储套件的历史基线见 `docs/内存管理/RAM预算台账.md` 趋势)
|
||||
|
||||
+27
-27
@@ -1,17 +1,17 @@
|
||||
# 存储栈 RAM 优化调研
|
||||
|
||||
> 版本 v1.2 日期 2026-10-23(v1.2:新增 §5 页缓冲可合并性论证,承接报告的 N-15) 作者 AI 辅助调研
|
||||
> 版本 v1.2 日期 2026-10-23(v1.2:新增 §5 页缓冲可合并性论证,承接原报告那条待评估项) 作者 AI 辅助调研
|
||||
> 数据来源:`data/ram_report_20260921.md`(.map 静态占用)+ 逐行代码核验(`nand_ftl.c` / `gd5f2gq5ue.c` / `Lib/dhara` / `Lib/FatFs/ffconf.h` / `lftpd*`)
|
||||
> 定位:`RAM使用分析与优化方案.md` 的存储专项补充;优化项编号 P0/P1/P2,与 `docs/内存管理/RAM使用分析与优化方案.md` §6 的 S 序号在"规划"一节对齐
|
||||
> v1.1 清理(2026-09-21 同日):移除已落地的 P0-1 BBT 页缓冲收缩(−1,776B,commit `be1a30a`)与编程回读校验整体移除的实施记录(详见 GD5F TRAP-GD5F-05),以及过期逐模块基线表;仅保留未实施项与回归要求
|
||||
> ⏸ **实施状态(用户裁定 2026-10-15)**:本文**全部未实施项整簇暂缓、不再排期**——P0-2 页缓冲合并(= 报告 R-3)、P1-5 ①② 迁 CCM、以及依赖"堆 48K→32K"的第三步。当前没有功能在等这块预算,而搬迁要逐条过 DMA 可达性清单(违例是静默传错不是报错)。**保持常开**的是测量与门禁面(`ram_report.py` / `stack_report.py` / `mem-budget` 92% 门禁 / 台账 / 趋势)。理由与重开条件 → `RAM使用分析与优化方案.md` §4;本文保留作重开时的实施依据,**不代表现在要做**。
|
||||
> v1.1 清理(2026-09-21 同日):移除已落地的 BBT 页缓冲收缩(−1,776B,commit `be1a30a`)与编程回读校验整体移除的实施记录(详见 GD5F TRAP-GD5F-05),以及过期逐模块基线表;仅保留未实施项与回归要求
|
||||
> ⏸ **实施状态(用户裁定 2026-10-15)**:本文**全部未实施项整簇暂缓、不再排期**——`s_copy_buf` 分块(原报告的同一评估项)、`APP_CCM_ENABLE` 的 ①② 迁 CCM、以及依赖"堆 48K→32K"的第三步。当前没有功能在等这块预算,而搬迁要逐条过 DMA 可达性清单(违例是静默传错不是报错)。**保持常开**的是测量与门禁面(`ram_report.py` / `stack_report.py` / `mem-budget` 92% 门禁 / 台账 / 趋势)。理由与重开条件 → `RAM使用分析与优化方案.md` §4;本文保留作重开时的实施依据,**不代表现在要做**。
|
||||
|
||||
## 1. 现状约束(不变,是下述全部方案的依据)
|
||||
|
||||
- 存储栈静态 RAM 全在 **RW_IRAM1(主 SRAM 128KB)**;页缓冲(nand_ftl 3×2KB + gd5f 页缓冲/位图)走 SPI1 DMA(阈值 >1024B),**DMA1/DMA2 物理不可达 CCM** → 不能直迁 CCM(唯一途径:迁移 + `gd5f_dma_buf_ok()` 运行时守卫自动回落 CPU 轮询(2026-09-21 加固),不会静默失败,代价仅每页零点几 ms CPU)
|
||||
- 3×2KB 页缓冲是结构成本不可直缩:dhara journal 要求整页 checkpoint(`journal.c:196` 整页 memset);512B 扇区落 2KB 页必须整页 RMW;可动的只有 `s_copy_buf`(→ P0-2)
|
||||
- CPU-only 缓冲(lftpd static ~3.6K / cfg_file 0.7K / FATFS win 0.6K / lftpd_io 0.6K)迁 CCM 零代价(→ P1-5①)
|
||||
- 栈上 FIL 重复占深链:syslog 两处、cfg 存储两处、开机探针各一个局部 `FIL`(每个含 512B 私有 buf,≈552B),全压在 defaultTask 最坏链 2,776B 内(→ P1-4 靶点)
|
||||
- 3×2KB 页缓冲是结构成本不可直缩:dhara journal 要求整页 checkpoint(`journal.c:196` 整页 memset);512B 扇区落 2KB 页必须整页 RMW;可动的只有 `s_copy_buf`(见 §2 分块方案)
|
||||
- CPU-only 缓冲(lftpd static ~3.6K / cfg_file 0.7K / FATFS win 0.6K / lftpd_io 0.6K)迁 CCM 零代价(见 §2 迁 CCM 方案 ①)
|
||||
- 栈上 FIL 重复占深链:syslog 两处、cfg 存储两处、开机探针各一个局部 `FIL`(每个含 512B 私有 buf,≈552B),全压在 defaultTask 最坏链 2,776B 内(靶点见 §2 `FF_FS_TINY` 行)
|
||||
- FatFs 配置已低 RAM 取向:`FF_MAX_SS=512`、`FF_USE_LFN=0`、`FF_VOLUMES=1`、`FF_FS_LOCK=0`;`FF_FS_REENTRANT=1` 为 defaultTask/ftpTask 并发访问必需,勿动
|
||||
- 教训(2026-09-21):任何比对式校验必须在**两份独立副本**间进行(U-Boot `sf test` 双缓冲形态)——旧 GC 拷贝自比对缺陷已随回读校验整体移除而消失;若未来测试构建恢复回读诊断,勿重蹈此坑
|
||||
|
||||
@@ -19,13 +19,13 @@
|
||||
|
||||
| # | 方案 | 省 RAM | 区域 | 风险 | 验证 |
|
||||
|---|---|---:|---|---|---|
|
||||
| P0-2 | `s_copy_buf` 2048→512:GC 拷贝改分段 read→program_load(`program_load`/`read_from_cache` 支持列地址);纯 RAM 优化(GC 拷贝暂存减半) | **−1,536B(可选,不计入当前预期)** | SRAM1 | 低(仅动拷贝机制) | 待 RAM 余量需要时再议 |
|
||||
| P0-3 | lftpd 缓冲收紧:response 512→256、read_buffer 512→256、arg_buf 512→256、name 256→128 ×2(本卷仅 8.3 短名,路径深度浅);数据块 2×1024 与 message 不动 | **−1,024B** | SRAM1 | 低(FTP 客户端实测行长远低于新值) | `@build` + FTP 上传/下载/LIST 闭环 + `@test` |
|
||||
| P1-4 | `FF_FS_TINY=1`:删每 FIL 私有的 512B buf,文件数据走 `FatFs->win` 共享窗 | 静态 **−528B**;且栈上每处 FIL 峰值 **−528B**(defaultTask 最坏链 2,776→~2,250,实测峰 2,136→~1,600) | SRAM1 + CCM 栈 | 中(所有文件 I/O 经 512B 窗 bounce,FTP 吞吐 −20~40%;LIST 与文件读交错只影响速度) | 存储套件 + FTP 吞吐实测 + 日志/配置闭环;**与 S7 缩栈捆绑**(直接支撑 defaultTask 降档) |
|
||||
| P1-5 | `APP_CCM_ENABLE` 门(与 S6 同宏):①CPU-only 缓冲迁 CCM——lftpd static 3.6K + cfg_file 0.7K + FATFS win 0.6K + lftpd_io ≈ **−4.9K** 零代价;②DMA 页缓冲(nand_ftl 4.6K + gd5f 位图/页 0.8K)迁 CCM 走轮询 ≈ **−5.4K**,需实测吞吐 | **−10.3K** | SRAM1→CCM | 低①/中② | 分段实施;每步跑 `ram_report.py` + `@test` + FTP 吞吐 |
|
||||
| P2-6 | NAND copy-back 命令(0x15→0x10)替代主机搬页:省 `s_copy_buf` 的拷贝用途 + 减半 SPI 流量 | −512B(P0-2 后) | SRAM1 | 高(片上 ECC 在 copy-back 下的语义须台架实证) | 仅评估,暂缓 |
|
||||
| P2-7 | lftpd 数据块 2×1024→512 | −1,024B | SRAM1 | 吞吐 −~30% | RAM 仍紧时才做 |
|
||||
| P2-8 | syslog/cfg 共享一个静态 FIL(同任务串行) | 净≈0(静态+528/栈−528) | — | 不推荐:P1-4 已覆盖同一收益面 | — |
|
||||
| `s_copy_buf` 分块 | `s_copy_buf` 2048→512:GC 拷贝改分段 read→program_load(`program_load`/`read_from_cache` 支持列地址);纯 RAM 优化(GC 拷贝暂存减半) | **−1,536B(可选,不计入当前预期)** | SRAM1 | 低(仅动拷贝机制) | 待 RAM 余量需要时再议 |
|
||||
| lftpd 缓冲收紧 | lftpd 缓冲收紧:response 512→256、read_buffer 512→256、arg_buf 512→256、name 256→128 ×2(本卷仅 8.3 短名,路径深度浅);数据块 2×1024 与 message 不动 | **−1,024B** | SRAM1 | 低(FTP 客户端实测行长远低于新值) | `@build` + FTP 上传/下载/LIST 闭环 + `@test` |
|
||||
| `FF_FS_TINY` 共享窗 | `FF_FS_TINY=1`:删每 FIL 私有的 512B buf,文件数据走 `FatFs->win` 共享窗 | 静态 **−528B**;且栈上每处 FIL 峰值 **−528B**(defaultTask 最坏链 2,776→~2,250,实测峰 2,136→~1,600) | SRAM1 + CCM 栈 | 中(所有文件 I/O 经 512B 窗 bounce,FTP 吞吐 −20~40%;LIST 与文件读交错只影响速度) | 存储套件 + FTP 吞吐实测 + 日志/配置闭环;**与 RAM方案 实施步骤 7 的缩栈捆绑**(直接支撑 defaultTask 降档) |
|
||||
| `APP_CCM_ENABLE` 迁 CCM | `APP_CCM_ENABLE` 门(与 RAM方案 实施步骤 6 同宏):①CPU-only 缓冲迁 CCM——lftpd static 3.6K + cfg_file 0.7K + FATFS win 0.6K + lftpd_io ≈ **−4.9K** 零代价;②DMA 页缓冲(nand_ftl 4.6K + gd5f 位图/页 0.8K)迁 CCM 走轮询 ≈ **−5.4K**,需实测吞吐 | **−10.3K** | SRAM1→CCM | 低①/中② | 分段实施;每步跑 `ram_report.py` + `@test` + FTP 吞吐 |
|
||||
| NAND copy-back | NAND copy-back 命令(0x15→0x10)替代主机搬页:省 `s_copy_buf` 的拷贝用途 + 减半 SPI 流量 | −512B(`s_copy_buf` 分块后) | SRAM1 | 高(片上 ECC 在 copy-back 下的语义须台架实证) | 仅评估,暂缓 |
|
||||
| lftpd 数据块减半 | lftpd 数据块 2×1024→512 | −1,024B | SRAM1 | 吞吐 −~30% | RAM 仍紧时才做 |
|
||||
| 共享静态 FIL | syslog/cfg 共享一个静态 FIL(同任务串行) | 净≈0(静态+528/栈−528) | — | 不推荐:`FF_FS_TINY` 那条已覆盖同一收益面 | — |
|
||||
|
||||
**明确不做**:移除 dhara(丢掉电一致性与坏块重映射,代价不对称);journal checkpoint 分片(违反 dhara 协议);调 `gc_ratio`(无 RAM 收益);`FF_FS_REENTRANT=0`(defaultTask+ftpTask 并发访问 FatFs 必需)。
|
||||
|
||||
@@ -33,20 +33,20 @@
|
||||
|
||||
| 阶段 | 内容 | 收益 | 前置 |
|
||||
|---|---|---:|---|
|
||||
| **第一步**(独立小批) | P0-3(P0-2 搁置,待 RAM 余量需要时再议) | **−1,024B** | 无 |
|
||||
| **第二步**(并入 S7 缩栈批) | P1-4 `FF_FS_TINY=1` → 复跑 `stack_report.py` → defaultTask 降档(最坏链 ~2,250 支撑 3,584B 配置,余量 37%)+ 其余任务按 S7 目标 | −528B 静态 + 栈档下调释放 CCM 堆 | 第一步合入 |
|
||||
| **第三步**(与 S6/S8 同批) | 先 S8 堆 48K→32K(CCM 释放 ~16K),再 P1-5 ①→② 分批迁 CCM | SRAM1 再 **−10.3K**;CCM 占用 +10.3K(由 S8 腾挪覆盖) | S8 或同批评估 CCM 水位 |
|
||||
| **第一步**(独立小批) | lftpd 缓冲收紧(`s_copy_buf` 分块搁置,待 RAM 余量需要时再议) | **−1,024B** | 无 |
|
||||
| **第二步**(并入 RAM方案 步骤 7 的缩栈批) | `FF_FS_TINY=1` → 复跑 `stack_report.py` → defaultTask 降档(最坏链 ~2,250 支撑 3,584B 配置,余量 37%)+ 其余任务按该步骤 7 目标 | −528B 静态 + 栈档下调释放 CCM 堆 | 第一步合入 |
|
||||
| **第三步**(与 RAM方案 步骤 6/8 同批) | 先做步骤 8 的堆 48K→32K(CCM 释放 ~16K),再按迁 CCM 方案 ①→② 分批 | SRAM1 再 **−10.3K**;CCM 占用 +10.3K(由该步腾挪覆盖) | 与步骤 8 同批或同批评估 CCM 水位 |
|
||||
|
||||
**全部落地后存储栈预期**:SRAM1 常驻降至 **~1.9KB**(现 13.7KB,其中 P0-1 已省 1,776B 不重复计;余下仅小状态量),页缓冲驻 CCM(轮询),未实施项合计换回 SRAM1 ≈ **−11.9K**(P0-2 搁置,其 −1,536B 不计);叠加 S5(LVGL 40K→16K)后 SRAM1 余量 >65KB。
|
||||
**全部落地后存储栈预期**:SRAM1 常驻降至 **~1.9KB**(现 13.7KB,其中 BBT 页缓冲收缩已省 1,776B 不重复计;余下仅小状态量),页缓冲驻 CCM(轮询),未实施项合计换回 SRAM1 ≈ **−11.9K**(`s_copy_buf` 分块搁置,其 −1,536B 不计);叠加 RAM方案 步骤 5(LVGL 40K→16K)后 SRAM1 余量 >65KB。
|
||||
|
||||
## 4. 回归与基线
|
||||
|
||||
- **FTP 吞吐基线(2026-09-21 实测,4MB 文件,端到端含网络;瓶颈在存储侧,100M 网络非瓶颈)**:STOR **126.9 KB/s**(32.3s)/ RETR **321.4 KB/s**(12.7s),回传逐字节 MATCH(测试文件已自清理)→ P0-3/P1-4 前后各留一轮实测对比(P1-4 预期吞吐降幅 20~40%)
|
||||
- P1-4 前后各跑一次 `stack_report.py` + `ram_report.py`(AGENTS.md 门禁)
|
||||
- P1-5 的 ②(页缓冲入 CCM 走轮询)须以实测吞吐定去留:若 NAND 读吞吐降幅 >30%,则只迁 CPU-only 侧(①)
|
||||
- P0-2/P2-x:待 RAM 余量需要时再议
|
||||
- **FTP 吞吐基线(2026-09-21 实测,4MB 文件,端到端含网络;瓶颈在存储侧,100M 网络非瓶颈)**:STOR **126.9 KB/s**(32.3s)/ RETR **321.4 KB/s**(12.7s),回传逐字节 MATCH(测试文件已自清理)→ 两条 FTP 相关方案前后各留一轮实测对比(`FF_FS_TINY` 那条预期吞吐降幅 20~40%)
|
||||
- `FF_FS_TINY` 前后各跑一次 `stack_report.py` + `ram_report.py`(AGENTS.md 门禁)
|
||||
- 迁 CCM 方案的 ②(页缓冲入 CCM 走轮询)须以实测吞吐定去留:若 NAND 读吞吐降幅 >30%,则只迁 CPU-only 侧(①)
|
||||
- `s_copy_buf` 分块与 copy-back、数据块减半等小项:待 RAM 余量需要时再议
|
||||
- 下次存储改动照常执行台架破坏性套件 + 掉电 resume
|
||||
- 基线数字可用 `data/ram_report_20260921.md`(P0-1 前快照)复核;实施后重生成基线报告并回填总方案
|
||||
- 基线数字可用 `data/ram_report_20260921.md`(BBT 页缓冲收缩前快照)复核;实施后重生成基线报告并回填总方案
|
||||
|
||||
## 5. 页缓冲可合并性论证(2026-10-23)
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
> (该注释已在本轮改为指向本节)。
|
||||
> 结论:**三块不能合并**(最坏路径上同时存活,合并后的失败形态是**静默数据损坏**,不是报错);
|
||||
> 可削减的只有 `s_copy_buf` 一块,上限 −2,048 B,而**收益落点不是红线区** →
|
||||
> 原报告的 N-15 由"待评估"改为"**已评估、判定不做**"(报告已删除,结论以本节为准),
|
||||
> 原报告的该项由"待评估"改为"**已评估、判定不做**"(报告已删除,结论以本节为准),
|
||||
> 与本文件 §2 那两条残余方案一起留在暂缓簇里。
|
||||
|
||||
### 5.1 6,216 B 的构成(`.map` 实证)
|
||||
@@ -87,7 +87,7 @@
|
||||
这是**跨调用存活的状态**,不是暂存。
|
||||
|
||||
于是第 4 步执行时三块同时持有活数据:待写的缓存页、已攒的 checkpoint 元数据、搬页暂存。
|
||||
任取两块合并,被覆盖的一方都会变成垃圾,而**没有一处会报错**——这与 E-31 / N-21 两次
|
||||
任取两块合并,被覆盖的一方都会变成垃圾,而**没有一处会报错**——这与越界校验、挂载失败处置两次
|
||||
"宁可报错,不可静默"的教训同族,属于必须回避的失败形态。
|
||||
|
||||
### 5.3 逐对否证
|
||||
@@ -116,7 +116,7 @@
|
||||
- 三块页缓冲全在 `RW_IRAM1`(0x2000_0000 窗口内,`gd5f_dma_buf_ok()` 白名单覆盖),该区
|
||||
2026-10-23 实测 **75,264 / 57.4%,余 55,808 B**;
|
||||
- 红线在 **`RW_CCM`:57,376 / 87.9%,余 7,904 B**(FreeRTOS 堆 56 KB 吃掉了它);
|
||||
- 所以这条线即使做满(−2,048 B)也**一分不减红线**;反过来把页缓冲搬进 CCM(本文件 §2 的 P1-5②)
|
||||
- 所以这条线即使做满(−2,048 B)也**一分不减红线**;反过来把页缓冲搬进 CCM(本文件 §2 的迁 CCM 方案 ②)
|
||||
才是"对红线有害"的方向——6,144 B 会吃掉 CCM 余量的 78%;
|
||||
- 把 `s_copy_buf` 挪到栈上同理:defaultTask 静态最坏链 3,024 B / 5,120 B,再塞 2 KB 直接顶到上限,
|
||||
而任务栈本身就在 CCM。
|
||||
@@ -133,8 +133,8 @@ grep -n "s_page_buf\|s_cache_buf\|s_copy_buf" MDK-ARM/STM32F407-Demo/STM32F407-D
|
||||
|
||||
### 5.7 顺带订正的两处注释
|
||||
|
||||
- `nand_ftl.c:300` 原写"页缓冲三块不可合并的评估见报告 R-3",而报告里此前**没有**这份评估
|
||||
- `nand_ftl.c:300` 原写"页缓冲三块不可合并的评估见报告",而报告里此前**没有**这份评估
|
||||
→ 改为指向本节。
|
||||
- `nand_ftl.c:405` 原写"`s_page_buf` 现仅装 dhara meta 132 B 走轮询",**不成立**:`s_page_buf` 是
|
||||
按整页编程的(`journal.c:992` → `dhara_nand_prog` → `gd5f_program_load(0, data, 2048)`),
|
||||
与另两块一样走 DMA。原文这句话会误导后来做 P1-5②(迁 CCM)的人,已按实况改写。
|
||||
与另两块一样走 DMA。原文这句话会误导后来做迁 CCM ②的人,已按实况改写。
|
||||
|
||||
@@ -320,7 +320,7 @@ t = 1000 µs 下一个更新事件
|
||||
|
||||
| 项 | 现状 | 说明 / 出口 |
|
||||
|---|---|---|
|
||||
| **8 路电气量分属两片转换器** | 跨转换器**没有共同采样触发点** → 无同一时刻性、相位不确定 | **V0.1 硬件缺陷**(登记簿 N-18):V0.1 上**禁止**跨转换器做相位 / 功率 / 功率因数 / 矢量运算;根治要改板(8 路全接 TPAFE) |
|
||||
| **8 路电气量分属两片转换器** | 跨转换器**没有共同采样触发点** → 无同一时刻性、相位不确定 | **V0.1 硬件缺陷**(登记簿条目「双转换器无共同采样触发」):V0.1 上**禁止**跨转换器做相位 / 功率 / 功率因数 / 矢量运算;根治要改板(8 路全接 TPAFE) |
|
||||
| STM32 侧数据滞后 | 固定 1 拍(1 ms) | 乒乓半区的结构代价;因上一条,不新增误差(§4.4) |
|
||||
| TPAFE 侧仍是"脉冲 + 中断读" | ISR 内 GPIO 脉冲、`BUSY` EXTI 逐通道读 8 次,**未 DMA 化** | 单点成本约 0.5 µs,非当前瓶颈;DMA / FMC 化的**前提未定**:接口类型与 `DRDY`、读时序须先用逻辑分析仪确认 |
|
||||
| 等周波调频 | **硬件侧已具备**:1 µs 分辨率 + ARR 预装载 + 唤醒与生产同源 → 运行期 `__HAL_TIM_SET_AUTORELOAD(&htim3, 周期µs - 1)` 即可无毛刺改频,**消费节拍自动跟随** | 采样率随动到相量窗与定值不在本层;测频见 `App/algo/freq.c`,上位需求见 `docs/算法/继电保护功能复现规划.md` §3.1 |
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
> **定位**:DTU 上行规约 IEC 60870-5-104(DL/T 634.5104-2009)的设计基线——
|
||||
> 范围、点表、链路流程、板端接入、预算与测试。规格来源
|
||||
> `docs/算法/继电保护功能复现规划.md` §1.5(B0 产品定义,验收 = 省电科院点表);
|
||||
> 代码落点 `App/protocol/iec104/`;未闭环的验收项挂 `docs/任务规划/采集保护收尾.md`(B10 送检)。
|
||||
> 代码落点 `App/protocol/iec104/`;未闭环的送检验收挂 `docs/任务规划/登记簿.md` §7。
|
||||
> **角色**:本 DTU = **被控站(受控端)**,104 **TCP 服务器,端口 2404**;主站
|
||||
> (控制端,点表参考 `192.168.1.199`)主动连入。
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
| 定值 | C_RD 读 + C_SE_NC 两段写(地址 = prot_set `comm_addr`) | 定值区切换/下装文件 |
|
||||
| 其他 | C_CS 对时(→ `sys_clock`)、C_TS、C_RP | 固有参数 8001H~800AH(字符串类)、C_CI 电度、文件传输(录波) |
|
||||
|
||||
## 2. 分层与模块(A-4 约束 1:协议解析与硬件 I/O 分离)
|
||||
## 2. 分层与模块(采集链路测试可验证性约束:协议解析与硬件 I/O 分离)
|
||||
|
||||
| 模块 | 文件 | 职责 | I/O |
|
||||
|---|---|---|---|
|
||||
@@ -37,7 +37,7 @@
|
||||
| IOA | 点 | 来源 | V0.1 状态 |
|
||||
|---|---|---|---|
|
||||
| 0x4011 | 1Ua | L2 遥测快照槽 `ADC_SEM_UA`(卡 9) | ✅ 有效 |
|
||||
| 0x4012/0x4013 | 1Ub/1Uc | 同表槽位;STM32 侧削顶(`docs/算法/继电保护功能复现规划.md` §1.6) | ❌ 发 IV——**品质驱动**(快照 CLIPPED 位映射,非点表绑死;V0.2/N-18 消失后零改动自动启用) |
|
||||
| 0x4012/0x4013 | 1Ub/1Uc | 同表槽位;STM32 侧削顶(`docs/算法/继电保护功能复现规划.md` §1.6) | ❌ 发 IV——**品质驱动**(快照 CLIPPED 位映射,非点表绑死;V0.2 消除双转换器无共同采样触发后零改动自动启用) |
|
||||
| 0x4014 | 1U0 | 快照槽 `ADC_SEM_UN`(外部零序专用通道) | ✅ 有效 |
|
||||
| 0x4015 | 1Ia | 快照槽 `ADC_SEM_IA` | ✅ 有效 |
|
||||
| 0x4016~0x4018 | 1Ib/1Ic/1I0 | 同 Ub/Uc:绑槽 + 品质驱动 | ❌ 发 IV |
|
||||
@@ -169,11 +169,11 @@
|
||||
- **门控 + 兜底**:`net_listener_armed`/`net_can_read`(纯 RAM 读)省无谓 RPC 往返
|
||||
(门控不用只认 ESTABLISHED 的 `net_can_accept`——那会把监听
|
||||
服役窗口全挡掉,CONNECT 事件补 accept 探针从不运行);
|
||||
每 32 轮无条件 recv 一次防 RECV_OK 事件未收到(ui_net_sink I-1/I-2 先例)。
|
||||
每 32 轮无条件 recv 一次防 RECV_OK 事件未收到(沿用 UI 推流侧「周期 recv 兜事件丢失」的先例)。
|
||||
- **网络代次自愈**:`net_get_generation()` 变化 → 关旧 fd 重建监听(netTask
|
||||
NET_RECONFIG 重建路径的既有约定)。
|
||||
- **主动拆链**(与 EOF 路径相对):协议故障(坏帧/N(R) 倒退/t1 超时)或发送连续
|
||||
3 次失败(E-04 短写先例)→ 本端 `net_close` + 重建监听,促主站重连——违例时
|
||||
3 次失败(短写先例)→ 本端 `net_close` + 重建监听,促主站重连——违例时
|
||||
主站不会自行断开,必须本端断(time_sync 会话收尾先例,非芯片 auto_relisten 风暴路径)。
|
||||
- **抢占策略修正(V0.1 如实登记)**:建档时定"后连优先",实现后确认单连接
|
||||
socket 在连接态无法 accept(监听即数据通道),**V0.1 实为首到优先**——旧会话
|
||||
|
||||
+30
-30
@@ -3,7 +3,7 @@
|
||||
> **版本**:v1.5(已实施;修订史见文末「修订记录」)
|
||||
> **日期**:2026-10-24(v1.5;初版 v1.0 于 2026-09-25)
|
||||
> **状态**:已实施并验证——`@build` 0 错误 0 警告、`@test` 硬件闭环 PASS(2026-09-25,见 §10);设计 2026-09-24 加固实施(当时位于 `Src/usart.c` USER CODE 区),2026-09-25 实现迁出至 `App/log/`(HAL 生成文件不含应用代码);同日写者任务体自 `Src/freertos.c` 迁至 `App/task/default_task.c`(与其余 5 任务文件同址归位)
|
||||
> **关联文档**:`项目架构总览.md` · `运行与自检记录设计说明.md`(姊妹模块:持久化日志,同一写者任务) · `测试说明/链路延迟测试说明.md`(D6 日志税 / S8 非阻塞日志,需求出处) · AGENTS.md「平台约束」
|
||||
> **关联文档**:`项目架构总览.md` · `运行与自检记录设计说明.md`(姊妹模块:持久化日志,同一写者任务) · `测试说明/链路延迟测试说明.md`(D6 日志税 / 步骤 8 非阻塞日志,需求出处) · AGENTS.md「平台约束」
|
||||
|
||||
## 1. 背景:实测故障与根因
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
| F1 | 日志行字符级交错 | 崩溃前两行日志逐字符交错:`"[2026-[2026-0909-24 15:2-24 15:27:37:39]…"` | @test 必检标记可能假性丢失、日志不可读 |
|
||||
| F2 | HardFault(脏指针直接进入 UART) | BFAR=0x10010000(恰为 CCM 末尾+1),PC 落在 `HAL_UART_Transmit` 的缓冲读取处 | 崩溃上报路径自身再崩;被破坏的字符串指针被 UART 逐字节读取 |
|
||||
|
||||
前兆:2026-09-22 链路延迟测试实测**开机连续丢行**(多任务并发 `printf` → 非重入 `fputc`/`HAL_UART_Transmit` 丢整行,~2s 自恢复;`链路延迟测试说明.md` §9.2)——同类竞态的温和形态,当时列为 S8 待办(日志非阻塞化)。
|
||||
前兆:2026-09-22 链路延迟测试实测**开机连续丢行**(多任务并发 `printf` → 非重入 `fputc`/`HAL_UART_Transmit` 丢整行,~2s 自恢复;`链路延迟测试说明.md` §9.2)——同类竞态的温和形态,当时列为待办(日志非阻塞化)。
|
||||
|
||||
### 1.2 根因分析(旧路径:`DBG_*` → `printf` → `fputc`)
|
||||
|
||||
@@ -320,12 +320,13 @@ sequenceDiagram
|
||||
没有任何任务真的死等,只是主循环周期被 drain 拉长到 450~500ms,而喂狗抽样是 100ms
|
||||
节流的、IWDG 最坏容限仅 1.7s,间歇被拉长就触发停喂。**看日志会以为"系统很健康"**。
|
||||
|
||||
**已做(缓解)**:单次 drain 250ms 预算(round-3)+ 发送故障后 300ms 冷却(round-6)
|
||||
+ 超时判据换 DWT(round 8b)。
|
||||
**已做(缓解)**:单次 drain 250ms 预算(第 3 轮)+ 发送故障后 300ms 冷却(第 6 轮)
|
||||
+ 超时判据换 DWT(第 8b 轮台架)。
|
||||
|
||||
**未做(根治)**:让 USART1 为 **TX-only**(.ioc 中不再使能 RX / PA10 不作 USART1_RX),
|
||||
从机制上消除 ORE。属 `.ioc` 结构性改动 + CubeMX 重生成,需单开一轮并复跑台架闭环
|
||||
→ 已登记为 `docs/任务规划/登记簿.md` **S-3**。
|
||||
**已裁定不做(2026-10-26 用户决定)**:让 USART1 变成**只发不收**(`.ioc` 里不使能 RX、PA10 不再复用为
|
||||
`USART1_RX`)确实能从机制上消除 ORE,但它是 `.ioc` 结构性改动 + CubeMX 重生成——要清空全部工作树、
|
||||
独占一轮、复跑台架闭环,代价不抵收益。**现行缓解即长期方案**(单次 drain 250 ms 预算 + 发送故障后
|
||||
300 ms 冷却 + DWT 时间源无关的超时判据)。机制根源继续记录在本节,将来若要重评不必重新踩一遍。
|
||||
|
||||
## 13. 开放问题
|
||||
|
||||
@@ -334,31 +335,31 @@ sequenceDiagram
|
||||
| O1 | 未注册期裸发无互斥 | 启动窗口(内核启动 → attach)`dbg_console_write_raw` 无互斥 → 多任务并发会**逐字节交错**(非旧 `HAL_BUSY` 丢整行)。2026-10-10 已固化"周期任务用 `dbg_console_writer_ready()` 门控"纪律;若未来开机日志密度上升,可升级为"内核前静态待发行 + attach 后统一补发"或给裸发加轻量互斥 |
|
||||
| O2 | `HAL_UART_Transmit` 超时未计数 —— **已处置(2026-10-24,v1.5)** | 三本账已分离:`dbg_console_dropped()` = **真没落地**的数(缓冲满丢的一行,或没能确认送达而出环的一个块);`dbg_console_tx_fault()` = 外设**软复位自愈次数**(语义不变);新增 `dbg_console_tx_timeout()` = 写者排空时看到的**块超时次数**(TXE 与 TC 两条硬上界都算)。**口径边界**:裸发路径(内核前 / ISR / 两条告警行自身)的超时**不进**超时账——裸发没有「块」的概念,混进来读数失去意义。**尚未接线**:本读口暂无生产调用者;候选位置 `App/util/task_watchdog.c` 的 `STALL` 行是**被解析的证据行**,加字段要连解析端与台架判据一起改 → 列为后续项 |
|
||||
| O3 | `printf` 逐字节开销 | 遗留 `printf` 路径 = 逐字节临界区 + 逐字节事件置位;遗留调用点全部切 `DBG_*` 宏后开销自然消失(不改变机制) |
|
||||
| O4 | **ORE 僵尸未根治** | §12:现仅有缓解(250ms 预算 / 300ms 冷却 / DWT 超时),机制根源是 USART1 使能了 RX。根治需 `.ioc` 改 TX-only + CubeMX 重生成 → 已登记 `docs/任务规划/登记簿.md` **S-3** |
|
||||
| O4 | **ORE 僵尸未根治** | §12:现仅有缓解(250ms 预算 / 300ms 冷却 / DWT 超时),机制根源是 USART1 使能了 RX。根治 = `.ioc` 改只发不收 + CubeMX 重生成,**2026-10-26 用户裁定不做** → O4 是**长期现状**而非待办(见 §12) |
|
||||
|
||||
## 14. 相关文档
|
||||
|
||||
- `项目架构总览.md` —— 六层分层 / 启动时序 / 6 任务(写者任务与就绪屏障位置)
|
||||
- `运行与自检记录设计说明.md` —— sys_log 持久化日志(姊妹模块:同写者任务、不同通道)
|
||||
- `测试说明/链路延迟测试说明.md` —— D6 日志税 / S8 非阻塞日志(需求出处与 09-22 丢行实证)
|
||||
- `测试说明/链路延迟测试说明.md` —— D6 日志税 / 步骤 8 非阻塞日志(需求出处与 09-22 丢行实证)
|
||||
- `测试说明/自动化测试流程.md` —— `@test` 标记体系(Required / Forbidden 模式,`[ERR]` 语义)
|
||||
- AGENTS.md —— 平台约束(内核前禁内核对象 / C 堆禁令 / 事件位语义 / 内存预算)
|
||||
|
||||
## 附录:N-2 × S8 合并评估(2026-10-25,道F 批 2 / task-18,零代码改动)
|
||||
## 附录:日志静默观察项 × 步骤 8 合并评估(2026-10-25,道F 批 2 / task-18,零代码改动)
|
||||
|
||||
> 评估任务(`docs/任务规划/登记簿.md` N-2 行「残余动作:与 S8 合并评估」):N-2
|
||||
> (49s 全系统日志静默,2026-09-22 L3 台架世代号 181)与 S8(日志非阻塞化,需求
|
||||
> 评估任务(登记簿曾登记的**日志静默观察项**,已销项;残余动作是「与步骤 8 合并评估」):该观察项
|
||||
> (49s 全系统日志静默,2026-09-22 L3 台架世代号 181)与步骤 8(日志非阻塞化,需求
|
||||
> 出处 = `docs/测试说明/链路延迟测试说明.md` §9.2/§10.2)的合并性价比判定。
|
||||
> 评估纪律 = 结论即交付,不顺手重构;本节结论:**无需最小实现**(不新增代码)。
|
||||
|
||||
### A.1 S8:目标已由「单写者形态」在**生产者侧**达成
|
||||
### A.1 步骤 8:目标已由「单写者形态」在**生产者侧**达成
|
||||
|
||||
S8 要治的是阻塞式日志税(L10 实测 `logtax_line` **4402 µs/行**,`fputc` 逐字节
|
||||
步骤 8 要治的是阻塞式日志税(L10 实测 `logtax_line` **4402 µs/行**,`fputc` 逐字节
|
||||
@115200 阻塞调用方整行)与并发丢行(实测 `docs/测试说明/链路延迟测试说明.md` §9.2:
|
||||
必检标记被竞态吞)。2026-09-24 单写者
|
||||
改造正是同一需求落的方案(§1/§2 G1-G5):
|
||||
|
||||
| S8 子项(需求出处 `docs/测试说明/链路延迟测试说明.md` §10.2 第 9 条) | 原案 | 现状(代码实证) |
|
||||
| 步骤 8 子项(需求出处 `docs/测试说明/链路延迟测试说明.md` §10.2 第 9 条) | 原案 | 现状(代码实证) |
|
||||
|---|---|---|
|
||||
| `fputc` → 环形缓冲 | 串口 TX 环形 | ✅ 4KB BSS 环 + 事件位唤醒(§4.1/§4.2);生产者 = 亚微秒~µs 级临界区整行入环(≤192B 拷贝),日志税较 4402µs/行**降 3 个量级** |
|
||||
| TX 中断/DMA | 非阻塞发送 | ❌ 有意不做(轮询单写者,D4);复议时机见 A.2 |
|
||||
@@ -366,25 +367,24 @@ S8 要治的是阻塞式日志税(L10 实测 `logtax_line` **4402 µs/行**,
|
||||
| HardFault 冲刷 | 待处理 | ✅ 有界裸发 ≤256B(G4/§4.4,DWT/计数硬上界,不依赖 tick、零内核对象) |
|
||||
|
||||
热路径日志税另已由 D6 单独削掉(删 per-recv 日志,`queue_rt_recv` 5997→1223µs)。
|
||||
**结论:S8 按“生产者不阻塞业务”的意图已闭环**;剩余的“阻塞”只在写者任务
|
||||
**结论:步骤 8 按“生产者不阻塞业务”的意图已闭环**;剩余的“阻塞”只在写者任务
|
||||
(defaultTask)自身——drain 预算 250ms + 故障冷却 300ms + DWT 硬上界(§11/§12),
|
||||
**不在业务任务关键链上**,且预算值按“让位 800ms 停喂容忍”定档,属设计内行为。
|
||||
|
||||
### A.2 TX 中断/DMA(原案后半):维持否决,排序绑定 S-3
|
||||
### A.2 TX 中断/DMA(原案后半):维持否决
|
||||
|
||||
D4 否决理由对现状仍逐条成立(115200 发送率低、日志行稀疏;IT/DMA 引入新内核
|
||||
对象、缓冲所有权/双缓冲复杂度、DMA 可达性清单)。三点补充判断:
|
||||
|
||||
1. 把 drain 拖长的真凶是 **ORE 僵尸通道**(登记簿 S-3:PA10 悬空 + RX 使能,
|
||||
软复位后毫秒级重锁 → 每轮块超时 100ms 级)——`.ioc` 改 TX-only(批 2.5
|
||||
独占轮,CubeMX 重生成约束见 AGENTS)落地后该形态整体消失;
|
||||
1. 把 drain 拖长的真凶是 **ORE 僵尸通道**(PA10 悬空 + RX 使能,软复位后毫秒级重锁 → 每轮块超时
|
||||
100ms 级);根治办法(`.ioc` 改只发不收)已于 2026-10-26 裁定不做 → **该形态长期存在**,靠缓解措施兜住;
|
||||
2. 根治前后数据已可机读:`dbg_console_tx_timeout()`(§13-O2 三本账,v1.5 起)
|
||||
就是为“IT/DMA 还剩多少收益”留的量尺;
|
||||
3. S-3 之前动 TX 路径 = 给即将被移除的场景写两遍代码。
|
||||
3. 根治既已裁定不做,TX 路径的形态就是终态:动它不再需要"等根治",但必须拿 `tx_timeout` 的实测收益说话。
|
||||
|
||||
**结论:不采。复议触发条件 = S-3 落地后实测 `tx_timeout` 增量仍 > 0。**
|
||||
**结论:不采。**原复议触发条件绑定根治项,已随 2026-10-26 裁定不做而失效;将来若再议 TX 中断/DMA,直接以 `dbg_console_tx_timeout()` 的实测增量为依据。
|
||||
|
||||
### A.3 N-2:观察窗收敛到 V5 复跑;“真停滞 vs 无源”判别成立
|
||||
### A.3 日志静默观察项:观察窗收敛到 V5 复跑;“真停滞 vs 无源”判别成立
|
||||
|
||||
- 判据②(静默 → 可观测)= **已具备**:控制台三本账 `dbg_console_dropped /
|
||||
dbg_console_tx_fault / dbg_console_tx_timeout` + syslog 的
|
||||
@@ -392,7 +392,7 @@ D4 否决理由对现状仍逐条成立(115200 发送率低、日志行稀疏
|
||||
(`App/log/sys_log_mcu.c`);任何“静默丢行”现形为 `[ERR]` → `@test` FAIL。
|
||||
- 判据①(复现 49s 并定位):V5 30min 未复现;实测(`docs/测试说明/实机测试实施指南.md` §7.2)
|
||||
运行期 >10s 静默 24 处**全部落在 e02_probe 窗口、长度 ≈28s**——其
|
||||
同源阻塞机制(`drop_conn` 同步占用 netTask 400-600ms)已随 N-17 修复
|
||||
同源阻塞机制(`drop_conn` 同步占用 netTask 400-600ms)已随登记式拆链改造修复
|
||||
(登记式拆链,`docs/网络/网络自愈架构设计.md` §4.6)。本评估补充一个此前
|
||||
缺位的替代解释:**探针窗内的静默很可能本来就是“无日志源”的正常形态**——
|
||||
探针一轮(挂起 30s + 短暂复连)业务日志天然稀疏,defaultTask 无周期串口输出
|
||||
@@ -402,19 +402,19 @@ D4 否决理由对现状仍逐条成立(115200 发送率低、日志行稀疏
|
||||
丢弃账——账目零增量且静默后无 `[ERR] CONSOLE dropped` = **无源**(正常,
|
||||
不开卡);账目有增量或出现 dropped 行 = **真停滞**(开卡,按 §12 ORE 与
|
||||
冷却路径核对)。
|
||||
- **处置建议**:N-2 保留为低风险观察,至 N-17 修复版(merge 969fc5c)的 V5
|
||||
- **处置建议**:该观察项保留为低风险观察,至拆链修复版(merge 969fc5c)的 V5
|
||||
复跑(判据 = 运行期 `[WD] task stall` 与非开机 `MISS start` 双零,台架由
|
||||
lead 排窗)达成后销项;本附录即销项结论落点。登记簿 N-2/N-17 行与波次行
|
||||
lead 排窗)达成后销项;本附录即销项结论落点。登记簿相应两行与波次行
|
||||
的清理归单写者(lead)。
|
||||
|
||||
### A.4 评估后的遗留面(全部既有,无新增)
|
||||
|
||||
| 项 | 归属 | 处置 |
|
||||
|---|---|---|
|
||||
| ORE 僵尸根治(TX-only) | 登记簿 S-3 / §12 / §13-O4 | 批 2.5 独占轮;落地后触发 A.2 复议 |
|
||||
| ORE 僵尸根治(改只发不收) | §12 / §13-O4 | **2026-10-26 用户裁定不做**;量尺 `dbg_console_tx_timeout()` 保留,将来重评直接用 |
|
||||
| `tx_timeout` 读口接线(STALL 证据行加字段) | §13-O2 | 涉 `App/util/task_watchdog.c` 与被解析证据行的台架判据,非本卡写域;维持 O2“后续项” |
|
||||
| 未注册期裸发互斥 / `printf` 遗留开销 | §13-O1/O3 | 现状 = 纪律已落地,开机日志密度上升再议 |
|
||||
| N-2 观察项 | 登记簿 §1 | 见 A.3:V5 复跑双零后销项(归 lead) |
|
||||
| 日志静默观察项 | 登记簿曾登记(已销项) | 见 A.3:V5 复跑双零后销项(归 lead) |
|
||||
|
||||
---
|
||||
|
||||
@@ -424,8 +424,8 @@ D4 否决理由对现状仍逐条成立(115200 发送率低、日志行稀疏
|
||||
|------|------|------|
|
||||
| v1.0 | 2026-09-25 | 初版:完整设计说明(背景根因 / 单写者模型 / 详细设计 / API / 参数 / 失效模式 / 内存预算 / 设计决策 / 验证记录);实现位于 `App/log/console_log.{h,c}` |
|
||||
| v1.1 | 2026-09-25 | 文件拆分同步:写者任务体迁至 `App/task/default_task.c`(`Src/freertos.c` 只留 CubeMX 接线与崩溃钩子);§3.2 文件清单 / §4.3 / §6 / §11 位置引用更新 |
|
||||
| v1.2 | 2026-10-02 | 新增 §12 ORE 僵尸通道(台架 gen-288 实证:节奏性喂狗饥饿,非死等;缓解已做、TX-only 根治待办)+ §11 时间线两条 10-02 记录;§13 新增 O4;原 §12/§13 顺延为 §13/§14 |
|
||||
| v1.2 | 2026-10-02 | 新增 §12 ORE 僵尸通道(台架日志代次 288 实证:节奏性喂狗饥饿,非死等;缓解已做、TX-only 根治待办)+ §11 时间线两条 10-02 记录;§13 新增 O4;原 §12/§13 顺延为 §13/§14 |
|
||||
| v1.3 | 2026-10-10 | 栈链整改(**未抬栈**)三处:① 裸发改为纯寄存器轮询——DWT 不可用时走 `con_tx_counted`(计数上界),**不再回退 `HAL_UART_Transmit`**(tick 依赖不可信 + 其调用链污染所有任务最坏栈链);② 切断 `drain → syslog_post → write_line` **调用图成环**,改为置标志 + 写者任务在 drain 之外补记(新 API `dbg_console_tx_fault_log_take`);③ 行缓冲按模块可收紧(`dbg_log.h` 新增 `DBG_LINE_BUF_MAX`,深链模块 128)+ 时间戳缓冲并入行缓冲(32 → 24)。§4.4 / §5 / §6 / §7 / §8 同步;实测 defaultTask 静态最坏链 5312 → 2776 B |
|
||||
| v1.4 | 2026-10-10 | 新增 `dbg_console_writer_ready()`(写者就绪查询)并固化"未注册期只有 defaultTask 记日志、周期任务用就绪门控"纪律;更正 §3.4 / §7 / §9-D5 / §13-O1 的"只丢不交错"旧结论(裸发已改寄存器级轮询、无 `gState` 互斥) |
|
||||
| v1.6 | 2026-10-25 | 新增文末**附录:N-2 × S8 合并评估**(道F 批 2 / task-18,零代码):A.1 S8 已由单写者形态在生产者侧达成(4402µs/行 → µs 级入环);A.2 TX 中断/DMA 维持 D4 否决、复议绑定 S-3 落地后 `tx_timeout` 实测;A.3 N-2 判据②已具备、①给出「无源 vs 真停滞」判别口径与 V5 复跑销项条件;A.4 遗留面全部既有、无新增。§11 时间线同步 |
|
||||
| v1.6 | 2026-10-25 | 新增文末**附录:日志静默观察项 × 步骤 8 合并评估**(道F 批 2 / task-18,零代码):A.1 步骤 8 已由单写者形态在生产者侧达成(4402µs/行 → µs 级入环);A.2 TX 中断/DMA 维持 D4 否决、复议绑定 S-3 落地后 `tx_timeout` 实测;A.3 该观察项判据②已具备、①给出「无源 vs 真停滞」判别口径与 V5 复跑销项条件;A.4 遗留面全部既有、无新增。§11 时间线同步 |
|
||||
| v1.5 | 2026-10-24 | **主机单测批次照出的四条现状全部处置**(生产码在 `App/log/console_log.c`,用例在 `test/host/console_log/`):① 冷却判据改用独立 `s_con_cooling` 标志,不再拿 `HAL_GetTick()` 的 0 值当哨兵——旧写法在 tick==0 那一拍(开机头 1 ms,或 49.7 天回绕到 0)冷却等于没记;② `con_append` 的空位判据 / 推进 head / 整行拷贝收进同一临界区——旧实现是临界区外 check-then-act,多生产者可在环 >95% 满时双双过判据把 head 推过容量 → 静默覆盖且**既不打 [ERR] 也不计 dropped**;③ `Instance == NULL`(未初始化)与僵尸通道**分诊**,未初始化绝不 reinit(旧路径会在 HAL 未就绪时经 MspInit 重配 RCC/GPIO);④ 三本账,见本文 §13-O2。**dropped 的单位口径变了**:一次 = 一行(缓冲满)或一个块(没能确认送达 / 通道不可用),故 `[ERR] CONSOLE dropped N lines` 的 N **不恒等于行数**(为兼容 `@test` 标记匹配,文案未改词)。本文 §3.1 与 §4.1 的「单生产者 vs 全上下文生产者」矛盾一并消除 |
|
||||
|
||||
+14
-16
@@ -6,13 +6,12 @@
|
||||
> **日期**:2026-09-29 创建;**2026-10-10 按当前代码重写正文**(旧正文含大量立项前的
|
||||
> 描述,已清理;实施史与逐次决策见 §10 与文末变更记录,未删)。
|
||||
> **相关文档**:
|
||||
> [`../任务规划/README.md`](../任务规划/README.md)(登记簿未办项 N-17 / S-3,见 `../任务规划/登记簿.md`)、
|
||||
> [`运行与自检记录设计说明.md`](运行与自检记录设计说明.md)(复位记录与 `selftest.log`)、
|
||||
> [`../测试说明/看门狗单元测试说明.md`](../测试说明/看门狗单元测试说明.md)(L0.5 判定状态机单测)、
|
||||
> [`../测试说明/实机测试实施指南.md`](../测试说明/实机测试实施指南.md)(故障注入台架流程)、
|
||||
> [`../架构设计/项目启动顺序管理.md`](../架构设计/项目启动顺序管理.md)(启动时序与就绪屏障)、
|
||||
> [`../测试说明/ST-LINK_CLI_复位使用说明.md`](../测试说明/ST-LINK_CLI_复位使用说明.md)(复位语义)、
|
||||
> 《项目审查与优化建议报告》(N-03 的立项出处;该条已修复并按「修复即销项」从报告删除,**完整记录即本文**;报告本身 2026-10-25 已删除)
|
||||
> 《项目审查与优化建议报告》(本模块缺口的立项出处;该条已修复并按「修复即销项」从报告删除,**完整记录即本文**;报告本身 2026-10-25 已删除)
|
||||
|
||||
---
|
||||
|
||||
@@ -55,7 +54,7 @@
|
||||
|
||||
### 1.3 立项前状态(历史,2026-09-29)
|
||||
|
||||
当时全库无 IWDG/WWDG 初始化、HAL IWDG 驱动源码不在仓库、`.ioc` 无看门狗条目、无复位原因读取——缺陷登记为 N-03(原登记于《项目审查与优化建议报告》,已修复并按销项删除正文)。**该节只作立项背景**:现状是 IWDG 已启用(`.ioc` + `HAL_IWDG_MODULE_ENABLED` + 驱动已挂载),复位原因每次开机都在上报。
|
||||
当时全库无 IWDG/WWDG 初始化、HAL IWDG 驱动源码不在仓库、`.ioc` 无看门狗条目、无复位原因读取——缺陷原登记于《项目审查与优化建议报告》(已修复并按销项删除正文)。**该节只作立项背景**:现状是 IWDG 已启用(`.ioc` + `HAL_IWDG_MODULE_ENABLED` + 驱动已挂载),复位原因每次开机都在上报。
|
||||
|
||||
---
|
||||
|
||||
@@ -387,9 +386,9 @@ snapshot == required → miss_streak=0、证据门闩复位、喂狗
|
||||
|
||||
| 层 | 载体 | 开机读出并打印 |
|
||||
|---|---|---|
|
||||
| round 7 | RAM(近 8 次抽样位图环、最大喂狗间隔、console tx_fault 计数) | 停喂时 `STALL snap=… req=… h=… mg=… cf=… seg=…`(裸 UART + `/log/wdev.log` 各一份) |
|
||||
| round 8 | `.noinit` 槽 `s_wd_seg_trail[4]`(magic/段号/时刻/循环序号) | `PREVRUN seg=N seq=N t=ms`——直接指向 defaultTask 主循环最后进段 |
|
||||
| round 8b | `.noinit` 槽 `s_wd_tick_cur/prev[4]`(uwTick + TIM7 中断计数) | `TICKRUN uw=… n=… duw=…`——判定 HAL 时基(TIM7)是否与停摆同刻冻结 |
|
||||
| 第 7 轮 | RAM(近 8 次抽样位图环、最大喂狗间隔、console tx_fault 计数) | 停喂时 `STALL snap=… req=… h=… mg=… cf=… seg=…`(裸 UART + `/log/wdev.log` 各一份) |
|
||||
| 第 8 轮 | `.noinit` 槽 `s_wd_seg_trail[4]`(magic/段号/时刻/循环序号) | `PREVRUN seg=N seq=N t=ms`——直接指向 defaultTask 主循环最后进段 |
|
||||
| 第 8b 轮 | `.noinit` 槽 `s_wd_tick_cur/prev[4]`(uwTick + TIM7 中断计数) | `TICKRUN uw=… n=… duw=…`——判定 HAL 时基(TIM7)是否与停摆同刻冻结 |
|
||||
|
||||
要点:
|
||||
- `.noinit` 必须 `section(".noinit")` **与** `zero_init` 同时给,并配 scatter 的 `UNINIT` 执行区;只给 section 时 armcc 会当"带初值 RW"→ 启动 scatterload 抹掉保留内容。
|
||||
@@ -435,13 +434,13 @@ snapshot == required → miss_streak=0、证据门闩复位、喂狗
|
||||
| V2 | **任务饿死**(netTask 插 `while(1)`) | ✅ **2026-10-03 闭环** | 800 ms 声明 `task stall: mask=0x00000001 req=0x00000037` → ≤2.5 s IWDG 复位(`reset cause: IWDG`,`RCC_CSR=0x24000000`)。首轮曾不复位,根因是证据落盘自身喂狗 → 加门闩(§5.3) |
|
||||
| V3 | 断言失败 | 🟡 未单独注入 | 宏与钩子已在用(`configASSERT` 全内核可达);行为经编译与代码路径核对,未做定向注入用例 |
|
||||
| V4 | **关中断死循环** | ✅ **2026-10-03 闭环** | `__disable_irq()` + `while(1)` → 每 ~4.9 s 稳定复位(20+ 周期,`IWDG`)→ 证实 IWDG 独立于中断 |
|
||||
| V5 | **长期不误杀**(真实负载 ≥30 min) | ✅ **2026-10-03 闭环** | FTP 512 KB 上/下传 + `e02_probe` 探针 30 min → **120/120 次传输全 PASS、零 IWDG 复位**。遗留观察 44 次 stall(探针场景专属)→ 登记 **N-17** |
|
||||
| V5 | **长期不误杀**(真实负载 ≥30 min) | ✅ **2026-10-03 闭环** | FTP 512 KB 上/下传 + `e02_probe` 探针 30 min → **120/120 次传输全 PASS、零 IWDG 复位**。遗留观察 44 次 stall(探针场景专属)→ 登记「探针窗口心跳缺口」 |
|
||||
| V6 | 测试套件共存 | 🟡 部分 | 2026-10-02 曾出现测试构建 IWDG 复位循环,已按 §3.5 掩码规则修复;未跑完整套件用例矩阵 |
|
||||
| V7 | 上电复位辨识 | 🟡 未单独注入 | `reset cause:` 每次开机都在打(POR 串已实现),未做专门断电对照 |
|
||||
| V8 | 引脚复位辨识 | ⏳ 未做 | 未做定向注入(`external pin (NRST)` 分支已实现) |
|
||||
| U1 | 判定状态机主机侧单测 | ✅ 39/39 | `test/host/watchdog/run_unit_test.py`(L0.5,pre-commit `watchdog-unit-test`) |
|
||||
| U2 | 门禁接入 | ✅ | 改 `App/util/task_watchdog*.{c,h}` 或 `test/host/watchdog/**` 触发 |
|
||||
| S1 | 模拟器 `--watchdogtest` | ⏳ **已降级不做** | 位图与判定逻辑已由 U1 覆盖;模拟器不编译本模块 |
|
||||
| 主机单测 | 判定状态机主机侧单测 | ✅ 39/39 | `test/host/watchdog/run_unit_test.py`(L0.5,pre-commit `watchdog-unit-test`) |
|
||||
| 门禁触发 | 门禁接入 | ✅ | 改 `App/util/task_watchdog*.{c,h}` 或 `test/host/watchdog/**` 触发 |
|
||||
| 模拟器 | `--watchdogtest` | ⏳ **已降级不做** | 位图与判定逻辑已由主机单测覆盖;模拟器不编译本模块 |
|
||||
|
||||
用例细节见 [`../测试说明/看门狗单元测试说明.md`](../测试说明/看门狗单元测试说明.md);故障注入流程见 [`../测试说明/实机测试实施指南.md`](../测试说明/实机测试实施指南.md) §4。
|
||||
|
||||
@@ -471,18 +470,17 @@ snapshot == required → miss_streak=0、证据门闩复位、喂狗
|
||||
|---|---|---|
|
||||
| R1 | **启动段无保护**(复位 → `task_wd_start()` 约数秒) | 接受;表现为"无输出 + LED 不闪",人工辨识。要覆盖需"短超时 + 手动多喂",复杂度收益比不划算 |
|
||||
| R2 | **LSI 精度差** | 已按 47 kHz 最坏值校验,停喂到复位仍留 ~900 ms |
|
||||
| R3 | **喂狗节奏饥饿** | 控制台 drain 曾把主循环拉长导致误复位(2026-10-02 gen-288)。现缓解 = drain 单次 250 ms 预算 + 发送故障 300 ms 冷却;**结构根治(USART1 TX-only)未做** → 登记 **S-3** |
|
||||
| R3 | **喂狗节奏饥饿** | 控制台 drain 曾把主循环拉长导致误复位(2026-10-02 台架日志代次 288)。现缓解 = drain 单次 250 ms 预算 + 发送故障 300 ms 冷却;**结构根治(USART1 改只发不收)2026-10-26 已裁定不做 → 现行缓解即长期方案**(机制详述 `控制台单写者日志设计说明.md` §12) |
|
||||
| R4 | **NAND 真实卡死时 FTL 直接喂狗** | 设备存活但存储功能冻结(与 ORE 自愈同类边界)。若要求"NAND 死也必须复位",需给 `nand_ftl_wd_feed()` 加次数/时限上限 |
|
||||
| R5 | **栈溢出与断言在复位原因上不可区分**(都是 `SFTRSTF`) | 可接受;串口分别打 `[ERR] STACK OVERFLOW` / `[ERR] ASSERT FAILED`,`selftest.log` 侧另有记录 |
|
||||
| R6 | **`RCC_CSR` 读后即清** | 已在 `main.c` 统一处理;漏清会让下次软复位读回上次标志 |
|
||||
| R7 | **UI 推流的网络往返卡死不占心跳位**(产品掩码仍 `0x77`) | 刻意:往返卡死的根因在 netTask,netTask 已在掩码内、由它暴露;为"远端显示卡了"新增一位只会把观感问题升级成整机复位。UI 心跳已由 P1-4a 自产、不受推流影响;推流耗时看 `[PROF]` 的 `uis`/`uisn`。成因与判读见本文 **§11.3 第 2 条**;门控方案与残留暴露见 `../UI设计/RemoDispBus协议与接收设计说明.md` §3 |
|
||||
| R7 | **UI 推流的网络往返卡死不占心跳位**(产品掩码仍 `0x77`) | 刻意:往返卡死的根因在 netTask,netTask 已在掩码内、由它暴露;为"远端显示卡了"新增一位只会把观感问题升级成整机复位。UI 心跳已由自身喂位自产、不受推流影响;推流耗时看 `[PROF]` 的 `uis`/`uisn`。成因与判读见本文 **§11.3 第 2 条**;门控方案与残留暴露见 `../UI设计/RemoDispBus协议与接收设计说明.md` §3 |
|
||||
|
||||
### 9.2 未办项(登记簿同步)
|
||||
|
||||
| 编号 | 内容 | 与本案关系 |
|
||||
| 条目 | 内容 | 与本案关系 |
|
||||
|---|---|---|
|
||||
| **N-17** | `time_sync` 30 s 挂起客户端掉线 + 监听重建期间 NET/FTP/UI 心跳缺口 800 ms~1 s(声明 stall 但未复位),**余量仅 ~0.7 s** | 待定位监听重建为何阻塞其它任务;必要时缩短重试 |
|
||||
| **S-3** | USART1 TX-only 结构根治(灭 ORE 僵尸机制) | 是 R3 节奏饥饿的机制根源 |
|
||||
| 探针窗口心跳缺口 | `time_sync` 30 s 挂起客户端掉线 + 监听重建期间 NET/FTP/UI 心跳缺口 800 ms~1 s(声明 stall 但未复位),**余量仅 ~0.7 s** | 待定位监听重建为何阻塞其它任务;必要时缩短重试 |
|
||||
| O1 | 是否需要复位计数与"连续 N 次看门狗复位后进入安全模式" | 当前不做;若现场出现复位风暴再评估 |
|
||||
| O2 | 细粒度复位原因是否上 `run.log`/UI | 倾向不上(避免中文字符集重生成),只保留串口 + `selftest.log` |
|
||||
|
||||
@@ -552,7 +550,7 @@ python scripts/check_cubemx_survival.py --write # 确认改动无误后重建
|
||||
|
||||
---
|
||||
|
||||
## 11. 任务级饥饿的诊断方法与实测基线(Task #32 沉淀,2026-10-10)
|
||||
## 11. 任务级饥饿的诊断方法与实测基线(2026-10-10 结案沉淀)
|
||||
|
||||
> **来源**:`[ERR][WD] task stall: mask=0x00000067 req=0x00000077`(缺 bit4 = `TASK_WD_UI`)
|
||||
> 的完整归因与处置。故障本身已结案——**累计 38 次上板启动 0 复现**(原 L2 基线 3/10),
|
||||
|
||||
@@ -109,9 +109,9 @@ mac=00:00:00:00:00:00
|
||||
|
||||
INI 格式两端一致,文件可互读;mtime 变更令牌:MCU = FAT 打包时间(`fdate<<16\|ftime`,分钟级粒度),模拟器 = 宿主文件 mtime(秒级)。
|
||||
|
||||
### 3.4 `[ftp]` 段:FTP 鉴权(2026-10-11 新增,N-19)
|
||||
### 3.4 `[ftp]` 段:FTP 鉴权(2026-10-11 新增)
|
||||
|
||||
FTP 服务(lftpd,:21)自 N-19 起启用口令鉴权。配置与 `[network]` **同文件、同引擎**(`net_cfg_load()` 内统一注册,键表与工厂默认见 `Drivers/BSP/NETCFG/ftp_cfg.c/h`;鉴权状态机在 `Drivers/BSP/NET/lftpd/lftpd_auth.c/h`,纯函数、主机侧可测):
|
||||
FTP 服务(lftpd,:21)自 2026-10-11 起启用口令鉴权。配置与 `[network]` **同文件、同引擎**(`net_cfg_load()` 内统一注册,键表与工厂默认见 `Drivers/BSP/NETCFG/ftp_cfg.c/h`;鉴权状态机在 `Drivers/BSP/NET/lftpd/lftpd_auth.c/h`,纯函数、主机侧可测):
|
||||
|
||||
```ini
|
||||
[ftp]
|
||||
|
||||
+18
-18
@@ -2,7 +2,7 @@
|
||||
|
||||
> **版本**:v1.1(已实施)
|
||||
> **日期**:2026-09-14
|
||||
> **状态**:S1–S9 全部完成——双端构建 0/0、`--logtest` PASS、ui-verify 五门禁全绿;真机 @test 待上电回归(§8.2)
|
||||
> **状态**:步骤 1–9 全部完成——双端构建 0/0、`--logtest` PASS、ui-verify 五门禁全绿;真机 @test 待上电回归(§8.2)
|
||||
> **关联文档**:`项目架构总览.md` · `STM32F4-Base存储架构说明.md` · `系统墙钟时间维护说明.md` · `UI设计/内容页架构.md`(如存在)· `docs/UI设计/mockups/`(待机显示页面.jpg / 运行记录页.jpg / 自检记录页.jpg / 密码页面实际机器的示例图片.jpg)
|
||||
|
||||
## 1. 背景与需求
|
||||
@@ -140,20 +140,20 @@ min_ever=8464` 说明余量充足。回归由 **TC-SYSLOG-108**(投出去之
|
||||
defaultTask(唯一写者,挂载成功后):
|
||||
1) f_mkdir("/log")(幂等)
|
||||
2) 排空启动前数组 + 队列 → 按文件合并落盘(一批最多 8 条:一次
|
||||
f_open FA_OPEN_APPEND → f_write(n×64B) → f_close,见下方 N-24 说明)
|
||||
f_open FA_OPEN_APPEND → f_write(n×64B) → f_close,见下方「日志读写放大收口」说明)
|
||||
3) 写"上电/重启"分类记录(§5.3,基于 run.log 末条 epoch)
|
||||
4) 主循环:osMessageQueueGet(阻塞, 10s 超时) → 落盘;超时空转继续 LED 闪烁
|
||||
```
|
||||
|
||||
- **N-24(2026-10-15,报告 N-16 写侧):一次排空合并成"每文件一次 open/write/close"**。旧实现每条记录一轮,而 `f_close` 要回写目录项、`f_write` 要对目标扇区做读-改-写 → **每条日志 2~4 次 NAND 页读写**。现在同一文件的一批(≤8 条 = 512 B 静态缓冲 `s_batch`)合并成一次追加写:
|
||||
- **掉电语义不变**:批次仍在**同一次 `syslog_drain()` 调用内**写完并 `f_close`;`f_close` 内部 `sync_fs` → `disk_ioctl(CTRL_SYNC)` 会 `ftl_flush_cache()` 把 FTL 的单页写回缓存刷进 NAND(`Drivers/BSP/GD5F2GQ5UE/nand_ftl.c` 的 `CTRL_SYNC` 分支)。落盘时机与旧实现每条 close 等价,**批次不跨调用驻留 RAM**:"写完即关"的路径关文件即落盘,残余只到"单次写事务进行中掉电/复位"为止(`../任务规划/登记簿.md` N-22:无空闲/掉电前周期 flush,2026-10-22 用户裁定暂不做)。
|
||||
- **日志读写放大收口(2026-10-15,写侧):一次排空合并成"每文件一次 open/write/close"**。旧实现每条记录一轮,而 `f_close` 要回写目录项、`f_write` 要对目标扇区做读-改-写 → **每条日志 2~4 次 NAND 页读写**。现在同一文件的一批(≤8 条 = 512 B 静态缓冲 `s_batch`)合并成一次追加写:
|
||||
- **掉电语义不变**:批次仍在**同一次 `syslog_drain()` 调用内**写完并 `f_close`;`f_close` 内部 `sync_fs` → `disk_ioctl(CTRL_SYNC)` 会 `ftl_flush_cache()` 把 FTL 的单页写回缓存刷进 NAND(`Drivers/BSP/GD5F2GQ5UE/nand_ftl.c` 的 `CTRL_SYNC` 分支)。落盘时机与旧实现每条 close 等价,**批次不跨调用驻留 RAM**:"写完即关"的路径关文件即落盘,残余只到"单次写事务进行中掉电/复位"为止(`../任务规划/登记簿.md` 条目「写回缓存空闲 flush」:无空闲/掉电前周期 flush,2026-10-22 用户裁定暂不做)。
|
||||
- **条目不丢**:启动前数组按下标"看而不删",整批成功才删;队列条目在落盘失败(-2 卷忙 / -1 写失败 / -3 容量不足)时**回投队列**。
|
||||
⚠ **2026-10-24 更正本条**:旧实现里 -2 只在**按条慢路径**被正确回投,**批量路径根本没有 -2 分支**(`done` 保持 `n` → 回投循环空转)→ 卷忙时一批(≤8 条)既不落盘也不回投、静默丢失,而本节长期写着"条目不丢"替它背书。现已补 `rc == -2` 分支整批回投(不计故障、不打日志、保序),由 `test/host/sys_log_mcu/` 的 TC-SYSLOG-035 组逐条钉住。**真机必验**:FTP 传输期间持续投日志,传输结束后条数 == 投递条数、顺序不乱。
|
||||
- **容量轮转仍只在按条慢路径做**:批量路径发现剩余容量装不下一批时返回 -3,退回逐条 `s_append()`("满了 unlink 重建"只保留一处实现,避免一批跨多轮重建)。
|
||||
- 自愈重试(L1 丢弃重建 + 重试一次)与错误去重(L2 只报第一次)判据与单条路径一致。
|
||||
- **自愈触发集分类(2026-10-24,代码侧唯一入口 `s_is_selfheal_code()`)**:只有"删了这个文件真能修好"的介质/结构类码才触发 unlink 重建——`FR_DISK_ERR` / `FR_INT_ERR` / `FR_NO_FILESYSTEM` / `FR_DENIED`;**名字/参数类严禁归入**(`FR_INVALID_NAME` / `FR_NO_PATH` / `FR_NO_FILE` / `FR_INVALID_OBJECT`,另显式排除 `FR_NOT_READY` / `FR_NOT_ENABLED` / `FR_TIMEOUT`)。同名同因下 unlink 必然同样失败,旧集合的真实后果是**每轮排空删一次自己的历史日志且永远修不好**,违反 `docs/架构设计/STM32F4-Base存储架构说明.md` §10.1 第 10 条。`f_write` 之后的"失败/短写 → unlink 重试一次"**不接**本判定(能走到那里说明已打开成功;而簇分配失败是 `FR_OK` + 短写、根本没有码可判,必须无条件重试)。钉住:TC-SYSLOG-101 / 101b / 102 / 103;`App/log/soe_store.c` 侧同源但取**更保守子集**(TC-SOESTORE-022 / 022b)。
|
||||
- **留痕节流分两层、各自独立抑制位**:drain 侧"整批回投"只在正常→故障那一次报(`write fail, requeue %lu entries`,落盘成功一轮复位;旧文案写作 "drop N entries" 与实际行为相反——整批其实一条没丢);post 侧 `queue full, drop` / `preboot full, drop` 各一位(**丢弃语义不变,满则丢照旧**,只压留痕次数)。节流之后**没有丢弃计数**——要计数属新增对外可见信息,另列后续项。
|
||||
- 读路径与写路径并发安全:UI 页在 uiTask 经 `syslog_get_record()` 读记录(内部走 `s_read_raw()`,见 §4.5);读写两侧都取卷锁 try 语义(P2-10),FatFS 系统锁保护单次调用。
|
||||
- 读路径与写路径并发安全:UI 页在 uiTask 经 `syslog_get_record()` 读记录(内部走 `s_read_raw()`,见 §4.5);读写两侧都取卷锁 try 语义,FatFS 系统锁保护单次调用。
|
||||
- **存储未就绪/挂载失败**:待发条目滞留 RAM(下次上电丢失),串口打印告警——存储故障时本就无法持久化,属预期行为。
|
||||
|
||||
### 4.5 读路径(UI / 模拟器)
|
||||
@@ -164,7 +164,7 @@ int syslog_get_record(syslog_id_t id, uint32_t idx, char *ts, size_t ts_len
|
||||
char *desc, size_t desc_len); /* 越界 / 读失败 / 缓冲容量不足 均返回 -1 */
|
||||
```
|
||||
|
||||
- MCU:**8 条滑动读窗口**(N-24,报告 N-16 读侧)——`s_read_raw()` 先查窗口(同 id + 代数未变 + 落在区间内 → **零 I/O** 直接从 512 B 静态窗口返回);未命中才 `f_open(FA_READ) → f_lseek(窗口首条×64) → f_read(≤8×64B) → f_close` **一次取回连续 8 条**,再从中切出请求的那条。旧实现每读一条都要 open/lseek/read/close 一轮,UI 翻 20 条记录 = 20 次目录项/FAT 往返。
|
||||
- MCU:**8 条滑动读窗口**(日志读写放大收口,读侧)——`s_read_raw()` 先查窗口(同 id + 代数未变 + 落在区间内 → **零 I/O** 直接从 512 B 静态窗口返回);未命中才 `f_open(FA_READ) → f_lseek(窗口首条×64) → f_read(≤8×64B) → f_close` **一次取回连续 8 条**,再从中切出请求的那条。旧实现每读一条都要 open/lseek/read/close 一轮,UI 翻 20 条记录 = 20 次目录项/FAT 往返。
|
||||
- 失效机制:写者每次落盘后把 `s_rd_gen[id]` 自增,读者比对填充时记录的代数,不匹配就重填。对齐 32 位在 ARM 上原子,跨任务(uiTask 填、defaultTask 增)无需临界区;最坏情况多读一轮,不会读错。
|
||||
- **API 与调用方一律不变**(`syslog_get_record()` 签名照旧,`ui_page_runlog` / `ui_page_selftest` 零改动)。
|
||||
- **容量契约(2026-10-24 写死在 `App/log/sys_log.h`)**:`ts_len > SYSLOG_TS_LEN`、`desc_len > SYSLOG_DESC_MAX`,**不足一律 -1,既不静默截断也不写调用方一个字节**(描述在写入侧已截到 `SYSLOG_DESC_MAX`,按最小容量给就一定装得下,读侧不需要第二道截断)。旧实现里那句 `if (dl >= desc_len) dl = desc_len - 1` 由上面的守卫保证**永不可达**,已删除;它的存在还会误导调用方"给 28 字节缓冲能读到 27 字符"——实际是整条读不到。UI 侧现用 32 B 列缓冲,走允许路径、行为不变。钉住:TC-SYSLOG-057、057b(0x7A 哨兵逐字节回比)、098。
|
||||
@@ -285,21 +285,21 @@ Forbidden:`FAIL`/`ERROR`/`HardFault`。
|
||||
| O2 | 故障"已复归"/持续监测(mockup 语义) | v2:周期自检 + 活动故障状态机 + 恢复记录 |
|
||||
| O3 | "清除记录"菜单项(node 27 #P,现为空框) | v2:UI 动作 = 删除/重建 log 文件(与满时策略同路径) |
|
||||
| O4 | 待机页电流值接实时数据 | 待交流量标定管线(AC 页占位数据替换)落地后接入 `tpafe5160_snapshot()`(原子快照;旧 `tpafe5160_get_buf()` 已于 2026-10-10 删除,见 `AGENTS.md`) |
|
||||
| R-1 | FAT32 小追加簇开销 | §3 调研结论:写频率极低可接受;容量上限约束增长 |
|
||||
| R-2 | UI 读与落盘并发 | 只读既有内容 + EOF 追加 + FatFS 系统锁,无互斥需求(§4.4) |
|
||||
| — | FAT32 小追加簇开销 | §3 调研结论:写频率极低可接受;容量上限约束增长 |
|
||||
| — | UI 读与落盘并发 | 只读既有内容 + EOF 追加 + FatFS 系统锁,无互斥需求(§4.4) |
|
||||
|
||||
## 10. 实施步骤(按序执行,每步双端构建 0/0)
|
||||
|
||||
> ✅ **S1–S9 已于 2026-09-14 全部完成**:Keil `@build` 0 错 0 警 + 模拟器 0 警告;S8 = `--logtest` PASS(期间修复 ts 19 字符 / epoch 10 位两处格式 bug)+ ui-verify 五门禁全绿(池基线 5440/5520B、pwc 参考更新)+ 记录页/待机屏/密码错误提示截图目检通过;S9 = 文档同步。
|
||||
> ✅ **步骤 1–9 已于 2026-09-14 全部完成**:Keil `@build` 0 错 0 警 + 模拟器 0 警告;步骤 8 = `--logtest` PASS(期间修复 ts 19 字符 / epoch 10 位两处格式 bug)+ ui-verify 五门禁全绿(池基线 5440/5520B、pwc 参考更新)+ 记录页/待机屏/密码错误提示截图目检通过;步骤 9 = 文档同步。
|
||||
|
||||
| # | 步骤 | 产物 |
|
||||
|---|------|------|
|
||||
| S1 | 字体补字 + 重生成 | `ui_cn_chars.txt`、`ui_font_cn_12.c` |
|
||||
| S2 | 日志引擎:`sys_log.h`(共享 API/格式)+ `sys_log_mcu.c` + `sim/sim_syslog.c` | 双端可 post/count/get |
|
||||
| S3 | 自检埋点 + defaultTask 落盘循环 + 上电/重启分类 | app_main/freertos/net_task 接线 |
|
||||
| S4 | 密码错误提示 | ui_page_password.c |
|
||||
| S5 | 待机屏 `ui_standby`(空闲检测 + 覆盖层)+ 键挂钩 | ui_menu/ui_content_page 各一行通知 |
|
||||
| S6 | 记录页 ×2 + 内容页框架接线(枚举/描述符表/node 映射) | ui_page_runlog/selftest、ui_content_page.h/.c、ui_menu.c |
|
||||
| S7 | 双端注册新文件(uvprojx + CMakeLists)+ 构建 0/0 | new-source-file skill |
|
||||
| S8 | 模拟器无头回归(--logtest/--standby/截图断言)+ 真机 @test | 测试通过记录 |
|
||||
| S9 | 文档同步(项目架构总览、AGENTS.md、本文档状态) | docs |
|
||||
| 步骤 1 | 字体补字 + 重生成 | `ui_cn_chars.txt`、`ui_font_cn_12.c` |
|
||||
| 步骤 2 | 日志引擎:`sys_log.h`(共享 API/格式)+ `sys_log_mcu.c` + `sim/sim_syslog.c` | 双端可 post/count/get |
|
||||
| 步骤 3 | 自检埋点 + defaultTask 落盘循环 + 上电/重启分类 | app_main/freertos/net_task 接线 |
|
||||
| 步骤 4 | 密码错误提示 | ui_page_password.c |
|
||||
| 步骤 5 | 待机屏 `ui_standby`(空闲检测 + 覆盖层)+ 键挂钩 | ui_menu/ui_content_page 各一行通知 |
|
||||
| 步骤 6 | 记录页 ×2 + 内容页框架接线(枚举/描述符表/node 映射) | ui_page_runlog/selftest、ui_content_page.h/.c、ui_menu.c |
|
||||
| 步骤 7 | 双端注册新文件(uvprojx + CMakeLists)+ 构建 0/0 | new-source-file skill |
|
||||
| 步骤 8 | 模拟器无头回归(--logtest/--standby/截图断言)+ 真机 @test | 测试通过记录 |
|
||||
| 步骤 9 | 文档同步(项目架构总览、AGENTS.md、本文档状态) | docs |
|
||||
|
||||
@@ -211,9 +211,9 @@ flowchart TD
|
||||
L --> M["f_stat 更新变更基线"]
|
||||
```
|
||||
|
||||
- **超长守卫(E-01,v1.12)**:外科手术输出超 `CFG_FILE_MAX_LEN`(4096B)→ **拒绝保存返回 -1**(原文件不动 + 自检上报 `cfg save overflow`);`s_write_doc`(模板/外科同闸的唯一落盘出口)硬性拒写 >4096B —— "引擎永不产出超长 config.ini"是结构性质。超长文件一律按损坏处置(load/poll 同判,见 §5.3)
|
||||
- **超长守卫(v1.12)**:外科手术输出超 `CFG_FILE_MAX_LEN`(4096B)→ **拒绝保存返回 -1**(原文件不动 + 自检上报 `cfg save overflow`);`s_write_doc`(模板/外科同闸的唯一落盘出口)硬性拒写 >4096B —— "引擎永不产出超长 config.ini"是结构性质。超长文件一律按损坏处置(load/poll 同判,见 §5.3)
|
||||
|
||||
**(3) 变更检测** —— `cfg_file_poll()`(defaultTask / 模拟器主循环,2s 节拍):`f_stat` 取 (size, mtime-epoch) 与基线比对 → 沉降后**先按真实 `st.size` 查超长**(E-01,v1.12):>4096B = 损坏 → 各段复位工厂默认 + 重建模板 + 自检留痕(`cfg poll oversized`),**不触发段回调**(保留 FTP/在线修复通道,下次保存或重启收敛);正常路径重载 → 段变化则触发该段回调 → 刷新基线。
|
||||
**(3) 变更检测** —— `cfg_file_poll()`(defaultTask / 模拟器主循环,2s 节拍):`f_stat` 取 (size, mtime-epoch) 与基线比对 → 沉降后**先按真实 `st.size` 查超长**(v1.12):>4096B = 损坏 → 各段复位工厂默认 + 重建模板 + 自检留痕(`cfg poll oversized`),**不触发段回调**(保留 FTP/在线修复通道,下次保存或重启收敛);正常路径重载 → 段变化则触发该段回调 → 刷新基线。
|
||||
|
||||
**(4) 段变更回调** —— 未来模块的接入点:
|
||||
|
||||
@@ -356,7 +356,7 @@ typedef struct { ... } cfg_section_reg_t;
|
||||
int cfg_file_register(const cfg_section_reg_t *p_sec); /* 注册段(首次 load 前;变更回调随段注册) */
|
||||
int cfg_file_load(void); /* 0 = 正常(含回退默认)/ -1 = 严重错误 */
|
||||
int cfg_file_save(void); /* 0 = 成功 / -1 = 失败(原文件保持不动;输出超 4096B 拒绝保存,v1.12) */
|
||||
void cfg_file_poll(void); /* 变更检测 + 沉降去抖(defaultTask / 模拟器主循环,2s 节拍);沉降后先判超长(E-01) */
|
||||
void cfg_file_poll(void); /* 变更检测 + 沉降去抖(defaultTask / 模拟器主循环,2s 节拍);沉降后先判超长 */
|
||||
void *cfg_file_section_data(const char *p_name); /* 取段 RAM 副本(未注册 = NULL) */
|
||||
```
|
||||
|
||||
@@ -374,7 +374,7 @@ int cfg_store_write_atomic(const char *p_path, const uint8_t *p_buf, size_t len)
|
||||
int cfg_store_stat(const char *p_path, cfg_file_stat_t *p_st); /* 0 = 存在 / -1 = 缺失/失败 */
|
||||
int cfg_store_remove(const char *p_path);
|
||||
|
||||
/* 平台堆(P0-1,2026-09-18):共享核心的 KB 级临时缓冲一律经此三件套取用,
|
||||
/* 平台堆(2026-09-18 起):共享核心的 KB 级临时缓冲一律经此三件套取用,
|
||||
* 核心禁止直接调用 C 库 malloc —— MCU 端 = pvPortMalloc/vPortFree(FreeRTOS 堆),
|
||||
* 模拟器端 = malloc/free(宿主 CRT 堆,堆余量以 MB 计,不参与 MCU 预算) */
|
||||
void *cfg_store_alloc(size_t size); /* 失败返回 NULL,由调用方打印 FAIL */
|
||||
@@ -441,7 +441,7 @@ void adc_cfg_init(void)
|
||||
|
||||
## 8. 内存预算
|
||||
|
||||
依据:最新 map(2026-09-18,P0-1 修复后):静态区(128 KB 映射 SRAM1)已用 **126,064 B(96.2%)**,**余 5,008 B**;FreeRTOS 堆 `configTOTAL_HEAP_SIZE = 49,152 B`,扣除六任务栈 32 KB + 空闲/定时器栈 + IPC 后**空闲 ≈14 KB**(首启实测值直接看串口 `load: OK (…B, heap free …B)` 行)。
|
||||
依据:最新 map(2026-09-18 平台堆改造后):静态区(128 KB 映射 SRAM1)已用 **126,064 B(96.2%)**,**余 5,008 B**;FreeRTOS 堆 `configTOTAL_HEAP_SIZE = 49,152 B`,扣除六任务栈 32 KB + 空闲/定时器栈 + IPC 后**空闲 ≈14 KB**(首启实测值直接看串口 `load: OK (…B, heap free …B)` 行)。
|
||||
|
||||
| 项 | 大小 | 性质 | 说明 |
|
||||
|---|---|---|---|
|
||||
@@ -454,9 +454,9 @@ void adc_cfg_init(void)
|
||||
| **堆峰值(save 期间)** | **≤ 9,217 B** | 暂态 | 编译期由 `CFG_HEAP_BUDGET = 10,240 B` 钉死,放大缓冲宏会先编译失败 |
|
||||
| **静态 .bss 增量** | **≈ 0.7 KB(实测 706 B)** | 稳态 | 段表 + 行号表 + 快照 + 基线 << 静态余量 5.0 KB ✓ |
|
||||
|
||||
**P0-1(2026-09-18)实现纠偏**:本表原设计即"暂态走堆",但实现落在 C 库 `malloc` 上——本机工具链为 **MicroLIB**,其 C 堆只有 `Heap_Size = 0x200`(512 B),真机上 4 处 KB 级分配**必然返回 NULL**,症状是"配置读不到 → 静默回落工厂默认值"(模拟器用宿主 CRT 堆,故两端表现不一致)。现全部改走 `cfg_store_alloc`;map 复核:`malloc.o` 不再参与链接,`Removing startup_stm32f407xx.o(HEAP), (512 bytes)` → **静态区反而净增 512 B 余量**。
|
||||
**实现纠偏(2026-09-18)**:本表原设计即"暂态走堆",但实现落在 C 库 `malloc` 上——本机工具链为 **MicroLIB**,其 C 堆只有 `Heap_Size = 0x200`(512 B),真机上 4 处 KB 级分配**必然返回 NULL**,症状是"配置读不到 → 静默回落工厂默认值"(模拟器用宿主 CRT 堆,故两端表现不一致)。现全部改走 `cfg_store_alloc`;map 复核:`malloc.o` 不再参与链接,`Removing startup_stm32f407xx.o(HEAP), (512 bytes)` → **静态区反而净增 512 B 余量**。
|
||||
|
||||
**结论**:配置引擎自身不需要内存优化专项;但 9,217 B 暂态峰值已占 FreeRTOS 堆空闲的一半以上,且与 lftpd 的每命令分配共存——**流式读写(免整文件驻留内存)仍列为后续优化项**,方案见本文 §6.2/§8(原报告 §4.4.1 已随 N-01 修复按销项删除,完整记录沉淀在本文)。
|
||||
**结论**:配置引擎自身不需要内存优化专项;但 9,217 B 暂态峰值已占 FreeRTOS 堆空闲的一半以上,且与 lftpd 的每命令分配共存——**流式读写(免整文件驻留内存)仍列为后续优化项**,方案见本文 §6.2/§8(原报告该节已随修复按销项删除,完整记录沉淀在本文)。
|
||||
|
||||
## 9. 兼容与迁移
|
||||
|
||||
|
||||
+3
-3
@@ -12,7 +12,7 @@
|
||||
|
||||
| 规则 | 说明 |
|
||||
|---|---|
|
||||
| **目录名一律不含空格** | 空格迫使脚本/链接/CI 处处加引号,且 URL 编码形态(`UI%20设计`)极易被漏改(D-6,2026-09-25 起强制;全库已无含空格目录) |
|
||||
| **目录名一律不含空格** | 空格迫使脚本/链接/CI 处处加引号,且 URL 编码形态(`UI%20设计`)极易被漏改(2026-09-25 起强制;全库已无含空格目录) |
|
||||
| **按领域归入子目录** | 顶层不放散落 `.md`;新领域先建无空格子目录,再在 [`README.md`](README.md) 登记 |
|
||||
| 现有目录 | `架构设计/` `子系统设计/` `算法/` `网络/` `测试说明/` `代码规范/` `内存管理/` `问题记录/` `环境与部署/` `UI设计/` `硬件平台/` `芯片手册/` `images/` |
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
| `docs/xxx.md`(docs 根下) | `` |
|
||||
| `docs/子目录/xxx.md` | `` |
|
||||
|
||||
> ⚠️ **踩坑记录**:2026-09-25 目录重组时,5 篇文档从 `docs/` 迁入子目录,`images/xxx.svg` 未同步改为 `../images/xxx.svg` → **7 处真实断链**(由 D-7 门禁 `check_doc_links.py` 揪出)。迁移含图文档时务必检查此项。
|
||||
> ⚠️ **踩坑记录**:2026-09-25 目录重组时,5 篇文档从 `docs/` 迁入子目录,`images/xxx.svg` 未同步改为 `../images/xxx.svg` → **7 处真实断链**(由 `doc-links` 门禁揪出)。迁移含图文档时务必检查此项。
|
||||
|
||||
### 3.3 引用尚未创建 / 已删除的文件
|
||||
|
||||
@@ -167,7 +167,7 @@
|
||||
|
||||
---
|
||||
|
||||
## 4. 门禁:文档-代码一致性(D-7)
|
||||
## 4. 门禁:文档-代码一致性
|
||||
|
||||
三个层次,全部由 pre-commit 机械校验:
|
||||
|
||||
|
||||
@@ -336,10 +336,10 @@ dhara 通过 7 个回调函数访问物理 NAND:
|
||||
|
||||
所有回调自动将 dhara 逻辑块/页加 `FTL_START_BLOCK` 偏移转换为物理地址。
|
||||
|
||||
⚠ **两条移植层硬约束(2026-10-15,登记簿 N-21 / 报告 N-12、N-13)**:
|
||||
⚠ **两条移植层硬约束(2026-10-15)**:
|
||||
|
||||
1. **`is_free` 必须整页精确**。dhara 的 journal 用它判断"检查点组是否未编程"(`journal.c:416 cp_free`、`journal.c:520` 找下一空闲页),其正确性前提是"答空闲的页必须真的全 0xFF"(`journal.c:405-414` 的注释论证)。旧实现只看页首 64 B → 一个"页首 0xFF、后段有数据"的已编程页会被误判空闲,dhara 遂**往已编程页再编程一次** = 位碰撞、journal/map 指向垃圾(数据丢失,且不报任何错)。本卷跑的是 FatFS 数据页,这种页型很常见(刚格式化的卷、稀疏文件块、日志尾部)。成本上做了快路径:页首 64 B 有数据就当场返回非空,与旧实现同价,只有"目前读到的全是 0xFF"的页才继续扫后段。
|
||||
2. **六个 HAL 入口一律做几何上界校验**(上界 = `n->num_blocks << n->log2_ppb`)。越界页/块号(含 dhara 哨兵 `DHARA_PAGE_NONE` = 0xffffffff)旧实现直接加偏移送进 SPI 命令,会被芯片地址位**截断成某个真实页** → 静默读写/搬走无辜数据。现越界时 prog/read/copy/erase 返回 -1 且 `*err == DHARA_E_CORRUPT_MAP`,`is_free` 返回 0(保守判非空)、`is_bad` 返回 1(保守判坏)、`mark_bad` 直接返回(绝不标无辜好块)。**错误码选择是刻意的**:不能用 `DHARA_E_BAD_BLOCK`(`journal.c:904 recover_from` 会据此标坏块并跳块),也不能用 `DHARA_E_RECOVER`(`map.c:275 try_recover` 会据此启动回收);其余错误一律原样上抛,不会静默清 map(E-31 教训)。
|
||||
2. **六个 HAL 入口一律做几何上界校验**(上界 = `n->num_blocks << n->log2_ppb`)。越界页/块号(含 dhara 哨兵 `DHARA_PAGE_NONE` = 0xffffffff)旧实现直接加偏移送进 SPI 命令,会被芯片地址位**截断成某个真实页** → 静默读写/搬走无辜数据。现越界时 prog/read/copy/erase 返回 -1 且 `*err == DHARA_E_CORRUPT_MAP`,`is_free` 返回 0(保守判非空)、`is_bad` 返回 1(保守判坏)、`mark_bad` 直接返回(绝不标无辜好块)。**错误码选择是刻意的**:不能用 `DHARA_E_BAD_BLOCK`(`journal.c:904 recover_from` 会据此标坏块并跳块),也不能用 `DHARA_E_RECOVER`(`map.c:275 try_recover` 会据此启动回收);其余错误一律原样上抛,不会静默清 map(教训:宁报错不销毁数据)。
|
||||
|
||||
### 5.4 初始化流程 (disk_initialize)
|
||||
|
||||
@@ -596,11 +596,11 @@ if (nand_ftl_format() == 0) {
|
||||
13. **BBT 恢复模式** — 运行期坏块会随 TC-STORAGE-03 注入累积;当介质被**误标脏**(如 DMA 误打 CCM 栈导致随机块被写坏并持久化)时,打开 `test/board/storage_test.h` 的 `ENABLE_STORAGE_RECOVERY_TESTS` 编译**恢复构建**,testTask 会执行 `gd5f2gq5ue_bbt_rebuild()`(出厂扫描清除运行期误标)+ `nand_ftl_format()` 清账后复位。恢复后容量回到基线(即扣除 BBT 保留池后的正常容量,非出厂裸容量)。
|
||||
14. **lftpd 路径口径(归档更正 2026-10-13:原误记于 `docs/问题记录/CH395F_Trap_Records.md`——非 CH395F 议题,移入本节)** — FTP STOR/CWD 曾频发 `FR_INVALID_NAME`(6):真约束即上条第 10 项的严格 8.3。原记录"FatFS 不接受 `/` 前缀 / 空字符串失败"两条与仓内 `Lib/FatFs/ff.c` 矛盾(`ff.c:3101-3109` 会剥前导分隔符、`:3127-3129` 空名返回根目录),**已删**。现行口径:`lftpd_io.c` 的 `to_fatfs_path()` 剥 `/` 前缀(行为正确,保留)+ 本仓路径用 `"0:"` 卷前缀(`FF_FS_RPATH=0` 下 `"."` 不是合法路径段)。长文件名需 `FF_USE_LFN=1` + `FF_LFN_UNICODE`(显著增 RAM,未启用)。
|
||||
|
||||
### 10.2 FTP 服务(lftpd)鉴权语义(2026-10-11,N-19)
|
||||
### 10.2 FTP 服务(lftpd)鉴权语义(2026-10-11 起启用)
|
||||
|
||||
FTP 根目录 = 卷根,lftpd 是卷的网络文件入口(`Drivers/BSP/NET/lftpd/`)。N-19 起启用口令鉴权——`[ftp]` 配置段、鉴权流程与改口令方法的**权威口径**在 `docs/子系统设计/网络配置说明.md` §3.4,此处只登记存储侧语义:
|
||||
FTP 根目录 = 卷根,lftpd 是卷的网络文件入口(`Drivers/BSP/NET/lftpd/`)。FTP 鉴权启用——`[ftp]` 配置段、鉴权流程与改口令方法的**权威口径**在 `docs/子系统设计/网络配置说明.md` §3.4,此处只登记存储侧语义:
|
||||
|
||||
- **未登录命令门** — 登录成功前仅 `USER`/`PASS`/`QUIT`/`FEAT`/`SYST`/`NOOP` 放行,其余命令(含 RETR/STOR/LIST/DELE)一律 `530`。修复前 `cmd_user`/`cmd_pass` 对任意口令无条件回 `230` = **匿名全读写整卷**(N-19 根因)。
|
||||
- **未登录命令门** — 登录成功前仅 `USER`/`PASS`/`QUIT`/`FEAT`/`SYST`/`NOOP` 放行,其余命令(含 RETR/STOR/LIST/DELE)一律 `530`。修复前 `cmd_user`/`cmd_pass` 对任意口令无条件回 `230` = **匿名全读写整卷**(鉴权缺失的根因)。
|
||||
- **STOR/DELE 写门** — `[ftp] write=0` 时写命令一律 `550` 拒,卷对 FTP 侧只读(`/log`、`/config.ini` 仍可下载不可改写)。
|
||||
- **全局失败锁定** — 连续 5 次鉴权失败 → 锁定 60 s(跨会话全局、易失、重启清零);纯 lftpd 层状态,不触存储。
|
||||
- **默认口令告警锚点** — 出厂 `pwd_hash` 在用期间每次启动打 INFO `[FTP] using factory default password`。
|
||||
@@ -633,7 +633,7 @@ lftpd 原先把全部异常路径一律按 error 级打(串口上带 `[ERR]`
|
||||
"error reading next command"改成"control channel closed by peer"——原先那句把正常收尾
|
||||
写成了故障,误导过排查方向。
|
||||
|
||||
### 10.4 dhara 失败类:ECC / 预算耗尽 / 完整性故障(2026-10-23,S-5 C2)
|
||||
### 10.4 dhara 失败类:ECC / 预算耗尽 / 完整性故障(2026-10-23)
|
||||
|
||||
一次 NAND 读写要穿过 **SPI → `gd5f_*` → dhara(`dhara_error_t`)→ FTL glue → FatFs `RES_ERROR`**
|
||||
五段,而 glue 以前把 dhara 的所有失败**压成一个 `GD5F_ERROR`**——上层分不清"该重试"、
|
||||
@@ -647,11 +647,11 @@ LPN 与原始码的位置**就地分类并打印(`ftl_err_name()` 给可读名
|
||||
| `JOURNAL_FULL` / `MAP_FULL` | `BSP_ERR_NO_SPACE` | 介质还健康,是 **journal / 映射层块池见底**:该走容量恢复(`../测试说明/存储维护与容量恢复.md`),此时重格式化只是把问题推回去 |
|
||||
| `BAD_BLOCK` / `RECOVER` / `NOT_FOUND` / `CORRUPT_MAP` / 越界 | `BSP_ERR_IO` | 映射或介质**完整性**故障:保卷 + 上报,不许自愈重格式化 |
|
||||
|
||||
- 这条分类与 **E-31** 是同一条纪律的两端:E-31 规定"只有扫描全程 I/O 干净且无
|
||||
- 这条分类与真空白卷判据是同一条纪律的两端:那边规定"只有扫描全程 I/O 干净且无
|
||||
checkpoint(`DHARA_E_TOO_BAD`)才算真空白卷",本表则保证失败**可读**——两者合起来
|
||||
才是"别把瞬态毛刺当卷损坏去 `f_mkfs`"(旧行为:单次 I2C/SPI 抖动 → 清 map → 整卷
|
||||
重格式化 → 静默销毁全部用户数据)。
|
||||
- **仍未闭环**:分类目前**只进日志**;`disk_read`/`disk_write` 对 FatFs 仍只能回 `RES_ERROR`
|
||||
(那是 FatFs 的契约)。要让 defaultTask 的卷健康探针**按类分支**,还需要一个跨调用
|
||||
存活的失败类快照(`nand_ftl_last_error()`,8 B;代价是要先定多写者纪律——
|
||||
defaultTask 与 testTask 都会碰存储)→ 报告 S-5 的 C4 待还项。
|
||||
defaultTask 与 testTask 都会碰存储)→ 即登记簿条目「可选全序列卷锁」的待还项。
|
||||
|
||||
@@ -219,7 +219,7 @@ if (sys_evtHandle != NULL) {
|
||||
- **修法**:所有**状态位**等待加 `osFlagsNoClear`(已改:`Src/freertos.c` 的 ftpTask、`App/task/ui_task.c`、`App/sync/time_sync.c`、`App/task/net_task.c`、`test/board/ch395f_test_task.c`);**命令位**(`CFG_SAVE`/`NET_RECONFIG`)保持消费型等待。
|
||||
- **工程化防线**:① 关键消费者加"启动超时告警"(如 ftpTask 10s 内未到 listen 就 `DBG_ERROR`);② 用 `scripts/stack_report.py` 看任务栈水位——**某任务水位异常低 = 它根本没干活**(本次正是靠 ftpTask 只有 156B 才发现)。
|
||||
|
||||
8. **启动段(`osKernelStart` 之前)死机的判读法(2026-10-02 S10 落地)**:`app_main_init` 全程运行在**内核启动前**——此时没有任务、没有看门狗保护,一旦卡死就是"无输出 + LED 不闪"(N-03b 的显式代价)。得益于 S10 补齐的可观测性,现在**每一步都有结果日志**,判读规则很简单:
|
||||
8. **启动段(`osKernelStart` 之前)死机的判读法(2026-10-02 落地)**:`app_main_init` 全程运行在**内核启动前**——此时没有任务、没有看门狗保护,一旦卡死就是"无输出 + LED 不闪"(立项时明示的代价)。得益于那次整改补齐的可观测性,现在**每一步都有结果日志**,判读规则很简单:
|
||||
|
||||
> **开机日志的最后一行 = 卡住的那一步**(该步的"结果日志"没打出来)。
|
||||
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@
|
||||
| `defaultTask` | 5120 | Normal | FatFS 挂载(无卷 `f_mkfs`)→ 卷健康探针/自愈 → `net_cfg_load`(配置引擎属主)→ 置 `STORAGE_READY`(= 存储+配置就绪)→ 日志落盘(唯一写者,`syslog_drain`)+ 配置保存执行/2s poll + LED 闪烁 + **栈水位观测**(`stack_probe_poll`:首次 5s 后报告,此后仅在出现更深峰值时打印) | `StartDefaultTask` |
|
||||
| `netTask` | 3840 | Normal | 等存储(配置已由 defaultTask 就绪,本任务只读 RAM 副本)→ `net_stack_bring_up()`(不触碰配置文件引擎)→ 置 `NET_READY` → 循环 `net_poll` + `net_process_messages`;消费 `SYS_EVT_NET_RECONFIG` → 按网络代次号重建监听(CH395F 硬件层测试模式下入口自挂起) | `StartNetTask` |
|
||||
| `ftpTask` | 4096 | Normal | 等网络**且**存储(`WaitAll`)→ `lftpd_start("/", 21)` → 单客户端会话循环(断开后经 `net_listener` 重建监听) | `StartFtpTask` |
|
||||
| `testTask` | 8192 | BelowNormal | 测试套件入口(`test/board/test_config.h` 选择)。**产品构建不创建**:CubeMX 生成区无条件建后,`MX_FREERTOS_Init()` 在未选套件时(`!TEST_SUITE_SELECTED`)立即 `vTaskDelete` 回收其 8KB CCM 栈(P2-13,2026-10-04) | `start_test_task` |
|
||||
| `testTask` | 8192 | BelowNormal | 测试套件入口(`test/board/test_config.h` 选择)。**产品构建不创建**:CubeMX 生成区无条件建后,`MX_FREERTOS_Init()` 在未选套件时(`!TEST_SUITE_SELECTED`)立即 `vTaskDelete` 回收其 8KB CCM 栈(2026-10-04) | `start_test_task` |
|
||||
| `uiTask` | 16384 | BelowNormal | 等网络 → `ui_port_init`/`ui_menu_init`/`ui_standby_init`(空闲 60s 切待机屏)/`ui_net_sink` → 10ms 刷新 | `ui_task_func` |
|
||||
| `timeSyncTask` | 2560 | Normal | 等网络 → TCP :8888 收 PC 推送时间 → 写 RTC | `time_sync_task` |
|
||||
| `adcTask` | 2560 | AboveNormal | 纯消费者:`osThreadFlagsWait` 等 TIM3 1kHz 唤醒(ISR 内 `adc_tick_irq_notify` 置位)→ `adc_input_poll()`(TPAFE 原子快照 + STM32 ADC1 DMA 双缓冲)→ L1/L2 消费,不取数不做保护运算 | `adc_task_func` |
|
||||
|
||||
+10
-10
@@ -13,7 +13,7 @@
|
||||
> [`相量层单元测试说明.md`](相量层单元测试说明.md)(同批落地的 L2 姊妹篇)、
|
||||
> [`../硬件平台/ADC通道映射说明.md`](../硬件平台/ADC通道映射说明.md)(**语义映射权威口径**)、
|
||||
> [`../算法/继电保护功能复现规划.md`](../算法/继电保护功能复现规划.md)(L1-3 / L1-4 设计依据)、
|
||||
> 历史审计 E-44 / E-58(快照语义约定;属主文档已于 2026-10-15 删除,编号仅作指称)
|
||||
> 快照语义约定的历史审计(属主文档已于 2026-10-15 删除)
|
||||
|
||||
---
|
||||
|
||||
@@ -135,7 +135,7 @@ test/host/adc_input/adc_input_test.c
|
||||
| **TC-ADCIN-017** | `IN` → STM32 `CH2` | 同上 |
|
||||
| **TC-ADCIN-018** | `TEMP` → STM32 `CH5`(V_ZL2) | 同上 |
|
||||
| **TC-ADCIN-019** | `adc_input_desc(ADC_SEM_COUNT)` → `NULL` | 越界防御 |
|
||||
| **TC-ADCIN-01A** | `adc_input_desc((adc_semantic_t)-1)` → `NULL` | 无符号比较兜底 |
|
||||
| **TC-ADCIN-01a** | `adc_input_desc((adc_semantic_t)-1)` → `NULL` | 无符号比较兜底 |
|
||||
|
||||
### 2.3 映射表自检(`map_check`,静态)
|
||||
|
||||
@@ -158,15 +158,15 @@ test/host/adc_input/adc_input_test.c
|
||||
| **TC-ADCIN-027** | `UC` = CH3 / rank4 = 103 | 同上 |
|
||||
| **TC-ADCIN-028** | `IB` = CH6 / rank7 = 106 | 同上 |
|
||||
| **TC-ADCIN-029** | `IC` = CH1 / rank2 = 101 | 同上 |
|
||||
| **TC-ADCIN-02A** | `IN` = CH2 / rank3 = 102 | 同上 |
|
||||
| **TC-ADCIN-02B** | `TEMP` = CH5 / rank6 = 105 | 同上 |
|
||||
| **TC-ADCIN-02C** | 取帧后 `UA`(TPAFE)仍为 -2 | 两来源互相独立 |
|
||||
| **TC-ADCIN-02a** | `IN` = CH2 / rank3 = 102 | 同上 |
|
||||
| **TC-ADCIN-02b** | `TEMP` = CH5 / rank6 = 105 | 同上 |
|
||||
| **TC-ADCIN-02c** | 取帧后 `UA`(TPAFE)仍为 -2 | 两来源互相独立 |
|
||||
| **TC-ADCIN-080..085** | ⭐ **乒乓双缓冲**:往"正在被 DMA 写的另一半区"填 900/800 系干扰值,`stm32_take()` 仍必须读到**刚完成那一半**(108 / 208) | **撕裂帧防线**(读错半区 = 半新半旧混合帧) |
|
||||
| **TC-ADCIN-086..089** | 两档超拍:连投 2 帧不消费 → 取到最新帧(408)且 `gaps()` = 1;再连投 3 帧不消费(一次跨 2 帧)→ `gaps()` 累计到 3,把单位钉成**丢掉的帧点数**(2026-10-21 由「次数」改来,与判定层 `tgap` 同单位);`errs()` 始终 = 0 | **丢帧与停摆分开计数**(消费者超拍 ≠ 节拍源停);两档并列才分得出「次数 vs 点数」 |
|
||||
| **TC-ADCIN-090..09A** | `HAL_ADC_ErrorCallback(&hadc1)` ×2 → `hw_errs()` = 2;用**别的句柄**调三个回调 → `seq` / `hw_errs` 均不动 | 三个 HAL 弱回调的 `hadc == &hadc1` **句柄守卫** |
|
||||
| **TC-ADCIN-030..034** | `HAL_ADC_Start_DMA` 返回 `HAL_ERROR` → `init()` 返回 **-2**、状态码 `RC_START`、计数 +1、STM32 侧无有效数据 | 挂载失败(一次性,非每拍) |
|
||||
| **TC-ADCIN-035..039** | 无任何 DMA 完成 → `RC_STALL`、**单拍不计故障**、`seq` 不前进、STM32 侧无有效数据 | 无新帧路径 + 相位伪影不误报 |
|
||||
| **TC-ADCIN-03A..03E** | 连续两拍无新帧 → `errs()` = 1;第三拍 → 2;恢复拍成功且 `gaps()` 仍 0 | 停摆判据 = **连续 ≥2 拍**;跨次单调累计 |
|
||||
| **TC-ADCIN-03a..03e** | 连续两拍无新帧 → `errs()` = 1;第三拍 → 2;恢复拍成功且 `gaps()` 仍 0 | 停摆判据 = **连续 ≥2 拍**;跨次单调累计 |
|
||||
| **TC-ADCIN-070..078** | ⭐ **停摆拍不得沿用上一拍旧值**:先成功一拍让 STM32 侧进入有效态(`UB`=108),再注入无新帧拍 → `adc_input_raw()` 必须返 **-2**;恢复拍重新可取数 | **陈旧帧**(2026-10-10 真机实测发现的缺陷,见下注) |
|
||||
|
||||
> ⚠ **为什么 TC-ADCIN-034 照不出这条缺陷**:它是"`adc_input_init()` 后**立刻**失败",此时
|
||||
@@ -192,8 +192,8 @@ test/host/adc_input/adc_input_test.c
|
||||
| **TC-ADCIN-044** | TPAFE 无有效帧 → -2 | 有效标志语义 |
|
||||
| **TC-ADCIN-045** | STM32 无有效扫描 → -2 | 有效标志语义 |
|
||||
| **TC-ADCIN-049** | `UA` → `buf[6]` 的值(注入 3006) | 按**下标**取数(非按枚举序) |
|
||||
| **TC-ADCIN-04A** | `UN` → `buf[5]` 的值(注入 2005) | 同上 |
|
||||
| **TC-ADCIN-04B** | `IA` → `buf[2]` 的值(注入 **-1234**) | 16 位补码负值原样保留(不截断 / 不取绝对值) |
|
||||
| **TC-ADCIN-04a** | `UN` → `buf[5]` 的值(注入 2005) | 同上 |
|
||||
| **TC-ADCIN-04b** | `IA` → `buf[2]` 的值(注入 **-1234**) | 16 位补码负值原样保留(不截断 / 不取绝对值) |
|
||||
|
||||
### 2.6 采集一拍(`adc_input_poll`)
|
||||
|
||||
@@ -260,9 +260,9 @@ test/host/adc_input/adc_input_test.c
|
||||
`adc_input_raw()` 返回的是**未标定原始码值**(TPAFE = 16 位补码,STM32 = 0..4095)。
|
||||
一次系数 / 零漂标定属 **L1-5,尚未实现**,故本单测不对"物理量换算"做任何断言。
|
||||
|
||||
### 4.3 不覆盖 V0.1 的硬件缺陷(N-18)
|
||||
### 4.3 不覆盖 V0.1 的硬件缺陷(双转换器无共同采样触发)
|
||||
|
||||
V0.1 上 8 路电气量分属两片转换器且**无共同采样触发**(N-18),本层只做**逐通道独立监视**。
|
||||
V0.1 上 8 路电气量分属两片转换器且**无共同采样触发**(登记簿条目「双转换器无共同采样触发」),本层只做**逐通道独立监视**。
|
||||
"跨转换器相量合成"(线 / 负序 / 零序)不得在本层或 L2 上做——属 L2-5 且 V0.1 受限
|
||||
(见 `docs/算法/继电保护功能复现规划.md` §1.6)。
|
||||
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
|
||||
## 1. 概述
|
||||
|
||||
本文档定义 CH395F 以太网驱动(STM32F407ZGTx,SPI2 接口)的测试规范。当前固件 `FUN_PARA=0x08`(bit3 SOCKET_CLOSE=1,bit0/bit1 均为 0):8 个 Socket 0~7 全部可用(**由 Socket 索引 `_SN` 命令族 + 缓冲显式分配实现,与 FUN_PARA 无关**,见 `问题记录/CH395F_Trap_Records.md` TRAP-NET-15),Socket 0 作 TCP Server 单连接,覆盖单连接与多并发客户端场景。测试按阶段(TM-PHY-NN)组织,每个阶段包含独立测试用例(TC-NET-NNN)。
|
||||
本文档定义 CH395F 以太网驱动(STM32F407ZGTx,SPI2 接口)的测试规范。当前固件 `FUN_PARA=0x08`(bit3 SOCKET_CLOSE=1,bit0/bit1 均为 0):8 个 Socket 0~7 全部可用(**由 Socket 索引 `_SN` 命令族 + 缓冲显式分配实现,与 FUN_PARA 无关**,见 `问题记录/CH395F_Trap_Records.md` TRAP-NET-15),Socket 0 作 TCP Server 单连接,覆盖单连接与多并发客户端场景。测试按阶段组织,每个阶段包含独立测试用例(TC-NET-NNN)。
|
||||
|
||||
### 设计原则
|
||||
|
||||
| 原则 | 描述 | 验证用例 |
|
||||
|------|------|----------|
|
||||
| DP-01 | 单连接 socket:Socket 0 唯一,复用监听和数据通道;CONNECT 后切换数据通道;DISCONNECT/TIMEOUT 后重新 OPEN → LISTEN | TC-NET-201~203, 601~606, 701~703, 801, 802, 901, 902, 1001~1006 |
|
||||
| DP-02 | 中断集中处理:所有 CH395F 中断在 `net_poll()` 中通过 `GET_GLOB_INT_STATUS` 统一读取并清除,ISR 及其他位置不处理 | TC-NET-101 |
|
||||
| DP-03 | 线程安全:所有 CH395F 操作通过 `netMsgQueue` 在 netTask 串行处理 | TC-NET-301~302 |
|
||||
| DP-04 | DMA 边界安全:`CH395F_SPI_DMA_BUF_SIZE=4100`,单次事务最大载荷 `4096B`,超限自动分块 | TC-NET-1001~1005 |
|
||||
| 单连接 socket | Socket 0 唯一,复用监听和数据通道;CONNECT 后切换数据通道;DISCONNECT/TIMEOUT 后重新 OPEN → LISTEN | TC-NET-201~203, 601~606, 701~703, 801, 802, 901, 902, 1001~1006 |
|
||||
| 中断集中处理 | 所有 CH395F 中断在 `net_poll()` 中通过 `GET_GLOB_INT_STATUS` 统一读取并清除,ISR 及其他位置不处理 | TC-NET-101 |
|
||||
| 线程安全 | 所有 CH395F 操作通过 `netMsgQueue` 在 netTask 串行处理 | TC-NET-301~302 |
|
||||
| DMA 边界安全 | `CH395F_SPI_DMA_BUF_SIZE=4100`,单次事务最大载荷 `4096B`,超限自动分块 | TC-NET-1001~1005 |
|
||||
|
||||
### CH395F 缓冲架构(关键参数)
|
||||
|
||||
@@ -97,7 +97,7 @@ MCU: STM32F407ZGTx @ 168MHz, Keil MDK-ARM v5 (ARMCC)
|
||||
|
||||
## 2. 阶段 1:寄存器与 SPI 命令验证
|
||||
|
||||
| 阶段 ID | TM-PHY-01 |
|
||||
| 阶段 | 阶段 1 |
|
||||
|---------|-----------|
|
||||
| **类型** | 独立运行 |
|
||||
| **耗时** | ~1 秒 |
|
||||
@@ -130,13 +130,13 @@ MCU: STM32F407ZGTx @ 168MHz, Keil MDK-ARM v5 (ARMCC)
|
||||
|
||||
**通过标准**:9/9 通过,0 失败。任一失败 → 阶段标记 FAIL,后续阶段不执行
|
||||
|
||||
**覆盖原则**:DP-02
|
||||
**覆盖原则**:中断集中处理
|
||||
|
||||
---
|
||||
|
||||
## 3. 阶段 2:TCP Client(CH395F 主动发起连接)
|
||||
|
||||
| 阶段 ID | TM-PHY-02 |
|
||||
| 阶段 | 阶段 2 |
|
||||
|---------|-----------|
|
||||
| **类型** | 需 PC 配合 |
|
||||
| **耗时** | ~60 秒 |
|
||||
@@ -171,7 +171,7 @@ MCU: STM32F407ZGTx @ 168MHz, Keil MDK-ARM v5 (ARMCC)
|
||||
|
||||
**通过标准**:7/7 通过,0 失败。任一失败 → 阶段标记 FAIL,后续阶段不执行
|
||||
|
||||
**覆盖原则**:DP-01(open→connect→send→recv→close 主路径,硬件层)
|
||||
**覆盖原则**:单连接 socket(open→connect→send→recv→close 主路径,硬件层)
|
||||
|
||||
---
|
||||
|
||||
@@ -198,7 +198,7 @@ MCU: STM32F407ZGTx @ 168MHz, Keil MDK-ARM v5 (ARMCC)
|
||||
|
||||
**通过标准**:3/3 轮全部 6 步通过,0 失败。任一失败 → 阶段标记 FAIL,后续不执行
|
||||
|
||||
**覆盖原则**:DP-01(open→connect→close→re-open→reconnect,硬件层)
|
||||
**覆盖原则**:单连接 socket(open→connect→close→re-open→reconnect,硬件层)
|
||||
|
||||
---
|
||||
|
||||
@@ -223,7 +223,7 @@ MCU: STM32F407ZGTx @ 168MHz, Keil MDK-ARM v5 (ARMCC)
|
||||
|
||||
**通过标准**:检测到 `SOCK_TIMEOUT` / `DISCONNECT` 且系统稳定,0 崩溃。任一异常 → 阶段标记 FAIL
|
||||
|
||||
**覆盖原则**:DP-01(异常路径的 connect 失败处理,硬件层)
|
||||
**覆盖原则**:单连接 socket(异常路径的 connect 失败处理,硬件层)
|
||||
|
||||
---
|
||||
|
||||
@@ -250,13 +250,13 @@ MCU: STM32F407ZGTx @ 168MHz, Keil MDK-ARM v5 (ARMCC)
|
||||
|
||||
**通过标准**:45/45。任一模式偏离上表 → 说明芯片关闭语义或 `FUN_PARA` 配置变了,须回查 `问题记录/CH395F_Trap_Records.md` TRAP-NET-07。
|
||||
|
||||
**覆盖原则**:DP-03(状态机边界:关闭次序 × Socket 复用)
|
||||
**覆盖原则**:线程安全(状态机边界:关闭次序 × Socket 复用)
|
||||
|
||||
---
|
||||
|
||||
## 4. 阶段 3:UDP Server Echo(CH395F 作为 UDP Server)
|
||||
|
||||
| 阶段 ID | TM-PHY-03 |
|
||||
| 阶段 | 阶段 3 |
|
||||
|---------|-----------|
|
||||
| **类型** | 需 PC 配合 |
|
||||
| **耗时** | ~60 秒 |
|
||||
@@ -279,7 +279,7 @@ MCU: STM32F407ZGTx @ 168MHz, Keil MDK-ARM v5 (ARMCC)
|
||||
| **标题** | 30 轮 64B UDP 数据报回显 |
|
||||
| **前置条件** | PC: `python test/host/ch395f_socket_test.py udp_client --ip 192.168.1.100 --port 60000` |
|
||||
|
||||
> **会话结构**(固件单会话,与 udp_client 脚本约定):累计 **60 个有效数据包**后关闭 Socket——第 1~30 轮对应本用例(PC 发 64B),第 31~60 轮对应 TC-302(变长);脚本 `"HELLO"` 就绪探针只回显、**不计数**,不占用用例预算。
|
||||
> **会话结构**(固件单会话,与 udp_client 脚本约定):累计 **60 个有效数据包**后关闭 Socket——第 1~30 轮对应本用例(PC 发 64B),第 31~60 轮对应 TC-NET-302(变长);脚本 `"HELLO"` 就绪探针只回显、**不计数**,不占用用例预算。
|
||||
|
||||
**测试步骤与判定标准**:
|
||||
|
||||
@@ -292,7 +292,7 @@ MCU: STM32F407ZGTx @ 168MHz, Keil MDK-ARM v5 (ARMCC)
|
||||
|
||||
**通过标准**:30/30 轮回显成功,0 失败。任一失败 → 阶段标记 FAIL
|
||||
|
||||
**覆盖原则**:DP-03(UDP 收发路径,包头源地址解析)
|
||||
**覆盖原则**:线程安全(UDP 收发路径,包头源地址解析)
|
||||
|
||||
---
|
||||
|
||||
@@ -310,13 +310,13 @@ MCU: STM32F407ZGTx @ 168MHz, Keil MDK-ARM v5 (ARMCC)
|
||||
|
||||
**通过标准**:30/30 轮回显成功且 PC 端比对无误,0 失败。任一失败 → 阶段标记 FAIL
|
||||
|
||||
**覆盖原则**:DP-03(变长载荷边界)
|
||||
**覆盖原则**:线程安全(变长载荷边界)
|
||||
|
||||
---
|
||||
|
||||
## 5. 阶段 4:DHCP 动态获取 IP
|
||||
|
||||
| 阶段 ID | TM-PHY-04 |
|
||||
| 阶段 | 阶段 4 |
|
||||
|---------|-----------|
|
||||
| **类型** | PC 配合(脚本绑定 UDP/67,Windows 需**管理员权限**) |
|
||||
| **耗时** | ~10s(上限 30s DISCOVER 轮询 + 30s HELLO 等待) |
|
||||
@@ -377,7 +377,7 @@ CH395F PC (dhcp_server)
|
||||
|
||||
**通过标准**:步 2~4 全部满足,串口 IP 与 PC 分配一致。任一失败 → 阶段标记 FAIL
|
||||
|
||||
**覆盖原则**:DP-03(DHCP 自动配置路径)
|
||||
**覆盖原则**:线程安全(DHCP 自动配置路径)
|
||||
|
||||
---
|
||||
|
||||
@@ -401,13 +401,13 @@ CH395F PC (dhcp_server)
|
||||
|
||||
**通过标准**:步 1~3 全部满足(HELLO 至少 1 次完整往返;固件设计为单次回显后关闭)。任一失败 → 阶段标记 FAIL
|
||||
|
||||
**覆盖原则**:DP-03(动态 IP 下的端到端 UDP 通路)
|
||||
**覆盖原则**:线程安全(动态 IP 下的端到端 UDP 通路)
|
||||
|
||||
---
|
||||
|
||||
## 6. 阶段 5:大文件传输(硬件层)
|
||||
|
||||
| 阶段 ID | TM-PHY-05 |
|
||||
| 阶段 | 阶段 5 |
|
||||
|---------|-----------|
|
||||
| **类型** | PC 配合(`tcp_bulk`:先收 256KB 不回声 → 再按 LCG 回放 256KB) |
|
||||
| **耗时** | ~20 秒(256KB 顺序双向:TX 256KB + RX 256KB,视链路/SPI 吞吐) |
|
||||
@@ -463,7 +463,7 @@ MCU (TCP Client, ch395f_* 裸命令) PC (tcp_bulk --port 8081)
|
||||
- **为什么顺序双测向**:单向隔离,分别测得**纯 TX / 纯 RX** 吞吐与完整性——不被"回声耦合"掩盖各自链路的真实能力
|
||||
- **TX 节奏**:写 4096B → 等 `SENBUF_FREE`(芯片把 socket 缓冲数据搬入内部协议栈/MAC 缓冲后触发)→ 写下一块,全程不等回显;单向发送阶段 PC 只收不回声,故无回读死锁问题
|
||||
- **RX 校验**:PC 按相同 LCG 模式回放,MCU 期望流按块生成 `exp[]` 字节对位 + `sum_rx` 累加,天然处理 TCP 分包/粘包
|
||||
- 单块 4096B 数据 = 触发 DP-04 的 DMA 单次读边界(注意:单 Socket 发送缓冲实际为 1KB,net_send 写入需受此约束)
|
||||
- 单块 4096B 数据 = 触发 DMA 边界安全原则的单次读边界(注意:单 Socket 发送缓冲实际为 1KB,net_send 写入需受此约束)
|
||||
- 双重完整性:逐字节比对 + 全量 32 位累加和 `SUM(TX)==SUM(RX)`(双向同源 LCG,相等即双向一致)
|
||||
- 双向独立吞吐打印(TX/RX 各自 KB/s),作为 SPI 时钟/驱动调整的回归基线
|
||||
|
||||
@@ -498,7 +498,7 @@ MCU (TCP Client, ch395f_* 裸命令) PC (tcp_bulk --port 8081)
|
||||
| 3 | close 并输出结论 | "TX phase: 64/64 blocks" + "RX phase: ..." + "checksum TX==RX" | bad_chunks>0 / 累加和不一致 |
|
||||
|
||||
**通过标准**:步 1~3 全部满足。任一失败 → 阶段标记 FAIL
|
||||
**覆盖原则**:DP-02(两级中断轮询)、DP-04(4KB DMA 读边界)
|
||||
**覆盖原则**:中断集中处理(两级中断轮询)、DMA 边界安全(4KB DMA 读边界)
|
||||
|
||||
---
|
||||
|
||||
@@ -516,12 +516,12 @@ MCU (TCP Client, ch395f_* 裸命令) PC (tcp_bulk --port 8081)
|
||||
|
||||
| 步 | 操作 | 成功标准 | 失败标准 |
|
||||
|----|------|----------|----------|
|
||||
| 1 | `PHASE5_TOTAL_BYTES=64*1024` 重编译,PC `--bulk 65536` 跑一遍 | 全绿 | 同 TC-501 |
|
||||
| 1 | `PHASE5_TOTAL_BYTES=64*1024` 重编译,PC `--bulk 65536` 跑一遍 | 全绿 | 同 TC-NET-501 |
|
||||
| 2 | `PHASE5_TOTAL_BYTES=1024*1024` 重编译,PC `--bulk 1048576` 跑一遍 | 全绿且吞吐无劣化趋势 | 同上 |
|
||||
| 3 | `PHASE5_CHUNK_SIZE=4093`(非 4 对齐,制造跨包边界),PC `--chunk 4093 --bulk 261952` 跑一遍 | 全绿(4093 档实际回传 `64×4093=261952B`,不足一块的尾数不上送,完成判定按实际上送字节) | 尾块校验失败 |
|
||||
|
||||
**通过标准**:三组配置均全绿。任一失败 → 阶段标记 FAIL
|
||||
**覆盖原则**:DP-04(跨包/非对齐边界)
|
||||
**覆盖原则**:DMA 边界安全(跨包/非对齐边界)
|
||||
|
||||
> **记录(2026-08-24 实测)**:三档全部 **6/6 PASSED**,checksum 逐档相等 ——
|
||||
> 64KB(4096B 块): TX 420 / RX 364 KB/s;1MB(4096B 块): TX 449 / RX 391 KB/s;
|
||||
@@ -532,14 +532,14 @@ MCU (TCP Client, ch395f_* 裸命令) PC (tcp_bulk --port 8081)
|
||||
|
||||
## 7. 阶段 6:NET 层 TCP Server 回显
|
||||
|
||||
| 阶段 ID | TM-PHY-06 |
|
||||
| 阶段 | 阶段 6 |
|
||||
|---------|-----------|
|
||||
| **类型** | PC 配合,netTask 运行 |
|
||||
| **耗时** | 持续运行(Server 模式)/ 约 60s(Client 模式) |
|
||||
| **入口** | `ENABLE_PHASE6_TESTS` → `net_layer_test_main()`(`net_test_task.c`,持续监听回显循环) |
|
||||
| **出口** | 用户终止(Server)/ 用例结束自动回到 IDLE(Client) |
|
||||
|
||||
本阶段在 NET 层(单连接 socket,DP-01)经 `net_socket` API 驱动,MCU 作 TCP Server 监听 8080,PC 主动连接,验证回显通路、单连接生命周期与字节级完整性 —— 已实现(net 层自动重监听,应用层零生命周期代码)
|
||||
本阶段在 NET 层(单连接 socket)经 `net_socket` API 驱动,MCU 作 TCP Server 监听 8080,PC 主动连接,验证回显通路、单连接生命周期与字节级完整性 —— 已实现(net 层自动重监听,应用层零生命周期代码)
|
||||
|
||||
> Client 主动连接(原 TC-NET-607/608/609,现 701/702/703)已独立为 **阶段 7**(见 §8),使用独立宏 `ENABLE_PHASE7_TESTS` 与独立入口 `net_layer_client_test_main()`。
|
||||
|
||||
@@ -581,7 +581,7 @@ sequenceDiagram
|
||||
```
|
||||
|
||||
- `phase6_run()` 为**纯回显**:非阻塞 `net_recv(sockfd, s_rx_buf, TEST_BUF_SIZE, NET_MSG_DONTWAIT)` 收到 N 字节后,`net_send(sockfd, s_rx_buf, N, 0)` 原样回显;不做固件侧字节自检(字节完整性由 PC 侧 `data == test_data` 校验)。
|
||||
- 单连接约束(DP-01):Socket 0 复用监听/数据通道;连接断开(DISCONNECT / KeepAlive TIMEOUT / 静默丢失)后由 **net 层自动重监听**(`auto_relisten`:`net_recv` 收到 EOF 时内部重新 `OPEN` + `TCP_LISTEN`),应用层无需 `net_close`/`net_listen`,下一次 `net_accept` 即接到新连接,行为等同 Linux BSD Socket 监听常驻。
|
||||
- 单连接约束:Socket 0 复用监听/数据通道;连接断开(DISCONNECT / KeepAlive TIMEOUT / 静默丢失)后由 **net 层自动重监听**(`auto_relisten`:`net_recv` 收到 EOF 时内部重新 `OPEN` + `TCP_LISTEN`),应用层无需 `net_close`/`net_listen`,下一次 `net_accept` 即接到新连接,行为等同 Linux BSD Socket 监听常驻。
|
||||
|
||||
> Client 主动连接(原 TC-NET-607/608/609,现 701/702/703)已独立为 **阶段 7**,架构与用例见 §8。
|
||||
|
||||
@@ -605,7 +605,7 @@ sequenceDiagram
|
||||
| 4 | 串口观测 `net_get_sock` 状态 | 仅 Socket 0 状态变化,无其它 Socket 干扰 | 出现非预期 Socket 状态跳变 |
|
||||
|
||||
**通过标准**:步 1~4 全部满足,单连接生命周期正常。任一失败 → 标记 FAIL
|
||||
**覆盖原则**:DP-01(OPEN→LISTEN→ESTABLISHED 单连接主路径) |
|
||||
**覆盖原则**:单连接 socket(OPEN→LISTEN→ESTABLISHED 单连接主路径) |
|
||||
|
||||
### TC-NET-602: 64 字节小包回显
|
||||
|
||||
@@ -626,7 +626,7 @@ sequenceDiagram
|
||||
| 3 | PC 汇总 10 轮并逐字节校验 | 10/10 匹配 | 任一轮失败 |
|
||||
|
||||
**通过标准**:10/10 匹配,0 失败。任一失败 → 标记 FAIL
|
||||
**覆盖原则**:DP-01(单连接数据通路,小包) |
|
||||
**覆盖原则**:单连接 socket(单连接数据通路,小包) |
|
||||
|
||||
### TC-NET-603: 1460 字节回显(当前固件 MSS=1024,1460B 会按 MSS 分片)
|
||||
|
||||
@@ -647,7 +647,7 @@ sequenceDiagram
|
||||
| 3 | PC 校验 | 1460B 完全匹配 | 任意字节不符 |
|
||||
|
||||
**通过标准**:1460B 完全匹配,无截断。任一失败 → 标记 FAIL
|
||||
**覆盖原则**:DP-04(1460 ≤ 2KB 接收缓冲,单次 DMA 读空) |
|
||||
**覆盖原则**:DMA 边界安全(1460 ≤ 2KB 接收缓冲,单次 DMA 读空) |
|
||||
|
||||
### TC-NET-604: 4096 字节缓冲满回显
|
||||
|
||||
@@ -668,7 +668,7 @@ sequenceDiagram
|
||||
| 3 | PC 校验 | 4096B 完全匹配 | 任意字节不符 |
|
||||
|
||||
**通过标准**:4096B 完全匹配。任一失败 → 标记 FAIL
|
||||
**覆盖原则**:DP-04(2KB 接收缓冲边界 + 单次 DMA 上限) |
|
||||
**覆盖原则**:DMA 边界安全(2KB 接收缓冲边界 + 单次 DMA 上限) |
|
||||
|
||||
> **2026-09-23 结案**:TC-NET-604 的"缓冲满回显"路径**判定为非缺陷**——真实生产路径(产品固件 + 真 lftpd FTP 上传,判据 = FTP 协议结果 + **上传后 RETR 回读 SHA-256**)实测 **227 轮全过**(8KB~1MB,含零间隔快速重连与 100 轮浸泡),并发生产 UI 流(`:7003`)600 帧 CRC 全过;原台架"停摆"系**测试程序自吞数据 + 判读工具误判**(详见 `CH395F_Trap_Records.md`「台架纪律」节)。
|
||||
> - **本用例判据(不变)**:PC 发 4096B → 固件分次取空并回显 → **PC 侧内容完全匹配**即 PASS;上传/中止类真实缺陷见 **TRAP-NET-18**(回归工具 `test/host/ftp_abort_probe.py`)。
|
||||
@@ -695,7 +695,7 @@ sequenceDiagram
|
||||
| 4 | PC 发 64B → 固件原样回显 | 回显正常且 PC `data == test_data` 通过 | 回显失败 / PC 校验不符 |
|
||||
|
||||
**通过标准**:重连成功且回显正常,0 失败。任一失败 → 标记 FAIL
|
||||
**覆盖原则**:DP-01(DISCONNECT → CLOSED → re-OPEN → LISTEN 单连接恢复) |
|
||||
**覆盖原则**:单连接 socket(DISCONNECT → CLOSED → re-OPEN → LISTEN 单连接恢复) |
|
||||
|
||||
### TC-NET-606: 连接异常恢复(静默断开 / KeepAlive 超时)(未实现:不发 FIN 的静默断开与 KeepAlive 超时后 `auto_relisten` 能否自动回 LISTEN,**无任何可重复观测**——PC 侧 TC-NET-605 走的是干净 close(DISCONNECT 事件),与本条要求的 TIMEOUT 路径机制不同,不算覆盖;断连恢复语义见 docs/网络/网络自愈架构设计.md,2026-10-21 用例清点)
|
||||
|
||||
@@ -716,7 +716,7 @@ sequenceDiagram
|
||||
| 3 | PC 重连 → 发 64B → 验证回显 | 回显正常 | 回显失败 |
|
||||
|
||||
**通过标准**:自动恢复监听,无需手动复位。任一异常 → 标记 FAIL
|
||||
**覆盖原则**:DP-01(异常路径恢复;KeepAlive 探测机制见 TC-NET-1101) |
|
||||
**覆盖原则**:单连接 socket(异常路径恢复;KeepAlive 探测机制见 TC-NET-1101) |
|
||||
|
||||
---
|
||||
|
||||
@@ -726,7 +726,7 @@ sequenceDiagram
|
||||
|
||||
## 8. 阶段 7:NET 层 TCP Client 主动连接
|
||||
|
||||
| 阶段 ID | TM-PHY-07 |
|
||||
| 阶段 | 阶段 7 |
|
||||
|---------|-----------|
|
||||
| **类型** | PC 配合,netTask 运行 |
|
||||
| **耗时** | 约 60s |
|
||||
@@ -804,7 +804,7 @@ sequenceDiagram
|
||||
|
||||
**通过标准**:6/6 通过,0 失败。任一失败 → 标记 FAIL
|
||||
|
||||
**覆盖原则**:DP-01(net_socket→net_connect→net_send→net_recv→net_close 主路径,NET 层)
|
||||
**覆盖原则**:单连接 socket(net_socket→net_connect→net_send→net_recv→net_close 主路径,NET 层)
|
||||
|
||||
### TC-NET-702: TCP Client 关闭重连 ×3 轮
|
||||
|
||||
@@ -827,7 +827,7 @@ sequenceDiagram
|
||||
|
||||
**通过标准**:3/3 轮全部通过,0 失败。任一失败 → 标记 FAIL
|
||||
|
||||
**覆盖原则**:DP-01(net 层 open→connect→close→re-open→reconnect)
|
||||
**覆盖原则**:单连接 socket(net 层 open→connect→close→re-open→reconnect)
|
||||
|
||||
### TC-NET-703: TCP Client 连接超时
|
||||
|
||||
@@ -849,7 +849,7 @@ sequenceDiagram
|
||||
|
||||
**通过标准**:`net_select` 超时且资源正确释放,0 崩溃。任一异常 → 标记 FAIL
|
||||
|
||||
**覆盖原则**:DP-01(NET 层异常路径 connect 失败处理)
|
||||
**覆盖原则**:单连接 socket(NET 层异常路径 connect 失败处理)
|
||||
|
||||
> **实现说明**:TC-NET-703 与 TC-NET-701/702 的 PC 环境互斥(前者要求 PC 服务关闭、后两者要求开启),故固件中 TC-NET-703 由子开关 `PHASE7_TEST_TIMEOUT` 单独启用——默认 `ENABLE_PHASE7_TESTS` 仅跑 701/702;单独开启 `PHASE7_TEST_TIMEOUT` 并关闭 PC 服务后重编,方可执行 703。
|
||||
|
||||
@@ -873,17 +873,17 @@ sequenceDiagram
|
||||
|
||||
**通过标准**:5/5 路全部通过,0 失败。任一失败 → 标记 FAIL
|
||||
|
||||
**覆盖原则**:DP-01(多 Socket 并发主路径)、缓冲架构(8×6 块分配,MSS=1024)
|
||||
**覆盖原则**:单连接 socket(多 Socket 并发主路径)、缓冲架构(8×6 块分配,MSS=1024)
|
||||
|
||||
> **注**:PC 端 `--max-conn` 须为**并发**计数(连接关闭即减),否则 Phase 7 全量(701+702+704 共 12 连接)会按累计计数超限而拒掉 4~7。该用例已随 Phase 7 实测通过(并发回显落在 sock2/4/5/6/7,见 TRAP-NET-15 末)。
|
||||
>
|
||||
> **2026-10-11 复跑(N-31,`FUN_PARA=0x08`)**:**Phase 7 34/34 全通过**,5 路并发 ESTABLISHED + 64 B 回显字节级比对 OK,芯片 Socket 实测落在 **sock2/4/5/6/7**(0/1/3 被 FTP/对时/远显三个监听占用)→ 证明 Socket 可用性不依赖 FUN_PARA。两条**前置排雷**(否则会得到全量假 FAIL):① PC 适配器落在 **Public** 防火墙配置文件会静默丢入站 8081,症状是 TC701/702/704 全部 `CONNECT TIMEOUT`;② 残留的旧 `tcp_server` 进程占着 8081,新服务器绑不上端口不报错。另:`PHASE7_MULTI_COUNT=5`(2026-10-15 由 8 降至此;`NET_MAX_SOCKETS=8` 减去三个常驻监听)。证据链见 `问题记录/CH395F_Trap_Records.md` TRAP-NET-15。
|
||||
> **2026-10-11 复跑(`FUN_PARA=0x08`)**:**Phase 7 34/34 全通过**,5 路并发 ESTABLISHED + 64 B 回显字节级比对 OK,芯片 Socket 实测落在 **sock2/4/5/6/7**(0/1/3 被 FTP/对时/远显三个监听占用)→ 证明 Socket 可用性不依赖 FUN_PARA。两条**前置排雷**(否则会得到全量假 FAIL):① PC 适配器落在 **Public** 防火墙配置文件会静默丢入站 8081,症状是 TC701/702/704 全部 `CONNECT TIMEOUT`;② 残留的旧 `tcp_server` 进程占着 8081,新服务器绑不上端口不报错。另:`PHASE7_MULTI_COUNT=5`(2026-10-15 由 8 降至此;`NET_MAX_SOCKETS=8` 减去三个常驻监听)。证据链见 `问题记录/CH395F_Trap_Records.md` TRAP-NET-15。
|
||||
|
||||
---
|
||||
|
||||
## 9. 阶段 8:大文件 / 批量传输(100KB,文件收发)
|
||||
|
||||
| 阶段 ID | TM-PHY-08 |
|
||||
| 阶段 | 阶段 8 |
|
||||
|---------|-----------|
|
||||
| **类型** | PC 配合(PC 作 TCP Client 连接 MCU:8080),netTask 运行 |
|
||||
| **耗时** | 取决于文件大小与速率(100KB 约数秒) |
|
||||
@@ -915,7 +915,7 @@ sequenceDiagram
|
||||
| **前置条件** | 1. PC: `python ./test/host/ch395f_socket_test.py tcp_file --ip 192.168.1.100 --port 8080 --op recv --file rx_100k.bin --size 102400`(先连接等待数据)<br>2. `ENABLE_PHASE8_TESTS`,`PHASE8_FILE_SIZE=102400`,`PHASE8_DIRECTION=SEND`<br>3. `net_init` 完成,MSS=1024 |
|
||||
| **测试步骤** | 1. MCU `net_accept` 建链(PC 已连接)<br>2. 循环填充一个滑动窗口(≤ s_tx_buf)并调用 `net_send`;`net_send` 内部按硬件发送 FIFO(`NET_SEND_CHUNK_MAX`=1KB,见 TRAP-NET-16)自动拆分写入,直至 100KB 发完<br>3. PC 接收全部字节写入 `rx_100k.bin`,按递增模式或预置 CRC32 校验 |
|
||||
| **通过标准** | PC 收满 102400B 且逐字节/CRC32 校验一致,MCU 无发送错误 |
|
||||
| **覆盖原则** | DP-04(分块发送、DMA 边界)、缓冲架构(1KB 发送缓冲) |
|
||||
| **覆盖原则** | DMA 边界安全(分块发送、DMA 边界)、缓冲架构(1KB 发送缓冲) |
|
||||
| **实测** | ✅ PASS(2026-08-26):固件 `PHASE8_DIRECTION=SEND`,PC `tcp_file --op recv` 收满 102400B,递增模式逐字节校验通过,CRC32=0x9A0E0C8C,耗时 1209ms / 82.7 KB/s,落盘 `rx_100k.bin` 成功。 |
|
||||
|
||||
### TC-NET-802: 100KB 文件接收(PC→MCU)
|
||||
@@ -929,7 +929,7 @@ sequenceDiagram
|
||||
| **前置条件** | 1. PC: `python ./test/host/ch395f_socket_test.py tcp_file --ip 192.168.1.100 --port 8080 --op send --file tx_100k.bin --size 102400`(先连接并发送;无文件则生成 100KB 递增模式)<br>2. 同 TC-NET-801(`PHASE8_DIRECTION=RECV`) |
|
||||
| **测试步骤** | 1. MCU `net_accept` 建链(PC 已连接)<br>2. 循环 `net_recv`(≤2KB/次,保守一次读空)→ 按 offset 字节校验 + 累计 CRC32,直至收满 100KB<br>3. PC 在文件末尾附 4 字节 CRC32(小端);MCU 收齐后比对 CRC32 |
|
||||
| **通过标准** | MCU 收满 102400B,字节校验全过且 CRC32 匹配,无溢出/截断 |
|
||||
| **覆盖原则** | DP-04(接收缓冲 2KB 一次读空) |
|
||||
| **覆盖原则** | DMA 边界安全(接收缓冲 2KB 一次读空) |
|
||||
| **实测** | 🟡 待验证(参考:默认递增模式 100KB 的 CRC32 经 SEND 实测为 `0x9A0E0C8C`,RECV 方向 MCU 累计 CRC32 应与之相等) |
|
||||
|
||||
### TC-NET-803: 100KB 回显 round-trip(可选)
|
||||
@@ -943,7 +943,7 @@ sequenceDiagram
|
||||
| **前置条件** | MCU: `PHASE8_DIRECTION=ECHO`(net_accept 监听 8080);PC: `python ./test/host/ch395f_socket_test.py tcp_file --ip 192.168.1.100 --port 8080 --op echo`(PC 作 Client 连 MCU 并原样回显) |
|
||||
| **测试步骤** | MCU 发 100KB → PC 回显 → MCU 收 100KB 字节校验 |
|
||||
| **通过标准** | 100KB 全过,验证 100KB 经回显链路完整 |
|
||||
| **覆盖原则** | DP-01、DP-04 |
|
||||
| **覆盖原则** | 单连接 socket、DMA 边界安全 |
|
||||
| **实测** | 🟢 已验证(MCU 收齐 102400B 逐字节校验通过;PC 回显客户端 1241ms @ 80.6 KB/s,对端关闭后正常退出;修复了 phase8_run 未关闭连接导致 MCU 在同连接上无限重复、PC 挂起的问题) |
|
||||
|
||||
### 实现说明
|
||||
@@ -963,7 +963,7 @@ IDLE → ACCEPT → [SEND: 分块发 → DONE] / [RECV: 分块收+校验 → DON
|
||||
|
||||
## 10. 阶段 9:Select/Poll I/O 多路复用(单连接)
|
||||
|
||||
| 阶段 ID | TM-PHY-09 |
|
||||
| 阶段 | 阶段 9 |
|
||||
|---------|-----------|
|
||||
| **类型** | PC 配合,netTask 运行 |
|
||||
| **耗时** | 持续运行 |
|
||||
@@ -980,7 +980,7 @@ IDLE → ACCEPT → [SEND: 分块发 → DONE] / [RECV: 分块收+校验 → DON
|
||||
| **前置条件** | Socket 0 ESTABLISHED |
|
||||
| **测试步骤** | 1. PC 发送数据<br>2. `net_select(1, &readfds, ...)` → 返回 > 0<br>3. `NET_FD_ISSET(0, &readfds)` == true<br>4. `net_recv()` → `net_send()` 回显 |
|
||||
| **通过标准** | 回显成功 |
|
||||
| **覆盖原则** | DP-02(select 内部调 net_poll) |
|
||||
| **覆盖原则** | 中断集中处理(select 内部调 net_poll) |
|
||||
|
||||
### TC-NET-902: net_select() 超时
|
||||
|
||||
@@ -998,7 +998,7 @@ IDLE → ACCEPT → [SEND: 分块发 → DONE] / [RECV: 分块收+校验 → DON
|
||||
|
||||
## 11. 阶段 10:边界条件测试
|
||||
|
||||
| 阶段 ID | TM-PHY-10 |
|
||||
| 阶段 | 阶段 10 |
|
||||
|---------|-----------|
|
||||
| **类型** | PC 配合,netTask 运行 |
|
||||
| **耗时** | 按需 |
|
||||
@@ -1015,7 +1015,7 @@ IDLE → ACCEPT → [SEND: 分块发 → DONE] / [RECV: 分块收+校验 → DON
|
||||
| **前置条件** | Socket 0 ESTABLISHED |
|
||||
| **测试步骤** | MCU 生成 4095B 递增模式数据 → `net_send_sock(sk, data, 4095)` → 等待 PC 回显 → 验证 |
|
||||
| **通过标准** | 4095B 完全匹配 |
|
||||
| **覆盖原则** | DP-04 |
|
||||
| **覆盖原则** | DMA 边界安全 |
|
||||
|
||||
### TC-NET-1002: DMA 边界(4096 字节)
|
||||
|
||||
@@ -1027,7 +1027,7 @@ IDLE → ACCEPT → [SEND: 分块发 → DONE] / [RECV: 分块收+校验 → DON
|
||||
| **标题** | 发送 4096 字节(等于 SPI 最大载荷,填满单次 DMA) |
|
||||
| **测试步骤** | MCU 发 4096B → 等待回显 → 验证 |
|
||||
| **通过标准** | 4096B 完全匹配 |
|
||||
| **覆盖原则** | DP-04 |
|
||||
| **覆盖原则** | DMA 边界安全 |
|
||||
|
||||
### TC-NET-1003: DMA 边界 +1(4097 字节)
|
||||
|
||||
@@ -1039,7 +1039,7 @@ IDLE → ACCEPT → [SEND: 分块发 → DONE] / [RECV: 分块收+校验 → DON
|
||||
| **标题** | 发送 4097 字节(超过 SPI 最大载荷,自动拆两次 DMA:4096+1) |
|
||||
| **测试步骤** | MCU 发 4097B → `net_send_locked` 自动拆 4096+1 → 等待回显 → 验证 |
|
||||
| **通过标准** | 4097B 完全匹配,两次 DMA 无缝衔接 |
|
||||
| **覆盖原则** | DP-04 |
|
||||
| **覆盖原则** | DMA 边界安全 |
|
||||
|
||||
### TC-NET-1004: 零长度收发
|
||||
|
||||
@@ -1078,7 +1078,7 @@ IDLE → ACCEPT → [SEND: 分块发 → DONE] / [RECV: 分块收+校验 → DON
|
||||
|
||||
## 12. 阶段 11:KeepAlive 超时断开
|
||||
|
||||
| 阶段 ID | TM-PHY-11 |
|
||||
| 阶段 | 阶段 11 |
|
||||
|---------|-----------|
|
||||
| **类型** | PC 配合,netTask 运行 |
|
||||
| **耗时** | ~1.5–2 分钟(连接+网卡禁用后实测判死 18~31s,加恢复重连;芯片定时语义以实测为准,见 E11/E13) |
|
||||
@@ -1170,43 +1170,43 @@ WAIT_CLOSE 阶段已内置二段补发(只补一次),生产 net 层则靠
|
||||
|
||||
| 阶段 | TC ID | 优先级 | 类型 | 状态 |
|
||||
|------|-------|--------|------|------|
|
||||
| TM-PHY-01 | TC-NET-101 | P0 | 功能测试 | ✅ |
|
||||
| TM-PHY-01 | TC-NET-102 | P1 | 功能测试 | ✅ 由阶段 1 第 6 项覆盖(`test/board/ch395f_test_task.c` 的 `ch395f_get_glob_int_status_all()` 双读断言);原条目在 2026-08-22 重构中删除、本汇总行未同步 → 2026-10-21 核对补注 |
|
||||
| TM-PHY-02 | TC-NET-201 | P0 | 功能测试 | ✅ |
|
||||
| TM-PHY-02 | TC-NET-202 | P0 | 恢复测试 | ✅ |
|
||||
| TM-PHY-02 | TC-NET-203 | P1 | 负向测试 | ✅ |
|
||||
| TM-PHY-03 | TC-NET-301 | P0 | 功能测试 | ✅ |
|
||||
| TM-PHY-03 | TC-NET-302 | P1 | 合规测试 | ✅ |
|
||||
| TM-PHY-04 | TC-NET-401 | P0 | 功能测试 | ✅ |
|
||||
| TM-PHY-04 | TC-NET-402 | P1 | 功能测试 | ✅ |
|
||||
| TM-PHY-05 | TC-NET-501 | P0 | 功能测试 | ✅ |
|
||||
| TM-PHY-05 | TC-NET-502 | P1 | 合规测试 | ✅ |
|
||||
| TM-PHY-06 | TC-NET-601 | P0 | 功能测试 | ✅ |
|
||||
| TM-PHY-06 | TC-NET-602 | P0 | 功能测试 | ✅ |
|
||||
| TM-PHY-06 | TC-NET-603 | P0 | 边界测试 | ✅ |
|
||||
| TM-PHY-06 | TC-NET-604 | P0 | 边界测试 | ✅ |
|
||||
| TM-PHY-06 | TC-NET-605 | P0 | 恢复测试 | ✅ |
|
||||
| TM-PHY-06 | TC-NET-606 | P1 | 恢复测试 | ✅ |
|
||||
| TM-PHY-07 | TC-NET-701 | P0 | 功能测试 | ✅ |
|
||||
| TM-PHY-07 | TC-NET-702 | P0 | 恢复测试 | ✅ |
|
||||
| TM-PHY-07 | TC-NET-703 | P1 | 负向测试 | ✅ |
|
||||
| TM-PHY-07 | TC-NET-704 | P0 | 并发测试 | ✅ |
|
||||
| TM-PHY-08 | TC-NET-801 | P0 | 文件发送 | ✅ |
|
||||
| TM-PHY-08 | TC-NET-802 | P0 | 文件接收 | 🟡 |
|
||||
| TM-PHY-08 | TC-NET-803 | P1 | 回显/压力 | 🟡 |
|
||||
| TM-PHY-09 | TC-NET-901 | P0 | 功能测试 | 🟡 |
|
||||
| TM-PHY-09 | TC-NET-902 | P1 | 负向测试 | 🟡 |
|
||||
| TM-PHY-10 | TC-NET-1001 | P0 | 边界测试 | 🟡 |
|
||||
| TM-PHY-10 | TC-NET-1002 | P0 | 边界测试 | 🟡 |
|
||||
| TM-PHY-10 | TC-NET-1003 | P0 | 边界测试 | 🟡 |
|
||||
| TM-PHY-10 | TC-NET-1004 | P1 | 负向测试 | 🟡 |
|
||||
| TM-PHY-10 | TC-NET-1005 | P1 | 压力测试 | 🟡 |
|
||||
| TM-PHY-10 | TC-NET-1006 | P1 | 稳定性测试 | 🟡 |
|
||||
| TM-PHY-11 | TC-NET-1101 | P1 | 功能测试 | 🟡 |
|
||||
| TM-PHY-15 | TC-NET-1501 | P0 | 状态回读/二段关闭 | ✅ |
|
||||
| TM-PHY-15 | TC-NET-1502 | P0 | 复位状态机 | ✅ |
|
||||
| TM-PHY-15 | TC-NET-1502b | P1 | LISTEN 态复位 | ✅ |
|
||||
| TM-PHY-15 | TC-NET-1503 | P1 | 链路缓存/事件护栏 | ✅ |
|
||||
| 阶段 1 | TC-NET-101 | P0 | 功能测试 | ✅ |
|
||||
| 阶段 1 | TC-NET-102 | P1 | 功能测试 | ✅ 由阶段 1 第 6 项覆盖(`test/board/ch395f_test_task.c` 的 `ch395f_get_glob_int_status_all()` 双读断言);原条目在 2026-08-22 重构中删除、本汇总行未同步 → 2026-10-21 核对补注 |
|
||||
| 阶段 2 | TC-NET-201 | P0 | 功能测试 | ✅ |
|
||||
| 阶段 2 | TC-NET-202 | P0 | 恢复测试 | ✅ |
|
||||
| 阶段 2 | TC-NET-203 | P1 | 负向测试 | ✅ |
|
||||
| 阶段 3 | TC-NET-301 | P0 | 功能测试 | ✅ |
|
||||
| 阶段 3 | TC-NET-302 | P1 | 合规测试 | ✅ |
|
||||
| 阶段 4 | TC-NET-401 | P0 | 功能测试 | ✅ |
|
||||
| 阶段 4 | TC-NET-402 | P1 | 功能测试 | ✅ |
|
||||
| 阶段 5 | TC-NET-501 | P0 | 功能测试 | ✅ |
|
||||
| 阶段 5 | TC-NET-502 | P1 | 合规测试 | ✅ |
|
||||
| 阶段 6 | TC-NET-601 | P0 | 功能测试 | ✅ |
|
||||
| 阶段 6 | TC-NET-602 | P0 | 功能测试 | ✅ |
|
||||
| 阶段 6 | TC-NET-603 | P0 | 边界测试 | ✅ |
|
||||
| 阶段 6 | TC-NET-604 | P0 | 边界测试 | ✅ |
|
||||
| 阶段 6 | TC-NET-605 | P0 | 恢复测试 | ✅ |
|
||||
| 阶段 6 | TC-NET-606 | P1 | 恢复测试 | ✅ |
|
||||
| 阶段 7 | TC-NET-701 | P0 | 功能测试 | ✅ |
|
||||
| 阶段 7 | TC-NET-702 | P0 | 恢复测试 | ✅ |
|
||||
| 阶段 7 | TC-NET-703 | P1 | 负向测试 | ✅ |
|
||||
| 阶段 7 | TC-NET-704 | P0 | 并发测试 | ✅ |
|
||||
| 阶段 8 | TC-NET-801 | P0 | 文件发送 | ✅ |
|
||||
| 阶段 8 | TC-NET-802 | P0 | 文件接收 | 🟡 |
|
||||
| 阶段 8 | TC-NET-803 | P1 | 回显/压力 | 🟡 |
|
||||
| 阶段 9 | TC-NET-901 | P0 | 功能测试 | 🟡 |
|
||||
| 阶段 9 | TC-NET-902 | P1 | 负向测试 | 🟡 |
|
||||
| 阶段 10 | TC-NET-1001 | P0 | 边界测试 | 🟡 |
|
||||
| 阶段 10 | TC-NET-1002 | P0 | 边界测试 | 🟡 |
|
||||
| 阶段 10 | TC-NET-1003 | P0 | 边界测试 | 🟡 |
|
||||
| 阶段 10 | TC-NET-1004 | P1 | 负向测试 | 🟡 |
|
||||
| 阶段 10 | TC-NET-1005 | P1 | 压力测试 | 🟡 |
|
||||
| 阶段 10 | TC-NET-1006 | P1 | 稳定性测试 | 🟡 |
|
||||
| 阶段 11 | TC-NET-1101 | P1 | 功能测试 | 🟡 |
|
||||
| 阶段 15 | TC-NET-1501 | P0 | 状态回读/二段关闭 | ✅ |
|
||||
| 阶段 15 | TC-NET-1502 | P0 | 复位状态机 | ✅ |
|
||||
| 阶段 15 | TC-NET-1502b | P1 | LISTEN 态复位 | ✅ |
|
||||
| 阶段 15 | TC-NET-1503 | P1 | 链路缓存/事件护栏 | ✅ |
|
||||
|
||||
✅ = 已实现并验证 | 🟡 = 已实现待验证 | 🟠 = 待实现
|
||||
|
||||
@@ -1214,10 +1214,10 @@ WAIT_CLOSE 阶段已内置二段补发(只补一次),生产 net 层则靠
|
||||
|
||||
| 原则 | 覆盖用例 |
|
||||
|------|----------|
|
||||
| DP-01:单 socket 生命周期 | TC-NET-202, 203, 601, 605, 606, 701, 702, 703, 704, 801, 802, 901, 902, 1001~1006 |
|
||||
| DP-02:中断即读即清 | TC-NET-101, 102, 501, 502, 901 |
|
||||
| DP-03:消息队列线程安全 | TC-NET-301, 302, 401 |
|
||||
| DP-04:DMA 边界安全 | TC-NET-501, 502, 603, 604, 801, 802, 1001~1005 |
|
||||
| 单 socket 生命周期 | TC-NET-202, 203, 601, 605, 606, 701, 702, 703, 704, 801, 802, 901, 902, 1001~1006 |
|
||||
| 中断即读即清 | TC-NET-101, 102, 501, 502, 901 |
|
||||
| 消息队列线程安全 | TC-NET-301, 302, 401 |
|
||||
| DMA 边界安全 | TC-NET-501, 502, 603, 604, 801, 802, 1001~1005 |
|
||||
|
||||
## 附录 D:CH395F 边界条件速查
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
> 全部公开/私有函数,并向上延伸到 FTL(`nand_ftl.c`)与 FatFS diskio。
|
||||
> 详细芯片行为见 `docs/芯片手册/GD5F2GQ5UExxG.md`,已知陷阱见 `docs/问题记录/GD5F2GQ5UE_Trap_Records.md`。
|
||||
>
|
||||
> **2026-10-03 错误通道硬化**(E-10/E-42/E-53/E-54/E-56/E-57,见 `问题记录/GD5F2GQ5UE_Trap_Records.md` TRAP-GD5F-06):
|
||||
> **2026-10-03 错误通道硬化**(见 `问题记录/GD5F2GQ5UE_Trap_Records.md` TRAP-GD5F-06):
|
||||
> `wait_busy` 区分"超时"(`GD5F_WAIT_EXPIRED`,旧名 `GD5F_BUSY_TIMEOUT`)与"真故障"(`GD5F_ERROR`)、`bbt_scan` 失败**放弃持久化**、
|
||||
> init 全链路检查返回值 + **回读 B0h 校验 ECC 使能**、`read` 的 raw 契约文档化、公开 API 统一 `int32_t`。
|
||||
> 套件回归 `=== GD5F2GQ5UE Tests: 16/16 PASSED (failed=0) ===`。
|
||||
@@ -66,7 +66,7 @@ ECC 状态(`ECCS1:ECCS0`):`00`=无错;`01/10/11`=纠正 1/2/3 bit;`10`
|
||||
> **破坏性用例开关(2026-09-21 新增,默认关闭)**:`test_config.h` 的 `ENABLE_DESTRUCTIVE_TESTS`
|
||||
> 控制所有**会改变设备持久状态**的用例——写/擦 NAND、`nand_ftl_format`、FatFS 建文件写文件、
|
||||
> 向 BBT 持久化坏块标记(永久减少可用容量)。关闭时为**只读模式**,可随时在在用设备上跑;
|
||||
> 打开后才编译并运行 PHASE3~9,以及 PHASE2 的 TC-206/207、PHASE10 的 TC-1003/1004。
|
||||
> 打开后才编译并运行 PHASE3~9,以及 PHASE2 的 TC-GD5F-206/207、PHASE10 的 TC-GD5F-1003/1004。
|
||||
> 依据:2026-09-21 实测一轮破坏性 GD5F 运行即让 dhara 多记一个坏块(容量 95248 → 95200;
|
||||
> dhara 把该计数持久化在 journal checkpoint 头里,普通恢复模式清不掉——见下文容量恢复说明),
|
||||
> 故破坏性用例只在**产品首次上电/产线首启**或明确需要时开启。
|
||||
@@ -82,7 +82,7 @@ ECC 状态(`ECCS1:ECCS0`):`00`=无错;`01/10/11`=纠正 1/2/3 bit;`10`
|
||||
|
||||
执行顺序(由 `gd5f_test_run()` 按阶段串行,与函数依赖一致):
|
||||
|
||||
- **只读(默认)**:`init/read_id/reset` → `BBT(读取与 RAM 内标记)` → `DMA 守卫读方向(TC-704)` → `边界条件(越界 / size=0)`
|
||||
- **只读(默认)**:`init/read_id/reset` → `BBT(读取与 RAM 内标记)` → `DMA 守卫读方向(TC-GD5F-704)` → `边界条件(越界 / size=0)`
|
||||
- **破坏性(开关打开时插入其间)**:`页读写` → `块擦除` → `ECC` → `SPI 原语` → `DMA 边界(701~703、705)` → `FTL(含 format)` → `FatFS`
|
||||
|
||||
开机横幅会明确打印本次模式:`mode: READ-ONLY (...)` 或 `mode: DESTRUCTIVE (...)`。
|
||||
@@ -759,7 +759,7 @@ ECC 状态(`ECCS1:ECCS0`):`00`=无错;`01/10/11`=纠正 1/2/3 bit;`10`
|
||||
| TC-STORAGE-04 | BBT 重建 + 重新格式化(恢复) | P1 | 受 `ENABLE_STORAGE_RECOVERY_TESTS` 控制(默认关) |
|
||||
|
||||
> 当前实测(2026-09-21,`ENABLE_DESTRUCTIVE_TESTS` 关闭 / 打开两种配置):
|
||||
> 只读模式 `=== GD5F2GQ5UE Tests: 16/16 PASSED (failed=0) ===`(PHASE1/2/7 的 TC-704/10,无任何写操作,
|
||||
> 只读模式 `=== GD5F2GQ5UE Tests: 16/16 PASSED (failed=0) ===`(PHASE1/2/7 那批只读阶段用例,含 704 那条只读守卫项;无任何写操作,
|
||||
> 卷内容与容量均不变);破坏性模式 `=== GD5F2GQ5UE Tests: 68/68 PASSED (failed=0) ===`(全部阶段)。
|
||||
> `TEST_SUITE_STORAGE` 只读模式实测 `=== Storage Tests: 3/3 PASSED (failed=0) ===`(mount + TC-STORAGE-05,
|
||||
> 卷内容与容量不变);破坏性模式为全量集成用例(2026-09-20 实测 **20/20 PASSED**,含 TC-STORAGE-01/02/03/05/06)。
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
> **版本**:v1.1(需求 + 设计 + 实施记录)
|
||||
> **日期**:2026-09-15
|
||||
> **状态**:**已实施**(S1–S6 完成;本机验收 A1–A5/A8 通过,A6/A7 正路径待 CH340 硬件接入后补验)
|
||||
> **状态**:**已实施**(步骤 1–6 完成;本机验收 A1–A5/A8 通过,A6/A7 正路径待 CH340 硬件接入后补验)
|
||||
> **关联文档**:`串口助手使用指南.md`(命令用法/工作流/排障) · `自动化测试流程.md` · `serial-assistant` skill(命令速查/陷阱) · `.serialtest/config.json`(端口单一配置源,2026-10-10 由 `.opencode/serial_config.json` 迁入)
|
||||
> **取代**:`serial-mcp-server_串口调试.md`(实施时删除,工具历史并入本文 §12)
|
||||
|
||||
@@ -237,12 +237,12 @@ flowchart LR
|
||||
|
||||
| # | 步骤 | 产物 | 验证 |
|
||||
|---|---|---|---|
|
||||
| S1 | `requirements.txt` 增 pyserial + `.venv` 安装 | requirements.txt | `pip show pyserial` 有版本 ✅ |
|
||||
| S2 | daemon 核心:HTTP 服务 + 串口读线程 + 行日志写(含 clear/截头/DTR 策略) | `.dsh/skills/serial-assistant/scripts/serial_tool.py`(daemon 部分) | `start→status→send→stop` 手动走通 ✅ |
|
||||
| S3 | CLI 全子命令 + 自动拉起 + 超时契约 + `selftest` | serial_tool.py(CLI 部分) | `selftest` 0=PASS + 命令走查 ✅ |
|
||||
| S4 | 验收 A1–A6、A8 | 测试通过记录 | A1–A5/A8 PASS ✅(本机无 CH340,A6 待硬件) |
|
||||
| S5 | @test 集成:`run_boot_test.py` 采集步改写 + 参数收敛 | run_boot_test.py | 负路径(端口缺失→exit 2)+ 假烧录全链路 + verify 正/负判定 ✅;**A7 正路径待 CH340 接入** |
|
||||
| S6 | 文档/配置迁移(§7.2 全清单) | docs + 配置 | 全库 grep 无 serial-mcp-server 残留引用(本文 §12 工具历史除外) ✅ |
|
||||
| 步骤 1 | `requirements.txt` 增 pyserial + `.venv` 安装 | requirements.txt | `pip show pyserial` 有版本 ✅ |
|
||||
| 步骤 2 | daemon 核心:HTTP 服务 + 串口读线程 + 行日志写(含 clear/截头/DTR 策略) | `.dsh/skills/serial-assistant/scripts/serial_tool.py`(daemon 部分) | `start→status→send→stop` 手动走通 ✅ |
|
||||
| 步骤 3 | CLI 全子命令 + 自动拉起 + 超时契约 + `selftest` | serial_tool.py(CLI 部分) | `selftest` 0=PASS + 命令走查 ✅ |
|
||||
| 步骤 4 | 验收 A1–A6、A8 | 测试通过记录 | A1–A5/A8 PASS ✅(本机无 CH340,A6 待硬件) |
|
||||
| 步骤 5 | @test 集成:`run_boot_test.py` 采集步改写 + 参数收敛 | run_boot_test.py | 负路径(端口缺失→exit 2)+ 假烧录全链路 + verify 正/负判定 ✅;**A7 正路径待 CH340 接入** |
|
||||
| 步骤 6 | 文档/配置迁移(§7.2 全清单) | docs + 配置 | 全库 grep 无 serial-mcp-server 残留引用(本文 §12 工具历史除外) ✅ |
|
||||
|
||||
提交:全部完成后单提交(pre-commit 门禁;纯宿主侧 Python,不涉及 Keil 构建)。
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
保护下运行**,而且 `gd5f_check_ecc()` 在 ECC 关闭时恒读"无 ECC 错误",整条链不会再有任何信号。
|
||||
|
||||
- 现在(2026-10-23 改)关 ECC 失败会**立即中止**(此刻 ECC 仍开着,是安全侧;带着 ECC 去扫 spare 反而会把
|
||||
厂标好块误判成坏块,"重建 BBT"变成制造坏块),重开失败则复用 init 的 **E-10** 做法**回读 B0h 校验
|
||||
厂标好块误判成坏块,"重建 BBT"变成制造坏块),重开失败则复用 init 的做法**回读 B0h 校验
|
||||
`ECC_EN` 位**,"写了但没生效"与写失败同罪,一律返回错误。
|
||||
- **运维判据**:串口/`run.log` 里出现 `BBT rebuild: ECC restore FAILED` 或 `ECC not enabled (B0h=…)`
|
||||
→ 本次恢复**不算完成**,设备处于无 ECC 保护态,必须**断电重启**让 init 重走一遍并使回读校验通过,
|
||||
|
||||
+37
-36
@@ -23,10 +23,10 @@
|
||||
|---|---|---|---|
|
||||
| **步骤 1** | 环境预检(P0-A,每次上台架必跑) | 常设 | §2 |
|
||||
| **步骤 2** | 产品 `@test` 闭环 + 自检结果判定(P0-B) | ✅ 已闭环 | §3 |
|
||||
| **步骤 3** | IWDG 故障注入 V2/V4 + 长跑 V5(P1-A / N-03) | ✅ 已闭环 | §4 |
|
||||
| **步骤 3** | IWDG 故障注入 V2/V4 + 长跑 V5(P1-A) | ✅ 已闭环 | §4 |
|
||||
| **步骤 4** | 堆低水位告警实测(P1-B / S11) | ✅ 已闭环 | §5 |
|
||||
| **步骤 5** | GD5F 错误通道回归(P2-A / S9) | ✅ 已闭环 | §6 |
|
||||
| **步骤 6** | 网络稳定性与基线重锁(P2-B / P1-8 + N-2/N-3) | ◐ 部分闭环(7.1/7.2 ✅;7.3 待 PC peer) | §7 |
|
||||
| **步骤 6** | 网络稳定性与基线重锁(P2-B / 日志静默观察项 + L5 队列往返基线待重验) | ◐ 部分闭环(7.1/7.2 ✅;7.3 待 PC peer) | §7 |
|
||||
| **步骤 7** | 工程卫生(P3 / S5 + S4 + 待核实项) | ✅ 已闭环 | §8 |
|
||||
|
||||
> **每步出口**:`@build` 0/0 → 一轮 `@test` PASS → ST-LINK 全片回读 `No difference found` →
|
||||
@@ -45,7 +45,7 @@
|
||||
| A1 | 工作区干净 | `git status --short` | 无输出(或有明确待提交项) |
|
||||
| A2 | 产品构建 0/0 | `& '.venv\Scripts\python.exe' .dsh\skills\keil-build\scripts\keil_build.py` | 末行 `BUILD_OK: 0 errors, 0 warnings` |
|
||||
| A3 | 构建产物为**产品态** | 检查 `test/board/test_config.h` L30-33 | 四个 `TEST_SUITE_*` **全部注释** |
|
||||
| A4 | `.map` 非测试态 | 看 `MDK-ARM/STM32F407-Demo/STM32F407-Demo.map` 的 `ER_IROM1` | 产品态基线随已接受的修复增长:262,100(初版)→ 262,836 B(10-02 round 1~6)→ 264,284 B(round 7~9)→ **264,936 B(当前,含 A2/A3/A4 补码)**;明显阶跃 ≈3.7KB 及以上(10-02 实测产品 262,836 → 套件 266,540)= 停在套件态 → 重跑 A2 |
|
||||
| A4 | `.map` 非测试态 | 看 `MDK-ARM/STM32F407-Demo/STM32F407-Demo.map` 的 `ER_IROM1` | 产品态基线随已接受的修复增长:262,100(初版)→ 262,836 B(10-02 第 1~6 轮台架)→ 264,284 B(第 7~9 轮台架)→ **264,936 B(当前,含 A2/A3/A4 补码)**;明显阶跃 ≈3.7KB 及以上(10-02 实测产品 262,836 → 套件 266,540)= 停在套件态 → 重跑 A2 |
|
||||
| A5 | 全量静态门禁 | `pre-commit run --all-files` | **17/17 Passed**(2026-10-03 实测;含新增 S5 `test-cppcheck`) |
|
||||
| A6 | ST-LINK 探针可见 | `& '.venv\Scripts\python.exe' .dsh\skills\stlink-flash\scripts\stlink_flash.py list`(CLI 经 `DTU_STLINK_CLI` / PATH 解析) | 列出探针 SN `0B250D12A218303030303032` |
|
||||
| A7 | 串口端口正确 | 检查 `.serialtest/config.json` 的 `portName` | 端口单一配置源 = 此文件(当前 COM6,2026-09-21 台架重插后由 COM7 变更);变更后先杀旧 daemon 再 `open` |
|
||||
@@ -97,7 +97,7 @@
|
||||
|
||||
---
|
||||
|
||||
## 4. 步骤 3:IWDG 故障注入与长跑(P1-A,N-03 收尾) · ✅ 已闭环
|
||||
## 4. 步骤 3:IWDG 故障注入与长跑(P1-A 收尾) · ✅ 已闭环
|
||||
|
||||
> **2026-10-03 台架结论**(实施细节与证据见 `子系统设计/看门狗设计说明.md` 变更记录):
|
||||
> V2/V4/V5 三用例全部通过——V2(任务饿死)声明 stall 后 ≤2.5s `reset cause: IWDG`;V4(关中断死循环)每 ~4.9s 稳定 IWDG 复位(IWDG 独立于中断);V5(30 min 真实负载)**120/120 次 FTP 传输全 PASS、零 IWDG 复位**。
|
||||
@@ -186,11 +186,11 @@ $cli = if ($env:DTU_STLINK_CLI) { $env:DTU_STLINK_CLI } else { (Get-Command ST-L
|
||||
|
||||
## 6. 步骤 5:GD5F 错误通道统一(P2-A,S9 = 上游 C2) · ✅ 已闭环
|
||||
|
||||
> **2026-10-03 台架结论**:四要素(分类/透传/分级/留痕)+ 返回类型统一 `int32_t` 已落地(E-10/E-42/E-53/E-54/E-56/E-57 全部销项;历史编号,属主文档已删除)。
|
||||
> **2026-10-03 台架结论**:四要素(分类/透传/分级/留痕)+ 返回类型统一 `int32_t` 已落地。
|
||||
> 套件回归:`test/run_all_suites.py --suites gd5f` → **`=== GD5F2GQ5UE Tests: 16/16 PASSED (failed=0) ===`**(只读模式,4 个破坏性用例按设计跳过);编排器 `[GD5F] -> PASS`。
|
||||
> **顺带修复(编排器缺陷,非本次代码引入)**:`run_all_suites.py` 原对所有套件统一 `--forbidden "HardFault;assert;[ERR]"`,而 GD5F 的 `TC-GD5F-704`(CCM 非 DMA 可达缓冲)会**预期**打出 `[ERR][NAND] RX DMA buffer not DMA-reachable ... fallback poll`(用例 PASS)→ GD5F 套件**永远被判 FAIL**(自 `2055de0` 起)。按 `verify_log.py` 的说明改为**按套件覆盖 `--forbidden`**(GD5F = `HardFault;assert`),修复后 PASS。
|
||||
|
||||
> **来源**:第二档 #1(E-10/E-42/E-53/E-54/E-56/E-57,历史编号);
|
||||
> **来源**:第二档 #1;
|
||||
> `docs/产品需求/产品需求设计文档.md` §7.1(错误码通道四要素骨架,设计基线)。
|
||||
|
||||
**现状证据**:`ch395f.c`(1330 行) 与 `gd5f2gq5ue.c`(1496 行) 是同代驱动,但**只有 CH395F**
|
||||
@@ -198,13 +198,13 @@ $cli = if ($env:DTU_STLINK_CLI) { $env:DTU_STLINK_CLI } else { (Get-Command ST-L
|
||||
|
||||
**统一错误通道四要素**(以 CH395F 为范式):
|
||||
|
||||
| 要素 | 内容 | 对应缺陷 |
|
||||
|---|---|---|
|
||||
| ① **分类** | `wait_busy` 区分「超时 / 真故障 / 参数错」——不得混为一个返回码 | E-53 |
|
||||
| ② **透传** | 底层错误码逐层上报,不吞不猜(禁 `(void)ret`) | E-10 / E-42 |
|
||||
| ③ **分级** | 可恢复(重试)/ 不可恢复(上报自检 + 降级)显式判定 | E-54 / E-56 |
|
||||
| ④ **留痕** | 不可恢复项写 syslog selftest;可恢复项计数并在 UI/日志可见 | E-57 |
|
||||
| — | 返回类型统一 `int32_t` | E-57 |
|
||||
| 要素 | 内容 |
|
||||
|---|---|
|
||||
| ① **分类** | `wait_busy` 区分「超时 / 真故障 / 参数错」——不得混为一个返回码 |
|
||||
| ② **透传** | 底层错误码逐层上报,不吞不猜(禁 `(void)ret`) |
|
||||
| ③ **分级** | 可恢复(重试)/ 不可恢复(上报自检 + 降级)显式判定 |
|
||||
| ④ **留痕** | 不可恢复项写 syslog selftest;可恢复项计数并在 UI/日志可见 |
|
||||
| — | 返回类型统一 `int32_t` |
|
||||
|
||||
**实施顺序**(数据安全优先):
|
||||
1. 先建**分类函数**(`gd5f_wait_busy` 内检查三次 HAL 调用)——所有下游判断的基础;
|
||||
@@ -216,7 +216,7 @@ $cli = if ($env:DTU_STLINK_CLI) { $env:DTU_STLINK_CLI } else { (Get-Command ST-L
|
||||
7. **RAM 预算**:新增错误分支**不得引入新的大缓冲**(先跑 `ram_report.py` 核算)。
|
||||
|
||||
**判据**:
|
||||
- **E-10 / E-42 / E-53 / E-54 / E-56 / E-57 全部销项**;
|
||||
- **错误通道审计项全部销项**;
|
||||
- **GD5F 套件回归 PASS**:
|
||||
```bash
|
||||
# 套件回归(需实机)
|
||||
@@ -236,7 +236,7 @@ $cli = if ($env:DTU_STLINK_CLI) { $env:DTU_STLINK_CLI } else { (Get-Command ST-L
|
||||
|
||||
## 7. 步骤 6:网络稳定性与基线重锁(P2-B) · ◐ 部分闭环(7.1/7.2 已闭环;7.3 待 PC peer)
|
||||
|
||||
### 7.1 P1-8 网络重建失败恢复(A2;实施细节见 `网络/Net层阻塞模型架构设计.md`,状态见 §10) · ✅ 正常路径已闭环
|
||||
### 7.1 网络重建失败恢复(A2;实施细节见 `网络/Net层阻塞模型架构设计.md`,状态见 §10) · ✅ 正常路径已闭环
|
||||
|
||||
**判据**:拔插网线/改 IP 触发重建后——
|
||||
- 失败路径**写 syslog 自检**(不再零日志);
|
||||
@@ -249,12 +249,12 @@ $cli = if ($env:DTU_STLINK_CLI) { $env:DTU_STLINK_CLI } else { (Get-Command ST-L
|
||||
- **正常路径 ✅**:V5 长跑(30 min,FTP 512 KB 上/下传)**120/120 PASS、零 IWDG 复位**,
|
||||
网络重建后的 FTP/time_sync 服务据代次号重建监听、功能正常(证据 `/tmp/v5_soak_serial_20261003.log`)。
|
||||
- **负向路径(拔线/芯片级 `net_init` 失败)**受**台架拓扑**限制(CH395↔交换机,
|
||||
拔交换机侧线缆链路仍 UP;芯片级失败需 SPI 故障注入)→ 已登记 `docs/任务规划/登记簿.md` **N-16**
|
||||
拔交换机侧线缆链路仍 UP;芯片级失败需 SPI 故障注入)→ 已登记 `docs/任务规划/登记簿.md` 条目「网络负向场景台架验证」
|
||||
(① PHY 拔线负向 ② A2 `net_init` 失败分支 ③ A4 短写压测),需专项窗口。
|
||||
|
||||
### 7.2 N-2:49s 全系统日志静默复现与定位 · ✅ 判据②已满足 / 判据①未复现
|
||||
### 7.2 日志静默观察项:49s 全系统日志静默复现与定位 · ✅ 判据②已满足 / 判据①未复现
|
||||
|
||||
**现状证据**(登记簿 N-2):2026-09-22 台架实测,串口日志 **49s 无行**
|
||||
**现状证据**(登记簿条目「日志静默观察项」):2026-09-22 台架实测,串口日志 **49s 无行**
|
||||
(testTask/netTask/[STACK] 行全缺),期间 net 栈照常处理外部连接 → **日志管线停滞**,
|
||||
队列满后各任务日志行被丢;系统功能不受损。
|
||||
|
||||
@@ -268,15 +268,15 @@ $cli = if ($env:DTU_STLINK_CLI) { $env:DTU_STLINK_CLI } else { (Get-Command ST-L
|
||||
- **判据①(复现 49s 并定位卡点)→ 未复现**:对 V5 30 min 长跑日志(6031 条带时间戳行)
|
||||
做间隔分析,**最大静默 41s**(发生在**开机/烧录边界**,非运行期),**运行期无 49s 静默**。
|
||||
运行期 >10s 的静默共 24 处,**全部**为 ~28s,且**均落在 `e02_probe` 的 time_sync 30s
|
||||
挂起客户端窗口内**——与 **N-17** 同源(探针场景专属,非通用负载)。
|
||||
挂起客户端窗口内**——与「探针窗口心跳缺口」同源(探针场景专属,非通用负载)。
|
||||
- **结论**:49s 静默在当前固件 + V5 负载下**不复现**;可观测性缺口已由既有代码补齐。
|
||||
N-2 降级为**低风险观察项**(保留登记,若再现则借 `[ERR] CONSOLE dropped` 计数定位)。
|
||||
日志静默观察项降级为**低风险**(保留登记,若再现则借 `[ERR] CONSOLE dropped` 计数定位)。
|
||||
- **后续(2026-10-25,道F 批 2 合并评估)**:窗内静默的同源阻塞机制
|
||||
(`drop_conn` 同步占用 netTask 400-600ms)已随「登记式拆链」修复
|
||||
(`../网络/网络自愈架构设计.md` §4.6);N-2 × S8 合并评估已完成,结论与「无源 vs
|
||||
(`../网络/网络自愈架构设计.md` §4.6);日志静默观察项与日志单写者化的合并评估已完成,结论与「无源 vs
|
||||
真停滞」判别口径落 `../子系统设计/控制台单写者日志设计说明.md` 文末附录——
|
||||
再现静默先按三本账(`dbg_console_dropped/_tx_fault/_tx_timeout`)+ syslog 丢弃
|
||||
账对照定性,再决定是否开卡;销项条件 = N-17 修复版 V5 复跑(e02_probe + FTP
|
||||
账对照定性,再决定是否开卡;销项条件 = 探针窗口心跳缺口修复版 V5 复跑(e02_probe + FTP
|
||||
≥30 min)运行期 `task stall` 与真停滞嫌疑静默段双零(2026-10-25 v1.1 起
|
||||
`MISS start` 降级为诊断行不计销项——见下方判读工具与
|
||||
`../子系统设计/看门狗设计说明.md` §6.1)。
|
||||
@@ -299,7 +299,7 @@ $cli = if ($env:DTU_STLINK_CLI) { $env:DTU_STLINK_CLI } else { (Get-Command ST-L
|
||||
|
||||
**执行步骤**:长跑(§4.2 V5)期间周期性打点 + 对照 `CH395F` 无关的 SD2506 侧日志判别卡点。
|
||||
|
||||
### 7.3 N-3:L5 队列往返基线重验 · ⬜ 待 PC peer
|
||||
### 7.3 L5 队列往返基线待重验 · ⬜ 待 PC peer
|
||||
|
||||
**现状**:L5 基线(1223/988µs)属**分片时代**;L3 对该路径逐位不变 → 机制上无影响,
|
||||
但严格重锁需跑一轮 Phase 13(**需 PC peer**)。
|
||||
@@ -353,9 +353,10 @@ cppcheck --enable=warning --error-exitcode=1 test/ 2>&1 | tee test_cppcheck_base
|
||||
**判据**:一键列出双向差异清单;差异收敛后再考虑升为门禁。
|
||||
|
||||
**结论(✅ 已闭环,2026-10-03)**:`scripts/check_test_traceability.py` 已落地并跑通,
|
||||
**默认仅告警(exit 0)、不阻断提交**。当前输出 **30 处差异**(26 处"文档有、代码无" +
|
||||
4 处"代码有、文档无":`TC-GD5F-1100/1101/1102`、`TC-STORAGE-06`)。差异清单已收敛为
|
||||
可追踪项,后续按需补登记;**暂不升门禁**(与 §8.2 目标一致)。
|
||||
**默认仅告警(exit 0)、不阻断提交**。2026-10-26 重打:当前差异 **25 处**(文档有代码无 + 代码有文档无两向),
|
||||
另有约 1,486 处属"代码有该号、号旁写着人话意图",按「代码即属主登记处」放过——**弱于文档的保证**,
|
||||
对外举证仍需模块级说明。当年列出的孤儿号(GD5F 那三个 11xx、存储 06 号)已在 2026-10-26 清号批次
|
||||
里从代码侧删号收口。差异清单可追踪,后续按需补登记;**暂不升门禁**(与 §8.2 目标一致)。
|
||||
|
||||
### 8.3 待核实项:`TEST_SUITE_SELECTED` 未含 `TEST_SUITE_RTC` · ✅ 已核实(非缺陷)
|
||||
|
||||
@@ -397,7 +398,7 @@ CH395F / STORAGE / GD5F,未含 RTC;怀疑 RTC 构建下 `testTask` 不被创
|
||||
但正常 `f_close` 就会走到 `CTRL_SYNC`(FatFs `sync_fs` → `disk_ioctl` → `ftl_flush_cache`),
|
||||
所以**"写完即关"的路径(日志、配置保存)关文件即落盘,不必再"写另一个文件逼刷"**;会丢的
|
||||
只有**写事务进行中**掉电/硬复位(含 IWDG 误复位)里最后那笔未跨页的写(≤512 B)——
|
||||
FTP STOR 传输途中掉电就落在这一档(`N-14` 已登记;登记簿 N-22 于 2026-10-22 裁定暂不做,
|
||||
FTP STOR 传输途中掉电就落在这一档(已登记观察;「写回缓存空闲 flush」于 2026-10-22 裁定暂不做,
|
||||
缺的是"空闲/掉电前周期 flush",且本机无掉电检测硬件,掉电时点无法补救)。
|
||||
→ 排查写入丢失时**先看开机日志的 head/tail/epoch**(`Map head=… tail=… epoch=…`,
|
||||
纯内存字段、零 I/O):head 复位后倒退 = L1(resume 错);head 正常 = L2(缓存未刷)。
|
||||
@@ -446,14 +447,14 @@ CH395F / STORAGE / GD5F,未含 RTC;怀疑 RTC 构建下 `testTask` 不被创
|
||||
| 事项 | 状态 | 实施细节 / 证据所在 |
|
||||
|---|---|---|
|
||||
| **S7** 自检结果判定 | ✅ 已落地并投用 | `测试说明/自动化测试流程.md`;提交 `4a4cd29` |
|
||||
| **A1** P0-1 `cfg_file` 堆分配改造 | ✅ 已闭环(含真机持久化) | `子系统设计/配置文件设计说明.md`(实施 v1.11 + 2026-10-03 真机验证记录 + 2026-10-04 独立复跑记录) |
|
||||
| **A2** P1-8 网络重建失败恢复 | ✅ 已闭环(正常路径零回归;故障分支见 N-16) | `网络/Net层阻塞模型架构设计.md` |
|
||||
| **A3** E-34 CH395F 字节命令超时 | ✅ 已闭环(正常路径零回归;故障分支待专项窗口) | —(历史编号,属主文档已于 2026-10-15 删除) |
|
||||
| **A4** E-04 `remo_send` 返回值 | ✅ 已闭环(正常路径零回归;推流压测待专项窗口) | —(历史编号,属主文档已于 2026-10-15 删除) |
|
||||
| **A1** `cfg_file` 堆分配改造 | ✅ 已闭环(含真机持久化) | `子系统设计/配置文件设计说明.md`(实施 v1.11 + 2026-10-03 真机验证记录 + 2026-10-04 独立复跑记录) |
|
||||
| **A2** 网络重建失败恢复 | ✅ 已闭环(正常路径零回归;故障分支见「网络负向场景台架验证」) | `网络/Net层阻塞模型架构设计.md` |
|
||||
| **A3** CH395F 字节命令超时 | ✅ 已闭环(正常路径零回归;故障分支待专项窗口) | — |
|
||||
| **A4** `remo_send` 返回值 | ✅ 已闭环(正常路径零回归;推流压测待专项窗口) | — |
|
||||
| 2026-10-02 台架取证链(IWDG PR/RLR 错配 / dhara resume 回滚 / ORE 僵尸通道) | ✅ 已修 | `子系统设计/看门狗设计说明.md` 2026-10-02 变更记录 · `架构设计/STM32F4-Base存储架构说明.md` §5.4.1 · `子系统设计/控制台单写者日志设计说明.md` §12;提交 `930215f` |
|
||||
|
||||
> **真机判定汇总**(2026-10-03,本机 MCU,新固件全闭环 `@test` PASS 7/7):A1 ✅ PASS(含配置持久化);
|
||||
> A2/A3/A4 正常路径零回归;芯片级失败分支 / 短写 / 拔线负向场景记 `docs/任务规划/登记簿.md` N-16,待专项台架窗口。
|
||||
> A2/A3/A4 正常路径零回归;芯片级失败分支 / 短写 / 拔线负向场景记 `docs/任务规划/登记簿.md` 条目「网络负向场景台架验证」,待专项台架窗口。
|
||||
|
||||
---
|
||||
|
||||
@@ -464,14 +465,14 @@ CH395F / STORAGE / GD5F,未含 RTC;怀疑 RTC 构建下 `testTask` 不被创
|
||||
| S7 自检判定 | —(原复审项,已闭环 2026-10-02) | `测试说明/自动化测试流程.md`(参数已落地,`4a4cd29`) |
|
||||
| V2/V4/V5 | `子系统设计/看门狗设计说明.md` §7 验证记录 | `子系统设计/看门狗设计说明.md` 变更记录(2026-10-03) |
|
||||
| S11 堆告警 | —(原复审项,已闭环 2026-10-03) | `内存管理/RAM使用分析与优化方案.md`(基线更新) |
|
||||
| S9 GD5F | —(第二档 #1:历史编号 E-10/E-42/E-53/E-54/E-56/E-57,属主文档已删除) | `问题记录/GD5F2GQ5UE_Trap_Records.md`、`测试说明/GD5F2GQ5UE_Test_Guide.md` |
|
||||
| N-2 日志静默 | `docs/任务规划/登记簿.md` N-2 | `网络/Net层阻塞模型架构设计.md`(E-02 头阻塞,历史编号) |
|
||||
| P1-8 网络重建 | —(原台账项,已闭环 2026-10-02) | `网络/Net层阻塞模型架构设计.md` |
|
||||
| S9 GD5F | —(第二档 #1) | `问题记录/GD5F2GQ5UE_Trap_Records.md`、`测试说明/GD5F2GQ5UE_Test_Guide.md` |
|
||||
| 日志静默观察项 | `docs/任务规划/登记簿.md` | `网络/Net层阻塞模型架构设计.md`(头阻塞,历史编号) |
|
||||
| 网络重建 | —(原台账项,已闭环 2026-10-02) | `网络/Net层阻塞模型架构设计.md` |
|
||||
| S5/S4 | —(原复审项,已闭环 2026-10-03) | `测试说明/测试开发标准流程.md` |
|
||||
| 模拟器差距 | `测试说明/模拟器差距清单.md` §3 决策规则 | 本文为"需回真机"项的执行面 |
|
||||
|
||||
> **模拟器差距清单 §3 的六条"必须回真机"规则**决定"哪些改动**必须在本规划内验证——
|
||||
> 改动触及 `Drivers/BSP/` 寄存器时序 / H-1~H-7 硬件项 / L-2~L-4 / 网络重建并发 / 启动段 / 内存预算,
|
||||
> 改动触及 `Drivers/BSP/` 寄存器时序 / 模拟器差距清单的硬件专属项 / 配置变更检测与回调 / 网络重建并发 / 启动段 / 内存预算,
|
||||
> 一律在本文件找到对应批次。
|
||||
|
||||
---
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
> [`看门狗单元测试说明.md`](看门狗单元测试说明.md)(喂狗位图判定状态机)、
|
||||
> [`卷锁单元测试说明.md`](卷锁单元测试说明.md)(同批落地的姊妹篇)、
|
||||
> [`../子系统设计/看门狗设计说明.md`](../子系统设计/看门狗设计说明.md)(`required_mask` / 抽样窗 / 长耗时白名单)、
|
||||
> [`../任务规划/README.md`](../任务规划/README.md)(**N-17** 登记条目)、
|
||||
> 历史审计 **E-02**(netTask 头阻塞;属主文档已于 2026-10-15 删除,现状见 [`../网络/Net层阻塞模型架构设计.md`](../网络/Net层阻塞模型架构设计.md))
|
||||
> [`../任务规划/README.md`](../任务规划/README.md)(登记条目「探针窗口心跳缺口」)、
|
||||
> 历史审计(netTask 头阻塞;属主文档已于 2026-10-15 删除,现状见 [`../网络/Net层阻塞模型架构设计.md`](../网络/Net层阻塞模型架构设计.md))
|
||||
|
||||
---
|
||||
|
||||
@@ -23,12 +23,12 @@
|
||||
|
||||
本模块是**两件已知风险的当事方**,而两件风险的成因**全部是本模块的纯逻辑**:
|
||||
|
||||
1. **N-17(看门狗余量)**:登记簿 N-17 记录"time_sync 监听重建期间心跳缺口 800ms~1s,
|
||||
1. **探针窗口心跳缺口(看门狗余量)**:登记簿条目记录"time_sync 监听重建期间心跳缺口 800ms~1s,
|
||||
距 IWDG 最坏超时 1701ms 余量仅约 0.7s"。该缺口的每一段都由本模块产生——
|
||||
`time_sync_delay_fed()` 的**分片喂狗节奏**、监听重试退避(500 / 2000ms)、
|
||||
`accept` 轮询退避(200ms)、收尾延时(50ms),以及"就绪屏障等待态也要喂心跳"。
|
||||
真机上只能靠"跑起来看复位不复位"间接观察;主机侧可**逐片断言**心跳次数与片长。
|
||||
2. **E-02(头阻塞)**:旧实现用单次 30s 阻塞 `net_recv` 等时间包,独占 `netTask`,
|
||||
2. **头阻塞**:旧实现用单次 30s 阻塞 `net_recv` 等时间包,独占 `netTask`,
|
||||
使其余任务的网络操作整体停摆。现改为"分片有界读 + 总预算",本单测钉死其**分片语义**
|
||||
(单次等待片长恒 ≤ 50ms、总预算 30s 不因分片而改变)。
|
||||
|
||||
@@ -73,7 +73,7 @@ test/host/time_sync/time_sync_test.c
|
||||
看门狗抽样窗为 `WD_POLL_PERIOD_MS = 100ms`(`App/util/task_watchdog.c`)。若一次长等待
|
||||
(如 2000ms 退避)期间不喂心跳,或心跳节奏恰好滑过两个连续抽样窗,该任务就会被判"卡死"。
|
||||
故 `time_sync_delay_fed()` 把任意长等待切成 **≤ `TIME_SYNC_WAIT_SLICE_MS` = 50ms** 的短片,
|
||||
**每片前**喂一次心跳——语义等价于一次长延时,仅把心跳节奏钉在窗内(`round 8b` 消抖)。
|
||||
**每片前**喂一次心跳——语义等价于一次长延时,仅把心跳节奏钉在窗内(第 8b 轮台架消抖)。
|
||||
|
||||
**(二)`net_recv_to()` 的四态返回。**
|
||||
`time_sync_handle_conn()` 的重组循环依赖该契约:
|
||||
@@ -118,7 +118,7 @@ test/host/time_sync/time_sync_test.c
|
||||
| **门禁层级** | **L0.5 层**(介于 L0 静态门禁与 L1 板端套件之间):主机侧、秒级、纯逻辑 |
|
||||
| **pre-commit 钩子** | `time-sync-unit-test`(本地钩子,`.pre-commit-config.yaml` §7g) |
|
||||
| **汇总行** | `=== Time Sync Tests: 80/80 PASSED (failed=0) ===` |
|
||||
| **与板端测试的关系** | 互补:本单测保证**延时节奏与重组逻辑**符合设计;板端保证**真实 TCP 时序 + IWDG 不误复位**(N-17 的实际余量只能由板端长跑判定) |
|
||||
| **与板端测试的关系** | 互补:本单测保证**延时节奏与重组逻辑**符合设计;板端保证**真实 TCP 时序 + IWDG 不误复位**(该心跳缺口的实际余量只能由板端长跑判定) |
|
||||
|
||||
---
|
||||
|
||||
@@ -219,16 +219,16 @@ definition)规则静默合并为同一个对象**——于是 `task_wd_bind`
|
||||
CH395F 缓冲区边界。因此本单测能保证的是"**给定返回码序列,状态机反应正确**",
|
||||
**不能**保证真实链路上的时序行为——后者属板端与 PC 对端(`test/host/time_sync_server.py`)职责。
|
||||
|
||||
### 4.4 N-17 的实际余量仍由板端判定
|
||||
### 4.4 探针窗口心跳缺口的实际余量仍由板端判定
|
||||
|
||||
本单测把"每片喂心跳、片长 ≤ 50ms、退避值正确"这些**逻辑前提**钉死,但 N-17 关注的
|
||||
本单测把"每片喂心跳、片长 ≤ 50ms、退避值正确"这些**逻辑前提**钉死,但该缺口关注的
|
||||
是**端到端心跳缺口 vs IWDG 超时**——这还取决于真实调度延迟、`netTask` 排队时长、
|
||||
Flash 写耗时等主机侧无法建模的因素。故:
|
||||
|
||||
- 本单测 ✅ 保证"逻辑上不会出现超过 50ms 的**无喂狗**窗口";
|
||||
- 板端 ✅ 保证"实测缺口 + 调度抖动仍小于 1701ms"。
|
||||
|
||||
两者都过,N-17 才能闭环。
|
||||
两者都过,这个心跳缺口才能闭环。
|
||||
|
||||
---
|
||||
|
||||
|
||||
+28
-28
@@ -38,35 +38,35 @@
|
||||
|
||||
### 2.1 网络(`net_socket_sim.c` vs `net_socket.c`)
|
||||
|
||||
| # | 差距 | 模拟器行为 | 真机行为 | 影响 | 回归补测 |
|
||||
|---|---|---|---|---|---|
|
||||
| N-1 | **无 pending 机制** | `net_accept`/`net_send` 直接失败或阻塞于宿主 socket;无"挂起队列"概念 | 异步 TCP 状态机,`accept`/`send` 可处于 pending,由 `net_poll` 推进 | **E-06**(accept 轮询计时失真)、**E-20**(lftpd 控制通道 errno 分类)、**E-21**(timeSync errno 分级)等在模拟器上无法复现 | `@test` + FTP 套件;ACCEPT 决定不 pending 化(2026-10-15),不再专门建模 |
|
||||
| N-2 | **代次号恒为 0** | `net_get_generation()` 恒返 0(无"网络重建"概念) | 每次 `net_stack_bring_up` / 重配置递增,各 TCP 服务据此重建监听 | "网络重建后服务是否重建监听" 的逻辑**在模拟器上恒走同一分支** | `@test` 网络重配置用例(UI 改 IP 免重启生效) |
|
||||
| N-3 | ~~`net_recv_to` 缺失~~(**已消除**:sim 以 `GetTickCount64` + `Sleep(1)` 轮询兑现预算,含 -2 返回码与 `timeout_ms=0` 拒 INVAL);`net_process_messages` 仍缺失 | `net_recv_to` 已实现(包装层模拟);消息泵未实现(MCU 专属:CH395F 消息队列驱动) | 由 `netMsgQueue` 串行化 SPI 事务、支持毫秒级超时接收 | 依赖"消息泵"的上层逻辑在模拟器上**不可编译/不可运行**;带超时接收的**外部语义**已可双端共测,但预算兑现精度为 Sleep(1) 粒度 | 板端 CH395F / NET 套件 |
|
||||
| N-4 | **Socket 失效语义不同** | 以 `in_use` 判活(`net_socket_sim.c` 设计要点 4) | 监听 Socket 随客户端一同失效,由 net 层 `auto_relisten` + 对账形态③④自动重建(无手动 `net_relisten`) | "客户端断线 → 监听失效 → 重连" 的黏滞状态在模拟器上不出现 | `check_remo_sink.py` 覆盖重连;真机 `@test` |
|
||||
| N-5 | **单连接 backlog** | `NET_SIM_BACKLOG = 1` | CH395F 多 socket 并发 | 多客户端并发场景(FTP + 推流 + timeSync 同时)不可在模拟器验证 | 板端 NET 套件 + 台架并发场景 |
|
||||
| N-6 | **非阻塞语义模拟** | 创建即 `FIONBIO`(Winsock 句柄恒非阻塞,UI 主循环安全底线);**阻塞/非阻塞按控制块 `blocking` 属性在包装层模拟**(`net_recv` 无限轮询等待 / `net_recv_nb` / `NET_MSG_DONTWAIT` 立即 WOULDBLOCK,`net_setblocking` 双端同名) | 中断驱动 + 状态机 + 挂起 recv(等待睡任务通知,netTask 零占用) | 外部语义**对齐**(登记以说明"为何模拟器能测非阻塞路径与显式预算路径");内部挂起模型(N-1)仍不建模 | —— |
|
||||
| 差距 | 模拟器行为 | 真机行为 | 影响 | 回归补测 |
|
||||
|---|---|---|---|---|
|
||||
| **无 pending 机制** | `net_accept`/`net_send` 直接失败或阻塞于宿主 socket;无"挂起队列"概念 | 异步 TCP 状态机,`accept`/`send` 可处于 pending,由 `net_poll` 推进 | accept 轮询计时失真、lftpd 控制通道 errno 分类、timeSync errno 分级等在模拟器上无法复现 | `@test` + FTP 套件;ACCEPT 决定不 pending 化(2026-10-15),不再专门建模 |
|
||||
| **代次号恒为 0** | `net_get_generation()` 恒返 0(无"网络重建"概念) | 每次 `net_stack_bring_up` / 重配置递增,各 TCP 服务据此重建监听 | "网络重建后服务是否重建监听" 的逻辑**在模拟器上恒走同一分支** | `@test` 网络重配置用例(UI 改 IP 免重启生效) |
|
||||
| **消息泵缺失**:~~`net_recv_to` 缺失~~(**已消除**:sim 以 `GetTickCount64` + `Sleep(1)` 轮询兑现预算,含 -2 返回码与 `timeout_ms=0` 拒 INVAL);`net_process_messages` 仍缺失 | `net_recv_to` 已实现(包装层模拟);消息泵未实现(MCU 专属:CH395F 消息队列驱动) | 由 `netMsgQueue` 串行化 SPI 事务、支持毫秒级超时接收 | 依赖"消息泵"的上层逻辑在模拟器上**不可编译/不可运行**;带超时接收的**外部语义**已可双端共测,但预算兑现精度为 Sleep(1) 粒度 | 板端 CH395F / NET 套件 |
|
||||
| **Socket 失效语义不同** | 以 `in_use` 判活(`net_socket_sim.c` 设计要点 4) | 监听 Socket 随客户端一同失效,由 net 层 `auto_relisten` + 对账形态③④自动重建(无手动 `net_relisten`) | "客户端断线 → 监听失效 → 重连" 的黏滞状态在模拟器上不出现 | `check_remo_sink.py` 覆盖重连;真机 `@test` |
|
||||
| **单连接 backlog** | `NET_SIM_BACKLOG = 1` | CH395F 多 socket 并发 | 多客户端并发场景(FTP + 推流 + timeSync 同时)不可在模拟器验证 | 板端 NET 套件 + 台架并发场景 |
|
||||
| **非阻塞语义模拟** | 创建即 `FIONBIO`(Winsock 句柄恒非阻塞,UI 主循环安全底线);**阻塞/非阻塞按控制块 `blocking` 属性在包装层模拟**(`net_recv` 无限轮询等待 / `net_recv_nb` / `NET_MSG_DONTWAIT` 立即 WOULDBLOCK,`net_setblocking` 双端同名) | 中断驱动 + 状态机 + 挂起 recv(等待睡任务通知,netTask 零占用) | 外部语义**对齐**(登记以说明"为何模拟器能测非阻塞路径与显式预算路径");内部挂起模型(无 pending 机制)仍不建模 | —— |
|
||||
|
||||
### 2.2 日志与配置
|
||||
|
||||
| # | 差距 | 模拟器行为 | 真机行为 | 影响 | 回归补测 |
|
||||
|---|---|---|---|---|---|
|
||||
| L-1 | **控制台单写者无对应实现** | `simulator/dbg_log.h` 把 `DBG_*` 映射到 `printf`;**不编译** `console_log.c` | 单写者环形缓冲 + defaultTask 唯一发送 | `console_log` 的环形缓冲溢出/丢弃计数逻辑**模拟器测不到**;共享代码若误调 `console_log.h` 声明,模拟器链接失败(已被此约束捕获) | `@test` + 板端串口观测;`docs/子系统设计/控制台单写者日志设计说明.md` §4.1 |
|
||||
| L-2 | **mtime 粒度不同** | 宿主文件 mtime(**秒级**) | FAT 打包时间(`fdate<<16\|ftime`,**分钟级**) | `cfg_file_poll` 的 `(size, mtime)` 变更令牌在两端触发时机不同;分钟级粒度下的"同分钟内两次改动"在真机可能被判为无变化 | 板端 STORAGE 套件;`配置文件设计说明.md` §变更检测 |
|
||||
| L-3 | **无应用回调(空操作)** | 模拟器不注册段回调,`cfg_file_poll` 重载后回调为空 | 各段回调真正执行(如网络重配置) | "配置变更 → 触发回调 → 副作用"链路在模拟器上**只验证到写盘**,回调逻辑不覆盖 | `@test`(配置保存 → UI 生效) |
|
||||
| L-4 | **堆后端不同** | `cfg_store_alloc` = 宿主 `malloc`(堆余量以 MB 计) | FreeRTOS 堆(`configTOTAL_HEAP_SIZE` 48 KB,实测最低水位 ~4.8 KB) | **分配失败路径在模拟器上永不触发**——P0-1 类"KB 级分配必然返回 NULL"缺陷模拟器照不出来(`AGENTS.md` 已列为铁律) | 内存预算门禁 + 真机 `[HEAP]` 水位告警(S11) |
|
||||
| 差距 | 模拟器行为 | 真机行为 | 影响 | 回归补测 |
|
||||
|---|---|---|---|---|
|
||||
| **控制台单写者无对应实现** | `simulator/dbg_log.h` 把 `DBG_*` 映射到 `printf`;**不编译** `console_log.c` | 单写者环形缓冲 + defaultTask 唯一发送 | `console_log` 的环形缓冲溢出/丢弃计数逻辑**模拟器测不到**;共享代码若误调 `console_log.h` 声明,模拟器链接失败(已被此约束捕获) | `@test` + 板端串口观测;`docs/子系统设计/控制台单写者日志设计说明.md` §4.1 |
|
||||
| **mtime 粒度不同** | 宿主文件 mtime(**秒级**) | FAT 打包时间(`fdate<<16\|ftime`,**分钟级**) | `cfg_file_poll` 的 `(size, mtime)` 变更令牌在两端触发时机不同;分钟级粒度下的"同分钟内两次改动"在真机可能被判为无变化 | 板端 STORAGE 套件;`配置文件设计说明.md` §变更检测 |
|
||||
| **无应用回调(空操作)** | 模拟器不注册段回调,`cfg_file_poll` 重载后回调为空 | 各段回调真正执行(如网络重配置) | "配置变更 → 触发回调 → 副作用"链路在模拟器上**只验证到写盘**,回调逻辑不覆盖 | `@test`(配置保存 → UI 生效) |
|
||||
| **堆后端不同** | `cfg_store_alloc` = 宿主 `malloc`(堆余量以 MB 计) | FreeRTOS 堆(`configTOTAL_HEAP_SIZE` 48 KB,实测最低水位 ~4.8 KB) | **分配失败路径在模拟器上永不触发**——"KB 级分配必然返回 NULL"这类缺陷模拟器照不出来(`AGENTS.md` 已列为铁律) | 内存预算门禁 + 真机 `[HEAP]` 水位告警(S11) |
|
||||
|
||||
### 2.3 硬件专属(模拟器完全无对应)
|
||||
|
||||
| # | 差距 | 模拟器行为 | 真机行为 | 影响 | 回归补测 |
|
||||
|---|---|---|---|---|---|
|
||||
| H-1 | **IWDG 硬件行为** | **不编译看门狗模块**(`simulator/` 无 `task_watchdog.c`,也无 IWDG 桩) | 独立看门狗,LSI 时钟驱动,超时真复位 | **真实复位行为、LSI 漂移、`RCC_CSR` 标志均不可建模**;位图/判定逻辑也不在模拟器内跑——改由主机侧单测覆盖 | 真机 `@test`(复位原因日志 + 故障注入 V2/V4)+ 看门狗主机侧单测(L0.5,39 断言)<br>`看门狗设计说明.md` §4.7 / §7 |
|
||||
| H-2 | **CH395F 芯片** | 无(Winsock 代其 BSD API) | SPI 寄存器/命令/中断、PHY 协商、真实以太网帧 | 寄存器时序、命令回复、中断风暴、PHY 100M 全双工强制 | 板端 CH395F 套件(52 断言点)+ `@test` |
|
||||
| H-3 | **GD5F NAND** | 无 | SPI NAND:BBT 扫描、ECC、坏块管理、dhara FTL | 坏块/ECC/写入失败等路径完全不可测 | 板端 GD5F 套件(76 断言点)+ `@test` |
|
||||
| H-4 | **SD2506 RTC** | 无 | I2C RTC:时间读写、闹钟、温度、电池电压 | 时间源相关(`sys_clock_init` 降级路径)在模拟器上不可触发 | 板端 RTC 套件(18 断言点)+ `sys_clock` L0.5(已覆盖算术面) |
|
||||
| H-5 | **TPAFE5160 ADC** | 无 | SPI ADC + BUSY EXTI 中断 | 中断驱动采集链路 | 待功能实现(上游 B1) |
|
||||
| H-6 | **RS-485 半双工** | 无 | UART4 + DE 方向控制,DWT 微秒延时 | DE 收发切换时序(特有陷阱) | 待功能实现(上游 B2) |
|
||||
| H-7 | **启动段硬件初始化** | 只跑纯软件部分 | I2C/SPI 外设初始化、BBT 扫描耗时、FatFS 挂载 | 启动段死机(无看门狗保护窗口)**只能在真机复现** | 真机开机日志判读(`项目启动顺序管理.md` §6,S10 落地) |
|
||||
| 差距 | 模拟器行为 | 真机行为 | 影响 | 回归补测 |
|
||||
|---|---|---|---|---|
|
||||
| **IWDG 硬件行为** | **不编译看门狗模块**(`simulator/` 无 `task_watchdog.c`,也无 IWDG 桩) | 独立看门狗,LSI 时钟驱动,超时真复位 | **真实复位行为、LSI 漂移、`RCC_CSR` 标志均不可建模**;位图/判定逻辑也不在模拟器内跑——改由主机侧单测覆盖 | 真机 `@test`(复位原因日志 + 故障注入 V2/V4)+ 看门狗主机侧单测(L0.5,39 断言)<br>`看门狗设计说明.md` §4.7 / §7 |
|
||||
| **CH395F 芯片** | 无(Winsock 代其 BSD API) | SPI 寄存器/命令/中断、PHY 协商、真实以太网帧 | 寄存器时序、命令回复、中断风暴、PHY 100M 全双工强制 | 板端 CH395F 套件(52 断言点)+ `@test` |
|
||||
| **GD5F NAND** | 无 | SPI NAND:BBT 扫描、ECC、坏块管理、dhara FTL | 坏块/ECC/写入失败等路径完全不可测 | 板端 GD5F 套件(76 断言点)+ `@test` |
|
||||
| **SD2506 RTC** | 无 | I2C RTC:时间读写、闹钟、温度、电池电压 | 时间源相关(`sys_clock_init` 降级路径)在模拟器上不可触发 | 板端 RTC 套件(18 断言点)+ `sys_clock` L0.5(已覆盖算术面) |
|
||||
| **TPAFE5160 ADC** | 无 | SPI ADC + BUSY EXTI 中断 | 中断驱动采集链路 | 待功能实现(上游 B1) |
|
||||
| **RS-485 半双工** | 无 | UART4 + DE 方向控制,DWT 微秒延时 | DE 收发切换时序(特有陷阱) | 待功能实现(上游 B2) |
|
||||
| **启动段硬件初始化** | 只跑纯软件部分 | I2C/SPI 外设初始化、BBT 扫描耗时、FatFS 挂载 | 启动段死机(无看门狗保护窗口)**只能在真机复现** | 真机开机日志判读(`项目启动顺序管理.md` §6 已落地) |
|
||||
|
||||
### 2.4 哪些差异是"有意的对齐"(非缺陷)
|
||||
|
||||
@@ -86,11 +86,11 @@
|
||||
模拟器回归(L3)通过后,**满足以下任一条件即必须走真机**(`@test` / 板端套件):
|
||||
|
||||
1. **改动触及硬件访问层**:`Drivers/BSP/` 下任何驱动的寄存器/时序/中断代码
|
||||
2. **改动触及 §2.3 的 H-1~H-7 任一子系统**的初始化或运行时行为
|
||||
3. **改动触及 §2.2 的 L-2/L-3/L-4**:变更检测令牌、段回调副作用、内存分配失败路径
|
||||
4. **涉及网络重建 / 多连接并发**(N-2、N-5)
|
||||
5. **涉及启动段(`osKernelStart` 之前)**(H-7)
|
||||
6. **涉及内存预算**:新增任务/缓冲/栈(L-4;模拟器堆不可作依据)
|
||||
2. **改动触及 §2.3 硬件专属差距的任一子系统**的初始化或运行时行为
|
||||
3. **改动触及 §2.2 的 mtime 粒度 / 无应用回调 / 堆后端三条**:变更检测令牌、段回调副作用、内存分配失败路径
|
||||
4. **涉及网络重建 / 多连接并发**(代次号恒为 0、单连接 backlog)
|
||||
5. **涉及启动段(`osKernelStart` 之前)**(启动段硬件初始化)
|
||||
6. **涉及内存预算**:新增任务/缓冲/栈(堆后端不同;模拟器堆不可作依据)
|
||||
|
||||
反之,**纯 UI 场景/渲染/导航、配置解析算术、日志记录编解码格式**的改动,模拟器 + L0.5 可给出足够信心。
|
||||
|
||||
|
||||
+27
-27
@@ -36,7 +36,7 @@
|
||||
> [`看门狗单元测试说明.md`](看门狗单元测试说明.md)。适格对象:算法 / 状态机 / 协议编解码 /
|
||||
> 参数校验等**无副作用**的模块。
|
||||
>
|
||||
> **CI**:**L0 + L0.5 已上 CI**(Gitea Actions,`.gitea/workflows/ci.yml`,2026-10-01 T-6);
|
||||
> **CI**:**L0 + L0.5 已上 CI**(Gitea Actions,`.gitea/workflows/ci.yml`,2026-10-01);
|
||||
> L1/L2/L3 需硬件,只在本地。本地等价命令 `scripts/ci_local.py`。详见 §9。
|
||||
|
||||
### 1.1 门禁决策表(改动类型 → 必跑门禁)
|
||||
@@ -65,9 +65,9 @@ G0~G3 命令详见 §6 / §7;ui-verify 完整命令见 `UI_自动化测试流
|
||||
|
||||
| 对象 | 格式 | 现用示例 |
|
||||
|---|---|---|
|
||||
| 阶段 | `TM-{MOD}-{NN}` | TM-PHY-01 |
|
||||
| 阶段 | 直接写中文「阶段 N」(不再发号) | 阶段 6 |
|
||||
| 测试用例 | `TC-{MOD}-{NNN}` | `TC-NET-601`(CH395F)、`TC-GD5F-205`、`TC-STORAGE-03`、`TC-RTC-002` |
|
||||
| 设计原则 | `DP-{NN}` | DP-01(单连接 socket) |
|
||||
| 设计原则 | 写语义短语(不再发号) | 单连接 socket |
|
||||
|
||||
模块缩写 `{MOD}` 在新模块测试文档立文档时确定(2~4 个大写字母);现有:`NET`=CH395F 网络、`GD5F`、`STO`=存储、`RTC`、`ADC`、`RS485`。
|
||||
|
||||
@@ -114,7 +114,7 @@ flowchart TD
|
||||
|
||||
断言宏(语义统一,统计变量按套件独立,防跨套件串数):
|
||||
|
||||
**内核集中在 `test_common.h`**(2026-10-01 抽取,T-4)——4 套件的宏此前逐字重复,改一处要改四处:
|
||||
**内核集中在 `test_common.h`**(2026-10-01 抽取)——4 套件的宏此前逐字重复,改一处要改四处:
|
||||
|
||||
```c
|
||||
/* test/board/test_common.h */
|
||||
@@ -185,12 +185,12 @@ static void phaseN_run(void) {
|
||||
|
||||
> 注意:`test/` 在 pre-commit 检查范围之外(工具代码豁免)——上表约定属**自律**要求,但 0 错 0 警的构建红线对测试代码同样生效。
|
||||
|
||||
### 3.4 测试构建下的 netTask(2026-09-15 已修复 P1-6,未来测试设计必读)
|
||||
### 3.4 测试构建下的 netTask(2026-09-15 已修复,未来测试设计必读)
|
||||
|
||||
代码事实(2026-09-15 修复后):
|
||||
|
||||
1. `netTask` = **基础线程**:定义于 `.ioc` → `Src/freertos.c` 的 **CubeMX 生成区无条件创建**(全构建唯一实例)。产品 / NET 层测试模式下正常运行:等存储就绪(≤10s)→ `net_stack_bring_up()`(CH395F 初始化)→ 置 `SYS_EVT_NET_READY` → `net_poll()` 轮询循环。
|
||||
2. ~~USER CODE 区在 `ENABLE_NET_LAYER_TESTS` 下另建一个 netTask(双 netTask 并存)~~ → **2026-09-15 已删除**(P1-6):NET 层测试构建不再重复创建。
|
||||
2. ~~USER CODE 区在 `ENABLE_NET_LAYER_TESTS` 下另建一个 netTask(双 netTask 并存)~~ → **2026-09-15 已删除**:NET 层测试构建不再重复创建。
|
||||
3. **CH395F 硬件层模式下 `net_task_func` 入口自挂起**(2026-09-15 守卫,`ENABLE_HW_LAYER_TESTS`):不 bring_up、不轮询、不广播 NET_READY;testTask 自行 `net_stack_bring_up()` 后独占 CH395F 跑各阶段。任务仍被创建(基础线程策略:恒存在、该模式"不运行"),占 4KB 栈——彻底方案(`.ioc` 移除 + 条件创建)经评估未采用:网络线程是基础线程,仅测试模式"不运行"。
|
||||
|
||||
由此产生的设计约束:
|
||||
@@ -208,7 +208,7 @@ static void phaseN_run(void) {
|
||||
6. 立 `docs/测试说明/<模块>_Test_Guide.md`(§2 模板);
|
||||
7. `@test` 以套件标题行为 `-Required` 标记跑通回归。
|
||||
|
||||
### 3.6 多套件回归编排(`test/run_all_suites.py`,2026-10-01 加 T-5)
|
||||
### 3.6 多套件回归编排(`test/run_all_suites.py`,2026-10-01 加)
|
||||
|
||||
套件互斥(编译期 `#error`)→ 跑 4 个套件的回归本来要手工循环 4 轮
|
||||
(改宏 → 构建 → 烧录 → 采集 → 判读)。本脚本编排成一条命令:
|
||||
@@ -217,7 +217,7 @@ static void phaseN_run(void) {
|
||||
& '.venv\Scripts\python.exe' test/run_all_suites.py # 全部套件
|
||||
& '.venv\Scripts\python.exe' test/run_all_suites.py --suites STORAGE,GD5F
|
||||
& '.venv\Scripts\python.exe' test/run_all_suites.py --dry-run # 只看计划
|
||||
& '.venv\Scripts\python.exe' test/run_all_suites.py --check-build # 只编译不烧录(S6)
|
||||
& '.venv\Scripts\python.exe' test/run_all_suites.py --check-build # 只编译不烧录
|
||||
```
|
||||
|
||||
**核心保障:`try/finally` 无条件还原 `test_config.h`**(含异常 / `KeyboardInterrupt`
|
||||
@@ -227,7 +227,7 @@ static void phaseN_run(void) {
|
||||
> ⚠️ **完整回归不挂 pre-commit**:每轮真机烧录 + 采集(8s 静默 + boot),4 套件约数分钟起,
|
||||
> 且破坏性套件会改设备持久状态。仅回归窗口手工使用。
|
||||
|
||||
#### 3.6.1 `--check-build`:只编译不烧录(2026-10-02 加 S6)
|
||||
#### 3.6.1 `--check-build`:只编译不烧录(2026-10-02 加)
|
||||
|
||||
**解决的问题**:测试套件的**构建可编译性没有独立门禁**——产品构建 `@build` 天天跑,
|
||||
但测试构建可能长期"编不过"而无人知,直到某次要用才发现(2026-08~09 CH395F 套件
|
||||
@@ -242,11 +242,11 @@ static void phaseN_run(void) {
|
||||
| 做什么 | 逐套件:改 `test_config.h` 宏 → `@build` → 记 PASS/FAIL;结束后无条件还原 |
|
||||
| **不需要** | MCU / 串口 / ST-LINK(**纯离机**,可在 CI 或任何有 Keil 的机器上跑) |
|
||||
| 判定 | `@build` 退出码 0 = PASS;非 0(含 `L6406E` 链接失败)= FAIL |
|
||||
| RAM 溢出 | P1-9 类"编译过但链接失败"会**自然暴露**为 `L6406E`——这正是想要的 |
|
||||
| RAM 溢出 | "编译过但链接失败"这类问题会**自然暴露**为 `L6406E`——这正是想要的 |
|
||||
| 退出码 | 同完整模式:0=全 PASS / 1=有套件编不过 / 2=用法缺文件 |
|
||||
|
||||
> **2026-10-02 实测**:4 套件(CH395F / STORAGE / GD5F / RTC)**全部 `BUILD_OK: 0 errors, 0 warnings`**
|
||||
> ——即 T-4 提到的"CH395F 套件不可编译"问题**已修复**,现已纳入可自检范围。
|
||||
> ——即前述"CH395F 套件不可编译"问题**已修复**,现已纳入可自检范围。
|
||||
|
||||
> ⚠️ **隐藏陷阱:`.map` 必须复位为产品态**(2026-10-02 实测踩到)。脚本跑完最后一轮留下的
|
||||
> `STM32F407-Demo.map` 是**测试套件**的体积(RTC 套件下 ER_IROM1 达 266 KB),
|
||||
@@ -267,13 +267,13 @@ static void phaseN_run(void) {
|
||||
|---|---|---|
|
||||
| Python 串口助手(serial_tool) | `.dsh/skills/serial-assistant/scripts/serial_tool.py`(.venv + pyserial) | 常驻 daemon + 薄 CLI:列端口 / 开关 / 收发 / 全量日志 / wait-idle |
|
||||
| `.dsh/skills/serial-boot-test/scripts/run_boot_test.py` | `test/host/` | 一键闭环:采集 → 烧录 → 提取日志 → 校验 |
|
||||
| **`test/run_all_suites.py`** | `test/` | **多套件回归编排**(T-5)+ **`--check-build` 只编译不烧录**(S6,纯离机,验证 4 套件可编译性);见 §3.6 |
|
||||
| `.dsh/skills/serial-boot-test/scripts/verify_log.py` | `test/host/` | 日志标记校验(Required / Forbidden → PASS / FAIL)+ 可选套件汇总行校验(T-2) |
|
||||
| **`test/host/common/unit_test_harness.py`** | `test/host/common/` | **L0.5 通用单测 harness**:工具链探测 / `INCLUDE`-`LIB` 拼接 / 编译运行 / 退出码契约。各模块运行器只做声明式配置(T-3) |
|
||||
| **`test/run_all_suites.py`** | `test/` | **多套件回归编排** + **`--check-build` 只编译不烧录**(纯离机,验证 4 套件可编译性);见 §3.6 |
|
||||
| `.dsh/skills/serial-boot-test/scripts/verify_log.py` | `test/host/` | 日志标记校验(Required / Forbidden → PASS / FAIL)+ 可选套件汇总行校验 |
|
||||
| **`test/host/common/unit_test_harness.py`** | `test/host/common/` | **L0.5 通用单测 harness**:工具链探测 / `INCLUDE`-`LIB` 拼接 / 编译运行 / 退出码契约。各模块运行器只做声明式配置 |
|
||||
| **`test/host/watchdog/run_unit_test.py`** | `test/host/watchdog/` | **L0.5 主机侧单测**:声明 `TestBuild` 后调 harness,穷举看门狗判定状态机(零硬件、秒级)。**需本机装有 VS(`cl.exe`)**,见 §4.2 环境要求 |
|
||||
| **`test/host/sys_clock/run_unit_test.py`** | `test/host/sys_clock/` | **L0.5 主机侧单测**:穷举 `sys_clock` 时间换算 / 星期 / 惰性再基准化 / RTC 故障降级(100 断言,S1-a) |
|
||||
| **`test/host/cfg_file/run_unit_test.py`** | `test/host/cfg_file/` | **L0.5 主机侧单测**:INI 解析 / 值编解码 / 段注册 / load-save-poll 契约,内存虚拟 FS 驱动(139 断言,S1-b) |
|
||||
| **`test/host/nand_port/run_unit_test.py`** | `test/host/nand_port/` | **L0.5 主机侧单测**:离线编译真实 `Drivers/BSP/GD5F2GQ5UE/nand_ftl.c` + 真实 dhara,以 **RAM 假芯片**驱动,149 断言钉死 is_free 整页扫描(N-12)与六个入口的越界守卫(N-13) |
|
||||
| **`test/host/sys_clock/run_unit_test.py`** | `test/host/sys_clock/` | **L0.5 主机侧单测**:穷举 `sys_clock` 时间换算 / 星期 / 惰性再基准化 / RTC 故障降级(100 断言,首批主机侧单测) |
|
||||
| **`test/host/cfg_file/run_unit_test.py`** | `test/host/cfg_file/` | **L0.5 主机侧单测**:INI 解析 / 值编解码 / 段注册 / load-save-poll 契约,内存虚拟 FS 驱动(139 断言,首批主机侧单测) |
|
||||
| **`test/host/nand_port/run_unit_test.py`** | `test/host/nand_port/` | **L0.5 主机侧单测**:离线编译真实 `Drivers/BSP/GD5F2GQ5UE/nand_ftl.c` + 真实 dhara,以 **RAM 假芯片**驱动,149 断言钉死 is_free 整页扫描与六个入口的越界守卫 |
|
||||
| **`scripts/ci_local.py`** | `scripts/` | **本地跑与 CI 等价的门禁**(L0 + L0.5):自动选用装了 pre-commit 的解释器;`.map` 自适应跳过 `mem-numbers`;退出码 0/1/2 与 CI 对齐。见 §9.3 |
|
||||
| `.serialtest/config.json` | 仓库 | **串口端口单一配置源**(当前 COM6 / 115200);换端口只改这个文件 |
|
||||
| `test/host/ftp_*.py`(4 个)/ `ch395f_socket_test.py` / `time_sync_server.py` | `test/host/` | PC 端交互测试工具(FTP 客户端 / socket 回显 / 对时推送) |
|
||||
@@ -314,7 +314,7 @@ static void phaseN_run(void) {
|
||||
- 测试专用钩子(如静态态复位)用 `#ifdef <模块>_UNIT_TEST` 守卫,MCU 构建不编入(零符号);
|
||||
- 单测**不能替代**板端验证:真机寄存器 / 复位原因 / 时序仍须 L1/L2 台架闭环。
|
||||
|
||||
#### 4.2.1 L0.5 适格模块台账(2026-10-02 加,S2)
|
||||
#### 4.2.1 L0.5 适格模块台账(2026-10-02 加)
|
||||
|
||||
**问题**:L0.5 起步阶段只有"看门狗"一个先例,**下一个该测谁**靠临时判断,易遗漏高价值模块。
|
||||
|
||||
@@ -324,22 +324,22 @@ static void phaseN_run(void) {
|
||||
| 模块 | 规模 | 状态 | 平台层形态 | 备注 |
|
||||
|---|---|---|---|---|
|
||||
| `App/util/task_watchdog.c` | — | ✅ 已覆盖(39 断言) | 内联 `__weak` 钩子 | 范式来源;`#ifdef TASK_WATCHDOG_UNIT_TEST` 复位钩子 |
|
||||
| `App/util/sys_clock.c` | 479 行 | ✅ 已覆盖(100 断言,2026-10-02 S1-a) | 外部符号(`HAL_GetTick`/`sd2506_*`)+ 宏 | **零侵入**(无需 `#ifdef`);首测即抓出 Zeller 星期缺陷 |
|
||||
| `App/cfg/cfg_file.c` | 1250 行 | ✅ 已覆盖(139 断言,2026-10-02 S1-b) | 后端抽象(`cfg_file_store.h`) | 内存虚拟 FS 桩;**首测即抓出外科手术保存死码 P0**(见 §5) |
|
||||
| `App/util/sys_clock.c` | 479 行 | ✅ 已覆盖(100 断言,2026-10-02 首批) | 外部符号(`HAL_GetTick`/`sd2506_*`)+ 宏 | **零侵入**(无需 `#ifdef`);首测即抓出 Zeller 星期缺陷 |
|
||||
| `App/cfg/cfg_file.c` | 1250 行 | ✅ 已覆盖(139 断言,2026-10-02 首批) | 后端抽象(`cfg_file_store.h`) | 内存虚拟 FS 桩;**首测即抓出外科手术保存死码 P0**(见 §5) |
|
||||
| `App/log/sys_log_mcu.c` | — | ⬜ 候选 | 记录编解码(定长 64B) | 编解码纯逻辑;写入端依赖 FatFS + 队列,测编解码即可 |
|
||||
| `App/util/time_sync.c` | — | ⬜ 候选 | 协议帧编解码 | 报文组装/解析纯逻辑;网络收发不测 |
|
||||
| `Drivers/BSP/NETCFG/net_cfg_legacy.c` | — | ⛔ 已删除(2026-10-10) | — | 旧档 NCFG 迁移整体移除(旧档 `/cfg/netcfg.bin` 不读、不删、不迁移),测试候选随之撤销 |
|
||||
| `App/protocol/iec104/*`(104 协议栈) | — | ✅ 已覆盖(82 断言,2026-10-12 B4) | 数据源 vtable + tick 注入 + 发送回调注入 | APCI 重组/总召分片/COV/k-w-t1~t3/两段式全离线穷举;`iec104-unit-test` 钩子 |
|
||||
| `Drivers/BSP/GD5F2GQ5UE/nand_ftl.c`(dhara 移植层) | 573 行 | ✅ 已覆盖(149 断言,2026-10-15 N-21) | 11 个 SPI 原语(`gd5f2gq5ue.h`)→ **RAM 假芯片** | 移植层是纯地址算术 + 边界判定,换掉芯片即可离线跑;钉死 N-12(is_free 整页扫描)与 N-13(六入口越界守卫),并内联旧算法做对照证明断言有牙 |
|
||||
| `Drivers/BSP/GD5F2GQ5UE/nand_ftl.c`(dhara 移植层) | 573 行 | ✅ 已覆盖(149 断言,2026-10-15 起离线钉死 dhara 移植层两条硬约束) | 11 个 SPI 原语(`gd5f2gq5ue.h`)→ **RAM 假芯片** | 移植层是纯地址算术 + 边界判定,换掉芯片即可离线跑;钉死 is_free 整页扫描与六入口越界守卫,并内联旧算法做对照证明断言有牙 |
|
||||
| `App/util/rs485.c` | — | ⏸ 待功能实现 | — | 上游 B2;当前为空桩 |
|
||||
| `Drivers/BSP/TPAFE5160/*.c` | — | ❌ 不适格 | — | 寄存器序列为主,需真机时序 |
|
||||
| 其余驱动(CH395F/GD5F2GQ5UE 芯片层/SD2506) | — | ❌ 不适格 | — | 需硬件时序 / SPI / I2C 总线。⚠ **例外**:GD5F 之上的 `nand_ftl.c` 移植层**适格**(见上一行)——"驱动不适格"不等于"驱动之上的胶水层不适格" |
|
||||
| `App/util/crc.c` · `ringbuf.c` | 120/154 行 | ⛔ 已删除(2026-10-02 S8) | — | 孤儿文件,零引用,已 `git rm` |
|
||||
| `App/util/crc.c` · `ringbuf.c` | 120/154 行 | ⛔ 已删除(2026-10-02) | — | 孤儿文件,零引用,已 `git rm` |
|
||||
|
||||
**使用方式**:新增/改动上述模块前,按表判断是否需补 L0.5;`⬜ 候选` 表示"适格但未做",
|
||||
在性价比允许时应排入(判据:边界密集、零硬件、单次真机回归 30s~2min vs 单测 2~5s)。
|
||||
|
||||
> ⭐ **两条实证**:`sys_clock`(S1-a)与 `cfg_file`(S1-b)**首次落地即各抓出一处
|
||||
> ⭐ **两条实证**:`sys_clock` 与 `cfg_file` **首次落地即各抓出一处
|
||||
> 生产缺陷**(Zeller 星期公式错误 / 外科手术保存死码)。这印证了本台账的性价比判断——
|
||||
> 高价值纯逻辑模块的 L0.5 覆盖,是**投入最小、产出最大**的测试改进方向。
|
||||
|
||||
@@ -413,7 +413,7 @@ flowchart TD
|
||||
| 开机全量(存储 / RTC / RS485 / ADC) | 默认 + `RS485 init: OK;NAND init:;ADC init:;SD2506 ID:` |
|
||||
| 测试套件构建 | 套件结尾汇总行(`=== Storage Tests:` / `=== GD5F2GQ5UE Tests:` 等,确切字符串见各模块 Test_Guide) |
|
||||
|
||||
### 6.2.1 套件汇总行校验(2026-10-01 加,T-2)
|
||||
### 6.2.1 套件汇总行校验(2026-10-01 加)
|
||||
|
||||
> ⚠️ **纯 Required 子串匹配有盲区**:套件启动横幅命中即判 PASS——**套件是否跑到汇总行、
|
||||
> 断言数是否为 0 完全不可见**。套件中途挂死/复位、或 Phase 宏全关(没编入任何断言)时,
|
||||
@@ -458,7 +458,7 @@ flowchart TD
|
||||
| gitlint | commit message 标题 ≤100 字符 |
|
||||
| cppcheck | 静态分析(warning / performance / portability / style,含 suppress 清单) |
|
||||
| no-mojibake | 禁止 U+FFFD 乱码字节(保护中文注释) |
|
||||
| coding-standard | 代码规范 V1.0 机械检查(S1~S19) |
|
||||
| coding-standard | 代码规范 V1.0 机械检查(条款号 `CODE-RULE-nn`,规则表在 `scripts/check_coding_standard.py`) |
|
||||
| **test-suite-switch** | **测试套件开关=产品构建**(`test/board/test_config.h` 的 `TEST_SUITE_*` 须全注释;跑套件回归确需提交测试构建时用 `--allow-test-build` 显式放行) |
|
||||
|
||||
范围:仅项目自有代码受检;第三方与生成物(`Lib/`、`Middlewares/`、CMSIS/HAL、`lftpd`、`dhara`、`MDK-ARM/`、`test/`、CubeMX 生成的 `Src/` `Inc/` 等)被排除(详见 `pre-commit使用说明.md`)。
|
||||
@@ -502,7 +502,7 @@ flowchart LR
|
||||
|
||||
---
|
||||
|
||||
## 9. CI 持续集成(Gitea Actions,2026-10-01 加 T-6)
|
||||
## 9. CI 持续集成(Gitea Actions,2026-10-01 加)
|
||||
|
||||
远程仓库为 **Gitea 1.25.4**(`gitea.bitnasdaq.vip/wandering1/STM32F4-Base.git`),支持 Gitea Actions
|
||||
(兼容 GitHub Actions 语法,workflow 置于 `.gitea/workflows/`)。落地文件 **`.gitea/workflows/ci.yml`**。
|
||||
@@ -526,7 +526,7 @@ flowchart LR
|
||||
`.map` 时自动跳过该钩子**(`SKIP=mem-numbers`,钩子显示 `Skipped` 而非 `Passed`——
|
||||
是"不适用",不是"通过");有 `.map` 的 runner(如自建带 Keil 的机器)则照常跑。
|
||||
|
||||
> 🔴 **门禁盲区(S14,2026-10-02)**:跳过 `mem-numbers` 意味着 **CI 不守 Flash/RAM 体积门禁**——
|
||||
> 🔴 **门禁盲区(2026-10-02 记录)**:跳过 `mem-numbers` 意味着 **CI 不守 Flash/RAM 体积门禁**——
|
||||
> 新增任务/栈/缓冲/代码导致的体积增长**不会在 CI 被拦**。故该跳过以 `::warning::` 明示
|
||||
> (不是弱化的 notice)并写入 step-summary。**兜底必须靠本地**:改代码后 `@build`(0/0)
|
||||
> → `python scripts/check_mem_numbers.py --scan`。详见
|
||||
|
||||
+14
-23
@@ -24,7 +24,7 @@
|
||||
|
||||
## 1. 概述
|
||||
### 1.1 套件与入口(TEST_SUITE_* 宏 / 入口函数 / 阶段宏 / 运行方式)
|
||||
### 1.2 设计原则覆盖表(DP-xx → 描述 → 验证用例)
|
||||
### 1.2 设计原则覆盖表(原则短语 → 描述 → 验证用例)
|
||||
### 1.3 测试环境(拓扑、工具链、硬件版本、PC 端依赖)
|
||||
### 1.4 启用方法(编译开关 + 运行命令)
|
||||
### 1.5 回归接入(@test 标记 / PC 端脚本 / 门禁层级)
|
||||
@@ -73,7 +73,7 @@
|
||||
|
||||
| 字段名 | 填写说明 |
|
||||
|--------|----------|
|
||||
| **阶段 ID** | `TM-模块缩写-两位数序号`,如 TM-PHY-01、TM-NAND-01 |
|
||||
| **阶段** | 直接写中文「阶段 N」(如 阶段 1、阶段 6),不再发阶段号 |
|
||||
| **类型** | 独立运行 / 需 PC 配合 / 需物理操作 / 在 xxTask 中运行 |
|
||||
| **耗时** | 预估执行时间 |
|
||||
| **入口** | 代码入口函数或宏定义 |
|
||||
@@ -100,7 +100,7 @@
|
||||
| **预期结果** | 系统应表现的行为 |
|
||||
| **通过标准** | 可量化的判定条件 |
|
||||
| **机器可判** | 串口标记 / TEST_CHECK / 像素参考 / 池水位 / L3 人工(见 §7.4) |
|
||||
| **覆盖原则** | DP-xx(可选,关联设计原则) |
|
||||
| **覆盖原则** | 设计原则短语(可选,关联设计原则) |
|
||||
```
|
||||
|
||||
### 5.1 类型枚举
|
||||
@@ -127,14 +127,11 @@
|
||||
|
||||
## 6. 命名规则
|
||||
|
||||
### 6.1 阶段 ID
|
||||
### 6.1 阶段
|
||||
|
||||
```
|
||||
TM-{MOD}-{NN}
|
||||
```
|
||||
|
||||
- `TM` — Test Module
|
||||
- `{NN}` — 两位序号,从 01 开始
|
||||
- 正文、元信息表、汇总表一律写中文**「阶段 N」**(如 阶段 1、阶段 6),**不再发阶段号**;
|
||||
- 用例号的百位已经带阶段信息(§6.3),无需另立阶段标识;
|
||||
- 历史文档里出现过的旧阶段号冻结不回改,新文档按本条。
|
||||
|
||||
### 6.2 模块缩写(以项目现用为准)
|
||||
|
||||
@@ -160,16 +157,10 @@ TC-{MOD}-{NNN}
|
||||
- **无阶段划分套件**:全局顺序编号(如 `TC-STORAGE-03`、`TC-RTC-001`);
|
||||
- 编号不复用:废弃用例保留编号并注明"已废弃"。
|
||||
|
||||
### 6.4 设计原则 ID
|
||||
### 6.4 设计原则
|
||||
|
||||
```
|
||||
DP-{NN}
|
||||
```
|
||||
|
||||
- `DP` — Design Principle
|
||||
- `{NN}` — 两位序号,从 01 开始
|
||||
|
||||
示例:`DP-01`(CH395F 单连接 socket)、`DP-02`(中断集中处理)
|
||||
- 设计原则**写语义短语**,**不再发号**:如「单连接 socket」「中断集中处理」「线程安全」「DMA 边界安全」;
|
||||
- 覆盖原则处、汇总表与代码注释**引用同一条短语**(同一事实只在一处详述)。
|
||||
|
||||
---
|
||||
|
||||
@@ -246,7 +237,7 @@ DP-{NN}
|
||||
|
||||
| 原则 | 描述 | 验证用例 |
|
||||
|------|------|----------|
|
||||
| DP-01 | ... | TC-XXX-xxx |
|
||||
| 单连接 socket | ... | TC-NET-601 |
|
||||
|
||||
### 1.3 测试环境
|
||||
|
||||
@@ -268,18 +259,18 @@ DP-{NN}
|
||||
|
||||
| 项 | 值 |
|
||||
|---|---|
|
||||
| 阶段 ID | TM-XXX-01 |
|
||||
| 阶段 | 阶段 1 |
|
||||
| 类型 | ... |
|
||||
| 耗时 | ... |
|
||||
| 入口 | ... |
|
||||
| 出口 | ... |
|
||||
| 阶段宏 | `ENABLE_XXX_PHASE1_TESTS` |
|
||||
|
||||
### TC-XXX-001: 用例标题
|
||||
### TC-<模块码>-<序号>: 用例标题
|
||||
|
||||
| 字段 | 值 |
|
||||
|------|-----|
|
||||
| **ID** | TC-XXX-001 |
|
||||
| **ID** | `TC-<模块码>-<序号>`(全局唯一,不复用) |
|
||||
| **优先级** | P0 |
|
||||
| **类型** | 功能测试 |
|
||||
| **标题** | ... |
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
> [`ADC输入层单元测试说明.md`](ADC输入层单元测试说明.md)(同批落地的 L1 姊妹篇)、
|
||||
> [`../算法/傅氏算法详解.md`](../算法/傅氏算法详解.md)(**系数约定权威口径** §2.3)、
|
||||
> [`../算法/继电保护功能复现规划.md`](../算法/继电保护功能复现规划.md)(§3.2 L2 设计点 / §10.2 术语表)、
|
||||
> [`../硬件平台/ADC通道映射说明.md`](../硬件平台/ADC通道映射说明.md)(L1 输入口径 / N-18 约束)
|
||||
> [`../硬件平台/ADC通道映射说明.md`](../硬件平台/ADC通道映射说明.md)(L1 输入口径 / 「双转换器无共同采样触发」约束)
|
||||
|
||||
---
|
||||
|
||||
@@ -184,7 +184,7 @@ test/host/phasor/phasor_test.c
|
||||
### 4.2 主机侧合成波形**不代表真实硬件**
|
||||
|
||||
`frame_at()` 给 9 路语义通道灌的是**同值**波形,仅为驱动 L2 本身。V0.1 上各通道**不同刻**
|
||||
(N-18:TPAFE 与 STM32 无共同采样触发),跨通道相量运算在本平台上不成立——本单测**不**做
|
||||
(V0.1 硬件缺陷:TPAFE 与 STM32 无共同采样触发),跨通道相量运算在本平台上不成立——本单测**不**做
|
||||
任何跨通道合成断言(L2-5 受限,见 `docs/算法/继电保护功能复现规划.md` §1.6)。
|
||||
|
||||
### 4.3 实例数 4 → 5:规划表已对齐(2026-10-10)
|
||||
|
||||
@@ -71,7 +71,7 @@ test/host/watchdog/watchdog_test.c
|
||||
> `reg.exe`。运行器因此**直接拼 `INCLUDE`/`LIB` 环境变量**并用绝对
|
||||
> 路径调 `cl.exe`(只需 MSVC 版本目录 + Windows SDK 的 include/lib),无副作用、可重复。
|
||||
>
|
||||
> 该工具链逻辑**不在本模块目录内**(2026-10-01 T-3 抽取):已沉淀为通用 harness
|
||||
> 该工具链逻辑**不在本模块目录内**(2026-10-01 抽取):已沉淀为通用 harness
|
||||
> [`../../test/host/common/unit_test_harness.py`](../../test/host/common/unit_test_harness.py),
|
||||
> 本模块的 `run_unit_test.py` 只**声明** `TestBuild`(源文件 / 桩目录 / 汇总行标记)。
|
||||
> 新增 L0.5 单测时直接复用 harness,见 [`../../test/host/common/README.md`](../../test/host/common/README.md)。
|
||||
|
||||
+33
-33
@@ -5,7 +5,7 @@
|
||||
> 哪些缺陷已修/未修、新异常出现时查什么。
|
||||
> **数据日期**:2026-09-22 台架(COM6 @115200;STM32F407ZGTx @168MHz + CH395F,SPI2 分频 8)
|
||||
> **数据文件**:`m2_data/`、`m3_data/`(JSON + 串口证据片段);本文所有数字均可回溯到这些文件
|
||||
> **代码状态**:D10 / E-02 / D17 / D12 / D14 / D15 / D16 已修复并台架复验(§8);
|
||||
> **代码状态**:D10 / D17 / D12 / D14 / D15 / D16 已修复并台架复验(§8);
|
||||
> D1(重传周期 200ms)/ D6(per-recv 日志)2026-09-22 已实施并台架复验(P0-a/P0-b,§10.1);
|
||||
> D20(开机首个 FTP 会话第 2 个数据连接 425)已定位未修(§8.2)
|
||||
> **合并说明**:本文统一原《链路延迟测试说明》《链路时延实测数据分析》《远程显示延迟分析》
|
||||
@@ -25,7 +25,7 @@ MCU 侧真实处理只占 6.7ms,任务拾取/调度约 2.3ms(2026-09-22 重
|
||||
- **解法在客户端一侧(生产客户端已实装)**:Windows 连接时关延迟 ACK(帧耗时 **20.7ms**,3.3×)/
|
||||
非 Windows 用"入站轻推"兜底(**29.4ms**,2.3×);协议与固件都不需要改(§7.4)。
|
||||
- **设备侧无可行解**(帧长 3209 为质数、TX FIFO = MSS、CH395F 无 Nagle 开关)→ 不必再投入。
|
||||
- **缺陷**:D10(断线重监听 588ms 冻结 netTask)、E-02(一条空闲 FTP 控制连接冻结全网 17.7s)、
|
||||
- **缺陷**:D10(断线重监听 588ms 冻结 netTask)、头阻塞(一条空闲 FTP 控制连接冻结全网 17.7s)、
|
||||
D17(INIT 应答帧字节数字段恒 0)等已量化并**修复 + 台架复验**(§8);
|
||||
D1(重传周期 500→200ms)/ D6(per-recv 日志)2026-09-22 已实施(§10.1);D20 已定位未修(§8.2)。
|
||||
|
||||
@@ -114,12 +114,12 @@ sequenceDiagram
|
||||
| **L2** | SPI DMA | `ch395f_read_recv_buf(N)` 完整 DMA 事务(含 CS 切换),N ∈ {4, 64, 1024, 2048} | MCU,DWT µs,Phase 12,N=100/档 | 20 / 114 / **1611** / 3208µs(斜率 1.56µs/B + 固定 14µs) | SPI2/DMA/总线异常 |
|
||||
| **L3** | 发送分块握手 | `write_send_buf(1KB)` → `SENBUF_FREE` 的等待时长(= `net_send_locked` 每 chunk 的真实等待) | MCU(netTask 上下文),Phase 13 | **219µs**/chunk | 芯片发送路径 / 重传(D1) / 链路(D7) |
|
||||
| **L4** | 芯片→线上+PC | 数据交入芯片协议栈 → PC 首见字节 / 收齐全帧(peer 逐 `recv()` 批次打时间戳) | PC(peer),Phase 13/14 | 首批 8.6ms;**段间间隙 ≥200ms = 重传**(P0-a 后粒度;旧固件 500ms) | D1/D4/D7("网络延迟"直接证据) |
|
||||
| **L5** | 队列往返 | 调用方视角 `net_recv(DONTWAIT)` / `net_send` 全程 = 入队 + netTask 调度 + 处理 + 通知 | MCU(调用方计时),Phase 13,**两档**:静默基线 + 压力档(并发 FTP 流量) | 静默:收 1223µs / 发 988µs(2026-09-22 重锁,P0-b 后;L3 对 DONTWAIT 路径逐位不变,重验留待 Phase 13 下次窗口) | D3(E-02 头阻塞,已两阶段修复) / D5 调度 |
|
||||
| **L5** | 队列往返 | 调用方视角 `net_recv(DONTWAIT)` / `net_send` 全程 = 入队 + netTask 调度 + 处理 + 通知 | MCU(调用方计时),Phase 13,**两档**:静默基线 + 压力档(并发 FTP 流量) | 静默:收 1223µs / 发 988µs(2026-09-22 重锁,P0-b 后;L3 对 DONTWAIT 路径逐位不变,重验留待 Phase 13 下次窗口) | D3(头阻塞,已两阶段修复) / D5 调度 |
|
||||
| **L6** | 请求→首字节 | peer 发 10B 请求 → MCU 收齐并回显(服务端视角);与 PC 侧对照,差值 = 线路 + PC 栈 | MCU + PC 双侧,Phase 13 | MCU 986µs / PC 3.9ms | MCU 收路径/调度 |
|
||||
| **L7** | 整帧 3209B 往返 | LCDMEM 全帧:PC 发 → 收齐(含 L3+L4) | PC 为主,Phase 13 | 61.0ms(M2);**spike(≥500ms)=0** | D1+D2+D4 综合 |
|
||||
| **L8** | 生产路径帧周期 | **真实 uiTask + 真实 `ui_net_sink`**(:7003)完整帧周期:请求拾取(10ms 拍)+ 队列 + 发送 + L4 + peer 侧编码 | MCU 探针 + PC,Phase 14 | 真机 61.6ms / 模拟器 6.8ms(含 peer 100ms 节拍) | 全段(用户真实体感) |
|
||||
| **L9** | 连接/重监听 | connect→ESTABLISHED;close→relisten 成功 | MCU(net_poll 观测点),Phase 14 | relisten **89ms**(D10 修复后) | 握手/队列;**≥500ms = D10 回归** |
|
||||
| **L10** | 日志税 | 一行 60 字符 `printf`(现 fputc 逐字节 @115200)耗时 | MCU,Phase 13 附带 | **4402µs/行** | D6(per-recv 日志已删 2026-09-22;S8 非阻塞日志仍待办) |
|
||||
| **L10** | 日志税 | 一行 60 字符 `printf`(现 fputc 逐字节 @115200)耗时 | MCU,Phase 13 附带 | **4402µs/行** | D6(per-recv 日志已删 2026-09-22;非阻塞日志仍待办) |
|
||||
| **L11** | uiTask 节拍 | 生产循环实测周期(`osDelay(10)` 之外多花多少 = LVGL 渲染 + 渲染中排空) | MCU 探针,Phase 14 | **10986µs**(渲染仅 ~1ms/帧) | D5/D9(实测均非瓶颈) |
|
||||
| **Δ** | CH395F 净贡献 | `L8(真机) − L8(模拟器)`,同一 peer 交替跑 | PC,Phase 14 | **54.8ms**(阈值 ≤80ms) | 直接回答"网络延迟"占多少 |
|
||||
|
||||
@@ -411,14 +411,14 @@ D10 修复后实测 89ms(= 30ms 重试间隔 + 约 60ms 芯片沉降),故
|
||||
重连 17.1/22.4ms → pending 构建:帧周期 med **58.9ms**(−2.7ms)、尾批 **50.4ms**(−2.2ms)——
|
||||
执行器零占用使生产路径净缩短(更早的空闲窗口)。)
|
||||
|
||||
**压力档(`--ftp-stress`,E-02 复现;第 25 帧起 FTP 空闲登录保持)**
|
||||
**压力档(`--ftp-stress`,头阻塞复现;第 25 帧起 FTP 空闲登录保持)**
|
||||
|
||||
| 分桶 | n | med | p95 | max | 尖峰(≥500ms) |
|
||||
|---|---|---|---|---|---|
|
||||
| quiet(0~24 帧) | 25 | 58.4ms | 69.0ms | 69.8ms | 0 |
|
||||
| stress(25~49 帧,**挂起 recv 构建**) | 25 | **60.1ms** | 66.4ms | **69.3ms** | **0** |
|
||||
|
||||
(E-02 修复前 stress 档 med 17718ms、尖峰 1 次 = 17.7s 全网冻结(旧固件);阶段一 5ms 分片修复后
|
||||
(头阻塞修复前 stress 档 med 17718ms、尖峰 1 次 = 17.7s 全网冻结(旧固件);阶段一 5ms 分片修复后
|
||||
med 65.0ms/max 133.5ms(133.5 = 压力启动瞬态单帧);**挂起 recv 化后 med 60.1ms/max 69.3ms**
|
||||
——p99 尾部较分片档压缩近半(133.5→69.3),MCU 侧 `prod_cycle_mcu` 6706µs 在压力下纹丝不动
|
||||
(min 6698/max 6720):头阻塞工况不再向 UI 帧周期传导 = 结构性收益。本档重锁 =
|
||||
@@ -444,7 +444,7 @@ med 65.0ms/max 133.5ms(133.5 = 压力启动瞬态单帧);**挂起 recv 化
|
||||
|
||||
¹ L5 两行为 2026-09-22 上午分片时代(M2 B2 档)数值:L3 对 DONTWAIT 快速路径**逐位不变**(dispatch
|
||||
→ `net_poll` → `get_recv_len` 读,无 readable 门控),pending tick 无 pending 时为纯指针读零 SPI
|
||||
(µs 级)——机制上不影响 L5;M2 重验未在本轮执行(低风险,留待 Phase 13 下次窗口,见 `docs/任务规划/README.md` N-3)。
|
||||
(µs 级)——机制上不影响 L5;M2 重验未在本轮执行(低风险,留待 Phase 13 下次窗口,见 `docs/任务规划/README.md` 条目「L5 队列往返基线待重验」)。
|
||||
|
||||
数据来源:L1/L2 = §6.1;L3/L5/L6/L7 = M2 B2 档(200ms、per-recv 日志已删)串口 `[LAT]` 行
|
||||
(`m2_data/m2_quiet_r200.json`);L8/L9/L11 = **挂起 recv 构建 2026-09-22 16:42/16:43 重锁**
|
||||
@@ -497,7 +497,7 @@ peer 侧 = `m3_data/m3_pending_*.json`(L3 重锁)与 `m3_data/m3_dev_*_r200.
|
||||
|---|---|---|
|
||||
| ① 同一客户端 → 模拟器 | tail = **0.0ms**,cycle 6.8ms | 客户端栈、Windows、请求格式全部相同 → 尾批**不是 PC 侧**造成 |
|
||||
| ② M2 `L3` 批量排空(16×4096B,全满块) | 65536B / **125.4ms**(≈2ms/KB) | 16 个满块若各带 50ms 尾巴应 ≥800ms → **满块无此惩罚** |
|
||||
| ③ 压力档(E-02 头阻塞)下的 L7/生产帧 | tail 仍 43~62ms | 尾批**不受 netTask 拥塞影响** → 属芯片 TX 行为 |
|
||||
| ③ 压力档(头阻塞)下的 L7/生产帧 | tail 仍 43~62ms | 尾批**不受 netTask 拥塞影响** → 属芯片 TX 行为 |
|
||||
|
||||
### 7.3 尾批 ~52ms:机理与带内验证(全部不需要抓包)
|
||||
|
||||
@@ -604,12 +604,12 @@ sock4 auto-relisten ok / relisten retry ok ← 监听器随后自行恢复
|
||||
3. 寄存器级定位(如需):首会话复现窗口内打印 `CMD_GET_SOCKET_STATUS_SN`(2 字节)与 SINT 序列;
|
||||
4. **现场规避**:客户端重试(425 属 RFC 959 瞬态 4xx,重试一次即可)——最省事的临时手段。
|
||||
|
||||
### 8.3 关键实现要点(D10/E-02 修复,供后续维护)
|
||||
### 8.3 关键实现要点(D10/头阻塞修复,供后续维护)
|
||||
|
||||
1. **D10 重试必须防饥饿**:调用方(accept/recv 路径每 10ms 一次)只登记一次重试,实际重试由 netTask
|
||||
轮询到点执行;若让调用方每次立即重试并重置时刻,会永不重试。重试间隔 100ms→30ms 后恢复时间
|
||||
147ms→89ms(芯片沉降约 60ms);
|
||||
2. **(历史,阶段一)E-02 分片长度 = 其他任务的最坏等待**:100ms 片下受压帧仍 ~750ms(多片排队),收到
|
||||
2. **(历史,阶段一)头阻塞修复的分片长度 = 其他任务的最坏等待**:100ms 片下受压帧仍 ~750ms(多片排队),收到
|
||||
**5ms** 片后才降到 ~75ms——该"分片即上限"模型已于 2026-09-22 由 **挂起 recv 化**取代
|
||||
(`a45c0cb`):执行器零占用后,其他任务的最坏等待 = 一个主循环节拍(~1ms),与任何片长无关
|
||||
(M3 压力档实测:med 60.1ms/max 69.3ms,p99 尾部较分片档 133.5ms 压缩近半);
|
||||
@@ -625,12 +625,12 @@ sock4 auto-relisten ok / relisten retry ok ← 监听器随后自行恢复
|
||||
维护注意:队列中长 SEND/CLOSE 消息处理期间,pending 完成顺延至下轮 tick(~1ms 级;长 SEND
|
||||
stall 期间最多顺延相应时长)——已知代价,勿"优化"回执行器内等待。
|
||||
|
||||
### 8.4 相关既有缺陷(会掩盖/放大延迟;编号为历史审计编号,属主文档已删除,仅作指称)
|
||||
### 8.4 相关既有缺陷(会掩盖/放大延迟)
|
||||
|
||||
| 编号 | 位置 | 与延迟的关系 |
|
||||
| 缺陷 | 位置 | 与延迟的关系 |
|
||||
|---|---|---|
|
||||
| **E-04** | `ui_net_sink.c` `remo_send` | 丢弃 `net_send` 返回值 → 弱网短写静默截断,客户端 CRC 不过 → 断连 → 观感"卡完直接黑屏/卡住" |
|
||||
| **E-33/E-34** | `ch395f.c` SPI DMA/字节命令 | DMA 失败 void 化无错误通道;`HAL_MAX_DELAY` → 一次 SPI 故障可能让 netTask 永久挂死(无看门狗) |
|
||||
| **`remo_send` 短写** | `ui_net_sink.c` `remo_send` | 丢弃 `net_send` 返回值 → 弱网短写静默截断,客户端 CRC 不过 → 断连 → 观感"卡完直接黑屏/卡住" |
|
||||
| **SPI 错误通道** | `ch395f.c` SPI DMA/字节命令 | DMA 失败 void 化无错误通道;`HAL_MAX_DELAY` → 一次 SPI 故障可能让 netTask 永久挂死(无看门狗) |
|
||||
|
||||
---
|
||||
|
||||
@@ -642,9 +642,9 @@ sock4 auto-relisten ok / relisten retry ok ← 监听器随后自行恢复
|
||||
|---|---|---|
|
||||
| 每帧都**稳定**慢 ≈150~300ms | 结构性基线(§10.1 的 D2/D5/D6/D8) | 跑 §5 的 Phase 13/14 对照基线 |
|
||||
| **间歇**卡,且 ≈200ms 的整数倍(旧固件 500ms) | **D1** 丢包重传 | Wireshark `tcp.analysis.retransmission`;查 PHY/网线/Wi-Fi |
|
||||
| **间歇**整屏冻结数秒~数十秒 | **E-02** 头阻塞(已修)/ D10 重连(已修)/ 回归 | 查 FTP/对时会话是否挂着;核对 §8 修复在位 |
|
||||
| 只在开 FTP / 对时后卡 | E-02 + 单连接 socket 争用 | 临时停 ftpTask/timeSyncTask 对照 |
|
||||
| 换网口/换线/换 PC 就好 | D7 物理链路 | §10.2-S3 拓扑纪律 |
|
||||
| **间歇**整屏冻结数秒~数十秒 | **头阻塞**(已修)/ D10 重连(已修)/ 回归 | 查 FTP/对时会话是否挂着;核对 §8 修复在位 |
|
||||
| 只在开 FTP / 对时后卡 | 头阻塞 + 单连接 socket 争用 | 临时停 ftpTask/timeSyncTask 对照 |
|
||||
| 换网口/换线/换 PC 就好 | D7 物理链路 | 拓扑纪律:核对开机日志 PHY 行 + 交换机端口强制全双工 + PC 有线直连 |
|
||||
|
||||
### 9.2 分段对照
|
||||
|
||||
@@ -653,7 +653,7 @@ sock4 auto-relisten ok / relisten retry ok ← 监听器随后自行恢复
|
||||
| L1/L2 超 crit | SPI 走线/PCB/SPI2 分频或 DMA 配置 | 对照 `docs/问题记录/CH395F_Trap_Records.md`;逻辑分析仪抓 SCK/CS |
|
||||
| L3 spike ≥200ms(连续台阶;旧固件 500ms) | **D1 重传 / D7 链路** | Wireshark `tcp.analysis.retransmission`;查 PHY 协商/网线/Wi-Fi |
|
||||
| L3 基线(非 spike)抬高 | 芯片发送路径 / 中断响应 | 对照 `docs/芯片手册/CH395F.md` §5.17/5.18(注意:状态寄存器**不被 SET 类命令更新**,`GET_CMD_STATUS` 恒读到 RESET 的 0x10 陈旧残留,2026-09-22 台架实证——不可用作 SET 值验收) |
|
||||
| L5 压力档爆表 | **E-02 头阻塞(已修)→ 回归** | 定位触发源(阻塞 recv 的 FTP/对时);核对 挂起 recv 在位(`net_recv_locked` 阻塞分支 = 登记 pending 而非等待;`net_pending_tick` 在主循环) |
|
||||
| L5 压力档爆表 | **头阻塞(已修)→ 回归** | 定位触发源(阻塞 recv 的 FTP/对时);核对 挂起 recv 在位(`net_recv_locked` 阻塞分支 = 登记 pending 而非等待;`net_pending_tick` 在主循环) |
|
||||
| L5/L6 静默档抬高 | D5 调度(任务抢占/节拍) | 查任务优先级与 osDelay;`stack_report.py` 核对栈水位 |
|
||||
| L6/L7 整体抬高且 L1~L5 正常 | 线路+PC 段(L4) | Wireshark 段间间隙;`Δ` 对照定位 MCU 侧净贡献 |
|
||||
| **L7/L8 尾批固定迟到 ~50ms** | 已定性(§7.3):次 MSS 尾段被 Nagle 扣住 + Windows 延迟 ACK | 客户端侧解法已实测(§7.4):`--ack-probe` / `--ack-fast` → tail 52→3.9ms;生产客户端已实装;**设备侧无解**,不必再投入 |
|
||||
@@ -662,15 +662,15 @@ sock4 auto-relisten ok / relisten retry ok ← 监听器随后自行恢复
|
||||
| **L7 一直超时 / peer 报 `l7_crc.fail`** | **D15**:帧格式不一致 / peer 超读 | 对照 `ui_net_sink.c` 的 `remo_send`/`remo_handle`(§8 D15) |
|
||||
| **会话跑完一段后无限循环、peer 空等 300s** | **D16**:Phase 13 状态机迁移目标错 | 核对顺序 L5→L3→L10→L6→L7→DONE(§8 D16) |
|
||||
| **`[LAT]` 段行缺失/截断、wait-idle 判不出空闲** | **D12-b**:热路径日志洪水 | 删除 net 热路径逐调用日志(§8 D12-b) |
|
||||
| **开机日志连续丢行**(含必检标记 `net init: OK` 等)但系统健康 | **日志并发竞态**:多任务并发 `printf` → 非重入 `fputc`/`HAL_UART_Transmit` 丢整行、UART 状态短暂卡住(2026-09-22 台架实证:boot 时 testTask 启动行与 netTask 日志并发 → 连续 4 行丢失、~2s 后自恢复) | 必现证据行采用"静默采集 + 延迟到安静窗口打印"模式(范例:P0-a 验收行曾按此模式实装,验收完成后探针已移除);根治 = S8 日志非阻塞/串行化(§10.2) |
|
||||
| **开机日志连续丢行**(含必检标记 `net init: OK` 等)但系统健康 | **日志并发竞态**:多任务并发 `printf` → 非重入 `fputc`/`HAL_UART_Transmit` 丢整行、UART 状态短暂卡住(2026-09-22 台架实证:boot 时 testTask 启动行与 netTask 日志并发 → 连续 4 行丢失、~2s 后自恢复) | 必现证据行采用"静默采集 + 延迟到安静窗口打印"模式(范例:P0-a 验收行曾按此模式实装,验收完成后探针已移除);根治 = 日志非阻塞/串行化(§10.2) |
|
||||
| **`relisten` 段 FAIL、断线固定 ~588ms** | **D10** 回归(退回 `osDelay(500)`) | 核对 `net_listener_request`/`net_listener_tick` 非阻塞重试在位(§8 D10) |
|
||||
| **远端显示整帧卡住十几秒后自恢复** | **E-02** 回归 | 核对 挂起 recv 在位:`net_recv_locked` 阻塞分支登记 pending(哨兵 `NET_PENDING_REGISTERED`)+ `net_pending_tick` 在主循环 + 调用方剩余预算循环(lftpd/timeSync)(§8.3 要点 4) |
|
||||
| **远端显示整帧卡住十几秒后自恢复** | **头阻塞回归** | 核对 挂起 recv 在位:`net_recv_locked` 阻塞分支登记 pending(哨兵 `NET_PENDING_REGISTERED`)+ `net_pending_tick` 在主循环 + 调用方剩余预算循环(lftpd/timeSync)(§8.3 要点 4) |
|
||||
| **INIT 应答帧字节数字段恒为 0** | **D17** 回归 | 核对 `remo_send_init` 发满 8B(§8 D17) |
|
||||
| **开机首个 FTP 会话第 2 个数据连接 425** | **D20**(已定位未修,§8.2) | 复现:`test/host/ftp_regression.py`(复位开边界);现场规避:客户端重试 425(瞬态 4xx);根治方向:数据 Socket 轮换 |
|
||||
| **`[LAT]` 多段数值雷同 / 全 0 却 verdict=OK** | **D18/D19**(测试工装) | 核对 `lat_probe_add_seg` 段名过滤 + `lat_time_init` 调用 + `med==0` 判无效 |
|
||||
| **连接建立后 15~30s 无流量即被 RST** | **D13**:芯片空闲超时(芯片行为) | 客户端须容忍并重连(peer `--wait` 重试是正常路径) |
|
||||
| **peer 重连后 MCU 状态滞留、新连接字节被吞** | **D14**:芯片静默回收 Socket | 对账⑤自动认领(手动 `net_resync_listen`/`net_relisten` 已退役,Phase 13 abort 期自愈亦交 net 层) |
|
||||
| L8 超而 L7 正常 | 生产路径附加成本(uiTask 节拍/LVGL/日志) | 对照 L10/L11 与 §10.1(渲染已排除;per-recv 日志已删,S8 非阻塞日志仍待办) |
|
||||
| L8 超而 L7 正常 | 生产路径附加成本(uiTask 节拍/LVGL/日志) | 对照 L10/L11 与 §10.1(渲染已排除;per-recv 日志已删,非阻塞日志仍待办) |
|
||||
| Δ 显著 >80ms | CH395F 栈净开销异常 | 回到 L1~L9 逐段排查 |
|
||||
|
||||
---
|
||||
@@ -682,12 +682,12 @@ sock4 auto-relisten ok / relisten retry ok ← 监听器随后自行恢复
|
||||
| # | 原因 | 实测验证(2026-09-22 台架) | 当前状态 |
|
||||
|---|---|---|---|
|
||||
| D1 | CH395F TCP 重传固定周期(非 RTT 自适应) | 台架链路(有线 100M 全双工)多轮零重传尖峰 → 台架无丢包;**弱网(Wi-Fi/双工不匹配)仍是秒级卡顿首要嫌疑**,200ms 粒度台阶 = 重传指纹(旧固件 500ms) | **已修(P0-a,2026-09-22)**:`NET_RETRANS_PERIOD_MS` 500→**200**(窗口 8×200=1.6s,原 4s)。台架验收说明:`GET_CMD_STATUS` 对 SET 类命令无判别力(500/2000ms 超限对照均读 0x10 陈旧残留,§9.2)→ 接受性以手册范围(≤1000ms)+ 全套件零回归(§6.2/§6.3)+ 与 500ms 行为同构为准。验收探针(3×20ms 状态轮询 + 证据行)验收完成后已从代码移除,结论保留于本文档 |
|
||||
| D2 | 3209B × 1KB 发送 FIFO 停止等待(4 次串行分块握手,期间 netTask 全程占用) | `chunk_wait` 219µs/块 ≈ SPI 搬运成本的 1/7 → 握手本身**不是瓶颈**;每帧固定成本小(MCU 净 7.1ms) | 基线成本,可接受;根治 = 差量/RLE + 帧版本号(待办 S2) |
|
||||
| D3 | netMsgQueue 头阻塞(= §8 E-02) | 已量化:一条空闲 FTP 控制连接冻结全网 17.7s | **两阶段闭环**:① 5ms 分片有界读 + 让出(f8d6e90/4a1605b,缓解)② **挂起 recv 化**(`a45c0cb`,结构性——执行器零占用,缺陷类消灭,§8.3 要点 4) |
|
||||
| D2 | 3209B × 1KB 发送 FIFO 停止等待(4 次串行分块握手,期间 netTask 全程占用) | `chunk_wait` 219µs/块 ≈ SPI 搬运成本的 1/7 → 握手本身**不是瓶颈**;每帧固定成本小(MCU 净 7.1ms) | 基线成本,可接受;根治 = 差量/RLE + 帧版本号(待办) |
|
||||
| D3 | netMsgQueue 头阻塞 | 已量化:一条空闲 FTP 控制连接冻结全网 17.7s | **两阶段闭环**:① 5ms 分片有界读 + 让出(f8d6e90/4a1605b,缓解)② **挂起 recv 化**(`a45c0cb`,结构性——执行器零占用,缺陷类消灭,§8.3 要点 4) |
|
||||
| D4 | PC 端延迟 ACK 与"每段等 ACK"停止等待交互 | `--ack-fast` 带内实验证实:关掉延迟 ACK 尾批自行消失(52→3.9ms) | **已客户端侧解决**(生产客户端关延迟 ACK/轻推兜底,§7.4) |
|
||||
| D5 | uiTask 节拍:10ms 循环 + 每拍一次 64B recv + step 在 poll 前 | `ui_loop` 10986µs ≈ 设计值(渲染 ~1ms);拾取调度 ~2.3ms(P0-b 删 per-recv 日志后,原 ~6.8ms) | 基线行为;可选优化 S7(poll 前置 + while 排空),低优先 |
|
||||
| D6 | 阻塞式日志在关键路径(fputc 逐字节 @115200) | `logtax_line` 4402µs/行;per-recv 日志已删(2026-09-22):`queue_rt_recv` 5997→1223µs、帧周期 66.0→61.6ms、首字节 13.9→9.6ms | **部分已修(P0-b,2026-09-22)**;S8 非阻塞日志仍待办(同时是开机日志并发丢行 §9.2 的根治项) |
|
||||
| D7 | 物理链路:强制 100M 全双工 vs 交换机自协商 → 双工不匹配静默丢包 | 台架 `PHY: 100M FULL` 成立、零尖峰 → 台架干净 | 现场排查项(S3):核对开机日志 PHY 行 + 交换机端口强制全双工 + 验证 PC 有线直连 |
|
||||
| D6 | 阻塞式日志在关键路径(fputc 逐字节 @115200) | `logtax_line` 4402µs/行;per-recv 日志已删(2026-09-22):`queue_rt_recv` 5997→1223µs、帧周期 66.0→61.6ms、首字节 13.9→9.6ms | **部分已修(P0-b,2026-09-22)**;非阻塞日志仍待办(同时是开机日志并发丢行 §9.2 的根治项) |
|
||||
| D7 | 物理链路:强制 100M 全双工 vs 交换机自协商 → 双工不匹配静默丢包 | 台架 `PHY: 100M FULL` 成立、零尖峰 → 台架干净 | 现场排查项:核对开机日志 PHY 行 + 交换机端口强制全双工 + 验证 PC 有线直连 |
|
||||
| D8 | 客户端固定成本:100ms 拉取节拍、按键后不立即取帧、1bpp→PNG→base64→WS 编码链 | 生产客户端优化后:帧耗时 20.7ms、显示帧率 ~9fps | 部分已优化(延迟确认抑制已上线);其余待办 S9(按键后立即取帧/不传 PNG/自适应节拍)——客户端仓库 |
|
||||
|
||||
### 10.2 待办优化项(按性价比排序,均未实施)
|
||||
@@ -698,7 +698,7 @@ sock4 auto-relisten ok / relisten retry ok ← 监听器随后自行恢复
|
||||
3. **~~P0-b~~ 已实施(2026-09-22)**:删除 `net_socket.c` per-recv `DBG_INFO`;实测 `queue_rt_recv` −80%
|
||||
(5997→1223µs)、生产帧周期 −4.4ms(66.0→61.6ms)、首字节 −4.3ms(13.9→9.6ms);
|
||||
4. **S1** 超时参数分档:`NET_SEND/RECV_TIMEOUT_MS` 全局一刀切 → 按服务分离(远显短超时+非阻塞,FTP 保留长超时);
|
||||
5. **S2** 差量/RLE + 帧版本号 + 由拉改推(**根治,收益最大**:典型变化 <100B → 单段一帧,延迟 ≈ 一个 RTT;
|
||||
5. **差量/RLE + 帧版本号 + 由拉改推**(**根治,收益最大**:典型变化 <100B → 单段一帧,延迟 ≈ 一个 RTT;
|
||||
稳态带宽 32KB/s → ≈0;D1 影响面 4 段 → 1 段;新命令走同一帧格式与 CRC,旧客户端兼容);
|
||||
6. **S4** 发送块配额与 MSS:48 块按实际使用的 3 个 socket 重新分配(各 16 块),MSS → 1460
|
||||
(3209B 从 4 段降到 1~2 段);**约束**:单次写长度必须 ≤ 发送缓冲(TRAP-NET-16 铁律),
|
||||
@@ -706,20 +706,20 @@ sock4 auto-relisten ok / relisten retry ok ← 监听器随后自行恢复
|
||||
**另**:MSS/块配额变更**必须**跑可信用例(`test/host/ch395f_socket_test.py tcp_client` 全序列 + 新连接独立 4096B 对照),判据 = **客户端侧内容完全匹配**(勿用带固件内读者的台架配方,其短收是读者吞数据不是故障);
|
||||
7. **S5** 去掉一次 3200B 拷贝(`g_tx` 直接承接位图,省 ~3.2KB 常驻 RAM;改前跑 `scripts/ram_report.py`);
|
||||
8. **S7** uiTask:`ui_net_sink_poll()` 前置到 `ui_port_step` 前 + while 排空(省按键一整拍);
|
||||
9. **~~S8~~ 已实施·形态变更(生产者侧 2026-09-24 单写者;2026-10-25 N-2 合并评估收口)**:
|
||||
9. **日志非阻塞化:已实施·形态变更(生产者侧 2026-09-24 单写者;2026-10-25 与日志静默观察项合并评估收口)**:
|
||||
`fputc` → 环形缓冲**已落地**(4KB 环 + 单写者 + 事件位;4402µs/行 → µs 级入环,
|
||||
溢出 = 有界 200ms + dropped 账 + `[ERR]` 留痕;冲刷 = 有界裸发,见
|
||||
`../子系统设计/控制台单写者日志设计说明.md` §4);**TX 中断/DMA 维持否决**
|
||||
(该文档 D4),复议绑定 S-3 TX-only 根治后的 `tx_timeout` 实测——N-2 × S8 全文
|
||||
(该文档 D4),原绑定的复议条件(根治项落地后实测 `tx_timeout`)已随 2026-10-26 裁定不做而失效——日志静默观察项 × 日志单写者化合并评估全文
|
||||
结论见同文档文末附录;
|
||||
10. **S9** 客户端侧(DTU-RemtoeLCD):按键后立即取帧、不传 PNG(直接发 1bpp/差量 + canvas 绘制)、
|
||||
自适应节拍(帧耗时补偿)、验证 PC 一律有线同交换机;
|
||||
11. **M4**(可选)`[计划] test/run_latency_test.py` 一键编排(open/clear/flash/wait-idle/peer/collect/merge/verdict)——待排期;
|
||||
12. **M5**(可选,在役设备)非独占采样器:事件触发、10s 旁路打点入 syslog——设计预留;
|
||||
13. 协议补位(尾批退路,仅当客户端无法改动时;见 §7.4)。
|
||||
14. **日志并发保护(2026-09-22 新增,与 S8 同源、优先级上调)**:开机多任务并发 `printf` 丢整行
|
||||
14. **日志并发保护(2026-09-22 新增,与日志非阻塞化同源、优先级上调)**:开机多任务并发 `printf` 丢整行
|
||||
(实测 §9.2:必检标记 `net init: OK` 曾被竞态吞掉 → 影响开机验收可靠性)。过渡:必现证据行按
|
||||
"静默采集 + 延迟到安静窗口打印"模式(范例:P0-a 验收行,验收完成后已移除);根治 = S8(串口 TX 环形缓冲
|
||||
"静默采集 + 延迟到安静窗口打印"模式(范例:P0-a 验收行,验收完成后已移除);根治 = 日志非阻塞化(串口 TX 环形缓冲
|
||||
+ 中断/DMA,溢出丢弃策略需定义)。
|
||||
**现状(2026-10-25)**:根治已随单写者落地——行级原子 = 临界区整行入环、单写者发出,
|
||||
交错/丢行结构性消除;「写者注册前」窗口为裸发例外,纪律 = `dbg_console_writer_ready()`
|
||||
@@ -754,10 +754,10 @@ sock4 auto-relisten ok / relisten retry ok ← 监听器随后自行恢复
|
||||
| `m2_data/m2_quiet_r500.json` | 2026-09-22 A/B 对照档 B1(500ms + per-recv 日志 = 旧基线条件;复跑与 run15 重合 ±0.2%) |
|
||||
| `m2_data/m2_quiet_r200.json` | **2026-09-22 M2 重锁基线** B2(200ms、per-recv 日志已删 = 当前代码) |
|
||||
| `m2_data/README.md` | M2 数据说明(逐帧尾批明细、方法学约束) |
|
||||
| `m3_data/m3_dev_quiet.json` | 真机 65 帧生产周期(D10/E-02/D17 修复前基线) |
|
||||
| `m3_data/m3_dev_quiet.json` | 真机 65 帧生产周期(D10/头阻塞/D17 修复前基线) |
|
||||
| `m3_data/m3_dev_quiet_fixed.json` | 真机 65 帧(修复后:帧周期 65.7ms、relisten OK、INIT framebytes=3200) |
|
||||
| `m3_data/m3_dev_stress.json` | E-02 压力档(修复前:17.7s 尖峰) |
|
||||
| `m3_data/m3_dev_stress_fixed.json` | E-02 压力档(修复后:med 74.7ms / max 106.8ms,零尖峰) |
|
||||
| `m3_data/m3_dev_stress.json` | 头阻塞压力档(修复前:17.7s 尖峰) |
|
||||
| `m3_data/m3_dev_stress_fixed.json` | 头阻塞压力档(修复后:med 74.7ms / max 106.8ms,零尖峰) |
|
||||
| `m3_data/m3_dev_quiet_r200.json` | **2026-09-22 M3 静默档重锁基线**(50 帧,P0-a/P0-b 代码:帧周期 61.6ms) |
|
||||
| `m3_data/m3_dev_stress_r200.json` | **2026-09-22 M3 压力档重锁基线**(45 帧,第 15 帧起 FTP stress:med 65.0ms / max 133.5ms,零尖峰)——分片时代数值,**已被 L3 档取代**(历史对照) |
|
||||
| `m3_data/m3_pending_quiet.json` | **2026-09-22 M3 静默档 L3 重锁基线(当前)**(50 帧,pending 构建 16:42:帧周期 58.9ms / 首字节 9.2ms / 尾批 50.4ms,零尖峰,CRC 50/0) |
|
||||
|
||||
@@ -36,7 +36,7 @@ Python 环境、以及 `docs/任务规划/` 这类**全局唯一登记簿**都
|
||||
2026-09-19 建、已过期),本方案沿用其「仓库同级 + `_` 前缀」命名,但把散落的目录收敛到统一的
|
||||
`_wt/` 容器下。**两者已于 2026-10-12 清理**:`_v1pin-build` 干净直接移除;`_v2oui-build` 有 2 个
|
||||
未提交改动(uvprojx / freertos.c),已按字节留档于 `_wt/.archive/2026-10-12-legacy-worktrees/`
|
||||
后才移除(两提交由 `wip/trap22-fix` / `wip/v2-pending-recv` 持有,无提交丢失)。
|
||||
后才移除(两提交由两条 `wip/*` 保活分支持有,其一为 `wip/v2-pending-recv`;无提交丢失)。
|
||||
|
||||
---
|
||||
|
||||
@@ -209,8 +209,8 @@ D:/Code/DTU Code/
|
||||
|
||||
### 7.3 并行道与写范围规则(规划层 ↔ 执行层映射)
|
||||
|
||||
规划层(任务卡在 `docs/任务规划/数据可信.md` 与 `docs/任务规划/采集保护收尾.md`,
|
||||
五字段 = **DoD / 硬依赖 / 资源 / 写范围 / 状态**;归道见 `docs/任务规划/并行分道方案.md`)
|
||||
规划层(当前任务卡在 `docs/任务规划/UI补齐.md`,后续事项在 `docs/任务规划/登记簿.md`;
|
||||
五字段 = **DoD / 硬依赖 / 资源 / 写范围 / 状态**)
|
||||
按**资源属性**把任务切进三条道,本方案(工作树 + 锁)是它的执行层:
|
||||
|
||||
| 道 | 资源 | 并行性 | 锁 / 机制 |
|
||||
|
||||
@@ -408,7 +408,7 @@ pre-commit run --all-files
|
||||
> 获取渠道优先级:① `winget`(自动校验、免手动)→ ② 上表官方页 → ③ 网络受限时自行选可信镜像;
|
||||
> Keil / ST 官网访问受限时可走代理。
|
||||
|
||||
### 2.11 CI runner 环境(Gitea Actions,2026-10-01 T-6)
|
||||
### 2.11 CI runner 环境(Gitea Actions,2026-10-01 起)
|
||||
|
||||
CI 跑 **L0 静态门禁 + L0.5 主机侧单测**(**不含 L1/L2/L3**——需真机 + ST-LINK,只在本地)。
|
||||
workflow 见 `.gitea/workflows/ci.yml`;覆盖边界与判定细节见 [`../测试说明/测试开发标准流程.md`](../测试说明/测试开发标准流程.md) §9。
|
||||
@@ -533,7 +533,7 @@ $env:DTU_KEIL_UV4 = 'D:\NotExist\UV4.exe' # 仅当前会话,不动用户级
|
||||
|
||||
| 开关 | 位置 | 当前值 | 说明 |
|
||||
|---|---|---|---|
|
||||
| 功能裁剪开关 | — | 无 | **当前没有任何可裁剪的编译开关**(2026-10-22):原 `APP_NET_ENABLE` / `APP_ADC_ENABLE` / `APP_RS485_ENABLE` 三个宏全库零消费点,已按报告 S-4 删除,`App/app/app_cfg.h` 只留决策占位说明。要不要真实门控取决于产品定义(`docs/任务规划/README.md` §2 阶段 B0);在此之前各模块一律编译进产品 |
|
||||
| 功能裁剪开关 | — | 无 | **当前没有任何可裁剪的编译开关**(2026-10-22):原 `APP_NET_ENABLE` / `APP_ADC_ENABLE` / `APP_RS485_ENABLE` 三个宏全库零消费点,已于 2026-10-22 删除,`App/app/app_cfg.h` 只留决策占位说明。要不要真实门控取决于产品定义(开放问题见 `docs/任务规划/登记簿.md` §9);在此之前各模块一律编译进产品 |
|
||||
| `TEST_SUITE_*` | `test/board/test_config.h` | 全注释(产品构建) | 测试套件**互斥**:一次构建只开一个(CH395F / 存储 / GD5F / RTC);全注释 = 正常产品固件 |
|
||||
|
||||
---
|
||||
|
||||
+24
-24
@@ -39,7 +39,7 @@
|
||||
| 采样硬件 | TPAFE5160(16 位、8 通道**同步**、±5 V 双极性、并行 `GPIOG[15:0]`)+ STM32 内部 ADC1(12 位、9 通道**顺序**扫描、0~3.3 V 单极性) |
|
||||
| 采样软件 | `Drivers/BSP/TPAFE5160/tpafe5160.h` 驱动就绪(原子快照 API);`App/task/adc_task.c` **已实现真实消费者(B1,2026-10-10)**——`tpafe5160_snapshot()` 取数 + 帧统计;**采样节拍由 TIM3 更新事件(1 kHz)硬件触发**(2026-10-10;同一事件经 TRGO 触发 ADC1 + DMA);STM32 侧 **`App/algo/adc_input.c` 已实现语义映射 + ADC1 DMA 乒乓帧消费(L1-3/L1-4,v2.0)**,`HAL_ADC_Start_DMA` 已出现 |
|
||||
| 保护算法层 | **L2 相量层已实现并台架闭环**(`App/algo/sample_ring.c` + `phasor.c`:全周傅氏 5 实例、双区交换、每 1 ms 刷新,2026-10-11 `@test`);**L3 元件框架 + 过流/过负荷/过压/欠压/零序过压 + 定值模型软件侧完成**(`prot_elm.c` + `prot_set.c`,2026-10-11,57 项主机单测);**出口 / SOE 记录仍缺失**(P4) |
|
||||
| 已知硬件缺陷 | **N-18**:8 路电气量分属两片转换器 → V0.1 上禁止跨转换器做相位/功率/矢量运算 |
|
||||
| 已知硬件缺陷 | 登记簿条目「双转换器无共同采样触发」:8 路电气量分属两片转换器 → V0.1 上禁止跨转换器做相位/功率/矢量运算 |
|
||||
|
||||
### 1.3 复现范围界定
|
||||
|
||||
@@ -50,11 +50,11 @@
|
||||
3. 保护元件:**V0.1 测量有效子集**——过压/欠压(`UA`)、零序过压(`UN`)、过流(A 相,`IA`)、过负荷(A 相)、过频/低频;三相完整过流、零序过流、涌流制动、PT/CT 断线等**建接口不使能**,待 V0.2(见 §1.6)。
|
||||
4. 出口与记录:跳闸/告警出口、SOE/动作记录、定值模型与 cfg_file 集成、自检闭锁。
|
||||
|
||||
> ⚠️ **V0.1 硬件裁剪**(2026-10-10 定性):本清单受 **N-18**(跨转换器无同一时刻性)与**"STM32 侧无中点偏置"**两条约束,实际可闭环的保护元件见 **§1.6**——V0.1 上只有 TPAFE 三路(`UA`/`UN`/`IA`)测量有效。
|
||||
> ⚠️ **V0.1 硬件裁剪**(2026-10-10 定性):本清单受「双转换器无共同采样触发」(跨转换器无同一时刻性)与**"STM32 侧无中点偏置"**两条约束,实际可闭环的保护元件见 **§1.6**——V0.1 上只有 TPAFE 三路(`UA`/`UN`/`IA`)测量有效。
|
||||
|
||||
**本期不做(延后或依赖条件)**
|
||||
|
||||
- 方向元件 / 功率 / 功率因数 / 对称分量类运算——受 **N-18** 制约,V0.1 上取子板计量结果,或待 V0.2 硬件改版后实现。
|
||||
- 方向元件 / 功率 / 功率因数 / 对称分量类运算——受「双转换器无共同采样触发」制约,V0.1 上取子板计量结果,或待 V0.2 硬件改版后实现。
|
||||
- 三相完整过流、零序过流、依赖三相的 PT/CT 断线——需 V0.2 硬件(8 路电气量全上 TPAFE + 中点偏置)后启用。
|
||||
- 重合闸、馈线自动化(FA)等 FTU 专有功能——视产品定义(B0)。
|
||||
- 双核 / DSP 拆分、VxWorks 特有机制、IEC 61850、完整故障录波——与单核 FreeRTOS 平台不匹配。
|
||||
@@ -66,7 +66,7 @@
|
||||
| --- | --- | --- |
|
||||
| **B0 产品定义** | 采集是否持续 / 采样率与通道 / 转发目标 / 保护元件清单——决定 B1 与保护层的**规模** | ✅ 已确认(2026-10-10,见 §1.5) |
|
||||
| **B1 ADC 采集链路** | 周期 CONVST + `adc_task` 消费 `tpafe5160_snapshot()` + 建任务 + 栈预算 | ✅ 已实现并 `@test` 实机闭环(2026-10-10;`adcTask` 512 words,台架 1000 Hz) |
|
||||
| **N-18 硬件缺陷** | V0.1 跨转换器无同一时刻性 → 限定 V0.1 可实现的保护范围 | ⚠️ 硬件改版项(V0.2) |
|
||||
| **双转换器无共同采样触发(硬件缺陷)** | V0.1 跨转换器无同一时刻性 → 限定 V0.1 可实现的保护范围 | ⚠️ 硬件改版项(V0.2) |
|
||||
| **栈预算** | 保护任务栈需入 `Src/freertos.c` 并经 `scripts/stack_report.py` 核算 | ✅ 两任务均已核算:`adcTask`(**L1-6 后:栈抬至 640 words,静态 1080 B / 台架实测峰值 952/2560 / 余 57%**);`protectTask`(B5,2026-10-12:**512 words,静态链 872 B / 余 1176 B / 57%**,台架水位待 `@test`) |
|
||||
|
||||
### 1.5 B0 产品定义(2026-10-10 确认)
|
||||
@@ -101,7 +101,7 @@
|
||||
| `4014` | `1U0` 零序电压 | `UN`(外部专用零序电压通道) |
|
||||
| `4015~4017` | `1Ia`、`1Ib`、`1Ic` | `IA`/`IB`/`IC` |
|
||||
| `4018` | `1I0` 零序电流 | `IN`(外部专用零序电流通道) |
|
||||
| `4019~401c` | `1P`/`1Q`/`1S`/`1Pf` | 计算量(受 **N-18** 制约,V0.1 不可做) |
|
||||
| `4019~401c` | `1P`/`1Q`/`1S`/`1Pf` | 计算量(受「双转换器无共同采样触发」制约,V0.1 不可做) |
|
||||
| `401d` | `1f` 频率 | 软件测频 |
|
||||
| `401e/f` | `V1`/`V2` 直流量(点表注"FTU 无") | ⚠️ 无对应硬件通道 → **本期不做**(B0-a) |
|
||||
|
||||
@@ -138,7 +138,7 @@
|
||||
|
||||
| # | 约束 | 出处 | 后果 |
|
||||
| --- | --- | --- | --- |
|
||||
| N-18 | 8 路电气量分属 TPAFE5160 与 STM32 ADC1 **两片**,两片**无共同采样触发** | `ADC通道映射说明.md` §1、登记簿 N-18 | 跨转换器的相位 / 矢量 / 功率 / 功率因数 / 负序运算**不成立** |
|
||||
| 双转换器无共同采样触发 | 8 路电气量分属 TPAFE5160 与 STM32 ADC1 **两片**,两片**无共同采样触发** | `ADC通道映射说明.md` §1、登记簿条目「双转换器无共同采样触发」 | 跨转换器的相位 / 矢量 / 功率 / 功率因数 / 负序运算**不成立** |
|
||||
| R5 | STM32 侧**无中点偏置**(1k 串联 + 1k 到 `*_GND`),0~3.3 V 单极性 | `ADC通道映射说明.md` §7、本文 §9 R5 | STM32 侧交流量负半周**削顶** → 该侧**算不出有效值 / 相量** |
|
||||
|
||||
**(2)净效果:V0.1 只有 TPAFE 三路"测量有效"**
|
||||
@@ -158,8 +158,8 @@
|
||||
| 过负荷(A 相) | `IA` | TPAFE | ✅ | 测量有效 |
|
||||
| 过频 / 低频 | `UA` / `IA` | TPAFE | ✅ | 单通道测频,有效 |
|
||||
| 过流(B / C 相) | `IB` / `IC` | STM32 | ❌ | 削顶,无有效值 |
|
||||
| 零序过流 | `IN`(外部)/ 自产 `Ia+Ib+Ic` | STM32 / 跨转换器 | ❌ | 削顶 / 跨转换器(N-18) |
|
||||
| 方向 / 功率 / 功率因数 / 负序 | 多路 | 跨转换器 | ❌ | N-18 |
|
||||
| 零序过流 | `IN`(外部)/ 自产 `Ia+Ib+Ic` | STM32 / 跨转换器 | ❌ | 削顶 / 跨转换器(双转换器无共同采样触发) |
|
||||
| 方向 / 功率 / 功率因数 / 负序 | 多路 | 跨转换器 | ❌ | 双转换器无共同采样触发 |
|
||||
| PT / CT 断线 | 三相判据 | 跨转换器 | ❌ | 需三相同时刻 |
|
||||
| 母线接地告警 | `3U0`(UN) + `3I0`(IN) | UN 可 / IN 不可 | ⚠️ 部分 | 仅电压侧可判 |
|
||||
|
||||
@@ -168,7 +168,7 @@
|
||||
采用**"骨架全做 + 有效通道子集闭环"**:
|
||||
|
||||
- **与通道无关的骨架**(采集触发、`adcTask`、语义映射、标定、全周傅氏、双区交换、统一保护元件接口、定值模型 + cfg_file、出口驱动、SOE / 记录、自检闭锁)——**本期全做**;这是 V0.2 改版后**不需要重构**的核心资产(§6.2 的接口设计启示)。
|
||||
- **保护元件**——本期只让**测量有效的通道**闭环动作:`UA`(过压/欠压、测频)、`UN`(零序过压)、`IA`(过流 A 相、过负荷)。其余元件**建接口 + 预置定值但不使能**,待 **V0.2**(N-18 修复 + 补中点偏置,8 路电气量全上 TPAFE)。
|
||||
- **保护元件**——本期只让**测量有效的通道**闭环动作:`UA`(过压/欠压、测频)、`UN`(零序过压)、`IA`(过流 A 相、过负荷)。其余元件**建接口 + 预置定值但不使能**,待 **V0.2**(修复「双转换器无共同采样触发」+ 补中点偏置,8 路电气量全上 TPAFE)。
|
||||
- **控制类 / FTU 专有功能**(重合闸、小电流接地选线、后加速、检合环同期):均依赖三相 / 零序测量或出口硬件,**本期不做**,随 V0.2。
|
||||
- 即:**本期交付"整条保护链路的软件实现" + "单相/中性线保护闭环验证"**;三相完整过流、零序过流、方向/功率类随 V0.2 硬件启用。
|
||||
|
||||
@@ -189,7 +189,7 @@
|
||||
| **L4 出口与信号** | 跳闸/告警出口、信号灯 | `TripKO` / KO | `App/protect/` + BSP 出口驱动 |
|
||||
| **L5 记录与上送** | SOE/动作记录、UI 显示、遥测上送 | 记录模块 + 通信 | `App/log/` + `Drivers/BSP/UI/` + `App/protocol/` |
|
||||
|
||||
> **分层原则**:L1 只做"数"(码值→工程量),L2 只做"相量"(工程量→复相量),L3 只做"判据"(相量 + 定值→布尔),L4/L5 只做"动作与留痕"。**算法与 I/O 分离**,使 L2/L3 成为主机侧单元测试(L0.5)的天然适格对象(落实登记簿 **A-4**)。
|
||||
> **分层原则**:L1 只做"数"(码值→工程量),L2 只做"相量"(工程量→复相量),L3 只做"判据"(相量 + 定值→布尔),L4/L5 只做"动作与留痕"。**算法与 I/O 分离**,使 L2/L3 成为主机侧单元测试(L0.5)的天然适格对象(落实 `docs/任务规划/测试与架构专项.md`「采集链路测试可验证性约束」)。
|
||||
|
||||
### 2.2 任务与中断模型(映射到 STM32F4 + FreeRTOS)
|
||||
|
||||
@@ -248,7 +248,7 @@
|
||||
| L1-8 | 零序通道接入(外部专用 / 自产切换) | 外部 `UN`/`IN`;自产 `3I0 = Ia+Ib+Ic`(V0.2 起) | 零序通道可切换来源,值正确 | ⬜ |
|
||||
| L1-9 | 二次谐波/五次谐波提取入口 | k=2(涌流)、k=5(选线) | 相量层可产出对应谐波相量 | ✅ 2026-10-11:`phasor.c` 实例表 `C04-IA-F2`(k=2)/ `C05-IA-F5`(k=5)随每拍重算产出,台架心跳日志 `phasor(hb) C04/C05` 行可见(`boot_log_data/20261011_prod_phasor_boot_log.txt`);谐波**抑制/提取正确性**已由主机单测覆盖(`test/host/phasor/`) |
|
||||
|
||||
> ⚠️ **N-18 约束**:L1-4 中 `UA/UN/IA` 在 TPAFE、`UB/UC/IB/IC/IN` 在 STM32 ADC。V0.1 上 L1 只做**逐通道独立监视**,不得假设同族量同刻(`UA` 与 `UB` 无共同采样触发)。
|
||||
> ⚠️ **「双转换器无共同采样触发」约束**:L1-4 中 `UA/UN/IA` 在 TPAFE、`UB/UC/IB/IC/IN` 在 STM32 ADC。V0.1 上 L1 只做**逐通道独立监视**,不得假设同族量同刻(`UA` 与 `UB` 无共同采样触发)。
|
||||
|
||||
### 3.2 L2 相量计算
|
||||
|
||||
@@ -258,7 +258,7 @@
|
||||
| L2-2 | 基波相量实例 | **5 个实例**(参考项目 4 个,见下方注):`C01-IA-F1` / `C02-UA-F1` / `C03-UN-F1` / `C04-IA-F2` / `C05-IA-F5` | 每实例输出 `{fRe, fIm, fAm, fAmSQ}` | ✅ 2026-10-11:`k_inst[]` 数据驱动 5 实例;台架开机即产出 `phasor(first)` 5 行(`boot_log_data/20261011_prod_phasor_boot_log.txt`) |
|
||||
| L2-3 | 相量有效值输出 | `fAmSQ = √(fRe²+fIm²)` 直接为**有效值**(系数已折算) | 标准源读数 = 设定有效值 | ✅ 2026-10-11(链路级):`fAmSQ` 口径实现 + 单测合成正弦幅值误差 ≤1%;**"标准源读数"判据在无信号源台架不可达**(同 §7.1),待 L1-5 标定后复核 |
|
||||
| L2-4 | 相位输出 | `φ = atan2(fIm, fRe)` | 相位误差 ≤ 目标值 | ✅ 2026-10-11(链路级):`fRe/fIm` 常驻双区、每拍产出,φ 由消费侧 `atan2f` 现算(不常驻结构体,见 `docs/算法/采集与算法层设计说明.md` §6);单测覆盖相位;**目标值待产品定义 + 标准源复核** |
|
||||
| L2-5 | 线/负序/零序合成 | 线电压 `Uab=Ua−Ub` 等;负序 `3U2`/`3I2`;零序 `3U0`/`3I0` | 合成相量可复用于保护元件(**V0.1 仅同转换器内可合成**,见 §1.6) | ⬜ **V0.1 不适用**:跨转换器合成被 N-18 禁止;零序走**外部专用通道** `UN`/`IN`(§6.4),无需自产 → 随 V0.2 启用 |
|
||||
| L2-5 | 线/负序/零序合成 | 线电压 `Uab=Ua−Ub` 等;负序 `3U2`/`3I2`;零序 `3U0`/`3I0` | 合成相量可复用于保护元件(**V0.1 仅同转换器内可合成**,见 §1.6) | ⬜ **V0.1 不适用**:跨转换器合成被「双转换器无共同采样触发」禁止;零序走**外部专用通道** `UN`/`IN`(§6.4),无需自产 → 随 V0.2 启用 |
|
||||
| L2-6 | 每 1 ms 滑动窗刷新 | 每来新点,窗滑动一格、20 点重算(暴力法) | 相量每拍更新 | ✅ 2026-10-11:`sample_ring` 40 点环 + `phasor_run()` 每拍整窗重算(仅 `r==1` 新帧压环,P0 修复);台架 `ring` 随 `frames` 同步递增、`idle=0` |
|
||||
| L2-7 | 双区指针原子交换 | 计算区/使用区切换 | 保护元件读使用区,无撕裂 | ✅ 2026-10-11:`s_zone[2][5]` + 单字节 `volatile` 切换(Cortex-M 原子);单测覆盖双区交换;为独立 L3 任务预留无锁读 |
|
||||
| L2-8 | 遥测谐波轨(可选) | k=1~9,方和根 `√(ΣHk²)` | 与基波轨并行,供 UI/上送 | ⬜ |
|
||||
@@ -267,7 +267,7 @@
|
||||
|
||||
> **L2-2 实例数 4 → 5 的来历**:参考项目(`APP/CLS100_Dsp/InstCalCell.c`)为 **4 个实例**——C01 基波 I/U、C02 零序基波、C03 二次谐波、C04 五次谐波。本项目按 V0.1 **有效通道**(`UA`/`UN`/`IA`,见 §1.6:`UB/UC/IB/IC/IN` 无中点偏置 → 削顶不可用)展开:C01 的"I/U"拆为两行(`C01-IA-F1` 电流 / `C02-UA-F1` 电压),其余顺延为 `C03-UN-F1` 零序、`C04-IA-F2` 二次、`C05-IA-F5` 五次。实现见 `App/algo/phasor.c` 的 `k_inst[]`;判据按 **5** 个实例断言(见 `docs/测试说明/相量层单元测试说明.md` §2.6)。
|
||||
|
||||
> **本表状态列口径**(2026-10-11 更新):L2-1~L2-4 / L2-6 / L2-7 已**实现 + 主机单测(57 用例)+ 台架 `@test` 闭环**——闭环命令 `run_boot_test.py --required "...;phasor(first);phasor(hb)" --require-order "App init OK>phasor(first)>phasor(hb)"`,证据 `boot_log_data/20261011_prod_phasor_boot_log.txt`(`fw build` 身份戳匹配、回读一致、锚点 ×1、零 `[ERR]`)。⚠ **幅值/相位精度判据(标准源)在无信号源台架上不可达**(同 §7.1 无示波器口径),且 L1-5 标定未实现 → 现读数为**原始码值**,只证明链路通;精度复核排在标定之后。L2-5 随 V0.2(N-18),L2-8 可选项未做。
|
||||
> **本表状态列口径**(2026-10-11 更新):L2-1~L2-4 / L2-6 / L2-7 已**实现 + 主机单测(57 用例)+ 台架 `@test` 闭环**——闭环命令 `run_boot_test.py --required "...;phasor(first);phasor(hb)" --require-order "App init OK>phasor(first)>phasor(hb)"`,证据 `boot_log_data/20261011_prod_phasor_boot_log.txt`(`fw build` 身份戳匹配、回读一致、锚点 ×1、零 `[ERR]`)。⚠ **幅值/相位精度判据(标准源)在无信号源台架上不可达**(同 §7.1 无示波器口径),且 L1-5 标定未实现 → 现读数为**原始码值**,只证明链路通;精度复核排在标定之后。L2-5 随 V0.2(双转换器无共同采样触发),L2-8 可选项未做。
|
||||
|
||||
### 3.3 L3 保护元件
|
||||
|
||||
@@ -278,11 +278,11 @@
|
||||
| # | 元件 | 判据要点 | 关键定值 | 状态 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| L3-1 | 三段式相间过流 | 相电流基波 > 定值,经延时出口;返回系数滞回 | Ⅰ/Ⅱ/Ⅲ 段电流 + 延时 | 🔶 2026-10-11 主机实现:`App/algo/prot_elm.c` 通用"滞回+定时限"核 + `prot_set.c` 定值(Ⅰ/Ⅱ/Ⅲ 段,A 相 `IA`),单测 27 用例含 1.01× 启动/100 ms 到点/滞回保持/返回释放;**板端接线已落地(B5,2026-10-12:protectTask 20 ms 节拍,动作经 104 YX16~18 上送)**;出口(L4)待做 |
|
||||
| L3-2 | 三段式零序过流 | 零序电流 > 定值,经延时出口 | Ⅰ/Ⅱ/Ⅲ 段零序电流 + 延时 | ⬜(N-18:`IN` 走 STM32,V0.2 使能;框架已就绪,加实例表一行即可) |
|
||||
| L3-2 | 三段式零序过流 | 零序电流 > 定值,经延时出口 | Ⅰ/Ⅱ/Ⅲ 段零序电流 + 延时 | ⬜(双转换器无共同采样触发:`IN` 走 STM32,V0.2 使能;框架已就绪,加实例表一行即可) |
|
||||
| L3-3 | 过负荷 | 相电流 > 定值,告警/跳闸可整定 | 过负荷电流 + 延时 | 🔶 同 L3-1(`OL-IA` 实例,默认告警不跳闸;板端接线随 B5 落地,YX23 上送) |
|
||||
| L3-4 | 过压 / 欠压 | 相/线电压越限,经延时出口 | 过压定值、失压定值 + 延时 | 🔶 同 L3-1(`OV-UA`/`UV-UA`,欠量方向单测覆盖;沿用参考告警段 0x8027/0x8029) |
|
||||
| L3-5 | 过频 / 低频 | 频率越限,经延时出口 | 过频、低频定值 + 延时 | ✅ 软件侧完成(B8,2026-10-12):`freq` 层测频(自适应窗,45~55 Hz 扫频最坏 **0.0101 Hz** / 1% 噪声 0.0160 Hz)+ `OF/UF` 实例(51.0/49.0 Hz、dly 1000 ms、返回系数 0.99/1.01,本地定值 8 项);OF/UF 暂无独立遥信点,动作仅经 YX15 总聚合可见(独立分点 + 注入验收 = B10) |
|
||||
| L3-6 | 零序过压 | 零序电压 > 定值 | 零序过压定值 + 延时 | 🔶 同 L3-1(`3U0-UN` 实例,外部零序电压通道,不受 N-18 限制) |
|
||||
| L3-6 | 零序过压 | 零序电压 > 定值 | 零序过压定值 + 延时 | 🔶 同 L3-1(`3U0-UN` 实例,外部零序电压通道,不受双转换器无共同采样触发限制) |
|
||||
|
||||
**扩展集(P2/P3)**
|
||||
|
||||
@@ -295,7 +295,7 @@
|
||||
| L3-11 | 故障启动(波形启动) | 突变量启动,触发录波/启动元件 | ⬜ |
|
||||
| L3-12 | 无压/无流闭锁 | 低电压或低电流时闭锁过流 | ⬜ |
|
||||
|
||||
**延后集(受 N-18 / 产品定义制约)**
|
||||
**延后集(受双转换器无共同采样触发 / 产品定义制约)**
|
||||
|
||||
| # | 元件 | 制约 |
|
||||
| --- | --- | --- |
|
||||
@@ -426,10 +426,10 @@
|
||||
| --- | --- | --- | --- |
|
||||
| AD 器件 | 专用同步采样 AD | TPAFE5160(16 位、8 通道同步、±5 V)+ STM32 ADC1(12 位、顺序、0~3.3 V) | 统一到"工程量"层,屏蔽码值差异 |
|
||||
| 通道数 | 8 实通道(4U+4I,自产零序) | 8 路电气量(4U+4I)+ 温度 | 语义映射见 `docs/硬件平台/ADC通道映射说明.md` |
|
||||
| 同一时刻性 | 单芯片同步 | **跨转换器无共同触发**(N-18) | V0.1 只做逐通道独立监视 |
|
||||
| 同一时刻性 | 单芯片同步 | **跨转换器无共同触发**(登记簿条目「双转换器无共同采样触发」) | V0.1 只做逐通道独立监视 |
|
||||
| 量程/精度 | 一致 | TPAFE LSB ≈ 152.6 µV vs STM32 LSB ≈ 806 µV | 同族量不可统一算法处理 |
|
||||
|
||||
### 6.2 N-18 影响与降级口径
|
||||
### 6.2 双转换器无共同采样触发:影响与降级口径
|
||||
|
||||
- **V0.1 现板**:主板侧只做**逐通道独立监视**(有效值/越限/温度);**禁止**跨转换器的同周期相位、功率、功率因数、矢量类运算。
|
||||
- **受影响功能**:方向元件、功率方向、差动类——延后(L3-13)。
|
||||
@@ -449,7 +449,7 @@
|
||||
- 参考:TLV13 选择映射表——外部零序(专用通道)或**自产零序**(`3I0 = Ia+Ib+Ic`)。
|
||||
- 本项目 V0.1 实况(**2026-10-10 更正**,此前"V0.1 无专用零序通道"的表述作废):
|
||||
- **有外部零序专用通道**——`UN`(零序电压,TPAFE)与 `IN`(零序电流,STM32 ADC),对应点表 `4014` / `4018`;
|
||||
- **自产零序在 V0.1 不可行**:`Ia` 在 TPAFE、`Ib`/`Ic` 在 STM32,求和属**跨转换器**(N-18)。
|
||||
- **自产零序在 V0.1 不可行**:`Ia` 在 TPAFE、`Ib`/`Ic` 在 STM32,求和属**跨转换器**(双转换器无共同采样触发)。
|
||||
- 于是本期:**零序过压**(`UN`,TPAFE,测量有效)可做;**零序过流**(`IN`,STM32 削顶 → 无有效值)不可做。
|
||||
- V0.2(8 路电气量全上 TPAFE)后可自产,外部/自产可切换(恢复 TLV13 语义)。
|
||||
- 落点:L1-8。
|
||||
@@ -477,7 +477,7 @@
|
||||
| **P4** | 出口、记录与定值集成 | L4 出口与记录、§5 定值模型落 cfg_file、UI 显示、上送 | P1 | 动作出口 + SOE 记录 + UI 显示闭环(**定值持久化 + 软压板 + 竞态收口 = B7 完成 2026-10-12,台架腿已验 ✅**;**SOE/动作记录 = B9 完成 2026-10-12 ✅**:protectTask 边沿→SPSC 环→defaultTask 落盘 `/log/soe.log`,protectTask 静态链 872 B 不变,自发 YX 上送 M_SP_TB_1 带时标;出口继电器 L4-1~L4-3 仍 ⬜——V0.1 无出口硬件,跳闸维持否定确认 R7 口径) |
|
||||
| **P5** | 方向/功率类(延后) | L3-13 方向元件等 | V0.2 硬件 / 子板计量 | 跨转换器相位一致后实现 |
|
||||
|
||||
> ⚠️ **V0.1 硬件裁剪**(2026-10-10,详见 §1.6):V0.1 上只有 TPAFE 三路(`UA`/`UN`/`IA`)测量有效。故 **P0 骨架全做**(与通道无关),**P1/P2 只做有效通道子集**——A 相过流、A 相过负荷、过压/欠压、零序过压、过频/低频;**三相过流(B/C 相)、零序过流、方向/功率类、PT/CT 断线**依赖 V0.2 硬件(N-18 修复 + 中点偏置),本期**建接口不使能**。
|
||||
> ⚠️ **V0.1 硬件裁剪**(2026-10-10,详见 §1.6):V0.1 上只有 TPAFE 三路(`UA`/`UN`/`IA`)测量有效。故 **P0 骨架全做**(与通道无关),**P1/P2 只做有效通道子集**——A 相过流、A 相过负荷、过压/欠压、零序过压、过频/低频;**三相过流(B/C 相)、零序过流、方向/功率类、PT/CT 断线**依赖 V0.2 硬件(修复「双转换器无共同采样触发」+ 中点偏置),本期**建接口不使能**。
|
||||
|
||||
### 7.2 每阶段交付物与验收判据
|
||||
|
||||
@@ -516,9 +516,9 @@ B0 产品定义 ✅(2026-10-10 已确认,见 §1.5)
|
||||
| L1 板端套件 | 采样/相量/保护元件 | `test/run_all_suites.py` 板端套件 |
|
||||
| L2/L3 台架 | 标准源注入、动作出口、时序 | 台架闭环(COM6 @115200) |
|
||||
|
||||
### 8.2 A-4 约束落实
|
||||
### 8.2 `docs/任务规划/测试与架构专项.md`「采集链路测试可验证性约束」落实
|
||||
|
||||
登记簿 **A-4** 对采集链路提出三条设计约束,保护层须一并满足:
|
||||
`docs/任务规划/测试与架构专项.md`「采集链路测试可验证性约束」对采集链路提出三条设计约束,保护层须一并满足:
|
||||
|
||||
1. **协议解析与硬件 I/O 分离**——保护判据函数只吃相量 + 定值,可单测;
|
||||
2. **采集缓冲双缓冲 + 序号**——防撕裂(单测测不出时序撕裂,须设计上消除);
|
||||
@@ -538,8 +538,8 @@ B0 产品定义 ✅(2026-10-10 已确认,见 §1.5)
|
||||
|
||||
| # | 风险 / 开放问题 | 影响 | 处置方向 |
|
||||
| --- | --- | --- | --- |
|
||||
| R1 | **V0.1 硬件裁剪保护范围**(N-18 + 无中点偏置 → 仅 TPAFE 三路 `UA`/`UN`/`IA` 测量有效) | 三相过流 / 零序过流 / 方向功率类本期无法闭环 | 本期做有效通道子集(§1.6);其余随 V0.2 硬件启用 |
|
||||
| R2 | **N-18 硬件缺陷** | 方向/功率/矢量类无法在 V0.1 实现 | V0.2 硬件改版;V0.1 取子板计量 |
|
||||
| R1 | **V0.1 硬件裁剪保护范围**(双转换器无共同采样触发 + 无中点偏置 → 仅 TPAFE 三路 `UA`/`UN`/`IA` 测量有效) | 三相过流 / 零序过流 / 方向功率类本期无法闭环 | 本期做有效通道子集(§1.6);其余随 V0.2 硬件启用 |
|
||||
| R2 | **双转换器无共同采样触发(硬件缺陷)** | 方向/功率/矢量类无法在 V0.1 实现 | V0.2 硬件改版;V0.1 取子板计量 |
|
||||
| R3 | **单核算力** | 1 ms 节拍内完成傅氏 + 全部保护元件 | 实测 CPU 余量;必要时裁剪遥测谐波轨或降低元件扫描频率 |
|
||||
| R4 | **等周波调频实现** | 频偏时精度不达标 | TIM 重装载调频;先固定 1000 Hz 跑通再上闭环 |
|
||||
| R5 | **STM32 侧无中点偏置** | 交流量负半周削顶,无法算 RMS | V0.1 只做监视;V0.2 补偏置 |
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
|
||||
两条边界是刻意的,破坏它们的代价写在右边:
|
||||
|
||||
1. **ISR 侧只加计数,不在中断里打日志**——FRSTDATA 异常只累计(E-44),帧序号只自增(E-45)。
|
||||
1. **ISR 侧只加计数,不在中断里打日志**——FRSTDATA 异常只累计,帧序号只自增。
|
||||
中断里做重活会直接推后下一拍采样,见 `docs/子系统设计/ADC采样节拍设计说明.md` §5。
|
||||
2. **判定层不许出现 HAL / 日志 / 取数**——`test/host/adc_health/adc_health_test.c` 用 `#include`
|
||||
原样纳入生产源文件、**零桩**跑全套。判定层里多一个 `DBG_ERROR`,主机侧就要为它写一份桩,
|
||||
@@ -283,7 +283,7 @@ else { 清电平位 } /* 只有 stall 类有 else 分支,SEQ_BACKWARD 没有
|
||||
|
||||
| 计数(快照字段) | 生产者 | 正常增量 | 出现增量意味着 | 事件位 | 锁存位 | 闭锁 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| `tpafe_frst_err` | TPAFE BUSY EXTI | 0 | 该帧 8 个通道不可信(FRSTDATA 无跳变,E-44) | `ADC_HE_FRSTDATA` | `ADC_HF_FRSTDATA` | 否 |
|
||||
| `tpafe_frst_err` | TPAFE BUSY EXTI | 0 | 该帧 8 个通道不可信(FRSTDATA 无跳变) | `ADC_HE_FRSTDATA` | `ADC_HF_FRSTDATA` | 否 |
|
||||
| `stm32_errs` | L1 消费侧 | 0 | 连续 >=2 拍无新帧,或 DMA 挂载失败 | `ADC_HE_STM32_ERR` | `ADC_HF_STM32_ERR` | 否 |
|
||||
| `stm32_gaps` | L1 消费侧 | 少量 | 超拍丢帧(§6.2) | `ADC_HE_STM32_GAP` | 不入锁存 | 否 |
|
||||
| `stm32_hw_errs` | HAL ADC/DMA 错误回调 | 0 | 硬件层面报过错 | `ADC_HE_HW_ERR` | `ADC_HF_HW_ERR` | 否 |
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
ADC1)、不做出口动作。
|
||||
- **这样分离换到什么**:`sample_ring` / `phasor` / `adc_health` / `prot_set` / `prot_elm` /
|
||||
`freq` **零平台依赖**(只用 `stdint.h` / `math.h` / `stddef.h` 与本目录头),因此可被主机侧
|
||||
单测以 `#include` 原样纳入、离线全覆盖(落实登记簿 **A-4**),不需要真机就能钉死判据。
|
||||
单测以 `#include` 原样纳入、离线全覆盖(落实 `docs/任务规划/测试与架构专项.md`「采集链路测试可验证性约束」),不需要真机就能钉死判据。
|
||||
- **上下文约束**:`*_init()` 一律无 RTOS 依赖、幂等,由 `app_main_init()` 在**内核启动前**调用;
|
||||
`adc_input_poll()` / `phasor_run()` / `freq_run()` **仅任务上下文**(快照走临界区)。
|
||||
- **消费者在 `App/task/`**:`adcTask` 采集并压环、`protectTask`(B5)跑 `prot_elm_run()`;
|
||||
@@ -85,7 +85,7 @@ flowchart TD
|
||||
|
||||
## 3. L1 语义取数 `adc_input.c`
|
||||
|
||||
**解决的问题**:V0.1 上 8 路电气量被两片转换器分片(硬件缺陷 **N-18**),且网名 `AINn`
|
||||
**解决的问题**:V0.1 上 8 路电气量被两片转换器分片(硬件缺陷**双转换器无共同采样触发**),且网名 `AINn`
|
||||
≠ 板级 `ADCn` ≠ 转换器通道号(17 路里 13 路置换)。消费侧若直接索引驱动缓冲,改版即全线错位。
|
||||
本层把"哪一路"收进一张表 `k_adc_map[]`,上层**按语义取数、不写死下标**。
|
||||
|
||||
@@ -105,7 +105,7 @@ flowchart TD
|
||||
- **STM32 侧是顺序扫描**(Rank1..8 = CH0..CH7、Rank9 = CH14,与 `MX_ADC1_Init()` 严格一致),
|
||||
9 个通道**不是同一时刻**(一轮 ≈67 µs);由 TIM3 TRGO 硬件触发 + DMA 自动搬运(
|
||||
`docs/子系统设计/ADC采样节拍设计说明.md` §4)。STM32 侧数据**固定滞后 1 拍(1 ms)**——与 TPAFE
|
||||
侧本来就没有同刻性(N-18),无新增误差。
|
||||
侧本来就没有同刻性(双转换器无共同采样触发),无新增误差。
|
||||
- **开机映射自检**挡住"映射到一个从不扫描的通道"这类静默错(启动日志 `ADC input layer init: OK`)。
|
||||
- 本文件是本层**唯一**允许出现 HAL 调用的地方;新增模块若不需要外设,请保持 `sample_ring` /
|
||||
`phasor` 那种零依赖形态,才能免桩单测。
|
||||
@@ -233,7 +233,7 @@ flowchart TD
|
||||
无有效波形(浮空 / PT 断线时 rms ≈ 0,相位无意义)→ 停止更新、`valid` 清零、读数保持,
|
||||
台架浮空因此**不发散**;信号刚消失的过渡段(≤20 ms 残窗)读数漂移有界 ≤0.3 Hz。
|
||||
- **源优先级 UA(C02) → IA(C01)**,按名前缀解析、每拍动态回退(台架只注电流也能测频);
|
||||
**源切换即废相位基准重建**——UA 与 IA 之间没有共同相位基准(N-18),跨源相位差无意义。
|
||||
**源切换即废相位基准重建**——UA 与 IA 之间没有共同相位基准(双转换器无共同采样触发),跨源相位差无意义。
|
||||
|
||||
### 7.2 精度判据(J1~J6,与 `test/host/freq/freq_test.c` 文件头同口径)
|
||||
|
||||
@@ -321,7 +321,7 @@ UA 无幅值落 IA → 0.0020 Hz。
|
||||
- 相量类**任一未就绪 → 整拍跳过**(不给判据喂陈旧值);
|
||||
- 频率类**无有效读数 → 按方向填"必不启动"值**(过量填 `0`、欠量填 `1e30` → 滞回比较恒假 →
|
||||
元件复位),**不整拍跳过**——频率源缺失不得饿死电流 / 电压类元件。
|
||||
- **V0.1 实例表**(受 N-18 约束):`OC1 / OC2 / OC3 / OL`(IA)、`OV / UV`(UA)、`3U0`
|
||||
- **V0.1 实例表**(受双转换器无共同采样触发约束):`OC1 / OC2 / OC3 / OL`(IA)、`OV / UV`(UA)、`3U0`
|
||||
(UN 外部通道)、`OF / UF`(`freq` 测频,B8)。**零序过流(IN 走 STM32)故意不在表中**
|
||||
——跨转换器不构成同刻矢量。
|
||||
- **OF / UF 的出口可见性**:两元件**未单独映射 104 遥信点**(送检点表口径见
|
||||
@@ -338,7 +338,7 @@ UA 无幅值落 IA → 0.0020 Hz。
|
||||
|
||||
1. **语义映射只有一处权威**:`docs/硬件平台/ADC通道映射说明.md`。取数一律经 `adc_input_raw()`,
|
||||
**禁止**在消费侧直接索引驱动缓冲或写死下标。
|
||||
2. **禁止跨转换器运算**(V0.1 硬件缺陷 **N-18**):`UA/UN/IA` 在 TPAFE、`UB/UC/IB/IC/IN` 在
|
||||
2. **禁止跨转换器运算**(V0.1 硬件缺陷**双转换器无共同采样触发**):`UA/UN/IA` 在 TPAFE、`UB/UC/IB/IC/IN` 在
|
||||
STM32 ADC1,两片转换器没有共同采样触发 → 无同一时刻性、相位不确定。故本层**不做**跨转换器的
|
||||
相位 / 功率 / 功率因数 / 负序零序类矢量运算;**8 路全接 TPAFE(V0.2 硬件)后方可解禁**。
|
||||
3. **标定折算已落地、精度复核未做**(2026-10-25 `App/algo/adc_cal`;标准源两点注入见
|
||||
|
||||
+156
-546
@@ -1,604 +1,224 @@
|
||||
# 编号规范
|
||||
# 编号规范:默认**不**用编号
|
||||
|
||||
> **适用对象**:本仓库全部 Markdown 文档、C/Python/脚本源码注释、提交信息中出现的**实体编号**(`E-44`、`N-21`、`TC-NET-601`、`FR-STO-1`、`Trap 07` 这类"字母 + 数字"的条目身份标识)。
|
||||
> **不适用**:C 语言标识符(`g_`/`s_`/`PS_*`/`TEST_SUITE_*`)、元器件位号(`U1`/`C12`/`R3`)、章节号(`§3.2`,归 [`docs/文档规范.md`](文档规范.md) §3.5 管)——见下文「划界」一节。
|
||||
> **强制程度**:§2~§5 为**强制**(由 `scripts/check_ids.py` 机械校验,§8 已落地 warn-only);§6~§10 为**约定 + 迁移计划**。
|
||||
> **相关文档**:[`docs/文档规范.md`](文档规范.md)(链接/章节/门禁总规范)、[`docs/任务规划/README.md`](任务规划/README.md) §0(本规范的登记簿摘要)、[`docs/测试说明/测试文档模板规范.md`](测试说明/测试文档模板规范.md) §6(测试侧编号细则)、[`docs/门禁说明/id-check.md`](门禁说明/id-check.md)(`id-check` 钩子逐项详解,含限制与盲区)。
|
||||
> **状态**:**§8 门禁已落地**(warn-only,含 `scripts/id_registry.json` / `scripts/id_aliases.json`,实测基线见 §8.1);§4 的目标前缀与 §7 的迁移映射在阶段 1 落地前**尚未生效**,落地进度见 §9。
|
||||
> **一句话:能把事实写清楚,就别发号。** 全项目允许使用「字母+数字」编号的族只有 **8 个**(§4.1),
|
||||
> 它们的共同点只有一个——**有脚本按字面量匹配它**。除此之外,一律写语义短语(§3.3)。
|
||||
>
|
||||
> 这条不是洁癖:规划 / 待办 / 审计 / 差距 / 阶段这些给人看的东西,历史上全发过号,也全都变成了
|
||||
> 没人认得的代号。2026-10-26 一天清了两批 + 本文瘦身,编号字面量 **10,956 → 8,230 处**(§8.1),清掉的号里
|
||||
> 绝大多数从来没被任何脚本读过一次。沿革与教训留在 §8.3 与 git log,正文不复述。
|
||||
>
|
||||
> **机器面才是事实源**:族注册表 `scripts/id_registry.json`、旧号别名 `scripts/id_aliases.json`、
|
||||
> 门禁 `scripts/check_ids.py`(八项校验,详解 `docs/门禁说明/id-check.md`)。本文与机器面冲突时
|
||||
> **以机器面为准,并回来改本文**。
|
||||
|
||||
---
|
||||
|
||||
## 1. 为什么要重写编号体系
|
||||
## 1. 决定要不要发号之前,先问三句
|
||||
|
||||
### 1.1 病根:前缀按"来源"分配,不按"事物类别"分配
|
||||
|
||||
每来一次审计/复审/专项,就自造一套前缀,字母很快瓜分殆尽:
|
||||
|
||||
| 来源 | 自造的前缀 |
|
||||
| 问自己 | 答"否"的结论 |
|
||||
|---|---|
|
||||
| 2026-09-21 错误码传播审计 | `E-xx`、缺陷模式 `P1~P9`、严重度 `P0~P2` |
|
||||
| 2026-09-15/09-21 代码审计 | `P0-x` ~ `P3-x`(严重度直接进编号) |
|
||||
| 2026-09 项目审查与优化建议报告(**2026-10-25 已删除**) | `N-xx`、`D-x`、`S-x`、`R-x`、`F-x`、`U1~U5`(六族属主文档已删,存量冻结作历史指称) |
|
||||
| 台架与长期观察 | `N-x`、`S-x`、`T-x`、`gen`、`round`、`V2/V4/V5` |
|
||||
| 2026-10-02 复审 | `S1~S14`、`A-1~A-7` |
|
||||
| 任务规划 | `W<n>`、`B\d`、`C\d`、`D\d`、`M\d` |
|
||||
| 各模块陷阱/设计文档 | `Trap NN`、`陷阱 N`、`D1~D10`、`O1~O6`、`U1~U15`、`①~④` |
|
||||
| 有脚本 / CI / 回归测试要按这个字面量做匹配吗? | **不发号**,写语义短语(§3.3) |
|
||||
| 现有文档或登记表里已经能指代这件事吗? | 引用它,别再发第二个号指同一件事 |
|
||||
| 一年后别人还能在属主登记表查到它的定义吗? | 查不到就别发——"先记着,以后再说"是编号失控的唯一来源 |
|
||||
|
||||
**后果**:同一字母被 3~5 个来源共用,编号本身不再能定位事物。
|
||||
三条硬规矩(对确实要发的号):
|
||||
|
||||
### 1.2 已确证的事故(全部有仓内证据,非假想)
|
||||
- **号不承载语义**:严重度、优先级、模块名、轮次都不写进号里。事实一变,号就开始撒谎。
|
||||
- **号不回收、不复用**:销项 = 删登记行 + 清掉所有引用 + 别名表标 `void`(§5.5)。历史上"销掉的号被
|
||||
重新取走"撞过两次。
|
||||
- **引用必须带语义**:号旁边要有人话,裸号不许独担信息(读者不该被迫查表才看懂一句话)。
|
||||
|
||||
| 类型 | 实锤 |
|
||||
|---|---|
|
||||
| **同字母多义** | `P1` 五义(缺陷模式 / 严重度 / 审计条目 `P1-8` / 用例优先级 / `ch395f_test_task.c` 的 Phase1 测试项 `P1-01`);`L1` 四义(算法层 / 测试分层 / UI 四层 / CubeMX 三层);`U1` 四义;`O4` 四篇文档四义 |
|
||||
| **同一文件内双义** | `实机测试实施指南.md` 的 `A2/A3/A4` 既是环境预检项(§2)又是已完成事项(§10) |
|
||||
| **连字符/补零偷偷承载语义** | `R1`=风险、`R-2`=内存优化项;`D7`=验证窗口、`D-7`=文档门禁、`D1~D7`=设计决策;`N-2`(登记簿)与 `N-02`(报告)同号不同义 |
|
||||
| **跨文档同号不同义** | `Trap 02` 在 CH395F 是"缓冲区重叠"、在 GD5F 是"测试缓冲越界";`B10` 在规划是"送检窗口"、在陷阱审计是"孤儿监听" |
|
||||
| **语义进编号 → 事实一变编号就撒谎** | `P1-x` 把严重度写进号里,而审计中大量条目事后降级(`E-59` P0→P1、dhara `is_free` P1→P2):改号则引用全断,不改则号实不符 |
|
||||
| **孤儿编号(代码有、文档无)** | `I-1`/`I-2`、`Task #32` 会话号、`P1-01~P1-09`、`TC-GD5F-1100/1101/1102`、`TC-STORAGE-06`、`TC-AH-*`、`TC-PE-*`(前两项项目已在 `docs/测试说明/实机测试实施指南.md` 自行承认) |
|
||||
| **悬空引用(引用了不存在的号)** | `Trap 19`(裸形;**当时的 NET 域在册表里没有这一号**——别误读成"这个坑不存在",2026-10-13 全库重排后该域确有 `TRAP-NET-19` 这条真实条目,两回事)曾被 `docs/测试说明/CH395F_Test_Guide.md` 引用;`N-5/N-8/N-19/N-30/N-31/N-32` 销项删行后仍被引用(`N-32` = 监听生命周期模块化,被 `docs/网络/` 三篇与代码注释多处引用) |
|
||||
| **同一事物多种字面** | `Trap 07` / `TRAP-07` / `陷阱 1`;`gen 181` / `gen-288` / `gen68`;`TC-NET-704` / `TC704` / `TC-203` |
|
||||
| **规范自身就不自洽** | `docs/测试说明/测试文档模板规范.md` §6.3 同一行并列 `TC-STORAGE-03`(2 位)与 `TC-RTC-001`(3 位);`docs/测试说明/测试文档模板规范.md` §6.2 已废止 `PHY` 模块码,而阶段 ID 至今仍是 `TM-PHY-01` |
|
||||
| **机器校验只覆盖一个族** | (2026-10-15 现状,2026-10-20 已由 §8.1 收口)当时 31 个 pre-commit 钩子中只有 `TC` 有 `scripts/check_test_traceability.py`,且**未挂钩子、warn-only、正则 `TC-[A-Za-z0-9]+-\d+` 匹配不到大写后缀形态**;`E/N/S/B/C/D/A/U/O/gen/Trap` 全部裸奔 |
|
||||
### 1.2 这四类事故就是上面三条的由来
|
||||
|
||||
> **可借鉴的先例**:`§N.M` 章节引用当年 1,578 处也全靠自觉,靠「紧邻写法 + 别名表 + 可判定比例 + 钩子」把可判定比例做到 58% 并转为拦提交([`docs/文档规范.md`](文档规范.md) §3.5)。编号走同一条路径即可收口。
|
||||
1. **同一字母多义**:`P1` 五义、`L1` 四义、`U1` 四义、`D7` 与元器件位号同形 → 前缀必须按**事物类别**
|
||||
分配(§2)。
|
||||
2. **属主文档一删,号全体成孤儿**:审计报告删除后,全仓几百处引用再也查不到定义 → 号越少,这种
|
||||
"集体失效"的爆炸半径越小(§4.5)。
|
||||
3. **语义塞进号里**:条目事后降级,改号则引用全断、不改则号实不符 → 号不承载语义(P-2)。
|
||||
4. **销项号被复用**:登记簿删行后仓库里毫无痕迹,下一个条目顺手取走同号 → 不回收、不复用,
|
||||
改用**语义标识**(短语自带唯一性)。
|
||||
|
||||
---
|
||||
|
||||
## 2. 八条设计原则(强制)
|
||||
## 2. 八条设计原则(一句话版)
|
||||
|
||||
| # | 原则 | 理由 |
|
||||
**P-8 语义优先**压过其余七条:**给人看的条目一律不发号**。其余七条只在"确实要发号"时生效——
|
||||
P-1 前缀 = 事物类别(不是来源文档 / 审计轮次)· P-2 号不承载语义 · P-3 一个事实一个号 ·
|
||||
P-4 规范形态唯一(连字符与补零不承载语义,写法只许一种)· P-5 只增不复用,新增先取游标 ·
|
||||
P-6 号必须能反查到定义(属主登记处得存在)· P-7 编号不语义、**引用必语义**。
|
||||
|
||||
---
|
||||
|
||||
## 3. 三种指代方式,按这个顺序挑
|
||||
|
||||
| 优先 | 方式 | 用在 |
|
||||
|---|---|---|
|
||||
| **P-1** | **前缀 = 事物类别,不是来源文档/审计轮次**。来源是登记簿的「出处」列,不进编号 | 否则每轮审计都造一套新字母,必然瓜分殆尽 |
|
||||
| **P-2** | **编号不携带语义**:严重度、状态、日期、负责人、波次一律是表格列 | 降级只改列,编号永不变、引用永不断(`P1-x` 的历史教训) |
|
||||
| **P-3** | **一个前缀只有一个属主登记处**;前缀一经分配**永不复用给别类**,号段用尽即扩位(`N-99`→`N-100`),绝不换字母 | 保证"看到前缀就知道去哪张表查" |
|
||||
| **P-4** | **形态唯一**:`<前缀>-<序号>`;前缀 1~3 位大写字母;序号位数按类别固定并左补零;子项只允许一级 `-<小写字母>`。**禁止**裸形(`S3`)、空格形(`Trap 07`)、中文形(`陷阱 1`)、圈号(`①②③④`) | 连字符与补零不得承载语义;字面唯一才能被机器判定 |
|
||||
| **P-5** | **只增不复用**;每个类别有「下一个可用号」游标(`scripts/id_registry.json`,§8.1 已落地),新增先取游标 | 并行任务与多文档同时新增时防撞号(《项目审查与优化建议报告》与登记簿并轨时 `N-16` 撞过号,就是没有游标——见 `docs/任务规划/README.md` §0) |
|
||||
| **P-6** | **引用必须机器可判定**:跨文档引用用行内代码,首次出现紧邻属主文档名;文档内编号**必须**带文档名 | 与 `§N.M` 同一条路:能校验的约定才算存在 |
|
||||
| **P-7** | **编号不语义,引用必语义**:编号本体保持无语义并冻结(同 P-2);但**正文引用必须带语义括注**——`TRAP-NET-18(异常释放后排空 RX 残渣)`、`docs/网络/网络自愈架构设计.md` §4.6(应用主动拆会话保监听);**禁止裸 ID 单独承担信息**。语义放括注,事实变了只改括注、编号不变 | 读者不该为看懂一句话去跳三篇文档。可读性由**引用方式**解决,不由**编号命名**解决——命名带语义会重蹈 `P1-x` 覆辙(§1.2)。落地见 §5.6 |
|
||||
| **P-8** | **语义优先**:规划 / 待办类条目**优先用语义标识**(§3.3)——一行短语即标识,不分配字母+数字号;只有**需机器解析**或**作历史证词**的类别才发编号,且引用时强制带语义括注(P-7) | 编号的唯一性维护成本已实测超过收益:`N-31` 销项删行后按"现存最大值 +1"又被取走,与两处历史引用撞号(`docs/任务规划/README.md` §0)。短语自带唯一性(重名一眼可见),且读者不必跳表查号 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 主轴:编号 / 语义标识 / 章节引用
|
||||
|
||||
| 层 | 适用事物 | 形态 | 引用规则 | 门禁校验 |
|
||||
|---|---|---|---|---|
|
||||
| **全局编号** | 会跨文档流转:需求、缺陷、待办、决策、风险、测试用例、陷阱记录 | 全局唯一前缀 + 全局序号 + **唯一属主登记处** | 行内代码;跨文档首次出现紧邻属主名 | 全库唯一;必须能在属主表查到定义行 |
|
||||
| **文档内编号** | 只在定义它的那篇文档内有意义:状态机组合、方案档位、专项风险、专项阶段 | 允许存在,前缀带类别码,**号段文档内独立** | **必须紧邻文档名**(同 `§N.M` 紧邻规则) | 校验"该文档内确有此编号" |
|
||||
| **语义标识**(§3.3,**规划 / 待办类默认**) | 登记簿条目、任务卡、待确认、风险、决策、缺陷、工作项、差距、验证场景 | **一行短语即标识**,不分配字母+数字号;≤20 汉字 | 同文档内写短语;跨文档紧邻属主文档名 | 同表内去重(同义异写算撞名);引用查不到 = 悬空 |
|
||||
| ① 最好 | **语义短语** | 规划 / 待办 / 缺陷 / 风险 / 决策 / 差距 / 文档内步骤与阶段——**默认形态** |
|
||||
| ② 其次 | **文档名 + 章节号** | 指某篇文档的某节(`docs/网络/网络自愈架构设计.md` §4.10,紧邻写法) |
|
||||
| ③ 最后 | **编号** | 只有 §4.1 那 8 个族,且必须能反查到定义 |
|
||||
|
||||
### 3.1 判定口诀
|
||||
|
||||
> **会不会在别的文档里被引用?会 → 全局编号;不会 → 文档内编号,且引用必须带文档名。**
|
||||
>
|
||||
> **前置一步(P-8)**:规划 / 待办类条目先问"能不能用一行短语说清是什么事"——
|
||||
> **能 → 用语义标识(§3.3),不发编号**;只有需机器解析(`TC`)或作历史证词(`TRAP`)才进上面的判定。
|
||||
|
||||
现状的病根正是把该全局的(发现、待办)做成了文档内编号(各文档自造 `O1~O4`、`A1~A6`),又把该文档内的(设计决策 `D1~D7`、状态机 `U1~U15`)做成了裸形全局编号。
|
||||
**机器读 → 发号;人读 → 写短语。** 拿不准就写短语:短语看不懂还能靠上下文猜,号看不懂只能去查表。
|
||||
|
||||
### 3.2 编号 vs 章节引用
|
||||
章节引用不是编号,但同样要**紧邻文档名**——只写「`§` + 小节号」而不写文档名,会被 doc-links 当成本文自引用而静默放过,
|
||||
这是它的已知盲区,别踩。
|
||||
|
||||
| 条目特征 | 用什么 |
|
||||
|---|---|
|
||||
| 会增删、会重排、只是"读第几条" | **章节引用** `` `docs/xxx.md` §N.M ``(不造编号) |
|
||||
| 需要稳定身份(要销项、要被代码引用、要跨文档追溯) | **编号** |
|
||||
### 3.3 语义标识(默认形态,怎么写)
|
||||
|
||||
各设计文档的"本期不做 / 遗留可选项"清单(现状 `O1~O4` 四篇文档四义)**默认不造编号**,改用 §小节引用;确需逐条引用时才启用文档内编号 `OOS-<nn>`。
|
||||
|
||||
### 3.3 语义标识(新条目默认形态)
|
||||
|
||||
> **立场**:编号是"确需跨文档长期引用"才付的成本(§5.1 第 0 步)。规划与待办类条目
|
||||
> 生命周期短、销项即删行,编号带来的唯一性维护成本已实测超过收益——`N-31` 销项删行后
|
||||
> 按"现存最大值 +1"又被取走,与两处历史引用撞号(详见 `docs/任务规划/README.md` §0)。
|
||||
> **这类条目改用语义标识:一行短语本身就是标识,不再分配字母+数字号。**(原则见 P-8)
|
||||
|
||||
**形态规则**(强制):
|
||||
|
||||
| 项 | 规则 |
|
||||
|---|---|
|
||||
| 构成 | 主语 + 症状/动作,直接说清是什么事:`49s 日志静默`、`USART1 TX-only 根治`、`dhara is_free/copy 判据` |
|
||||
| 长度 | **≤20 个汉字**(或 ≤40 个 ASCII 字符),一行写完 |
|
||||
| 禁用 | 不含 `\|`(表格安全)、不换行、不以 `-` 结尾、不带序号后缀(`日志静默-1` 非法) |
|
||||
| 不含易变属性 | 严重度、状态、日期、负责人、波次一律写进表格列,不进标识(同 P-2) |
|
||||
| 唯一性 | 同一属主登记处内唯一;**同义异写视为撞名**(`日志静默` 与 `49s 日志静默` 只能留一条) |
|
||||
| 冻结 | 措辞一经登记即**冻结**;确需改写在原行加"别名"列,旧措辞保留可查(§5.7) |
|
||||
|
||||
**适用分界**(强制):
|
||||
|
||||
| 域 | 条目 | 标识形态 |
|
||||
|---|---|---|
|
||||
| **规划 / 待办**(转语义) | 登记簿条目(原 `N-x` / `S-x` / `T-x`)、排期任务卡(原 `B` / `C` / `D`)、待确认(`OQ`)、风险(`RSK`)、决策(`DR`)、缺陷(`DEF`)、工作项(`WI`)、模拟器差距(`GAP`)、验证场景(`SC`) | **语义标识** |
|
||||
| **机器解析 / 历史证词**(保留编号) | `TC-*`、`TRAP-*`、`FR-*` / `NFR-*`、`RC-*` | **编号 + 强制语义括注**(P-7) |
|
||||
| **历史冻结族**(§4.3) | `E-xx`、报告自有编号、`S1~S14`、`A-1~A-7`、`P0-x`~`P3-x` | 不回改,走别名表 |
|
||||
|
||||
> ⚠ **为什么 `TC-*` 不能转语义**(硬约束,勿试):`scripts/check_test_traceability.py`
|
||||
> 用 `TC-[A-Z]{1,4}-\d{3,4}` 做可追溯性比对;`test/host/ch395f_socket_test.py` 把
|
||||
> `TC-NET-602` 打进运行日志;板级 `test/board/ch395f_test_task.c` 直接把它编进 C 宏名
|
||||
> `PHASE2_TC203_TIMEOUT_MS`。语义短语进不了宏名,也做不了正则排序。
|
||||
> `TRAP-*` 同理不转:196 处文档 + 122 处代码引用,是历史证词的高频锚点。
|
||||
|
||||
**引用写法**:
|
||||
|
||||
| 场景 | 写法 |
|
||||
|---|---|
|
||||
| 登记处表内 | `` `49s 日志静默` ``(`#` 列填短语本身,不再填号) |
|
||||
| 跨文档 | `` `docs/任务规划/登记簿.md` 的 `49s 日志静默` ``(紧邻文档名,同 §N.M 规则) |
|
||||
| 代码注释 | 允许,但**必须带属主文档名**(同 §5.3),如:(登记簿 `8 路电气量分属两片转换器`) |
|
||||
| 销项 | 删行 + 清全库引用;短语**不复用**(同"号不回收",见 §5.7) |
|
||||
- 一行短语就是标识:≤20 汉字、说清"是什么事"、**同一登记表内不撞名**(同义异写算撞名)。
|
||||
- 好的例子:`双转换器无共同采样触发`、`FTP 鉴权`、`写回缓存空闲 flush`、`L5 队列往返基线待重验`。
|
||||
坏的例子:`优化项 3`、`遗留问题`、`重要缺陷`——换个上下文就指代不明,等于又造了个号。
|
||||
- 登记处就是那张表:表首格写短语,**不要再配一个字母号**;跨文档引用写成
|
||||
`` `docs/任务规划/登记簿.md` 「双转换器无共同采样触发」 ``,同篇后续直接用短语。
|
||||
- 文档内的实施步骤 / 测试阶段 / 设计原则条目写中文:「步骤 3」「阶段 7」「DMA 边界安全」,
|
||||
**不写 `S3` / `TM-PHY-01` / `DP-03` 这种号**。
|
||||
|
||||
---
|
||||
|
||||
## 4. 编号空间总表
|
||||
## 4. 编号空间
|
||||
|
||||
### 4.1 在册保留(零改写,仅补规则)
|
||||
### 4.1 允许用号的族(**穷举**——这张表以外一律不许发号)
|
||||
|
||||
| 前缀(正则) | 类别 | 属主登记处 | 游标/规则 |
|
||||
| 族 | 形态 | 属主登记处(定义在哪查) | 为什么必须是号 |
|
||||
|---|---|---|---|
|
||||
| `FR-[A-Z0-9]+-\d{2}` | 功能需求 | `docs/产品需求/产品需求设计文档.md` §5 | 各域独立递增;**新增域写进该文 §1.2 术语与缩写** |
|
||||
| `NFR-[A-Z0-9]+-\d{2}` | 非功能需求(**新建**,现 §7 全是散文无号) | `docs/产品需求/产品需求设计文档.md` §7 | 从 `NFR-<域>-01` 起 |
|
||||
| `N-\d{1,3}[a-z]?` | **登记簿条目**(技术债 / 长期观察 / 硬件改版项;含义由"网络项"重定义) | `docs/任务规划/登记簿.md` | **曾用**最大 `N-33`(`N-30`~`N-33` 均已销项、登记簿行已删,**现存至 `N-29`**)→ 游标 `N-34`(号不回收);原 `S-x`/`T-x` 并入本族(§7.1)。⚠ 实测另有报告侧补零带子项后缀的 `N-03a`/`N-03c` 与 §5.5 的扩位示例 `N-100` → 位数收到 3、允许小写子项后缀 |
|
||||
| `E-\d{1,2}` | 错误码/返回值传播审计发现 | 无(原属主 `docs/问题记录/错误码传播审计.md` 已于 2026-10-15 删除) | **冻结**:`E-63` 为最大号,**不再新增**;新发现一律 `DEF`;现存引用仅作历史指称(§4.3)。⚠ 属主已删 → 该族**无法判定义存在与否**,门禁只拦越游标(§8.1) |
|
||||
| `E\d+` | **自愈实验编号**(N34 台架实验,**无连字符**) | `docs/网络/网络自愈架构设计.md` §5.2 | ⚠ 规范原记「已封闭 `E0`~`E15`」,**实测该表已到 `E19`**(E16~E19 是其后追加)→ 游标按实测 `E19` 收录,封闭线待订。⚠ 与上一行靠**连字符**区分:带连字符 = 审计发现 |
|
||||
| `TC-[A-Z][A-Z0-9]{0,4}-\d{1,4}[a-z]?` | 测试用例 | 各测试文档 | 3 位起;分阶段套件序号 = 阶段号×100 + 项号(阶段 ≥10 自然进位 4 位,`TC-NET-1001` 合规);后缀只允许 `-<小写字母>`。⚠ 模块码 `GD5F`/`I104` **含数字**,规范原写的 `[A-Z]{1,4}` 会整族漏掉 GD5F(实测 285 处)→ 已按实测放宽 |
|
||||
| `F-<MOD>-<nn>` | **net / 驱动侧功能与改进项**(`F-NET-2~17`、`F-DRV-*`、`F-MS-*`) | `docs/网络/网络自愈架构设计.md` | 2026-10-20 补行:本族**早就在被代码注释大量引用**(实测 60+ 处)而总表里没有——正是 §5.1 第 1 步"表里没有的类别先改本规范"的适用对象;`id-check` 落地时按实测收编 |
|
||||
| `P-<n>` | **本规范的设计原则条目**(`P-1`~`P-8`) | 本文档 §2 | 2026-10-20 补行;⚠ 与档位词 `P0~P3`(§4.4)、审计条目 `P0-x`(§4.3)靠**连字符**区分,三者形态互斥 |
|
||||
| `CODE-RULE-<nn>` | **嵌入式 C 代码规范条款号**(配原文章节号,如 `CODE-RULE-03 (3.4.1)`) | `scripts/check_coding_standard.py`(规则表 = 单一事实源) | 2026-10-20 批 1 新建:原名是裸形 `S1`~`S19`,与登记簿 `S-x`、UI 像素状态、2026-10-02 复审专项条目**四义撞形**(§1.2)→ 单词化改名,旧号进 `id_aliases.json` 的 **scoped** 条目。⚠ `S14` 历史上不存在,空洞不复用 → 游标 19 |
|
||||
| `MENU-STATE-<nn>` | **UI 菜单像素回归状态号**(按键序列状态,共 8 态) | `simulator/tests/check_menu_rows.py` 的 `STATES` 表 | 2026-10-20 批 1 新建:原名裸形 `S0`~`S7`(同上撞形);**冻结在 07**,加状态须先改本族游标 |
|
||||
| `TM-[A-Z]{1,4}-\d{2}` | 测试阶段 | 各测试文档 | 模块码取 §6 统一表(`TM-PHY-01` → `TM-NET-01`) |
|
||||
| `DP-[A-Z]{1,4}-\d{2}` | 设计原则 | 各测试文档 | **加模块码**(现 `DP-01` 跨文档会撞) |
|
||||
| `L\d` / `L\d-\d{1,2}` | 采集与保护分层、层内条目 | `docs/算法/继电保护功能复现规划.md` §3 | 保留(代码侧 141 处引用,是全项目最规范的一族,作样板);`L` 前缀**专属**此族 |
|
||||
| `W\d+` | 波次 | `docs/任务规划/README.md` §2.0 | **2026-10-25 废止**:波次改用语义名,理由见该文档 §2.0;游标冻结 `W8`,存量仅作历史指称;子任务卡不再用 `W1-0` 形态(并入 `WI`) |
|
||||
| `TC-*` | `TC-<模块码>-<序号>` | `docs/测试说明/*_Test_Guide.md`、`test/host/<模块>/*`(代码即登记处) | 用例↔断言双向追溯,要进 C 断言标签 |
|
||||
| `TRAP-*` | `TRAP-<域>-<nn>` | `docs/问题记录/*_Trap_Records.md` | 踩坑证词的永久锚点,代码注释反查 |
|
||||
| `L<n>-<nn>` | 保护功能号 | `docs/算法/继电保护功能复现规划.md` | 全库唯一"定义与引用都齐"的样板族 |
|
||||
| `F-<MOD>-<nn>` | 功能项 | `docs/网络/网络自愈架构设计.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>` | **本文的设计原则** | 本文 §2 | 就是本文自己的条目 |
|
||||
|
||||
### 4.2 目标前缀(阶段 1 改名后启用)
|
||||
- **新增族的唯一正当条件**:有脚本要按字面量匹配它。顺序固定:先改 `id_registry.json`(含属主登记处)
|
||||
→ 再写属主文档 → 最后才允许在别处引用。反过来做必然造出悬空号。
|
||||
- 模块码是既定缩写,事实源 = registry 的族 pattern 与属主文档标题行,**别自创**(§6)。
|
||||
|
||||
> **2026-10-15 修订(依 P-8 / §3.3)**:本表中**规划 / 待办类**前缀在阶段 1 落地时改为
|
||||
> **语义标识**形态(不再分配序号)——`DEF` / `WI` / `OQ` / `RSK` / `DR` / `MS` / `GAP` / `SC`;
|
||||
> **需机器解析或作历史证词**的保留编号——`TC` / `TM` / `DP` / `TRAP` / `FR` / `NFR` /
|
||||
> `RC` / `GEN` / `RUN`,引用时强制带语义括注(P-7)。下表的"游标"列对转语义的前缀不再适用。
|
||||
### 4.1.1 已停发的族(别再指,更别再"复用"这些号)
|
||||
|
||||
| 新前缀 | 类别 | 收编的旧编号 | 新属主登记处 | 游标 |
|
||||
|---|---|---|---|---|
|
||||
| `DEF-<nnn>` | 缺陷 / 问题发现 | `P0-x`~`P3-x`(在册项)、新发现 | `[计划] docs/问题记录/缺陷登记簿.md` | `DEF-001` |
|
||||
| `WI-<nnn>` | 工作项 / 任务卡 | `B\d`(功能主线)、`C\d`(结构债)、`D\d`(验证窗口)、`W1-0`、`S1~S14`、`A-1~A-7`、`P1-10`、报告 `R-x`(内存优化)、`F-x`、`U1~U5` 的未闭环项 | `docs/任务规划/` 波次与排期文件(类别做列) | `WI-001` |
|
||||
| `DR-<nnn>` | 决策记录 | `docs/网络/网络自愈架构设计.md` 的 `D1~D7` | `[计划] docs/架构设计/决策记录登记簿.md` | `DR-001` |
|
||||
| `OQ-<nnn>` | 待确认 / 开放问题 | `B0-a/b/c`、`待确认-N` | `docs/任务规划/基线与待确认.md` | `OQ-001` |
|
||||
| `RSK-<nn>` | 风险(**文档内编号**) | 保护规划 `R1~R8`、看门狗 `R1~R7` | 各文档风险表(引用必须带文档名) | 各文档自 `RSK-01` |
|
||||
| `TRAP-<MOD>-<nn>` | 陷阱记录 | `Trap 07`、`TRAP-07`、`陷阱 1` | `docs/问题记录/<模块>_Trap_Records.md` | 保留原号(`TRAP-NET-01~21`——NET 域 2026-10-13 全库迁移并重排连续,沿革见该文档、`TRAP-GD5F-01~06`、`TRAP-RTC-01~`) |
|
||||
| `GAP-<nn>` | 模拟器差距 | `H-1~H-7`、`L-1~L-4`、差距清单 `N-1~N-6` | `docs/测试说明/模拟器差距清单.md` | `GAP-01` |
|
||||
| `SC-<nn>` | 实机验证场景 | 实机预检 `A1~A8`、看门狗验证用例 `V2/V4/V5` | `docs/测试说明/实机测试实施指南.md` | `SC-01` |
|
||||
| `T0/T0.5/T1/T2/T3` | **测试分层**(原 `L0/L0.5/L1/L2/L3`) | 测试分层五档 | `docs/测试说明/测试开发标准流程.md` §1 | 固定五档 |
|
||||
| `G0/G0.5/G1/G2/G3` | **门禁**(必跑清单,与测试分层是两套,不合并) | 现门禁决策表 `G0~G3` | `docs/测试说明/测试开发标准流程.md` §1.1 | 固定 |
|
||||
| `GEN-<nnn>` | 台架日志代次 | `gen 181`、`gen-288`、`gen68` | `docs/测试说明/串口助手设计说明.md` | 数字不变,仅改字面 |
|
||||
| `RUN-<yyyymmdd>-<n>` | 台架轮次 | `round 1~9` | `docs/测试说明/实机测试实施指南.md` | 日期制 |
|
||||
| `MS-<nn>` | 里程碑 | `M1~M3` | 波次文件 | `MS-01` |
|
||||
| `RC-<nn>` | net 周期对账类型 | `①②③④⑤`(唯一被代码逻辑引用的圈号链) | `docs/网络/网络自愈架构设计.md` | `RC-01`~`RC-05` |
|
||||
| `PAT-<nn>` | 缺陷模式(九类) | 原 `docs/问题记录/错误码传播审计.md` §1.1 的 `P1~P9`(该文档已删除,定义迁至本文档 §4.2.1) | 本文档 §4.2.1 | `PAT-01`~`PAT-09` |
|
||||
| `ST-<n>` | 专项内部实施阶段(**文档内编号**) | 保护规划 §7.1 的 `P0~P5`、方案阶段 `P0~P3` | 各专项文档 | 各文档自 `ST-0` |
|
||||
| `UL-<n>` | UI 标准化四层(**文档内编号**) | 报告 UI 四层 `L0~L3` | `docs/UI设计/UI_设计架构.md` | `UL-0` |
|
||||
| `LAT-<nn>` | 链路延迟分段(**文档内编号**) | `docs/测试说明/链路延迟测试说明.md` 的 `L1~L11` | 同文 | `LAT-01` |
|
||||
| `CS-<n>` | CubeMX 定制存活三层 | `AGENTS.md` 的 `L1 写进 .ioc → L2 USER CODE → L3 审计` | `docs/子系统设计/看门狗设计说明.md` §10 | `CS-1`~`CS-3` |
|
||||
| 停发族 | 现在怎么写 | 旧号去哪查 |
|
||||
|---|---|---|
|
||||
| 登记簿 `N-x` / `S-x` / `T-x`、专项 `A-x`、已删报告的 UI 簇 `U1~U5`(2026-10-26 方案 B) | 语义短语——**登记簿表首格本身就是短语**,如「双转换器无共同采样触发」「CI 远端闭环未验证」 | `scripts/id_aliases.json` 标 `retired-to-phrase` |
|
||||
| `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` 等) | 同上,写事实 | 无定义,本就不该存在 |
|
||||
|
||||
#### 4.2.1 缺陷模式定义(`PAT-01`~`PAT-09`)
|
||||
> 想知道某个号还活着吗:跑 `scripts/check_ids.py --top 0`,或直接查 `id_aliases.json`——命中 `void` /
|
||||
> `retired-to-phrase` 就是死号。**看到查不到的号,正确动作是删号留事实,不是补一个定义。**
|
||||
|
||||
2026-10-15 由已删除的 `docs/问题记录/错误码传播审计.md` §1.1 迁入(原编号 `P1`~`P9`,与发现编号 `E-xx` 区分)。
|
||||
新发现归入 `DEF-<nnn>` 时,"缺陷模式"列仍按本表取值:
|
||||
|
||||
| 模式 | 名字 | 一句话 | 典型症状 |
|
||||
|---|---|---|---|
|
||||
| **PAT-01** | 值拷贝队列陷阱 | 消息体按值拷进队列,netTask 修改的是**副本**,调用方看不到 | 回传字段恒为初始值 |
|
||||
| **PAT-02** | 共享全局错误变量竞态 | 全局 `errno` 被多任务交错覆写 | 报出别人的错误码 |
|
||||
| **PAT-03** | 返回值与错误码混同 | "0 = 成功"其实是"命令已发出";成功路径不清 errno | 失败被当成功 |
|
||||
| **PAT-04** | 返回值未检查 | `HAL_*` / 库函数返回被丢弃 | 失败静默继续 |
|
||||
| **PAT-05** | 事件标志语义 | 状态位被当作命令位消费掉 | 等待者永不唤醒 |
|
||||
| **PAT-06** | 通知值宽度与符号 | 32 位通知值装不下 / 符号位被当成数据 | 大长度变负数 |
|
||||
| **PAT-07** | ISR 与跨上下文共享状态 | ISR 写、任务读,无同步 | 读到半包 / 撕裂 |
|
||||
| **PAT-08** | 外设 / 库特定约定 | 该外设 / 该移植版特有的规则 | 照抄上游示例即错 |
|
||||
| **PAT-09** | 超时与错误混同 | 超时用同一个码表达,调用方无法区分 | 无法复位 / 无法重试 |
|
||||
### 4.2 目标前缀(作废)
|
||||
2026-10-26 删除:那批"改名后才启用"的前缀族从未有属主登记处,留着只会把读者带到一张不存在的登记表前。
|
||||
|
||||
### 4.3 冻结前缀(历史快照,正文不回改)
|
||||
族还在注册表里、但属主登记处已删的:**只为让冻结历史行不报"未登记前缀"而保留登记**,游标一律冻结,
|
||||
不得新增、不得复用。
|
||||
|
||||
| 冻结对象 | 处置 |
|
||||
|---|---|
|
||||
| `E-<nn>` | 冻结于 `E-63`;引用照旧,**禁止新增**;门禁拒绝游标之外的新 E 号 |
|
||||
| 《项目审查与优化建议报告》自造的 `N-xx`/`D-x`/`S-x`/`R-x`/`F-x`/`U1~U5`(**该报告 2026-10-25 已删除**) | 报告是历史基线,**不回改**;引用一律紧邻文档名;未闭环项已并轨进 `N-19~N-29`,出处列保留报告编号。六族在 `id_registry.json` 里 `owner_docs` 已清空、`check_dangling` 关闭(§4.3) |
|
||||
| `docs/问题记录/CH395F_Trap_Records.md` 2026-10-11 审计的 `A1~A6`/`B1~B10` | 该表是审计快照(条目已修复或推翻),**冻结**;新发现进 `DEF`;引用紧邻文档名 |
|
||||
| `P0-x`~`P3-x` | 在册项迁 `DEF`;已闭环项留在历史文档,走别名表 |
|
||||
| `Task #32` 等会话临时号 | **禁止入册**;现存引用(`Src/main.c`、`Drivers/BSP/UI/ui_net_sink.c` 的 `I-1/I-2`)改写为可解析形式或就地展开成事实描述 |
|
||||
### 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`。
|
||||
判据只有一条:**带连字符、且能在属主登记表查到定义**才叫编号;查不到的就是普通文本,不是"漏登记的号"。
|
||||
|
||||
### 4.4 划界:这些不是编号,不受本规范管
|
||||
|
||||
| 对象 | 例子 | 归属 |
|
||||
|---|---|---|
|
||||
| C 标识符 | `PS_OC1_EN`、`TEST_SUITE_STORAGE`、`ENABLE_PHASE14_TESTS`、`SYS_EVT_NET_READY`、`TASK_WD_ADC` | `docs/代码规范/嵌入式C语言代码规范_V1.0.md` |
|
||||
| 元器件位号 | `U1`、`C12`、`R3`、`L5`、`D7`(`docs/硬件平台/`、`docs/芯片手册/`) | **门禁与改写脚本一律排除**,这是最大误伤风险源 |
|
||||
| 章节号 | `§3.2` | `docs/文档规范.md` §3.5 |
|
||||
| **档位词** | `P0`/`P1`/`P2`/`P3`(严重度、用例优先级) | 允许继续使用,但**永不带 `-<数字>` 后缀**——`P1-8` 这类形态一律非法 |
|
||||
| 图元 id | `README.md` 架构图 Mermaid 节点 `A1`/`B1`/`C1`/`D2` | 改描述性 id(`net`/`sto`/`ui`),避免与条目字面撞名 |
|
||||
| 运行时计数 | 网络代次号 `net_get_generation()` | 代码概念;与台架 `GEN` 是两回事,文档里须写全"网络代次号" |
|
||||
|
||||
### 4.5 报告自有编号族登记处(属主文档 2026-10-25 已删,本表是唯一登记处)
|
||||
|
||||
> 《项目审查与优化建议报告》(原 `docs/问题记录/项目审查与优化建议报告.md`)已于 **2026-10-25 删除**,
|
||||
> 但它自造的 6 个编号族(`N-xx` / `D-x` / `S-x` / `R-x` / `F-x` / `U1~U5`)在全仓仍有大量**历史指称**。
|
||||
> 本节承接原报告 §9 的登记职责,`scripts/id_registry.json` 里这 6 族的 `owner_docs` 就指向本节。
|
||||
>
|
||||
> - 六族**一律冻结**:不再新增号,新条目用语义标识(§3.3)。
|
||||
> - 引用时仍**必须紧邻文档名或「报告」字样**(`原报告 N-14`、`报告 F-5`)——它们与登记簿的
|
||||
> `N-x` / `S-x` / `D-x` **同字母不同义**(原报告 N-16 = 日志逐条开关,登记簿 N-16 = A2/A4 负向台架)。
|
||||
> - 未闭环项早已并轨到 `docs/任务规划/登记簿.md` 的 `N-19`~`N-29` 与 U 簇,出处列保留报告编号。
|
||||
>
|
||||
> **⚠ 本节的登记处身份只恢复「可判定比例」,不构成定义集。** 规范正文混着大量写法示例
|
||||
> (`N-99`、`S1`、`N-31`),若让本节进定义集会同时打穿两条判定:裸形 `S1` 被判成 `S-1` 漏连字符、
|
||||
> 本节表里的 `S-3` 与登记簿 S-3 被判重复定义。因此 `check_ids.py` 对 `snapshot_only` 族另设
|
||||
> `_def_owners`(剔除规范正文)——本表是**存档**,悬空/撞号/裸形一律不拿它当依据。
|
||||
>
|
||||
> **⚠ 11 个已死号另有别名登记**(`scripts/id_aliases.json`,`status: void`):`N-03b` / `N-10` / `N-11` /
|
||||
> `N-12` / `N-13` / `N-20` / `N-21` / `N-24` / `N-26` / `S-1` / `S-2`。它们被代码注释与文档广泛引用
|
||||
> (`nand_port_test.c`、`sys_log_mcu.c`、`nand_ftl.c`、`gd5f2gq5ue.h` 等约 110 处),原先是靠"报告里
|
||||
> 顺带提过一句"才算有定义——报告一删就集体悬空。别名表逐条写明它们现在详述于哪篇文档,这也正是
|
||||
> 原报告「去处表」的内容。其中 `N-21` / `S-1` / `S-2` **一号两义**(登记簿与原报告各有一个),
|
||||
> 别名注记里已分别标明。
|
||||
|
||||
|
||||
| 号 | 事项 | 状态 | 现在详述于 |
|
||||
|---|---|---|---|
|
||||
| N-01 | 配置引擎整文件驻留 | ✅ 已修(流式列为后续项) | `docs/子系统设计/配置文件设计说明.md` §6.2/§8 |
|
||||
| N-02 / N-03 / N-03a / N-03b / N-03c | 存储与日志取证类条目 | ✅ 已闭环 | `docs/架构设计/STM32F4-Base存储架构说明.md` §10.1 |
|
||||
| N-06 | 注册白名单与 `--strict` | 🟡 残余随 B2 | 登记簿 N-23 残余 |
|
||||
| N-07 / N-08 | 网络自愈与卷锁 | ✅ 已闭环 | `docs/网络/网络自愈架构设计.md` §4.10 |
|
||||
| **N-09** | `NET_MAX_SOCKETS`/PHY/PASV 三项网络债 | ❌ 在策 | `docs/任务规划/登记簿.md` N-25 |
|
||||
| N-10 ~ N-13 | 主机侧 nand/dhara 移植层单测动因 | ✅ 已建 | `test/host/nand_port/`(第 16 个单测钩子) |
|
||||
| **N-14** | FTL 写回缓存无空闲/掉电强制 flush | ⏸ 暂缓 | `docs/任务规划/登记簿.md` N-22 |
|
||||
| **N-15** | `nand_ftl` 三块 2 KB 页缓冲未合并 | 🟡 **观察项(2026-10-23 判定不做)** | `docs/内存管理/存储栈RAM优化调研.md` §5、登记簿 N-25 |
|
||||
| N-16 / N-17 | 台架窗口项(task stall 归因等) | 🟡 待窗口 | 登记簿 N-16/N-17 |
|
||||
| **N-18** | V0.1 双转换器无共同采样触发 | ❌ 待 V0.2 | `AGENTS.md` 硬件引脚节 |
|
||||
| N-19 ~ N-21 | 时钟/对时与已销项条目 | ✅ 已闭环 | `git log`(该报告已删) |
|
||||
| **D-1** | 外部资料与工程文档同仓同树 | ❌ 暂不处理 | `docs/任务规划/登记簿.md` N-29 |
|
||||
| D-2 ~ D-7 | 文档治理条目(链接/同源/编号/BOM 等) | ✅ 多数已制度化为钩子 | `docs/文档规范.md` |
|
||||
| D-9 | 文档面残余观察 | 🟡 观察 | 本节即定义位 |
|
||||
| **S-1** | 分层反向依赖(BSP include App 的头) | 🟡 已止住恶化(存量 6 条基线待还,新增被 `layer-deps` 拦) | `docs/门禁说明/layer-deps.md`(存量 6 条基线) |
|
||||
| **S-2** | 跨模块裸 `extern` | ✅ **已闭环 2026-10-22**(24 处手写全消;两类本就不算债见 §0.4) | `git log`;契约见 `App/task/task_handles.h`、`gd5f_spi1_notify_*`、`net_msg_queue_adopt` |
|
||||
| **S-4** | `app_cfg.h` 未接线占位开关 | ✅ **已闭环 2026-10-22**(4 个零消费点宏删除) | `App/app/app_cfg.h` 修改记录 v1.2;口径同步见 `docs/环境与部署/项目部署环境要求.md` §3.2/§3.5、`docs/产品需求/产品需求设计文档.md`、`docs/任务规划/排期详述.md` C5 |
|
||||
| **S-3** | `.ioc` 侧 USART1 配置 | ❌ 在策 | 登记簿 S-3 |
|
||||
| **S-5** | 统一 `bsp_err_t` 错误码与超时命名约定 + **返回值不得裸丢弃** | 🟡 主体已落地(2026-10-23:契约 + `bsp-err` 四规则 + RS485/SD2506/TPAFE 收编 + GD5F 改名 + dhara 三类码 + `consume-result` 照出 37 条丢弃 + ECC 回读校验;基线 19 → 1 → 38) | `docs/代码规范/pre-commit使用说明.md` §2.27、`STM32F4-Base存储架构说明.md` §10.4、`Drivers/BSP/bsp_err.h` |
|
||||
| R-1 ~ R-9 | 内存优化项(R-9 已落地、R-5 判定不可行、其余随簇暂缓) | 见 `docs/内存管理/RAM使用分析与优化方案.md` §4 | `docs/内存管理/RAM使用分析与优化方案.md` §4、`docs/内存管理/RAM预算台账.md` §3 |
|
||||
| F-1 / F-2 / F-3 | LVGL 死代码裁剪,省 64,576 B | ✅ 已落地 2026-10-11 | `docs/内存管理/RAM使用分析与优化方案.md` §2.6.4 |
|
||||
| **F-4 / F-5 / F-6** | Flash 双精度与死代码簇 | ✅/🟡/❌ 见 `docs/内存管理/RAM使用分析与优化方案.md` §2.6.4 | `App/algo/prot_set.h` 注释 |
|
||||
| U1 ~ U5 | UI 标准化簇 | 见 `docs/UI设计/UI_设计架构.md` §1.4;排期见 `docs/任务规划/README.md` §2.0「UI 扩展」 |
|
||||
### 4.5 已删报告的自有族
|
||||
《项目审查与优化建议报告》2026-10-25 已删除,它自造的六族随之失去定义,且与登记簿同字母不同义。
|
||||
看到"报告 N-16"这类写法一律按死号处理:删号留事实——各条目原本指向的设计文档就是现在的出处。
|
||||
|
||||
---
|
||||
|
||||
## 5. 分配、引用、销项规则(强制)
|
||||
## 5. 分配、引用、销项
|
||||
|
||||
### 5.1 新增编号
|
||||
先过 §1 三问。确实要发号:① 在 `id_registry.json` 确认族与游标 ② 在属主登记处写定义行 ③ 才允许在
|
||||
别处引用。**没有属主登记处的号不许存在**——门禁的校验 3 就是照这句实现的。
|
||||
|
||||
0. **先问"能不能不加号"**:能用 § 小节引用、表格列、语义标题表达清楚的,就不要分配编号——
|
||||
编号是"确需跨文档长期引用"时才付的成本(P-1 / P-3 / P-7)。确需新增才往下走。
|
||||
1. 查 §4 总表确定类别与属主登记处;**表里没有的类别 → 先改本规范,不得自造前缀**。
|
||||
2. 到属主登记处取游标号(`scripts/id_registry.json` 记每类的游标与冻结状态),登记处新增一行。
|
||||
3. 严重度 / 状态 / 波次 / 出处写进表格列,**不进编号**。
|
||||
|
||||
### 5.2 引用写法
|
||||
|
||||
| 场景 | 写法 |
|
||||
|---|---|
|
||||
| 全局编号,跨文档首次出现 | `` `docs/任务规划/登记簿.md` N-21 ``(紧邻,同 `§N.M` 规则) |
|
||||
| 全局编号,同段后续 | `` `N-21` `` |
|
||||
| 文档内编号 | **必须** `` `docs/网络/网络自愈架构设计.md` DR-003 `` |
|
||||
| 尚未创建的条目文件 | 加 `[计划] ` 前缀(`docs/文档规范.md` §3.3) |
|
||||
| 引用报错样例/历史字面 | 该行加 `[示例]` 标记 |
|
||||
|
||||
### 5.3 代码注释引用
|
||||
|
||||
- **允许引用**(长期有效):`FR-*`、`NFR-*`、`DEF-*`、`E-*`(冻结存量)、`N-*`、`TRAP-*`、`DR-*`、`TC-*`、`L<n>-<nn>`。
|
||||
- **禁止引用**(易变):`WI-*`、`W<n>`、`MS-*`、`OQ-*`、`ST-*`——代码是长期资产,波次与任务卡会变。
|
||||
- 首次出现带属主文档名(现状 90% 裸引,靠"全库唯一"这一未成文假设)。
|
||||
|
||||
### 5.4 提交信息
|
||||
|
||||
标题带主编号:`fix(net): N-32 监听重建阻塞导致心跳缺口`。一次提交只挂一个主编号,其余进正文。
|
||||
### 5.3 代码注释
|
||||
**优先写短语**(`FTP 鉴权`、`监听生命周期模块化`),别写字母号;确需引用活号时必须带属主文档名。
|
||||
**规划 / 待办类编号禁止出现在代码里**——代码的寿命比任何一张待办表都长,待办表改了行,注释就成了
|
||||
永久的假引用(本仓实测:196 处这样的死引用,全是这么攒出来的)。
|
||||
|
||||
### 5.5 销项与归档
|
||||
删登记行 + **同步清掉全仓引用**(清引用是销项的一部分,不是"以后再说")+ 别名表标 `void`。
|
||||
冻结的历史(变更记录行、`[示例]` / `[计划]` 行)不回改,门禁对它们已豁免。
|
||||
|
||||
- 销项 = 删登记行 + **清全库引用**(沿用 `docs/任务规划/README.md` §3 与 `AGENTS.md` 既有规则)+ 游标**不回退**。
|
||||
- 号段用尽 → 扩位(`N-99`→`N-100`),**不换字母**。
|
||||
- 历史文档(审计报告、评审报告、已闭环陷阱)不回改,走别名表。
|
||||
|
||||
### 5.6 编号密集文档的对照节(强制)
|
||||
|
||||
一篇文档若引用 **≥3 个编号族**(如 `I*` + `E*` + `F-*` + `M*` + `U*` + `TRAP-*`),**必须**在正文之前
|
||||
加一节「导读:本文用到的编号与术语」——每个记号一行,给出「是什么 + 在哪查」,让读者不必跳出本文拼语义。
|
||||
|
||||
- **首次实践**:`docs/网络/网络自愈架构设计.md` 的 `## 导读:本文用到的编号与术语`。
|
||||
- 对**已封闭 / 已归档**的编号族尤其必要:属主登记表可能已删行(`N-30`~`N-33` 销项、`E0`~`E15` 随审计归档),
|
||||
此时该文档即其**唯一可查处**。
|
||||
- 与 P-7 配套:**正文引用带语义括注**(局部可读)+ **对照节给编号族总览**(全局可查),两者合起来才算看得懂。
|
||||
|
||||
### 5.7 语义标识的登记、冻结与别名
|
||||
|
||||
- **登记**:在属主登记处新增一行,`#` 列填短语本身;落笔前先 `grep` 确认同表内无同名 /
|
||||
同义条目(同义异写 = 撞名,见 §3.3 形态规则)。
|
||||
- **冻结**:短语即标识,**改措辞等于换 ID**。确需改写时在原行加「别名」列,新旧措辞并存,
|
||||
引用侧同步替换完成后再删旧名——**禁止原地改写且不留下别名**。
|
||||
- **历史编号迁移**:编号转语义标识时,原号进别名表(例:`N-18` → `8 路电气量分属两片转换器`);
|
||||
历史文档中的裸号**不回改**(§5.5 同款处置)。
|
||||
- **销项**:删行 + 清全库引用(沿用 `docs/任务规划/README.md` §3 与 `AGENTS.md` 既有规则);
|
||||
短语**不复用**——重名即视为同一条目,与"号不回收"同理(撞名风险高于撞号,故由门禁兜底)。
|
||||
- **代码注释**:语义短语可进代码注释(中文注释允许),但必须带属主文档名(同 §5.3);
|
||||
现状 `App/algo/` 下 `N-18` 等 6+ 处**裸编号引用违反 P-7**,迁移时一并补语义。
|
||||
- **门禁**(`scripts/check_ids.py`,§8,2026-10-20 已落地 warn-only):① 同一登记处内短语去重;
|
||||
② 引用了登记处不存在的短语 = 悬空,报错;③ 打印「语义标识可判定比例」,只许涨不许跌。
|
||||
⚠ **当前落的是"编号"侧的 ②③**(编号族的悬空与可判定比例已机械化);**语义短语**侧的
|
||||
同表去重与短语悬空仍由人工 + `grep` 执行——短语是自由文本,机械去重要先解决同义异写判定
|
||||
(`日志静默` vs `49s 日志静默`),那是另一个问题,别把它记成"已由门禁兜住"。
|
||||
### 5.7 语义标识的登记与别名
|
||||
短语就是登记处的行名,不需要别名表;**只有"号转短语"**时才在别名表留一条 `retired-to-phrase`,
|
||||
`note` 写清短语,方便把残留引用找干净。
|
||||
|
||||
---
|
||||
|
||||
## 6. 模块码表(`TC` / `TM` / `DP` / `TRAP` 共用)
|
||||
## 6. 模块码表
|
||||
`TC` 与 `TRAP` 共用模块码。唯一事实源是 `scripts/id_registry.json` 的族 pattern 与属主文档标题行;
|
||||
**本文故意不再抄一份**——抄一份就多一处会过期的地方(历史上这张表就长期与代码不同步)。
|
||||
要加模块码:先改 registry,再在属主文档出现,最后才在别处引用。
|
||||
|
||||
现状是**板端 6 个码 + 主机侧 10 个码两套并存**,且 `docs/测试说明/ADC输入层单元测试说明.md` 明文豁免主机侧"与板端缩写表互不影响"。本规范合并为一张表,**现有码全部沿用(零改写)**,只规定新模块必须先登记:
|
||||
## 7. 改号与迁移
|
||||
|
||||
| 码 | 模块(源文件/目录) | 码 | 模块 |
|
||||
|---|---|---|---|
|
||||
| `NET` | `Drivers/BSP/CH395F` + `Drivers/BSP/NET` | `ADCIN` | `App/algo/adc_input` |
|
||||
| `GD5F` | `Drivers/BSP/GD5F2GQ5UE` | `ADCHEALTH` | `App/algo/adc_health` |
|
||||
| `STORAGE` | 存储栈(FTL + FatFs + `App/fs`) | `PHASOR` | `App/algo/phasor` + `sample_ring` |
|
||||
| `RTC` | `Drivers/BSP/SD2506` | `PROTSET` | `App/algo/prot_set` |
|
||||
| `ADC` | 采集节拍与通道映射(`Src/adc.c`、TIM3) | `PROTELEM` | `App/algo/prot_elm` |
|
||||
| `RS485` | `Drivers/BSP/RS485` | `VOLLOCK` | `App/fs/vol_lock` |
|
||||
| `UI` | `Drivers/BSP/UI` | `TIMESYNC` | `App/sync/time_sync` |
|
||||
| `LOG` | `App/log` | `SYSCLK` | `App/util/sys_clock` |
|
||||
| `CONFIG` | `App/cfg` + `Drivers/BSP/NETCFG` | `WATCHDOG` | `App/util/task_watchdog` |
|
||||
| `SHA256` | `App/util/sha256` | `FTPAUTH` | `Drivers/BSP/NET/lftpd` 鉴权 |
|
||||
| `IEC104` | `App/protocol/iec104` | `TOOL` | PC 端工具(串口助手等) |
|
||||
### 7.1 映射规则(作废)
|
||||
"按审计报告把某族整体迁到另一族"那套映射已作废。2026-10-26 的实测结论是:**绝大多数号该删不该迁**。
|
||||
|
||||
> 废止码:`PHY`(→ `NET`)、`NAND`(→ `GD5F`)。历史文档不回改,新文档按本表。
|
||||
### 7.2 孤儿编号处置(已完成)
|
||||
代码有号、文档无号那批已按同一口径处理完:能对上属主表的补模块码,对不上的删号留事实;
|
||||
**绝不为了少报孤儿而凭空补定义行**(那等于把账做平、把问题藏起来)。
|
||||
|
||||
### 7.3 改号操作规程(要动号就照这个走,一步都别省)
|
||||
1. 走 `scripts/rename_ids.py`:映射表驱动、**显式 scope**、默认干跑、自动写别名条目;
|
||||
**绝不全局查找替换**——同一裸形字面量可能同属多个族(实测 `S3` 三义),全局替换等于造新撞号。
|
||||
2. 改完复核**所有识别面**:`check_ids.py` 与 `check_test_traceability.py` 的候选正则上界都要还能匹配新
|
||||
形态;判据是"编号字面量总数有没有真的变小"(曾经因为正则上界太窄,改完号静默隐形 339 个)。
|
||||
3. **逐号做语义复核**,不能只看 dry-run 命中数:最阴的失效是"字面改对、意思改错"。
|
||||
4. 登记表 / 映射表类文件**不得当引用语料**,否则自家审计表里的旧形态会被判成新账。
|
||||
5. 收尾重打台账 `--prune-backlog`(只减不增),并确认新错误级为 0。
|
||||
|
||||
---
|
||||
|
||||
## 8. 门禁:`id-check`(八项校验)
|
||||
|
||||
> ⚠ **2026-10-20 批 2**:上表 16 个有歧义的码已单词化(`AI`→`ADCIN`、`AH`→`ADCHEALTH`、`PS`→`PROTSET`、`PE`→`PROTELEM`、`PH`→`PHASOR`、`TS`→`TIMESYNC`、`VL`→`VOLLOCK`、`NP`→`NANDPORT`、`CFG`→`CONFIG`、`CLK`→`SYSCLK`、`WD`→`WATCHDOG`、`STO`→`STORAGE`、`SH`→`SHA256`、`FA`→`FTPAUTH`、`FR`→`FREQ`、`104`→`IEC104`),全库 1,146 处随 `scripts/rename_ids.py` 改写,旧号入 `scripts/id_aliases.json`。`NET`/`GD5F`/`RTC`/`SOE`/`UI`/`ADC`/`LOG`/`RS485`/`TOOL` 不动(已是单词、芯片名或业界通用词)。**连带修门禁**:模块码变长到 9 位(`ADCHEALTH`),候选正则与族正则的 `{0,4}` 上界必须放宽到 `{0,9}`,否则改名后的号会整批从门禁眼里消失(实测漏掉 950 处——改名类批次必须连带复核识别面,不能只改数据不改判据)。
|
||||
## 7. 迁移映射(legacy → 新号)
|
||||
查什么、报错怎么读、盲区在哪——**全在 `docs/门禁说明/id-check.md`**,本文只留口径与基线。
|
||||
八项校验一句话版:① 未登记前缀 ② 形态不合规(裸形 / 空格 / 中文 / 补零)③ 悬空引用 ④ 重复定义
|
||||
⑤ 冻结族越游标 ⑥ 编号未紧邻文档名 ⑦ 孤儿条目(告警)⑧ 可判定比例 + 两根护栏。
|
||||
|
||||
### 7.1 映射规则
|
||||
|
||||
| 旧族 | 新族 | 规则 |
|
||||
|---|---|---|
|
||||
| 登记簿 `N-2`…`N-33`(`N-30`~`N-33` 已销项,现存至 `N-29`) | `N-02`…`N-33` | 仅补零,数字不变;号不回收,游标仍 `N-34` |
|
||||
| 登记簿 `S-3/S-4/S-5`、`T-7` | `N-34`… | 续号并入,别名表保留旧号 |
|
||||
| 主线 `B0~B10`、结构债 `C1~C6`、验证窗口 `D2~D7`、`W1-0` | `WI-001`… | 按波次顺序连续重编,映射表逐条列出并落别名表 |
|
||||
| 复审 `S1~S14`、`A-1~A-7`、报告 `R-x`/`F-x`/`U1~U5` 未闭环项 | `WI-*` | 同上;已闭环项留历史文档 |
|
||||
| `P0-x`~`P3-x` 在册项 | `DEF-*` | 严重度转列 |
|
||||
| 设计说明 `D1~D10` | `DR-001`~`DR-010` | 数字对齐 |
|
||||
| `B0-a/b/c`、`待确认-N` | `OQ-001`… | — |
|
||||
| `Trap NN` / `陷阱 N` | `TRAP-<MOD>-<nn>` | 数字不变,补模块码 —— **批 4 已做(2026-10-21)**:GD5F `01~07`、RTC `01`、NET `19`/`21`;`docs/硬件平台/` 属排除语料,里面的 `Trap05` 未动(见 §8.3 批 4 说明) |
|
||||
| `H-1~H-7`、`L-1~L-4`、差距 `N-1~N-6` | `GAP-01`~`GAP-17` | 按文档内出现顺序 |
|
||||
| 实机 `A1~A8`、看门狗 `V2/V4/V5` | `SC-01`… | — |
|
||||
| 测试分层 `L0/L0.5/L1/L2/L3` | `T0/T0.5/T1/T2/T3` | 门禁 `G0~G3` 不动(两套不同尺度,不合并) |
|
||||
| `gen 181`/`gen-288`/`gen68` | `GEN-181`/`GEN-288`/`GEN-068` | 数字不变 |
|
||||
| `round 1~9` | `RUN-<日期>-<n>` | 无日期的历史轮次留别名表 |
|
||||
| `M1~M3` | `MS-01`~`MS-03` | — |
|
||||
| 对账 `①~④` | `RC-01`~`RC-04` | 代码注释同步 |
|
||||
| 审计模式 `P1~P9` | `PAT-01`~`PAT-09` | 正文冻结,新文档用新号 |
|
||||
| 保护 `R1~R8`、看门狗 `R1~R7` | 各文档 `RSK-01`… | 文档内编号 + 引用带文档名 |
|
||||
| 保护阶段 `P0~P5`、方案 `P0~P3` | 各文档 `ST-0`… | 与档位词 `P0` 解耦 |
|
||||
| `TC-STORAGE-01~06` | `TC-STORAGE-001~006` | 补零 |
|
||||
| `TC-ADCIN-01A`/`02A`/`02B`/`02C`、`TC-VOLLOCK-008b` | `TC-ADCIN-001a`… / `TC-VOLLOCK-008b` | 后缀统一小写字母,基号补零 |
|
||||
| `TM-PHY-01~11` | `TM-NET-01~11` | 模块码 |
|
||||
| `DP-01~04` | `DP-NET-01~04` | 加模块码 |
|
||||
|
||||
### 7.2 孤儿编号处置(阶段 1 一并清)
|
||||
|
||||
| 孤儿 | 处置 |
|
||||
|---|---|
|
||||
| `I-1`/`I-2`(`ui_net_sink.c`) | 就地展开成事实描述(原属主《网络Socket监听生命周期设计说明》已并入 `docs/网络/网络自愈架构设计.md` §9.3,不再补编号定义行) |
|
||||
| `Task #32` 会话号及其小节引用 | 会话号,改写为可解析引用(结论已沉淀进 `docs/子系统设计/看门狗设计说明.md` §11) |
|
||||
| `P1-01~P1-09`(`ch395f_test_task.c`) | 改指 `TC-NET-101`…,或补文档条目 |
|
||||
| `TC-GD5F-1100/1101/1102`、`TC-STORAGE-06` | 补进 `docs/测试说明/GD5F2GQ5UE_Test_Guide.md` |
|
||||
| `TC-AH-*`、`TC-PE-*`、iec104 `TC-014/015/024` | 补单测说明文档(缺文档 = 追溯断链) |
|
||||
| `Trap 19` | 悬空引用,删除或改指实际条目 |
|
||||
|
||||
### 7.3 改写操作规程(每批必走)
|
||||
|
||||
```powershell
|
||||
# 1) 预览:映射表驱动的 dry-run,人工通读 diff(重点看 docs/硬件平台/ 是否被误伤)
|
||||
& '.venv\Scripts\python.exe' [计划] scripts/rename_ids.py --map [计划] scripts/id_aliases.json --dry-run
|
||||
|
||||
# 2) 落盘后三重复核
|
||||
git grep -n '<旧字面量>' # 零残留
|
||||
& '.venv\Scripts\python.exe' scripts/check_doc_links.py --all
|
||||
& '.venv\Scripts\python.exe' .dsh\skills\keil-build\scripts\keil_build.py # 0 错误 0 警告
|
||||
```
|
||||
|
||||
**硬约束**:`docs/硬件平台/`、`docs/芯片手册/` 全程排除(元器件位号 `U1/C12/R3/L5/D7` 与编号字面同形);带 BOM 的文件(`Drivers/BSP/UI/*`、`App/task/ui_task.c`、`App/cfg/cfg_file.c`、`Lib/lv_conf.h`)改写后必须核对 BOM 未丢;**禁止**用 `Get-Content`/`Set-Content` 重写含中文文件。
|
||||
|
||||
---
|
||||
|
||||
## 8. 门禁:`check_ids.py` 与 `id-check` 钩子
|
||||
|
||||
配置两份:`scripts/id_registry.json`(前缀 → 属主文档 / 形态正则 / 是否冻结 / 游标)、`scripts/id_aliases.json`(旧号 → 新号,照搬 `scripts/section_aliases.json` 的成功范式)。
|
||||
|
||||
| # | 校验 | 级别 |
|
||||
|---|---|---|
|
||||
| 1 | 出现未登记前缀(自造编号) | 错误 |
|
||||
| 2 | 形态不合规:裸形 `S3`、空格形 `Trap 07`、中文形 `陷阱 1`、补零错、`P1-8` 这类档位词带后缀 | 错误 |
|
||||
| 3 | 引用查无定义且不在别名表(悬空引用) | 错误 |
|
||||
| 4 | 同一字面量被两个属主重复定义(`N-16` 类事故) | 错误 |
|
||||
| 5 | 冻结前缀出现游标之外的新号 | 错误 |
|
||||
| 6 | 文档内编号引用未紧邻文档名 | 错误 |
|
||||
| 7 | 定义了但全库无引用(孤儿条目) | 告警 |
|
||||
| 8 | 打印**「编号引用可判定比例」** | 每次运行,只许涨不许跌 |
|
||||
|
||||
- 排除:`Lib/`、`Middlewares/`、HAL/CMSIS、`docs/芯片手册/`、`docs/硬件平台/`(位号)、构建产物。
|
||||
- 上线节奏:**先 warn-only → 2026-10-21 关闸为【增量拦截】**(`--strict` + 债务台账,见 §8.4)。与 `doc-links` 的差别在于:存量太多(710 处),等清零会逼出 `--no-verify`,所以先关闸再还债。
|
||||
- 顺带收编 `scripts/check_test_traceability.py`:正则补齐大写后缀与无模块码形态,覆盖 7 篇「单元测试说明.md」,一并挂进 `id-check`。
|
||||
**2026-10-21 口径改写**(B 层之后):差异分三档——`DOC-ONLY` 文档声明而代码没有(真断链)、`CODE-ONLY` 代码有而母号不在登记处且号旁无意图(真未登记)、`IN-CODE` 靠「代码旁写着意图」放过(弱保证,单列示数、不算过关);小写子项后缀按母号算。
|
||||
|
||||
### 8.1 落地记录(2026-10-20)
|
||||
|
||||
**已落地并挂上 `id-check` 钩子(warn-only)**。三项机械判据先定死,否则八项校验全是空话:
|
||||
|
||||
| 判据 | 口径 |
|
||||
|---|---|
|
||||
| 「定义」存在 | 字面量出现在该族的**属主登记处文档**里(registry 的 `owner_docs` / `owner_docs_glob`)——不依赖表格行首等易漂移形态 |
|
||||
| 「重复定义」 | 字面量出现在**定义位**(表格首格 / 标题行 / 列表项行首);正文里"提到过"不算定义,否则任何交叉引用都会被误判 |
|
||||
| 「可判定」 | 字面量落进已登记前缀族**且该族属主登记处已存在**;未登记前缀、属主还是 `[计划]` 的都算不可判定 |
|
||||
|
||||
**首轮基线(本仓库实测,`--update-baseline` 写进 `id_registry.json`,只许涨不许跌)**:
|
||||
### 8.1 当前基线(2026-10-26 编号迁移批次后重打)
|
||||
|
||||
| 项 | 数值 |
|
||||
|---|---|
|
||||
| 扫描文件 | 536 个(`git ls-files` 减去 §8 排除清单) |
|
||||
| 编号字面量出现 | 8271 处 |
|
||||
| **可判定比例基线** | **84.0%**(8747 / 10410 = 84.02%,2026-10-25 删报告 + 补登 11 条已死号别名后重打;存进 `id_registry.json` 时**下取整到 0.1pp**——用 `round()` 会让 82.34 进位成 82.3 再反过来把自己判死,实测踩过;比较容差 0.1pp) |
|
||||
| 校验 1 未登记前缀 | 0 处 |
|
||||
| 校验 2 形态不合规 | 396 处(**批 1 已从 417 降到 396**:裸形 `S`/`T` 类 71 → 50。剩余大头:真无模块码 `TC-nnn` 181 处 / 5 文件、数字模块码 `TC-104-nnn` 23 处(§6 表里模块码是 `I104`,非数字)、`DP-01`~`DP-04` 22 处、`Task #nn` 33 处、`Trap 空格形`+`陷阱 中文形` 43 处、`gen/round` 36 处、大写后缀 31 处) |
|
||||
| 校验 3 悬空引用 | 错误 626 / 告警 223(scoped 别名收编旧号后 −16)(错误集中在 `TC-PS-*`/`TC-PE-*`/`TC-AH-*`/`TC-FR-*`/`TC-SOE-*`——**主机侧单测有码无文档**,正是 §7.2 列的"缺文档 = 追溯断链") |
|
||||
| 校验 4 重复定义 | 0 处(`§4.3` 已声明的同号不同义族对 443 个字面量走 `collides_with` 白名单,不计事故) |
|
||||
| 校验 5 冻结越游标 | 0 处 |
|
||||
| 校验 6 未紧邻文档名 | 269 处(报告自有编号 `D-x`/`R-x`/`F-x`/`P0-x` 被裸引,属 §9 阶段 1-③ 待办) |
|
||||
| 校验 7 孤儿条目 | 88 处(告警) |
|
||||
| 附带 TC 双向追溯 | 代码侧 556 / 文档侧 290 / 交集 260(差异 326,收编后含主机侧单测一侧,比原板级口径的 33 大一个量级——**原口径漏的正是 7 篇单测说明**) |
|
||||
| 扫描文件 / 编号字面量 | 754 个 / **8,230 处**(两批清理前 10,956;本规范自己瘦身去掉 160 处 → 8,343,编号迁移批次再降到 8,230) |
|
||||
| **护栏 1**:可判定比例下限 `decidable_ratio_baseline` | **86.0%**(实测 86.01%;容差 0.1pp,只许涨) |
|
||||
| **护栏 2**:不可判定引用绝对数上限 `undecidable_total_ceiling` | **1,166 处**,只减不增(实跑 1,151 处) |
|
||||
| 校验 1/2/3/4/5/6 错误级 | **0**;债务台账 0 条指纹 → `--strict` 实为**全量拦截** |
|
||||
| 告警 | 悬空 2(`App/algo/freq.c` 的正序 / 负序记号,属 §4.4 误判面)+ 孤儿 50(陷阱条目这类本就允许无人引用) |
|
||||
|
||||
**有牙实测**([示例] 下列字面量是注入用的假编号,不是真实引用):临时注入 `Z-99` / 裸形 `S3` / `TC-NET-9999`(悬空)/ `E-70`(越 `E-63` 游标)/ 裸引 `D-7` / 在第二篇属主文档重复定义 `DP-01` → 六项分别被校验 1/2/3/5/6/4 点名,`--strict` 退出码 1;临时档删除后 `git status` 干净。
|
||||
> ⚠ **读这些数字的口径**:跨批次**不可直接相减**。方案 B 把"本可判定的引用"换成散文,分子分母同缩,
|
||||
> 比例反而从 86.7% 掉到 85.98%,而**不可判定绝对数一处没涨**——所以同批加了护栏 2,并把比例基线
|
||||
> **人工下调**一次(工具按设计拒绝下调,必须留书面理由,见 `docs/门禁说明/id-check.md` §7.6);本规范瘦身后比例回到 86.0%,
|
||||
> 护栏 2 也顺手从 1,192 收紧到 1,166。
|
||||
> 以后判断"编号有没有变坏"看**绝对数**,不看比值:号只许越清越少,新增没登记的号一定被护栏 2 拦住。
|
||||
|
||||
**口径修正记录(2026-10-21,B 层)**——下列改动**改变了比例的分母/分子含义**,读历史数字必须知道:
|
||||
|
||||
| 改动 | 动机 | 对比例的影响 |
|
||||
|---|---|---|
|
||||
| 主机侧单测建 **9 族 `TC-HOST-<模块码>`**,属主登记处 = `test/host/<目录>/*`(代码即登记处;**2026-10-23 起同一口径新增 4 族,现 13 族**,见 §8.4 变更记录) | 实测这些号在代码目录外**零消费者**(唯一"外部引用"是 `id_aliases.json` 自己),逐号补文档只会造出没人读的复述层 | 悬空错误 −508 中的 430(**口径修正,不是仓库变好**) |
|
||||
| `subitem_ok`:小写子项后缀(`TC-TIMESYNC-003b`)母号在册即算已定义 | §4.1 明允许小写后缀,是合法形态;双向追溯仍按完整字面量报差异,可见性不丢 | 悬空 −74(同上,属口径) |
|
||||
| **`snapshot_only`**:§4.3 冻结历史快照族(`N-RPT`/`D-RPT`/`S-RPT`/`R-RPT`/`F-RPT`/`P-AUDIT`/`A-AUDIT`/`B-AUDIT`)**不参与"定义位优先"** | 曾试过让定义位优先无差别生效:`N-21`(登记簿条目已销项)被审计报告里同号的另一码事"接管",门禁转而去报 ⑥"请写报告文档名"——**照做就制造 §1.2 的 `N-31` 撞号**;实测该做法使校验 6 从 266 暴涨到 1437、比例假崩到 68.7% | 校验 6 回到 269(与 B 层前持平) |
|
||||
| **补属主**:`docs/任务规划/README.md` 加入 `N`/`S-LDG`/`T-LDG` 族的 `owner_docs` | 这是**我的配置漏项**:活登记处在 README(`N-21` 出现 2 次),我原先只登记了 `登记簿.md`(`N-21` = 0)→ 真条目被误判悬空 74 处 | 悬空 −74(**修 bug,不是口径**) |
|
||||
| `excluded_paths` 加 `scripts/id_aliases.json`、`scripts/id_registry.json` | 别名表/注册表**自身不得制造引用面**——上批别名条目一度成为这些号的唯一"外部引用" | 极小 |
|
||||
| **追溯脚本同口径对齐**(`check_test_traceability.py`):文档声明了代码没有 = DOC-ONLY 真断链(38);代码有、母号不在登记处**且号旁没写人话意图** = CODE-ONLY 真未登记(7);代码有但旁边写着意图 → 单列 `IN-CODE`(238),**弱于文档的保证,禁止当成已登记** | B 层认代码为属主后,老口径「每个号都必须出现在文档」与门禁自相矛盾——照它升 `--strict` 会拦死 173+ 处本不该写文档的号,逼出 `--no-verify`,门禁公信力就是这么没的 | 差异从 284 降到 45(38+7),另 238 处转入「看得见但不过关」的 `IN-CODE` 账 |
|
||||
| ⚠ 同批改名要复核**所有**识别面:`TC_RE` 也停在 `{0,4}`,模块码单词化后代码侧集合从 556 悄悄缩到 217(339 个号隐形),已放宽到 `{0,8}` | 这是「改名必须连带复核判据面」教训的**第二次发生**,发生在另一支脚本上 | 修回后代码侧 578 |
|
||||
| **追溯器补上「变更记录 / `[示例]` / `[计划]` 行」豁免**(`check_test_traceability.py`,与 `check_ids.py` / `rename_ids.py` / `doc-links` 同一条口径) | 追溯器是**唯一没这条豁免**的一支:它把冻结历史当活引用,凡变更记录里写过的旧用例号一律要求代码里也存在同号 (例:`\| 2026-10-10 \| 新增 TC-AI-070..078 \|` 写的是**当年**的名字,号在批 2 已改成 `TC-ADCIN-*`,按 §8.1 历史行不回改 → 拿它去代码里找同号必然落空) | `DOC-ONLY` 38 → **29**(−9 全是假阳性,**不是真变好**)。关键佐证:**交集 260 → 260 不变**——豁免没有吞掉任何一条真对应,只吐出了冻结行 |
|
||||
| 已销项历史任务号 `T-2`/`T-3`/`T-4`/`T-6` 入别名表(`status: void`) | §5.5「销项 = 删行 + 清引用」只做了一半的欠账;本条只让门禁停止把它当自造号,并如实指路 | 悬空错误 −35 |
|
||||
|
||||
**修正后实测(2026-10-21)**:错误级 **711**(B 层前 1318)= ②398 + ③44 + ⑥269;告警级 ③223 + ⑦100;可判定比例 **82.71%**(6883/8322),基线仍 82.6%。
|
||||
⚠ 拿 711 与 1318 直接比是**错的**——其中 504 处是口径修正,只有 74 处是我修的注册表 bug;真正"变好"的部分是 **0**。剩下的 711 处没有一条能靠调判据消掉,只能补文档、改写引用或按 §4.3 登记冻结。
|
||||
|
||||
**显式盲区(不是"检查通过",是记在案上的判定边界)**:裸形同字母多义(§1.2 的 P1 五义 / L1 四义 / U1 四义 / D7 三义)与元器件位号同形(§4.4)→ 裸形族**只在属主登记处文档内**判越游标,文档外降为告警;圈号编号与正常列举无法机械区分,不入判定。这两块的收口属 §9 阶段 1-②/1-③ 的迁移批次,收口后再扩判定范围。
|
||||
|
||||
### 8.2 落地时发现的规范 ↔ 仓库偏差(registry 按实测收录,规范行待订正)
|
||||
|
||||
| 规范原文 | 实测 | 处置 |
|
||||
|---|---|---|
|
||||
| §4.1 `E\d+`「已封闭 `E0`~`E15`」 | `docs/网络/网络自愈架构设计.md` §5.2 实验表已到 **E19** | 游标按实测 E19 收录;封闭线待修订 |
|
||||
| §4.1 `FR-[A-Z0-9]+-\d{2}` | 现存 `FR-STO-1` 等全是**未补零**的 1 位序号 | 正则放宽到 `\d{1,2}`,补零归 §9 阶段 1 |
|
||||
| §4.1 `TC-[A-Z]{1,4}-\d{3,4}` | 模块码 `GD5F`/`I104` **含数字**,按原文正则会漏掉 GD5F 全族(实测 285 处) | 放宽为 `[A-Z][A-Z0-9]{0,4}`;序号暂收 2 位(`TC-STORAGE-06` 属 §7.2 孤儿) |
|
||||
| §4.1/§4.2 总表无 `F-<MOD>-<nn>` | `F-NET-2~17`/`F-DRV-*`/`F-MS-*` 定义在 `docs/网络/网络自愈架构设计.md` 且被大量代码注释引用 | 先按实测收编成族(§5.1 第 1 步:表里没有的类别先改本规范) |
|
||||
| §4.1 `N-\d{2}` | 报告用 `N-03a`/`N-03c` 子项后缀;§5.5 扩位示例 `N-100` | 放宽到 `\d{1,3}[a-z]?` |
|
||||
### 8.3 改号与清号批次(只留要点)
|
||||
2026-10-21 五批统一改名(陷阱号归范、主机侧单测认代码为属主登记处、追溯器三档口径对齐);
|
||||
2026-10-26 两批清号(A:删死号约 1,557 处文本实删;B:登记簿系 20 个号转语义短语约 418 处)。
|
||||
逐批动机与影响只在 git log 与 `scripts/rename_maps/`,**本文不维护流水账**。要记住的只有两条教训:
|
||||
门禁曾经把"政策上禁止回改的变更记录行"当活账拦提交;也曾经用比值当唯一护栏而**惩罚清号动作本身**
|
||||
——两处都在 2026-10-26 修掉了,别再往回改。
|
||||
|
||||
### 8.4 台账与 `--strict`
|
||||
错误级问题按「文件 + 校验项 + 字面量 + 次数」记指纹进 `scripts/id_known_backlog.json`,`--strict` 只拦
|
||||
**台账之外**的新账,台账只减不增。本批台账已还清到 **0 条**——从现在起任何一条新错误级问题都会当场
|
||||
拦提交,**别指望还有豁免面**可钻。
|
||||
|
||||
---
|
||||
|
||||
### 8.3 迁移批次记录(改名走 `scripts/rename_ids.py`)
|
||||
## 9. 还剩什么(以及别再做什么)
|
||||
剩下能被机器读到的号就是 §4.1 那 8 族。除此之外,**"编号说明"这件事本身应该继续变薄**:每多一个族,
|
||||
就多一处需要有人记得它的地方;每多发一个号,就多一个将来没人敢删的字符串。要新增族之前,请把这张
|
||||
只有 8 行的表当作反对你的第一手证据。
|
||||
|
||||
| 批 | 日期 | 族 | 旧 → 新 | 处数 / 文件 | 别名 |
|
||||
|---|---|---|---|---|---|
|
||||
| **批 5(口径)** | 2026-10-21 | 追溯器豁免 | **未改任何编号**:给 `check_test_traceability.py` 补与其它三支工具同源的「变更记录 / `[示例]` / `[计划]` 行不比对」口径 + `--verbose` 打印被豁免的 9 个号 | 判据改动;`DOC-ONLY` 38 → 29、交集 260 不变 | 无新增(`TC-AI-070` 等 8 个旧号**早在批 2 就已在别名表**,本批一度以为缺、写错层级后被 assert 拦下) |
|
||||
| **批 4(Trap)** | 2026-10-21 | 陷阱号形态 | `Trap 01~07` → `TRAP-GD5F-01~07`、`陷阱 1` → `TRAP-RTC-01`、`Trap 21`/`Trap 19` → `TRAP-NET-21`/`TRAP-NET-19`、`见陷阱 01` → `TRAP-GD5F-01` | 23 处 / 11 文件(含 `Drivers/BSP/GD5F2GQ5UE/*` 注释 4 处、`test/board/*` 2 处) | 11 条全部带 scope;映射表即审计轨迹 `scripts/rename_maps/batch3-trap.json` |
|
||||
| **批 1** | 2026-10-20 | 代码规范条款 | `S1`~`S19` → `CODE-RULE-01`~`19` | 78 处 / 2 文件 | 18 条(scoped:`scripts/check_coding_standard.py`、`docs/代码规范/pre-commit使用说明.md`) |
|
||||
| **批 3(口径)** | 2026-10-21 | 主机侧单测归属 | 建 9 族 `TC-HOST-*`(代码即属主)+ `subitem_ok` + `snapshot_only` + 补 README 属主 + `T-x` 入别名 | 判据与注册表改动,未改任何存量号 | 见 §8.1 口径修正记录 |
|
||||
| **批 2** | 2026-10-20 | 测试用例模块码 | 16 个码 → 单词化(见 §6) | 1,146 处 / 约 30 文件 | 全局别名(字面量已完全限定,无歧义) |
|
||||
| **批 1** | 2026-10-20 | UI 像素回归状态 | `S0`~`S7` → `MENU-STATE-00`~`07` | 61 处 / 3 文件 | 8 条(scoped:`simulator/tests/check_menu_rows.py`、`docs/UI设计/UI_自动化测试流程.md`、`simulator/README.md`) |
|
||||
|
||||
⚠ **别名必须带 scope**:同一裸形字面量可同时是多族的旧号(实测 `S3` 三义)。全局别名会把另一族的真悬空洗成「已解析」——等于用工具复制 §1.2 的 `N-31`/`N-32` 撞号事故。
|
||||
|
||||
---
|
||||
|
||||
**批 5 的经过值得记一笔:我的判断被自己的证据推翻了两次**
|
||||
|
||||
1. 我据 `DOC-ONLY` 38 处判定「批 2 模块码单词化漏扫了 4 篇属主文档」(`TC-AI-070/080/090`、
|
||||
`TC-PH-001/030`、`TC-TS-001`、`TC-VL-001`),并写好了逐号点名的映射表准备改名。
|
||||
2. 改名工具干跑 **0 处命中** → 查下去发现这 8 处**全部位于变更记录行**(`| 2026-10-10 | … |`),
|
||||
按 §8.1 属冻结历史、**本就不该回改**;再查别名表,`TC-AI-070 → TC-ADCIN-070` 这批
|
||||
**早在批 2 就已登记**。也就是说:真要按原计划改,是在销毁历史记录,而收益是零。
|
||||
3. 我顺手补别名时把键写到了 JSON **顶层**(真容器是 `aliases`,515 条),条目完全无效——
|
||||
是 `assert k not in d['aliases']` 把它拦下来的;删掉无效键后该文件字节与 HEAD 完全一致。
|
||||
|
||||
**教训写在这里而不只是提交信息里**:`DOC-ONLY` 这类"两侧字面比对"的差异,**先判它是不是冻结行/
|
||||
别名可解析**,再谈改数据;改名工具的 0 命中和 assert 失败都是**信号**,不是小故障。
|
||||
|
||||
**剩 29 处 `DOC-ONLY` 是真问题,但不是编号问题**(`--verbose` 可复现全清单):
|
||||
- 4 处无模块码形态(`TC-1003`、`TC-206`、`TC-501`、`TC-704`)——属 ② 大批的文档侧镜像;
|
||||
- `TC-NET-607` 一条是**历史指称**:原文写「原 TC-NET-607/608/609,现 701/702/703」,
|
||||
一条对三条,别名表是一对一模型,写不进别名;
|
||||
- `TC-NET-302/401/402/501` 标题明写「(硬件层)」= 人工台架步骤,代码里没有实现载体**是预期**;
|
||||
- 其余 20 处(`TC-NET-101/102/1101/601/606/701~704/801/802/901/902/1006/1501~1503` 与
|
||||
`TC-GD5F-503`)**全库无任何载体**(代码、台架脚本、模拟器都没有)——文档声明了用例而没有实现,
|
||||
这三类要不要各立口径(人工台架豁免 / 历史指称 void 别名 / 真未实现登记待办),**属产品裁决,不由门禁决定**。
|
||||
|
||||
**批 4 刻意不改的三处(写清楚,别被当成漏网)**
|
||||
|
||||
- `docs/环境与部署/并行任务工作树方案.md` 里的 `wip/trap22-fix` 是 **git 分支名**,不是编号——
|
||||
这类「非编号字面量」要靠**类型识别**处理(与位号 `T1`、IEEE 负序 `S2`、gitlint 规则 ID 同一批),
|
||||
不靠白名单硬豁免,也不许为它改分支名。
|
||||
- `docs/UI设计/菜单页面设计.md` 的变更记录行「陷阱 3」按 §8.1 冻结不改写;正文里指向本文自己小节的
|
||||
那处(原「见 §8.2 陷阱 1」)**本来就不是 `TRAP-*` 族的号**,已改写成
|
||||
「见本文 §8.2 第 1 条(`lv_text_get_width` 的 `length=0` 陷阱)」——引用要能当问题读,
|
||||
不必为两处文档内自指另立一族。
|
||||
- `docs/硬件平台/` 网表分析报告里 6 处 `Trap05`(语义 = `TRAP-NET-05`)留在排除语料里不动,
|
||||
盲区已登记进 `id_registry.json` 的 TRAP 族 `cursor_note`。
|
||||
|
||||
### 8.4 债务台账与增量拦截(2026-10-21 关闸)
|
||||
|
||||
**为什么不照 §8 原节奏「清零后再 `--strict`」**:存量 710 处(② 形态迁移 398 + ⑥ 裸引写全属主 269 + ③ 真悬空 44),
|
||||
靠人清完要数周到数月;这期间**新欠的债一条都不会被拦**——而新增恰恰是编号烂掉的主因(`N-31`/`N-32` 撞号
|
||||
就是新增时撞上的)。更糟的是「等清零」会让所有人习惯看到「门禁报红但照样提交」,真到关闸那天已经没人信它。
|
||||
|
||||
**机制**:`--strict` 不再「有任何错误就失败」,而是**只拦台账之外的新错误级问题**。
|
||||
|
||||
| 件 | 说明 |
|
||||
|---|---|
|
||||
| 台账 | `scripts/id_known_backlog.json`:340 条指纹,覆盖 710 处错误级问题(② 167 类 / ⑥ 135 类 / ③ 38 类) |
|
||||
| 指纹 | `(文件, 校验号, 字面量) → 出现次数`。**故意不含行号**:行号每改必漂,拿它当指纹会让台账天天「假新增」,三天后没人敢看 strict 输出,台账等于失效——**台账失效比没有台账更糟** |
|
||||
| 为什么带计数 | 同一文件里同一个号**多出现一次**也算新账:复制粘贴式扩散是编号烂掉的常见路径,只按「有没有出现过」判会放过它 |
|
||||
| 只减不增 | `--prune-backlog` 收掉已还清条目;台账内条目**变多**会被 `--strict` 当场拦;确需新增一条必须写 `reason` 字段(默认禁止顺手加行,否则一周后台账变成第二个 backlog) |
|
||||
| 初始化 | `--write-backlog` 全量快照(关闸那次用过;之后再跑等于豁免新债,须显式确认) |
|
||||
| `--only` 与 `--strict` | **互斥**(局部扫描不能当门禁结论),同时给直接返回 2 |
|
||||
| 缺台账 | `--strict` 直接返回 2 并提示先生成,**绝不退化成「一次性拦死全部存量」**(那样必然逼人 `--no-verify`) |
|
||||
| 台账自身不得当语料 | 关闸第一次提交就被自己的台账咬了:`id_known_backlog.json` 里必然写着 `P1-3` / `Trap 05` 这些号,扫描器当成新引用 → 报 10 类新账、提交被拦。已把台账加入 `excluded_paths`(与 `id_aliases.json` / `id_registry.json` 同一条道理:**登记号的表不是引用号的文档**。第 4 次同样自循环:改名映射表 `scripts/rename_maps/batch3-trap.json` 里必然写着 `Trap 21` / `陷阱 1` 这些旧形态,关闸后第一次提交就被它自己拦下 6 类「新账」→ 整个 `scripts/rename_maps/` 目录一并入 `excluded_paths`(它是审计轨迹,不是引用语料) |
|
||||
|
||||
**关闸验收(三例,2026-10-21 实测)**:
|
||||
|
||||
| 情况 | 期望 | 实测 |
|
||||
|---|---|---|
|
||||
| A 全新未登记前缀(`Z-99`)[示例] | 拦 | exit 1,`+1 [校验1] docs/tmp_teeth_a.md Z-99` ✅ |
|
||||
| B 同一文件里已登记的号**多出现一次**(计数 1→2) | 拦 | exit 1,`+1 [校验6] ui-verify/SKILL.md 内的 R-9` ✅ |
|
||||
| C 干净态(710 处存量全在台账内) | 放行 | exit 0,`增量拦截通过` ✅ |
|
||||
|
||||
临时注入文件与追加行当场还原(`git diff` 干净)。**C 例最关键**:放不住存量就会逼出 `--no-verify`,
|
||||
那是把门禁从「闸」降级成「报表」——本仓已有 mem-budget / mem-numbers 走 `--no-verify` 的先例,别再开第二个口子。
|
||||
|
||||
## 9. 落地阶段与验收
|
||||
|
||||
| 阶段 | 内容 | 验收判据 | 风险 |
|
||||
|---|---|---|---|
|
||||
| **0 规范** | 本文件;`docs/任务规划/README.md` §0 改为指向本规范的摘要;`docs/README.md`、`AGENTS.md`、`docs/文档规范.md` §6 登记;两份 `id_*.json` 初版 | `check_doc_links --all` 通过、`@build` 0/0 | 零(纯新增 + 指针) |
|
||||
| **0.5 语义标识** | §3.3 / §5.7 规范落地:登记簿、排期、波次的**存量条目转语义短语**(原号进别名表,`N-x`/`S-x`/`T-x`/`B`/`C`/`D`);代码注释裸编号(如 `N-18`)补语义;`DEF`/`WI`/`OQ`/`RSK`/`DR`/`GAP`/`SC` 按语义形态启用 | 每批:dry-run 通读 → 落盘 → `git grep` 零残留 → `check_doc_links --all` → `@build` 0/0 | 中(撞名与措辞漂移是主要风险) |
|
||||
| **1-① 小族** | `RC`/`PAT`/`GEN`/`RUN`/`MS`/`GAP`/`SC`/`OQ`/`RSK`/`DR`/`TRAP`/`ST`/`UL`/`LAT`/`CS` + Mermaid 节点 id + 孤儿处置 | 每批:dry-run 通读 → 落盘 → `git grep` 零残留 → `check_doc_links --all` → `@build` 0/0 → `ci_local.py` | 中 |
|
||||
| **1-② 大族** | `N` 补零 + `S`/`T` 并入;`WI` ← `B`/`C`/`D`/`W1-0`/`S1x`/`A-x`/`R-x`/`F-x`/`U-x`;测试分层 `L0~L3` → `T0~T3`(**最大机械批次**,`L0.5` 一词全库百余处) | 同上,逐族一个 commit | **高** |
|
||||
| **1-③ 缺陷族** | `DEF` ← `P0-x`~`P3-x` 在册项;报告历史编号补齐紧邻文档名;档位词规则落地;别名表与游标定稿 | 同上 | 中 |
|
||||
| **2 门禁** | ✅ **已落地(2026-10-20,warn-only)**:`scripts/check_ids.py` + `id-check` 钩子 + `scripts/id_registry.json` / `scripts/id_aliases.json`;`check_test_traceability.py` 已收编(正则补齐 + 纳入 7 篇「单元测试说明.md」与 `test/host/` 一侧) | 全库告警清零后 entry 加 `--strict` 转拦提交;可判定比例基线 **84.0%** 已入档(批 1 改名后由 82.3% 抬升,2026-10-25 删报告后由 82.6% 抬到 84.0%)(§8.1,写在 `id_registry.json` 里,跌破即失败) | 中(首轮确实暴露出 626 处真悬空 + 416 处形态违规 + 269 处未紧邻文档名,见 §8.1) |
|
||||
|
||||
每阶段结束停下等指令再提交(`AGENTS.md` 边界:commit/push 须明确指示)。
|
||||
|
||||
---
|
||||
|
||||
## 10. 常见错误速查
|
||||
|
||||
| 现象 | 原因 | 修复 |
|
||||
|---|---|---|
|
||||
| `id-check` 报"未登记前缀" | 自造了一套编号 | 查 §4 总表归到既有类别;确属新类别先改本规范 |
|
||||
| 同一编号在两篇文档各指一物 | 用了文档内编号却裸引 | 改全局编号,或引用补文档名(紧邻) |
|
||||
| 引用的编号查不到定义 | 孤儿/悬空 | 补定义行,或删引用 |
|
||||
| 降级后编号与事实不符 | 语义进了编号 | 违反 P-2;严重度改列,编号不动 |
|
||||
| 硬件文档里 `U1`/`C12` 被改 | 改写脚本没排除位号目录 | 回滚该批,按 §7.3 排除清单重跑 |
|
||||
| 改完中文变乱码 | 用了整文件重写 | 见 `AGENTS.md` 铁律:只用精确子串替换,BOM 按原样补回 |
|
||||
## 10. 速查
|
||||
- 看到一个不认识的号 → 先查 `id_aliases.json` 与属主登记表;查不到就**删号留事实**,不要补定义。
|
||||
- 想给待办 / 缺陷 / 差距 / 风险发号 → 不许,写短语(§3.3)。
|
||||
- 想给文档内步骤或测试阶段发号 → 不许,写「步骤 3」「阶段 7」(§3.3)。
|
||||
- 想新增前缀族 → 先回答"哪个脚本要按字面量匹配它"(§4.1);答不出就别建。
|
||||
- 要改号 → `scripts/rename_ids.py` + §7.3 五步。
|
||||
- 门禁报错读不懂 → `docs/门禁说明/id-check.md`。
|
||||
|
||||
---
|
||||
|
||||
@@ -606,14 +226,4 @@ git grep -n '<旧字面量>' # 零残留
|
||||
|
||||
| 日期 | 变更 | 说明 |
|
||||
|---|---|---|
|
||||
| 2026-10-23 | **主机侧单测族 +4(现共 13 族)** | 覆盖率口径 `docs/测试说明/主机单测覆盖率口径.md` §9 P1 第①批新建 `test/host/{net_cfg,ftp_cfg,prot_set_store,task_prof}` 四个模块,按 2026-10-21 批 3 的同一 B 层口径补建 `TC-HOST-{NETCFG,FTPCFG,PROTSTOR,TASKPROF}`(代码即属主登记处、`allow_orphans`、游标按实测最大号 056/014/016/020)。**验证了这条口径真的在拦东西**:建族前,文档里引用 `TC-NETCFG-028` 被判「台账之外的新账」而卡提交;建族后 `--strict` 通过 |
|
||||
| 2026-10-14 | 新增 P-7 与引用可读性规则 | §2 加 **P-7「编号不语义,引用必语义」**(编号本体保持无语义并冻结,但正文引用必须带语义括注、禁裸 ID 独担信息)→ 六条原则变**七条**;§5.1 加前置步"先问能不能不加号";新增 **§5.6「编号密集文档的对照节(强制)」**(≥3 个编号族必须加「导读:编号与术语」);§4.1 补登记 **`E\d+`**(N34 自愈实验编号族,已封闭)并把 `N-\d{2}` 的在册范围订正为「曾用最大 `N-33`,现存至 `N-29`」;§1.2 悬空引用示例补 `N-32`;§7.1 同步订正。起因:`docs/网络/网络自愈架构设计.md` 合并与导读节实践暴露"裸编号引用不可读",用户裁定以后尽量用语义标识 |
|
||||
| (规划稿) | 建立本文档 | 全库扫描 1,385 个不同编号 / 19,306 处出现后定稿的两层编号体系(全局编号 + 文档内编号)、六条原则、目标前缀总表、三批迁移映射与 `check_ids.py` 门禁设计;用户决策:`E-xx` 冻结保留、严重度档位词 `P0~P3` 不变、文档落 `docs/编号规范.md`、阶段 1 三批全做 |
|
||||
| 2026-10-21 | **批 5:追溯器口径补齐(未改任何号)** | `check_test_traceability.py` 加入与 `check_ids.py`/`rename_ids.py`/`doc-links` 同源的「变更记录 / `[示例]` / `[计划]` 行不参与比对」豁免,并新增 `frozen_ids` 留痕(`--verbose` 可列);`DOC-ONLY` 38 → 29、总差异 45 → 36,**交集 260 → 260 不变**(证明没吞掉真对应)。批 5 原计划的 8 处文档侧改名**被证据否掉**(全在变更记录行、别名批 2 已登记),未落盘;经过与教训、以及剩 29 处的三类真问题都写进 §8.3 批 5 段 |
|
||||
| 2026-10-21 | **批 4:陷阱号统一(② 清的第一族)** | 23 处 / 11 文件:`Trap 01~07` → `TRAP-GD5F-01~07`(属主文档 7 个标题行从此成为定义位)、`陷阱 1` → `TRAP-RTC-01`、`Trap 21`/`Trap 19` → `TRAP-NET-21`/`TRAP-NET-19`;UI 文档自指改写成平实语言。别名 11 条全部带 scope。改名后 `TRAP-GD5F-01/05/06` 三处历史悬空引用自动落地为已定义;三处刻意不改与 `docs/硬件平台/` 盲区写进 §8.3 批 4 |
|
||||
| 2026-10-21 | **关闸:`id-check` 转增量拦截** | `check_ids.py` 新增 `--write-backlog` / `--prune-backlog` 与按台账比对的 `--strict`(指纹 = 文件 + 校验号 + 字面量 + 计数,**不含行号**);生成 `scripts/id_known_backlog.json`(340 条覆盖 710 处存量);钩子 `entry` 加 `--strict`。验收三例:新字面量拦、同号计数增长拦、干净态放行,全通过。新增 §8.4 说明机制与「为什么不照清零再升 strict 的原节奏」 |
|
||||
| 2026-10-21 | **追溯脚本同口径对齐** | `check_test_traceability.py` 差异定义改为 DOC-ONLY / CODE-ONLY / IN-CODE 三档(真差异 45 = 38 + 7;弱保证 238 单列示数);顺带修 `TC_RE` 模块码上界 `{0,4}`→`{0,8}`——**同一个坑第二次踩**(代码侧一度从 556 缩到 217),已写进 §8.1 |
|
||||
| 2026-10-21 | **B 层口径落地(批 3)** | 主机侧单测 118 号实测在代码目录外零消费者 → 建 9 族 `TC-HOST-*` 认代码为属主登记处(不逐号补文档);新增 `subitem_ok`(小写子项后缀母号在册即算已定义)、`snapshot_only`(§4.3 冻结快照族不参与定义位优先)、`allow_orphans` 旗标与 `excluded_paths` 补两项;补 `docs/任务规划/README.md` 为 `N`/`S-LDG`/`T-LDG` 属主(**我的配置漏项,曾误判 74 处真条目悬空**);`T-2`/`T-3`/`T-4`/`T-6` 入别名表标 `void`。错误级 1318 → 711(其中 504 处属口径修正、74 处属修 bug,**真正变好 0 处**)。新增 §8.1 口径修正记录表 |
|
||||
| 2026-10-20 | **编号改名开禁(用户授权)+ 批 1 落地** | 新增 `scripts/rename_ids.py`(§7.3 规划脚本:映射表驱动、显式 scope、干跑/落盘两态、自动写 `id_aliases.json` 的 scoped 条目、跳过 `[示例]`/`[计划]` 行与变更记录表、按原字节读写保 BOM 与行尾)。**批 1**:代码规范条款 `S1~S19` → `CODE-RULE-nn`(78 处/2 文件)、UI 像素回归状态 `S0~S7` → `MENU-STATE-nn`(61 处/3 文件);`check_ids.py` 支持 **scoped 别名** 并登记两族(66 族);可判定比例 82.3% → **82.7%**、裸形判错 71 → 50、错误级 1312 → 1291。§4.1 补两行、新增 §8.3 迁移批次记录 |
|
||||
| 2026-10-20 | **§8 门禁落地(warn-only)** | 新增 `scripts/check_ids.py`(八项校验 + 可判定比例基线)、`scripts/id_registry.json`(逐项来自 §4 总表 + 实测游标)、`scripts/id_aliases.json`;挂上 `id-check` 钩子(36→37);顺带收编 `check_test_traceability.py`(正则补齐大写后缀/无模块码形态,比对范围扩到 7 篇「单元测试说明.md」+ `test/host/` 一侧,另加 `--board-only` 回退原口径)。**新增 §8.1 落地记录**(基线 82.3%、backlog 分布、有牙实测、显式盲区)与 **§8.2 规范↔仓库偏差表**(`E19`、`FR` 未补零、`TC` 模块码含数字、`F-<MOD>-<nn>` 总表缺行、`N` 子项后缀/扩位);§4.1 相应行按实测订正并补 `F-<MOD>` / `P-<n>` 两行 |
|
||||
| 2026-10-15 | 新增 P-8 与语义标识规范(§3.3 / §5.7) | §2 加 **P-8「语义优先」**(规划 / 待办类条目优先用语义标识,不发字母+数字号)→ 七条原则变**八条**;§3 主轴由"两层编号"扩为**编号 / 语义标识 / 章节引用**三种;新增 **§3.3「语义标识(新条目默认形态)」**(形态规则、适用分界、引用写法)与 **§5.7「语义标识的登记、冻结与别名」**;§4.2 加修订说明(规划类前缀改语义标识,`TC`/`TRAP`/`FR`/`NFR`/`RC` 等保留编号);§9 加「0.5 语义标识」阶段。起因:用户裁定去除字母数字编号(难理解),先定规范本体 |
|
||||
| 2026-10-26 | **编号治理收口:清死号 → 停发活号 → 本文重写为短版(用户三次裁定)** | 全仓字母+数字编号 10,956 → 8,230 处。① **清死号**:属主登记处已删或从未启用的号一律就地删号留事实、禁补号(文本实删约 1,557 处)。② **停发活号**:登记簿 `N-x`/`S-x`/`T-x`、专项 `A-x`、已删报告的 UI 簇 `U1~U5` 共 20 个号转成语义短语(约 418 处)——登记簿表首格就是短语,旧号进 `scripts/id_aliases.json` 标 `retired-to-phrase`;已销项的死号**故意不进别名表**,让门禁继续咬残留引用。③ **本文瘦身**:619 行 → 229 行,删掉八原则长表、迁移映射表、模块码表与门禁细节(那些各有事实源:registry / 别名表 / `docs/门禁说明/id-check.md`),改成「先问三句再决定要不要发号」+ §4.1 允许用号的族**穷举 = 8 个**。④ **门禁配套**:`check_ids.py` 加变更记录行豁免与第二根护栏 `undecidable_total_ceiling`(比值会被清号动作稀释,绝对数不会),债务台账还清到 0 条 → `--strict` 实为全量拦截,比例基线重打为 86.0%。**本表按用户 2026-10-26 的明确指示只保留最近一条**,更早沿革看 `git log` 与 `docs/门禁说明/id-check.md` §7.5(含其后的方案 B 一节);这是**本文档的例外**,不改变 §5.5对其他文档「冻结历史不回改」的约束。 |
|
||||
|
||||
@@ -177,7 +177,7 @@ int net_close_sock(net_sock_t *p_sock);
|
||||
- **消息队列由 CubeMX 创建**:在 `MX_FREERTOS_Init()`(`osKernelInitialize()` 之后)中调用 `osMessageQueueNew(8, sizeof(net_msg_t), NULL)` 创建
|
||||
- **队列句柄全局可见**:通过 `extern osMessageQueueId_t netMsgQueueHandle` 引用
|
||||
- **`netTask` 不可向自身发消息**:`netTask` 中直接调 `net_send()` 会死锁(等待自己处理消息),必须在 `netTask` 中使用 `net_send_sock()` 等内部版本
|
||||
- **阻塞 recv 不独占 netTask(挂起 recv 模型)**:无数据时公共 `net_recv()` / `net_recv_to()` **登记挂起请求后返回**(每 fd 至多一个,禁止覆盖——覆盖即丢失前调用方通知 = 永久挂死);完成由 `net_pending_tick()` 按主循环节拍检查(①数据 ②到点[仅显式预算] ③断连)并经任务通知唤醒调用方——等待期间调用方在自己上下文睡通知,netTask 零占用(消除 E-02 头阻塞)。副作用:`buf` 指针须保持有效至返回;close / 网络重建 / 陈旧重同步会**显式取消并通知**(`NET_ERR_CONNRESET` 等),调用方永不挂死
|
||||
- **阻塞 recv 不独占 netTask(挂起 recv 模型)**:无数据时公共 `net_recv()` / `net_recv_to()` **登记挂起请求后返回**(每 fd 至多一个,禁止覆盖——覆盖即丢失前调用方通知 = 永久挂死);完成由 `net_pending_tick()` 按主循环节拍检查(①数据 ②到点[仅显式预算] ③断连)并经任务通知唤醒调用方——等待期间调用方在自己上下文睡通知,netTask 零占用(消除队头阻塞)。副作用:`buf` 指针须保持有效至返回;close / 网络重建 / 陈旧重同步会**显式取消并通知**(`NET_ERR_CONNRESET` 等),调用方永不挂死
|
||||
- **recv 语义主流化**:对齐 POSIX/Python——**模式归使用者、超时归调用方、API 不强加默认预算**。`net_recv()` 默认**无限阻塞**(`NET_RECV_TIMEOUT_MS` 30s 默认已删),唤醒源 = 数据 / EOF / close / 网络重建(CONNRESET),会话死亡由对账① ~400ms 判死兜底;非阻塞具名入口 `net_recv_nb()`(原 `NET_MSG_DONTWAIT` 路径转正),模式属性 `net_setblocking(fd, on)` 挂 socket 控制块;超时首选 `net_select(...)`,`net_recv_to(...)` 保留为**显式预算**便捷入口。内部看门狗降级为 **tripwire**:挂起超 60s 只 `[ERR]` 留痕一条(完成逻辑缺位探针),不再伪造 TIMEDOUT 返回值。⚠ **文档契约(嵌入式特有)**:IWDG `required_mask` 内任务**禁止无限阻塞 recv**——必须 `net_select` 超时或 `net_recv_to` 显式预算("超时归使用者"对受监控任务是义务不是选项)
|
||||
- **阻塞 send 不独占 netTask(挂起 send 模型)**:`net_send()` 快路径**有界自旋**等发送缓冲腾出(预算 `NET_SEND_SPIN_MS` = 2ms;健康链路实测块间等待 med 219µs ≪ 2ms,故正常发送不会触发挂起),超预算即登记挂起 send 返回;推进由 `net_send_pending_tick()` 按主循环节拍分块完成(①断连 ②推进 ③写完 ④无进展超时),调用方睡任务通知——netTask 最坏停滞由 `NET_SEND_TIMEOUT_MS`(1s)压到 2ms。返回值恒为**已写入字节数**:`= len` 全部写入,`< len` 为**短写**,调用方**必须**检查并重试剩余(断连/超时/取消均以已发字节数结束,不会伪造全部成功)。停滞计时按**无进展**刷新(每次成功写块重置),大文件传输不会被误判超时
|
||||
- **队列阻塞语义**:只有 `osMessageQueuePut` 失败(8 长度固定队列,极端情形)时公共 API 阻塞;recv / send 挂起等待**不计入**队列占用(完成前队列中无消息滞留)
|
||||
@@ -191,7 +191,7 @@ int net_close_sock(net_sock_t *p_sock);
|
||||
|---|---|---|---|
|
||||
| **`auto_relisten`** | 数据通道正常 EOF / DISCONNECT | 重开 + 重新 LISTEN,回 LISTENING;应用层无需 close/重 listen | `net_listen()` 置位;`net_close()` 清 |
|
||||
| **D10 非阻塞重监听重试** | 重开失败(TRAP-NET-09:芯片 close 后需沉降) | 单次尝试失败即登记待重试,每轮到点重试;超时限放弃并记 `relisten give up` | 重试间隔 30ms / 时限 2s(自首次尝试);同 fd 有在途挂起 recv / send 时跳过(挂起保险,防毁在途连接 / 截断在途传输) |
|
||||
| **TRAP-NET-17 周期对账 + 监听重建(合一 `net_reconcile_tick`;对账①②⑤ + 原 pump③④/U11)** | 芯片 CONNECT/DISCONNECT 事件未收到(快速复连,读清消费竞态——E14 复核:非芯片侧丢失);静默回收 Socket(peer FIN,无 DISCONNECT 事件);监听型 fd 芯片监听失位 / 本层状态滞后 | 每 100ms 对在用 socket 读**驱动状态缓存**(`ch395f_sock_state_cached`,唯一刷新点 = `net_poll` 每轮全量刷新,E2 实测单次回读 18.1µs),修正**五类**失同步 + 一类被动重同步:① 本层 ESTABLISHED 而芯片已断 → 按断开处理(只置事实);② 本层 LISTENING 而芯片已握手 → 补 accept(N-30 幽灵甄别);③ 本层 LISTENING 而芯片监听失位 → 重建(`net_listener_request`);④ 本层 CLOSED(监听型 fd)而芯片不在 LISTEN → 重建;⑤ 本层 ESTABLISHED 而芯片已静默回收回 LISTEN(0x05/0x01)→ RESYNC 语义只修本层、不发芯片命令(原手动 API `net_resync_listen` 的语义并入);U11 本层 CLOSED 而芯片**正在** LISTEN → 只做状态重同步、不发芯片命令 | 周期 100ms;**分级去抖**:②=1 轮、③④⑤=2 轮、①=4 轮(M3 让位窗 400ms,**勿改小**)+ 动手后 **1s 冷却**(防"刚 open 未生效"瞬态重建风暴;U11 被动重同步不去抖、不占冷却);其它位置只置事实、不做重建动作 |
|
||||
| **TRAP-NET-17 周期对账 + 监听重建(合一 `net_reconcile_tick`;对账①②⑤ + 原 pump③④/U11)** | 芯片 CONNECT/DISCONNECT 事件未收到(快速复连,读清消费竞态——E14 复核:非芯片侧丢失);静默回收 Socket(peer FIN,无 DISCONNECT 事件);监听型 fd 芯片监听失位 / 本层状态滞后 | 每 100ms 对在用 socket 读**驱动状态缓存**(`ch395f_sock_state_cached`,唯一刷新点 = `net_poll` 每轮全量刷新,E2 实测单次回读 18.1µs),修正**五类**失同步 + 一类被动重同步:① 本层 ESTABLISHED 而芯片已断 → 按断开处理(只置事实);② 本层 LISTENING 而芯片已握手 → 补 accept(幽灵甄别,属「relisten 沉降段原语化受阻」);③ 本层 LISTENING 而芯片监听失位 → 重建(`net_listener_request`);④ 本层 CLOSED(监听型 fd)而芯片不在 LISTEN → 重建;⑤ 本层 ESTABLISHED 而芯片已静默回收回 LISTEN(0x05/0x01)→ RESYNC 语义只修本层、不发芯片命令(原手动 API `net_resync_listen` 的语义并入);U11 本层 CLOSED 而芯片**正在** LISTEN → 只做状态重同步、不发芯片命令 | 周期 100ms;**分级去抖**:②=1 轮、③④⑤=2 轮、①=4 轮(M3 让位窗 400ms,**勿改小**)+ 动手后 **1s 冷却**(防"刚 open 未生效"瞬态重建风暴;U11 被动重同步不去抖、不占冷却);其它位置只置事实、不做重建动作 |
|
||||
| **TRAP-NET-18 排渣隔离** | 异常释放(芯片 TIMEOUT,如客户端中止上传):在途数据落进 RX 缓冲,直接复监听 → 下条连接把 ~2048B 残渣当自己的数据读走(上传静默截断);正常 FIN 释放亦有残留 DISCONNECT 收尾问题 | 复监听前沉降/隔离:持续排空 RX 残渣 + 主动 close + 排空中断,等芯片回 CLOSED/TCP_CLOSED 才 open+listen;到期强制放行 | 沉降等级(`net_listener_settle`):异常释放 QUARANTINE **400ms** / 正常释放 GRACEFUL **100ms**(2026-09-24 起正常 FIN 亦需沉降);上限 **800ms** 强制放行(**必须 < 2s 时限**,否则监听被放弃) |
|
||||
|
||||
**行为结论**:监听器恢复从"一次性事件"变为"登记 → 到点重试"过程:
|
||||
@@ -249,7 +249,7 @@ int main(void)
|
||||
- 更新所有 Socket 的连接状态(CONNECT / DISCONNECT / RECV / TIMEOUT)
|
||||
- 触发事件回调
|
||||
- 处理数据接收
|
||||
- `net_process_messages()` 每轮先跑 4 个**非阻塞**检查再取队列:D10 重监听重试(断连后监听器恢复)→ 挂起 recv 完成检查(阻塞 recv 唤醒,E-02 修复)→ 挂起 send 推进(阻塞 send 唤醒)→ TRAP-NET-17 芯片/本层对账 + 监听重建合一 reconciler(100ms 周期,读驱动状态缓存,事件未收到/静默回收/监听失位自愈,§3.6)
|
||||
- `net_process_messages()` 每轮先跑 4 个**非阻塞**检查再取队列:D10 重监听重试(断连后监听器恢复)→ 挂起 recv 完成检查(阻塞 recv 唤醒,队头阻塞修复)→ 挂起 send 推进(阻塞 send 唤醒)→ TRAP-NET-17 芯片/本层对账 + 监听重建合一 reconciler(100ms 周期,读驱动状态缓存,事件未收到/静默回收/监听失位自愈,§3.6)
|
||||
- **监听 Socket 建立**:由就绪屏障后的服务任务(timeSyncTask / ftpTask / uiTask)经队列 API 建立(`net_socket` → `net_bind` → `net_listen`);断连后 net 层自动重监听(§3.6),服务层只需循环 `net_accept`,无需维护重监听逻辑
|
||||
|
||||
```c
|
||||
@@ -962,7 +962,7 @@ int net_recv(int sockfd, void *buf, int len, int flags);
|
||||
|
||||
> **语义主流化**:对齐 POSIX/Python——`net_recv()` 默认**无限阻塞**(旧 `NET_RECV_TIMEOUT_MS` 30s 默认预算已删,API 不再强加隐藏值)。唤醒源 = 数据 / EOF / close / 网络重建(`NET_ERR_CONNRESET`);会话死亡由对账①在 ~400ms 内判死兜底(§3.6),不存在"对端消失后永久挂死"窗口。需要"等但不无限等":首选 `net_select(r,w,e,timeout_ms)`(§7.1),或 `net_recv_to()` 显式预算。
|
||||
>
|
||||
> **挂起 recv 模型**:无数据时阻塞接收**不占 netTask**——登记挂起请求(每 fd 至多一个,禁止覆盖:覆盖会丢失前调用方通知 = 永久挂死)后**立即返回**;完成按主循环节拍检查(①数据 ②到点[仅显式预算] ③断连)并经任务通知唤醒调用方。等待期间调用方在自己上下文睡通知,netTask 全程零占用(消除 E-02 头阻塞)。内部 tripwire(原看门狗降级):挂起超 60s 只 `[ERR]` 留痕一条("完成逻辑缺位"探针),**绝不伪造 TIMEDOUT 返回值**。
|
||||
> **挂起 recv 模型**:无数据时阻塞接收**不占 netTask**——登记挂起请求(每 fd 至多一个,禁止覆盖:覆盖会丢失前调用方通知 = 永久挂死)后**立即返回**;完成按主循环节拍检查(①数据 ②到点[仅显式预算] ③断连)并经任务通知唤醒调用方。等待期间调用方在自己上下文睡通知,netTask 全程零占用(消除队头阻塞)。内部 tripwire(原看门狗降级):挂起超 60s 只 `[ERR]` 留痕一条("完成逻辑缺位"探针),**绝不伪造 TIMEDOUT 返回值**。
|
||||
>
|
||||
> ⚠ **文档契约(嵌入式特有,Python 没有)**:IWDG `required_mask` 内任务(当前产品掩码 `0x1F7`:default/net/ftp/ui/timeSync/adc/iec104/protect)**禁止无限阻塞 recv**——必须 `net_select` 超时或 `net_recv_to` 显式预算并周期喂心跳,否则"对端连上不发数据"这种完全正常的场景 = IWDG 复位。
|
||||
|
||||
@@ -1005,7 +1005,7 @@ int net_recv_to(int sockfd, void *buf, int len, uint32_t timeout_ms);
|
||||
| `timeout_ms` | 本片等待预算(ms,**必须 >0**;0 = `net_recv` 的无限等待语义,恰与本接口"有界"存在理由相反,直接拒 `NET_ERR_INVAL`——本接口是**显式预算**入口,没有"默认 30s"隐藏值) |
|
||||
| 返回值 | >0=字节数(允许部分读,TCP 分段);`0`=对端关闭(排空残留后);`-1`=真错误(`net_get_errno` 可查);**-2=本片预算内无数据**(**不是 errno**,不得依赖 errno 判超时——`s_net_errno` 是跨任务共享全局量) |
|
||||
|
||||
调用方累计自身总预算:见到 -2 发起下一片,直到收齐 / EOF / 总预算耗尽。生产用途:lftpd 数据行读、timeSync 帧读(E-02 头阻塞修复,完整例 §11.2);受 IWDG 监控任务的长等待必须走本接口(或 `net_select`)+ 每片喂心跳。
|
||||
调用方累计自身总预算:见到 -2 发起下一片,直到收齐 / EOF / 总预算耗尽。生产用途:lftpd 数据行读、timeSync 帧读(队头阻塞修复,完整例 §11.2);受 IWDG 监控任务的长等待必须走本接口(或 `net_select`)+ 每片喂心跳。
|
||||
|
||||
#### net_sendto - 发送 UDP 数据
|
||||
|
||||
@@ -1029,7 +1029,7 @@ int net_close(int sockfd);
|
||||
|
||||
释放 Socket 控制块,TCP 先断开连接。⚠ **单连接模型(MCU 端 CH395F)不得对监听 fd 调本 API**——连接与监听同一 fd,close 会连监听一起毁掉(§12.4);EOF 时 net 层已 `auto_relisten`,应用层**不得**在 EOF 时 close 该 fd。"放弃会话但保监听"用下面的 `net_drop_conn()`。
|
||||
|
||||
#### net_drop_conn - 主动拆会话、保留监听(E-02 收口)
|
||||
#### net_drop_conn - 主动拆会话、保留监听(队头阻塞收口)
|
||||
|
||||
```c
|
||||
int net_drop_conn(int sockfd);
|
||||
@@ -1042,7 +1042,7 @@ int net_drop_conn(int sockfd);
|
||||
- **EOF 路径不要调**:EOF 时 net 层 `auto_relisten` 已接管(§12.4),无需也不应再拆
|
||||
- 经消息队列委托 netTask(同其它 `net_*` API,非 netTask 上下文调用);等待期 netTask 有界占用 ~400-600ms
|
||||
- 模拟器(`net_socket_sim.c`,数据 fd ≠ 监听 fd)实现为关数据连接、监听常驻
|
||||
- 台架定案(2026-10-13,E-02):CH395F close **无 RST 语义**——对端内核存活但不 close 时芯片停 FIN_WAIT_2 长尾,监听恢复受限于对端 close;对端配合则 TIME_WAIT 过渡 ~150ms → reconciler 形态④ relisten → 新连接接入。不配合场景兜底 = 芯片 TIMEOUT/keepalive 拆僵尸(E13 定案 30~90s)。详见 `docs/问题记录/CH395F_Trap_Records.md` TRAP-NET-07
|
||||
- 台架定案(2026-10-13):CH395F close **无 RST 语义**——对端内核存活但不 close 时芯片停 FIN_WAIT_2 长尾,监听恢复受限于对端 close;对端配合则 TIME_WAIT 过渡 ~150ms → reconciler 形态④ relisten → 新连接接入。不配合场景兜底 = 芯片 TIMEOUT/keepalive 拆僵尸(E13 定案 30~90s)。详见 `docs/问题记录/CH395F_Trap_Records.md` TRAP-NET-07
|
||||
|
||||
#### 自愈与查询 API
|
||||
|
||||
@@ -1257,7 +1257,7 @@ void tcp_client_reconnect(void)
|
||||
|
||||
### 11.2 分片阻塞读(`net_recv_to`,timeSync 模式)
|
||||
|
||||
长等待 recv 曾独占 netTask(E-02 头阻塞)。挂起 recv 模型下:单次 `net_recv_to` 单次占用有界(≤ 本片预算)且等待期间 netTask 零占用(挂起模型);调用方累计总预算,收齐协议帧再返回:
|
||||
长等待 recv 曾独占 netTask(队头阻塞)。挂起 recv 模型下:单次 `net_recv_to` 单次占用有界(≤ 本片预算)且等待期间 netTask 零占用(挂起模型);调用方累计总预算,收齐协议帧再返回:
|
||||
|
||||
```c
|
||||
#define FRAME_LEN 8 /* "TIME" + uint32 大端 本地时间 */
|
||||
|
||||
@@ -117,7 +117,7 @@ flowchart TB
|
||||
|
||||
| 函数 | 设计作用 | 主要调用 | 意图 / 注意 |
|
||||
|---|---|---|---|
|
||||
| `net_init(ip,mask,gw,mac)` | 芯片一次性配置:探测/复位 → 参数 → MAC → 协议栈初始化 → 8 Socket 缓冲布局 → 使能 PING | `net_pending_cancel_all` → `ch395f_check_exist` / `ch395f_reset` / `set_fun_para(0x08)` / `set_tcp_mss` / `set_retrans_count+period` / `set_keepalive_idle+intvl+cnt` → `set_mac_addr` → `parse_ip_string` + `set_ip_addr` / `set_gwip_addr` / `set_mask_addr`(或 `set_dhcp`)→ `ch395f_init` → `set_send_buf` / `set_recv_buf` ×8 → `ping_enable` | ① **重建前**先取消全部挂起 recv 并逐一通知(不通知 = 调用方永久挂死),且必须早于控制块清零与芯片复位;② 重传/KeepAlive/**MAC**/IP/GW/MASK 参数**必须**在 `ch395f_init` 之前下发(`docs/芯片手册/CH395F.md` §9.2.1:SET_MAC 为步骤①,INIT_CH395 加载 MAC——顺序反了本次上电不生效,P1-7);③ `fun_para=0x08`:bit3 SOCKET_CLOSE(DISCONNECT/TIMEOUT 后不清缓冲,软件排空后手动关);bit0/bit1 保持 0——8 个 Socket 由索引 `_SN` 寻址 + 缓冲显式分配实现,与 FUN_PARA 无关(bit0 是保留位,必须为 0);④ 缓冲布局每 Socket 6 块(收 4 + 发 2)×8 = 48 块恰好用尽,Socket 0~7 必须显式重分配(TRAP-NET-01/-02);⑤ 捕获 `xTaskGetCurrentTaskHandle` 存入 `s_net_task_handle`(防自通知死锁的判据) |
|
||||
| `net_init(ip,mask,gw,mac)` | 芯片一次性配置:探测/复位 → 参数 → MAC → 协议栈初始化 → 8 Socket 缓冲布局 → 使能 PING | `net_pending_cancel_all` → `ch395f_check_exist` / `ch395f_reset` / `set_fun_para(0x08)` / `set_tcp_mss` / `set_retrans_count+period` / `set_keepalive_idle+intvl+cnt` → `set_mac_addr` → `parse_ip_string` + `set_ip_addr` / `set_gwip_addr` / `set_mask_addr`(或 `set_dhcp`)→ `ch395f_init` → `set_send_buf` / `set_recv_buf` ×8 → `ping_enable` | ① **重建前**先取消全部挂起 recv 并逐一通知(不通知 = 调用方永久挂死),且必须早于控制块清零与芯片复位;② 重传/KeepAlive/**MAC**/IP/GW/MASK 参数**必须**在 `ch395f_init` 之前下发(`docs/芯片手册/CH395F.md` §9.2.1:SET_MAC 为步骤①,INIT_CH395 加载 MAC——顺序反了本次上电不生效);③ `fun_para=0x08`:bit3 SOCKET_CLOSE(DISCONNECT/TIMEOUT 后不清缓冲,软件排空后手动关);bit0/bit1 保持 0——8 个 Socket 由索引 `_SN` 寻址 + 缓冲显式分配实现,与 FUN_PARA 无关(bit0 是保留位,必须为 0);④ 缓冲布局每 Socket 6 块(收 4 + 发 2)×8 = 48 块恰好用尽,Socket 0~7 必须显式重分配(TRAP-NET-01/-02);⑤ 捕获 `xTaskGetCurrentTaskHandle` 存入 `s_net_task_handle`(防自通知死锁的判据) |
|
||||
| `net_get_generation()` | 读网络代次号(纯 RAM) | 无 | FTP/UI/对时服务据此感知"网络已重建"→ 放弃旧监听并重建 |
|
||||
| `net_generation_inc()` | 代次号 +1 | 无 | 唯一合法递增点 = `net_stack_bring_up()` 末尾(PHY/链路就绪后)——太早递增会让服务在网络不可用时抢跑重建;模拟器端恒为 0(无重建概念,上层自愈逻辑空转) |
|
||||
|
||||
@@ -140,9 +140,9 @@ flowchart TB
|
||||
| `net_send` | `NET_MSG_SEND` | `net_send_locked` | `ch395f_write_send_buf`(分块)+ 等 SENBUF_FREE(`net_poll` 轮询,**有界自旋 ≤ `NET_SEND_SPIN_MS`**);超预算登记挂起 send(`net_send_pending_register`) | 实际字节数 / -1 | 分块 ≤ `NET_SEND_CHUNK_MAX` = 1KB(**硬件发送 FIFO 硬上限**,TRAP-NET-16:写穿 FIFO = 数据错位);`send_ready` 门控用 `net_poll` 轮询而非 osDelay,**自旋超 `NET_SEND_SPIN_MS`(2ms)即转挂起**(netTask 最坏停滞由 1s 压到 2ms);短写**必须**告警——静默截断会让对端永久等待剩余字节(2026-09-21 实证:UI 推流应答截断 → 客户端失联) |
|
||||
| `net_recv` | `NET_MSG_RECV`(timeout=0→**无限等待**,无 30s 默认预算) | `net_recv_locked` | `net_poll` + `get_recv_len` / `read_recv_buf` | >0 / 0(EOF) / -1(errno = WOULDBLOCK / CONNRESET;阻塞形态无 TIMEDOUT 一档) | 快路径:数据已在 → 立即读出返回(允许部分读);无数据 + 阻塞(`blocking` 属性=1 且未 DONTWAIT)→ **登记挂起后立即返回**(挂起登记,netTask 零占用),唤醒源=数据/EOF/close/网络重建;DONTWAIT / `blocking=0` + CLOSED/session_dead → EOF + 触发重监听;⚠ IWDG 受监控任务禁用无限形态(`net_socket.h` 文档契约) |
|
||||
| `net_recv_nb` | `NET_MSG_RECV`(flags=DONTWAIT) | `net_recv_locked` | 同上 | >0 / 0 / -1(WOULDBLOCK 等) | 原 `NET_MSG_DONTWAIT` 路径转正的具名入口;不改变 `blocking` 属性;受 IWDG 监控 / 有周期职责任务的推荐默认(ui_net_sink / iec104_serv 已迁) |
|
||||
| `net_recv_to` | `NET_MSG_RECV`(timeout>0) | `net_recv_locked` | 同上 | >0 / 0 / -1 / **-2(本片超时无数据)** | E-02 头阻塞修复配套 + **显式预算**入口(等价 Python settimeout,无隐藏默认值):调用方把长等待切成有界片(如剩余预算),**总超时语义不变、单次占用有界**;`timeout_ms=0` 直接拒(0 = 无限等待,与本接口"有界"存在理由相反);超时**只凭 -2 判定、不得依赖 errno**(`s_net_errno` 是跨任务共享全局量,随时被别的任务覆盖) |
|
||||
| `net_close` | `NET_MSG_CLOSE` | `net_close_locked` | `ch395f_cmd_done(CLOSE)` 快路径(芯片已 CLOSED → 只清本 Socket 残留事件)/ `net_sock_reset_sync(GRACEFUL)` 确定性排渣 | 0 / -1 | **先**结束本 fd 挂起 recv(排空/取消 + 必通知,关不得让等待者悬挂);排空只碰本 Socket SINT,**不再读清全局中断寄存器**(F-NET-7:全局唯一读者 = `net_poll`);原"close + 500ms 盲等排空循环"已换 sock_reset(内置 LISTEN 态二段 CLOSE 补发,E2 补充发现);控制块整体清零(`last_peer_port` 幽灵基准跨 fd 保留,N-30) |
|
||||
| `net_drop_conn` | `NET_MSG_DROP_CONN` | `net_drop_conn_locked` | `net_pending_settle_close` + `net_sock_reset_sync(QUARANTINE)` +(auto_relisten)`net_listener_request` | 0(含幂等)/ -1 | **拆会话保监听**(E-02 收口):应用放弃会话(对时 30s 预算耗尽 / 协议超时)而单连接监听被挂起对端永久占住时的应用侧出口;EOF 路径**不得**调(`auto_relisten` 已接管);非 ESTABLISHED/CONNECTING 直接返 0 不动监听;本层收口 CLOSED 不清 fd(保留 local_port/auto_relisten),监听型 fd 登记重监听、失败交 D10 + reconciler 形态④ |
|
||||
| `net_recv_to` | `NET_MSG_RECV`(timeout>0) | `net_recv_locked` | 同上 | >0 / 0 / -1 / **-2(本片超时无数据)** | 队头阻塞修复配套 + **显式预算**入口(等价 Python settimeout,无隐藏默认值):调用方把长等待切成有界片(如剩余预算),**总超时语义不变、单次占用有界**;`timeout_ms=0` 直接拒(0 = 无限等待,与本接口"有界"存在理由相反);超时**只凭 -2 判定、不得依赖 errno**(`s_net_errno` 是跨任务共享全局量,随时被别的任务覆盖) |
|
||||
| `net_close` | `NET_MSG_CLOSE` | `net_close_locked` | `ch395f_cmd_done(CLOSE)` 快路径(芯片已 CLOSED → 只清本 Socket 残留事件)/ `net_sock_reset_sync(GRACEFUL)` 确定性排渣 | 0 / -1 | **先**结束本 fd 挂起 recv(排空/取消 + 必通知,关不得让等待者悬挂);排空只碰本 Socket SINT,**不再读清全局中断寄存器**(F-NET-7:全局唯一读者 = `net_poll`);原"close + 500ms 盲等排空循环"已换 sock_reset(内置 LISTEN 态二段 CLOSE 补发,E2 补充发现);控制块整体清零(`last_peer_port` 幽灵基准跨 fd 保留,属「relisten 沉降段原语化受阻」) |
|
||||
| `net_drop_conn` | `NET_MSG_DROP_CONN` | `net_drop_conn_locked` | `net_pending_settle_close` + `net_sock_reset_sync(QUARANTINE)` +(auto_relisten)`net_listener_request` | 0(含幂等)/ -1 | **拆会话保监听**(队头阻塞收口):应用放弃会话(对时 30s 预算耗尽 / 协议超时)而单连接监听被挂起对端永久占住时的应用侧出口;EOF 路径**不得**调(`auto_relisten` 已接管);非 ESTABLISHED/CONNECTING 直接返 0 不动监听;本层收口 CLOSED 不清 fd(保留 local_port/auto_relisten),监听型 fd 登记重监听、失败交 D10 + reconciler 形态④ |
|
||||
| ~~`net_relisten`~~ | ~~`NET_MSG_RELISTEN`~~ | **已删除**(消息类型同删) | — | — | 原"无条件芯片侧重建"与 pump/D10 完全重叠,且对健康监听器是 footgun(open→USE→close 自毁 ~1s);生产零调用。历史实现见 `net_socket.c` git 历史 |
|
||||
| ~~`net_resync_listen`~~ | ~~`NET_MSG_RESYNC_LISTEN`~~ | **已删除**(语义并入对账⑤) | — | — | D14 静默回收(芯片自行回监听、不发 DISCONNECT)现由 `net_reconcile_tick` 判据⑤自动认领:本层 ESTABLISHED 且芯片 0x05/0x01 → 只修本层(state→LISTENING + 转登 `last_peer_port` + 清 `lost_conn_seen` + 取消挂起 recv),**不发芯片命令**(纪律原样保留,run8 实证 170s 拒绝);去抖/冷却沿用对账框架 |
|
||||
|
||||
@@ -164,7 +164,7 @@ flowchart TB
|
||||
|
||||
### 4.5 挂起 recv 子系统(阻塞等待不独占 netTask)
|
||||
|
||||
**模型**:阻塞等待 = **挂起请求登记**(每 fd 至多一个,禁止覆盖)+ **主循环节拍完成检查** + **通知唤醒**(LwIP netconn 模型)。消除 E-02 头阻塞(旧实现:netTask 自旋等数据,一次 30s 空闲 recv 冻住全网 17.7s)。
|
||||
**模型**:阻塞等待 = **挂起请求登记**(每 fd 至多一个,禁止覆盖)+ **主循环节拍完成检查** + **通知唤醒**(LwIP netconn 模型)。消除队头阻塞(旧实现:netTask 自旋等数据,一次 30s 空闲 recv 冻住全网 17.7s)。
|
||||
|
||||
| 函数 | 设计作用 | 主要调用 | 意图 / 注意 |
|
||||
|---|---|---|---|
|
||||
@@ -387,7 +387,7 @@ sequenceDiagram
|
||||
|---|---|---|
|
||||
| 1 | **一切芯片访问收敛 netTask**(唯一执行者);跨任务调用走队列 | TRAP-NET-14:跨任务 SPI 竞争破坏芯片寄存器 → 连接必超时 |
|
||||
| 2 | **结果只经任务通知值回传**;消息按值入队,调用方看不到 netTask 对消息的写入;勿给消息加"回传用"字段 | TRAP-NET-10:6 个 API 永远返回 -1;"加 msg.err 字段"的修法曾致 `ui_net_sink` 每次空轮询误判真错误 → 连上即断 |
|
||||
| 3 | **netTask 不为任何人自旋等待**:阻塞 recv = 挂起登记;重开失败 = 重试登记(D10);初次 listen/connect 的 open 重试环(`net_sock_reset_sync` 有界等待,GRACEFUL 100ms 底 / 600ms 封顶)是唯一豁免(启动期无竞争,原 3×500ms 盲等已换确定性排渣) | E-02:一次空闲 30s recv 冻住全网 17.7s;旧重监听 osDelay(500) → 恢复 588ms、期间重连被拒 |
|
||||
| 3 | **netTask 不为任何人自旋等待**:阻塞 recv = 挂起登记;重开失败 = 重试登记(D10);初次 listen/connect 的 open 重试环(`net_sock_reset_sync` 有界等待,GRACEFUL 100ms 底 / 600ms 封顶)是唯一豁免(启动期无竞争,原 3×500ms 盲等已换确定性排渣) | 队头阻塞整改:一次空闲 30s recv 冻住全网 17.7s;旧重监听 osDelay(500) → 恢复 588ms、期间重连被拒 |
|
||||
| 4 | **netTask 不向自身发消息 / 不自我挂起**(挂起登记对执行任务自身发起直接拒绝) | 自等自通知 = 死锁 |
|
||||
| 5 | **基于状态读的重建动作必须去抖 + 冷却**:分级门槛 ②=1 轮 / ③④⑤=2 轮 / ①=4 轮(100ms/轮)+ 冷却 1s | 2026-09-23:无去抖 → 监听反复重建直至 `relisten give up`,三服务口全死 |
|
||||
| 6 | **异常释放(TIMEOUT)后复监听前必须隔离**:排空 RX 残渣 + 等 CLOSED/TCP_CLOSED;隔离上限 < 重试放弃时限 | TRAP-NET-18:~2KB 残渣被下条连接当自己的数据 → 首笔上传截断 2048B 并误报 226 成功;上限=2s 时隔离耗尽重试预算 → 监听被弃 |
|
||||
@@ -406,7 +406,7 @@ sequenceDiagram
|
||||
| `ch395f_check_exist` / `ch395f_reset` | `net_init` | 上电探测与复位 |
|
||||
| `ch395f_set_fun_para(0x08)` | `net_init` | bit3 手动关缓冲(SOCKET_CLOSE);bit0/1=0,Socket 个数与 FUN_PARA 无关 |
|
||||
| `ch395f_set_tcp_mss` / `set_retrans_count` / `set_retrans_period` / `set_keepalive_idle+intvl+cnt` | `net_init`(**均须在 `ch395f_init` 之前**) | 值见 `net_config.h` |
|
||||
| `ch395f_set_mac_addr` | `net_init`(**须在 `ch395f_init` 之前**) | 写芯片 EEPROM;INIT_CH395 加载 MAC(`docs/芯片手册/CH395F.md` §9.2.1 步骤①,P1-7) |
|
||||
| `ch395f_set_mac_addr` | `net_init`(**须在 `ch395f_init` 之前**) | 写芯片 EEPROM;INIT_CH395 加载 MAC(`docs/芯片手册/CH395F.md` §9.2.1 步骤①) |
|
||||
| `ch395f_set_ip_addr` / `set_gwip_addr` / `set_mask_addr` / `set_dhcp` | `net_init`(**均须在 `ch395f_init` 之前**) | 固定 IP 或 DHCP |
|
||||
| `ch395f_init` / `ch395f_ping_enable` | `net_init` | 协议栈初始化(INIT_CH395)/ PING(须在 init 之后) |
|
||||
| `ch395f_set_send_buf` / `ch395f_set_recv_buf` | `net_init`(8 Socket 布局);`net_bind`(UDP)(Socket 4~7 兜底) | 每 Socket 收 4 块 + 发 2 块 |
|
||||
|
||||
@@ -52,7 +52,7 @@ netTask 是**全部 socket 操作的唯一执行者**——CH395F 的 SPI 总线
|
||||
| B 有界分片轮询(`net_recv_to` 分片) | ≤ `timeout_ms` | 分片间隙可用 | ⚠️ 止血:仍周期性占用,调用方须自管总预算 |
|
||||
| C **挂起登记(本模型)** | 微秒级(登记一次) | 照常服务整个队列 | ✅ 结构性消灭 |
|
||||
|
||||
三条路线的量化对照见历史审计 E-02(头阻塞;属主文档已于 2026-10-15 删除,编号仅作指称)。本模型选 C;路线 B 的入口
|
||||
三条路线的量化对照见历史审计的队头阻塞发现(属主文档已于 2026-10-15 删除)。本模型选 C;路线 B 的入口
|
||||
`net_recv_to` **仍在 API 面上**,定位是**调用方显式预算**(§6.2、§8),与挂起登记互补。
|
||||
|
||||
> **send 是同一问题的第二个面**:`net_send` 写入 CH395F 发送 FIFO 后要等 `send_ready`
|
||||
|
||||
+15
-15
@@ -12,12 +12,12 @@
|
||||
| 记号 | 是什么 | 在哪查 |
|
||||
|---|---|---|
|
||||
| `I1`~`I8` | 本架构的**不变量**(Invariant)——违反即有实测后果 | §2 |
|
||||
| `E0`~`E19`、`E-02` | **台架实验**编号(E = Experiment):每个实验是「假设 → 方法 → 判据 → 门禁哪个决策」 | §5.2(原始记录已归档,见 §12) |
|
||||
| `E0`~`E19` | **台架实验**编号(E = Experiment):每个实验是「假设 → 方法 → 判据 → 门禁哪个决策」 | §5.2(原始记录已归档,见 §12) |
|
||||
| `F-NET-nn` / `F-DRV-nn` / `F-MS-nn` | 审计的**编号发现**:NET 层 / 驱动层 / 状态镜像层 | §7(只保留仍被引用的 12 条) |
|
||||
| `M1`~`M5` | 实验固件里的**候选修改代号**:M1 沉降无条件化 · M2 门控换 `net_listener_armed` · M3 可疑门 · M4/M4-lite 删沉降段全局读即清 · M5 `sock_reset` quiescent 排空 | §4.1、§4.3 |
|
||||
| `形态①`~`形态⑤` | `net_reconcile_tick` 的五类**失同步判据** | §4.1 |
|
||||
| `U1`~`U15` | 状态迁移的**"无人负责"组合**(架构欠债清单) | `docs/问题记录/CH395F_Trap_Records.md` B10 行 |
|
||||
| `TRAP-NET-nn`、`B3`/`B10` | **陷阱记录**条目与 B 系列 | 同上 |
|
||||
| `U1`~`U15` | 状态迁移的**"无人负责"组合**(架构欠债清单) | `docs/问题记录/CH395F_Trap_Records.md` 审计遗留章节 |
|
||||
| `TRAP-NET-nn` | **陷阱记录**条目 | 同上 |
|
||||
| `N-nn` | `docs/任务规划/登记簿.md` 的**任务/发现编号**(⚠ 已销项的号不再可查,本文引用处即其最终事实描述) | 该登记簿 |
|
||||
| `D1`~`D7` | 本文**决策记录** | §10 |
|
||||
| `自愈收敛阶段 N` | 2026-10 的分阶段实施标签,**只存在于历史文档与变更记录**(代码注释已全部改为平实语言);勾选清单已归档(§12)——**勿用它叙述设计,也勿再写回注释** | §12 |
|
||||
@@ -29,11 +29,11 @@
|
||||
|
||||
> ⚠ **字母 `E` 有两套编号,靠连字符区分**:
|
||||
> - `E0`~`E19`(**无**连字符)= 本文的**自愈实验**编号,逐条见 §5.2;
|
||||
> - `E-02`(**带**连字符)= **历史审计发现**编号(属主文档已于 2026-10-15 删除,
|
||||
> - 带连字符的 `E-<nn>` = **历史审计发现**编号(属主文档已于 2026-10-15 删除,
|
||||
> 编号冻结于 `docs/编号规范.md` §4.3)——
|
||||
> §5.2 末行引用它是为了记录该发现的**收口台架**,**不是**实验编号
|
||||
> (证据:`test/host/e02_probe.py` 文档串自述"历史审计 E-02 的 timeSync 触发形态");
|
||||
> - 该审计编号族冻结于 `E-63`,不再新增。
|
||||
> (证据:`test/host/e02_probe.py` 的文档串自述它是该审计发现的 timeSync 触发形态探针);
|
||||
> - 该审计编号族已冻结、不再新增,引用一律改说人话。
|
||||
|
||||
## 1. 为什么是这个架构
|
||||
|
||||
@@ -422,7 +422,7 @@ CLOSED → 由形态④ 接手。关键在两条快路径的判据(`net_pendin
|
||||
必须 `net_select` 超时或 `net_recv_to` 显式预算。
|
||||
- 上层 32 轮盲收(`ui_net_sink` / `iec104_serv`)保留现状(E6 裁决,§4.8)。
|
||||
|
||||
### 4.6 `net_drop_conn`——应用主动拆会话保监听(E-02 收口;N-17 异步收口 2026-10-25)
|
||||
### 4.6 `net_drop_conn`——应用主动拆会话保监听(队头阻塞收口;异步收口 2026-10-25)
|
||||
|
||||
- 语义(**返回值 = 拆除与重建已登记**,不代表芯片已拆完):`net_pending_settle_close`
|
||||
先结束挂起 recv(回传结果 + 唤醒调用方)→ 监听型(`auto_relisten`)fd:
|
||||
@@ -431,7 +431,7 @@ CLOSED → 由形态④ 接手。关键在两条快路径的判据(`net_pendin
|
||||
按 30ms 节奏执行(与被动超时/断连释放同一台机器),失败交 D10 + 形态④;
|
||||
非监听 client fd 无监听可保,仍同步 `net_sock_reset_sync`(600ms 封顶)。
|
||||
端口恢复窗 ~0.4~1s,与被动断连恢复窗(E1 发现 A)同型。
|
||||
- **为什么监听型不得同步等待(N-17 定位,论证随结论一并留档)**:旧形态在
|
||||
- **为什么监听型不得同步等待(探针窗口心跳缺口定位时的论证,随结论一并留档)**:旧形态在
|
||||
`NET_MSG_DROP_CONN` 处理器内同步跑 `net_sock_reset_sync(QUARANTINE)`(2ms 节奏、
|
||||
400ms 底/600ms 顶,自家注释原记「等待期 netTask 有界占用 ~400-600ms」),netTask
|
||||
的 1ms 主循环冻结在同一迭代内:NET 位心跳停摆 + 串行总线整窗停摆(UI 推流/FTP/
|
||||
@@ -453,7 +453,7 @@ CLOSED → 由形态④ 接手。关键在两条快路径的判据(`net_pendin
|
||||
`time_sync.c`(不消费返回值,accept 轮询天然容忍 WOULDBLOCK 窗)。
|
||||
- **幂等**(非 ESTABLISHED/CONNECTING 直接返 0);**EOF 路径不得调**
|
||||
(`auto_relisten` 已接管,再调属重复拆)。
|
||||
- 芯片物理边界(E-02 台架,异步收口逐字不变——只移动「等待发生在哪」):
|
||||
- 芯片物理边界(台架定案,异步收口逐字不变——只移动「等待发生在哪」):
|
||||
`close` **无 RST 语义**——对端配合(收到 FIN 后其内核 close):`TIME_WAIT` ~150ms
|
||||
→ 形态④ relisten(恢复全程 ~500ms);对端内核存活但不 close:芯片停
|
||||
`FIN_WAIT_2` 长尾,**监听恢复受限于对端 close**,兜底 = 芯片 TIMEOUT/KeepAlive 拆
|
||||
@@ -614,8 +614,8 @@ DISCONNECT 会被 `(void)` 丢掉。但 RECV_OK 是条件位(下轮补回)
|
||||
> ⚠ **这些编号是冻结标识**:`net_socket.c` / `net_events.c` / `net_listener.c` 注释、
|
||||
> `test/host/e02_probe.py`、`test/host/e6_soak.py`、`docs/问题记录/CH395F_Trap_Records.md`
|
||||
> 都直接引用它们,**重排或改名会断链**。
|
||||
> ⚠ 末行 `E-02` **不是实验编号**——它是**历史审计发现**编号
|
||||
> (`E-<nn>` 族,属主文档已于 2026-10-15 删除,冻结于 `E-63`),列在此处只为记录该发现的**收口台架**。
|
||||
> ⚠ 末行 **不是实验编号**——它记录的是**历史审计发现**
|
||||
> (带连字符的 `E-<nn>` 族,属主文档已于 2026-10-15 删除并冻结),列在此处只为记录该发现的**收口台架**。
|
||||
> 区分规则:**带连字符 = 审计发现,无连字符 = 自愈实验**。
|
||||
|
||||
| 编号 | 验证了什么(方法) | 结论(现状口径) | 落点 |
|
||||
@@ -636,11 +636,11 @@ DISCONNECT 会被 `(void)` 丢掉。但 RECV_OK 是条件位(下轮补回)
|
||||
| **E13** | 产品固件 + PC 网卡抖动注入,追"残渣风暴态"根因 | 根因 = **僵尸会话**(对端静默死亡、芯片侧 ESTABLISHED 未清、单连接监听被占),而非跨烧录残渣;`RSTI←NRST` 推翻"跨烧录存活";自愈链端到端 30~90 s 有效 | §4.7;PASV 预清缺口由 `sock_reset` 收口 |
|
||||
| **E14** | 48 轮直读 SINT 矩阵复核"丢中断"说法(drain-int 现场抓取 + SINT 补读 ×3 + 超时归类) | **芯片侧事件丢失 = 0**;"丢失"实为 drain 读清消费 + 门控竞态 + 主机同步;幽灵态本轮 0/48 未复现 | §1 事实 2;生产 listen/relisten 排事件挪到 LISTEN 命令**之前**;TRAP-NET-17/-20 归因更正(机制保留不变) |
|
||||
| **E15** | 幽灵态归因复核(WCH 官网 + 手册出处) | `0x04` + 旧端口 = 芯片**如实报告**旧连接拆链进行中,不是谎报:bit3=1 是自家配置(手册 §5.52②);拆链走 RFC 9293 §3.3.2 状态机(FIN_WAIT_1→FIN_WAIT_2→TIME_WAIT,2MSL 驻留);WCH 官方博客确认"断连即重连被拒"、官方方案 = 关闭完成后重开 | TRAP-NET-20 口径"谎报"→"如实报告";settle 等待 = 官方方案;幽灵甄别 = 护栏;I3 加强 |
|
||||
| **E16** | 把 relisten 隔离段收口到驱动 `sock_reset` 原语(删 net 层自建序列与参数副本),同板 A/B 跑 `ftp_abort_probe` + `relisten_stress` + `n30_repro` | **收口失败、已回退**:失效面精确落在"中止后首笔复连";根因两条——残渣在 CLOSE **之后**才落进 RX(一次排空接不住);复位机"逼回 CLOSED"的目标与上层立即复用同一 Socket 冲突 | §8 延后项 1(三条前置语义);§4.4 警告;登记 **N-30** |
|
||||
| **E16** | 把 relisten 隔离段收口到驱动 `sock_reset` 原语(删 net 层自建序列与参数副本),同板 A/B 跑 `ftp_abort_probe` + `relisten_stress` + `n30_repro` | **收口失败、已回退**:失效面精确落在"中止后首笔复连";根因两条——残渣在 CLOSE **之后**才落进 RX(一次排空接不住);复位机"逼回 CLOSED"的目标与上层立即复用同一 Socket 冲突 | §8 延后项 1(三条前置语义);§4.4 警告;登记「relisten 沉降段原语化受阻」 |
|
||||
| **E17** | **单一所有者收口**:`net_listener_try`(当场动作、**无状态门**,各调用点自带门)改为 `net_listener_request`(只登记意图)+ `net_listener_tick`(唯一执行者,门集含"芯片已在 LISTEN 即了结"),同板全量回归 | 全绿;**延后一轮(≤1 ms)执行不伤即时性**(恢复窗 p50 与当场动作持平);relisten 留痕减半 | §4.2 登记/执行分离;§9.2 门集;§11.1 判据 |
|
||||
| **E18** | **负向注入打靶 · 三轮**(注入代码不入库):① 吞掉 DISCONNECT(在 i104 的 200 ms accept 轮询窗内 RST);③ 绕过本层簿记直接 close 芯片空闲监听;⑤ 开盲区吞掉芯片自发的中断 + 等芯片真 CLOSED 再 open+listen | **①③⑤ 全部命中并救回**;①⑤ 的前提会被更快的消费者路径消解 → 常态 0 命中;⑤ 还要先越过芯片 `FIN_WAIT_2`(E15 的 2MSL 长尾,实测 ≈1 s) | §4.1.4 / §4.1.5:**三条均不可降级为只留痕**;⑤ 的**取消挂起 recv/send** 不可省 |
|
||||
| **E19** | **`force open` 反事实 A/B**(本层已收口 CLOSED + 芯片停 `FIN_WAIT_2` `0x05/0x06` + **对端挂住不关** = E-02 场景;A = 现状放行,B = 只留痕不放行) | **放行与不放行的端口恢复时刻同一分布** → 动作在全部可产现场景内无可测收益;真正兜住"监听器永久失效"的是 **D10 预算 + 形态④ 重新登记**。两条实测坑:① 本层直接改 `state` **不会**进沉降窗(窗只由 `net_listener_settle` 开启);② `relisten retry budget exhausted` 在此被稳定复现 = 对端不配合拆链的签名,**非回归** | §4.3:800 ms 上限降级为**只留痕**(`keep waiting` 只留首末、隔离标志不清 → 继续排渣) |
|
||||
| **E-02**(审计编号) | `test/host/e02_probe.py` 台架定案 `net_drop_conn` 收口后的时序 | 对端配合(收到 FIN 后其内核 close):`TIME_WAIT` ~150 ms → 形态④ relisten,恢复全程 ~500 ms;对端内核存活但不 close:芯片停 `FIN_WAIT_2` 长尾,**监听恢复受限于对端 close** | §4.6 |
|
||||
| **E19** | **`force open` 反事实 A/B**(本层已收口 CLOSED + 芯片停 `FIN_WAIT_2` `0x05/0x06` + **对端挂住不关** = 队头阻塞场景;A = 现状放行,B = 只留痕不放行) | **放行与不放行的端口恢复时刻同一分布** → 动作在全部可产现场景内无可测收益;真正兜住"监听器永久失效"的是 **D10 预算 + 形态④ 重新登记**。两条实测坑:① 本层直接改 `state` **不会**进沉降窗(窗只由 `net_listener_settle` 开启);② `relisten retry budget exhausted` 在此被稳定复现 = 对端不配合拆链的签名,**非回归** | §4.3:800 ms 上限降级为**只留痕**(`keep waiting` 只留首末、隔离标志不清 → 继续排渣) |
|
||||
| **队头阻塞审计**(非实验编号) | `test/host/e02_probe.py` 台架定案 `net_drop_conn` 收口后的时序 | 对端配合(收到 FIN 后其内核 close):`TIME_WAIT` ~150 ms → 形态④ relisten,恢复全程 ~500 ms;对端内核存活但不 close:芯片停 `FIN_WAIT_2` 长尾,**监听恢复受限于对端 close** | §4.6 |
|
||||
|
||||
## 6. 红线(明确不做的事)
|
||||
|
||||
@@ -690,7 +690,7 @@ DISCONNECT 会被 `(void)` 丢掉。但 RECV_OK 是条件位(下轮补回)
|
||||
③ **槽位可加入**:每 Socket 只有一个复位槽位,`ch395f_sock_reset_begin` 返 -1(已在运行)
|
||||
不等于失败——同步包装必须**加入**已在跑的复位机,否则 `net_close` 走 "proceed
|
||||
anyway"、排渣被跳过。
|
||||
补齐 ①②③ 并各自回归后再接;登记 **N-30**(`docs/任务规划/登记簿.md`)。
|
||||
补齐 ①②③ 并各自回归后再接;登记 `docs/任务规划/登记簿.md` 条目「relisten 沉降段原语化受阻」。
|
||||
2. **部分读→再查 recv_len 定向 TC**:旧"部分读归零"机理未证实(与手册 §5.34 及
|
||||
TC-NET-201 相反),注释约束已降级为历史观察——以定向用例结案(陷阱记录「台架纪律」
|
||||
节已挂该待办)。
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
`language: system`、`pass_filenames: false`)。
|
||||
- 规则脚本:`scripts/check_bsp_err.py`(纯标准库;文件头就是规则正文)。
|
||||
- 约定正文:`Drivers/BSP/bsp_err.h`(**header-only,无 `.c`** → 不占体积、不需双端注册)。
|
||||
- 背景与整改史:S-5 条目的完整记录已随审查报告删除,现存依据 = 登记簿 **S-5** 行与 `Drivers/BSP/bsp_err.h`。
|
||||
- 背景与整改史:原审查报告里该条契约的完整记录已随报告删除,现存依据 = `Drivers/BSP/bsp_err.h` 与 `scripts/check_bsp_err.py` 的存量基线。
|
||||
|
||||
## 1. 它在查什么
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ CubeMX 重生成存活审计.......Failed
|
||||
**`--write` 必须与"确认过的改动"写在同一个提交里并说明。**
|
||||
6. 它不判断定制**是否仍然正确**,只判断"还在不在原来的位置"。
|
||||
7. **基线漏项 = 静默不检**(2026-10-25 实证):`--check` 只比对基线里已登记的条目——一条定制
|
||||
若从未进过基线,检查面再全也不会报它。`docs/任务规划/测试与架构专项.md` P1-10 返工时
|
||||
若从未进过基线,检查面再全也不会报它。`docs/任务规划/测试与架构专项.md` 那次返工时
|
||||
`--write` 顺带补出了原本缺失的
|
||||
`net-msgq-adopt`(`Src/freertos.c` RTOS_QUEUES 区须含 `net_msg_queue_adopt`),该条目此前
|
||||
处于"不存在于基线 → 永不检查"态。**新增标记区外定制时,登记必须与代码同提交**(同 §5 的
|
||||
|
||||
@@ -34,12 +34,12 @@
|
||||
|
||||
| 套件(登记出处) | 规模 | 为什么非要有 |
|
||||
|---|---|---|
|
||||
| `sha256`(N-19) | 13 例 | FIPS 180-4 标准向量(空串 / `abc` / 56 B 补位跨界 / 1 MB)+ `hex_eq` 非法输入。哈希算错是"正确口令被拒 / 错误口令放行"的静默语义错误,板端只见 `530`/`230` 看不出根因 |
|
||||
| `ftp-auth`(N-19) | 36 例 | 连续 5 败锁定 / 60 s 解锁 / 成功清零 / tick 32 位回绕。板端每验一条要真等 60 s、回绕要跑满 49.7 天;纯函数(tick 由参数注入)就是为了让这些分支能毫秒级穷举 |
|
||||
| `sha256`(FTP 鉴权) | 13 例 | FIPS 180-4 标准向量(空串 / `abc` / 56 B 补位跨界 / 1 MB)+ `hex_eq` 非法输入。哈希算错是"正确口令被拒 / 错误口令放行"的静默语义错误,板端只见 `530`/`230` 看不出根因 |
|
||||
| `ftp-auth`(FTP 鉴权) | 36 例 | 连续 5 败锁定 / 60 s 解锁 / 成功清零 / tick 32 位回绕。板端每验一条要真等 60 s、回绕要跑满 49.7 天;纯函数(tick 由参数注入)就是为了让这些分支能毫秒级穷举 |
|
||||
| `iec104`(B4) | 82 例 | CP56 往返 / APCI 半帧粘帧坏帧 / STARTDT-STOPDT / 总召分片 / COV 死区 / k=12 窗满 / w=8 触发 S / 三个超时定时器 / N(R) 倒退。板端复现要真主站 + 真等待(t1=15 s、窗满要发满 12 帧) |
|
||||
| `freq`(B8) | 46 断言 | 扫频 45~55 Hz 误差 ≤0.02 Hz(实测 0.0101)/ 1% 噪声 ≤0.10 Hz / 启动收敛 ≤40 ms / 阶跃 ≤120 ms。板端无标准源照不出来;定长窗的负序泄漏纹波(0.317 Hz)只有合成扫频能暴露 |
|
||||
| `soe`(B9) | 32 断言 | 64 B 定长记录编解码往返 / 截断与坏校验和拒绝 / IV 位 / seq 连续性 / 类型枚举。记录格式是**磁盘上的字节级契约**,错了要 FTP 下载再解码才看得见 |
|
||||
| `nand-port`(N-21) | 149 断言 | 整页扫描的空闲判定(页首 64 B 全 0xFF 而第 1000 字节有数据等形态)+ **与旧算法对照**(旧实现只看页首,同一页答"空闲")。这类缺陷真机极难复现,发作后只表现为"某次复位后丢数据" |
|
||||
| `nand-port`(dhara 移植层两条硬约束) | 149 断言 | 整页扫描的空闲判定(页首 64 B 全 0xFF 而第 1000 字节有数据等形态)+ **与旧算法对照**(旧实现只看页首,同一页答"空闲")。这类缺陷真机极难复现,发作后只表现为"某次复位后丢数据" |
|
||||
|
||||
- 运行器统一用 MSVC `cl.exe`(远端 CI 的 L0.5 层);公共骨架是
|
||||
`test/host/common/unit_test_harness.py` —— **改动这个骨架会同时触发 16 个钩子**
|
||||
@@ -50,7 +50,7 @@
|
||||
- 状态机、编解码、换算这类逻辑,在真机上验证成本极高(要么构造故障、要么等复现);
|
||||
在 PC 上毫秒级就能重跑,是"改完敢不敢提交"的第一层信心。
|
||||
- 它们**已经在真实收口上起过作用**:`nand-port-unit-test` 与 `sys-clock-unit-test` 的桩里就
|
||||
注入过 RTC 读失败等错误路径,用来证明失败分支的行为(本次 S-5 收编时同步改过这两个 runner
|
||||
注入过 RTC 读失败等错误路径,用来证明失败分支的行为(本次 BSP 错误码契约收编时同步改过这两个 runner
|
||||
的 include 目录,见 §6 第 4 条)。
|
||||
|
||||
## 3. 触发面
|
||||
|
||||
+61
-12
@@ -2,7 +2,7 @@
|
||||
|
||||
> 一句话:它管**"号"这个东西不许野生**——每个编号必须属于一个已登记的族、形态合法、
|
||||
> 有定义处、有人引用、引用它的时候说清是哪篇文档的号。
|
||||
> 规范正文 = `docs/编号规范.md`(§4 前缀总表、§8 门禁),本门禁是那八项的机械执行。
|
||||
> 规范正文 = `docs/编号规范.md`(§1 先问三句、§4.1 允许用号的族〔穷举〕、§8 门禁与实测基线),本门禁是那八项的机械执行。
|
||||
|
||||
- 配置:`entry: python scripts/check_ids.py --strict`,`pass_filenames: false`,
|
||||
`files:` 覆盖 `.md/.c/.h/.py/.yaml/.json/.txt` 与配置文件本身。
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
## 2. 为什么要它
|
||||
|
||||
- 本仓同时存在 `N-xx`/`N-x`/`TC-*`/`E-xx`/`TRAP-*`/`D10`/`U12` 等几十族编号,历史上出过
|
||||
- 本仓曾同时存在几十族编号(`N-xx`/`TC-*`/`E-xx`/`TRAP-*`/`D10`/`U12`…),历史上出过
|
||||
**真事故**:登记簿销项删行后号被复用(撞号)、引用指向已被删的号(悬空)、同一字面量两个
|
||||
属主(重复定义)。规范 §1 把成因写得很直白:连字符与补零偷偷承载语义。
|
||||
- **本次实测拦下过我自己两次**:一次是"字母加数字"自造号(校验 1),一次是引用某个跨文档
|
||||
@@ -36,18 +36,18 @@
|
||||
- **`owner_docs` ≠ 定义集**(2026-10-25 起):族可以"有登记处"却"没有定义位"。判可判定只看
|
||||
`owner_docs` 是否解析出真实文件;而悬空(校验 3)/ 撞号(校验 4)/ 裸形(校验 2)/ 紧邻(校验 6)
|
||||
一律只看 `_def_owners`。两者仅在一种情形下不同:**`snapshot_only` 族的登记处挂在规范正文**
|
||||
(`docs/编号规范.md` §4.5 那种冻结存档表)。规范里混着大量写法示例(`N-99`、`S1`、`N-31`),
|
||||
(`docs/编号规范.md` §4.3 说的冻结前缀:登记处只剩冻结存档,甚至只存在于规范正文)。规范正文里混着大量写法示例,
|
||||
若拿它当定义集会立刻误伤——实测裸形 `S1` 被判成 `S-1` 漏连字符 238 条、表里 `S-3` 与登记簿 S-3
|
||||
被判重复定义。所以这类族的 `_def_owners` 为空,等价于"属主已删、只有存档"。
|
||||
代价要认清:这类族的号**不会再被校验 3 兜住**,新增引用只能靠别名表或人工核。
|
||||
|
||||
## 3. 触发面
|
||||
|
||||
- 扫描面以 git 清单为准。当前一次实跑:**696 个文件、编号字面量 10410 处**。
|
||||
- 扫描面以 git 清单为准。最近一次实跑(2026-10-26 编号迁移批次后):**754 个文件、编号字面量 8,230 处**(方案 A 之前 10,956 → 方案 A 之后 8,946 → 方案 B 之后 8,503 → 编号迁移批次后 8,230)。
|
||||
- **排除**:`Lib/`、`Middlewares/`、HAL/CMSIS、`docs/芯片手册/`、`docs/硬件平台/`。
|
||||
最后一个是关键:硬件文档里的**元器件位号 `U1`/`C12`/`R3`/`L5`/`D7`** 与我们的编号字面
|
||||
同形,不整体排除就会大量误报(脚本里另有一套位号识别,但仍**没有解除这两个目录的语料排除**)。
|
||||
- 已声明的"同号不同义"族对(`docs/编号规范.md` §4.3):实跑 583 个字面量走 `collides_with`
|
||||
- 已声明的"同号不同义"族对(`docs/编号规范.md` §4.3):实跑 876 个字面量走 `collides_with`
|
||||
白名单,**不计入校验 4**。
|
||||
|
||||
## 4. 报错怎么读
|
||||
@@ -61,12 +61,12 @@
|
||||
- 单独跑:`& '.venv\Scripts\python.exe' scripts/check_ids.py --strict --verbose`(`--verbose` 带修法,`--top 30` 多打,`--only 1,3,5` 只跑指定校验)。
|
||||
- 常用旗标:`--strict`(钩子用的档位)、`--verbose`、`--write-backlog` / `--prune-backlog`
|
||||
(重建 / 收紧台账)、`--update-baseline`(把当前可判定比例写回 `id_registry.json`,只许涨)、`--no-trace`。
|
||||
- 存量在 `scripts/id_known_backlog.json`(按指纹豁免,实跑 **640 处**在册)。
|
||||
- 存量在 `scripts/id_known_backlog.json`(按指纹豁免,实跑 **0 处 / 0 类指纹**在册;HEAD 台账 303 条指纹 / 651 处)。
|
||||
|
||||
## 5. 好处
|
||||
|
||||
- **拦下过真事(2026-10-25 追加)**:`docs/任务规划/测试与架构专项.md` P1-10 的返工提交被
|
||||
**校验 6** 拦下 4 处——C 注释里裸写编号、未紧邻属主文档名;改成「条目属主 `docs/任务规划/测试与架构专项.md` P1-10」即过。
|
||||
- **拦下过真事(2026-10-25 追加)**:`docs/任务规划/测试与架构专项.md` 一条返工提交被 **校验 6**
|
||||
拦下 4 处——C 注释里裸写该文档的条目编号、未紧邻属主文档名;补齐文档名即过。
|
||||
实证**紧邻写法在代码注释里同样是硬约束**,不是只约束 Markdown。
|
||||
|
||||
- 把"编号卫生"从人脑记忆变成机器判定:销项只做一半、引用写错文档、自造号,都会在提交时被点名。
|
||||
@@ -74,13 +74,13 @@
|
||||
|
||||
## 6. 限制与盲区(这一节请当正文读)
|
||||
|
||||
1. **绿灯不等于编号都合法**:门禁是【增量拦截】——存量 640 处按台账豁免。它保证的是
|
||||
1. **绿灯不等于编号都合法**:门禁是【增量拦截】——存量 0 处按台账豁免。它保证的是
|
||||
"没变差",不是"干净"。
|
||||
2. **`collides_with` 白名单挡事故、不挡可读性**。已声明同号不同义的族对不再报——于是
|
||||
"新造一个和已有裸形撞车的代号"可以一路绿灯。**这正是本门禁今天照不出来的东西**:
|
||||
我自己造的四个字母数字代号在被改名前,没有任何一条校验会响(同形多义已被声明为已知事实)。
|
||||
结论:**编号可读性要人管**,`docs/门禁说明/bsp-err.md` §6 那条就是这个教训的落点。
|
||||
3. 实跑有 **867 处"裸形盲区"**:形态太像普通词/数字组合的字面量识别不出来,等于不在管辖内。
|
||||
3. 实跑有 **827 处"裸形盲区"**:形态太像普通词/数字组合的字面量识别不出来,等于不在管辖内。
|
||||
4. 校验 7(孤儿)只告警不拦提交:定义完一直没人引用的号会长期存在而门禁不响。
|
||||
5. "定义"的判据是"出现在属主登记处文档里",**不校验语义**:写进错的属主文档、或写成一句
|
||||
否定("该号从未存在")也算定义——批量改名工具最阴的失效模式就是"字面改对、意思改错"。
|
||||
@@ -88,7 +88,9 @@
|
||||
`scripts/rename_maps/` 里必然写着旧的非法形态),否则第一次提交就被自家审计表当"新账"拦下。
|
||||
7. 校验 8 只许涨不许跌:好处是防退化,代价是**顺手写一个未登记族的号就会红**,哪怕与本次改动无关。
|
||||
8. 它不懂"这个号该不该存在"。新增一族编号是否合理,仍是 `docs/编号规范.md` 的人工判断。
|
||||
9. **二进制工件整体跳过**(2026-10-25 task-22 补):gz 串口存档 / png 等字节流没有编号语义,
|
||||
9. **变更记录行豁免**(2026-10-26 加):首格是日期的表格行不参与判定——政策禁止回改历史,
|
||||
拦它等于逼人改历史或 `--no-verify`。代价:新写进变更记录行的旧形态编号照不出来。
|
||||
10. **二进制工件整体跳过**(2026-10-25 task-22 补):gz 串口存档 / png 等字节流没有编号语义,
|
||||
按文本 `errors=replace` 解码后随机字节会拼出「字母-数字」形态的**伪编号**,把无关存量顶成
|
||||
校验 1 的"台账外新账"(`boot_log_data` 落 f3rounds gz 时实测拦下提交——本节文字引用这类
|
||||
噪声形态时同样会被扫,措辞必须只描述形态不举例)。判据 = gzip 魔数或头 2KB 含 NUL → 计入
|
||||
@@ -109,7 +111,52 @@
|
||||
- 存量:`scripts/id_known_backlog.json`(指纹级);**只减不增**,收紧用 `--prune-backlog`。
|
||||
- 别名:`scripts/id_aliases.json`(旧字面量 → 现行字面量)——号改名走 `scripts/rename_ids.py`,
|
||||
它会显式写别名条目,**绝不全局查找替换**。
|
||||
- 比例基线:`id_registry.json` 的 `decidable_ratio_baseline`(实跑当前 84.02%,基线 84.0%、容差 0.1pp)。
|
||||
- 比例基线:`id_registry.json` 的 `decidable_ratio_baseline`(实跑当前 86.01%,基线 86.0%、容差 0.1pp)。
|
||||
|
||||
## 7.5 2026-10-26 清号批次对门禁的影响
|
||||
|
||||
- **删的是引用,不是登记**:`E-xx`、`P0-x`~`P3-x`、报告六族(`D/R/F/N/U`)、复审残号(S 族 1~14 / A 族 / B 族)、
|
||||
会话临时号、`TM-*` / `DP-*`、模拟器差距 `H-x`/`L-x` 等族**仍留在 `id_registry.json`**(`frozen` / `snapshot_only`),
|
||||
为的是历史行与 `[示例]` 不报错;但**活文档与代码注释里已不再引用它们**,新增引用会被校验 3 / 5 当场拦下。
|
||||
- **可判定比例为什么上涨**:这些族的属主登记处已删 → 字面量原本**进分母、不进分子**。删掉这类"判不了"
|
||||
的引用,分母缩小,比例自然上升。⚠ **这不等于"编号卫生变好了"**——真证据是**编号字面量绝对数下降**
|
||||
(清理前 10,956 → 现在 8,230)**且**校验 2/3/6 的存量同时下降。只报比例不报绝对数,就是自欺。
|
||||
- **族不是越多越好**:`docs/编号规范.md` §4.1 现在只列「有属主登记处、且全仓真有引用」的族;原 `docs/编号规范.md` §4.2 那 15 个
|
||||
「改名后才启用」的目标前缀已作废——**空族会骗人**:读者看到 `DR-001` 就会去找一张根本不存在的登记表。
|
||||
- 要加一族:先改 `docs/编号规范.md` §4.1,再改 `id_registry.json`,两处同一批提交(`docs/编号规范.md` §5.1 第 1 步)。
|
||||
- **本批顺带补了「变更记录行」豁免**(`CHANGELOG_ROW`:表格首格是日期、或「(规划稿)」):
|
||||
`rename_ids.py` / `doc-links` / 追溯器早就是这条口径,唯独本门禁缺——于是把 `docs/编号规范.md` §5.5「历史不回改」
|
||||
锁死的行当活账拦提交,实测 **36 处错误级 + 20 处告警全来自历史行**。豁免后这些行的编号
|
||||
**不再被判定**(新增时也判不到,这是这条豁免的代价,写进 §6 盲区);被跳过的字面量数打印在
|
||||
扫描首行(`变更记录行 N 处`),不让它变成看不见的面分母缩水。
|
||||
|
||||
## 7.6 方案 B(同日):登记簿系编号退休为语义短语,与新增的第二根护栏
|
||||
|
||||
用户裁定「B 方案」:把**规划 / 待办类**在册编号也停发——登记簿 `N-x`/`S-x`/`T-x`、专项 `A-x`、已删报告的 UI 簇 `U1~U5`,
|
||||
共 20 个号;引用侧同批改写约 418 处、**字面量净减 443**(8,946 → 8,503)——构成:在册活号 237 处 + 指向已销项号的死引用 196 处(FTP 鉴权 / 监听生命周期模块化 / 探针窗口心跳缺口 / 日志读写放大那批已销项号)+ UI 簇非位号约 45 处。
|
||||
对门禁的三件事:
|
||||
|
||||
1. **族保留登记、只停发**(游标冻结不前进)。不为"看着干净"而删族:删族后历史行与别名表里的旧号会立刻
|
||||
报「未登记前缀」,等于把清理变成制造新账(与 `docs/编号规范.md` §8.3 记的「快照族先补定义位」同一方向的教训)。
|
||||
2. **旧号进 `id_aliases.json` 标 `status: retired-to-phrase`**(不是 `void`)——区别在于条目还活着,
|
||||
只是不再用号指它。门禁两者都只当"可解析",**都不许再被活文档引用**。
|
||||
⚠ 反过来,那批**故意不进别名表的死号**(FTP 鉴权那个旧号):进了就等于把残留引用永久洗白;
|
||||
让校验 3 继续报它们,才是"引用清干净了"的机器证据。本批实测:转换掉定义位后,
|
||||
那 12 处 `Drivers/BSP/**` 残留立刻从"静默"变成 12 条错误——这正是想要的效果。
|
||||
3. **新增第二根护栏:不可判定引用绝对数上限**(`id_registry.json` → `undecidable_total_ceiling`,只减不增,
|
||||
`--update-baseline` 同时下调用它,且拒绝上调)。为什么必须加:
|
||||
|
||||
> 清号批次把「本可判定的引用」换成散文,**分子分母同时缩小**——比例这类比值指标反而下跌。
|
||||
> 实测本批 86.4% vs 批次前 86.7%,而**不可判定引用绝对数一处没涨**(清号前 1,192 → 清号后仍 ≤ 该值)。
|
||||
> 也就是说比例的下跌 100% 是**稀释**,不是卫生退化;只拿比值当护栏,等于惩罚清号本身。
|
||||
|
||||
所以同批把 `decidable_ratio_baseline` **下调**到本批实测值(工具按设计拒绝下调,需人工改 registry——
|
||||
这是有意的摩擦:下调基线必须留下书面理由,理由就写在本节)。此后判断"编号有没有变坏"看两条:
|
||||
**不可判定绝对数**(会不会新增没登记的号)+ **字面量总数**(号有没有变多),比值只作趋势参考。
|
||||
|
||||
顺带修的口径:`CHANGELOG_ROW` 原先只认「首格是日期」的变更记录行,**首格是版本号、次格是日期**
|
||||
(`| v1.6 | 2026-10-25 | …`)那类表漏豁免——同一份冻结历史被两种表头拆成两种待遇,属工具缺陷,
|
||||
现已补齐(要求版本号与日期两格连排,单独的版本号不算,避免普通表格被误免)。
|
||||
|
||||
## 8. 改这个门禁本身
|
||||
|
||||
@@ -122,6 +169,8 @@
|
||||
|
||||
| 日期 | 变更 |
|
||||
|---|---|
|
||||
| 2026-10-26 | **方案 B(同日续批)**:登记簿系 `N-x`/`S-x`/`T-x`/`A-x` 与 UI 簇 `U1~U5` 共 20 个号停发、约 418 处引用转语义短语(字面量净减 443:8,946 → 8,503);新增第二根护栏「不可判定引用绝对数上限」(`undecidable_total_ceiling`,只减不增),并把比例基线下调——理由与实测(比例跌、绝对数不涨)见 §7.6;`CHANGELOG_ROW` 补「版本号 + 日期」表头的变更记录行 |
|
||||
| 2026-10-26 | **清号批次**(用户裁定:字母+数字编号太多、没人认得):全仓删除「属主已死 / 从未启用」的编号约 1,100 处,规范 §4.1 收成全活族 + §4.1.1 列已清除族,§4.2/§4.5/§7.1/§9 作废压缩。门禁口径不变(族仍登记,只拦新增引用);扫描面 / 字面量总数 / 台账 / 比例基线按本批实跑重打(见 §3、§7)。新增 §7.5 讲清"比例上升 ≠ 卫生变好"的读法 |
|
||||
| 2026-10-25 | 二进制工件跳过(§6 第 9 条):`iter_files` 按 gzip 魔数/头 2KB NUL 嗅探排除 gz/png 等,防乱码伪编号顶出校验 1 假新账(f3rounds gz 入库实测触发);602 处存量台账口径不变 |
|
||||
| 2026-10-25 | 补「`owner_docs` ≠ 定义集」口径(§2 末条):`snapshot_only` 族的登记处挂在规范正文时,`_def_owners` 为空 → 只恢复可判定、不参与悬空/撞号/裸形/紧邻。基线 82.6% → **84.0%**(删《项目审查与优化建议报告》+ 补登 11 条已死号别名后重打,实测 84.02%、696 文件 / 10410 字面量) |
|
||||
| 2026-10-23 | 首篇逐项文档(数据为当日实跑:551 文件 / 8868 字面量 / 台账 640 处 / 可判定 82.85%) |
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
- 配置:`entry: python scripts/check_layer_deps.py`、`pass_filenames: false`、
|
||||
`files: ^Drivers/BSP/|^scripts/check_layer_deps\.py$|^\.pre-commit-config\.yaml$`。
|
||||
- 规范出处:`docs/架构设计/项目架构总览.md`(六层单向:业务 → UI/基础服务 → 中间件 →
|
||||
BSP 驱动 → HAL/RTOS → 硬件)、`AGENTS.md` 分层边界;整改背景见报告 §0.4 的 S-1 行。
|
||||
BSP 驱动 → HAL/RTOS → 硬件)、`AGENTS.md` 分层边界。
|
||||
|
||||
## 1. 它在查什么
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
- 配置:`entry: python scripts/ram_baseline.py --gate`、`pass_filenames: false`、
|
||||
`files:` 覆盖 `App/`、`Drivers/BSP/`、`Src/`、`Inc/`、`Lib/lv_conf.h` 等会影响占用面。
|
||||
- 背景:登记簿 N-27 前半;三件套里的机械部分(阈值门禁 + 趋势台账 + 台账受管区)。
|
||||
- 背景:登记簿条目「缩堆迁 CCM 后半(暂缓)」的前半;三件套里的机械部分(阈值门禁 + 趋势台账 + 台账受管区)。
|
||||
|
||||
## 1. 它在查什么
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
> ——这一门专抓"写了却从不生效"的死代码,包括第四种更隐蔽的:页面描述符没接线。
|
||||
|
||||
- 配置:`entry: python scripts/check_registration.py --strict`、`pass_filenames: false`。
|
||||
- 背景:登记簿 N-23(出处审查报告 N-06 残余);UI 页面那类是 U4 门禁补强(2026-10-15)。
|
||||
- 背景:登记簿条目「rs485_task 白名单缺口」;UI 页面那类是「UI 字符集与像素回归门禁」补强(2026-10-15)。
|
||||
|
||||
## 1. 它在查什么(四类缺口)
|
||||
|
||||
|
||||
@@ -154,7 +154,7 @@ CH395F 以太网驱动与 NET 层的实证陷阱:现象、定案根因、修
|
||||
2. **C 模式真因**:`FUN_PARA` bit3 `SOCKET_CLOSE=1`(§5.52 ②)下产生 DISCONNECT 后**芯片不关 Socket、不清缓冲**,长期停在 `05H/00H`;此时直接 `open_socket` 必返 `0x20` FAIL——**把 Socket 拉回 CLOSED 的动作是 `close`**;
|
||||
3. **做法**:直接 `ch395f_close_socket()`;`disconnect` 纯属多余且会**制造** DISCONNECT 事件(bit3=1 下必须被消费/预清,否则污染下一条连接,TRAP-NET-12/23 实证);
|
||||
4. **观测口径**:§5.22 第 1 字节只有 `00H/05H`,第 2 字节(TCP 态)**仅在 byte0=OPEN 时有意义**——关闭后轮询**第 1 字节**等 `00H` 再 open,别拿 byte1 当"卡住"判据。
|
||||
- **边界(E-02 台架)**:`close` 无 RST 的适用条件——对端配合(收到 FIN 后其内核 close):芯片走 `TIME_WAIT` ~150ms → relisten → 新连接接入;**对端内核存活但不 close**:芯片停在 **`FIN_WAIT_2`(byte0=05H/byte1=06H)长尾**——没有 RST 就拆不掉,**监听恢复受限于对端 close**。不配合场景的兜底 = 芯片自身 TIMEOUT/KeepAlive 拆僵尸会话(判死窗 30~90s,`docs/网络/网络自愈架构设计.md` §5.2 E13)——**不是**应用可加速的路径。
|
||||
- **边界(台架定案)**:`close` 无 RST 的适用条件——对端配合(收到 FIN 后其内核 close):芯片走 `TIME_WAIT` ~150ms → relisten → 新连接接入;**对端内核存活但不 close**:芯片停在 **`FIN_WAIT_2`(byte0=05H/byte1=06H)长尾**——没有 RST 就拆不掉,**监听恢复受限于对端 close**。不配合场景的兜底 = 芯片自身 TIMEOUT/KeepAlive 拆僵尸会话(判死窗 30~90s,`docs/网络/网络自愈架构设计.md` §5.2 E13)——**不是**应用可加速的路径。
|
||||
- **应用侧出口 = `net_drop_conn(fd)`**:netTask 侧走驱动 `sock_reset` QUARANTINE(FIN+排渣+排空事件+等 byte0=00H,400ms 底)+ 本层收口 CLOSED + `auto_relisten` 登记重监听(≤1ms 后 `net_listener_tick` 执行);**保监听不毁**(单连接模型不得 `net_close` 监听 fd)。对端不 close 时复位机等在 `net_poll` 步进里(`ch395f_sock_reset_poll`),对端 FIN 到达即自动走完——**不搁浅**。
|
||||
|
||||
## TRAP-NET-09 · 沉降窗:PHY link up 后 / close 后不能立即 open
|
||||
@@ -189,7 +189,7 @@ CH395F 以太网驱动与 NET 层的实证陷阱:现象、定案根因、修
|
||||
1. **异常释放(TIMEOUT/RST)隔离**:`handle_timeout_event` 置 per-fd 隔离标记;`net_relisten_locked` 隔离期内持续排空芯片 RX(`net_drain_chip_rx()`)+ 主动 close + 排空该 socket 中断 + 等 `CLOSED/TCP_CLOSED`,满 `NET_RELISTEN_QUARANTINE_MS`(400ms) 才 open+listen;上限 `NET_RELISTEN_SETTLE_MS`(800ms) 强制放行——**必须小于** `NET_RELISTEN_DEADLINE_MS`(2000ms):取 2000ms 会耗尽重试预算 → give up → **监听器死亡**;
|
||||
2. **正常释放(FIN)沉降**:`handle_disconnect_event` 登记(仅 `recv_bytes != 0` 时——纯连接即关与只发不收免沉降保复连时序),relisten 前最短等 `NET_RELISTEN_GRACEFUL_MS`(**100ms**,实测悬崖:0/30ms 无效、100ms 稳定通过);日志区分 `relisten settle`/`relisten quarantine`;
|
||||
3. **应用侧硬化**:`net_sock_t.released_abnormal` 标记(TIMEOUT 置 1/DISCONNECT 置 0,新 fd 与新监听清零——新连接不得继承上一条的释放原因);`net_pending_tick` 断连结束时按标记以 `NET_ERR_CONNRESET` 或 EOF(0) 回传;`lftpd receive_file` 错误路径 **unlink 截断文件** + STOR 回 **450**。
|
||||
- **收口尝试与边界(2026-10-14,E16)**:曾把上面修复 1 的排渣序列收口进驱动复合复位原语 `ch395f_sock_reset_*`(去重复实现与参数副本),**实测回退**:`ftp_abort_probe` RST **0/10**、FIN **0/5**(首笔复连仍被截断到 ≤2048B),并新增 `sock_reset_sync timeout (600ms)` / `close: sock_reset not done` 两条 `[ERR]`;同场 net 层自建序列 **10/10 + 5/5**(快复连 50/50、背靠背 30/30 两版都过 → 失效面精确落在"中止后首笔复连")。结论 = 原语缺**隔离窗内持续排空/关闭**与**复用让位**两条语义,补齐前 **net 层保留自建序列**,勿再直接把监听重建接进原语。前置语义与 A/B 数据 → `docs/网络/网络自愈架构设计.md` §8 延后项 1、§5.2 E16;登记 **N-30**。
|
||||
- **收口尝试与边界(2026-10-14,E16)**:曾把上面修复 1 的排渣序列收口进驱动复合复位原语 `ch395f_sock_reset_*`(去重复实现与参数副本),**实测回退**:`ftp_abort_probe` RST **0/10**、FIN **0/5**(首笔复连仍被截断到 ≤2048B),并新增 `sock_reset_sync timeout (600ms)` / `close: sock_reset not done` 两条 `[ERR]`;同场 net 层自建序列 **10/10 + 5/5**(快复连 50/50、背靠背 30/30 两版都过 → 失效面精确落在"中止后首笔复连")。结论 = 原语缺**隔离窗内持续排空/关闭**与**复用让位**两条语义,补齐前 **net 层保留自建序列**,勿再直接把监听重建接进原语。前置语义与 A/B 数据 → `docs/网络/网络自愈架构设计.md` §8 延后项 1、§5.2 E16;登记条目「relisten 沉降段原语化受阻」。
|
||||
- **协议边界(不可判定,留痕)**:FTP STOR 无长度声明,"在途 FIN 关闭"与"正常完成"**逐字节不可区分** → 优雅中止仍回 226;仅 RST/掉链(芯片 TIMEOUT)可识别 → 450。FIN 边界由客户端长度校验(SIZE/RETR 往返)兜底。
|
||||
- **回归基线**:`--check-abort` RST **5/5**(450)+ FIN **5/5**(226 边界不变);followup 全过;正常往返 freeze SHA-256 全 MATCH;`:7003` sink 复用 RST×4/FIN×4 全过;`:8888` 真实收包写 RTC 成功。
|
||||
- **与 TC-NET-604 的关系**:本条是独立、已可信复现并已修复的真实缺陷;TC-NET-604 已结案为非缺陷(判读教训见第六章台架纪律)。现场"上传失败/文件不完整/像卡死"类报告优先用本条判据复核。
|
||||
@@ -295,7 +295,7 @@ CH395F 以太网驱动与 NET 层的实证陷阱:现象、定案根因、修
|
||||
|
||||
## 主机侧测试工具过期
|
||||
|
||||
- **`test/host/ftp_abort_probe.py` 已修**:原用匿名登录,N-19 后匿名被 530 拒 → TRAP-NET-18 两条腿**假 0/5**(round 1 `PASV failed`,且半认证会话占死 FTP 唯一会话,后续轮全变 `ConnectionRefused`)。改 `admin/admin` 后 RST 5/5、FIN 5/5。**教训:跑既有回归腿前先确认凭据仍有效,否则会把工具过期读成固件回归。**
|
||||
- **`test/host/ftp_abort_probe.py` 已修**:原用匿名登录,FTP 鉴权落地后匿名被 530 拒 → TRAP-NET-18 两条腿**假 0/5**(第 1 轮 `PASV failed`,且半认证会话占死 FTP 唯一会话,后续轮全变 `ConnectionRefused`)。改 `admin/admin` 后 RST 5/5、FIN 5/5。**教训:跑既有回归腿前先确认凭据仍有效,否则会把工具过期读成固件回归。**
|
||||
- **同族未修**:`test/host/ftp_up_dl_test.py`、`ftp_speed_test.py`、`ftp_test.py` 仍用匿名登录 → 对当前固件必挂登录步;`docs/测试说明/FTP_Test_Guide.md` 推荐的这几个入口因此已失效(现行可用入口是 `test/host/ftp_regression.py`,默认 `admin/admin`)。
|
||||
|
||||
## 文档侧待修清单
|
||||
|
||||
@@ -155,7 +155,7 @@ if (ok) {
|
||||
1. 探针文件名改 `/fschk.tmp`(严格 8.3:名≤8、扩展≤3、不以点开头);
|
||||
2. `FR_INVALID_NAME` 移出重格式化触发集合(名字语法错误与卷健康无关)。
|
||||
|
||||
**验证**(gen 45~48,@test 连续复位):
|
||||
**验证**(台架日志代次 45~48,@test 连续复位):
|
||||
`Map resumed: 197→198→199→200 sectors used`(卷随 boot 正常增量持久)、
|
||||
无 reformat 行、`[CFG] load: OK (523B)`(config.ini 跨复位存活)、VERDICT PASS。
|
||||
|
||||
@@ -199,7 +199,7 @@ if (ok) {
|
||||
|
||||
## TRAP-GD5F-06 — 轮询路径"伪完成":HAL 失败被伪装成操作完成(已修复,2026-10-03)
|
||||
|
||||
**发现时间**:2026-10-03(错误码传播审计 E-10/E-42/E-53/E-54/E-56/E-57 复核 + 台架套件回归)
|
||||
**发现时间**:2026-10-03(错误码传播审计六条复核 + 台架套件回归)
|
||||
|
||||
**现象/机制**:
|
||||
`gd5f_wait_busy` 内 3 次 HAL 调用(`HAL_SPI_Transmit` / `HAL_SPI_Receive`)返回值**全部丢弃**,
|
||||
@@ -216,7 +216,7 @@ if (ok) {
|
||||
- 公开 API 返回类型 `int` / `int32_t` 混用(码值均为小负数,无功能影响)。
|
||||
|
||||
**修复(2026-10-03)**:
|
||||
- `gd5f_wait_busy` 检查三次 HAL 调用,失败即返 `GD5F_ERROR`(与 `GD5F_WAIT_EXPIRED` 区分;后者旧名 `GD5F_BUSY_TIMEOUT`,2026-10-23 按 S-5 R2 改名——返回码不许叫 `*_TIMEOUT`,因为同名形状里还有"毫秒数"和"自旋圈数"两种东西)。
|
||||
- `gd5f_wait_busy` 检查三次 HAL 调用,失败即返 `GD5F_ERROR`(与 `GD5F_WAIT_EXPIRED` 区分;后者旧名 `GD5F_BUSY_TIMEOUT`,2026-10-23 按 BSP 错误码契约改名——返回码不许叫 `*_TIMEOUT`,因为同名形状里还有"毫秒数"和"自旋圈数"两种东西)。
|
||||
- `gd5f_bbt_scan` 返回错误码、每轮 `spare` 清零、读失败中止;`bbt_rebuild` 扫描失败
|
||||
**放弃持久化**(`gd5f_bbt_load()` 回滚 RAM 后直接返回,不 `bbt_save`)。
|
||||
- init 全链路检查返回值;init 后**回读 B0h 校验 ECC 使能(bit4)**,未使能即报错。
|
||||
@@ -234,7 +234,7 @@ if (ok) {
|
||||
|
||||
## TRAP-GD5F-07 — dhara 移植层:`is_free` 只看页首 + HAL 无几何校验(已修复,2026-10-15)
|
||||
|
||||
**发现时间**:2026-10-15(原审查报告 N-12 / N-13 复核,登记簿原 N-21;该报告 2026-10-25 已删除)
|
||||
**发现时间**:2026-10-15(原审查报告两条移植层缺陷复核,登记簿曾登记、现已销项;该报告 2026-10-25 已删除)
|
||||
|
||||
**现象 / 机制**(两个独立缺陷,同一层):
|
||||
|
||||
@@ -263,7 +263,7 @@ if (ok) {
|
||||
- **错误码选择是刻意的**:越界返回 `DHARA_E_CORRUPT_MAP`。**不能**用 `DHARA_E_BAD_BLOCK`
|
||||
——`journal.c:904 recover_from` 只对该码执行"标坏块 + 跳块",会把无辜好块标掉;
|
||||
**不能**用 `DHARA_E_RECOVER`——`map.c:275 try_recover` 只对该码启动回收。其余错误一律
|
||||
原样上抛,不会静默清 map(E-31 教训)。
|
||||
原样上抛,不会静默清 map(教训:宁报错不销毁数据)。
|
||||
- 无错误通道的两个函数取**保守值**:`is_free` 越界返回 0(判非空,最多少用一页)、
|
||||
`is_bad` 越界返回 1(判坏,绝不读写)、`mark_bad` 越界直接返回(绝不标无辜好块)。
|
||||
- `is_free` 内 `gd5f_page_read` / `gd5f_read_from_cache` 任一失败 → 返回 0
|
||||
@@ -289,7 +289,7 @@ if (ok) {
|
||||
1. **`is_free` 读失败返 0 的方向性代价**:比"误判空闲 → 再编程"安全(dhara 会去读 checkpage,
|
||||
被 magic / CRC 门挡住),但一次**瞬态 SPI 毛刺**就可能让整次 mount 失败——旧实现反而会被
|
||||
"页首恰好读到 0xFF"的快路径掩盖过去。这是**刻意选择**:宁可挂载失败,不可误判空闲
|
||||
(E-31 纪律:绝不拿销毁数据换可用性)。排障时记住"挂载失败 + 有 SPI 错误"先看这里。
|
||||
(纪律:绝不拿销毁数据换可用性)。排障时记住"挂载失败 + 有 SPI 错误"先看这里。
|
||||
2. **空白卷首启成本**:dhara resume 扫到的每个检查点页都是全 0xFF → 每页要 32 次列读
|
||||
(旧实现 1 次)。量级仍小(O(log N) × ppc),但**首次挂载(新格式化卷)会明显变慢**。
|
||||
台架若观察到该现象,根因在此,**不是回归**。
|
||||
@@ -300,4 +300,4 @@ if (ok) {
|
||||
**单一真源**(`disk_initialize` 与守卫同取此宏,杜绝两处各写一遍再各自漂移),
|
||||
再加两条负数组编译期守卫 `FTL_PAGE_SIZE == (1 << FTL_LOG2_PAGE_SIZE)` /
|
||||
`GD5F_PAGES_PER_BLOCK == (1 << FTL_LOG2_PPB)`——改 GD5F 常量而不同步几何即编译错。
|
||||
AC5 不支持 C11 `_Static_assert`,负数组是本项目惯用法(同本目录 `gd5f2gq5ue.h` 的 N-26 守卫)。
|
||||
AC5 不支持 C11 `_Static_assert`,负数组是本项目惯用法(同本目录 `gd5f2gq5ue.h` 的 DMA 可达性三层防线守卫)。
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
> **定位**:以参考项目 CLS100(`Scatter_P_HV03.01_SV01.01`)的"采样 → 预处理 → 相量 → 遥测 → 录波 → 上送"全链路为对照,评测本项目在**电力采集与数据处理**上的完成度,指出下一步该补的短板与顺序。
|
||||
> **不是待办登记簿**:排序权威仍是 `docs/任务规划/README.md` §2;本文只出评测结论与建议,条目落地时按语义标识登记进 `docs/任务规划/登记簿.md`。
|
||||
> **对照口径**:项目内以 `docs/算法/继电保护功能复现规划.md` §3 的 L1~L5 清单为准;参考侧以参考项目 `项目分析文档/04-算法与采样专题/` 三篇(《ADC采集至数据使用全流程详解》《项目详细分析-交流采样与有效值计算》《傅氏算法详解》)与源码为准。
|
||||
> **硬件前提**:结论只针对 **V0.1 现板**;受 N-18(8 路电气量分属两片转换器)制约的项单独标注,V0.2 改版后解禁。
|
||||
> **硬件前提**:结论只针对 **V0.1 现板**;受「双转换器无共同采样触发」(8 路电气量分属两片转换器)制约的项单独标注,V0.2 改版后解禁。
|
||||
|
||||
---
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
### 5.3 派生量(L2-5)
|
||||
|
||||
- **现状**:只有 3 个基波实例 + 2 个谐波实例,无线电压、无负序/正序/零序合成、无差分、无直流分量。
|
||||
- **为什么现在做**:V0.1 受 N-18 限制,跨转换器合成**不成立**(`UA` 与 `UB` 无同一时刻性);但**代码与单测可以先就绪**,V0.2 只改映射表就能使能。参考侧 `CalfLineVec`/`CalfNegVec`/`CalfPosVec`/`CalfSeqVec`/`CalfZeroVec`/`CalfAnaDC`/`CalfAnaDif` 是七个小模块,逻辑清晰、天然可主机单测。
|
||||
- **为什么现在做**:V0.1 受双转换器无共同采样触发限制,跨转换器合成**不成立**(`UA` 与 `UB` 无同一时刻性);但**代码与单测可以先就绪**,V0.2 只改映射表就能使能。参考侧 `CalfLineVec`/`CalfNegVec`/`CalfPosVec`/`CalfSeqVec`/`CalfZeroVec`/`CalfAnaDC`/`CalfAnaDif` 是七个小模块,逻辑清晰、天然可主机单测。
|
||||
- **建议**:按"吃实例下标、出合成相量"的接口建 `derived.c/h`,V0.1 标注"不使能",单测用合成正弦验证相位关系。
|
||||
- **规模**:M。
|
||||
|
||||
@@ -220,7 +220,7 @@
|
||||
### 5.5 功率与电度
|
||||
|
||||
- **现状**:零。点表 `4019~401c`(P/Q/S/PF)与电度上送缺失。
|
||||
- **关键判断**:V0.1 上**算不出来**(N-18 禁止跨转换器功率运算),产品口径是"取子板计量模块结果"(见 `docs/硬件平台/ADC通道映射说明.md` §1)。所以这不是"补算法",而是**先定数据来源**:
|
||||
- **关键判断**:V0.1 上**算不出来**(双转换器无共同采样触发 → 禁止跨转换器功率运算),产品口径是"取子板计量模块结果"(见 `docs/硬件平台/ADC通道映射说明.md` §1)。所以这不是"补算法",而是**先定数据来源**:
|
||||
- 若子板计量有数字接口(RS-485/SPI)→ 这是 B2(RS-485 采集,已暂缓)的一部分;
|
||||
- 若没有 → 等 V0.2 三相全上 TPAFE 后自算。
|
||||
- **建议**:**先拍板来源,再写代码**。现在写功率算法在 V0.1 上无法验证,属于无效工作。
|
||||
@@ -318,7 +318,7 @@
|
||||
| 同期合闸、小电流接地选线 | 依赖三相/零序电流与出口,V0.1 均不具备;参考侧同期组件本身也被注释未启用 |
|
||||
| IEC 61850 / GOOSE | 与单核 FreeRTOS 平台、当前产品定义都不匹配 |
|
||||
| 双核拆分 / DSP 移植 | 平台不匹配;单核 168 MHz + FPU 目前余量够 |
|
||||
| 在 V0.1 上写功率算法 | N-18 使相位关系不成立,写出来无法验证(见 5.5) |
|
||||
| 在 V0.1 上写功率算法 | 双转换器无共同采样触发使相位关系不成立,写出来无法验证(见 5.5) |
|
||||
| 先改 4 kHz 节拍再想录波 | 节拍一改,保护窗、CPU、RAM 全变;应先定"录波要不要 80 点"再动 |
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user