diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c3a76b82..0693cef1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -750,7 +750,7 @@ repos: # P1 新增的 12 套不在任何提交钩子里。原先"再加一份全量插桩等于同一件事做两遍" # 这条理由到现在已经**反了**(现状是有一遍没做),所以必须挂;缺口此前如实登记在 # docs/测试说明/单元测试/主机单测覆盖率口径.md §8。 - # 为什么挂这一根而不是补 12 个 per-module 钩子:本钩子当时跑**全部 28 套**(现值 44 套,台账见 + # 为什么挂这一根而不是补 12 个 per-module 钩子:本钩子当时跑**全部 28 套**(现值 47 套,台账见 # docs/门禁说明/host-unit-tests.md §6 第 4 条),并且守 §5 的 # 回退台账(某套被删、或某文件的已覆盖行变少 → [REGRESS] 直接红)。这是 per-module # 钩子做不到的——删掉一套测试,它那根钩子只会因为"没有文件要检查"而静默跳过。 @@ -761,8 +761,8 @@ repos: # 口径 / 分母 / 基线 / 盲区详解都在 docs/测试说明/单元测试/主机单测覆盖率口径.md,本处只留接线事实。 # 触发面**含门禁自身**(.pre-commit-config.yaml):不带自身就等于谁改坏这根闸的 files: # 模式,它就再也不跑且无人察觉(同 lv-conf-sync / bsp-err 的既有做法)。 - # ⚠ stages: [manual](2026-10-28 用户裁定):本钩子跑光全部 44 套单测(41 套时实测 ~105 s,套件数 - # 涨了耗时就涨,44 套这轮未重测耗时; + # ⚠ stages: [manual](2026-10-28 用户裁定):本钩子跑光全部 47 套单测(41 套时实测 ~105 s,套件数 + # 涨了耗时就涨,47 套这轮未重测耗时; # 占一次带代码提交耗时的三分之二)→ 不压在提交期,由**远端 CI** 强制 # (.gitea/workflows/ci.yml 的「手动阶段门禁(覆盖率总闸 + 全量 cppcheck)」步),本地等价入口 = # scripts/ci_local.py(manual 段);手工复跑: diff --git a/AGENTS.md b/AGENTS.md index 25f65826..a447efd3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -10,12 +10,12 @@ ## 项目概况 -**现状一句话**:平台能力(网络 / 存储 / 时间 / UI / 日志 / 看门狗 / FTP / 配置)**已实现并台架验收**;采集主线已闭环到业务消费者(语义取数与有效性→全周傅氏相量→测频与遥测快照→保护判据 protectTask→104 遥信/遥测+UI,B5/批 2);⚠ **保护判据现处于「未标定闭锁」态**——产品构建下 `adc_cal_flags()` 的 `ADC_CAL_F_VALID` 未置位,`protect_task.c:98` 直接停走判据,等两点标定写入 `[adc_cal] valid` 后自动解卡(用户裁定 2026-10-25:保持闭锁,不用万用表走捷径);**RS-485 采集尚未接线**(B2 按用户决策冻结,见 `docs/任务规划/暂缓-RS485.md`)——当前最大功能缺口,接线节奏受 **RS-485 接线门禁**约束(见「平台约束」)。 +**现状一句话**:平台能力(网络 / 存储 / 时间 / UI / 日志 / 看门狗 / FTP / 配置)**已实现并台架验收**;采集主线已闭环到业务消费者(语义取数与有效性→全周傅氏相量→测频与遥测快照→保护判据 protectTask→104 遥信/遥测+UI,B5/批 2);⚠ **保护判据现处于「未标定闭锁」态**——产品构建下 `adc_cal_flags()` 的 `ADC_CAL_F_VALID` 未置位,`App/task/protect_task.c:268` 判停(判定本体 = `adc_cal_prot_blocked()`,本任务只是消费者),等两点标定写入 `[adc_cal] valid` 后自动解卡(用户裁定 2026-10-25:保持闭锁,不用万用表走捷径);**RS-485 采集尚未接线**(B2 按用户决策冻结,见 `docs/任务规划/暂缓-RS485.md`)——当前最大功能缺口,接线节奏受 **RS-485 接线门禁**约束(见「平台约束」)。 **数据主线**(能力视角;分层图与跨层依赖表 → `docs/架构设计/项目架构总览.md`): - **采集**:TPAFE5160(计量级 8 路,并行总线)+ 片内 ADC1(9 路,DMA)→ TIM3 1 kHz 节拍 + 原子快照 → adcTask → 语义取数与有效性校验 → 全周傅氏相量 → **测频与遥测快照(`meas` 200 ms 双区,104 与 UI 共用同一份上游,批 2)**+ 保护判据(protectTask 20 ms 判据节拍,B5)→ 104 遥信/遥测上送 -- **存储**:GD5F SPI NAND → dhara FTL → FatFs → `/log` 运行与自检记录、`/config.ini` 配置、FTP 根目录 +- **存储**:GD5F SPI NAND → dhara FTL → FatFs → `/log` 运行/自检等七本记录 + SOE、`/config.ini` 配置、FTP 根目录 - **网络**:CH395F → netTask 串行 socket 栈 → FTP(21) / 对时(8888) / RemoDispBus 远程显示(7003) / IEC 60870-5-104 上行(2404) - **人机**:LVGL 160×160 单色菜单(uiTask),**与 PC 模拟器同一份 UI 源码**,远端可看图 + 注键 @@ -42,9 +42,9 @@ `Src/main.c`(CubeMX 初始化)→ `app_main_init` → `osKernelStart` → 9 任务(`osKernelStart` 之前全是内核启动前代码:禁调任何内核 API,见「平台约束」) - `app_main_init`(时间子系统优先,使后续日志带时间戳):`sd2506_init` → `sys_clock_init` → `rs485_init` → `gd5f2gq5ue_init` → `tpafe5160_init` → `adc_input_init`(语义取数与有效性层)→ SD2506 诊断 → **启动 TIM3 1 kHz 采样节拍** -- **就绪屏障**(`App/app/sys_events.h` Event Flags,取代魔法延时):`SYS_EVT_NET_READY` / `STORAGE_READY` / `FTP_READY` / `TIMESYNC_READY`;消费者用 `osEventFlagsWait` 阻塞等待(就绪位 `osFlagsNoClear`) +- **就绪屏障**(`App/app/sys_events.h` Event Flags,取代魔法延时):**在用两位** `SYS_EVT_NET_READY` / `SYS_EVT_STORAGE_READY`(消费者 `osEventFlagsWait` 阻塞等待,就绪位 `osFlagsNoClear`)+ **预留两位** `FTP_READY`(有生产者、暂无消费者)/ `TIMESYNC_READY`(生产者消费者都无)→ 逐位对照表 `docs/架构设计/项目启动顺序管理.md` §3.2 - netTask:`net_stack_bring_up`(配置已由 defaultTask 在屏障前加载,本任务只读 RAM 副本)→ 置 NET_READY → 循环 `net_poll` + `net_process_messages`;消费 `SYS_EVT_NET_RECONFIG` → 按网络代次号重建监听(新 IP 免重启生效) -- defaultTask:`f_mount` forced(无卷自动 `f_mkfs`;挂载后卷健康探针,FAT 区陈旧时自愈重格式化)→ 加载网络配置 → STORAGE_READY → LED 闪烁;同时是 syslog(`/log/run.log`·`selftest.log`,定长 64B 记录)的**唯一写者**与**配置引擎属主**(netTask/uiTask 不得直接触碰配置引擎) +- defaultTask:`f_mount` forced(无卷自动 `f_mkfs`;挂载后卷健康探针,FAT 区陈旧时自愈重格式化)→ 加载网络配置 → STORAGE_READY → LED 闪烁;同时是 `/log` 的**唯一写者**(syslog 七本 run/selftest/accid/alarm/start/oper/yk,定长 64B 记录 + `soe.log` 事件序列;`wdev.log` 是变长取证行)与**配置引擎属主**(netTask/uiTask 不得直接触碰配置引擎) - adcTask:**纯消费者**——每拍 `adc_input_poll()`(TPAFE 原子快照 + 消费一帧 STM32 ADC1 DMA 双缓冲),只取数不做保护运算;**节拍与唤醒同源**(TIM3 ISR 内触发 CONVST + 同一更新事件经 TRGO 触发 ADC1,并调 `adc_tick_irq_notify()` 置位,任务 `osThreadFlagsWait` 等唤醒)。⚠ ISR 侧**只能**走 `adc_tick_irq_notify()`(内含"消费者就绪"门,TIM3 比调度器早 ≈100 ms 启动);手写于 `Src/freertos.c` 的 `USER CODE` 区,纳入 IWDG `required_mask`(`TASK_WD_ADC`) - **采集与算法层(语义取数与有效性/全周傅氏相量/保护判据)落在 `App/algo/`**:`adc_input`/`adc_health` = 语义取数与有效性,`sample_ring`/`phasor` = 全周傅氏相量,`freq` = 测频与遥测快照(B8,自适应窗),`prot_set`/`prot_elm` = 保护判据。板端消费者 = **protectTask**(B5,2026-10-12):20 ms 节拍 `prot_elm_run()` + 自检失败闭锁(采样故障闭锁)+ 定值校验和巡检;跨上下文复归(104 YK11)经 `prot_elm_request_reset()` 落请求。纳入 IWDG `required_mask`(`TASK_WD_PROTECT`,产品 `0x1F7`)。→ `docs/算法/采集与算法层设计说明.md`(设计与判据)、`App/algo/README.md`(目录索引) - 全景 → `docs/架构设计/项目架构总览.md`;启动时序与内核前模式 → `docs/架构设计/项目启动顺序管理.md` @@ -94,7 +94,7 @@ ## 提交门禁(pre-commit) -- 任一失败即拦截,共 **52 个钩子**(**口径 = YAML 解析后的 hook 条目数**:自查命令与「声明 / 文档 / 实跑」三数同源核对见 `docs/门禁说明/README.md` §2 首条——⚠ 直接 grep 配置里的声明行会多算一条**注释掉的**候选钩子(比口径多 1),不是口径;**配置注释里也别复述那个 grep 字面量**,它会让文本计数再虚高 1(2026-10-27 实测踩过);加一条钩子就同批改 AGENTS 与门禁索引两处计数。2026-10-25 道E 连加 `bom-guard` / `setview-check` / `uinav-selftest` 三条,2026-10-26 加 `generated-fresh` 一条,2026-10-27 加 `nested-comment` 一条;2026-10-28 加 `id-check-new` 一条并同批退役 `id-check`(口径 52 → 51:编号门禁换牙——新的只查新增行、零语料,旧的八项全库校验连语料一起移入 `scripts/archive/id_gate/`,手工普查与恢复机器面见 `docs/编号规范.md` §8.5);2026-10-29 加 `skill-size` 一条(51 → 52),同日按用户裁定**退役 `id-check-new`**(52 → **51**:只查新增行的编号门禁整体退场,脚本与白名单一起移入 `scripts/archive/id_gate/`,编号形态此后无机器面,留档 `docs/门禁说明/id-check-new.md`);2026-10-30 加 `mermaid-syntax` 一条(51 → **52**:mermaid 围栏内确定性语法——坏图此前只能靠肉眼在渲染端发现,实证见专篇);**每种门禁一篇详解(查什么 / 拦下过什么真事 / 限制与盲区 / 基线口径)→ `docs/门禁说明/README.md` 索引**;通用机制与整体口径 → `docs/代码规范/pre-commit使用说明.md`):通用 5 + `gitlint` + `cppcheck` / `test-cppcheck` + `no-mojibake` + `coding-standard` + 文档三件套 `doc-links` / `task-table` / `mem-numbers` + `lv-conf-sync`(两份 `lv_conf.h` 特性子集一致)+ `cubemx-survival` + `bom-guard` / `setview-check` / `uinav-selftest`(2026-10-25 道E 那三条:前半句的加钩流水里有它们、逐项枚举里漏了,补上后本行各项相加才等于 51;2026-10-30 又加 `mermaid-syntax` 后此句的"等于"目标数为 52)+ 主机侧单测 **22 根专属钩子**(`-unit-test` 后缀 = 有独立 `files:` 触发面、需要秒级归因的那个子集;2026-10-25 增补 adc-cal / prot-dim / vol-idle-sync / ui-data / meas / run-par 六根)——**这是口径不是缺口**:`test/host/` 实测 44 套带 `run_unit_test.py`,其余 **22 套**(含 `test/host/ui_sink` 与录波三套)没有专属钩子,但每次 CI / `scripts/ci_local.py` 都被 `test-coverage` 总闸全量真跑并守基线回退,**失败照样拦**,只是归因落在总闸输出上;**没有专属钩子 ≠ 没被跑**,22 套台账与补钩子的判据 → `docs/门禁说明/host-unit-tests.md` §6 第 4 条。**Lead 裁定 2026-10-27:不补第 23 根**——读「这套跑没跑」去看总闸输出,别数钩子(原写「23 个 / 含 ui-sink 七个」是双重错:既把 22 说成 23,又宣称 ui-sink 有钩子——配置历史里 `ui-sink-unit-test` 从未存在)+ `test-coverage`(**覆盖率总闸**:跑全部 44 套并守基线回退;缺 mscoverage 组件时按用户裁定 **FAIL**、不 skip,2026-10-24)+ `test-suite-switch` + `registration-check`(双端注册反向校验 + UI 页面描述符表接线,登记簿条目「rs485_task 白名单缺口」)+ `generated-fresh`(**生成器幂等性**:把 `tools/menu_gen/gen_menu.py`、中文字库链、`tools/arch_diagram/gen_*.py` 拷进**系统临时目录**重跑,与工作区**逐字节**必须一致——钩子只读、不写仓库也不 stash 别人在飞的改动;实证 `0f7b5a87` 改了模板文字没重跑生成物,接线前实测另有 5 张 `docs/images/` 配图已漂 → 钉成只减不增基线,**业务生成物零豁免面** → `docs/门禁说明/generated-fresh.md`)+ `nested-comment`(**块注释嵌套**:注释体内再出现 /* 会被 ARMCC 报 9-D,且**按包含者数量刷屏**、只在重编译该 TU 时才暴露;本仓诱因就是「在注释里写作用域/通配路径」,改法是写全目录或用尖括号 ;接线当日实扫 403 个 .c/.h,新发 0、存量 2 处(`test/host/common/` 两份假件头)钉只减不增基线 → `docs/门禁说明/nested-comment.md`)+ `skill-size`(**SKILL.md 不超插件写侧上限 65536 字节**:dsh-mnemon 只在写侧校验、加载侧不查,超限技能照常可读却每次「生成草案」被拒、永久卡在「生成中」;另查 `reference/` 指针悬空与 BOM → `docs/门禁说明/skill-size.md`)+ `mermaid-syntax`(**mermaid 围栏语法预检**:` ```mermaid ` 块里只查「错了必渲染失败」三条——图类型头 / `-.` 后直接跟管道(本坑:屏板链路设计说明 §1 坏图靠肉眼在渲染端发现,期间各文档门禁全绿)/ subgraph 与 sequence 块的 `end` 计数配对;零语料空基线、`docs/芯片手册/` 与 doc-links 同排除面 → `docs/门禁说明/mermaid-syntax.md`)+ `mem-budget`(RAM 92% 预算门禁,登记簿条目「缩堆迁 CCM 后半(暂缓)」)+ `font-charset`(UI 字符集差集检查,防缺字白框)+ `ui-golden`(UI 像素回归,菜单 8 状态 + 内容页 66 张黄金参考)+ `layer-deps`(**分层方向**:`Drivers/BSP/**` 不得 include `App/**` 的头;存量 3 条基线只减不增(2026-10-25 记录 reader 注入削掉 UI 记录 3 条边,6→3))+ `bsp-err`(**BSP 错误码与超时命名约定**:公开 API 不得拿 `HAL_StatusTypeDef`/`bool` 当错误通道、`*_TIMEOUT` 宏不得取负值、非 void 须写「返回值:」、**返回错误码的函数不得裸丢弃返回值**(须接住或显式 `(void)`;实测编译器与 cppcheck 都不报这类,只有这条会响);约定正文 `Drivers/BSP/bsp_err.h`,存量基线只减不增(2026-10-23 首清点 19 条 → 已还 18;`consume-result` 上线又暴露 37 条存量丢弃 → **现 38 条**))。**提交期实跑 49 根**(2026-10-30 起,前值是 48;三根慢钩子让位的裁定 2026-10-28):`cppcheck` / `test-cppcheck` / `test-coverage` 三根带 `stages: [manual]`——实测合计 ~165 s = 一次带代码提交耗时的三分之二,提交期只跑快的那些;这三根由**远端 CI** 强制(`.gitea/workflows/ci.yml` 的「手动阶段门禁」步,逐根 `--hook-stage manual`)与 `scripts/ci_local.py` 的 manual 段,本地手工复跑 `python -m pre_commit run --all-files --hook-stage manual `(一次只能一个 id) +- 任一失败即拦截,共 **52 个钩子**(**口径 = YAML 解析后的 hook 条目数**:自查命令与「声明 / 文档 / 实跑」三数同源核对见 `docs/门禁说明/README.md` §2 首条——⚠ 直接 grep 配置里的声明行会多算一条**注释掉的**候选钩子(比口径多 1),不是口径;**配置注释里也别复述那个 grep 字面量**,它会让文本计数再虚高 1(2026-10-27 实测踩过);加一条钩子就同批改 AGENTS 与门禁索引两处计数。2026-10-25 道E 连加 `bom-guard` / `setview-check` / `uinav-selftest` 三条,2026-10-26 加 `generated-fresh` 一条,2026-10-27 加 `nested-comment` 一条;2026-10-28 加 `id-check-new` 一条并同批退役 `id-check`(口径 52 → 51:编号门禁换牙——新的只查新增行、零语料,旧的八项全库校验连语料一起移入 `scripts/archive/id_gate/`,手工普查与恢复机器面见 `docs/编号规范.md` §8.5);2026-10-29 加 `skill-size` 一条(51 → 52),同日按用户裁定**退役 `id-check-new`**(52 → **51**:只查新增行的编号门禁整体退场,脚本与白名单一起移入 `scripts/archive/id_gate/`,编号形态此后无机器面,留档 `docs/门禁说明/id-check-new.md`);2026-10-30 加 `mermaid-syntax` 一条(51 → **52**:mermaid 围栏内确定性语法——坏图此前只能靠肉眼在渲染端发现,实证见专篇);**每种门禁一篇详解(查什么 / 拦下过什么真事 / 限制与盲区 / 基线口径)→ `docs/门禁说明/README.md` 索引**;通用机制与整体口径 → `docs/代码规范/pre-commit使用说明.md`):通用 5 + `gitlint` + `cppcheck` / `test-cppcheck` + `no-mojibake` + `coding-standard` + 文档三件套 `doc-links` / `task-table` / `mem-numbers` + `lv-conf-sync`(两份 `lv_conf.h` 特性子集一致)+ `cubemx-survival` + `bom-guard` / `setview-check` / `uinav-selftest`(2026-10-25 道E 那三条:前半句的加钩流水里有它们、逐项枚举里漏了,补上后本行各项相加才等于 51;2026-10-30 又加 `mermaid-syntax` 后此句的"等于"目标数为 52)+ 主机侧单测 **22 根专属钩子**(`-unit-test` 后缀 = 有独立 `files:` 触发面、需要秒级归因的那个子集;2026-10-25 增补 adc-cal / prot-dim / vol-idle-sync / ui-data / meas / run-par 六根)——**这是口径不是缺口**:`test/host/` 实测 47 套带 `run_unit_test.py`(48 个一级目录除 `common`),其余 **25 套**(含 `test/host/ui_sink`、录波三套与屏板链路三套)没有专属钩子,但每次 CI / `scripts/ci_local.py` 都被 `test-coverage` 总闸全量真跑并守基线回退,**失败照样拦**,只是归因落在总闸输出上;**没有专属钩子 ≠ 没被跑**,22 套台账与补钩子的判据 → `docs/门禁说明/host-unit-tests.md` §6 第 4 条。**Lead 裁定 2026-10-27:不补第 23 根**——读「这套跑没跑」去看总闸输出,别数钩子(原写「23 个 / 含 ui-sink 七个」是双重错:既把 22 说成 23,又宣称 ui-sink 有钩子——配置历史里 `ui-sink-unit-test` 从未存在)+ `test-coverage`(**覆盖率总闸**:跑全部 47 套并守基线回退;缺 mscoverage 组件时按用户裁定 **FAIL**、不 skip,2026-10-24)+ `test-suite-switch` + `registration-check`(双端注册反向校验 + UI 页面描述符表接线,登记簿条目「rs485_task 白名单缺口」)+ `generated-fresh`(**生成器幂等性**:把 `tools/menu_gen/gen_menu.py`、中文字库链、`tools/arch_diagram/gen_*.py` 拷进**系统临时目录**重跑,与工作区**逐字节**必须一致——钩子只读、不写仓库也不 stash 别人在飞的改动;实证 `0f7b5a87` 改了模板文字没重跑生成物,接线前实测另有 5 张 `docs/images/` 配图已漂 → 钉成只减不增基线,**业务生成物零豁免面** → `docs/门禁说明/generated-fresh.md`)+ `nested-comment`(**块注释嵌套**:注释体内再出现 /* 会被 ARMCC 报 9-D,且**按包含者数量刷屏**、只在重编译该 TU 时才暴露;本仓诱因就是「在注释里写作用域/通配路径」,改法是写全目录或用尖括号 ;接线当日实扫 403 个 .c/.h,新发 0、存量 2 处(`test/host/common/` 两份假件头)钉只减不增基线 → `docs/门禁说明/nested-comment.md`)+ `skill-size`(**SKILL.md 不超插件写侧上限 65536 字节**:dsh-mnemon 只在写侧校验、加载侧不查,超限技能照常可读却每次「生成草案」被拒、永久卡在「生成中」;另查 `reference/` 指针悬空与 BOM → `docs/门禁说明/skill-size.md`)+ `mermaid-syntax`(**mermaid 围栏语法预检**:` ```mermaid ` 块里只查「错了必渲染失败」三条——图类型头 / `-.` 后直接跟管道(本坑:屏板链路设计说明 §1 坏图靠肉眼在渲染端发现,期间各文档门禁全绿)/ subgraph 与 sequence 块的 `end` 计数配对;零语料空基线、`docs/芯片手册/` 与 doc-links 同排除面 → `docs/门禁说明/mermaid-syntax.md`)+ `mem-budget`(RAM 92% 预算门禁,登记簿条目「缩堆迁 CCM 后半(暂缓)」)+ `font-charset`(UI 字符集差集检查,防缺字白框)+ `ui-golden`(UI 像素回归,菜单 8 状态 + 内容页 66 张黄金参考)+ `layer-deps`(**分层方向**:`Drivers/BSP/**` 不得 include `App/**` 的头;存量 3 条基线只减不增(2026-10-25 记录 reader 注入削掉 UI 记录 3 条边,6→3))+ `bsp-err`(**BSP 错误码与超时命名约定**:公开 API 不得拿 `HAL_StatusTypeDef`/`bool` 当错误通道、`*_TIMEOUT` 宏不得取负值、非 void 须写「返回值:」、**返回错误码的函数不得裸丢弃返回值**(须接住或显式 `(void)`;实测编译器与 cppcheck 都不报这类,只有这条会响);约定正文 `Drivers/BSP/bsp_err.h`,存量基线只减不增(2026-10-23 首清点 19 条 → 已还 18;`consume-result` 上线又暴露 37 条存量丢弃 → **现 38 条**))。**提交期实跑 49 根**(2026-10-30 起,前值是 48;三根慢钩子让位的裁定 2026-10-28):`cppcheck` / `test-cppcheck` / `test-coverage` 三根带 `stages: [manual]`——实测合计 ~165 s = 一次带代码提交耗时的三分之二,提交期只跑快的那些;这三根由**远端 CI** 强制(`.gitea/workflows/ci.yml` 的「手动阶段门禁」步,逐根 `--hook-stage manual`)与 `scripts/ci_local.py` 的 manual 段,本地手工复跑 `python -m pre_commit run --all-files --hook-stage manual `(一次只能一个 id) - **范围 = 项目代码**:第三方(`Lib/`、`Middlewares/`、CMSIS、HAL、`lftpd`、`dhara`、`MDK-ARM`)排除;`cppcheck`/`coding-standard` 另排除 `test/`,规范检查再排除 CubeMX 生成的 `Src/`/`Inc/`。**`simulator/` 已纳入全部钩子**(2026-10-11)——生成物只靠 `.gitignore` 挡,**不在 `exclude` 里写目录名**(教训见 `docs/代码规范/pre-commit使用说明.md` §5.5) - ⚠ **pre-commit 4.x 已移除 `always: true`**(实测对 `local` 钩子只告警 `Unexpected key(s)` 并跳过)→ 想"总是跑"的钩子**必须让 `files:` 覆盖到所有会触发它的文件**,没有兜底开关 - **改写型钩子(`trailing-whitespace` + `end-of-file-fixer`)豁免 CubeMX/Keil 生成文件**(配置里 YAML 锚点 `&cubemx-generated`);⚠ **只读检查不受影响**:`cppcheck` / 乱码 / `cubemx-survival` / `task-table` / `mem-numbers` 仍覆盖 `Src/`、`Inc/` diff --git a/App/app/app_main.c b/App/app/app_main.c index 3d9948d9..4f25fa7d 100644 --- a/App/app/app_main.c +++ b/App/app/app_main.c @@ -194,7 +194,9 @@ int app_main_init(void) { syslog_post(SYSLOG_SELFTEST, "clock chip fault"); } - /* 2) RS-485 初始化(UART4 + PD0 方向控制),初始化即自动开启接收 */ + /* 2) RS-485 初始化(UART4 + 方向脚 = ST_DIR4 宏:V0.1 板实测 PA15,V0.0 曾是 PD0, + * 轮换记录 = docs/硬件平台/V0.1_网表详细分析报告.md 的 V0.0→V0.1 引脚迁移表), + * 初始化即自动开启接收 */ rs485_init(&g_rs485, &huart4, ST_DIR4_GPIO_Port, ST_DIR4_Pin); DBG_INFO("RS485 init: OK (UART4, DE=PA15)"); diff --git a/App/app/sys_events.h b/App/app/sys_events.h index b2d823f4..1785f919 100644 --- a/App/app/sys_events.h +++ b/App/app/sys_events.h @@ -22,11 +22,12 @@ extern "C" { * 由 MX_FREERTOS_Init 在 freertos.c 的 generated 区域自动声明并 osEventFlagsNew 创建) */ extern osEventFlagsId_t sys_evtHandle; -/* 各子系统"就绪"事件位(32 位上限内的 bit 0~30) */ +/* 各子系统"就绪"事件位(32 位上限内的 bit 0~30)。**bit0 / bit1 在用,bit2 / bit3 是预留位** + * ——逐位的生产者与消费者对照表 = docs/架构设计/项目启动顺序管理.md §3.2 */ #define SYS_EVT_NET_READY (1u << 0) /* netTask:net_init + PHY 稳定完成 */ #define SYS_EVT_STORAGE_READY (1u << 1) /* defaultTask:FTL/FatFS 挂载完成 */ -#define SYS_EVT_FTP_READY (1u << 2) /* ftpTask:lftpd_start 完成 */ -#define SYS_EVT_TIMESYNC_READY (1u << 3) /* timeSyncTask:首次时间同步完成 */ +#define SYS_EVT_FTP_READY (1u << 2) /* ftpTask:lftpd_start 完成后置位;暂无消费者(预留) */ +#define SYS_EVT_TIMESYNC_READY (1u << 3) /* 预留:timeSyncTask 在跑但不置本位,生产者消费者都没有 */ #define SYS_EVT_NET_RECONFIG (1u << 4) /* UI:请求立即应用新网口配置(netTask 消费后重建网络) */ #define SYS_EVT_CFG_SAVE (1u << 5) /* UI:网口配置保存请求(defaultTask = 配置引擎属主,消费并写盘) */ #define SYS_EVT_CONSOLE_TX (1u << 6) /* 控制台单写者:生产者入环形缓冲后置位,defaultTask 消费并发送 diff --git a/App/log/README.md b/App/log/README.md index 3324ea72..95715294 100644 --- a/App/log/README.md +++ b/App/log/README.md @@ -59,11 +59,11 @@ | 记录 | 日志 ID / 文件 | 容量上限 | 写入点 | 触发判据 | |---|---|---|---|---| -| 事故 | `SYSLOG_ACCIDENT` / `accid.log` | 512 | `App/task/protect_task.c:181` | `asserted` 上升沿**且**该元件跳闸投退项 = 1 | -| 保护告警 | `SYSLOG_ALARM` / `alarm.log` | 1024 | 同文件 `184` | `asserted` 上升沿**且**跳闸投退项 = 0 或该元件无此项 | -| 保护启动 | `SYSLOG_START` / `start.log` | 1024 | 同文件 `176` | `picked` 上升沿(越限电平,早于/等于动作) | -| 操作 | `SYSLOG_OPER` / `oper.log` | 512 | `App/protocol/iec104/iec104_pts.c:574/602`、`App/task/default_task.c:242`、`App/log/sys_log_mcu.c:646`(宿主 `sim_syslog.c:245`) | 强制复归受理 / 软压板投退落地 / 定值**真落盘成功** / 清除记录成功 | -| 遥控 | `SYSLOG_YK` / `yk.log` | 256 | `App/protocol/iec104/iec104_pts.c:573/576/582/586/596/598/609` | 104 双点命令的选择段、执行段、非法 DPC、未知 IOA 各一条 | +| 事故 | `SYSLOG_ACCIDENT` / `accid.log` | 512 | `App/task/protect_task.c:188` | `asserted` 上升沿**且**该元件跳闸投退项 = 1 | +| 保护告警 | `SYSLOG_ALARM` / `alarm.log` | 1024 | 同文件 `191` | `asserted` 上升沿**且**跳闸投退项 = 0 或该元件无此项 | +| 保护启动 | `SYSLOG_START` / `start.log` | 1024 | 同文件 `183` | `picked` 上升沿(越限电平,早于/等于动作) | +| 操作 | `SYSLOG_OPER` / `oper.log` | 512 | `App/protocol/iec104/iec104_pts.c:582/610`、`App/task/default_task.c:266`、`App/log/sys_log_mcu.c:682`(宿主 `sim_syslog.c:245`) | 强制复归受理 / 软压板投退落地 / 定值**真落盘成功** / 清除记录成功 | +| 遥控 | `SYSLOG_YK` / `yk.log` | 256 | `App/protocol/iec104/iec104_pts.c:581/584/590/594/604/606/617` | 104 双点命令的选择段、执行段、非法 DPC、未知 IOA 各一条 | - **"哪些元件算跳闸"只有一个真源**:定值表 `g_prot_set_meta` 里的 `PS_*_TRIP`(枚举注释 即"0 告警 / 1 跳闸")+ 实例表 `k_pe[]` 的 `trip_ctl` 列。分类入口 diff --git a/App/protocol/iec104/iec104_link.h b/App/protocol/iec104/iec104_link.h index 95584667..1c2181d8 100644 --- a/App/protocol/iec104/iec104_link.h +++ b/App/protocol/iec104/iec104_link.h @@ -11,7 +11,8 @@ * 时基 = 调用方注入 now_ms(tick ms,回绕安全:差值法) * → 全栈(asdu+pts+link)主机侧纯逻辑单测可离线跑(分层约束)。 * 参数(DL/T 634.5104 标准默认,§1.5 未另定):k=12 w=8 t1=15s t2=10s t3=20s。 - * 端口:TCP **2404**(§1.5 B0 定义;本 DTU = 被控站/服务器,主站连入)。 + * 端口:TCP **2404** = 工厂默认(§1.5 B0 定义 / IEC 60870-5-104 标准端口; + * 本 DTU = 被控站/服务器,主站连入)。真源与可改性见本文件下方 [comm] 段说明。 * 线程约定:单实例单任务上下文(板端 = 104 服务在 netTask 消息循环内驱动, * 见 iec104_serv 胶水层);非线程安全,禁止多任务共享一实例。 * 失败语义:send_apdu 内**不得阻塞**;发送失败由胶水层断链(主站会重连), diff --git a/App/task/ui_task.c b/App/task/ui_task.c index 31934983..2149ecc9 100644 --- a/App/task/ui_task.c +++ b/App/task/ui_task.c @@ -235,8 +235,9 @@ static int ui_task_maint_reset_req(void) { * 返回值:位图中置 1 的位数(纯 RAM 读,无锁) uint32_t * 限定条件:uiTask 绘制路径每帧可直调 * 函数说明:给个数而不是位图,是为了让 160x160 上一行放得下、也让"复归前 N>0 → - * 复归后 N=0"这个台架判据肉眼可读;判据前提(产品构建处于未标定闭锁, - * App/task/protect_task.c:98 停走判据 ⇒ 闭锁期 N 恒 0)已写进页面注释 + * 复归后 N=0"这个台架判据肉眼可读;判据前提(产品构建处于未标定闭锁—— + * App/task/protect_task.c:268 判停,判定本体 = adc_cal_prot_blocked(), + * 闭锁期 N 恒 0)已写进页面注释 */ static uint32_t ui_task_maint_active_count(void) { uint32_t mask = prot_elm_active_mask(); diff --git a/README.md b/README.md index 4468b364..3b444429 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ main.c | uiTask | 4096 words | BelowNormal | LVGL UI 界面 | | timeSyncTask | 640 words | Normal | 墙钟时间同步 | | adcTask | 640 words | AboveNormal | TPAFE5160 采样(TIM3 1kHz 事件驱动 + 原子快照 + STM32 ADC DMA,纯消费者) | -| iec104Task | 640 words | Normal | IEC 60870-5-104 上行(:2404 监听,遥信/遥测/定值区) | +| iec104Task | 640 words | Normal | IEC 60870-5-104 上行(工厂默认 :2404 监听,遥信/遥测/定值区) | | protectTask | 512 words | Normal | 保护判据 20ms 节拍(保护判据元件 + 采样故障闭锁,B5) | diff --git a/docs/UI设计/UI_设计架构.md b/docs/UI设计/UI_设计架构.md index 7b82ffbc..2d5e4f8a 100644 --- a/docs/UI设计/UI_设计架构.md +++ b/docs/UI设计/UI_设计架构.md @@ -39,7 +39,7 @@ MCU **无物理屏幕**:LVGL 做 160×160 **1bpp 单色离屏渲染**,帧缓 | 刷新周期 | 10 ms(`ui_port_step(10)` + `osDelay(10)`) | `ui_task.c` | | 推流端口 | 7003(TCP,与 DTU-RemoteLCD 客户端对齐) | `ui_net_sink.h` | | 默认字体 | `ui_font_cn_12`(12px 1bpp,224 汉字/符号 + ASCII 0x20–0x7E,共 319 字形) | `Lib/lv_conf.h` | -| uiTask 栈 | 16384 words(BelowNormal) | `Src/freertos.c` | +| uiTask 栈 | 4096 words = 16384 B(BelowNormal) | `Src/freertos.c:218`(`.stack_size = 4096 * 4`) | ### 1.4 硬约束(改 UI 必须遵守) diff --git a/docs/images/就绪屏障.svg b/docs/images/就绪屏障.svg index 76bcb271..3ed519a4 100644 --- a/docs/images/就绪屏障.svg +++ b/docs/images/就绪屏障.svg @@ -33,7 +33,7 @@ 3 bit3 · TIMESYNC_READY -预留(尚未接入调度) +预留(无生产者置位) defaultTask 卷挂载 + net_cfg_load(f_mount) diff --git a/docs/images/项目架构总览.svg b/docs/images/项目架构总览.svg index 002d4d7a..20515794 100644 --- a/docs/images/项目架构总览.svg +++ b/docs/images/项目架构总览.svg @@ -67,7 +67,7 @@ nand_ftl(dhara FTL) -LVGL v9.2(图形库) +LVGL v9.3(图形库) sys_clock(墙钟基准) diff --git a/docs/代码规范/pre-commit使用说明.md b/docs/代码规范/pre-commit使用说明.md index cb6f7c10..10c44941 100644 --- a/docs/代码规范/pre-commit使用说明.md +++ b/docs/代码规范/pre-commit使用说明.md @@ -32,7 +32,7 @@ git commit └─ manual(pre-commit --hook-stage manual;不随 git commit 跑) ├─ cppcheck 全量 C 静态分析(自有代码) ├─ test-cppcheck test/ 侧静态分析 - └─ test-coverage 主机单测覆盖率总闸(44 套 + 回退台账) + └─ test-coverage 主机单测覆盖率总闸(47 套 + 回退台账) ``` **阶段**:`pre-commit` 阶段拦截代码问题、`commit-msg` 阶段拦截格式问题,任一失败 → commit 中止;另有 `manual` 阶段(`stages: [manual]` 的慢钩子)**不随 `git commit` 跑**,由远端 CI 与 `scripts/ci_local.py` 的 manual 段承担(见下)。一次 `git commit` 实跑 **48** 根 = `pre-commit` 阶段 47 根 + `gitlint` 1 根。 diff --git a/docs/任务规划/数据可信.md b/docs/任务规划/数据可信.md index 5a680ad8..185f9373 100644 --- a/docs/任务规划/数据可信.md +++ b/docs/任务规划/数据可信.md @@ -237,7 +237,7 @@ M4 的六条退出判据(逐条对齐现状,别整格打勾): 保护判据拿"ADC 引脚电压"跟"二次值定值"比必然误动作,所以 `protect_task` 多一个闭锁源: **UA / UN / IA 的 `VALID` 未全置位 → 判据停走**(实现已搬进 `App/algo/adc_cal.c` 的 -`adc_cal_prot_blocked()`,`App/task/protect_task.c:245` 消费并打 INFO + 记 SOE)。 +`adc_cal_prot_blocked()`,`App/task/protect_task.c:268-273` 消费并打 INFO + 记 SOE)。 - 与"自检失败 / 采样故障闭锁"同构(`PROT_HF_LOCK_MASK` 那一套),**不新增机制**。 - 现有台架 `/serial-boot-test` 的期望会因此变化——**这是有意的**,任务卡里同步更新判据。 diff --git a/docs/架构设计/项目架构总览.md b/docs/架构设计/项目架构总览.md index e394cca0..b1ae8fae 100644 --- a/docs/架构设计/项目架构总览.md +++ b/docs/架构设计/项目架构总览.md @@ -24,7 +24,7 @@ | ① 业务层 | `Drivers/BSP/NETCFG/` | 顶层共享配置(被 UI 与基础服务共用) | `net_cfg`(`/config.ini` `[network]` 段) | | ② UI 层 | `Drivers/BSP/UI/` | LVGL 160×160 单色界面(与 PC 模拟器、屏板、远程显示**共用同一份显存**) | `ui_port` `ui_menu` `ui_menu_view` `ui_menu_tab`(生成物) `ui_content_page` `ui_page_registry`(生成物) `ui_page_*`(20+ 页插件) `ui_data`(数据供给发布 API) `ui_net_sink` `ui_standby` `ui_font_cn_12` `ui_deco` | | ③ 基础服务层 | `App/`、`Drivers/BSP/NET/lftpd/` | 应用侧服务与编排 | `app_main` `sys_events` `ui_data_feed` `task/*`(9 任务) `algo/*`(语义取数与有效性~保护判据 + 遥测快照 + 录波数据面 + 屏板灯位映射) `protocol/iec104` `sys_log`·`soe_*`·`console_log` `cfg_file`·`prot_set_store` `vol_lock` `time_sync` `lftpd` | -| ④ 中间件层 | `Drivers/BSP/NET/`、`Lib/`、`App/util/` | 通用库 / 协议栈 | `net_socket` `net_select` `net_events` `net_listener` `net_pending` `FatFs` `nand_ftl(dhara)` `LVGL v9.2` `sys_clock` `task_watchdog` | +| ④ 中间件层 | `Drivers/BSP/NET/`、`Lib/`、`App/util/` | 通用库 / 协议栈 | `net_socket` `net_select` `net_events` `net_listener` `net_pending` `FatFs` `nand_ftl(dhara)` `LVGL v9.3` `sys_clock` `task_watchdog` | | ⑤ 驱动层 | `Drivers/BSP/{CH395F,GD5F2GQ5UE,TPAFE5160,SD2506,RS485,ScreenLink}/` | 芯片寄存器 / 时序 / 中断 | `ch395f` `gd5f2gq5ue` `tpafe5160` `sd2506` `rs485` `sb_link`·`sb_proto` | | ⑥ 内核 / HAL | `Middlewares/`、`Drivers/STM32F4xx_HAL_Driver/`、`Drivers/CMSIS/` | 任务调度、外设 HAL、启动 | FreeRTOS V10.3.1 · STM32 HAL · CMSIS | | ⑦ 硬件 | — | STM32F407ZGTx @168MHz | SPI1 / SPI2 / I2C1 / UART4 / UART5 / USART1 / ADC1 / TIM3 / DMA / GPIO | @@ -59,7 +59,7 @@ | 任务 | 栈 (字节) | 优先级 | 职责 | 入口 | |---|---|---|---|---| -| `defaultTask` | 5120 | Normal | FatFS 挂载(无卷 `f_mkfs`)→ 卷健康探针/自愈 → `net_cfg_load`(配置引擎属主)→ 置 `STORAGE_READY`(= 存储+配置就绪)→ **`/log` 唯一写者**(`syslog_drain` 尾部统一排空 syslog / SOE 两条队列 → run/selftest/soe 三本日志 + 控制台排空)+ **录波落盘道**(已封存段游标分次搬 `/wave`,轮转号启动扫盘重建)+ 配置保存执行/2s poll + LED 闪烁 + **栈水位观测**(`stack_probe_poll`) | `StartDefaultTask` | +| `defaultTask` | 5120 | Normal | FatFS 挂载(无卷 `f_mkfs`)→ 卷健康探针/自愈 → `net_cfg_load`(配置引擎属主)→ 置 `STORAGE_READY`(= 存储+配置就绪)→ **`/log` 唯一写者**(`syslog_drain` 尾部统一排空 syslog / SOE 两条队列 → syslog 七本 + `soe.log` + 控制台排空)+ **录波落盘道**(已封存段游标分次搬 `/wave`,轮转号启动扫盘重建)+ 配置保存执行/2s poll + LED 闪烁 + **栈水位观测**(`stack_probe_poll`) | `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 栈(2026-10-04) | `start_test_task` | @@ -189,7 +189,7 @@ flowchart LR ``` - **配置文件**:通用 `/config.ini`(cfg_file 引擎,静态态单任务收敛于 defaultTask,外部变更 4s 沉降后自动重载),**多段注册制**:`[network]`(net_cfg)/ `[ftp]`(鉴权)/ `[adc_cal]`(标定系数与零点)/ `[run_par]`(运行参数 + 104 地址映射真源)/ `[comm]`(104 ca/端口);新模块加段=注册 `cfg_file` 段处理器,唯一落盘者不变。旧版 NCFG 二进制(`/cfg/netcfg.bin`)已不再读取(2026-10-10 删迁移),存在则忽略。→ `docs/子系统设计/配置文件设计说明.md` -- **记录三本**:`sys_log` 引擎写定长 64B 文本记录到 `/log/run.log` 与 `/log/selftest.log`;`soe_store` 同先例落 `/log/soe.log`(64B 定长二进制,容量满删除重建)。defaultTask 是 `/log` 唯一写者(两条队列在 `syslog_drain` 尾部统一排空),FTP 可直下。→ `docs/子系统设计/运行与自检记录设计说明.md` +- **记录九件**:`sys_log` 引擎按 `App/log/sys_log_mcu.c` 的 `s_paths[]` 写**七本**定长 64B 文本记录——`/log/run.log`、`selftest.log`、`accid.log`、`alarm.log`、`start.log`、`oper.log`、`yk.log`;`soe_store` 同先例落 `/log/soe.log`(64B 定长二进制,容量满删除重建);`/log/wdev.log` 是**变长取证行**(掉电不丢,`App/fs/vol_lock` 侧投,不走 64B 定长格式)。defaultTask 是 `/log` 唯一写者(两条队列在 `syslog_drain` 尾部统一排空),FTP 可直下。→ `docs/子系统设计/运行与自检记录设计说明.md` - **录波段文件**:`/wave`(首 boot `mkdir`,8.3 短名 WAVE 前缀轮转、启动扫盘重建下标),段头 + 通道表 + 两处 CRC-16/MODBUS + 整段自检;defaultTask 游标**分次搬运**(每次 64B 批)不独占 FatFs,落盘成功回执才解冻录波环。→ `docs/子系统设计/故障录波设计说明.md` - **实时调试流** = 控制台单写者日志(**UART5**/RS232#1,4KB 环形缓冲 + defaultTask 唯一发送;2026-10-29 因屏板占用 USART1 自 UART5 定态),详见 `docs/子系统设计/控制台单写者日志设计说明.md`。 - NAND 坏块表(BBT)持久化在保留块池,不交给 dhara 管理。 @@ -327,14 +327,15 @@ STM32F4-Base/ │ ├── UI/ LVGL UI(与模拟器共用):ui_port / ui_menu* / ui_content_page / ui_page_*(20+ 页)/ │ │ ui_page_registry(生成)/ ui_data / ui_net_sink / ui_standby / ui_font_cn_12 / ui_pwd_def.h │ └── dbg_log.h/dbg_cfg.h/app_assert.h/bsp_err.h 分级日志与 BSP 契约 -├── Lib/ 第三方:LVGL v9.2、FatFs、dhara + lv_conf.h(MCU 端) +├── Lib/ 第三方:LVGL v9.3、FatFs、dhara + lv_conf.h(MCU 端) ├── Middlewares/ FreeRTOS V10.3.1(ST 官方中间件) ├── Drivers/STM32F4xx_HAL_Driver/ + Drivers/CMSIS/ ST HAL / CMSIS(裁剪版) ├── MDK-ARM/ Keil 工程(uvprojx + scatter + build/download 脚本) ├── simulator/ PC 模拟器(CMake + SDL2,共用 UI 源码 + tests/ref 像素黄金参考回归) ├── test/ 测试套件(test_config.h 互斥选择,产品构建空转) -│ ├── board/ 板端套件(.c/.h:CH395F / 存储 / RTC / ADC / RS485 / UI) -│ └── host/ 主机侧单测与脚本(44 套带 run_unit_test.py,覆盖率总闸全量真跑) +│ ├── board/ 板端套件:CH395F(硬件层 + NET 层 Phase 6~11 + 链路时延探针)/ GD5F / +│ │ 存储性能 / SD2506 RTC(逐文件清单 = `test/board/README.md`;无 ADC / RS485 / UI 板端套件) +│ └── host/ 主机侧单测与脚本(47 套带 run_unit_test.py,覆盖率总闸全量真跑) ├── ui_menu_tree.txt 菜单树声明源(生成器输入,仓根) ├── ui_cn_chars.txt 中文字库输入(生成器输入,仓根) ├── tools/ font_gen / menu_gen / arch_diagram(文档配图生成器)/ refgraph(引用图)/ @@ -383,7 +384,7 @@ flowchart LR | ADC 通道映射(网名/板级/通道号 13 路置换) | `docs/硬件平台/ADC通道映射说明.md` | | 故障录波(数据面/段格式/回放契约) | `docs/子系统设计/故障录波设计说明.md` | | 屏板链路(USART1 主出口 / 帧 A 帧 B / 实测证据) | `docs/子系统设计/屏板链路设计说明.md` | -| IEC 60870-5-104 上行(:2404) | `docs/子系统设计/IEC104上行设计说明.md` | +| IEC 60870-5-104 上行(默认 :2404,可经 `[comm]` 改) | `docs/子系统设计/IEC104上行设计说明.md` | | 配置文件引擎(/config.ini 多段注册制) | `docs/子系统设计/配置文件设计说明.md` | | 运行与自检记录(64B 记录 + SOE) | `docs/子系统设计/运行与自检记录设计说明.md` | | 墙钟时间维护 | `docs/子系统设计/系统墙钟时间维护说明.md` | diff --git a/docs/测试说明/单元测试/主机单测覆盖率口径.md b/docs/测试说明/单元测试/主机单测覆盖率口径.md index 9d94ed28..4df79f4e 100644 --- a/docs/测试说明/单元测试/主机单测覆盖率口径.md +++ b/docs/测试说明/单元测试/主机单测覆盖率口径.md @@ -56,7 +56,7 @@ ## 3. 怎么跑 ```powershell -# 全量:44 套单测逐套"编译(带 PDB)→ 插桩运行 → 解析 Cobertura",最后并集 + 比基线 +# 全量:47 套单测逐套"编译(带 PDB)→ 插桩运行 → 解析 Cobertura",最后并集 + 比基线 & '.venv\Scripts\python.exe' scripts/check_test_coverage.py # 只跑一套(调试用;子集会跳过"在测文件消失"类回退判定,见 §5) @@ -78,7 +78,7 @@ 编译失败、XML 缺失)/ `3` 用法错误。全量实测约 **67 s**(33 套 × 编译 + 插桩运行; 2026-10-25 实测;16 套时约 25 s、28 套时约 45 s,套件数涨了耗时就涨,别拿旧数当预算)。最新一次实测: 2026-10-28 = 41 套 **~105 s**(该钩子同日移入 `stages: [manual]`,由远端 CI 与 `ci_local.py` 的 manual 段强制); -套件数现值 **44 套**(2026-10-29 实测,台账见 `docs/门禁说明/host-unit-tests.md` §6 第 4 条),**44 套这一轮的总闸耗时未重测**, +套件数现值 **47 套**(2026-10-30 实测,台账见 `docs/门禁说明/host-unit-tests.md` §6 第 4 条),**47 套这一轮的总闸耗时未重测**, 上面那三个耗时都是当时值,别当现值预算。 套件数的现值与逐个来历见 `docs/门禁说明/host-unit-tests.md` §6 第 4 条。 @@ -156,7 +156,7 @@ 宁可红,也不给可疑的数字。 6. **只覆盖跑到的进程树。** 一次 `collect` 只看一次运行;没跑到的套件不进分母 (全量跑时以"模块未跑到"判 REGRESS),子集运行明确降级(§5)。 -7. **头文件里的代码归 `.h`。** 统计面含 `.h`(静态内联与被展开的行落在头文件上);当前 44 套 +7. **头文件里的代码归 `.h`。** 统计面含 `.h`(静态内联与被展开的行落在头文件上);当前 47 套 几乎没触及 `.h`,表里看不到它们——不要以为头文件"天生 100%"。 8. **依赖 `Microsoft.CodeCoverage.Console.exe`。** 探测顺序:`DTU_MS_COVERAGE`(设了就必须 有效、**不静默回退**)→ 各 VS 安装根的 `Common7\IDE\Extensions\Microsoft\CodeCoverage.Console` → diff --git a/docs/硬件平台/ADC通道映射说明.md b/docs/硬件平台/ADC通道映射说明.md index 2db873b9..6e85a8a7 100644 --- a/docs/硬件平台/ADC通道映射说明.md +++ b/docs/硬件平台/ADC通道映射说明.md @@ -21,11 +21,11 @@ | **温度** | V_ZL2 | 温度 | 温度检测模拟采样 | | 备用 | AIN5 / AIN6 / AIN7 / AIN12 / AIN13 / AIN14 / AIN15 / V_ZL1 | — | **未使用**(悬空或不用),软件侧一律标 `RESERVED`,不参与采集与上报 | -**设计口径(重要,2026-10-10 更正)**:本产品的**电能计量在子板(计量模块)完成**,主板 ADC 只做**监视 / 辅助测量**。但**"8 路电气量被分到两片转换器上"(UA/UN/IA 走 TPAFE5160,UB/UC/IB/IC/IN 走 STM32 12 位 ADC)是 V0.1 的硬件缺陷**——建档时(2026-10-09)写的"有意分配、不要按'8 路电气量应全部走 TPAFE'去修正"**说法作废**:该分配**就是需要修正的对象**,已列入下一版硬件(V0.2)改版项(登记簿 **N-18**)。 +**设计口径(重要,2026-10-10 更正)**:本产品的**电能计量在子板(计量模块)完成**,主板 ADC 只做**监视 / 辅助测量**。但**"8 路电气量被分到两片转换器上"(UA/UN/IA 走 TPAFE5160,UB/UC/IB/IC/IN 走 STM32 12 位 ADC)是 V0.1 的硬件缺陷**——建档时(2026-10-09)写的"有意分配、不要按'8 路电气量应全部走 TPAFE'去修正"**说法作废**:该分配**就是需要修正的对象**,已列入下一版硬件(V0.2)改版项(登记簿条目「双转换器无共同采样触发」)。 **缺陷实质(为什么必须改)**: -1. **跨转换器通道没有同一时刻性**:TPAFE5160 是 8 通道**同步**采样,STM32 ADC 是**顺序**扫描(9 通道一轮 ≈ 67 µs),且两片转换器**没有共同采样触发**(CONVST 只打 TPAFE,ADC1 为软件触发)。于是 UA↔UB、IA↔IB 这类同族量之间**相位关系不确定**,主板侧任何功率 / 功率因数 / 相角 / 对称分量类运算都不成立。 +1. **跨转换器通道没有同一时刻性**:TPAFE5160 是 8 通道**同步**采样,STM32 ADC 是**顺序**扫描(9 通道一轮 ≈ 67 µs),且两片转换器**没有共同采样触发**(CONVST 只打 TPAFE;ADC1 由 TIM3 TRGO 触发——见 §7 与 `Src/adc.c:53`,但 TIM3 与 TPAFE 的 CONVST 之间没有硬件耦合,仍不构成「共同采样触发」)。于是 UA↔UB、IA↔IB 这类同族量之间**相位关系不确定**,主板侧任何功率 / 功率因数 / 相角 / 对称分量类运算都不成立。 2. **精度与量程不一致**:TPAFE 16 位 ±5 V **双极性**(LSB ≈ 152.6 µV,满量程 = 10 V 跨度,口径见 §7.1)vs STM32 12 位 0~3.3 V **单极性**(前端无中点偏置,交流量负半周削顶;LSB ≈ 806 µV)。同为相电压,UA 与 UB/UC 满量程码值差 16 倍、可用象限也不同——同一套算法无法统一处理 8 路电气量。 3. **语义与硬件归属交叉**:UA 在 TPAFE、UB 在 STM32,固件映射表 / UI 通道序 / 自检注入都必须逐通道查表绕开这个交叉(本文件 §4、§5 两张表的存在本身就是代价)。 @@ -128,11 +128,11 @@ STM32(U17)为 LQFP144 脚号。 | 项 | 现状 | 影响 | |---|---|---| -| **通道归属(硬件缺陷)** | 8 路电气量分属两片转换器:UA/UN/IA → TPAFE,UB/UC/IB/IC/IN → STM32 ADC | **V0.1 硬件缺陷**(非有意分配,理由见 §1)→ V0.1 上禁止跨转换器做相位/功率/功率因数/矢量类运算;**V0.2 改版要求 8 路电气量全部走 TPAFE**(登记簿 N-18) | +| **通道归属(硬件缺陷)** | 8 路电气量分属两片转换器:UA/UN/IA → TPAFE,UB/UC/IB/IC/IN → STM32 ADC | **V0.1 硬件缺陷**(非有意分配,理由见 §1)→ V0.1 上禁止跨转换器做相位/功率/功率因数/矢量类运算;**V0.2 改版要求 8 路电气量全部走 TPAFE**(登记簿条目「双转换器无共同采样触发」) | | STM32 ADC 外设 | **已生成(2026-10-09,CubeMX 6.17 + FW_F4)**:`Src/adc.c`/`Inc/adc.h` 已入库并挂进 `MDK-ARM/*.uvprojx`;`Inc/stm32f4xx_hal_conf.h` 的 `HAL_ADC_MODULE_ENABLED` 已生效;HAL `stm32f4xx_hal_adc.c/_ex.c` + `stm32f4xx_ll_adc.h` 已补入仓库(HAL 原本是裁剪子集);`Src/main.c` 里 `MX_ADC1_Init()` 排在 `MX_IWDG_Init()` 之后。生成配置核对无误:9 通道 / Rank 1~9 / 全部 144 cycles / `ScanConvMode=ENABLE` / `ContinuousConvMode=DISABLE` / `ExternalTrigConv=ADC_SOFTWARE_START` + `EDGE_NONE` / `EOCSelection=ADC_EOC_SINGLE_CONV` / `DataAlign=RIGHT` / 12 位;`HAL_ADC_MspInit()` 已把 PA0~PA7+PC4 配成 `GPIO_MODE_ANALOG` | 硬件通路已打通(`hadc1` 可用);**消费者已落地**——`App/algo/adc_input.c` 的 `stm32_take()`(「STM32 ADC1 启动与扫描」,v2.0,2026-10-10):ADC1 由 **TIM3 TRGO 硬件触发**一轮 9 通道 + **DMA2_Stream4 循环搬运**进乒乓双缓冲,任务侧只消费刚完成的半区(零忙等),9 通道一轮 ≈ 67 µs | | ADC1 上电自校准 | **已补(2026-10-10)**:`Src/adc.c` 的 `USER CODE BEGIN ADC1_Init 2` 调用 `adc1_calibrate()`(实现同文件 `USER CODE BEGIN 1`,按 RM0090 §13.3.6:清 ADON→等生效→置 ADON→置 CAL→等 CAL 由硬件清零)。⚠ **CubeMX 不生成这一步**,且本仓库裁剪版 HAL **没有** `HAL_ADCEx_Calibration_Start`、裁剪版 CMSIS 头**没有** `ADC_CR2_CAL`(bit3,代码里按 RM 自建 `ADC1_CAL_BIT`)→ 属 USER CODE 区手工定制,审计项 `adc1-calibration-call` / `adc1-calibration-impl` 兜底 | 实测有效:校准前后同一拍 STM32 侧 6 路**同向**变化 `UB 898→961`、`UC 978→1038`、`IB 906→922`、`IC 1061→1071`、`IN 1017→1055`、`T 790→846`(+10~+63 LSB ≈ 0.2~1.5 % FS);TPAFE 侧 `UA/UN/IA` 一字不变 → 变化确来自 ADC1 校准。缺这一步不报错,只是**读数带失调** | | ADC 时钟 | CubeMX 的 F4 ADC 面板**有** Clock Prescaler 一项(此前"面板没有该项、固定 DIV2"的判断有误),已选 **PCLK2/4 → ADCCLK = 21 MHz** ✓。面板里 **DIV2 是灰的、选不到**:DB 里 `FadcConstraint Max=36000000`,APB2 = 84 MHz → DIV2 = 42 MHz 超限,该候选值被 `Action="DISABLE"` 禁掉,超规值进不来 | **不设额外防护(2026-10-09 决定)**:约束已由 CubeMX 把关;`.ioc` 虽不保存 `ADC1.ClockPrescaler` 键,重生成也只会回落到约束允许的值。按 144+12 cycles 算 ≈ 7.4 µs/通道、9 通道一轮 ≈ 67 µs | -| `adc_task` | **已实现(B1,2026-10-10;语义取数与有效性层 v2.3;P1-5 事件驱动消费,2026-10-10)**:`App/task/adc_task.c` 每拍调 `adc_input_poll()`(`App/algo/adc_input.c`)= TPAFE `tpafe5160_snapshot()` 原子快照(8 通道)+ 消费一帧 STM32 ADC1 DMA 乒乓缓冲,**经 `adc_input_raw()` 按语义取数**(不再直接索引驱动缓冲);**消费唤醒由 TIM3 ISR 置位 `ADC_WAKE_FLAG`**(不再 1 ms 轮询);任务在 `Src/freertos.c` 的 `USER CODE` 区创建为 `adcTask`(512 words / **AboveNormal**) | 数据路径已通(台架 `/serial-boot-test`:`frames` 严格 1000 Hz 递增、**`idle=0`**、`adc1_rc=0` / `adc1_err=0`) | +| `adc_task` | **已实现(B1,2026-10-10;语义取数与有效性层 v2.3;P1-5 事件驱动消费,2026-10-10)**:`App/task/adc_task.c` 每拍调 `adc_input_poll()`(`App/algo/adc_input.c`)= TPAFE `tpafe5160_snapshot()` 原子快照(8 通道)+ 消费一帧 STM32 ADC1 DMA 乒乓缓冲,**经 `adc_input_raw()` 按语义取数**(不再直接索引驱动缓冲);**消费唤醒由 TIM3 ISR 置位 `ADC_WAKE_FLAG`**(不再 1 ms 轮询);任务在 `Src/freertos.c` 的 `USER CODE` 区创建为 `adcTask`(640 words / **AboveNormal**,`Src/freertos.c:159 .stack_size = 640 * 4`) | 数据路径已通(台架 `/serial-boot-test`:`frames` 严格 1000 Hz 递增、**`idle=0`**、`adc1_rc=0` / `adc1_err=0`) | | TPAFE 采样触发 | **周期 CONVST 已实现(2026-10-10)**:`Src/main.c` 的 `HAL_TIM_PeriodElapsedCallback` 在 **TIM3 更新事件(1 kHz)** 内调 `tpafe5160_start_conv_irq()`;`app_main_init()` 用 `HAL_TIM_Base_Start_IT(&htim3)` 启动节拍(在 `tpafe5160_init()` 之后)。同一 TIM3 更新事件还经 **TRGO** 硬件触发 ADC1 一轮 9 通道(DMA 搬运),并调 `adc_tick_irq_notify()` **唤醒消费者**(P1-5 方案 a,2026-10-10;内含"消费者就绪"门)→ 两片转换器由同一硬件事件同源对齐 | 连续波形(1 kHz);详见 `docs/子系统设计/ADC采样节拍设计说明.md` §4(DMA 乒乓搬运)与 §6(事件驱动唤醒) | | 前端偏置 | 每路 1k 串联 + 滤波 C 跨接差分输入;差分负端(`*_GND` 网)经 1k 拴 AGND。**不是对地分压**(2026-10-27 网表追线定死,拓扑图见 §7.1),**无中点偏置** | TPAFE 输入阻抗 **1 MΩ 恒定**(`../芯片手册/TPAFE5160.md` "Analog Input Impedance" 节),故端子对 AGND 的直流通路 = 1k + 1 MΩ + 1k ≈ **1.002 MΩ**,不是 1 kΩ。两侧各 1 kΩ 是手册要求的**源阻抗匹配**(AIN_nP / AIN_nGND 外接源阻抗相等以抵消失调),**不是分压**。STM32 侧只能测 **0~3.3 V 单极性**,交流量负半周被削顶;主板侧只做监视可接受,若要算 RMS/功率需硬件补偏置或明确算法口径 | | TPAFE 量程(**2026-10-25 量程口径冻结定死**) | 板上 RANGE 接 GND → **±5 V 双极性量程**(芯片手册输入量程表:RANGE = 0 → −5 ~ +5 V),16 位二进制补码,**±5 V 满量程 = 10 V 跨度**,LSB = 10 V / 65536 ≈ **152.59 µV/码(@ 转换器引脚)**。“±10 V” 是芯片的另一可选档(RANGE = HIGH,跨度 20 V、LSB ≈ 305.18 µV),**本板未用**——历史版本曾把本板误标为“±10 V 双极性”,与 §7 本行矛盾、且会让 TPAFE 侧系数差一倍,更正记录见 §9 | 用 `tpafe5160_to_voltage()` 换算;端到端口径见 §7.1 | diff --git a/docs/硬件平台/V0.1_网表详细分析报告.md b/docs/硬件平台/V0.1_网表详细分析报告.md index 9df07668..7488ceaf 100644 --- a/docs/硬件平台/V0.1_网表详细分析报告.md +++ b/docs/硬件平台/V0.1_网表详细分析报告.md @@ -63,7 +63,7 @@ | V7 | **VCAP1/VCAP2(U17.71/106)旁路电容 C94/C79 值未标注**:数据手册要求 VCAP1/VCAP2 各接 1~4.7µF 低 ESR 陶瓷电容至 VSS(内部 1.2V LDO 稳定裕量) | 实测 C94/C79 容值(若为 100nF 则低于手册建议,168MHz 满负荷下 1.2V 轨纹量/稳定性需留意);值补录 BOM | | V8 | **V15/J3/F3 子板 LED 3 线落在 PC13/PC14/PC15**(脚 7/8/9):备份域电源开关供电,手册 Note 3 限**灌流 ≤3mA、≤2MHz、不可作电流源** | 核子板 LED 驱动电流需求;超 3mA 则 V0.2 移足驱力脚或子板加三极管扩展 | | V9 | **V0.1 主板 SDIO 固定引脚组全被占用**:PC6/PC7/PC8/PC9/PA8(TPAFE 控制)+ PA9(USART1)+ PC10/PC11/PC12/PD2(UART4/UART5)= SDIO 全部 10 脚(F407 SDIO 无重映射) | 架构约束备案:V0.1 主板**无 SDIO 能力**;当前设计不受影响(代码未启用 SDIO,FatFs 卷在 SPI NAND 上) | -| **V10** | **8 路电气量分属两片转换器(V0.1 硬件缺陷,V0.2 改版项)**:UA/UN/IA 走 TPAFE5160(16 位、同步、±5 V 双极性),UB/UC/IB/IC/IN 走 STM32 ADC(12 位、顺序扫描、0~3.3 V 单极性)→ 跨转换器通道**无同一时刻性**(相位关系不确定)、精度与量程不一致。详见 §6-3 与 [`ADC通道映射说明.md`](ADC通道映射说明.md) §1(2026-10-10 定性更正,登记簿 **N-18**) | **V0.2 改版**:8 路电气量 UA/UB/UC/UN/IA/IB/IC/IN **全部接 TPAFE5160**,与 TPAFE 上 5 路备用路(AIN5/13/7/15/12)对调串联电阻在转换器一侧的目的地——元件数量与料号不变,属走线级改动。V0.1 现板:主板侧只做逐通道监视,**不做**跨转换器的相位/功率/功率因数/矢量运算 | +| **V10** | **8 路电气量分属两片转换器(V0.1 硬件缺陷,V0.2 改版项)**:UA/UN/IA 走 TPAFE5160(16 位、同步、±5 V 双极性),UB/UC/IB/IC/IN 走 STM32 ADC(12 位、顺序扫描、0~3.3 V 单极性)→ 跨转换器通道**无同一时刻性**(相位关系不确定)、精度与量程不一致。详见 §6-3 与 [`ADC通道映射说明.md`](ADC通道映射说明.md) §1(2026-10-10 定性更正,登记簿条目「双转换器无共同采样触发」) | **V0.2 改版**:8 路电气量 UA/UB/UC/UN/IA/IB/IC/IN **全部接 TPAFE5160**,与 TPAFE 上 5 路备用路(AIN5/13/7/15/12)对调串联电阻在转换器一侧的目的地——元件数量与料号不变,属走线级改动。V0.1 现板:主板侧只做逐通道监视,**不做**跨转换器的相位/功率/功率因数/矢量运算 | ## 2. 元件级变化 @@ -214,7 +214,7 @@ V0.0 §2.2/§4.7 的 6 路 MCU 控制 LED(实板位号 LED5~LED10,阴极经 1. **TPAFE 8 路 ↔ STM32 ADC 9 路的"归属"也变了**:V0.1 中 TPAFE(U3)采 U5 的 B6/A6/B5/A5/B4/A4/A3/B3,STM32 ADC 采 C13/C9/C10/C14/C12/C11/A8/B7——两族通道数(8+9)不变,成员重分。 2. 网名 AINn 与 ADCn 编号**不再一一对应**(如 AIN1→ADC7),任何按"AINn=ADCn"假设的代码/文档/测试都会静默采错通道——这正是 V0.0 §1.6 警示的"静默死亡"型风险,务必以本表建立映射。 -3. 置换疑似按 U5 连接器物理位置重排走线(TPAFE 8 路恰为 B6→B3 降序)。**2026-10-10 更正**:置换本身(AINn↔ADCn 编号打乱)可视为走线安排,但**"8 路电气量分到 TPAFE 与 STM32 两侧"属 V0.1 硬件缺陷**——2026-10-09 曾按"计量在子板、主板只做监视"把它确认为"有意设计",该定性**作废**。缺陷实质:TPAFE 8 通道同步采样、STM32 ADC 顺序扫描且两者无共同采样触发 → 跨转换器通道**无同一时刻性 / 相位关系不确定**;16 位 ±5 V 双极性 vs 12 位 0~3.3 V 单极性 → 同族量精度与量程不一致。**下一版硬件(V0.2)需把 8 路电气量 UA/UB/UC/UN/IA/IB/IC/IN 全部改接 TPAFE5160**(与 TPAFE 上 5 路备用路对调串联电阻目的地,BOM 不变),登记簿 **N-18**。语义分配(UA/UB/UC/UN、IA/IB/IC/IN、V_ZL2=温度检测,其余 8 路备用)与 17 路端到端映射已固化为 [`docs/硬件平台/ADC通道映射说明.md`](ADC通道映射说明.md)(缺陷实质与改版要求见其 §1);固件通道映射表、UI 通道显示、自检逐通道注入验证(V0.0 §5.1-6)按该表执行。 +3. 置换疑似按 U5 连接器物理位置重排走线(TPAFE 8 路恰为 B6→B3 降序)。**2026-10-10 更正**:置换本身(AINn↔ADCn 编号打乱)可视为走线安排,但**"8 路电气量分到 TPAFE 与 STM32 两侧"属 V0.1 硬件缺陷**——2026-10-09 曾按"计量在子板、主板只做监视"把它确认为"有意设计",该定性**作废**。缺陷实质:TPAFE 8 通道同步采样、STM32 ADC 顺序扫描且两者无共同采样触发 → 跨转换器通道**无同一时刻性 / 相位关系不确定**;16 位 ±5 V 双极性 vs 12 位 0~3.3 V 单极性 → 同族量精度与量程不一致。**下一版硬件(V0.2)需把 8 路电气量 UA/UB/UC/UN/IA/IB/IC/IN 全部改接 TPAFE5160**(与 TPAFE 上 5 路备用路对调串联电阻目的地,BOM 不变),登记簿条目「双转换器无共同采样触发」。语义分配(UA/UB/UC/UN、IA/IB/IC/IN、V_ZL2=温度检测,其余 8 路备用)与 17 路端到端映射已固化为 [`docs/硬件平台/ADC通道映射说明.md`](ADC通道映射说明.md)(缺陷实质与改版要求见其 §1);固件通道映射表、UI 通道显示、自检逐通道注入验证(V0.0 §5.1-6)按该表执行。 ## 7. 电源/地网络成员变化(拓扑不变) diff --git a/docs/门禁说明/README.md b/docs/门禁说明/README.md index 5dd6fcd3..227c9da6 100644 --- a/docs/门禁说明/README.md +++ b/docs/门禁说明/README.md @@ -85,7 +85,7 @@ | [`setview-check.md`](setview-check.md) | `setview-check` | 定值查看行表与 `prot_set` 枚举序 / `g_prot_set_meta` 上下限是否同一份口径 | `tools/setview_check/**`、`ui_w_setview.*` | 已写 | | (专篇待补,档位与限度正文在 [`../UI设计/UI_自动化测试流程.md`](../UI设计/UI_自动化测试流程.md) §7.3) | `uinav-selftest` | 板端 UI 导航器认屏快检(黄金参考帧分类;完整闭环档=合入前/上板前手工跑,快检不互替) | `scripts/board_ui_nav.py`、`simulator/tests/ref/*.bin` | 指针 | | [`host-unit-tests.md`](host-unit-tests.md) | 22 个 `*-unit-test` | 主机侧单测(同一机制 22 个实例):逻辑层在无硬件的 PC 上编译并跑断言 | 各自被测模块与其测试目录 | 已写 | -| 详解在 [`../测试说明/单元测试/主机单测覆盖率口径.md`](../测试说明/单元测试/主机单测覆盖率口径.md)(口径 / 分母 / 基线 / 盲区都在那篇,本目录不重复) | `test-coverage` | **覆盖率总闸**:跑全部 44 套主机单测 + 已覆盖行只增不减的回退台账 | `App/`、`Drivers/BSP/`、`test/host/`、脚本与基线 | 已写(在 `docs/测试说明/`;`stages: [manual]`) | +| 详解在 [`../测试说明/单元测试/主机单测覆盖率口径.md`](../测试说明/单元测试/主机单测覆盖率口径.md)(口径 / 分母 / 基线 / 盲区都在那篇,本目录不重复) | `test-coverage` | **覆盖率总闸**:跑全部 47 套主机单测 + 已覆盖行只增不减的回退台账 | `App/`、`Drivers/BSP/`、`test/host/`、脚本与基线 | 已写(在 `docs/测试说明/`;`stages: [manual]`) | | [`trailing-whitespace.md`](trailing-whitespace.md) | `trailing-whitespace` | 行尾空白(改写型;CubeMX/Keil 生成文件豁免) | 全部 | 已写 | | [`end-of-file-fixer.md`](end-of-file-fixer.md) | `end-of-file-fixer` | 文件末尾必须恰好一个换行(改写型;同豁免) | 全部 | 已写 | | [`check-added-large-files.md`](check-added-large-files.md) | `check-added-large-files` | 别把大文件(日志/镜像/二进制)误提进仓库 | 全部 | 已写 | diff --git a/docs/门禁说明/host-unit-tests.md b/docs/门禁说明/host-unit-tests.md index 6df942de..edd4a164 100644 --- a/docs/门禁说明/host-unit-tests.md +++ b/docs/门禁说明/host-unit-tests.md @@ -91,19 +91,19 @@ 清点(2026-10-28 复点、2026-10-29 录波三套入库后再复点:下列数字已按复点值更新;上一版写「16 个模块有专属钩子、另有 12 套、总闸跑 28 套」——三个数都随 2026-10-25 的 六根新钩子与后续新增套件过期了,正是本目录反复在防的"文档与机器面不同码"): - **22** 根专属钩子 = 有独立 `files:` 触发面、需要**秒级归因**的那个子集; - - `test/host/` 下带 `run_unit_test.py` 的套件实测 **44** 套(46 个目录,除 `common` 与 - `__pycache__`;两个数分别来自 `check_test_coverage.py --list` 与 `ls -d test/host/*/`,2026-10-29 实测) - ⇒ **没有专属钩子的是 22 套**:`boot_stats`、`cfg_file_store_mcu`、`console_log`、 + - `test/host/` 下带 `run_unit_test.py` 的套件实测 **47** 套(48 个目录,除 `common` 与 + `__pycache__`;两个数分别来自 `check_test_coverage.py --list`(47 行)与 `ls -d test/host/*/`(48 个目录),2026-10-30 复点) + ⇒ **没有专属钩子的是 25 套**:`boot_stats`、`cfg_file_store_mcu`、`console_log`、 `ftp_cfg`、`iec104_serv`、`lftpd`、`lftpd_inet`、`lftpd_io`、`net_cfg`、`net_events`、 - `net_listener`、`net_pending`、`net_select`、`net_socket`、`prot_set_store`、`soe_store`、 + `net_listener`、`net_pending`、`net_select`、`net_socket`、`prot_set_store`、`sb_led_map`、`sb_link`、`sb_proto`、`soe_store`、 `sys_log_mcu`、`task_prof`、`ui_sink`、`wave_ring`、`wave_store`、`wave_trig`(末三套 2026-10-29 随 - 故障录波入库,按同一条 Lead 裁定不补专属钩子;22 = 44 套 − 22 根专属钩子,逐点数与两处机器源互证); + 故障录波入库,屏板三套(`sb_proto`/`sb_link` 2026-10-29、`sb_led_map` 2026-10-30)随屏板链路入库,同一条 Lead 裁定不补专属钩子;25 = 47 套 − 22 根专属钩子,逐点数与两处机器源互证); - 这 22 套每次 CI 与 `scripts/ci_local.py` 都由 `test-coverage` **总闸**真跑(该钩子带 `stages: [manual]`: `git commit` 阶段不跑它,这一根与 `cppcheck` / `test-cppcheck` 同属 CI 与 `ci_local.py` 的 manual 段); 发现规则是 `HOST_TEST_DIR.rglob("run_unit_test.py")`(与 `scripts/ci_local.py` 的主机侧纯逻辑单测同一口径), 退出码语义写死「0 = 全部单测通过且覆盖率相对基线没回退 / 1 = 有单测失败或覆盖率回退」⇒ - **失败照样拦(CI 与 `ci_local.py` 的 manual 段)**。差的只是归因粒度(要在总闸输出里认出是哪套)与耗时(44 套全量比单根慢得多); + **失败照样拦(CI 与 `ci_local.py` 的 manual 段)**。差的只是归因粒度(要在总闸输出里认出是哪套)与耗时(47 套全量比单根慢得多); - 要不要给某套补第 23 根,判据现成:pre-commit 4.x 没有 `always: true`,**该模块有没有自己的 `files:` 触发面**决定补了会不会真跑;只为凑数加一根,等于把「快归因面」和「全量把关」两件事混成 一件,还要让钩子计数再改一次; @@ -113,7 +113,7 @@ 实跑数」三处同源同步的计数点——本仓 2026-10-26 到 27 一天之内就为 40 / 50 / 51 这三个数不同源 返工过两轮。**要读「这套跑没跑」,读总闸输出,不要来数钩子。** 两个方向的空头账一起堵住: ① 别把没接线的套件算进钩子账(原写「23 个 / 含 ui-sink」正是这么错的;2026-10-27 复核的准数是 - 22 根 / 40 套 / 18 套无专属钩子(三个数都是当时值)——第 41 套 `boot_stats` 当日 11:29 才入库,此后两数当时是 41 / 19,现值 44 / 22 以本条上面的实测行为准);② 也别把总闸的绿读成「每套都被单独归因过」——它只保证 + 22 根 / 40 套 / 18 套无专属钩子(三个数都是当时值)——第 41 套 `boot_stats` 当日 11:29 才入库,此后两数当时是 41 / 19,现值 47 / 25 以本条上面的实测行为准);② 也别把总闸的绿读成「每套都被单独归因过」——它只保证 「全跑过 + 覆盖率没回退」。将来确实要给某套补专属钩子,先过上一条判据,并在**同一笔**里改 AGENTS 与门禁索引的计数(口径 = YAML 解析条目数,见 `docs/门禁说明/README.md` §2 首条)。 - 总闸的触发面是 `App/`、`Drivers/BSP/`、`test/host/`、覆盖率脚本与基线,**外加门禁自身** diff --git a/scripts/README.md b/scripts/README.md index ef515860..f1794b3d 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -44,7 +44,7 @@ | `ci_local.py` | **本地跑与 CI 等价的门禁**(静态门禁 pre-commit 47 根 + **manual 段**(`cppcheck` / `test-cppcheck` / `test-coverage` 三根逐根 `--hook-stage manual`,默认跑)+ 提交信息门禁 + **体积门禁** + 主机侧纯逻辑单测):自动选用装了 pre-commit 的解释器;无 `.map` 时自适应跳过 `mem-numbers` / `mem-budget`(⚠ 那是 SKIP 不是通过,缺口由体积门禁兜住);退出码 0/1/2 与 CI 对齐。CI 定义见 `../.gitea/workflows/ci.yml`,覆盖边界见 `docs/测试说明/流程与规范/测试开发标准流程.md` §9 | | `check_size_gate.py` | **体积门禁的强制路径**:`.map` 只在本地有,钩子无它时自适应 SKIP,于是"没测=通过"。本脚本用**已提交的同码凭证** `scripts/size_attestation.json` 把这条判据变成无需 Keil 也能跑:`--stamp` 只在"`.map` 存在、比全部受管源码新、且未超 92%"时才盖章(已挂在 `ram_baseline.py --update` 里,无新增人工步骤);`--local` 供 ci_local 的体积门禁步;`--ci` 供 runner(同码性 + 按凭证数字复核红线,主干 push 拦红、其余事件 `--warn-only`);`--show` 排障。**口径与边界的唯一正文在本脚本模块 docstring** | | `size_attestation.json` | (被 `check_size_gate.py` 读写)体积同码凭证:受管源码指纹(`git ls-files` 范围内逐文件 sha256 聚合)+ 测量数字与占比 + `.map` 出处。改固件源码后不重测 → 指纹对不上 → 体积门禁与 CI 同时拦红 | -| `check_test_coverage.py` | 主机单测**覆盖率**(2026-10-23):mscoverage 动态插桩跑 `test/host/**` 全部 44 套,统计自研生产源码行/函数覆盖(并集)+ 与 `test_coverage_baseline.json` 比回退;`--module/--update-baseline/--md/--json/--list`;挂在 `test-coverage` 钩子上(`stages: [manual]`,**`git commit` 不跑**),入口 = 远端 CI「手动阶段门禁」步 / `scripts/ci_local.py` 的 manual 段(`--coverage` 旗标保留只为兼容旧命令;口径见 `docs/测试说明/单元测试/主机单测覆盖率口径.md`) | +| `check_test_coverage.py` | 主机单测**覆盖率**(2026-10-23):mscoverage 动态插桩跑 `test/host/**` 全部 47 套,统计自研生产源码行/函数覆盖(并集)+ 与 `test_coverage_baseline.json` 比回退;`--module/--update-baseline/--md/--json/--list`;挂在 `test-coverage` 钩子上(`stages: [manual]`,**`git commit` 不跑**),入口 = 远端 CI「手动阶段门禁」步 / `scripts/ci_local.py` 的 manual 段(`--coverage` 旗标保留只为兼容旧命令;口径见 `docs/测试说明/单元测试/主机单测覆盖率口径.md`) | | `ci_gitlint_range.ps1` | CI 侧**提交信息门禁**:逐条校验本次 push/PR 引入的提交(`--all-files` 跑不到 `commit-msg` stage,故必须单独守) | | `ci_find_python.ps1` | CI 侧 Python 探测(候选顺序须与 `ci_local.py` 同序同步,否则 CI 与本地判定会分叉) | | `ci_runner_bootstrap.ps1` | **本机 runner 运维脚本**(体检 `-Status` / 干跑 `-DryRun` / 部署 `-SetEnv -StartNow`):装"等 Gitea 就绪 + 崩溃自拉起"的看门狗 + 开机计划任务 + 机器级 `DTU_*` | diff --git a/scripts/gen_task_table.py b/scripts/gen_task_table.py index e2646947..da1ce5e5 100644 --- a/scripts/gen_task_table.py +++ b/scripts/gen_task_table.py @@ -76,7 +76,7 @@ ROLE = { "uiTask": "LVGL UI 界面", "timeSyncTask": "墙钟时间同步", "adcTask": "TPAFE5160 采样(TIM3 1kHz 事件驱动 + 原子快照 + STM32 ADC DMA,纯消费者)", - "iec104Task": "IEC 60870-5-104 上行(:2404 监听,遥信/遥测/定值区)", + "iec104Task": "IEC 60870-5-104 上行(工厂默认 :2404 监听,遥信/遥测/定值区)", "protectTask": "保护判据 20ms 节拍(保护判据元件 + 采样故障闭锁,B5)", } diff --git a/test/host/sys_log_mcu/sys_log_mcu_test.c b/test/host/sys_log_mcu/sys_log_mcu_test.c index 4568d644..5ec53c51 100644 --- a/test/host/sys_log_mcu/sys_log_mcu_test.c +++ b/test/host/sys_log_mcu/sys_log_mcu_test.c @@ -193,7 +193,7 @@ * (s_entry_fill / s_put / syslog_post_quiet / syslog_post_dropped)与 26 行 * 可执行代码**全部**有断言跑到:覆盖行 +26、函数 +4,未覆盖仍是同一批 3 行老账 * (一条死分支 + sys_log_evidence 里 snprintf<=0),**一条没涨**。 - * ⚠ 全量门禁(44 套并集 + 基线只增不减)由提交前那一次统一跑,本行只是自量记录。 + * ⚠ 全量门禁(47 套并集 + 基线只增不减)由提交前那一次统一跑,本行只是自量记录。 * L 族变异实测(2026-10-26,三处同时注入后逐字节还原): * ① s_paths[] 里 accid 与 alarm 两格**对调**(就是"表序错"那个静默错法); * ② 给 quiet 的丢弃分支补一条 `DBG_ERROR`(= 悄悄退化成 syslog_post); diff --git a/tools/arch_diagram/gen_arch_svg.py b/tools/arch_diagram/gen_arch_svg.py index b69e1efb..cfd00f73 100644 --- a/tools/arch_diagram/gen_arch_svg.py +++ b/tools/arch_diagram/gen_arch_svg.py @@ -64,7 +64,7 @@ L_SVC = dict( L_MW = dict( title="④ 中间件层", sub="通用库 / 协议栈", color="#16a34a", bg="#f0fdf4", chips=["net_socket / net_select / net_events / net_listener / net_pending(BSD API + 阻塞模型)", - "FatFs(文件系统)", "nand_ftl(dhara FTL)", "LVGL v9.2(图形库)", + "FatFs(文件系统)", "nand_ftl(dhara FTL)", "LVGL v9.3(图形库)", "sys_clock(墙钟基准)", "task_watchdog(IWDG 判定)"], ) L_DRV = dict( diff --git a/tools/arch_diagram/gen_barrier_svg.py b/tools/arch_diagram/gen_barrier_svg.py index 3b586704..ca3beb55 100644 --- a/tools/arch_diagram/gen_barrier_svg.py +++ b/tools/arch_diagram/gen_barrier_svg.py @@ -60,7 +60,7 @@ BITS = [ dict(bit="bit2", flag="FTP_READY", color="#d97706", bg="#fffbeb", note="ftpTask 置位 · 预留消费者"), dict(bit="bit3", flag="TIMESYNC_READY", color="#94a3b8", bg="#f8fafc", - note="预留(尚未接入调度)"), + note="预留(无生产者置位)"), ] # 生产者(左栏):row = 其置位的 bit 行