From bda7ab2b50a412290fc5aaa63eaa9113a8ffea34 Mon Sep 17 00:00:00 2001 From: Wanderingss <1624155937@qq.com> Date: Wed, 21 Oct 2026 09:53:28 +0800 Subject: [PATCH] =?UTF-8?q?refactor(=E7=BC=96=E5=8F=B7):=2016=20=E4=B8=AA?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E6=A8=A1=E5=9D=97=E7=A0=81=E5=8D=95=E8=AF=8D?= =?UTF-8?q?=E5=8C=96=20+=20=E9=97=A8=E7=A6=81=E8=AF=86=E5=88=AB=E9=9D=A2?= =?UTF-8?q?=E8=BF=9E=E5=B8=A6=E6=94=BE=E5=AE=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 批 2(用户授权改名 + 「新名要一眼看懂」裁定) - 16 个有歧义模块码单词化,共 1,146 处随 scripts/rename_ids.py 改写: 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 - 不动 NET/GD5F/RTC/SOE/UI/ADC/LOG/RS485/TOOL(已是单词、芯片名或业界通用词, 改了纯属 churn) - 别名按全局登记:这批字面量已完全限定(TC-<码>-),不存在裸形多义 - 映射表存档 scripts/rename_maps/batch2.json 作审计轨迹;§6 模块码表同步 连带修门禁(关键教训) - 模块码涨到 9 位(ADCHEALTH/WATCHDOG)后,候选正则与族正则的 {0,4} 上界 会让改名后的号**整批从门禁眼里消失**:实测编号字面量从 8271 掉到 7315、 悬空假降 490 处。已放宽到 {0,9} 并写进 §6 注记 - 结论:改名批次必须连带复核识别面,只改数据不改判据 = 静默放行; 这次是靠「可判定比例跌破基线即失败」那条线拦下来的 现状与遗留 - 校验 1 未登记前缀 0 处;可判定比例 82.71%(基线 82.6%,只涨不跌成立) - 遗留:7 个模块的「单元测试说明.md」仍缺(PROTSET 116、NANDPORT 109、 PROTELEM 65、FREQ 48、FTPAUTH 45、SHA256 25、SOE 14 处悬空)——改名不解决 缺文档,处置方式待议 - 遗留:T-2/T-3/T-4/T-6 历史任务号悬空(别名表未收全,属本工具批次漏项) - 未改任何 C/H 可编译语义(仅注释与宏名内的编号),故不需 @build --- App/algo/README.md | 2 +- App/util/sys_clock.c | 2 +- Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c | 2 +- Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h | 2 +- docs/代码规范/pre-commit使用说明.md | 2 +- docs/内存管理/内存内容分配策略.md | 2 +- docs/子系统设计/ADC采样节拍设计说明.md | 2 +- docs/子系统设计/看门狗设计说明.md | 2 +- docs/架构设计/STM32F4-Base存储架构说明.md | 2 +- docs/测试说明/ADC输入层单元测试说明.md | 136 +- docs/测试说明/GD5F2GQ5UE_Test_Guide.md | 44 +- docs/测试说明/卷锁单元测试说明.md | 32 +- docs/测试说明/存储维护与容量恢复.md | 8 +- docs/测试说明/实机测试实施指南.md | 2 +- docs/测试说明/时间同步单元测试说明.md | 64 +- docs/测试说明/测试开发标准流程.md | 6 +- docs/测试说明/测试文档模板规范.md | 2 +- docs/测试说明/相量层单元测试说明.md | 36 +- docs/测试说明/看门狗单元测试说明.md | 34 +- docs/测试说明/系统时钟单元测试说明.md | 52 +- docs/测试说明/配置文件单元测试说明.md | 64 +- docs/编号规范.md | 39 +- scripts/check_ids.py | 2 +- scripts/id_aliases.json | 2377 ++++++++++++++++++++- scripts/id_registry.json | 18 +- scripts/rename_ids.py | 14 +- scripts/rename_maps/batch2.json | 25 + test/board/storage_test.h | 2 +- test/board/storage_test_task.c | 100 +- test/board/test_config.h | 2 +- test/host/adc_health/adc_health_test.c | 106 +- test/host/adc_input/adc_input_test.c | 306 +-- test/host/cfg_file/cfg_file_test.c | 138 +- test/host/freq/freq_test.c | 96 +- test/host/ftp_auth/ftp_auth_test.c | 90 +- test/host/iec104/iec104_test.c | 46 +- test/host/nand_port/nand_port_test.c | 218 +- test/host/phasor/phasor_test.c | 52 +- test/host/prot_elm/prot_elm_test.c | 128 +- test/host/prot_set/prot_set_test.c | 224 +- test/host/sha256/sha256_test.c | 50 +- test/host/sys_clock/sys_clock_test.c | 84 +- test/host/time_sync/time_sync_test.c | 228 +- test/host/vol_lock/vol_lock_test.c | 100 +- test/host/watchdog/watchdog_test.c | 58 +- 45 files changed, 3706 insertions(+), 1295 deletions(-) create mode 100644 scripts/rename_maps/batch2.json diff --git a/App/algo/README.md b/App/algo/README.md index e218e991..76dc63d8 100644 --- a/App/algo/README.md +++ b/App/algo/README.md @@ -177,7 +177,7 @@ flowchart TD - **Q10 定点**(×1024)与参考 `2^10` 折算口径一致;元数据表(地址/范围/默认)是 ROM 常量,校验和只覆盖 RAM 值区。 - **通讯地址逐项对照参考** `Comm/Pub/Const_CommSetPara.c` `g_tCommSetParaTab` - (基址 0x8820);单测 TC-PS-006 保证地址不重复、`min ≤ def ≤ max`、投退项 0..1。 + (基址 0x8820);单测 TC-PROTSET-006 保证地址不重复、`min ≤ def ≤ max`、投退项 0..1。 - ⚠ **默认值/范围为拟定值**(参考 EEPROM 出厂表不在本仓库),待对照修订—— 见规划 §5.4 落实进度注。 - **B8 扩 8 项(32→40)**:`PS_OF_EN/OF_HZ/OF_DLY/UF_EN/UF_HZ/UF_DLY/RET_OF/RET_UF` diff --git a/App/util/sys_clock.c b/App/util/sys_clock.c index afdfb570..3133d0b1 100644 --- a/App/util/sys_clock.c +++ b/App/util/sys_clock.c @@ -77,7 +77,7 @@ static volatile uint32_t s_base_unix_secs = UINT32_MAX; * 修改记录: * 2026-10-02 修正:原式错用 (wy%100 + wy/100/4 - wy/100/15)(缺 K/4、 * 5J/世纪项,且把 1-based 月当 2-based 用),实测 1970~2099 - * 全部日期星期皆错(主机侧单测 TC-CLK-014/019 发现)。 + * 全部日期星期皆错(主机侧单测 TC-SYSCLK-014/019 发现)。 */ static uint8_t rtc_calc_week(uint16_t y, uint8_t m, uint8_t d) { uint32_t wy = y; diff --git a/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c b/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c index cc2752b7..069ea82c 100644 --- a/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c +++ b/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c @@ -632,7 +632,7 @@ void gd5f2gq5ue_bbt_clear(void) { * 返回值:GD5F_OK - 成功,其他 - 错误码 * 限定条件:gd5f2gq5ue_init() 已成功调用 * 函数说明:临时关闭 ECC 重新扫描每块 page0 spare[0] 的出厂坏块标记,覆盖 RAM BBT, - * 再写回持久化 BBT 池(版本 +1,掉电安全),从而清除 TC-STO-03 等运行时 + * 再写回持久化 BBT 池(版本 +1,掉电安全),从而清除 TC-STORAGE-03 等运行时 * 标记的坏块。调用后建议再执行 nand_ftl_format() 清空 dhara map。 */ int32_t gd5f2gq5ue_bbt_rebuild(void) { diff --git a/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h b/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h index 828566c4..df53eb51 100644 --- a/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h +++ b/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h @@ -225,7 +225,7 @@ void gd5f2gq5ue_print_bbt(void); * 入口参数:无 * 返回值:GD5F_OK - 成功,其他 - 错误码 * 限定条件:gd5f2gq5ue_init() 已成功调用 - * 函数说明:用于测试(如 TC-STO-03 注入坏块后)或出厂重置后恢复。 + * 函数说明:用于测试(如 TC-STORAGE-03 注入坏块后)或出厂重置后恢复。 * 临时关闭 ECC 重新扫描每块 page0 spare[0] 的出厂坏块标记,覆盖 RAM BBT, * 再写回持久化 BBT 池(版本 +1,掉电安全),从而清除运行时 mark 的坏块。 * 调用后建议再执行 nand_ftl_format() 清空 dhara map。 diff --git a/docs/代码规范/pre-commit使用说明.md b/docs/代码规范/pre-commit使用说明.md index d7b25ce7..c8f7a297 100644 --- a/docs/代码规范/pre-commit使用说明.md +++ b/docs/代码规范/pre-commit使用说明.md @@ -455,7 +455,7 @@ cppcheck 是开源 C/C++ 静态分析工具,**不运行代码**,通过语法 | **八项校验**([示例] 本行引用的是各种非法形态示例,不是真实编号) | ①未登记前缀 ②形态不合规(裸形 `S3` / 空格形 `Trap 07` / 中文形 `陷阱 1` / 补零错 / 档位词带后缀 / 大写后缀 / 缺模块码)③悬空引用 ④重复定义 ⑤冻结前缀越游标 ⑥文档内编号未紧邻文档名 ⑦孤儿条目(告警)⑧可判定比例(只许涨不许跌) | | **配置两份** | `scripts/id_registry.json`:前缀族 → 属主登记处 / 形态正则 / 是否冻结 / 游标,**逐项来自 `docs/编号规范.md` §4 总表**,游标取「规范记载值」与「全库实测最大号」的较大者,偏差写进 `cursor_note`(实测偏差见规范 §8.2);`scripts/id_aliases.json`:旧号 → 新号 / 作废标记(照搬 `section_aliases.json` 的成功范式) | | **判定口径** | 「定义」= 字面量出现在该族**属主登记处文档**里(不依赖表格行首等易漂移形态)→ §5.5「销项 = 删行 + 清全库引用」只做一半,校验 ③ 立刻报(`N-31`/`N-32` 正是这条)。「重复定义」= 字面量出现在**定义位**(表格首格 / 标题行 / 列表项行首),正文提到不算,否则任何交叉引用都会误判成事故 | -| **顺带收编** | `scripts/check_test_traceability.py`(TC 用例双向追溯)由本钩子一并调用:正则补齐 `TC-[A-Z]{1,4}-\d{3,4}[a-z]?` 与大写后缀 / 无模块码形态(旧 `TC-[A-Za-z0-9]+-\d+` **整条漏扫** `TC-AI-01A`),比对范围从「`test/board/*.c` ↔ `*_Test_Guide.md`」扩到 `test/host/` 一侧 + 7 篇「单元测试说明.md」(差异从 33 处涨到 326 处——**原口径漏的正是主机侧单测这一半**),另加 `--board-only` 回退旧口径 | +| **顺带收编** | `scripts/check_test_traceability.py`(TC 用例双向追溯)由本钩子一并调用:正则补齐 `TC-[A-Z]{1,4}-\d{3,4}[a-z]?` 与大写后缀 / 无模块码形态(旧 `TC-[A-Za-z0-9]+-\d+` **整条漏扫** `TC-ADCIN-01A`),比对范围从「`test/board/*.c` ↔ `*_Test_Guide.md`」扩到 `test/host/` 一侧 + 7 篇「单元测试说明.md」(差异从 33 处涨到 326 处——**原口径漏的正是主机侧单测这一半**),另加 `--board-only` 回退旧口径 | | **首轮实测(2026-10-20)** | 8271 处编号字面量 / 可判定 **82.3%**(6808/8271);错误级:②416 ③626 ⑥269,告警级:③239 ⑦88。错误集中在 `TC-PS-*`/`TC-PE-*`/`TC-AH-*`/`TC-SOE-*`(**主机侧单测有码无文档**,正是 §7.2 列的"缺文档 = 追溯断链")与报告自有编号被裸引(`D-x`/`R-x`/`F-x`/`P0-x`,属 §9 阶段 1-③)。逐项数字与口径见 `docs/编号规范.md` §8.1 | | **有牙实测(牙齿)**([示例] 下列字面量是注入用的假编号) | 注入打在临时档(`git add -N` 进索引,跑完 `git rm --cached` + 删除,`git status` 干净):`Z-99`→①、裸形 `S3`→②、`TC-NET-9999`→③、第二篇属主文档重复定义 `DP-01`→④、`E-70`→⑤(`E-xx` 冻结于 `E-63`)、裸引 `D-7`→⑥;六项分别被对应校验点名,`--strict` 退出码 1 | | **显式盲区(不是"检查通过")** | ① 裸形同字母多义(§1.2:`P1` 五义 / `L1` 四义 / `U1` 四义 / `D7` 三义)与元器件位号同形(§4.4)→ 裸形族**只在属主登记处文档内**判越游标,文档外降告警;② 圈号编号(①②③…)与正常列举无法机械区分,不入判定;③ `docs/芯片手册/`、`docs/硬件平台/` 整体排除(位号 `B1`/`C1`/`L1` 与编号同形,是撞形根源)。前两块收口属 §9 阶段 1-②/1-③ 迁移批次,落地后再扩判定范围——盲区登记在 `id_registry.json` 的 `blind_spots` / `unmanaged_bare` | diff --git a/docs/内存管理/内存内容分配策略.md b/docs/内存管理/内存内容分配策略.md index 1cdb8e11..d64ef180 100644 --- a/docs/内存管理/内存内容分配策略.md +++ b/docs/内存管理/内存内容分配策略.md @@ -127,7 +127,7 @@ LVGL 集合明细(均在 SRAM):LVGL 池 16,384B(`lv_mem_core_builtin.o` 1. `@build`(0 错误 0 警告) 2. 产品构建 `@test`(`.dsh/skills/serial-boot-test/scripts/run_boot_test.py`):标记校验 PASS,且**零 `[ERR]`**(默认 Forbidden 已含 `[ERR]`) -3. 存储套件(`test_config.h` → `TEST_SUITE_STORAGE`):只读模式实测 **3/3 PASSED**(破坏性关,卷内容不变);开启 `ENABLE_DESTRUCTIVE_TESTS` 后为全量集成用例(2026-09-20 实测 **20/20 PASSED**,含 TC-STO-01/02/03/05/06) +3. 存储套件(`test_config.h` → `TEST_SUITE_STORAGE`):只读模式实测 **3/3 PASSED**(破坏性关,卷内容不变);开启 `ENABLE_DESTRUCTIVE_TESTS` 后为全量集成用例(2026-09-20 实测 **20/20 PASSED**,含 TC-STORAGE-01/02/03/05/06) 4. GD5F 套件(`TEST_SUITE_GD5F`):只读模式实测 **16/16 PASSED**(含只读的守卫负路径 TC-GD5F-704);开启 `ENABLE_DESTRUCTIVE_TESTS` 后 **68/68 PASSED**,并确认日志出现 2 条守卫负路径 `[ERR]`(TC-GD5F-704/705)——破坏性模式运行须放宽 Forbidden(`--forbidden "FAIL;HardFault"`) 5. 恢复跑(`ENABLE_STORAGE_RECOVERY_TESTS`):期望 **3/3 PASSED** 6. **破坏性用例默认关闭**(见 `test_config.h` 的 `ENABLE_DESTRUCTIVE_TESTS`):写/擦 NAND、格式化、坏块注入与 FatFS 写类用例只在首次上电/产线首启或明确需要时开启——2026-09-21 实测一轮破坏性 GD5F 运行即让 dhara 多记一个坏块(容量 95248 → 95200,且该计数持久化在 dhara journal checkpoint 头里,`nand_ftl_format` 清不掉);日常回归请保持只读模式。容量满值 = **96064 pages(187 MB)**,被扣掉的容量可用 `ENABLE_STORAGE_RECOVERY_TESTS` + `STORAGE_RECOVERY_FULL_WIPE`(全片擦除 + 重建 BBT)恢复(实测 95200 → 96064 ✓) diff --git a/docs/子系统设计/ADC采样节拍设计说明.md b/docs/子系统设计/ADC采样节拍设计说明.md index fbf38a59..a7956fbf 100644 --- a/docs/子系统设计/ADC采样节拍设计说明.md +++ b/docs/子系统设计/ADC采样节拍设计说明.md @@ -318,7 +318,7 @@ t=1000 µs 下一个 TIM6 更新事件 只统计"从未成功过"、抓不到它。 **硬化排序**:① ✅ **已实施(2026-10-10)**——`stm32_scan()` 两条失败支路(启动失败 / 轮询 超时)都清 `s_stm32_valid` → 本拍 STM32 侧判为无有效数据,走既有 `skip` 整帧跳过路径, - 下一拍成功自动恢复;主机侧新增 **TC-AI-070..078** 钉死并做反向验证(改回旧行为 3 条立即 + 下一拍成功自动恢复;主机侧新增 **TC-ADCIN-070..078** 钉死并做反向验证(改回旧行为 3 条立即 FAIL)。② ✅ **已实施(2026-10-10)= DMA**:见 **§11**——TIM3 更新事件经 TRGO 硬件触发 ADC1 一轮 9 通道,`HAL_ADC_Start_DMA(&hadc1, buf, 18)`(乒乓双缓冲)由 DMA 自动搬运, 任务侧 `HAL_ADC_PollForConversion` **全部删除**,实测单拍 `adcp` **122 µs → 8 µs**; diff --git a/docs/子系统设计/看门狗设计说明.md b/docs/子系统设计/看门狗设计说明.md index 1a94e5b7..4a6a8a7f 100644 --- a/docs/子系统设计/看门狗设计说明.md +++ b/docs/子系统设计/看门狗设计说明.md @@ -588,7 +588,7 @@ python scripts/check_cubemx_survival.py --write # 确认改动无误后重建 等效采样间隔被拉长。当时 `idle` 占 3.2% → 窗长从 20.0 ms 漂到 ≈20.6 ms ≈ **3% 频率失配** → 幅值/相位**系统性误差**(不是随机噪声)。现仅 `r == 1` 压帧,上板印证 `ring == frames`。 - **失败拍静默沿用上一拍值**:失败支路不清 `s_stm32_valid` → 照样压环、`skip` 抓不到。 - 现失败即清标志走整帧跳过(`ADC采样节拍设计说明.md` §10.4;单测 TC-AI-070..078 钉死)。 + 现失败即清标志走整帧跳过(`ADC采样节拍设计说明.md` §10.4;单测 TC-ADCIN-070..078 钉死)。 ### 11.4 `[PROF]` / `[PROF2]` 字段语义与当前基线 diff --git a/docs/架构设计/STM32F4-Base存储架构说明.md b/docs/架构设计/STM32F4-Base存储架构说明.md index 079bee36..09137307 100644 --- a/docs/架构设计/STM32F4-Base存储架构说明.md +++ b/docs/架构设计/STM32F4-Base存储架构说明.md @@ -582,7 +582,7 @@ if (nand_ftl_format() == 0) { 10. **FatFs 严格 8.3 短名** — 本移植 `Lib/FatFs/ffconf.h` 为 `FF_USE_LFN=0`,**只支持严格 8.3 短名**:主名 ≤8 字符、扩展 ≤3 字符、**不得以点开头**(2026-09-20 台架实证,`.fschk` 无限重格式化事故根因)。`.fschk` 会被 `ff.c` 的 `create_short` 把「点之后」当扩展域解析而超限 → `f_open` 恒返 `FR_INVALID_NAME`(6);这是**纯 RAM 里的名字判定,不碰盘**。`ff.c` `create_short` 全部拒绝点的地方已加 DEBUG 打印:`[ERR][FATFS] SFN reject (原因) seg='名字片段' bad_ch=坏字符`——非法名字调用看开机日志即可定位。自愈类逻辑**严禁**把名字/参数类错误码(`FR_INVALID_NAME` 等)归入"卷损坏"触发集(整卷重格式化不可逆)。补充:含冒号 `:` 的名字被 FatFs 先解析为**盘符前缀** → `f_open` 返回 `FR_INVALID_DRIVE`(11) 而非 `FR_INVALID_NAME`(6);两者都属合法拒绝(测试用例须同时接受)。 11. **FA_OPEN_APPEND 陷阱 / 短写** — `FA_OPEN_APPEND`(0x30) = `FA_OPEN_ALWAYS|FA_SEEKEND`,**不含 `FA_WRITE`(0x02)**——不带写位打开的文件 `f_write` 恒返回 `FR_DENIED`(7)(这是当年 `/log` 写失败的真根因);追加写必须写 `FA_WRITE | FA_OPEN_APPEND`(2026-09-20 台架实测,`Lib/FatFs` 移植版)。该移植的 `f_write` 在簇分配失败时返回 `FR_OK` + 短写(**没有错误码**)→ 判失败必须校验写回的字节数。标志位为**旧式编号**:`FA_READ`=0x01 / `FA_WRITE`=0x02 / `FA_CREATE_NEW`=0x04 / `FA_CREATE_ALWAYS`=0x08 / `FA_OPEN_ALWAYS`=0x10 / `FA_OPEN_APPEND`=0x30 / `FA_SEEKEND`=0x20(`ff.c` 内部定义),与上游 FatFs R0.14 不同,**勿照抄上游代码示例**。 12. **崩溃可观测性(勿屏蔽)** — 已开启 `configCHECK_FOR_STACK_OVERFLOW=2` + `configUSE_MALLOC_FAILED_HOOK` + HardFault 现场报告(`Src/stm32f4xx_it.c`:裸 UART 打印 PC/LR/xPSR + CFSR/HFSR/BFAR/MMFAR 后复位,对照 `.map` 定位符号)。defaultTask **1024** words、testTask **2048** words 是**实测下限,勿降**。开机日志出现 `[ERR] STACK OVERFLOW task=` / `[ERR] HARDFAULT ...` / `MALLOC FAILED` 是精确定位线索,禁止屏蔽或降级。 -13. **BBT 恢复模式** — 运行期坏块会随 TC-STO-03 注入累积;当介质被**误标脏**(如 DMA 误打 CCM 栈导致随机块被写坏并持久化)时,打开 `test/board/storage_test.h` 的 `ENABLE_STORAGE_RECOVERY_TESTS` 编译**恢复构建**,testTask 会执行 `gd5f2gq5ue_bbt_rebuild()`(出厂扫描清除运行期误标)+ `nand_ftl_format()` 清账后复位。恢复后容量回到基线(即扣除 BBT 保留池后的正常容量,非出厂裸容量)。 +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) diff --git a/docs/测试说明/ADC输入层单元测试说明.md b/docs/测试说明/ADC输入层单元测试说明.md index df400a64..452317a9 100644 --- a/docs/测试说明/ADC输入层单元测试说明.md +++ b/docs/测试说明/ADC输入层单元测试说明.md @@ -114,34 +114,34 @@ test/host/adc_input/adc_input_test.c | 用例 | 断言 | 验证的设计点 | |---|---|---| -| **TC-AI-001** | 前置:注入 `HAL_ADC_Start` 失败 → poll 后失败计数 = 1 | 统计可见性(前置构造) | -| **TC-AI-002** | 前置:注入 TPAFE 有效帧 → poll 后 `UA` 可取数且值正确 | 取数通路(前置构造) | -| **TC-AI-003** | `adc_input_init()` 返回 0 | 映射表自检通过 | -| **TC-AI-004** | init 后 `adc_input_stm32_rc() == ADC_INPUT_RC_NOT_RUN` | 状态码复位 | -| **TC-AI-005** | init 后 `adc_input_stm32_errs() == 0` | 失败计数归零 | -| **TC-AI-006** | init 后 TPAFE / STM32 **两侧** `adc_input_raw()` 均返回 -2 | 有效标志被清(不会取到上一轮陈旧值) | +| **TC-ADCIN-001** | 前置:注入 `HAL_ADC_Start` 失败 → poll 后失败计数 = 1 | 统计可见性(前置构造) | +| **TC-ADCIN-002** | 前置:注入 TPAFE 有效帧 → poll 后 `UA` 可取数且值正确 | 取数通路(前置构造) | +| **TC-ADCIN-003** | `adc_input_init()` 返回 0 | 映射表自检通过 | +| **TC-ADCIN-004** | init 后 `adc_input_stm32_rc() == ADC_INPUT_RC_NOT_RUN` | 状态码复位 | +| **TC-ADCIN-005** | init 后 `adc_input_stm32_errs() == 0` | 失败计数归零 | +| **TC-ADCIN-006** | init 后 TPAFE / STM32 **两侧** `adc_input_raw()` 均返回 -2 | 有效标志被清(不会取到上一轮陈旧值) | ### 2.2 语义映射表(`adc_input_desc`) | 用例 | 断言(语义 → 来源 / 下标) | 权威口径 | |---|---|---| -| **TC-AI-010** | `UA` → TPAFE `buf[6]` | `docs/硬件平台/ADC通道映射说明.md` | -| **TC-AI-011** | `UB` → STM32 `CH14` | 同上 | -| **TC-AI-012** | `UC` → STM32 `CH3` | 同上 | -| **TC-AI-013** | `UN` → TPAFE `buf[5]` | 同上 | -| **TC-AI-014** | `IA` → TPAFE `buf[2]` | 同上 | -| **TC-AI-015** | `IB` → STM32 `CH6` | 同上 | -| **TC-AI-016** | `IC` → STM32 `CH1` | 同上 | -| **TC-AI-017** | `IN` → STM32 `CH2` | 同上 | -| **TC-AI-018** | `TEMP` → STM32 `CH5`(V_ZL2) | 同上 | -| **TC-AI-019** | `adc_input_desc(ADC_SEM_COUNT)` → `NULL` | 越界防御 | -| **TC-AI-01A** | `adc_input_desc((adc_semantic_t)-1)` → `NULL` | 无符号比较兜底 | +| **TC-ADCIN-010** | `UA` → TPAFE `buf[6]` | `docs/硬件平台/ADC通道映射说明.md` | +| **TC-ADCIN-011** | `UB` → STM32 `CH14` | 同上 | +| **TC-ADCIN-012** | `UC` → STM32 `CH3` | 同上 | +| **TC-ADCIN-013** | `UN` → TPAFE `buf[5]` | 同上 | +| **TC-ADCIN-014** | `IA` → TPAFE `buf[2]` | 同上 | +| **TC-ADCIN-015** | `IB` → STM32 `CH6` | 同上 | +| **TC-ADCIN-016** | `IC` → STM32 `CH1` | 同上 | +| **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` | 无符号比较兜底 | ### 2.3 映射表自检(`map_check`,静态) | 用例 | 断言 | 验证的设计点 | |---|---|---| -| **TC-AI-020** | `map_check() == 0` | 真实映射表自洽:TPAFE 下标 < 8;每个 STM32 映射通道都出现在扫描 Rank 内 | +| **TC-ADCIN-020** | `map_check() == 0` | 真实映射表自洽:TPAFE 下标 < 8;每个 STM32 映射通道都出现在扫描 Rank 内 | > 反向路径(表不自洽 → -1)**结构上不可达**,见 §4.1。 @@ -149,27 +149,27 @@ test/host/adc_input/adc_input_test.c | 用例 | 断言 | 验证的设计点 | |---|---|---| -| **TC-AI-021** | 有新帧 → 返回 0 | 正常路径 | -| **TC-AI-022** | `adc_input_stm32_rc() == RC_OK` | 状态码 | -| **TC-AI-023** | 成功不计入失败计数 | 统计语义 | -| **TC-AI-024** | `HAL_ADC_Start_DMA` 只在 `init()` 挂**一次** | 外设生命周期(每拍不重启) | -| **TC-AI-025** | DMA 完成计数 `seq` = 1 | 计数只由 HAL 回调推进 | -| **TC-AI-026** | ⭐ **Rank → 通道号映射**:`UB` = CH14 / rank9 = 108 | **本层核心判据**(板端无法验) | -| **TC-AI-027** | `UC` = CH3 / rank4 = 103 | 同上 | -| **TC-AI-028** | `IB` = CH6 / rank7 = 106 | 同上 | -| **TC-AI-029** | `IC` = CH1 / rank2 = 101 | 同上 | -| **TC-AI-02A** | `IN` = CH2 / rank3 = 102 | 同上 | -| **TC-AI-02B** | `TEMP` = CH5 / rank6 = 105 | 同上 | -| **TC-AI-02C** | 取帧后 `UA`(TPAFE)仍为 -2 | 两来源互相独立 | -| **TC-AI-080..085** | ⭐ **乒乓双缓冲**:往"正在被 DMA 写的另一半区"填 900/800 系干扰值,`stm32_take()` 仍必须读到**刚完成那一半**(108 / 208) | **撕裂帧防线**(读错半区 = 半新半旧混合帧) | -| **TC-AI-086..089** | 连投两帧不消费 → 取到最新帧(408)且 `gaps()` = 1、`errs()` = 0 | **丢帧与停摆分开计数**(消费者超拍 ≠ 节拍源停) | -| **TC-AI-090..09A** | `HAL_ADC_ErrorCallback(&hadc1)` ×2 → `hw_errs()` = 2;用**别的句柄**调三个回调 → `seq` / `hw_errs` 均不动 | 三个 HAL 弱回调的 `hadc == &hadc1` **句柄守卫** | -| **TC-AI-030..034** | `HAL_ADC_Start_DMA` 返回 `HAL_ERROR` → `init()` 返回 **-2**、状态码 `RC_START`、计数 +1、STM32 侧无有效数据 | 挂载失败(一次性,非每拍) | -| **TC-AI-035..039** | 无任何 DMA 完成 → `RC_STALL`、**单拍不计故障**、`seq` 不前进、STM32 侧无有效数据 | 无新帧路径 + 相位伪影不误报 | -| **TC-AI-03A..03E** | 连续两拍无新帧 → `errs()` = 1;第三拍 → 2;恢复拍成功且 `gaps()` 仍 0 | 停摆判据 = **连续 ≥2 拍**;跨次单调累计 | -| **TC-AI-070..078** | ⭐ **停摆拍不得沿用上一拍旧值**:先成功一拍让 STM32 侧进入有效态(`UB`=108),再注入无新帧拍 → `adc_input_raw()` 必须返 **-2**;恢复拍重新可取数 | **陈旧帧**(2026-10-10 真机实测发现的缺陷,见下注) | +| **TC-ADCIN-021** | 有新帧 → 返回 0 | 正常路径 | +| **TC-ADCIN-022** | `adc_input_stm32_rc() == RC_OK` | 状态码 | +| **TC-ADCIN-023** | 成功不计入失败计数 | 统计语义 | +| **TC-ADCIN-024** | `HAL_ADC_Start_DMA` 只在 `init()` 挂**一次** | 外设生命周期(每拍不重启) | +| **TC-ADCIN-025** | DMA 完成计数 `seq` = 1 | 计数只由 HAL 回调推进 | +| **TC-ADCIN-026** | ⭐ **Rank → 通道号映射**:`UB` = CH14 / rank9 = 108 | **本层核心判据**(板端无法验) | +| **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-080..085** | ⭐ **乒乓双缓冲**:往"正在被 DMA 写的另一半区"填 900/800 系干扰值,`stm32_take()` 仍必须读到**刚完成那一半**(108 / 208) | **撕裂帧防线**(读错半区 = 半新半旧混合帧) | +| **TC-ADCIN-086..089** | 连投两帧不消费 → 取到最新帧(408)且 `gaps()` = 1、`errs()` = 0 | **丢帧与停摆分开计数**(消费者超拍 ≠ 节拍源停) | +| **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-070..078** | ⭐ **停摆拍不得沿用上一拍旧值**:先成功一拍让 STM32 侧进入有效态(`UB`=108),再注入无新帧拍 → `adc_input_raw()` 必须返 **-2**;恢复拍重新可取数 | **陈旧帧**(2026-10-10 真机实测发现的缺陷,见下注) | -> ⚠ **为什么 TC-AI-034 照不出这条缺陷**:它是"`adc_input_init()` 后**立刻**失败",此时 +> ⚠ **为什么 TC-ADCIN-034 照不出这条缺陷**:它是"`adc_input_init()` 后**立刻**失败",此时 > `s_stm32_valid` 本来就是 0,断言 -2 恒成立。真正的缺陷路径是**成功过之后再失败**: > 本层只有一份 `s_stm32_raw[]`,而有效标志此前**只在成功时置 1、失败时从不清零** → > 消费侧照样取数、照样压入采样环(`adc_input_poll()` 返回值只由 TPAFE 决定, @@ -177,7 +177,7 @@ test/host/adc_input/adc_input_test.c > 修复 = 失败支路清 `s_stm32_valid`(`App/algo/adc_input.c`)。 > **这组用例在轮询版与 DMA 版都保留**:触发条件从"轮询超时"变成"本拍无新帧", > **同一条缺陷、同一个防线**。 -> **反向验证已做(v2.0)**:把停摆支路改回 `valid=1` → TC-AI-039 / 073 / 074 / 074B 四条立即 +> **反向验证已做(v2.0)**:把停摆支路改回 `valid=1` → TC-ADCIN-039 / 073 / 074 / 074B 四条立即 > FAIL(89/93 时点);把半区奇偶取反 → 11 条 FAIL;`STALL_RUN_MAX` 改 1 → 6 条 FAIL; > gap 阈值改 `>2` → 1 条 FAIL → 证明这些用例真的咬得住。 @@ -185,45 +185,45 @@ test/host/adc_input/adc_input_test.c | 用例 | 断言 | 验证的设计点 | |---|---|---| -| **TC-AI-040** | `out == NULL` → -1 | 参数防御 | -| **TC-AI-041** | `ch == ADC_SEM_COUNT` → -1 | 越界防御 | -| **TC-AI-042** | `ch == (adc_semantic_t)-1` → -1 | 负数兜底 | -| **TC-AI-043** | 参数错时**不写** `*out` | 无副作用 | -| **TC-AI-044** | TPAFE 无有效帧 → -2 | 有效标志语义 | -| **TC-AI-045** | STM32 无有效扫描 → -2 | 有效标志语义 | -| **TC-AI-049** | `UA` → `buf[6]` 的值(注入 3006) | 按**下标**取数(非按枚举序) | -| **TC-AI-04A** | `UN` → `buf[5]` 的值(注入 2005) | 同上 | -| **TC-AI-04B** | `IA` → `buf[2]` 的值(注入 **-1234**) | 16 位补码负值原样保留(不截断 / 不取绝对值) | +| **TC-ADCIN-040** | `out == NULL` → -1 | 参数防御 | +| **TC-ADCIN-041** | `ch == ADC_SEM_COUNT` → -1 | 越界防御 | +| **TC-ADCIN-042** | `ch == (adc_semantic_t)-1` → -1 | 负数兜底 | +| **TC-ADCIN-043** | 参数错时**不写** `*out` | 无副作用 | +| **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 位补码负值原样保留(不截断 / 不取绝对值) | ### 2.6 采集一拍(`adc_input_poll`) | 用例 | 断言 | 验证的设计点 | |---|---|---| -| **TC-AI-046** | 快照返回 1 → `poll()` 返回 1 | 返回码透传 | -| **TC-AI-047** | 快照被请求 **8** 通道 | 与 `ADC_INPUT_TPAFE_CH_NUM` 一致 | -| **TC-AI-048** | 快照目的缓冲非空 | 不传 NULL 给驱动 | -| **TC-AI-050** | 快照返回 0(无新帧)→ `poll()` 返回 0 | 无新帧语义 | -| **TC-AI-051** | 无新帧时 TPAFE 侧无效 | 不置有效标志 | -| **TC-AI-052** | 同拍 STM32 扫描**照常执行**(`rc == RC_OK`) | 两侧独立 | -| **TC-AI-053** | 快照返回 -1(参数错)→ `poll()` 返回 -1 | 错误透传 | -| **TC-AI-054** | 参数错时 TPAFE 侧无效 | 不置有效标志 | -| **TC-AI-055** | 已有有效帧后再"无新帧" → **保持**上次有效值 | 有效标志只置不清 | -| **TC-AI-056** | STM32 失败**不影响** `poll()` 返回值(仍为 1) | 两侧解耦 | -| **TC-AI-057** | STM32 失败不影响 TPAFE 取数 | 同上 | -| **TC-AI-058** | STM32 失败另由 `adc_input_stm32_rc()` 暴露 | 故障通道分离 | +| **TC-ADCIN-046** | 快照返回 1 → `poll()` 返回 1 | 返回码透传 | +| **TC-ADCIN-047** | 快照被请求 **8** 通道 | 与 `ADC_INPUT_TPAFE_CH_NUM` 一致 | +| **TC-ADCIN-048** | 快照目的缓冲非空 | 不传 NULL 给驱动 | +| **TC-ADCIN-050** | 快照返回 0(无新帧)→ `poll()` 返回 0 | 无新帧语义 | +| **TC-ADCIN-051** | 无新帧时 TPAFE 侧无效 | 不置有效标志 | +| **TC-ADCIN-052** | 同拍 STM32 扫描**照常执行**(`rc == RC_OK`) | 两侧独立 | +| **TC-ADCIN-053** | 快照返回 -1(参数错)→ `poll()` 返回 -1 | 错误透传 | +| **TC-ADCIN-054** | 参数错时 TPAFE 侧无效 | 不置有效标志 | +| **TC-ADCIN-055** | 已有有效帧后再"无新帧" → **保持**上次有效值 | 有效标志只置不清 | +| **TC-ADCIN-056** | STM32 失败**不影响** `poll()` 返回值(仍为 1) | 两侧解耦 | +| **TC-ADCIN-057** | STM32 失败不影响 TPAFE 取数 | 同上 | +| **TC-ADCIN-058** | STM32 失败另由 `adc_input_stm32_rc()` 暴露 | 故障通道分离 | ### 2.7 状态码与失败计数观测 | 用例 | 断言 | |---|---| -| **TC-AI-060** | init 后未取帧 → `RC_NOT_RUN(-3)` | -| **TC-AI-061** | init 后各计数 = 0 | -| **TC-AI-062** | 一次成功后 `rc == OK` 且 `errs` 不变 | -| **TC-AI-063** | 连续两拍无新帧 → `errs == 1`(单拍伪影不计) | -| **TC-AI-064** | `rc` = **最近一次**(`RC_STALL`) | -| **TC-AI-065** | 恢复成功后 `rc == OK` | -| **TC-AI-066** | `errs` **单调不回退**(不因成功回落) | -| **TC-AI-067** | `seq` 只由 DMA 完成回调推进(消费动作不改它) | +| **TC-ADCIN-060** | init 后未取帧 → `RC_NOT_RUN(-3)` | +| **TC-ADCIN-061** | init 后各计数 = 0 | +| **TC-ADCIN-062** | 一次成功后 `rc == OK` 且 `errs` 不变 | +| **TC-ADCIN-063** | 连续两拍无新帧 → `errs == 1`(单拍伪影不计) | +| **TC-ADCIN-064** | `rc` = **最近一次**(`RC_STALL`) | +| **TC-ADCIN-065** | 恢复成功后 `rc == OK` | +| **TC-ADCIN-066** | `errs` **单调不回退**(不因成功回落) | +| **TC-ADCIN-067** | `seq` 只由 DMA 完成回调推进(消费动作不改它) | **当前结果**:**101/101 PASSED**(`failed=0`)。 diff --git a/docs/测试说明/GD5F2GQ5UE_Test_Guide.md b/docs/测试说明/GD5F2GQ5UE_Test_Guide.md index 81b3132c..7a566160 100644 --- a/docs/测试说明/GD5F2GQ5UE_Test_Guide.md +++ b/docs/测试说明/GD5F2GQ5UE_Test_Guide.md @@ -526,7 +526,7 @@ ECC 状态(`ECCS1:ECCS0`):`00`=无错;`01/10/11`=纠正 1/2/3 bit;`10` > - 健康满容量 = **96064 pages(187 MB)**(`No valid map found, creating fresh` 分支下的满值)。 > - 容量随 dhara 计到的坏块数递减,且该计数**持久化在 journal checkpoint 头里** > (`journal.c` `hdr_set_bb_current/bb_last`);`dhara_journal_clear()` 只做 -> `bb_last = bb_current`(**不归零**)——所以 `nand_ftl_format()`(TC-STO-04 普通恢复) +> `bb_last = bb_current`(**不归零**)——所以 `nand_ftl_format()`(TC-STORAGE-04 普通恢复) > **清不掉被扣掉的容量**,断电重扫也一样。 > - 恢复满容量:启用 `ENABLE_STORAGE_RECOVERY_TESTS` **并叠加** `STORAGE_RECOVERY_FULL_WIPE` > 跑一次 STORAGE 套件(擦净 dhara 可见区 2044 块 + 重建 BBT),随后断电重启—— @@ -643,7 +643,7 @@ ECC 状态(`ECCS1:ECCS0`):`00`=无错;`01/10/11`=纠正 1/2/3 bit;`10` > 本套件独立于 GD5F 驱动套件,由 `test_config.h` 的 `TEST_SUITE_STORAGE` 选择, > 入口 `storage_test_run()`(`test/board/storage_test_task.c`),统一在 `ch395fTestTask` 中调度。 > 当前 `storage_test_run()` 已覆盖 mkfs/mount/文件写读/性能(与阶段 9 FatFs 同类路径), -> 并新增下列三项**集成测试**(TC-STO-01~03),覆盖 FTL journal 掉电恢复、大文件/随机访问、坏块注入下的存储可用性。 +> 并新增下列三项**集成测试**(TC-STORAGE-01~03),覆盖 FTL journal 掉电恢复、大文件/随机访问、坏块注入下的存储可用性。 > 三项均已于 STORAGE 套件实测通过(`=== Storage Tests: 11/11 PASSED (failed=0) ===`)。 > > **已知陷阱(已修复)**:FTL 页缓存用 `s_cached_lpn = 0` 表示"缓存未加载",但 LPN 0 是合法页(FAT 引导扇区所在页)。 @@ -651,11 +651,11 @@ ECC 状态(`ECCS1:ECCS0`):`00`=无错;`01/10/11`=纠正 1/2/3 bit;`10` > 引导扇区签名变成 `0000`,FatFs 报 `FR_NO_FILESYSTEM`。正常启动因 `f_mkfs` 兜底分支掩盖了此问题(第二次挂载才真正读盘)。 > 修复:将"缓存空"哨兵改为非法值 `(dhara_sector_t)-1`(0xFFFFFFFF,远超实际容量),涉及 `disk_initialize` / `nand_ftl_deinit` / `nand_ftl_format`。 -### TC-STO-01: FTL 掉电恢复(journal 持久化) +### TC-STORAGE-01: FTL 掉电恢复(journal 持久化) | 字段 | 值 | |------|-----| -| **ID** | TC-STO-01 | +| **ID** | TC-STORAGE-01 | | **优先级** | P1 | | **类型** | 集成/可靠性测试 | | **标题** | 写入文件并同步后,可经 `dhara_map_resume` 恢复映射,文件不丢 | @@ -666,11 +666,11 @@ ECC 状态(`ECCS1:ECCS0`):`00`=无错;`01/10/11`=纠正 1/2/3 bit;`10` | **依赖** | `nand_ftl_deinit()`(清 `s_initialized`/`s_cached_lpn`,使下次 init 真正重新 resume) | | **实测** | PASS(STORAGE 套件:resume 后 `pl.dat` 内容逐字节一致;修复 `s_cached_lpn` 哨兵 bug 后通过) | -### TC-STO-02: 大文件 / 多扇区 / 随机 seek +### TC-STORAGE-02: 大文件 / 多扇区 / 随机 seek | 字段 | 值 | |------|-----| -| **ID** | TC-STO-02 | +| **ID** | TC-STORAGE-02 | | **优先级** | P1 | | **类型** | 功能/压力测试 | | **标题** | 256KB 文件顺序写读 + 随机偏移 seek 读一致性 | @@ -680,25 +680,25 @@ ECC 状态(`ECCS1:ECCS0`):`00`=无错;`01/10/11`=纠正 1/2/3 bit;`10` | **覆盖原则** | FTL 大范围 LBA 映射 / 垃圾回收 / FatFs `f_lseek` + `f_read` | | **实测** | PASS(STORAGE 套件:256KB 顺序 + 随机 seek 读回一致) | -### TC-STO-03: 坏块注入下存储写入 +### TC-STORAGE-03: 坏块注入下存储写入 | 字段 | 值 | |------|-----| -| **ID** | TC-STO-03 | +| **ID** | TC-STORAGE-03 | | **优先级** | P1 | | **类型** | 负向/健壮性测试 | | **标题** | 运行时注入坏块后,FatFS 仍可正常写读且坏块未被占用 | | **前置条件** | `gd5f2gq5ue_init()` 成功;FTL 已复位 | | **测试步骤** | 1. `nand_ftl_format()` 清空旧 map → 选若干出厂好块 `gd5f2gq5ue_mark_block_bad()` 注入(更新并持久化 BBT)
2. `nand_ftl_deinit()` + `nand_ftl_init()` 使 dhara 经 `is_block_bad` 看到新坏块
3. `f_mkfs` 重建文件系统 → 正常文件写读 `bbt.dat` 并校验
4. 校验注入坏块仍 `gd5f2gq5ue_is_block_bad()==1` | | **通过标准** | 文件内容完整;注入坏块未被 dhara 分配使用(仍报告坏),存储可用 | -| **注意事项** | 本例会**永久**将若干好块标记为坏并持久化(测试设备专用);如需恢复,运行 TC-STO-04(启用 `ENABLE_STORAGE_RECOVERY_TESTS` 编译 STORAGE 套件一次)即可重建 BBT + 重新格式化 | +| **注意事项** | 本例会**永久**将若干好块标记为坏并持久化(测试设备专用);如需恢复,运行 TC-STORAGE-04(启用 `ENABLE_STORAGE_RECOVERY_TESTS` 编译 STORAGE 套件一次)即可重建 BBT + 重新格式化 | | **实测** | PASS(STORAGE 套件:注入 3 坏块后文件完整且坏块仍报告坏) | -### TC-STO-04: 重建 BBT + 重新格式化(恢复) +### TC-STORAGE-04: 重建 BBT + 重新格式化(恢复) | 字段 | 值 | |------|-----| -| **ID** | TC-STO-04 | +| **ID** | TC-STORAGE-04 | | **优先级** | P1 | | **类型** | 恢复/清理测试 | | **标题** | 重建 BBT(重新扫描出厂坏块并持久化)并清空 dhara map,恢复设备干净态 | @@ -753,22 +753,22 @@ ECC 状态(`ECCS1:ECCS0`):`00`=无错;`01/10/11`=纠正 1/2/3 bit;`10` | TC-GD5F-1002 | size=0 | P2 | PASS | | TC-GD5F-1003 | 未擦除写入 | P0 | PASS | | TC-GD5F-1004 | 写保护解除 | P1 | PASS | -| TC-STO-01 | FTL 掉电恢复(journal) | P1 | PASS | -| TC-STO-02 | 大文件/随机 seek | P1 | PASS | -| TC-STO-03 | 坏块注入下存储写入 | P1 | PASS | -| TC-STO-04 | BBT 重建 + 重新格式化(恢复) | P1 | 受 `ENABLE_STORAGE_RECOVERY_TESTS` 控制(默认关) | +| TC-STORAGE-01 | FTL 掉电恢复(journal) | P1 | PASS | +| TC-STORAGE-02 | 大文件/随机 seek | P1 | PASS | +| TC-STORAGE-03 | 坏块注入下存储写入 | P1 | PASS | +| 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: 68/68 PASSED (failed=0) ===`(全部阶段)。 -> `TEST_SUITE_STORAGE` 只读模式实测 `=== Storage Tests: 3/3 PASSED (failed=0) ===`(mount + TC-STO-05, -> 卷内容与容量不变);破坏性模式为全量集成用例(2026-09-20 实测 **20/20 PASSED**,含 TC-STO-01/02/03/05/06)。 +> `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)。 > 各套件在两种模式下均 0 错误 0 警告通过 MDK 编译。 > > **破坏性用例清单**(仅在 `ENABLE_DESTRUCTIVE_TESTS` 打开时编译运行): > GD5F:TC-GD5F-206/207、301~305、401~404、501~502、601~605、701~703、705、801~802、901、1003~1004 -> (TC-GD5F-704 为**只读**,两次运行都跑);存储:TC-STO-01、02、03、06 与内建文件系统写读/ -> 性能压测(TC-STO-05 为只读,始终运行);RTC:TC-RTC-002(写时间,跑完复原)、014(写 SRAM)、015(写报警)。 +> (TC-GD5F-704 为**只读**,两次运行都跑);存储:TC-STORAGE-01、02、03、06 与内建文件系统写读/ +> 性能压测(TC-STORAGE-05 为只读,始终运行);RTC:TC-RTC-002(写时间,跑完复原)、014(写 SRAM)、015(写报警)。 --- @@ -798,9 +798,9 @@ ECC 状态(`ECCS1:ECCS0`):`00`=无错;`01/10/11`=纠正 1/2/3 bit;`10` | `gd5f_check_ecc` | TC-GD5F-501/502 | | `nand_ftl_init` | TC-GD5F-801 | | `nand_ftl_format` | TC-GD5F-802 | -| `nand_ftl_deinit` | TC-STO-01 / TC-STO-03 | -| `gd5f2gq5ue_bbt_rebuild` | TC-STO-04 | -| `storage_test_run`(存储套件) | TC-STO-01/02/03/04 | +| `nand_ftl_deinit` | TC-STORAGE-01 / TC-STORAGE-03 | +| `gd5f2gq5ue_bbt_rebuild` | TC-STORAGE-04 | +| `storage_test_run`(存储套件) | TC-STORAGE-01/02/03/04 | --- diff --git a/docs/测试说明/卷锁单元测试说明.md b/docs/测试说明/卷锁单元测试说明.md index ac3797a8..727bafcd 100644 --- a/docs/测试说明/卷锁单元测试说明.md +++ b/docs/测试说明/卷锁单元测试说明.md @@ -63,7 +63,7 @@ test/host/vol_lock/vol_lock_test.c | **未创建 + 创建失败** | **`1`** | **否(零阻塞)** | **照常进入临界区**(无保护),事后 `release` 判空静默 | 即:**返回 1 = "你可以往下走"**,其代价是"可能没有真正持锁"。这保证了喂狗点在任何情况下 -都不会被锁阻塞。`TC-VL-008`(返回 1)与 `TC-VL-008b`(`osMutexWait` 调用次数 == 0) +都不会被锁阻塞。`TC-VOLLOCK-008`(返回 1)与 `TC-VOLLOCK-008b`(`osMutexWait` 调用次数 == 0) 两条断言共同钉死该语义——只断言返回 1 是不够的,必须同时证明**没有进入任何等待路径**。 > `vol_lock_init()` 的返回值与 `wait()` 的语义**无关**:`init` 失败返回 `-1`,但 @@ -112,32 +112,32 @@ test/host/vol_lock/vol_lock_test.c | 用例 | 断言 | |---|---| -| **TC-VL-001** | 首次调用返回 `0`;`osMutexNew` 恰好调用 1 次;模块静态态已持有句柄 | -| **TC-VL-002** | 重复调用仍返回 `0`(幂等);**不再**创建第二个互斥量(`osMutexNew` 仍为 1 次) | -| **TC-VL-003** | `osMutexNew` 返回 `NULL` 时 `init` 返回 `-1`;**不留下半初始化句柄**(`s_lock == NULL`) | -| **TC-VL-004** | 失败后重试可成功(返回 `0`);重试确实**再次**调用了 `osMutexNew` | +| **TC-VOLLOCK-001** | 首次调用返回 `0`;`osMutexNew` 恰好调用 1 次;模块静态态已持有句柄 | +| **TC-VOLLOCK-002** | 重复调用仍返回 `0`(幂等);**不再**创建第二个互斥量(`osMutexNew` 仍为 1 次) | +| **TC-VOLLOCK-003** | `osMutexNew` 返回 `NULL` 时 `init` 返回 `-1`;**不留下半初始化句柄**(`s_lock == NULL`) | +| **TC-VOLLOCK-004** | 失败后重试可成功(返回 `0`);重试确实**再次**调用了 `osMutexNew` | ### 2.2 `vol_lock_wait` — 获取与 fail-open ⭐ | 用例 | 断言 | |---|---| -| **TC-VL-005** | 获取成功返回 `1`;`osMutexWait` 调用 1 次;**`timeout` 原样透传**(100 → 100) | -| **TC-VL-014** | `wait(0)` 的 try 语义:返回 `1` 且透传值为 `0`(defaultTask 路径) | -| **TC-VL-006** | `osMutexWait` 返回非 `osOK` → `wait` 返回 `0`;超时路径确实尝试过等待 | -| **TC-VL-007** | 锁未创建时 `wait` **自动 `init`** 并正常获取(创建 1 次 + 等待 1 次) | -| **TC-VL-008** ⭐ | **fail-open**:锁未创建且创建失败 → 返回 **`1`**;**`osMutexWait` 调用次数 == 0**(零阻塞);`s_lock` 仍为 `NULL` | -| **TC-VL-009** | fail-open 之后 `release` 无害:`osMutexRelease` **未被调用**(判空静默返回) | -| **TC-VL-010** | 已创建时多次 `wait` **不重复创建**(`osMutexNew` 恒 1 次);每次 `wait` 各等待一次 | +| **TC-VOLLOCK-005** | 获取成功返回 `1`;`osMutexWait` 调用 1 次;**`timeout` 原样透传**(100 → 100) | +| **TC-VOLLOCK-014** | `wait(0)` 的 try 语义:返回 `1` 且透传值为 `0`(defaultTask 路径) | +| **TC-VOLLOCK-006** | `osMutexWait` 返回非 `osOK` → `wait` 返回 `0`;超时路径确实尝试过等待 | +| **TC-VOLLOCK-007** | 锁未创建时 `wait` **自动 `init`** 并正常获取(创建 1 次 + 等待 1 次) | +| **TC-VOLLOCK-008** ⭐ | **fail-open**:锁未创建且创建失败 → 返回 **`1`**;**`osMutexWait` 调用次数 == 0**(零阻塞);`s_lock` 仍为 `NULL` | +| **TC-VOLLOCK-009** | fail-open 之后 `release` 无害:`osMutexRelease` **未被调用**(判空静默返回) | +| **TC-VOLLOCK-010** | 已创建时多次 `wait` **不重复创建**(`osMutexNew` 恒 1 次);每次 `wait` 各等待一次 | -> **TC-VL-008 是本套件存在的主要理由**:真机上需堆耗尽才可能触发,板端无法构造。 +> **TC-VOLLOCK-008 是本套件存在的主要理由**:真机上需堆耗尽才可能触发,板端无法构造。 ### 2.3 `vol_lock_release` — 释放与判空 | 用例 | 断言 | |---|---| -| **TC-VL-011** | 已持锁时 `release` 调用 `osMutexRelease` **一次** | -| **TC-VL-012** | 锁未创建时 `release` **静默返回**(不调用、不崩溃) | -| **TC-VL-013** | 完整周期 `init → wait → release → wait → release`:全程只创建 **1** 个互斥量、释放 **2** 次、第二次 `wait` 的 `timeout` 透传正确(100) | +| **TC-VOLLOCK-011** | 已持锁时 `release` 调用 `osMutexRelease` **一次** | +| **TC-VOLLOCK-012** | 锁未创建时 `release` **静默返回**(不调用、不崩溃) | +| **TC-VOLLOCK-013** | 完整周期 `init → wait → release → wait → release`:全程只创建 **1** 个互斥量、释放 **2** 次、第二次 `wait` 的 `timeout` 透传正确(100) | **当前结果**:33/33 PASSED(`failed=0`)。 diff --git a/docs/测试说明/存储维护与容量恢复.md b/docs/测试说明/存储维护与容量恢复.md index e31d6d94..66b1b7f6 100644 --- a/docs/测试说明/存储维护与容量恢复.md +++ b/docs/测试说明/存储维护与容量恢复.md @@ -36,12 +36,12 @@ 5. 确认日志: ``` - === Storage Test: TC-STO-04 maintenance (recovery / full wipe) === - [PASS] TC-STO-04 bbt rebuild + === Storage Test: TC-STORAGE-04 maintenance (recovery / full wipe) === + [PASS] TC-STORAGE-04 bbt rebuild wipe progress: ... 2044/2044 wiped 2044 blocks (N skipped as bad, 2044 visible) - [PASS] TC-STO-04 full wipe (2044 blocks erased) - [PASS] TC-STO-04 persisted BBT version=N + [PASS] TC-STORAGE-04 full wipe (2044 blocks erased) + [PASS] TC-STORAGE-04 persisted BBT version=N === Storage Recovery: 3/3 PASSED (failed=0) === ``` diff --git a/docs/测试说明/实机测试实施指南.md b/docs/测试说明/实机测试实施指南.md index 63ba82e6..fd07c083 100644 --- a/docs/测试说明/实机测试实施指南.md +++ b/docs/测试说明/实机测试实施指南.md @@ -329,7 +329,7 @@ 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-STO-06`)。差异清单已收敛为 +4 处"代码有、文档无":`TC-GD5F-1100/1101/1102`、`TC-STORAGE-06`)。差异清单已收敛为 可追踪项,后续按需补登记;**暂不升门禁**(与 §8.2 目标一致)。 ### 8.3 待核实项:`TEST_SUITE_SELECTED` 未含 `TEST_SUITE_RTC` · ✅ 已核实(非缺陷) diff --git a/docs/测试说明/时间同步单元测试说明.md b/docs/测试说明/时间同步单元测试说明.md index 46b030df..b567bd0d 100644 --- a/docs/测试说明/时间同步单元测试说明.md +++ b/docs/测试说明/时间同步单元测试说明.md @@ -127,52 +127,52 @@ test/host/time_sync/time_sync_test.c > 命名 `TC-TS-NNN`(TS = Time Sync)。断言数(80)多于用例数(27),因为每个用例通常 > 包含 2~9 条子断言(后缀 `b` / `c` …)。桩状态在每用例前由 `fakes_reset()` 复位。 -### 2.1 `time_sync_delay_fed` — 分片喂心跳延时(TC-TS-001..006) +### 2.1 `time_sync_delay_fed` — 分片喂心跳延时(TC-TIMESYNC-001..006) | 用例 | 断言 | |---|---| -| **TC-TS-001** | `delay_fed(0)` 既不睡眠也不喂狗(零开销快路径) | -| **TC-TS-002** | 恰好一片(50ms):1 次 `vTaskDelay(50)` + 1 次心跳 | -| **TC-TS-003** | 非整片(120ms)切成 **50 / 50 / 20** 三片,每片喂一次心跳 | -| **TC-TS-004** | 长延时(2000ms)= **40 片 × 50ms**,每片喂心跳(监听退避路径) | -| **TC-TS-005** | 不足一片(49ms)单片处理,**不**被拆成 0 | -| **TC-TS-006** | 总预算 30s = **600 片**,片长上限**恒** 50ms | +| **TC-TIMESYNC-001** | `delay_fed(0)` 既不睡眠也不喂狗(零开销快路径) | +| **TC-TIMESYNC-002** | 恰好一片(50ms):1 次 `vTaskDelay(50)` + 1 次心跳 | +| **TC-TIMESYNC-003** | 非整片(120ms)切成 **50 / 50 / 20** 三片,每片喂一次心跳 | +| **TC-TIMESYNC-004** | 长延时(2000ms)= **40 片 × 50ms**,每片喂心跳(监听退避路径) | +| **TC-TIMESYNC-005** | 不足一片(49ms)单片处理,**不**被拆成 0 | +| **TC-TIMESYNC-006** | 总预算 30s = **600 片**,片长上限**恒** 50ms | -### 2.2 `time_sync_open_listener` — 监听建立与退避(TC-TS-010..015) +### 2.2 `time_sync_open_listener` — 监听建立与退避(TC-TIMESYNC-010..015) | 用例 | 断言 | |---|---| -| **TC-TS-010** | 首次成功:`socket` / `bind` / `listen` 各 1 次;端口经 `net_htons(8888)`;`sin_family` = `NET_AF_INET`;成功路径**无退避延时** | -| **TC-TS-011** | `bind` 失败 → **关闭该 socket** + 退避 2000ms(40 片)+ 留痕 `DBG_ERROR`,随后重试成功 | -| **TC-TS-012** | `listen` 失败 → 关闭该 socket + 退避 2000ms,随后重试成功 | -| **TC-TS-013** | `socket` 连续失败 → **5 次后返回 -1**;5 条 `DBG_ERROR`;5 × 500ms 退避(50 片) | -| **TC-TS-014** | 第 3 次重试成功并返回**新**描述符;恰好尝试 3 次;两次失败退避 500ms × 2 | -| **TC-TS-015** | 心跳总次数 = 每轮重试(5)+ 每片延时(50);**心跳位恒为 `TASK_WD_TIMESYNC`** | +| **TC-TIMESYNC-010** | 首次成功:`socket` / `bind` / `listen` 各 1 次;端口经 `net_htons(8888)`;`sin_family` = `NET_AF_INET`;成功路径**无退避延时** | +| **TC-TIMESYNC-011** | `bind` 失败 → **关闭该 socket** + 退避 2000ms(40 片)+ 留痕 `DBG_ERROR`,随后重试成功 | +| **TC-TIMESYNC-012** | `listen` 失败 → 关闭该 socket + 退避 2000ms,随后重试成功 | +| **TC-TIMESYNC-013** | `socket` 连续失败 → **5 次后返回 -1**;5 条 `DBG_ERROR`;5 × 500ms 退避(50 片) | +| **TC-TIMESYNC-014** | 第 3 次重试成功并返回**新**描述符;恰好尝试 3 次;两次失败退避 500ms × 2 | +| **TC-TIMESYNC-015** | 心跳总次数 = 每轮重试(5)+ 每片延时(50);**心跳位恒为 `TASK_WD_TIMESYNC`** | -### 2.3 `time_sync_handle_conn` — 时间包重组状态机(TC-TS-020..029) +### 2.3 `time_sync_handle_conn` — 时间包重组状态机(TC-TIMESYNC-020..029) | 用例 | 断言 | |---|---| -| **TC-TS-020** | 8 字节一次收齐 → **大端**解析 epoch + 更新墙钟 1 次 + 关连接;首次请求 16 字节;单次等待片长 = 50ms;留痕 `wall clock updated` | -| **TC-TS-021** | 分段送达(4+4)→ 累积后解析正确;读了两次;第二次**只请求剩余 12 字节**;每片 50ms | -| **TC-TS-022** | 一次到达 16 字节 → **只取前 8 字节**;一次读够即停 | -| **TC-TS-023** | 前缀非 `"TIME"` → **不更新墙钟**,但仍关闭连接 | -| **TC-TS-024** | 对端关闭(`n == 0`)→ 立即退出、不解析;关闭连接 | -| **TC-TS-025** | 真错误(`n == -1`)→ 立即退出、不解析 | -| **TC-TS-026** | 只收到 4 字节后 EOF → **不足 8 字节不解析**;期间继续等待后续字节 | -| **TC-TS-027** | 30s 预算耗尽 → 不再读(只读 1 次)+ 留痕 `no TIME packet in 30s, drop conn` + 关连接 | -| **TC-TS-028** | 剩余预算不足一片 → **末片按剩余(20ms)切分** | -| **TC-TS-029** | **32 位 tick 回绕** → 预算计算仍正确(无符号减法) | +| **TC-TIMESYNC-020** | 8 字节一次收齐 → **大端**解析 epoch + 更新墙钟 1 次 + 关连接;首次请求 16 字节;单次等待片长 = 50ms;留痕 `wall clock updated` | +| **TC-TIMESYNC-021** | 分段送达(4+4)→ 累积后解析正确;读了两次;第二次**只请求剩余 12 字节**;每片 50ms | +| **TC-TIMESYNC-022** | 一次到达 16 字节 → **只取前 8 字节**;一次读够即停 | +| **TC-TIMESYNC-023** | 前缀非 `"TIME"` → **不更新墙钟**,但仍关闭连接 | +| **TC-TIMESYNC-024** | 对端关闭(`n == 0`)→ 立即退出、不解析;关闭连接 | +| **TC-TIMESYNC-025** | 真错误(`n == -1`)→ 立即退出、不解析 | +| **TC-TIMESYNC-026** | 只收到 4 字节后 EOF → **不足 8 字节不解析**;期间继续等待后续字节 | +| **TC-TIMESYNC-027** | 30s 预算耗尽 → 不再读(只读 1 次)+ 留痕 `no TIME packet in 30s, drop conn` + 关连接 | +| **TC-TIMESYNC-028** | 剩余预算不足一片 → **末片按剩余(20ms)切分** | +| **TC-TIMESYNC-029** | **32 位 tick 回绕** → 预算计算仍正确(无符号减法) | -### 2.4 `time_sync_task` — 任务主循环(TC-TS-040..044) +### 2.4 `time_sync_task` — 任务主循环(TC-TIMESYNC-040..044) | 用例 | 断言 | |---|---| -| **TC-TS-040** | `sys_evtHandle == NULL` → **跳过就绪屏障**;`accept` 轮询 3 次(2 次无连接 + 1 次成功);收到时间包并更新墙钟;延时片数 = 4+4+1(200+200+50ms)且**全部按 50ms 分片**;心跳次数 = 主循环 1 + 退避 8 + 收连接 1 + 收尾 1 + 次轮 1 = **13**;所有心跳均打 `TASK_WD_TIMESYNC` 位 | -| **TC-TS-041** | 就绪屏障轮询 3 次(2 次未就绪 + 1 次就绪);屏障等待按 **100ms 分片**;等待 `SYS_EVT_NET_READY` 位;`osFlagsWaitAny \| osFlagsNoClear`(**就绪位不被消费**);未就绪的两次各喂一次心跳;仍先 `task_wd_bind` 登记心跳路由 | -| **TC-TS-042** | 屏障等待 4 次均未就绪 → **循环未挂死**(跳出并继续);每次未就绪后各喂一次心跳(2026-10-02 台架根因的**回归防线**) | -| **TC-TS-043** | 网络代次变化 → **关闭旧监听**并重监听;留痕 `network re-init, relisten`(另含 2 条 listen 成功);每次循环只轮询一次 `accept` 即放弃 | -| **TC-TS-044** | 监听建立失败 → 内部重试 5 次后放弃;6 条 `DBG_ERROR`(5 条 `net_socket FAIL` + 1 条 `retry later`);退避 5×500ms + 2000ms = **90 片**;心跳次数 = 2 + 5 + 50 + 40 = **97**;所有心跳均打 `TIMESYNC` 位 | +| **TC-TIMESYNC-040** | `sys_evtHandle == NULL` → **跳过就绪屏障**;`accept` 轮询 3 次(2 次无连接 + 1 次成功);收到时间包并更新墙钟;延时片数 = 4+4+1(200+200+50ms)且**全部按 50ms 分片**;心跳次数 = 主循环 1 + 退避 8 + 收连接 1 + 收尾 1 + 次轮 1 = **13**;所有心跳均打 `TASK_WD_TIMESYNC` 位 | +| **TC-TIMESYNC-041** | 就绪屏障轮询 3 次(2 次未就绪 + 1 次就绪);屏障等待按 **100ms 分片**;等待 `SYS_EVT_NET_READY` 位;`osFlagsWaitAny \| osFlagsNoClear`(**就绪位不被消费**);未就绪的两次各喂一次心跳;仍先 `task_wd_bind` 登记心跳路由 | +| **TC-TIMESYNC-042** | 屏障等待 4 次均未就绪 → **循环未挂死**(跳出并继续);每次未就绪后各喂一次心跳(2026-10-02 台架根因的**回归防线**) | +| **TC-TIMESYNC-043** | 网络代次变化 → **关闭旧监听**并重监听;留痕 `network re-init, relisten`(另含 2 条 listen 成功);每次循环只轮询一次 `accept` 即放弃 | +| **TC-TIMESYNC-044** | 监听建立失败 → 内部重试 5 次后放弃;6 条 `DBG_ERROR`(5 条 `net_socket FAIL` + 1 条 `retry later`);退避 5×500ms + 2000ms = **90 片**;心跳次数 = 2 + 5 + 50 + 40 = **97**;所有心跳均打 `TIMESYNC` 位 | **当前结果**:80/80 PASSED(`failed=0`)。 @@ -200,7 +200,7 @@ test/host/time_sync/time_sync_test.c **取舍**:这比"把循环体抽成可测函数"更贴近真实——**测的就是任务主体本身**, 不需要为了可测性改动生产代码结构。代价是**必须精确设定跳出点**:跳出点设错 -(多一次或少一次桩调用)会导致断言数不符,`TC-TS-040` 的跳出点曾因此修正。 +(多一次或少一次桩调用)会导致断言数不符,`TC-TIMESYNC-040` 的跳出点曾因此修正。 ### 4.2 ⚠ C 的"暂定定义"会静默合并同名静态量 diff --git a/docs/测试说明/测试开发标准流程.md b/docs/测试说明/测试开发标准流程.md index 31fc09b2..fca9c53b 100644 --- a/docs/测试说明/测试开发标准流程.md +++ b/docs/测试说明/测试开发标准流程.md @@ -66,7 +66,7 @@ G0~G3 命令详见 §6 / §7;ui-verify 完整命令见 `UI_自动化测试流 | 对象 | 格式 | 现用示例 | |---|---|---| | 阶段 | `TM-{MOD}-{NN}` | TM-PHY-01 | -| 测试用例 | `TC-{MOD}-{NNN}` | `TC-NET-601`(CH395F)、`TC-GD5F-205`、`TC-STO-03`、`TC-RTC-002` | +| 测试用例 | `TC-{MOD}-{NNN}` | `TC-NET-601`(CH395F)、`TC-GD5F-205`、`TC-STORAGE-03`、`TC-RTC-002` | | 设计原则 | `DP-{NN}` | DP-01(单连接 socket) | 模块缩写 `{MOD}` 在新模块测试文档立文档时确定(2~4 个大写字母);现有:`NET`=CH395F 网络、`GD5F`、`STO`=存储、`RTC`、`ADC`、`RS485`。 @@ -101,7 +101,7 @@ flowchart TD | 套件 | 宏 | 文件 | 阶段组织 | 备注 | |---|---|---|---|---| | CH395F | `TEST_SUITE_CH395F` | `ch395f_test.h/.c` + `net_test_task.c` | 硬件层 1~5 / NET 层 6~11 | 两层互斥(`#error`);阶段 2/3/4/5 与 6/7/8/10/11 需 PC 端配合 | -| STORAGE | `TEST_SUITE_STORAGE` | `storage_test.h` + `storage_test_task.c` | FTL + FatFS 集成(TC-STO-01~04) | 恢复测试(重建 BBT)默认关闭 | +| STORAGE | `TEST_SUITE_STORAGE` | `storage_test.h` + `storage_test_task.c` | FTL + FatFS 集成(TC-STORAGE-01~04) | 恢复测试(重建 BBT)默认关闭 | | GD5F | `TEST_SUITE_GD5F` | `gd5f_test.h` + `gd5f_test_task.c` | 10 阶段(选中时自动全开) | NAND 驱动全覆盖 | | RTC | `TEST_SUITE_RTC` | `sd2506_test.h` + `sd2506_test_task.c` | 阶段 1 基本 / 阶段 2 API(默认全开) | SD2506 RTC | @@ -598,7 +598,7 @@ CI 就静默停摆(2026-10-11 实测 run 16~21 共 12 个 job 零日志)。 | `test_common.h` | **板端测试公共断言内核**(`test_stats_t` + `TEST_CHECK_IMPL`/`TEST_REPORT_IMPL`) | | `ch395f_test.h` / `ch395f_test_task.c` | CH395F 套件:阶段开关、断言宏、Phase 1~5 实现 | | `net_test_task.h` / `net_test_task.c` | CH395F 套件 NET 层(6~11):TCP 监听循环 / Client 主动连接测试 | -| `storage_test.h` / `storage_test_task.c` | STORAGE 套件:FTL + FatFS 集成(TC-STO-01~04)+ 恢复测试 | +| `storage_test.h` / `storage_test_task.c` | STORAGE 套件:FTL + FatFS 集成(TC-STORAGE-01~04)+ 恢复测试 | | `gd5f_test.h` / `gd5f_test_task.c` | GD5F 套件:NAND 驱动 10 阶段 | | `sd2506_test.h` / `sd2506_test_task.c` | RTC 套件:SD2506 RTC 2 阶段组 | | `run_boot_test.py` / `verify_log.py` + `serial_tool` | 自动化闭环三件套(纯 Python 标准库 / 仓库内置) | diff --git a/docs/测试说明/测试文档模板规范.md b/docs/测试说明/测试文档模板规范.md index 2282de70..38786f20 100644 --- a/docs/测试说明/测试文档模板规范.md +++ b/docs/测试说明/测试文档模板规范.md @@ -157,7 +157,7 @@ TC-{MOD}-{NNN} ``` - **分阶段套件**:序号**百位放阶段号**,编号即自文档化——`TC-NET-101` = CH395F Phase 1 第 1 项、`TC-NET-601` = Phase 6 第 1 项、`TC-NET-1101` = Phase 11 第 1 项; -- **无阶段划分套件**:全局顺序编号(如 `TC-STO-03`、`TC-RTC-001`); +- **无阶段划分套件**:全局顺序编号(如 `TC-STORAGE-03`、`TC-RTC-001`); - 编号不复用:废弃用例保留编号并注明"已废弃"。 ### 6.4 设计原则 ID diff --git a/docs/测试说明/相量层单元测试说明.md b/docs/测试说明/相量层单元测试说明.md index 27b19f4c..1e14f403 100644 --- a/docs/测试说明/相量层单元测试说明.md +++ b/docs/测试说明/相量层单元测试说明.md @@ -50,7 +50,7 @@ test/host/phasor/phasor_test.c - **`fAmSQ = √(fRe² + fIm²)` 直接就是有效值(RMS)**,无需再除 √2; - `fAm = √2 · fAmSQ` 是正弦峰值。 -判据是归一化恒等式 **`Σsin² = Σcos² = 1/N`**(`TC-PH-001/002` 逐项校验,防转录错)。 +判据是归一化恒等式 **`Σsin² = Σcos² = 1/N`**(`TC-PHASOR-001/002` 逐项校验,防转录错)。 术语权威见 `docs/算法/继电保护功能复现规划.md` §10.2: `{fRe, fIm, fAm, fAmSQ}` = 实部 / 虚部 / **幅值** / **有效值**。 @@ -100,62 +100,62 @@ test/host/phasor/phasor_test.c | 用例 | 断言 | 设计点 | |---|---|---| -| **TC-PH-001** | 逐项:`sin[k] == sin(2πk/N)·(√2/N)`、`cos[k] == cos(2πk/N)·(√2/N)`(k = 0..19) | L2-1 防转录错 | -| **TC-PH-002** | 归一化 `Σsin² == Σcos² == 1/N`;精确零点 `sin@0,10`、`cos@5,15`;`sin[5] == √2/N` | L2-1 判据基础 | +| **TC-PHASOR-001** | 逐项:`sin[k] == sin(2πk/N)·(√2/N)`、`cos[k] == cos(2πk/N)·(√2/N)`(k = 0..19) | L2-1 防转录错 | +| **TC-PHASOR-002** | 归一化 `Σsin² == Σcos² == 1/N`;精确零点 `sin@0,10`、`cos@5,15`;`sin[5] == √2/N` | L2-1 判据基础 | ### 2.2 L2-3 / L2-4 基波幅值 / 有效值 / 相位 | 用例 | 断言 | 设计点 | |---|---|---| -| **TC-PH-003** | 纯基波:`fAmSQ == A/√2`(**有效值**)、`fAm == √2·fAmSQ`(幅值),误差 ≤ 1% | L2-3 | -| **TC-PH-004** | `atan2(fIm, fRe)` == 注入相角(6 组幅值 / 相位) | L2-4 | +| **TC-PHASOR-003** | 纯基波:`fAmSQ == A/√2`(**有效值**)、`fAm == √2·fAmSQ`(幅值),误差 ≤ 1% | L2-3 | +| **TC-PHASOR-004** | `atan2(fIm, fRe)` == 注入相角(6 组幅值 / 相位) | L2-4 | ### 2.3 直流与谐波抑制 / 任意次谐波提取 | 用例 | 断言 | 设计点 | |---|---|---| -| **TC-PH-005** | 直流 + 2 / 3 / 5 次谐波被**完全滤除**(基波读数不变,误差 ≤ 1%,5 例) | L2-1 | -| **TC-PH-006** | 任意次谐波提取(**索引步进 = 谐波次数**):k = 1 / 2 / 5 从混合信号中提取;纯基波下 2 / 5 次分量 ≈ 0 | L2-1 / L1-9 入口 | +| **TC-PHASOR-005** | 直流 + 2 / 3 / 5 次谐波被**完全滤除**(基波读数不变,误差 ≤ 1%,5 例) | L2-1 | +| **TC-PHASOR-006** | 任意次谐波提取(**索引步进 = 谐波次数**):k = 1 / 2 / 5 从混合信号中提取;纯基波下 2 / 5 次分量 ≈ 0 | L2-1 / L1-9 入口 | ### 2.4 频率敏感度 | 用例 | 断言 | 设计点 | |---|---|---| -| **TC-PH-007** | 幅值误差:50 Hz ≤ 0.1%、±1 Hz ≤ 1.5%、±2 Hz ≤ 3%(**最坏相位**) | L2-3 / L1-7 依据 | +| **TC-PHASOR-007** | 幅值误差:50 Hz ≤ 0.1%、±1 Hz ≤ 1.5%、±2 Hz ≤ 3%(**最坏相位**) | L2-3 / L1-7 依据 | ### 2.5 L2 输入采样环(`sample_ring.c`) | 用例 | 断言 | 设计点 | |---|---|---| -| **TC-PH-010** | `init` 清填充与帧计数;未攒满取窗 → -2;入环后取窗**按时序**(老 → 新);通道之间**互相独立**;填充量饱和于 `DEPTH` 但帧计数**不**饱和;回绕后取窗 == 最后 N 个值(有序);参数守卫:`n=0` / `n>DEPTH` / 越界通道 / `NULL out` / `NULL frame` / 错帧长 均拒绝 | L2 输入 | +| **TC-PHASOR-010** | `init` 清填充与帧计数;未攒满取窗 → -2;入环后取窗**按时序**(老 → 新);通道之间**互相独立**;填充量饱和于 `DEPTH` 但帧计数**不**饱和;回绕后取窗 == 最后 N 个值(有序);参数守卫:`n=0` / `n>DEPTH` / 越界通道 / `NULL out` / `NULL frame` / 错帧长 均拒绝 | L2 输入 | ### 2.6 L2-2 实例层 | 用例 | 断言 | 设计点 | |---|---|---| -| **TC-PH-020** | 实例数 == 5;实例表可取 `name`;越界实例 → `NULL`;未攒满一周波 `phasor_get()` → -2;越界 index / `NULL out` → -1;攒满 20 帧后 `get()` == 0 且实例 0 的 RMS == `A/√2`;谐波实例(`C04-IA-F2` / `C05-IA-F5`)在纯基波下 ≈ 0;**逐实例复核"实例窗 == 独立 `phasor_calc()` 结果"** | L2-2 | +| **TC-PHASOR-020** | 实例数 == 5;实例表可取 `name`;越界实例 → `NULL`;未攒满一周波 `phasor_get()` → -2;越界 index / `NULL out` → -1;攒满 20 帧后 `get()` == 0 且实例 0 的 RMS == `A/√2`;谐波实例(`C04-IA-F2` / `C05-IA-F5`)在纯基波下 ≈ 0;**逐实例复核"实例窗 == 独立 `phasor_calc()` 结果"** | L2-2 | ### 2.7 L2-6 滑动窗 | 用例 | 断言 | 设计点 | |---|---|---| -| **TC-PH-021** | 连续滑动 20 拍,基波读数**恒定**(误差 ≤ 1%) | L2-6 | +| **TC-PHASOR-021** | 连续滑动 20 拍,基波读数**恒定**(误差 ≤ 1%) | L2-6 | ### 2.8 L2-7 双区指针原子交换 | 用例 | 断言 | 设计点 | |---|---|---| -| **TC-PH-022** | 使用区逐次产出**交替** 0 → 1 → 0 → 1;**连测 60 拍**:每拍 `get()` == 当前环窗的独立重算(幅值每 20 拍在 100 / 10 之间切换 → 读到陈旧区会立刻不相等);扫描后结果仍可读 | L2-7 | +| **TC-PHASOR-022** | 使用区逐次产出**交替** 0 → 1 → 0 → 1;**连测 60 拍**:每拍 `get()` == 当前环窗的独立重算(幅值每 20 拍在 100 / 10 之间切换 → 读到陈旧区会立刻不相等);扫描后结果仍可读 | L2-7 | ### 2.9 `phasor_zero` / `phasor_init` 清零与幂等 | 用例 | 断言 | 设计点 | |---|---|---| -| **TC-PH-030** | 直接白盒调 `phasor_zero()` → 四字段(含 `fAm` / `fAmSQ`)全清零 | 静态辅助 | -| **TC-PH-031** | 先把双区写脏 → `phasor_init()` 后**双区全零** | init 清零 | -| **TC-PH-032** | `phasor_init()` 后使用区复位为 0 | init 复位 | -| **TC-PH-033** | `phasor_init()` 后就绪标志清(`phasor_get()` → -2) | init 复位 | -| **TC-PH-034** | 重复 `phasor_init()` 幂等 | 可重复调用 | +| **TC-PHASOR-030** | 直接白盒调 `phasor_zero()` → 四字段(含 `fAm` / `fAmSQ`)全清零 | 静态辅助 | +| **TC-PHASOR-031** | 先把双区写脏 → `phasor_init()` 后**双区全零** | init 清零 | +| **TC-PHASOR-032** | `phasor_init()` 后使用区复位为 0 | init 复位 | +| **TC-PHASOR-033** | `phasor_init()` 后就绪标志清(`phasor_get()` → -2) | init 复位 | +| **TC-PHASOR-034** | 重复 `phasor_init()` 幂等 | 可重复调用 | **当前结果**:57/57 PASSED(`failed=0`)。 @@ -178,7 +178,7 @@ test/host/phasor/phasor_test.c 每来一个新点,`phasor_run()` 对 20 点**整体重算**(滑动窗)。迭代法(加减首尾项)会累积 浮点误差且难以保证与"整体重算"逐位一致;暴力法的代价是每拍 `N × 实例数` 次乘加 + 取模, -在 1 ms 节拍下仍有余量。本单测的 `TC-PH-022`(每拍 `get()` == 独立重算)正是这条取舍的 +在 1 ms 节拍下仍有余量。本单测的 `TC-PHASOR-022`(每拍 `get()` == 独立重算)正是这条取舍的 **回归防线**——一旦有人改成迭代法,逐位一致性断言会立刻失败。 ### 4.2 主机侧合成波形**不代表真实硬件** diff --git a/docs/测试说明/看门狗单元测试说明.md b/docs/测试说明/看门狗单元测试说明.md index 897d41d6..d06f5acd 100644 --- a/docs/测试说明/看门狗单元测试说明.md +++ b/docs/测试说明/看门狗单元测试说明.md @@ -103,21 +103,21 @@ test/host/watchdog/watchdog_test.c | 用例 | 断言 | 验证的设计点 | |---|---|---| -| **TC-WD-001** | 未启动时 `poll` 不喂狗、`is_armed()==0` | 启动前不判定(`s_started` 门卫) | -| **TC-WD-016** | 未启动时即使全员置位也不喂、不更新 `last_mask` | 同上(位图无关) | -| **TC-WD-014** | 重复 `task_wd_start()` 只启动 IWDG 一次 | 启动幂等(IWDG 不可逆,重复启动无意义) | -| **TC-WD-015** | `start` 内部先喂一次(`feed_count==1`) | 首个抽样窗口从启动时刻起算,避免启动即超时 | -| **TC-WD-002** | 50 ms 内 `poll` 不喂;累计 100 ms 喂 1 次 | 100 ms 抽样节流 | -| **TC-WD-003** | 全员置位 → 喂狗 1 次;`last_mask==0x37` | 全员到位判定 + 掩码取值 | -| **TC-WD-004** | 不重新置位则第二轮不喂 | **取走清零**语义(旧位不残留) | -| **TC-WD-005** | 缺 UI(bit4)→ 不喂;`last_mask` 精确记录缺失位 | 必需掩码比较 + 缺失定位 | -| **TC-WD-006** | 连续 1..7 次缺席不报;**第 8 次**打 `[WD] task stall`;缺席期间不喂 | `WD_MISS_TOLERANCE=8`(800 ms)停喂触发点 | -| **TC-WD-007** | 停喂后**每 100 ms 复报**一条 stall(现状行为) | 见 §4 已知行为("最后遗言"持续到复位) | -| **TC-WD-008** | 恢复全员到位 → 立即喂狗 + `streak` 归零 | 停顿可恢复(非锁死状态机) | -| **TC-WD-009** | 99 ms 不判 / 100 ms 判 / 再 99 ms 不判 / 累计 100 ms 判 | 节流窗口**边界**(易错点) | -| **TC-WD-010** | `tick` 跨 2^32 回绕后 100 ms 仍正确判 | 无符号差比较(回绕安全) | -| **TC-WD-011** | `is_armed`/`last_mask`/`miss_count` 语义 | 观测接口正确性 | -| **TC-WD-013** | 非法任务 ID(`>= TASK_WD_ID_MAX`)被忽略,不污染位图 | 防位图越界(`task_wd_beat` 的守卫) | +| **TC-WATCHDOG-001** | 未启动时 `poll` 不喂狗、`is_armed()==0` | 启动前不判定(`s_started` 门卫) | +| **TC-WATCHDOG-016** | 未启动时即使全员置位也不喂、不更新 `last_mask` | 同上(位图无关) | +| **TC-WATCHDOG-014** | 重复 `task_wd_start()` 只启动 IWDG 一次 | 启动幂等(IWDG 不可逆,重复启动无意义) | +| **TC-WATCHDOG-015** | `start` 内部先喂一次(`feed_count==1`) | 首个抽样窗口从启动时刻起算,避免启动即超时 | +| **TC-WATCHDOG-002** | 50 ms 内 `poll` 不喂;累计 100 ms 喂 1 次 | 100 ms 抽样节流 | +| **TC-WATCHDOG-003** | 全员置位 → 喂狗 1 次;`last_mask==0x37` | 全员到位判定 + 掩码取值 | +| **TC-WATCHDOG-004** | 不重新置位则第二轮不喂 | **取走清零**语义(旧位不残留) | +| **TC-WATCHDOG-005** | 缺 UI(bit4)→ 不喂;`last_mask` 精确记录缺失位 | 必需掩码比较 + 缺失定位 | +| **TC-WATCHDOG-006** | 连续 1..7 次缺席不报;**第 8 次**打 `[WD] task stall`;缺席期间不喂 | `WD_MISS_TOLERANCE=8`(800 ms)停喂触发点 | +| **TC-WATCHDOG-007** | 停喂后**每 100 ms 复报**一条 stall(现状行为) | 见 §4 已知行为("最后遗言"持续到复位) | +| **TC-WATCHDOG-008** | 恢复全员到位 → 立即喂狗 + `streak` 归零 | 停顿可恢复(非锁死状态机) | +| **TC-WATCHDOG-009** | 99 ms 不判 / 100 ms 判 / 再 99 ms 不判 / 累计 100 ms 判 | 节流窗口**边界**(易错点) | +| **TC-WATCHDOG-010** | `tick` 跨 2^32 回绕后 100 ms 仍正确判 | 无符号差比较(回绕安全) | +| **TC-WATCHDOG-011** | `is_armed`/`last_mask`/`miss_count` 语义 | 观测接口正确性 | +| **TC-WATCHDOG-013** | 非法任务 ID(`>= TASK_WD_ID_MAX`)被忽略,不污染位图 | 防位图越界(`task_wd_beat` 的守卫) | **当前结果**:39/39 PASSED(`failed=0`)。 @@ -139,7 +139,7 @@ test/host/watchdog/watchdog_test.c ## 4. 已知行为与可优化点 -### 4.1 stall 日志在停喂后复报(TC-WD-007,现状) +### 4.1 stall 日志在停喂后复报(TC-WATCHDOG-007,现状) 实现(`task_watchdog.c`): @@ -153,7 +153,7 @@ if (s_miss_streak >= WD_MISS_TOLERANCE) { DBG_ERROR("[WD] task stall: ..."); } **评估**:这是**刻意的"最后遗言"**——复位前日志窗口内信息不丢。代价是日志冗余。 若改为"每停顿周期仅报一次",需加一个 `s_stall_reported` 标志(在 `streak` 归零时清除)。 -**当前保留现状**(单测按现状断言,行为变更须同步改 TC-WD-007 与本文)。 +**当前保留现状**(单测按现状断言,行为变更须同步改 TC-WATCHDOG-007 与本文)。 ### 4.2 测试隔离依赖 `task_wd_test_reset()` diff --git a/docs/测试说明/系统时钟单元测试说明.md b/docs/测试说明/系统时钟单元测试说明.md index 9e89cdda..d6d92bc3 100644 --- a/docs/测试说明/系统时钟单元测试说明.md +++ b/docs/测试说明/系统时钟单元测试说明.md @@ -105,27 +105,27 @@ test/host/sys_clock/sys_clock_test.c | 用例 | 断言 | 验证的设计点 | |---|---|---| -| **TC-CLK-000** | 未初始化时 `get()==UINT32_MAX`、`get_time()==-1`、`get_str()` 输出占位串 | "未初始化"哨兵语义(**必须最先跑**) | -| **TC-CLK-001** | RTC 合法 → `init()==0`,基准 = 换算 Unix 秒;不写回 RTC | 正常初始化路径 | -| **TC-CLK-002** | 2024-02-29 / 2000-02-29(世纪闰)换算正确;2/29→3/1 间隔恰 86400 s | 闰年规则(含世纪闰) | -| **TC-CLK-003** | 1/31、2/28、4/30 精确值;平年 2/28→3/1 间隔 86400 s | 月末边界 | -| **TC-CLK-004** | 2000-01-01 换算;2038-01-19 03:14:07 → `0x7FFFFFFF`;`set(0)` → 1970-01-01 | 世纪边界 / uint32 上限 | -| **TC-CLK-005** | RTC 读失败 → `init()==-1`,降级为编译期默认时间,打 `DBG_ERROR` | RTC 读故障降级 | -| **TC-CLK-006** | 年/月/日越界 → 自愈写回默认时间,`init()==0` | 越界自愈(启用默认值时) | -| **TC-CLK-020** | 越界 + 写回失败 → 降级默认时间,`init()==-1` | 组合故障降级 | -| **TC-CLK-007** | 越界 → 写回 RTC 一次,阴影 RTC 被修正,`init()==0` | 自愈写回 + 复验 | -| **TC-CLK-008** | 999ms 不变 / 1000ms +1s / 再 +2500ms 共 +3s | 正常推进 + 亚秒截断 | -| **TC-CLK-009** | +29 天线性推进(未达 30 天阈值,不触发再基准化) | 阈值下不触发 | -| **TC-CLK-010** | 30 天 + 1500ms → 值无损(+30 天 1 秒);再 +500ms 补足 1 秒 | **惰性再基准化** + 余数结转 | -| **TC-CLK-011** | 基准近 2^32,推进跨回绕 0x2000ms → +8s | tick 回绕(无符号差)安全 | -| **TC-CLK-012** | 10 天步进 ×9(累计 90 天,含 3 轮再基准)零漂移 | 长期运行无漂移 | -| **TC-CLK-013** | `get_str` 格式化 + 零点补零;未初始化占位串 | 字符串接口 | -| **TC-CLK-014** | 2026-10-02 08:09:10 → 年月日时分秒 + `week==5`(周五) | 日历字段 + 星期 | -| **TC-CLK-015** | `get_time(NULL) == -1` | NULL 参数防御 | -| **TC-CLK-016** | `set` 更新基准 + 写回 RTC;写失败仍更新基准 + 打错误 | set 两条路径 | -| **TC-CLK-017** | `set(..., NULL)` 不碰 RTC | 可选 RTC 写回 | -| **TC-CLK-018** | `set_unix` 写回 RTC,日历字段 + `week` 正确 | Unix 时间戳校时 | -| **TC-CLK-019** | 16 个已知日期(跨 1~12 月 / 世纪闰 / 闰日 / 范围首尾)星期对照 | **Zeller 全域正确性** | +| **TC-SYSCLK-000** | 未初始化时 `get()==UINT32_MAX`、`get_time()==-1`、`get_str()` 输出占位串 | "未初始化"哨兵语义(**必须最先跑**) | +| **TC-SYSCLK-001** | RTC 合法 → `init()==0`,基准 = 换算 Unix 秒;不写回 RTC | 正常初始化路径 | +| **TC-SYSCLK-002** | 2024-02-29 / 2000-02-29(世纪闰)换算正确;2/29→3/1 间隔恰 86400 s | 闰年规则(含世纪闰) | +| **TC-SYSCLK-003** | 1/31、2/28、4/30 精确值;平年 2/28→3/1 间隔 86400 s | 月末边界 | +| **TC-SYSCLK-004** | 2000-01-01 换算;2038-01-19 03:14:07 → `0x7FFFFFFF`;`set(0)` → 1970-01-01 | 世纪边界 / uint32 上限 | +| **TC-SYSCLK-005** | RTC 读失败 → `init()==-1`,降级为编译期默认时间,打 `DBG_ERROR` | RTC 读故障降级 | +| **TC-SYSCLK-006** | 年/月/日越界 → 自愈写回默认时间,`init()==0` | 越界自愈(启用默认值时) | +| **TC-SYSCLK-020** | 越界 + 写回失败 → 降级默认时间,`init()==-1` | 组合故障降级 | +| **TC-SYSCLK-007** | 越界 → 写回 RTC 一次,阴影 RTC 被修正,`init()==0` | 自愈写回 + 复验 | +| **TC-SYSCLK-008** | 999ms 不变 / 1000ms +1s / 再 +2500ms 共 +3s | 正常推进 + 亚秒截断 | +| **TC-SYSCLK-009** | +29 天线性推进(未达 30 天阈值,不触发再基准化) | 阈值下不触发 | +| **TC-SYSCLK-010** | 30 天 + 1500ms → 值无损(+30 天 1 秒);再 +500ms 补足 1 秒 | **惰性再基准化** + 余数结转 | +| **TC-SYSCLK-011** | 基准近 2^32,推进跨回绕 0x2000ms → +8s | tick 回绕(无符号差)安全 | +| **TC-SYSCLK-012** | 10 天步进 ×9(累计 90 天,含 3 轮再基准)零漂移 | 长期运行无漂移 | +| **TC-SYSCLK-013** | `get_str` 格式化 + 零点补零;未初始化占位串 | 字符串接口 | +| **TC-SYSCLK-014** | 2026-10-02 08:09:10 → 年月日时分秒 + `week==5`(周五) | 日历字段 + 星期 | +| **TC-SYSCLK-015** | `get_time(NULL) == -1` | NULL 参数防御 | +| **TC-SYSCLK-016** | `set` 更新基准 + 写回 RTC;写失败仍更新基准 + 打错误 | set 两条路径 | +| **TC-SYSCLK-017** | `set(..., NULL)` 不碰 RTC | 可选 RTC 写回 | +| **TC-SYSCLK-018** | `set_unix` 写回 RTC,日历字段 + `week` 正确 | Unix 时间戳校时 | +| **TC-SYSCLK-019** | 16 个已知日期(跨 1~12 月 / 世纪闰 / 闰日 / 范围首尾)星期对照 | **Zeller 全域正确性** | **当前结果**:100/100 PASSED(`failed=0`)。 @@ -145,7 +145,7 @@ test/host/sys_clock/sys_clock_test.c > > ⚠ **惰性再基准化的"正确用法"**:差值窗口必须恒 < 30 天。一次 `tick_advance` > 推进超过 ~49.7 天会让 `uint32_t diff` 溢出混叠——那是**调用方违约**(不是模块 -> 缺陷),测试应按 <30 天步长周期性调用 `get()`。见 TC-CLK-012 的注释。 +> 缺陷),测试应按 <30 天步长周期性调用 `get()`。见 TC-SYSCLK-012 的注释。 --- @@ -166,7 +166,7 @@ test/host/sys_clock/sys_clock_test.c | 目标状态 | 手段 | |---|---| -| **未初始化**(`UINT32_MAX`) | 只能靠 **进程首用例**(TC-CLK-000,在任何 `init`/`set` 之前)观测 | +| **未初始化**(`UINT32_MAX`) | 只能靠 **进程首用例**(TC-SYSCLK-000,在任何 `init`/`set` 之前)观测 | | **确定的已初始化状态** | `sys_clock_set(unix_secs, NULL)` —— 更新基准且**不碰 RTC**,是理想的隔离原语 | | **RTC 阴影态** | `rtc_set(...)` + `clear_obs()` 直接重置阴影寄存器与观测计数 | @@ -176,8 +176,8 @@ test/host/sys_clock/sys_clock_test.c ### 5.1 现象 -首次运行 TC-CLK-014/019 时,`2026-10-02`(真实为周五)返回 `week == 4`; -TC-CLK-019 的 16 个已知日期中,**仅 `2038-01-19` 正确**,其余 9 个(3~12 月) +首次运行 TC-SYSCLK-014/019 时,`2026-10-02`(真实为周五)返回 `week == 4`; +TC-SYSCLK-019 的 16 个已知日期中,**仅 `2038-01-19` 正确**,其余 9 个(3~12 月) 全错。 ### 5.2 根因 @@ -238,7 +238,7 @@ static uint8_t rtc_calc_week(uint16_t y, uint8_t m, uint8_t d) { /* m: 1-based ### 5.5 校验数据来源 -TC-CLK-019 的期望星期由 Python `datetime.date(...).weekday()` 独立生成 +TC-SYSCLK-019 的期望星期由 Python `datetime.date(...).weekday()` 独立生成 (`(weekday()+1) % 7` → 0=周日),**与被测实现算法正交**,避免"用错的算法 验证错的实现"。 diff --git a/docs/测试说明/配置文件单元测试说明.md b/docs/测试说明/配置文件单元测试说明.md index 27201587..fe6f8428 100644 --- a/docs/测试说明/配置文件单元测试说明.md +++ b/docs/测试说明/配置文件单元测试说明.md @@ -112,51 +112,51 @@ test/host/cfg_file/cfg_file_test.c | 用例 | 断言 | 验证的设计点 | |---|---|---| -| **TC-CFG-001** | UINT 1/2/4 字节往返(0 / 最大值);小端序(`0x1234` → `34 12`) | 小端编解码 | -| **TC-CFG-002** | UINT 非法:空 / 非数字 / 带后缀 / 超范围 / 负数 / len=3 | 严格校验 | -| **TC-CFG-003** | IP4:`0.0.0.0` / `255.255.255.255` / 常规;段数不足/超、>255、非数字、尾点、空 | 点分四段 | -| **TC-CFG-004** | MAC:`:` / `-` / `.` 三种分隔符、大小写;过短/过长/非十六进制/坏分隔符 | 分隔符 = **字节边界**替代 | -| **TC-CFG-005** | STR:正常 + NUL;恰好 `len-1` 放下;`len` 字符拒绝;空串 | 长度边界 | +| **TC-CONFIG-001** | UINT 1/2/4 字节往返(0 / 最大值);小端序(`0x1234` → `34 12`) | 小端编解码 | +| **TC-CONFIG-002** | UINT 非法:空 / 非数字 / 带后缀 / 超范围 / 负数 / len=3 | 严格校验 | +| **TC-CONFIG-003** | IP4:`0.0.0.0` / `255.255.255.255` / 常规;段数不足/超、>255、非数字、尾点、空 | 点分四段 | +| **TC-CONFIG-004** | MAC:`:` / `-` / `.` 三种分隔符、大小写;过短/过长/非十六进制/坏分隔符 | 分隔符 = **字节边界**替代 | +| **TC-CONFIG-005** | STR:正常 + NUL;恰好 `len-1` 放下;`len` 字符拒绝;空串 | 长度边界 | ### 2.2 INI 解析 | 用例 | 断言 | 验证的设计点 | |---|---|---| -| **TC-CFG-010** | `;` 与 `#` 注释、空行忽略 | 注释语义 | -| **TC-CFG-011** | LF-only 行结束符解析正常 | CRLF/LF 兼容 | -| **TC-CFG-012** | 段名/键名大小写无关;`=` 两侧与值两侧空白修剪 | 宽松匹配 | -| **TC-CFG-013** | 键值行 `=` 前后空白、值尾空白被修剪 | 值修剪 | -| **TC-CFG-014** | 未知键 / 未知段 / 缺失键 → 保留工厂默认,不崩溃 | 前向兼容 | -| **TC-CFG-014b** | 非法值 → 保留默认 + `DBG_ERROR` 留痕 | 无效键留痕 | -| **TC-CFG-015** | 段头之前的键值行被忽略 | 段作用域 | +| **TC-CONFIG-010** | `;` 与 `#` 注释、空行忽略 | 注释语义 | +| **TC-CONFIG-011** | LF-only 行结束符解析正常 | CRLF/LF 兼容 | +| **TC-CONFIG-012** | 段名/键名大小写无关;`=` 两侧与值两侧空白修剪 | 宽松匹配 | +| **TC-CONFIG-013** | 键值行 `=` 前后空白、值尾空白被修剪 | 值修剪 | +| **TC-CONFIG-014** | 未知键 / 未知段 / 缺失键 → 保留工厂默认,不崩溃 | 前向兼容 | +| **TC-CONFIG-014b** | 非法值 → 保留默认 + `DBG_ERROR` 留痕 | 无效键留痕 | +| **TC-CONFIG-015** | 段头之前的键值行被忽略 | 段作用域 | ### 2.3 段注册校验 | 用例 | 断言 | 验证的设计点 | |---|---|---| -| **TC-CFG-020** | 正常注册;重复段名拒绝;NULL 描述符 / NULL p_data 拒绝 | 参数防御 | -| **TC-CFG-021** | UINT len=3、MAC len≠6、STR len>79、key len=0 拒绝 | 键定义校验 | -| **TC-CFG-022** | 段名 ≥ `CFG_NAME_MAX`(16) 拒绝 | 段名长度 | -| **TC-CFG-023** | 挂回调段 `data_size > CFG_SNAP_MAX`(64) 拒绝;同段不挂回调则接受 | 回调段快照约束 | +| **TC-CONFIG-020** | 正常注册;重复段名拒绝;NULL 描述符 / NULL p_data 拒绝 | 参数防御 | +| **TC-CONFIG-021** | UINT len=3、MAC len≠6、STR len>79、key len=0 拒绝 | 键定义校验 | +| **TC-CONFIG-022** | 段名 ≥ `CFG_NAME_MAX`(16) 拒绝 | 段名长度 | +| **TC-CONFIG-023** | 挂回调段 `data_size > CFG_SNAP_MAX`(64) 拒绝;同段不挂回调则接受 | 回调段快照约束 | ### 2.4 load / save / poll 契约 | 用例 | 断言 | 验证的设计点 | |---|---|---| -| **TC-CFG-030** | 文件缺失 → 生成出厂模板写盘 + 返回 0;模板含段头与键 | 首启建文件 | -| **TC-CFG-031** | 文件存在 → 有效键进 RAM 副本 | 正常加载 | -| **TC-CFG-032** | 超长文件 → 工厂默认 + 重建模板 + 自检留痕 + 返回 0 | 损坏自愈 | -| **TC-CFG-033** | 读取失败 → 返回 -1,RAM 保持工厂默认 | 读故障 | -| **TC-CFG-034** | 未注册任何段 → 返回 -1 | 前置校验 | -| **TC-CFG-040** | 文件缺失 → 重建完整文档 | 整文档生成 | -| **TC-CFG-041** | 外科手术:保留注释/未知段/未知键,**受管键原位改写** | ⭐ 核心特性 | -| **TC-CFG-042** | 缺失受管段/键 → 文末补写 | 补写路径 | -| **TC-CFG-043** | 输出超长 → 拒绝保存(-1) + 原文件不动 + 自检留痕 | 溢出保护 | -| **TC-CFG-050** | 首轮 poll 建立基线,不重载 | 基线建立 | -| **TC-CFG-051/052** | 沉降去抖(连续 2 次稳定才重载);与基线一致不重载 | 去抖语义 | -| **TC-CFG-053** | 变更后重载 + 挂回调段差异触发回调 | 变更响应 | -| **TC-CFG-055** | `(size, mtime)` 令牌不变 → 不重载(令牌 = 变更信号) | 令牌契约 | -| **TC-CFG-054** | poll 检出超长 → 工厂默认 + 重建模板 + 留痕;**不触发回调** | 在线修复通道保留 | +| **TC-CONFIG-030** | 文件缺失 → 生成出厂模板写盘 + 返回 0;模板含段头与键 | 首启建文件 | +| **TC-CONFIG-031** | 文件存在 → 有效键进 RAM 副本 | 正常加载 | +| **TC-CONFIG-032** | 超长文件 → 工厂默认 + 重建模板 + 自检留痕 + 返回 0 | 损坏自愈 | +| **TC-CONFIG-033** | 读取失败 → 返回 -1,RAM 保持工厂默认 | 读故障 | +| **TC-CONFIG-034** | 未注册任何段 → 返回 -1 | 前置校验 | +| **TC-CONFIG-040** | 文件缺失 → 重建完整文档 | 整文档生成 | +| **TC-CONFIG-041** | 外科手术:保留注释/未知段/未知键,**受管键原位改写** | ⭐ 核心特性 | +| **TC-CONFIG-042** | 缺失受管段/键 → 文末补写 | 补写路径 | +| **TC-CONFIG-043** | 输出超长 → 拒绝保存(-1) + 原文件不动 + 自检留痕 | 溢出保护 | +| **TC-CONFIG-050** | 首轮 poll 建立基线,不重载 | 基线建立 | +| **TC-CONFIG-051/052** | 沉降去抖(连续 2 次稳定才重载);与基线一致不重载 | 去抖语义 | +| **TC-CONFIG-053** | 变更后重载 + 挂回调段差异触发回调 | 变更响应 | +| **TC-CONFIG-055** | `(size, mtime)` 令牌不变 → 不重载(令牌 = 变更信号) | 令牌契约 | +| **TC-CONFIG-054** | poll 检出超长 → 工厂默认 + 重建模板 + 留痕;**不触发回调** | 在线修复通道保留 | **当前结果**:139/139 PASSED(`failed=0`)。 @@ -213,7 +213,7 @@ test/host/cfg_file/cfg_file_test.c ### 5.1 现象 -`TC-CFG-041`(外科手术保存)首次运行即失败:对**已存在**的 `/config.ini` 调用 +`TC-CONFIG-041`(外科手术保存)首次运行即失败:对**已存在**的 `/config.ini` 调用 `cfg_file_save()`,即使 RAM 副本的值已改(如 `u8: 1 → 200`),落盘文件仍是 **原值** `u8 = 1`。 @@ -264,7 +264,7 @@ if (s_encode(p_key, ..., v, sizeof(v)) >= 0) { } ``` -修复后 `TC-CFG-041` / `TC-CFG-042` 转 PASS,`@build` 0 errors 0 warnings。 +修复后 `TC-CONFIG-041` / `TC-CONFIG-042` 转 PASS,`@build` 0 errors 0 warnings。 ### 5.5 建议后续动作 diff --git a/docs/编号规范.md b/docs/编号规范.md index c5270d6b..ed7fc15d 100644 --- a/docs/编号规范.md +++ b/docs/编号规范.md @@ -35,10 +35,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-STO-06`、`TC-AH-*`、`TC-PE-*`(前两项项目已在 `docs/测试说明/实机测试实施指南.md` 自行承认) | +| **孤儿编号(代码有、文档无)** | `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` 从未存在却被 `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-STO-03`(2 位)与 `TC-RTC-001`(3 位);`docs/测试说明/测试文档模板规范.md` §6.2 已废止 `PHY` 模块码,而阶段 ID 至今仍是 `TM-PHY-01` | +| **规范自身就不自洽** | `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` 全部裸奔 | > **可借鉴的先例**:`§N.M` 章节引用当年 1,578 处也全靠自觉,靠「紧邻写法 + 别名表 + 可判定比例 + 钩子」把可判定比例做到 58% 并转为拦提交([`docs/文档规范.md`](文档规范.md) §3.5)。编号走同一条路径即可收口。 @@ -291,22 +291,24 @@ | 码 | 模块(源文件/目录) | 码 | 模块 | |---|---|---|---| -| `NET` | `Drivers/BSP/CH395F` + `Drivers/BSP/NET` | `AI` | `App/algo/adc_input` | -| `GD5F` | `Drivers/BSP/GD5F2GQ5UE` | `AH` | `App/algo/adc_health` | -| `STO` | 存储栈(FTL + FatFs + `App/fs`) | `PH` | `App/algo/phasor` + `sample_ring` | -| `RTC` | `Drivers/BSP/SD2506` | `PS` | `App/algo/prot_set` | -| `ADC` | 采集节拍与通道映射(`Src/adc.c`、TIM3) | `PE` | `App/algo/prot_elm` | -| `RS485` | `Drivers/BSP/RS485` | `VL` | `App/fs/vol_lock` | -| `UI` | `Drivers/BSP/UI` | `TS` | `App/sync/time_sync` | -| `LOG` | `App/log` | `CLK` | `App/util/sys_clock` | -| `CFG` | `App/cfg` + `Drivers/BSP/NETCFG` | `WD` | `App/util/task_watchdog` | -| `SH` | `App/util/sha256` | `FA` | `Drivers/BSP/NET/lftpd` 鉴权 | -| `I104` | `App/protocol/iec104` | `TOOL` | PC 端工具(串口助手等) | +| `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 端工具(串口助手等) | > 废止码:`PHY`(→ `NET`)、`NAND`(→ `GD5F`)。历史文档不回改,新文档按本表。 --- + +> ⚠ **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 → 新号) ### 7.1 映射规则 @@ -331,8 +333,8 @@ | 审计模式 `P1~P9` | `PAT-01`~`PAT-09` | 正文冻结,新文档用新号 | | 保护 `R1~R8`、看门狗 `R1~R7` | 各文档 `RSK-01`… | 文档内编号 + 引用带文档名 | | 保护阶段 `P0~P5`、方案 `P0~P3` | 各文档 `ST-0`… | 与档位词 `P0` 解耦 | -| `TC-STO-01~06` | `TC-STO-001~006` | 补零 | -| `TC-AI-01A`/`02A`/`02B`/`02C`、`TC-VL-008b` | `TC-AI-001a`… / `TC-VL-008b` | 后缀统一小写字母,基号补零 | +| `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` | 加模块码 | @@ -343,7 +345,7 @@ | `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-STO-06` | 补进 `docs/测试说明/GD5F2GQ5UE_Test_Guide.md` | +| `TC-GD5F-1100/1101/1102`、`TC-STORAGE-06` | 补进 `docs/测试说明/GD5F2GQ5UE_Test_Guide.md` | | `TC-AH-*`、`TC-PE-*`、iec104 `TC-014/015/024` | 补单测说明文档(缺文档 = 追溯断链) | | `Trap 19` | 悬空引用,删除或改指实际条目 | @@ -400,7 +402,7 @@ git grep -n '<旧字面量>' # 零残留 | 编号字面量出现 | 8271 处 | | **可判定比例基线** | **82.6%**(6840 / 8271 = 82.70%,批 1 改名后重打,存进 `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-0n` 22 处、`Task #nn` 33 处、`Trap 空格形`+`陷阱 中文形` 43 处、`gen/round` 36 处、大写后缀 31 处) | +| 校验 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 处 | @@ -418,7 +420,7 @@ git grep -n '<旧字面量>' # 零残留 |---|---|---| | §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-STO-06` 属 §7.2 孤儿) | +| §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--` | `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]?` | @@ -430,6 +432,7 @@ git grep -n '<旧字面量>' # 零残留 | 批 | 日期 | 族 | 旧 → 新 | 处数 / 文件 | 别名 | |---|---|---|---|---|---| | **批 1** | 2026-10-20 | 代码规范条款 | `S1`~`S19` → `CODE-RULE-01`~`19` | 78 处 / 2 文件 | 18 条(scoped:`scripts/check_coding_standard.py`、`docs/代码规范/pre-commit使用说明.md`) | +| **批 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` 撞号事故。 diff --git a/scripts/check_ids.py b/scripts/check_ids.py index fcc7ae06..03e55e6c 100644 --- a/scripts/check_ids.py +++ b/scripts/check_ids.py @@ -63,7 +63,7 @@ TRACE_SCRIPT = REPO_ROOT / "scripts" / "check_test_traceability.py" # 候选池:任何「1~4 位大写字母 + 连字符 + 数字」先进来,再判是否登记过。 # 三段式(TC-NET-1501 / TRAP-NET-18)单独一条——中段可能含数字(GD5F), # 只用两段式正则会截出 "NET-1501" 这种假前缀。 -CAND_MOD = re.compile(r"(?(§7.1 统一为小写)" + "malformed": "大写后缀非法:§4.1 规定后缀只允许 -<小写字母>(§7.1 统一为小写)", + "module_code_note": "2026-10-20 批 2 模块码单词化后码长可达 9 位(ADCHEALTH/WATCHDOG),{0,4} 放宽到 {0,9};不放宽会让改名后的号整批从门禁眼里消失(实测漏 950 处)" }, { "name": "TC-NOMOD", @@ -431,7 +433,7 @@ "name": "TM", "class": "TM", "title": "测试阶段(§4.1 在册保留,模块码取 §6)", - "pattern": "\\bTM-[A-Z][A-Z0-9]{0,4}-[0-9]{2}\\b", + "pattern": "\\bTM-[A-Z][A-Z0-9]{0,9}-[0-9]{2}\\b", "owner_docs_glob": [ "docs/测试说明/*.md" ], @@ -452,7 +454,7 @@ "name": "DP", "class": "DP", "title": "测试设计原则(§4.1 目标形态带模块码)", - "pattern": "\\bDP-[A-Z][A-Z0-9]{0,4}-[0-9]{2}\\b", + "pattern": "\\bDP-[A-Z][A-Z0-9]{0,9}-[0-9]{2}\\b", "owner_docs_glob": [ "docs/测试说明/*.md" ], @@ -492,7 +494,7 @@ "name": "TRAP", "class": "TRAP", "title": "陷阱记录(§4.2 保留原号,历史证词高频锚点)", - "pattern": "\\bTRAP-[A-Z][A-Z0-9]{0,4}-[0-9]{2}\\b", + "pattern": "\\bTRAP-[A-Z][A-Z0-9]{0,9}-[0-9]{2}\\b", "owner_docs_glob": [ "docs/问题记录/*_Trap_Records.md" ], @@ -516,7 +518,7 @@ "name": "FEAT", "class": "FEAT", "title": "网络层功能/驱动改进项 F--(§4 总表缺这一族)", - "pattern": "\\bF-[A-Z][A-Z0-9]{0,3}-[0-9]{1,2}\\b", + "pattern": "\\bF-[A-Z][A-Z0-9]{0,9}-[0-9]{1,2}\\b", "owner_docs": [ "docs/网络/网络自愈架构设计.md" ], diff --git a/scripts/rename_ids.py b/scripts/rename_ids.py index 8619b198..58c72f22 100644 --- a/scripts/rename_ids.py +++ b/scripts/rename_ids.py @@ -88,12 +88,16 @@ def match_files(patterns, candidates): def render(template, groups): + """按模板渲染新号。**只有模板带格式说明符时**才把数字组转 int—— + 否则 `TC-PROTSET-011` 会被渲染成 `TC-PROTSET-11`(丢前导零,实测差点毁掉整批补零形态)。""" vals = {} for k, v in groups.items(): if v is None: vals[k] = "" + elif v.isdigit() and re.search(r"\{%s:[^}]+\}" % re.escape(k), template): + vals[k] = int(v) else: - vals[k] = int(v) if v.isdigit() else v + vals[k] = v return template.format(**vals) @@ -149,18 +153,20 @@ def merge_aliases(new_aliases, batch): """把本批 `旧号 → 新号` 并进 id_aliases.json,带 scope(同字面量多义的关键)。""" doc = json.loads(ALIASES_FILE.read_text(encoding="utf-8")) table = doc.setdefault("aliases", {}) - scope = [norm(x) for x in batch.get("files", [])] + # 已**完全限定**的字面量(如 `TC-PROTSET-011`)可以全局认别名;裸形(`S3`)必须带 scope + scope = [] if batch.get("global_alias") else [norm(x) for x in batch.get("files", [])] added = 0 for old, news in sorted(new_aliases.items()): scope_txt = ("旧号仅在本批 scope 内指向新号;scope 外同字面量属其它族,不受本条影响" - if scope else "全库生效(本批无 scope)") + if scope else "全库生效(本批字面量已完全限定,无歧义)") entry = { "to": sorted(news)[0] if len(news) == 1 else sorted(news), "status": "renamed", - "scope": scope, "note": "%s(scripts/rename_ids.py 批:族 %s)|%s" % (batch.get("note", "批量改名"), batch.get("family"), scope_txt), } + if scope: + entry["scope"] = scope cur = table.get(old) if cur is None: table[old] = entry diff --git a/scripts/rename_maps/batch2.json b/scripts/rename_maps/batch2.json new file mode 100644 index 00000000..94bbfbee --- /dev/null +++ b/scripts/rename_maps/batch2.json @@ -0,0 +1,25 @@ +{ + "schema": 1, + "batch": "批 2(模块码单词化,16 个有歧义的码)", + "applied_by": "scripts/rename_ids.py", + "record": "docs/编号规范.md §6 模块码表 + §8.3 迁移批次记录", + "note": "字面量已完全限定(TC-<旧码>-),故别名全局生效;裸形族才需要 scope", + "batches": [ + {"family": "TC-ADCIN", "old": "\\bTC-AI-(?P[0-9]{1,4}[a-zA-Z]?)\\b", "new": "TC-ADCIN-{n}", "global_alias": true, "files": ["*", "*/*", "*/*/*", "*/*/*/*", "*/*/*/*/*", "*/*/*/*/*/*"], "note": "批 2:模块码 AI → ADCIN(App/algo/adc_input;与 AH 只差一个字母)"}, + {"family": "TC-ADCHEALTH", "old": "\\bTC-AH-(?P[0-9]{1,4}[a-zA-Z]?)\\b", "new": "TC-ADCHEALTH-{n}", "global_alias": true, "files": ["*", "*/*", "*/*/*", "*/*/*/*", "*/*/*/*/*", "*/*/*/*/*/*"], "note": "批 2:模块码 AH → ADCHEALTH(App/algo/adc_health)"}, + {"family": "TC-PROTSET", "old": "\\bTC-PS-(?P[0-9]{1,4}[a-zA-Z]?)\\b", "new": "TC-PROTSET-{n}", "global_alias": true, "files": ["*", "*/*", "*/*/*", "*/*/*/*", "*/*/*/*/*", "*/*/*/*/*/*"], "note": "批 2:模块码 PS → PROTSET(App/algo/prot_set 保护定值)"}, + {"family": "TC-PROTELEM", "old": "\\bTC-PE-(?P[0-9]{1,4}[a-zA-Z]?)\\b", "new": "TC-PROTELEM-{n}", "global_alias": true, "files": ["*", "*/*", "*/*/*", "*/*/*/*", "*/*/*/*/*", "*/*/*/*/*/*"], "note": "批 2:模块码 PE → PROTELEM(App/algo/prot_elm 保护元件/判据)"}, + {"family": "TC-PHASOR", "old": "\\bTC-PH-(?P[0-9]{1,4}[a-zA-Z]?)\\b", "new": "TC-PHASOR-{n}", "global_alias": true, "files": ["*", "*/*", "*/*/*", "*/*/*/*", "*/*/*/*/*", "*/*/*/*/*/*"], "note": "批 2:模块码 PH → PHASOR(App/algo/phasor + sample_ring)"}, + {"family": "TC-TIMESYNC", "old": "\\bTC-TS-(?P[0-9]{1,4}[a-zA-Z]?)\\b", "new": "TC-TIMESYNC-{n}", "global_alias": true, "files": ["*", "*/*", "*/*/*", "*/*/*/*", "*/*/*/*/*", "*/*/*/*/*/*"], "note": "批 2:模块码 TS → TIMESYNC(App/sync/time_sync;TS 与 test suite / 时间戳 撞义)"}, + {"family": "TC-VOLLOCK", "old": "\\bTC-VL-(?P[0-9]{1,4}[a-zA-Z]?)\\b", "new": "TC-VOLLOCK-{n}", "global_alias": true, "files": ["*", "*/*", "*/*/*", "*/*/*/*", "*/*/*/*/*", "*/*/*/*/*/*"], "note": "批 2:模块码 VL → VOLLOCK(App/fs/vol_lock 卷锁)"}, + {"family": "TC-NANDPORT", "old": "\\bTC-NP-(?P[0-9]{1,4}[a-zA-Z]?)\\b", "new": "TC-NANDPORT-{n}", "global_alias": true, "files": ["*", "*/*", "*/*/*", "*/*/*/*", "*/*/*/*/*", "*/*/*/*/*/*"], "note": "批 2:模块码 NP → NANDPORT(dhara NAND 移植层;原名看不出是移植层)"}, + {"family": "TC-CONFIG", "old": "\\bTC-CFG-(?P[0-9]{1,4}[a-zA-Z]?)\\b", "new": "TC-CONFIG-{n}", "global_alias": true, "files": ["*", "*/*", "*/*/*", "*/*/*/*", "*/*/*/*/*", "*/*/*/*/*/*"], "note": "批 2:模块码 CFG → CONFIG(App/cfg + Drivers/BSP/NETCFG)"}, + {"family": "TC-SYSCLK", "old": "\\bTC-CLK-(?P[0-9]{1,4}[a-zA-Z]?)\\b", "new": "TC-SYSCLK-{n}", "global_alias": true, "files": ["*", "*/*", "*/*/*", "*/*/*/*", "*/*/*/*/*", "*/*/*/*/*/*"], "note": "批 2:模块码 CLK → SYSCLK(App/util/sys_clock;CLK 也泛指任何时钟信号)"}, + {"family": "TC-WATCHDOG", "old": "\\bTC-WD-(?P[0-9]{1,4}[a-zA-Z]?)\\b", "new": "TC-WATCHDOG-{n}", "global_alias": true, "files": ["*", "*/*", "*/*/*", "*/*/*/*", "*/*/*/*/*", "*/*/*/*/*/*"], "note": "批 2:模块码 WD → WATCHDOG(App/util/task_watchdog;WD 也读作『喂狗动作』)"}, + {"family": "TC-STORAGE", "old": "\\bTC-STO-(?P[0-9]{1,4}[a-zA-Z]?)\\b", "new": "TC-STORAGE-{n}", "global_alias": true, "files": ["*", "*/*", "*/*/*", "*/*/*/*", "*/*/*/*/*", "*/*/*/*/*/*"], "note": "批 2:模块码 STO → STORAGE(存储栈 FTL+FatFs+App/fs;STO 易读成 stop)"}, + {"family": "TC-SHA256", "old": "\\bTC-SH-(?P[0-9]{1,4}[a-zA-Z]?)\\b", "new": "TC-SHA256-{n}", "global_alias": true, "files": ["*", "*/*", "*/*/*", "*/*/*/*", "*/*/*/*/*", "*/*/*/*/*/*"], "note": "批 2:模块码 SH → SHA256(App/util/sha256;算法名应写全)"}, + {"family": "TC-FTPAUTH", "old": "\\bTC-FA-(?P[0-9]{1,4}[a-zA-Z]?)\\b", "new": "TC-FTPAUTH-{n}", "global_alias": true, "files": ["*", "*/*", "*/*/*", "*/*/*/*", "*/*/*/*/*", "*/*/*/*/*/*"], "note": "批 2:模块码 FA → FTPAUTH(Drivers/BSP/NET/lftpd 鉴权)"}, + {"family": "TC-FREQ", "old": "\\bTC-FR-(?P[0-9]{1,4}[a-zA-Z]?)\\b", "new": "TC-FREQ-{n}", "global_alias": true, "files": ["*", "*/*", "*/*/*", "*/*/*/*", "*/*/*/*/*", "*/*/*/*/*/*"], "note": "批 2:模块码 FR → FREQ(App/algo/freq L2.5 测频)"}, + {"family": "TC-IEC104", "old": "\\bTC-104-(?P[0-9]{1,4}[a-zA-Z]?)\\b", "new": "TC-IEC104-{n}", "global_alias": true, "files": ["*", "*/*", "*/*/*", "*/*/*/*", "*/*/*/*/*", "*/*/*/*/*/*"], "note": "批 2:数字模块码 104 → IEC104(§6 表里本就写 I104,代码写成纯数字 104;纯数字不是模块码)"} + ] +} diff --git a/test/board/storage_test.h b/test/board/storage_test.h index fdf18fc2..1fa91c7e 100644 --- a/test/board/storage_test.h +++ b/test/board/storage_test.h @@ -31,7 +31,7 @@ extern storage_test_stats_t g_storage_stats; void storage_test_run(void); /* 存储套件恢复测试(默认关闭):取消注释并编译 STORAGE 套件运行一次, - * 即可重建 BBT(清除 TC-STO-03 等注入的坏块)并重新格式化,恢复设备干净态。 + * 即可重建 BBT(清除 TC-STORAGE-03 等注入的坏块)并重新格式化,恢复设备干净态。 * 恢复完成后建议重新注释并编译正常构建。 */ //#define ENABLE_STORAGE_RECOVERY_TESTS /* 台架已跑过一次恢复(2026-09-20 BBT 回出厂态),保持注释 */ diff --git a/test/board/storage_test_task.c b/test/board/storage_test_task.c index dccef937..4c7bafc6 100644 --- a/test/board/storage_test_task.c +++ b/test/board/storage_test_task.c @@ -32,7 +32,7 @@ static FIL fil; * L6406E 实测;2048 分块仍覆盖整页写路径,128KB 总量不变) */ static uint8_t s_perf_buf[2048]; -/* TC-STO-01: FTL 掉电恢复(journal 持久化) +/* TC-STORAGE-01: FTL 掉电恢复(journal 持久化) * 写文件并同步落盘,随后模拟掉电(卸载 + 复位 FTL + 重新 resume),再挂载校验内容一致。 */ static void storage_test_powerloss(void) @@ -44,10 +44,10 @@ static void storage_test_powerloss(void) uint32_t i; int ok = 0; - DBG_INFO("=== Storage Test: TC-STO-01 Power-loss recovery ==="); + DBG_INFO("=== Storage Test: TC-STORAGE-01 Power-loss recovery ==="); if (f_mount(&fs, "", 1) != FR_OK) { - STORAGE_TEST_CHECK(0, "TC-STO-01 mount"); + STORAGE_TEST_CHECK(0, "TC-STORAGE-01 mount"); return; } @@ -62,7 +62,7 @@ static void storage_test_powerloss(void) f_sync(&fil); f_close(&fil); } else { - STORAGE_TEST_CHECK(0, "TC-STO-01 f_open(write)"); + STORAGE_TEST_CHECK(0, "TC-STORAGE-01 f_open(write)"); return; } @@ -72,7 +72,7 @@ static void storage_test_powerloss(void) nand_ftl_init(); if (f_mount(&fs, "", 1) != FR_OK) { - STORAGE_TEST_CHECK(0, "TC-STO-01 remount after resume"); + STORAGE_TEST_CHECK(0, "TC-STORAGE-01 remount after resume"); return; } @@ -93,11 +93,11 @@ static void storage_test_powerloss(void) } else { ok = 0; } - STORAGE_TEST_CHECK(ok, "TC-STO-01 content survived power-loss (resume)"); + STORAGE_TEST_CHECK(ok, "TC-STORAGE-01 content survived power-loss (resume)"); f_unlink("pl.dat"); } -/* TC-STO-02: 大文件 / 多扇区 / 随机 seek +/* TC-STORAGE-02: 大文件 / 多扇区 / 随机 seek * 写 256KB 位置相关模式文件,顺序读回比对 + 随机偏移 seek 读比对。 * 栈预算:testTask 栈 4KB,局部缓冲 4096 必然溢出栈(8 月侥幸未爆是堆使用 * 低),改 2048 = 恰好一个 NAND 整页,覆盖度等价。 @@ -111,16 +111,16 @@ static void storage_test_largefile(void) uint32_t off, i; int ok = 1; - DBG_INFO("=== Storage Test: TC-STO-02 Large file / random seek ==="); + DBG_INFO("=== Storage Test: TC-STORAGE-02 Large file / random seek ==="); if (f_mount(&fs, "", 1) != FR_OK) { - STORAGE_TEST_CHECK(0, "TC-STO-02 mount"); + STORAGE_TEST_CHECK(0, "TC-STORAGE-02 mount"); return; } /* 写:位置相关模式 */ if (f_open(&fil, "big.dat", FA_CREATE_ALWAYS | FA_WRITE) != FR_OK) { - STORAGE_TEST_CHECK(0, "TC-STO-02 f_open(write)"); + STORAGE_TEST_CHECK(0, "TC-STORAGE-02 f_open(write)"); return; } for (off = 0; off < total; off += chunk) { @@ -133,7 +133,7 @@ static void storage_test_largefile(void) /* 顺序读回 */ if (f_open(&fil, "big.dat", FA_READ) != FR_OK) { - STORAGE_TEST_CHECK(0, "TC-STO-02 f_open(read)"); + STORAGE_TEST_CHECK(0, "TC-STORAGE-02 f_open(read)"); return; } for (off = 0; off < total; off += chunk) { @@ -144,7 +144,7 @@ static void storage_test_largefile(void) } if (!ok) break; } - STORAGE_TEST_CHECK(ok, "TC-STO-02 sequential 256KB read consistent"); + STORAGE_TEST_CHECK(ok, "TC-STORAGE-02 sequential 256KB read consistent"); /* 随机 seek 读 */ if (ok) { @@ -160,13 +160,13 @@ static void storage_test_largefile(void) } if (!seek_ok) break; } - STORAGE_TEST_CHECK(seek_ok, "TC-STO-02 random seek read consistent"); + STORAGE_TEST_CHECK(seek_ok, "TC-STORAGE-02 random seek read consistent"); } f_close(&fil); f_unlink("big.dat"); } -/* TC-STO-03: 坏块注入下存储写入 +/* TC-STORAGE-03: 坏块注入下存储写入 * 清空旧 map → 注入若干好块为坏(持久化) → 重建文件系统 → 正常写读 → 校验坏块仍被报告。 */ static void storage_test_badblock(void) @@ -177,7 +177,7 @@ static void storage_test_badblock(void) int nbad = 0; int ok = 1; - DBG_INFO("=== Storage Test: TC-STO-03 Bad-block injection during storage ==="); + DBG_INFO("=== Storage Test: TC-STORAGE-03 Bad-block injection during storage ==="); /* 清空旧 dhara map,避免后续注入的坏块被旧映射引用 */ nand_ftl_format(); @@ -190,10 +190,10 @@ static void storage_test_badblock(void) } } if (nbad < 3) { - STORAGE_TEST_CHECK(0, "TC-STO-03 could not find 3 good blocks (got %d)", nbad); + STORAGE_TEST_CHECK(0, "TC-STORAGE-03 could not find 3 good blocks (got %d)", nbad); return; } - STORAGE_TEST_CHECK(nbad == 3, "TC-STO-03 injected %d bad blocks", nbad); + STORAGE_TEST_CHECK(nbad == 3, "TC-STORAGE-03 injected %d bad blocks", nbad); /* 复位 FTL 使 dhara 经 is_block_bad 看到新坏块 */ f_mount(&fs, "", 0); @@ -205,12 +205,12 @@ static void storage_test_badblock(void) MKFS_PARM opts = { FM_FAT32, 0, 0, 0, 0 }; uint8_t work[FF_MAX_SS]; if (f_mkfs("", &opts, work, sizeof(work)) != FR_OK) { - STORAGE_TEST_CHECK(0, "TC-STO-03 f_mkfs"); + STORAGE_TEST_CHECK(0, "TC-STORAGE-03 f_mkfs"); return; } } if (f_mount(&fs, "", 1) != FR_OK) { - STORAGE_TEST_CHECK(0, "TC-STO-03 mount"); + STORAGE_TEST_CHECK(0, "TC-STORAGE-03 mount"); return; } @@ -222,7 +222,7 @@ static void storage_test_badblock(void) f_write(&fil, wbuf, sizeof(wbuf), &bw); f_close(&fil); } else { - STORAGE_TEST_CHECK(0, "TC-STO-03 f_open(write)"); + STORAGE_TEST_CHECK(0, "TC-STORAGE-03 f_open(write)"); return; } @@ -239,24 +239,24 @@ static void storage_test_badblock(void) } else { ok = 0; } - STORAGE_TEST_CHECK(ok, "TC-STO-03 file intact with injected bad blocks"); + STORAGE_TEST_CHECK(ok, "TC-STORAGE-03 file intact with injected bad blocks"); /* 校验注入坏块仍被报告为坏(未被 dhara 占用) */ int badok = 1; for (int k = 0; k < nbad; k++) { if (gd5f2gq5ue_is_block_bad(bad[k]) != 1) { badok = 0; } } - STORAGE_TEST_CHECK(badok, "TC-STO-03 injected blocks still reported bad"); + STORAGE_TEST_CHECK(badok, "TC-STORAGE-03 injected blocks still reported bad"); f_unlink("bbt.dat"); /* 注意:注入的坏块已持久化,测试设备专用;如需恢复需重建 BBT / 重新格式化 - * (配套 TC-STO-04 恢复测试:storage_test.h 启用 ENABLE_STORAGE_RECOVERY_TESTS + * (配套 TC-STORAGE-04 恢复测试:storage_test.h 启用 ENABLE_STORAGE_RECOVERY_TESTS * 后跑一次套件,即可清除运行时注入坏块 + 清 dhara map 回出厂态) */ } -#endif /* ENABLE_DESTRUCTIVE_TESTS: s_perf_buf + TC-STO-01/02/03(写、擦、坏块注入) */ +#endif /* ENABLE_DESTRUCTIVE_TESTS: s_perf_buf + TC-STORAGE-01/02/03(写、擦、坏块注入) */ -/* TC-STO-05: 文件名/路径合法性校验(守护 ".fschk 无限重格式化" 真根因) +/* TC-STORAGE-05: 文件名/路径合法性校验(守护 ".fschk 无限重格式化" 真根因) * 本移植 FF_USE_LFN=0,只支持严格 8.3 短名(主名≤8、扩展≤3、不以点开头)。 * 非法名字 f_open 必返 FR_INVALID_NAME(纯 RAM 名字判定、不碰盘);合法但 * 不存在的名字返 FR_NO_FILE。本测试断言两类严格可区分——一旦哪天有人把 @@ -293,10 +293,10 @@ static void storage_test_name_validation(void) "pipe|name" /* | */ }; - DBG_INFO("=== Storage Test: TC-STO-05 Filename validation ==="); + DBG_INFO("=== Storage Test: TC-STORAGE-05 Filename validation ==="); if (f_mount(&fs, "", 1) != FR_OK) { - STORAGE_TEST_CHECK(0, "TC-STO-05 mount"); + STORAGE_TEST_CHECK(0, "TC-STORAGE-05 mount"); return; } @@ -310,7 +310,7 @@ static void storage_test_name_validation(void) DBG_ERROR(" valid name wrongly rejected: '%s'", good[i]); } } - STORAGE_TEST_CHECK(gok, "TC-STO-05 valid 8.3 names accepted"); + STORAGE_TEST_CHECK(gok, "TC-STORAGE-05 valid 8.3 names accepted"); for (i = 0; i < (uint32_t)(sizeof(bad) / sizeof(bad[0])); i++) { FRESULT r = f_open(&fil, bad[i], FA_READ); @@ -325,11 +325,11 @@ static void storage_test_name_validation(void) DBG_ERROR(" invalid name NOT rejected: '%s' -> fr=%d", bad[i], (int)r); } } - STORAGE_TEST_CHECK(bok, "TC-STO-05 invalid names rejected (FR_INVALID_NAME)"); + STORAGE_TEST_CHECK(bok, "TC-STORAGE-05 invalid names rejected (FR_INVALID_NAME)"); } #ifdef ENABLE_DESTRUCTIVE_TESTS -/* TC-STO-06: 打开模式与写回字节数语义(守护 FA_OPEN_APPEND / 短写陷阱) +/* TC-STORAGE-06: 打开模式与写回字节数语义(守护 FA_OPEN_APPEND / 短写陷阱) * 本移植 FA_OPEN_APPEND 不含 FA_WRITE → 不带写位打开 f_write 必返 FR_DENIED; * 追加写必须 FA_WRITE|FA_OPEN_APPEND。另 f_write 簇耗尽返 FR_OK+短写(无错误 * 码),判成败必须校验写回字节数。锁定这两条移植专有语义防回归。 @@ -339,17 +339,17 @@ static void storage_test_open_modes(void) UINT bw; FRESULT r; - DBG_INFO("=== Storage Test: TC-STO-06 Open-mode semantics ==="); + DBG_INFO("=== Storage Test: TC-STORAGE-06 Open-mode semantics ==="); if (f_mount(&fs, "", 1) != FR_OK) { - STORAGE_TEST_CHECK(0, "TC-STO-06 mount"); + STORAGE_TEST_CHECK(0, "TC-STORAGE-06 mount"); return; } (void)f_unlink("mode.tmp"); /* 1) 建一个含初始内容的文件 */ r = f_open(&fil, "mode.tmp", FA_CREATE_ALWAYS | FA_WRITE); - STORAGE_TEST_CHECK(r == FR_OK, "TC-STO-06 create base file"); + STORAGE_TEST_CHECK(r == FR_OK, "TC-STORAGE-06 create base file"); if (r == FR_OK) { f_write(&fil, "abc", 3, &bw); f_close(&fil); @@ -357,36 +357,36 @@ static void storage_test_open_modes(void) /* 2) FA_OPEN_APPEND(无 FA_WRITE)→ 写必返 FR_DENIED */ r = f_open(&fil, "mode.tmp", FA_OPEN_APPEND); - STORAGE_TEST_CHECK(r == FR_OK, "TC-STO-06 open append(no write)"); + STORAGE_TEST_CHECK(r == FR_OK, "TC-STORAGE-06 open append(no write)"); if (r == FR_OK) { FRESULT wr = f_write(&fil, "xyz", 3, &bw); STORAGE_TEST_CHECK(wr == FR_DENIED, - "TC-STO-06 append-no-write must DENY (fr=%d)", (int)wr); + "TC-STORAGE-06 append-no-write must DENY (fr=%d)", (int)wr); f_close(&fil); } /* 3) FA_WRITE|FA_OPEN_APPEND → 追加成功且字节数正确 */ r = f_open(&fil, "mode.tmp", FA_WRITE | FA_OPEN_APPEND); - STORAGE_TEST_CHECK(r == FR_OK, "TC-STO-06 open write|append"); + STORAGE_TEST_CHECK(r == FR_OK, "TC-STORAGE-06 open write|append"); if (r == FR_OK) { (void)f_write(&fil, "xyz", 3, &bw); - STORAGE_TEST_CHECK(bw == 3, "TC-STO-06 append byte-count (%u)", bw); + STORAGE_TEST_CHECK(bw == 3, "TC-STORAGE-06 append byte-count (%u)", bw); f_close(&fil); } /* 4) 只读打开后写 → 必返 FR_DENIED(读句柄不可写) */ r = f_open(&fil, "mode.tmp", FA_READ); - STORAGE_TEST_CHECK(r == FR_OK, "TC-STO-06 open read-only"); + STORAGE_TEST_CHECK(r == FR_OK, "TC-STORAGE-06 open read-only"); if (r == FR_OK) { FRESULT wr = f_write(&fil, "q", 1, &bw); STORAGE_TEST_CHECK(wr == FR_DENIED, - "TC-STO-06 read-only write must DENY (fr=%d)", (int)wr); + "TC-STORAGE-06 read-only write must DENY (fr=%d)", (int)wr); f_close(&fil); } (void)f_unlink("mode.tmp"); } -#endif /* ENABLE_DESTRUCTIVE_TESTS: TC-STO-06 */ +#endif /* ENABLE_DESTRUCTIVE_TESTS: TC-STORAGE-06 */ #endif /* !ENABLE_STORAGE_RECOVERY_TESTS: 共享缓冲 + 正常测试函数 */ #ifdef ENABLE_STORAGE_RECOVERY_TESTS @@ -506,7 +506,7 @@ static void storage_test_run_normal(void) } #endif /* ENABLE_DESTRUCTIVE_TESTS: 文件系统写读 + 性能压测 */ - /* ==================== 存储集成测试(TC-STO-05 契约 + 01~03 集成) ========== */ + /* ==================== 存储集成测试(TC-STORAGE-05 契约 + 01~03 集成) ========== */ /* 纯语义契约测试(非破坏性):文件名合法性 */ storage_test_name_validation(); @@ -581,42 +581,42 @@ static void storage_test_wipe_visible(void) DBG_INFO(" wiped %lu blocks (%lu skipped as bad, %lu visible)", (unsigned long)done, (unsigned long)skipped, (unsigned long)usable); - STORAGE_TEST_CHECK(done > 0U, "TC-STO-04 full wipe (%lu blocks erased)", + STORAGE_TEST_CHECK(done > 0U, "TC-STORAGE-04 full wipe (%lu blocks erased)", (unsigned long)done); } #endif /* STORAGE_RECOVERY_FULL_WIPE */ -/* TC-STO-04: 维护模式(恢复 = 重建 BBT + 重新格式化;叠加全片擦除 = 容量恢复) +/* TC-STORAGE-04: 维护模式(恢复 = 重建 BBT + 重新格式化;叠加全片擦除 = 容量恢复) * 仅在启用 ENABLE_STORAGE_RECOVERY_TESTS 时编译运行;运行一次即可把设备 * 恢复到干净出厂态(清除运行时注入坏块并清空 dhara map)。 */ static void storage_test_recover(void) { - DBG_INFO("=== Storage Test: TC-STO-04 maintenance (recovery / full wipe) ==="); + DBG_INFO("=== Storage Test: TC-STORAGE-04 maintenance (recovery / full wipe) ==="); int r = gd5f2gq5ue_bbt_rebuild(); - STORAGE_TEST_CHECK(r == GD5F_OK, "TC-STO-04 bbt rebuild"); + STORAGE_TEST_CHECK(r == GD5F_OK, "TC-STORAGE-04 bbt rebuild"); #ifdef STORAGE_RECOVERY_FULL_WIPE storage_test_wipe_visible(); #else nand_ftl_format(); - STORAGE_TEST_CHECK(1, "TC-STO-04 nand_ftl_format done"); + STORAGE_TEST_CHECK(1, "TC-STORAGE-04 nand_ftl_format done"); #endif uint8_t fb[GD5F_TOTAL_BLOCKS / 8]; uint32_t ver = 0; if (gd5f_bbt_dump_flash(fb, &ver) == GD5F_OK) { - STORAGE_TEST_CHECK(ver >= 1, "TC-STO-04 persisted BBT version=%lu", ver); + STORAGE_TEST_CHECK(ver >= 1, "TC-STORAGE-04 persisted BBT version=%lu", ver); } else { - STORAGE_TEST_CHECK(0, "TC-STO-04 dump_flash failed"); + STORAGE_TEST_CHECK(0, "TC-STORAGE-04 dump_flash failed"); } #ifdef STORAGE_RECOVERY_FULL_WIPE - DBG_INFO("TC-STO-04 full wipe complete; power-cycle to rebuild fresh " + DBG_INFO("TC-STORAGE-04 full wipe complete; power-cycle to rebuild fresh " "(capacity expected back to full)"); #else - DBG_INFO("TC-STO-04 recovery complete; recommend power-cycle to re-init cleanly"); + DBG_INFO("TC-STORAGE-04 recovery complete; recommend power-cycle to re-init cleanly"); #endif } #endif diff --git a/test/board/test_config.h b/test/board/test_config.h index 5d9aef92..d2123a9c 100644 --- a/test/board/test_config.h +++ b/test/board/test_config.h @@ -34,7 +34,7 @@ extern "C" { /* === 破坏性测试总开关(默认关闭)=== * 破坏性用例会改变设备的**持久状态**,跑一次即有代价(2026-09-21 实测:GD5F 整轮 - * 破坏性用例跑一次即消耗一个 NAND 块,容量 95248 → 95200,且 TC-STO-04 恢复不回来): + * 破坏性用例跑一次即消耗一个 NAND 块,容量 95248 → 95200,且 TC-STORAGE-04 恢复不回来): * - 向 BBT 持久化坏块标记 / 注入坏块(永久减少可用容量) * - 写、擦 NAND 块(覆盖卷数据);格式化卷(nand_ftl_format / f_mkfs) * - FatFS 建文件、写文件、性能压测 diff --git a/test/host/adc_health/adc_health_test.c b/test/host/adc_health/adc_health_test.c index 724d9f90..e543d66d 100644 --- a/test/host/adc_health/adc_health_test.c +++ b/test/host/adc_health/adc_health_test.c @@ -14,17 +14,17 @@ * 3. 不占 MCU 的 RAM,毫秒级完成。 * * 覆盖点(对应 docs/算法/继电保护功能复现规划.md §3.1 L1-6): - * TC-AH-001 init + 首拍只建基线(不误报) - * TC-AH-002 正常 1 kHz 推进 2000 拍:零故障零事件(健康不误报) - * TC-AH-003 TPAFE 静默:99ms 不报 / 100ms 报 / 恢复清除电平位、锁存位留痕 - * TC-AH-004 STM32 静默:TPAFE 正常时只报 STM32 侧 - * TC-AH-005 TPAFE 丢帧:d=3 → tgap+=2、事件仅当拍(边沿语义) - * TC-AH-006 STM32 gap 计数增量 → 事件(不入锁存:超拍非故障) - * TC-AH-007 序号倒退 → SEQ_BACKWARD 锁存(前进后仍留痕) - * TC-AH-008 FRSTDATA / STM32_ERR / HW_ERR 增量 → 事件位与锁存位编号一致 - * TC-AH-009 tick 回绕:跨 0xFFFFFFFF 的正常推进不误报静默;回绕后冻结仍报 - * TC-AH-010 NULL 守卫:in=NULL 跳过;out=NULL 只更新内部状态 - * TC-AH-011 init 幂等:故障后 re-init 全清 + * TC-ADCHEALTH-001 init + 首拍只建基线(不误报) + * TC-ADCHEALTH-002 正常 1 kHz 推进 2000 拍:零故障零事件(健康不误报) + * TC-ADCHEALTH-003 TPAFE 静默:99ms 不报 / 100ms 报 / 恢复清除电平位、锁存位留痕 + * TC-ADCHEALTH-004 STM32 静默:TPAFE 正常时只报 STM32 侧 + * TC-ADCHEALTH-005 TPAFE 丢帧:d=3 → tgap+=2、事件仅当拍(边沿语义) + * TC-ADCHEALTH-006 STM32 gap 计数增量 → 事件(不入锁存:超拍非故障) + * TC-ADCHEALTH-007 序号倒退 → SEQ_BACKWARD 锁存(前进后仍留痕) + * TC-ADCHEALTH-008 FRSTDATA / STM32_ERR / HW_ERR 增量 → 事件位与锁存位编号一致 + * TC-ADCHEALTH-009 tick 回绕:跨 0xFFFFFFFF 的正常推进不误报静默;回绕后冻结仍报 + * TC-ADCHEALTH-010 NULL 守卫:in=NULL 跳过;out=NULL 只更新内部状态 + * TC-ADCHEALTH-011 init 幂等:故障后 re-init 全清 * * 通过:全部 TC PASS(main 返回 0)。 * 入口:int main(void),返回 0=PASS / 1=FAIL(由 run 脚本判读)。 @@ -66,7 +66,7 @@ static adc_health_in_t mk_in(uint32_t seq, uint32_t now_ms) { /* ===================== TC ===================== */ -/* TC-AH-001:init + 首拍只建基线 */ +/* TC-ADCHEALTH-001:init + 首拍只建基线 */ static void tc_prime(void) { adc_health_in_t in; adc_health_status_t st; @@ -76,14 +76,14 @@ static void tc_prime(void) { adc_health_check(&in, &st); CHECK((st.flags == 0u) && (st.events == 0u) && (st.sticky == 0u) && (st.tpafe_gaps == 0u), - "TC-AH-001 first check only primes: no flags/events/sticky"); + "TC-ADCHEALTH-001 first check only primes: no flags/events/sticky"); /* 第二拍序号未动但仅 1ms(< 门限)→ 仍不报 */ in.now_ms = 1001u; adc_health_check(&in, &st); - CHECK(st.flags == 0u, "TC-AH-001 1ms without advance is not a stall"); + CHECK(st.flags == 0u, "TC-ADCHEALTH-001 1ms without advance is not a stall"); } -/* TC-AH-002:正常 1 kHz 推进 2000 拍零误报 */ +/* TC-ADCHEALTH-002:正常 1 kHz 推进 2000 拍零误报 */ static void tc_healthy(void) { adc_health_status_t st; adc_health_in_t in; @@ -100,10 +100,10 @@ static void tc_healthy(void) { seq++; now++; } - CHECK(ok, "TC-AH-002 healthy 1kHz sweep 2000 beats: zero flags/events"); + CHECK(ok, "TC-ADCHEALTH-002 healthy 1kHz sweep 2000 beats: zero flags/events"); } -/* TC-AH-003:TPAFE 静默 99/100ms 门限 + 恢复留痕 */ +/* TC-ADCHEALTH-003:TPAFE 静默 99/100ms 门限 + 恢复留痕 */ static void tc_tpafe_stall(void) { adc_health_status_t st; adc_health_in_t in; @@ -127,28 +127,28 @@ static void tc_tpafe_stall(void) { now++; } CHECK((st.flags & ADC_HF_TPAFE_STALL) == 0u, - "TC-AH-003 no TPAFE stall before 100ms"); + "TC-ADCHEALTH-003 no TPAFE stall before 100ms"); /* 第 100ms:报 */ in = mk_in(seq, now); in.stm32_seq = seq + 100u; adc_health_check(&in, &st); CHECK((st.flags & ADC_HF_TPAFE_STALL) != 0u, - "TC-AH-003 TPAFE stall at 100ms"); + "TC-ADCHEALTH-003 TPAFE stall at 100ms"); CHECK((st.sticky & ADC_HF_TPAFE_STALL) != 0u, - "TC-AH-003 stall latched into sticky"); + "TC-ADCHEALTH-003 stall latched into sticky"); CHECK(st.tpafe_stall_ms >= ADC_HEALTH_STALL_MS, - "TC-AH-003 stall_ms reported >= threshold"); + "TC-ADCHEALTH-003 stall_ms reported >= threshold"); /* 恢复:TPAFE 序号重新前进 → 电平位清除、sticky 留痕 */ in = mk_in(seq + 1u, now + 1u); in.stm32_seq = seq + 101u; adc_health_check(&in, &st); CHECK((st.flags & ADC_HF_TPAFE_STALL) == 0u, - "TC-AH-003 stall level clears on recovery"); + "TC-ADCHEALTH-003 stall level clears on recovery"); CHECK((adc_health_sticky() & ADC_HF_TPAFE_STALL) != 0u, - "TC-AH-003 sticky keeps the fault trace after recovery"); + "TC-ADCHEALTH-003 sticky keeps the fault trace after recovery"); } -/* TC-AH-004:STM32 静默(TPAFE 正常) */ +/* TC-ADCHEALTH-004:STM32 静默(TPAFE 正常) */ static void tc_stm32_stall(void) { adc_health_status_t st; adc_health_in_t in; @@ -169,12 +169,12 @@ static void tc_stm32_stall(void) { adc_health_check(&in, &st); } CHECK((st.flags & ADC_HF_STM32_STALL) != 0u, - "TC-AH-004 STM32 stall at 100ms"); + "TC-ADCHEALTH-004 STM32 stall at 100ms"); CHECK((st.flags & ADC_HF_TPAFE_STALL) == 0u, - "TC-AH-004 healthy TPAFE not falsely stalled"); + "TC-ADCHEALTH-004 healthy TPAFE not falsely stalled"); } -/* TC-AH-005:TPAFE 丢帧计数 + 边沿语义 */ +/* TC-ADCHEALTH-005:TPAFE 丢帧计数 + 边沿语义 */ static void tc_tpafe_gap(void) { adc_health_status_t st; adc_health_in_t in; @@ -185,15 +185,15 @@ static void tc_tpafe_gap(void) { in.tpafe_seq = 13u; in.stm32_seq = 11u; in.now_ms = 11u; /* TPAFE d=3 */ adc_health_check(&in, &st); CHECK((st.events & ADC_HE_TPAFE_GAP) != 0u, - "TC-AH-005 gap event on d>1"); - CHECK(st.tpafe_gaps == 2u, "TC-AH-005 d=3 accumulates 2 lost points"); + "TC-ADCHEALTH-005 gap event on d>1"); + CHECK(st.tpafe_gaps == 2u, "TC-ADCHEALTH-005 d=3 accumulates 2 lost points"); in.tpafe_seq = 14u; in.stm32_seq = 12u; in.now_ms = 12u; /* 恢复正常 d=1 */ adc_health_check(&in, &st); - CHECK(st.events == 0u, "TC-AH-005 gap event is edge-only (next beat clean)"); - CHECK(st.tpafe_gaps == 2u, "TC-AH-005 gap counter is cumulative"); + CHECK(st.events == 0u, "TC-ADCHEALTH-005 gap event is edge-only (next beat clean)"); + CHECK(st.tpafe_gaps == 2u, "TC-ADCHEALTH-005 gap counter is cumulative"); } -/* TC-AH-006:STM32 gap 计数增量 → 事件、不入锁存 */ +/* TC-ADCHEALTH-006:STM32 gap 计数增量 → 事件、不入锁存 */ static void tc_stm32_gap(void) { adc_health_status_t st; adc_health_in_t in; @@ -204,13 +204,13 @@ static void tc_stm32_gap(void) { in.stm32_gaps = 1u; in.tpafe_seq = 2u; in.stm32_seq = 2u; in.now_ms = 2u; adc_health_check(&in, &st); CHECK((st.events & ADC_HE_STM32_GAP) != 0u, - "TC-AH-006 STM32 gap increment raises event"); + "TC-ADCHEALTH-006 STM32 gap increment raises event"); CHECK((st.sticky & (ADC_HF_FRSTDATA | ADC_HF_STM32_ERR | ADC_HF_HW_ERR)) == 0u, - "TC-AH-006 gap does NOT latch sticky (overrun is not a fault)"); + "TC-ADCHEALTH-006 gap does NOT latch sticky (overrun is not a fault)"); } -/* TC-AH-007:序号倒退 → 锁存 */ +/* TC-ADCHEALTH-007:序号倒退 → 锁存 */ static void tc_backward(void) { adc_health_status_t st; adc_health_in_t in; @@ -223,9 +223,9 @@ static void tc_backward(void) { in.tpafe_seq = 995u; in.stm32_seq = 995u; in.now_ms = 101u; /* 倒退 */ adc_health_check(&in, &st); CHECK((st.flags & ADC_HF_SEQ_BACKWARD) != 0u, - "TC-AH-007 backward seq raises latched flag"); + "TC-ADCHEALTH-007 backward seq raises latched flag"); CHECK((st.sticky & ADC_HF_SEQ_BACKWARD) != 0u, - "TC-AH-007 backward latched into sticky"); + "TC-ADCHEALTH-007 backward latched into sticky"); /* 恢复正常推进 50 拍:SEQ_BACKWARD 不清(锁存语义) */ s = 996u; t = 102u; for (i = 0; i < 50; i++) { @@ -234,10 +234,10 @@ static void tc_backward(void) { s++; t++; } CHECK((adc_health_flags() & ADC_HF_SEQ_BACKWARD) != 0u, - "TC-AH-007 SEQ_BACKWARD persists after normal advance"); + "TC-ADCHEALTH-007 SEQ_BACKWARD persists after normal advance"); } -/* TC-AH-008:三类错误计数增量 → 事件位与锁存位编号一致 */ +/* TC-ADCHEALTH-008:三类错误计数增量 → 事件位与锁存位编号一致 */ static void tc_err_counters(void) { adc_health_status_t st; adc_health_in_t in; @@ -251,29 +251,29 @@ static void tc_err_counters(void) { adc_health_check(&in, &st); CHECK(((st.events & ADC_HE_FRSTDATA) != 0u) && ((st.sticky & ADC_HF_FRSTDATA) != 0u), - "TC-AH-008 FRSTDATA increment: event + sticky (same bit number)"); + "TC-ADCHEALTH-008 FRSTDATA increment: event + sticky (same bit number)"); in.tpafe_seq = 3u; in.stm32_seq = 3u; in.now_ms = 3u; in.stm32_errs = 1u; adc_health_check(&in, &st); CHECK(((st.events & ADC_HE_STM32_ERR) != 0u) && ((st.sticky & ADC_HF_STM32_ERR) != 0u), - "TC-AH-008 STM32 err increment: event + sticky (same bit number)"); + "TC-ADCHEALTH-008 STM32 err increment: event + sticky (same bit number)"); in.tpafe_seq = 4u; in.stm32_seq = 4u; in.now_ms = 4u; in.stm32_hw_errs = 1u; adc_health_check(&in, &st); CHECK(((st.events & ADC_HE_HW_ERR) != 0u) && ((st.sticky & ADC_HF_HW_ERR) != 0u), - "TC-AH-008 HAL err increment: event + sticky (same bit number)"); + "TC-ADCHEALTH-008 HAL err increment: event + sticky (same bit number)"); /* 计数不再变化 → 事件不再重复触发 */ in.tpafe_seq = 5u; in.stm32_seq = 5u; in.now_ms = 5u; adc_health_check(&in, &st); - CHECK(st.events == 0u, "TC-AH-008 steady error counters raise no repeat events"); + CHECK(st.events == 0u, "TC-ADCHEALTH-008 steady error counters raise no repeat events"); } -/* TC-AH-009:tick 回绕安全 */ +/* TC-ADCHEALTH-009:tick 回绕安全 */ static void tc_tick_wrap(void) { adc_health_status_t st; adc_health_in_t in; @@ -290,7 +290,7 @@ static void tc_tick_wrap(void) { } seq++; now++; /* uint32 自然回绕 */ } - CHECK(ok, "TC-AH-009 tick wrap sweep: no false stall"); + CHECK(ok, "TC-ADCHEALTH-009 tick wrap sweep: no false stall"); /* 回绕后两侧同时冻结。⚠ 第 1 拍消费 sweep 末尾的"未消费 +1"并重置计时起点 * → 第 i 拍 elapsed = i,需 101 拍才到 100ms */ for (i = 0; i < 101; i++) { @@ -300,10 +300,10 @@ static void tc_tick_wrap(void) { } CHECK(((st.flags & ADC_HF_TPAFE_STALL) != 0u) && ((st.flags & ADC_HF_STM32_STALL) != 0u), - "TC-AH-009 stall still detected after tick wrap"); + "TC-ADCHEALTH-009 stall still detected after tick wrap"); } -/* TC-AH-010:NULL 守卫 */ +/* TC-ADCHEALTH-010:NULL 守卫 */ static void tc_null_guard(void) { adc_health_status_t st; adc_health_in_t in; @@ -314,7 +314,7 @@ static void tc_null_guard(void) { adc_health_check(&in, &st); st.flags = 0xA5A5A5A5u; adc_health_check(NULL, &st); - CHECK(st.flags == 0xA5A5A5A5u, "TC-AH-010 in=NULL leaves out untouched"); + CHECK(st.flags == 0xA5A5A5A5u, "TC-ADCHEALTH-010 in=NULL leaves out untouched"); /* out=NULL:内部状态照常更新(两侧冻结 101 拍 → 静默位应出现) */ for (i = 0; i < 101; i++) { @@ -322,10 +322,10 @@ static void tc_null_guard(void) { adc_health_check(&in, NULL); } CHECK((adc_health_flags() & ADC_HF_TPAFE_STALL) != 0u, - "TC-AH-010 out=NULL still updates internal state"); + "TC-ADCHEALTH-010 out=NULL still updates internal state"); } -/* TC-AH-011:init 幂等 / 故障后全清 */ +/* TC-ADCHEALTH-011:init 幂等 / 故障后全清 */ static void tc_reinit(void) { adc_health_status_t st; adc_health_in_t in; @@ -338,15 +338,15 @@ static void tc_reinit(void) { in = mk_in(1u, (uint32_t)(2 + i)); adc_health_check(&in, &st); } - CHECK(st.sticky != 0u, "TC-AH-011 pre: sticky non-zero before re-init"); + CHECK(st.sticky != 0u, "TC-ADCHEALTH-011 pre: sticky non-zero before re-init"); adc_health_init(); CHECK((adc_health_flags() == 0u) && (adc_health_sticky() == 0u) && (adc_health_tpafe_gaps() == 0u), - "TC-AH-011 re-init clears flags/sticky/gaps"); + "TC-ADCHEALTH-011 re-init clears flags/sticky/gaps"); in = mk_in(9u, 9u); /* 序号跳变也无妨:首拍只建基线 */ adc_health_check(&in, &st); CHECK((st.flags == 0u) && (st.events == 0u), - "TC-AH-011 re-prime after re-init is clean"); + "TC-ADCHEALTH-011 re-prime after re-init is clean"); } int main(void) { diff --git a/test/host/adc_input/adc_input_test.c b/test/host/adc_input/adc_input_test.c index d61c091a..85bf5ab8 100644 --- a/test/host/adc_input/adc_input_test.c +++ b/test/host/adc_input/adc_input_test.c @@ -18,51 +18,51 @@ * 3. 不占 MCU 的 RAM,毫秒级完成。 * * 覆盖点(对应 docs/算法/继电保护功能复现规划.md §2.1 的 L1-3 / L1-4): - * —— adc_input_init(TC-AI-001..006)—— - * TC-AI-001 poll 失败后失败计数可见(前置状态构造) - * TC-AI-002 poll 成功后 TPAFE 侧可取数(前置状态构造) - * TC-AI-003 init 返回 0(映射表自检通过) - * TC-AI-004 init 后 STM32 状态码 = NOT_RUN - * TC-AI-005 init 后失败计数归零 - * TC-AI-006 init 后 TPAFE / STM32 两侧均无有效数据(有效标志被清) - * —— adc_input_desc(TC-AI-010..01A)—— - * TC-AI-010..018 九个语义通道 -> (来源, 下标) 与权威映射表逐项一致 - * TC-AI-019/01A 越界(ADC_SEM_COUNT)与负数语义 -> NULL - * —— map_check(TC-AI-020)—— - * TC-AI-020 真实映射表自洽(反向路径结构上不可达,见文件末说明) - * —— stm32_take(TC-AI-021..078,v2.0 DMA 模型)—— - * TC-AI-021..025 取到新帧:返回 0 / 状态码 / 不计失败 / DMA 只挂一次 / seq=1 - * TC-AI-026..02B **Rank -> 通道号映射**:UB->CH14(rank9) / UC->CH3(rank4) / + * —— adc_input_init(TC-ADCIN-001..006)—— + * TC-ADCIN-001 poll 失败后失败计数可见(前置状态构造) + * TC-ADCIN-002 poll 成功后 TPAFE 侧可取数(前置状态构造) + * TC-ADCIN-003 init 返回 0(映射表自检通过) + * TC-ADCIN-004 init 后 STM32 状态码 = NOT_RUN + * TC-ADCIN-005 init 后失败计数归零 + * TC-ADCIN-006 init 后 TPAFE / STM32 两侧均无有效数据(有效标志被清) + * —— adc_input_desc(TC-ADCIN-010..01A)—— + * TC-ADCIN-010..018 九个语义通道 -> (来源, 下标) 与权威映射表逐项一致 + * TC-ADCIN-019/01A 越界(ADC_SEM_COUNT)与负数语义 -> NULL + * —— map_check(TC-ADCIN-020)—— + * TC-ADCIN-020 真实映射表自洽(反向路径结构上不可达,见文件末说明) + * —— stm32_take(TC-ADCIN-021..078,v2.0 DMA 模型)—— + * TC-ADCIN-021..025 取到新帧:返回 0 / 状态码 / 不计失败 / DMA 只挂一次 / seq=1 + * TC-ADCIN-026..02B **Rank -> 通道号映射**:UB->CH14(rank9) / UC->CH3(rank4) / * IB->CH6(rank7) / IC->CH1(rank2) / IN->CH2(rank3) / TEMP->CH5(rank6) - * TC-AI-02C stm32_take 不置 TPAFE 有效标志(两来源独立) - * TC-AI-080..089 **乒乓双缓冲**:消费侧读"刚完成的半区",即使另一半正被 DMA + * TC-ADCIN-02C stm32_take 不置 TPAFE 有效标志(两来源独立) + * TC-ADCIN-080..089 **乒乓双缓冲**:消费侧读"刚完成的半区",即使另一半正被 DMA * 改写也不得读到(撕裂帧防线);两拍交替半区、seq 推进; * 超拍未消费 -> 记一次丢帧(gap),与停摆(err)分开计数 - * TC-AI-090..09A HAL 错误回调计数 + 三个回调的 `hadc == &hadc1` 句柄守卫 + * TC-ADCIN-090..09A HAL 错误回调计数 + 三个回调的 `hadc == &hadc1` 句柄守卫 * (别的句柄不得污染本层 seq / hw_errs) - * TC-AI-030..034 HAL_ADC_Start_DMA 失败:init 返回 -2 / 状态码 RC_START / 计数 +1 - * TC-AI-035..039 本拍无新帧:返回 RC_STALL / **单拍不计故障**(相位伪影)/ seq 不前进 - * TC-AI-03A..03E 连续两拍无新帧才计停摆;停摆与丢帧分开计数;恢复拍自愈 - * TC-AI-070..078 **停摆拍不得沿用上一拍旧值**(2026-10-10 补,真机实测发现的 + * TC-ADCIN-030..034 HAL_ADC_Start_DMA 失败:init 返回 -2 / 状态码 RC_START / 计数 +1 + * TC-ADCIN-035..039 本拍无新帧:返回 RC_STALL / **单拍不计故障**(相位伪影)/ seq 不前进 + * TC-ADCIN-03A..03E 连续两拍无新帧才计停摆;停摆与丢帧分开计数;恢复拍自愈 + * TC-ADCIN-070..078 **停摆拍不得沿用上一拍旧值**(2026-10-10 补,真机实测发现的 * 正确性缺陷;DMA 版改由"无新帧"触发同一路径):先成功一拍让 * STM32 侧进入有效态,再注入无新帧拍 -> adc_input_raw() 必须返 -2; - * 恢复拍重新置有效。TC-AI-034 只覆盖"挂载失败即无数据", + * 恢复拍重新置有效。TC-ADCIN-034 只覆盖"挂载失败即无数据", * 照不出"成功过之后停摆 → 静默沿用旧值",故单独立一组。 - * —— adc_input_raw(TC-AI-040..04B)—— - * TC-AI-040..043 参数守卫:out=NULL / 越界 / 负数 -> -1,且不写 out - * TC-AI-044/045 无有效数据 -> -2(两来源分别) - * TC-AI-046..048 poll 快照契约:返回码透传 / 请求 8 通道 / 目的缓冲非空 - * TC-AI-049..04B TPAFE 按**下标**取数(UA=6 / UN=5 / IA=2)且补码负值原样保留 - * —— adc_input_poll(TC-AI-050..058)—— - * TC-AI-050..052 无新帧(0):返回 0 / TPAFE 无效 / STM32 侧照常扫描 - * TC-AI-053/054 参数错(-1):返回 -1 / TPAFE 无效 - * TC-AI-055 已有有效帧后再"无新帧"**不清零**(保持上次有效值) - * TC-AI-056..058 STM32 失败**不阻断** TPAFE、**不影响** poll 返回值,另由状态码暴露 - * —— adc_input_stm32_rc / _errs(TC-AI-060..066)—— - * TC-AI-060/061 init 后 = NOT_RUN / 计数 0 - * TC-AI-062 成功: rc=OK 且 errs 不变 - * TC-AI-063/064 两次失败累计 = 2,rc = 最近一次(TIMEOUT) - * TC-AI-065/066 恢复成功 rc=OK,errs 单调不回退 + * —— adc_input_raw(TC-ADCIN-040..04B)—— + * TC-ADCIN-040..043 参数守卫:out=NULL / 越界 / 负数 -> -1,且不写 out + * TC-ADCIN-044/045 无有效数据 -> -2(两来源分别) + * TC-ADCIN-046..048 poll 快照契约:返回码透传 / 请求 8 通道 / 目的缓冲非空 + * TC-ADCIN-049..04B TPAFE 按**下标**取数(UA=6 / UN=5 / IA=2)且补码负值原样保留 + * —— adc_input_poll(TC-ADCIN-050..058)—— + * TC-ADCIN-050..052 无新帧(0):返回 0 / TPAFE 无效 / STM32 侧照常扫描 + * TC-ADCIN-053/054 参数错(-1):返回 -1 / TPAFE 无效 + * TC-ADCIN-055 已有有效帧后再"无新帧"**不清零**(保持上次有效值) + * TC-ADCIN-056..058 STM32 失败**不阻断** TPAFE、**不影响** poll 返回值,另由状态码暴露 + * —— adc_input_stm32_rc / _errs(TC-ADCIN-060..066)—— + * TC-ADCIN-060/061 init 后 = NOT_RUN / 计数 0 + * TC-ADCIN-062 成功: rc=OK 且 errs 不变 + * TC-ADCIN-063/064 两次失败累计 = 2,rc = 最近一次(TIMEOUT) + * TC-ADCIN-065/066 恢复成功 rc=OK,errs 单调不回退 * * 通过:全部 TC PASS(main 返回 0)。 * 入口:int main(void),返回 0=PASS / 1=FAIL(由 run 脚本判读)。 @@ -201,7 +201,7 @@ static void dma_beat(uint16_t base) { } } -/* ===================== TC-AI-001..006:init ===================== */ +/* ===================== TC-ADCIN-001..006:init ===================== */ static void tc_init(void) { int32_t v = -999; @@ -213,69 +213,69 @@ static void tc_init(void) { (void)adc_input_poll(); /* 单拍无新帧 = 相位伪影,不计故障 */ (void)adc_input_poll(); /* 连续第二拍无新帧 = 真停摆 */ - CHECK(adc_input_stm32_errs() == 1u, "TC-AI-001 连续两拍无新帧 -> 停摆计数 = 1"); + CHECK(adc_input_stm32_errs() == 1u, "TC-ADCIN-001 连续两拍无新帧 -> 停摆计数 = 1"); CHECK((adc_input_raw(ADC_SEM_UA, &v) == 0) && (v == 4321), - "TC-AI-002 poll 后 UA 可取数且值正确"); + "TC-ADCIN-002 poll 后 UA 可取数且值正确"); - CHECK(adc_input_init() == 0, "TC-AI-003 adc_input_init 返回 0(映射自检通过)"); + CHECK(adc_input_init() == 0, "TC-ADCIN-003 adc_input_init 返回 0(映射自检通过)"); CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_NOT_RUN, - "TC-AI-004 init 后 STM32 状态码 = NOT_RUN"); - CHECK(s_start_dma_calls == 1, "TC-AI-003B init 挂载 DMA 恰好一次"); - CHECK(s_dma_len == (2u * ADC_INPUT_STM32_CH_NUM), "TC-AI-003C DMA 长度 = 2 x 9(乒乓双缓冲)"); - CHECK(s_dma_buf != NULL, "TC-AI-003D DMA 目的缓冲地址已交下来"); - CHECK(adc_input_stm32_seq() == 0u, "TC-AI-005B init 后 DMA 完成计数 = 0"); - CHECK(adc_input_stm32_errs() == 0u, "TC-AI-005 init 后 STM32 失败计数归零"); + "TC-ADCIN-004 init 后 STM32 状态码 = NOT_RUN"); + CHECK(s_start_dma_calls == 1, "TC-ADCIN-003B init 挂载 DMA 恰好一次"); + CHECK(s_dma_len == (2u * ADC_INPUT_STM32_CH_NUM), "TC-ADCIN-003C DMA 长度 = 2 x 9(乒乓双缓冲)"); + CHECK(s_dma_buf != NULL, "TC-ADCIN-003D DMA 目的缓冲地址已交下来"); + CHECK(adc_input_stm32_seq() == 0u, "TC-ADCIN-005B init 后 DMA 完成计数 = 0"); + CHECK(adc_input_stm32_errs() == 0u, "TC-ADCIN-005 init 后 STM32 失败计数归零"); CHECK((adc_input_raw(ADC_SEM_UA, &v) == -2) && (adc_input_raw(ADC_SEM_UB, &v) == -2), - "TC-AI-006 init 后 TPAFE / STM32 两侧均无有效数据"); + "TC-ADCIN-006 init 后 TPAFE / STM32 两侧均无有效数据"); } -/* ===================== TC-AI-010..01A:desc 映射表 ===================== */ +/* ===================== TC-ADCIN-010..01A:desc 映射表 ===================== */ static void tc_desc(void) { const adc_channel_desc_t *d; d = adc_input_desc(ADC_SEM_UA); CHECK((d != NULL) && (d->source == ADC_SRC_TPAFE) && (d->index == 6u), - "TC-AI-010 UA -> TPAFE buf[6]"); + "TC-ADCIN-010 UA -> TPAFE buf[6]"); d = adc_input_desc(ADC_SEM_UB); CHECK((d != NULL) && (d->source == ADC_SRC_STM32) && (d->index == 14u), - "TC-AI-011 UB -> STM32 CH14"); + "TC-ADCIN-011 UB -> STM32 CH14"); d = adc_input_desc(ADC_SEM_UC); CHECK((d != NULL) && (d->source == ADC_SRC_STM32) && (d->index == 3u), - "TC-AI-012 UC -> STM32 CH3"); + "TC-ADCIN-012 UC -> STM32 CH3"); d = adc_input_desc(ADC_SEM_UN); CHECK((d != NULL) && (d->source == ADC_SRC_TPAFE) && (d->index == 5u), - "TC-AI-013 UN -> TPAFE buf[5]"); + "TC-ADCIN-013 UN -> TPAFE buf[5]"); d = adc_input_desc(ADC_SEM_IA); CHECK((d != NULL) && (d->source == ADC_SRC_TPAFE) && (d->index == 2u), - "TC-AI-014 IA -> TPAFE buf[2]"); + "TC-ADCIN-014 IA -> TPAFE buf[2]"); d = adc_input_desc(ADC_SEM_IB); CHECK((d != NULL) && (d->source == ADC_SRC_STM32) && (d->index == 6u), - "TC-AI-015 IB -> STM32 CH6"); + "TC-ADCIN-015 IB -> STM32 CH6"); d = adc_input_desc(ADC_SEM_IC); CHECK((d != NULL) && (d->source == ADC_SRC_STM32) && (d->index == 1u), - "TC-AI-016 IC -> STM32 CH1"); + "TC-ADCIN-016 IC -> STM32 CH1"); d = adc_input_desc(ADC_SEM_IN); CHECK((d != NULL) && (d->source == ADC_SRC_STM32) && (d->index == 2u), - "TC-AI-017 IN -> STM32 CH2"); + "TC-ADCIN-017 IN -> STM32 CH2"); d = adc_input_desc(ADC_SEM_TEMP); CHECK((d != NULL) && (d->source == ADC_SRC_STM32) && (d->index == 5u), - "TC-AI-018 TEMP -> STM32 CH5"); + "TC-ADCIN-018 TEMP -> STM32 CH5"); - CHECK(adc_input_desc(ADC_SEM_COUNT) == NULL, "TC-AI-019 越界(ADC_SEM_COUNT) -> NULL"); - CHECK(adc_input_desc((adc_semantic_t)(-1)) == NULL, "TC-AI-01A 负数语义 -> NULL"); + CHECK(adc_input_desc(ADC_SEM_COUNT) == NULL, "TC-ADCIN-019 越界(ADC_SEM_COUNT) -> NULL"); + CHECK(adc_input_desc((adc_semantic_t)(-1)) == NULL, "TC-ADCIN-01A 负数语义 -> NULL"); } -/* ===================== TC-AI-020:map_check ===================== */ +/* ===================== TC-ADCIN-020:map_check ===================== */ static void tc_map_check(void) { /* 真实映射表自洽:TPAFE 下标 < 8 且每个 STM32 通道号都出现在扫描 Rank 内。 * 反向路径(表不自洽 -> -1)需在运行时改表,而 k_adc_map / k_stm32_rank_ch 均为 * 编译期 static const、无运行时输入可使其不自洽 -> 结构上不可达(见文件末说明)。 */ - CHECK(map_check() == 0, "TC-AI-020 映射表自洽(TPAFE 下标与 STM32 Rank 均在范围内)"); + CHECK(map_check() == 0, "TC-ADCIN-020 映射表自洽(TPAFE 下标与 STM32 Rank 均在范围内)"); } -/* ===================== TC-AI-021..02C:stm32_scan 成功路径 ===================== */ +/* ===================== TC-ADCIN-021..02C:stm32_scan 成功路径 ===================== */ static void tc_take_ok(void) { int32_t v = 0; @@ -284,25 +284,25 @@ static void tc_take_ok(void) { (void)adc_input_init(); dma_beat(100); /* 前半区一帧:Rank i -> 100+i */ - CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-AI-021 stm32_take 取到新帧 -> 0"); - CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_OK, "TC-AI-022 状态码 = RC_OK"); - CHECK(adc_input_stm32_errs() == 0u, "TC-AI-023 成功不计入失败"); - CHECK(s_start_dma_calls == 1, "TC-AI-024 DMA 只在 init 挂一次(每拍不重启)"); - CHECK(adc_input_stm32_seq() == 1u, "TC-AI-025 DMA 完成计数 = 1"); + CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-ADCIN-021 stm32_take 取到新帧 -> 0"); + CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_OK, "TC-ADCIN-022 状态码 = RC_OK"); + CHECK(adc_input_stm32_errs() == 0u, "TC-ADCIN-023 成功不计入失败"); + CHECK(s_start_dma_calls == 1, "TC-ADCIN-024 DMA 只在 init 挂一次(每拍不重启)"); + CHECK(adc_input_stm32_seq() == 1u, "TC-ADCIN-025 DMA 完成计数 = 1"); /* Rank -> 通道号映射:第 i 个 Rank = 100+i。 * k_stm32_rank_ch = [CH0..CH7, CH14],故 CH3->103 / CH5->105 / CH6->106 / CH14->108。 */ - CHECK((adc_input_raw(ADC_SEM_UB, &v) == 0) && (v == 108), "TC-AI-026 UB 取到 CH14(rank9)=108"); - CHECK((adc_input_raw(ADC_SEM_UC, &v) == 0) && (v == 103), "TC-AI-027 UC 取到 CH3(rank4)=103"); - CHECK((adc_input_raw(ADC_SEM_IB, &v) == 0) && (v == 106), "TC-AI-028 IB 取到 CH6(rank7)=106"); - CHECK((adc_input_raw(ADC_SEM_IC, &v) == 0) && (v == 101), "TC-AI-029 IC 取到 CH1(rank2)=101"); - CHECK((adc_input_raw(ADC_SEM_IN, &v) == 0) && (v == 102), "TC-AI-02A IN 取到 CH2(rank3)=102"); - CHECK((adc_input_raw(ADC_SEM_TEMP, &v) == 0) && (v == 105), "TC-AI-02B TEMP 取到 CH5(rank6)=105"); + CHECK((adc_input_raw(ADC_SEM_UB, &v) == 0) && (v == 108), "TC-ADCIN-026 UB 取到 CH14(rank9)=108"); + CHECK((adc_input_raw(ADC_SEM_UC, &v) == 0) && (v == 103), "TC-ADCIN-027 UC 取到 CH3(rank4)=103"); + CHECK((adc_input_raw(ADC_SEM_IB, &v) == 0) && (v == 106), "TC-ADCIN-028 IB 取到 CH6(rank7)=106"); + CHECK((adc_input_raw(ADC_SEM_IC, &v) == 0) && (v == 101), "TC-ADCIN-029 IC 取到 CH1(rank2)=101"); + CHECK((adc_input_raw(ADC_SEM_IN, &v) == 0) && (v == 102), "TC-ADCIN-02A IN 取到 CH2(rank3)=102"); + CHECK((adc_input_raw(ADC_SEM_TEMP, &v) == 0) && (v == 105), "TC-ADCIN-02B TEMP 取到 CH5(rank6)=105"); - CHECK(adc_input_raw(ADC_SEM_UA, &v) == -2, "TC-AI-02C stm32_take 不置 TPAFE 有效标志"); + CHECK(adc_input_raw(ADC_SEM_UA, &v) == -2, "TC-ADCIN-02C stm32_take 不置 TPAFE 有效标志"); } -/* ============ TC-AI-080..085:乒乓双缓冲(读刚完成半区,不读正在写的半区) ============ +/* ============ TC-ADCIN-080..085:乒乓双缓冲(读刚完成半区,不读正在写的半区) ============ * 这是 DMA 方案最关键的一条:消费侧必须读"上一拍刚完成的那一半",而 DMA 此刻正在 * 写另一半。若读错半区,取到的是**正在被改写**的数据 → 半新半旧的撕裂帧。 */ @@ -314,30 +314,30 @@ static void tc_dma_pingpong(void) { dma_beat(100); /* 第 1 帧 -> 前半区(半传输回调) */ dma_fill(1u, 900u); /* 模拟 DMA 正在写后半区(值 900 系) */ - CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-AI-080 第一拍取帧成功"); + CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-ADCIN-080 第一拍取帧成功"); CHECK((adc_input_raw(ADC_SEM_UB, &v) == 0) && (v == 108), - "TC-AI-081 读的是刚完成的前半区(108),不是正在写的后半区"); + "TC-ADCIN-081 读的是刚完成的前半区(108),不是正在写的后半区"); dma_beat(200); /* 第 2 帧 -> 后半区(传输完成回调) */ dma_fill(0u, 800u); /* 模拟 DMA 正在写前半区(值 800 系) */ - CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-AI-082 第二拍取帧成功"); + CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-ADCIN-082 第二拍取帧成功"); CHECK((adc_input_raw(ADC_SEM_UB, &v) == 0) && (v == 208), - "TC-AI-083 第二拍读到后半区(208)"); - CHECK(adc_input_stm32_seq() == 2u, "TC-AI-084 DMA 完成计数 = 2"); + "TC-ADCIN-083 第二拍读到后半区(208)"); + CHECK(adc_input_stm32_seq() == 2u, "TC-ADCIN-084 DMA 完成计数 = 2"); /* 半区奇偶口径:seq=1 -> 前半区,seq=2 -> 后半区(与 dma_beat 独立推导,互相证伪) */ - CHECK(((adc_input_raw(ADC_SEM_UC, &v) == 0) && (v == 203)), "TC-AI-085 UC 同帧内一致(203)"); + CHECK(((adc_input_raw(ADC_SEM_UC, &v) == 0) && (v == 203)), "TC-ADCIN-085 UC 同帧内一致(203)"); /* 消费者超拍:两拍都没取 -> 中间那帧已被乒乓缓冲覆盖 -> 记一次丢帧 */ dma_beat(300); dma_beat(400); - CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-AI-086 超拍后仍取到最新帧"); - CHECK(adc_input_stm32_gaps() == 1u, "TC-AI-087 seq 前进 2 -> 记一次丢帧"); - CHECK((adc_input_raw(ADC_SEM_UB, &v) == 0) && (v == 408), "TC-AI-088 取到的是最新帧(408)"); - CHECK(adc_input_stm32_errs() == 0u, "TC-AI-089 丢帧不计入停摆(两类故障分开)"); + CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-ADCIN-086 超拍后仍取到最新帧"); + CHECK(adc_input_stm32_gaps() == 1u, "TC-ADCIN-087 seq 前进 2 -> 记一次丢帧"); + CHECK((adc_input_raw(ADC_SEM_UB, &v) == 0) && (v == 408), "TC-ADCIN-088 取到的是最新帧(408)"); + CHECK(adc_input_stm32_errs() == 0u, "TC-ADCIN-089 丢帧不计入停摆(两类故障分开)"); } -/* ============ TC-AI-090..093:HAL 错误回调与句柄守卫 ============ */ +/* ============ TC-ADCIN-090..093:HAL 错误回调与句柄守卫 ============ */ static void tc_hw_errs(void) { fakes_reset(); @@ -345,21 +345,21 @@ static void tc_hw_errs(void) { HAL_ADC_ErrorCallback(&hadc1); HAL_ADC_ErrorCallback(&hadc1); - CHECK(adc_input_stm32_hw_errs() == 2u, "TC-AI-090 错误回调累计 = 2"); + CHECK(adc_input_stm32_hw_errs() == 2u, "TC-ADCIN-090 错误回调累计 = 2"); HAL_ADC_ErrorCallback(&hadc_other); - CHECK(adc_input_stm32_hw_errs() == 2u, "TC-AI-091 别的 ADC 句柄不得计入(hadc 守卫)"); + CHECK(adc_input_stm32_hw_errs() == 2u, "TC-ADCIN-091 别的 ADC 句柄不得计入(hadc 守卫)"); HAL_ADC_ConvHalfCpltCallback(&hadc_other); HAL_ADC_ConvCpltCallback(&hadc_other); - CHECK(adc_input_stm32_seq() == 0u, "TC-AI-092 别的句柄的完成回调不得推进 seq"); + CHECK(adc_input_stm32_seq() == 0u, "TC-ADCIN-092 别的句柄的完成回调不得推进 seq"); HAL_ADC_ErrorCallback(&hadc1); - CHECK(adc_input_stm32_hw_errs() == 3u, "TC-AI-093 hw_errs 与 errs 分开计数、互不干扰"); - CHECK(adc_input_stm32_errs() == 0u, "TC-AI-09A hw_errs 不污染 errs"); + CHECK(adc_input_stm32_hw_errs() == 3u, "TC-ADCIN-093 hw_errs 与 errs 分开计数、互不干扰"); + CHECK(adc_input_stm32_errs() == 0u, "TC-ADCIN-09A hw_errs 不污染 errs"); } -/* ===================== TC-AI-030..034:DMA 挂载失败 ===================== */ +/* ===================== TC-ADCIN-030..034:DMA 挂载失败 ===================== */ static void tc_init_dma_fail(void) { int32_t v = 0; @@ -367,13 +367,13 @@ static void tc_init_dma_fail(void) { fakes_reset(); s_start_dma_rc = HAL_ERROR; - CHECK(adc_input_init() == -2, "TC-AI-030 HAL_ADC_Start_DMA 失败 -> init 返回 -2"); - CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_START, "TC-AI-031 状态码 = RC_START"); - CHECK(adc_input_stm32_errs() == 1u, "TC-AI-032 失败计数 +1"); - CHECK(adc_input_raw(ADC_SEM_UB, &v) == -2, "TC-AI-034 挂载失败后 STM32 侧无有效数据"); + CHECK(adc_input_init() == -2, "TC-ADCIN-030 HAL_ADC_Start_DMA 失败 -> init 返回 -2"); + CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_START, "TC-ADCIN-031 状态码 = RC_START"); + CHECK(adc_input_stm32_errs() == 1u, "TC-ADCIN-032 失败计数 +1"); + CHECK(adc_input_raw(ADC_SEM_UB, &v) == -2, "TC-ADCIN-034 挂载失败后 STM32 侧无有效数据"); } -/* ===================== TC-AI-035..03A:本拍无新帧(停摆) ===================== */ +/* ===================== TC-ADCIN-035..03A:本拍无新帧(停摆) ===================== */ static void tc_take_stall(void) { int32_t v = 0; @@ -382,29 +382,29 @@ static void tc_take_stall(void) { (void)adc_input_init(); /* 没有任何 DMA 完成回调 = TIM3 未启动 / ADC 停摆 / DMA 出错 */ - CHECK(stm32_take() == ADC_INPUT_RC_STALL, "TC-AI-035 无新帧 -> RC_STALL(-2)"); - CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_STALL, "TC-AI-036 状态码 = RC_STALL"); - CHECK(adc_input_stm32_errs() == 0u, "TC-AI-037 单拍无新帧不计故障(相位伪影)"); - CHECK(adc_input_stm32_seq() == 0u, "TC-AI-038 停摆期间 seq 不前进"); - CHECK(adc_input_raw(ADC_SEM_UB, &v) == -2, "TC-AI-039 停摆拍 STM32 侧无有效数据"); + CHECK(stm32_take() == ADC_INPUT_RC_STALL, "TC-ADCIN-035 无新帧 -> RC_STALL(-2)"); + CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_STALL, "TC-ADCIN-036 状态码 = RC_STALL"); + CHECK(adc_input_stm32_errs() == 0u, "TC-ADCIN-037 单拍无新帧不计故障(相位伪影)"); + CHECK(adc_input_stm32_seq() == 0u, "TC-ADCIN-038 停摆期间 seq 不前进"); + CHECK(adc_input_raw(ADC_SEM_UB, &v) == -2, "TC-ADCIN-039 停摆拍 STM32 侧无有效数据"); (void)stm32_take(); /* 连续第二拍无新帧 = 真停摆 */ - CHECK(adc_input_stm32_errs() == 1u, "TC-AI-03A 连续两拍无新帧 -> 停摆计数 = 1"); + CHECK(adc_input_stm32_errs() == 1u, "TC-ADCIN-03A 连续两拍无新帧 -> 停摆计数 = 1"); (void)stm32_take(); /* 第三拍仍无新帧 */ - CHECK(adc_input_stm32_errs() == 2u, "TC-AI-03B 停摆持续 -> 每拍累计 = 2"); - CHECK(adc_input_stm32_gaps() == 0u, "TC-AI-03C 停摆不计入丢帧(两类故障分开)"); + CHECK(adc_input_stm32_errs() == 2u, "TC-ADCIN-03B 停摆持续 -> 每拍累计 = 2"); + CHECK(adc_input_stm32_gaps() == 0u, "TC-ADCIN-03C 停摆不计入丢帧(两类故障分开)"); dma_beat(100); /* 恢复 */ - CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-AI-03D 恢复后取帧成功"); - CHECK(adc_input_stm32_gaps() == 0u, "TC-AI-03E 恢复拍前进 1 -> 不算丢帧"); + CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-ADCIN-03D 恢复后取帧成功"); + CHECK(adc_input_stm32_gaps() == 0u, "TC-ADCIN-03E 恢复拍前进 1 -> 不算丢帧"); } -/* ============ TC-AI-070..078:停摆拍不得沿用上一拍旧值(陈旧帧) ============ +/* ============ TC-ADCIN-070..078:停摆拍不得沿用上一拍旧值(陈旧帧) ============ * 背景(2026-10-10 真机实测发现):本层只有一份 s_stm32_raw[],而 s_stm32_valid * 此前只在成功时置 1、失败时**从不清零** → 消费侧照样取数、照样压入采样环, * s_frames_skip 抓不到。轮询版的触发路径是"超时拍半新半旧",DMA 版(v2.0)改成 * "本拍无新帧仍沿用上一拍"——**同一条缺陷、同一个防线**,故本组用例保留。 - * TC-AI-034 是"挂载失败后本就无数据"(valid 一直是 0),照不出这条路径—— + * TC-ADCIN-034 是"挂载失败后本就无数据"(valid 一直是 0),照不出这条路径—— * 必须先成功一拍。 */ static void tc_take_stale(void) { @@ -414,27 +414,27 @@ static void tc_take_stale(void) { fakes_reset(); (void)adc_input_init(); dma_beat(100); - CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-AI-070 前置:首拍成功"); - CHECK((adc_input_raw(ADC_SEM_UB, &v) == 0) && (v == 108), "TC-AI-071 前置:UB 取到 108(有效态)"); + CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-ADCIN-070 前置:首拍成功"); + CHECK((adc_input_raw(ADC_SEM_UB, &v) == 0) && (v == 108), "TC-ADCIN-071 前置:UB 取到 108(有效态)"); /* 第二拍没有任何 DMA 完成(TIM3 停 / ADC 停摆 / DMA 出错) */ - CHECK(stm32_take() == ADC_INPUT_RC_STALL, "TC-AI-072 第二拍无新帧"); - CHECK(adc_input_raw(ADC_SEM_UB, &v) == -2, "TC-AI-073 停摆拍不得沿用上一拍值 -> -2"); - CHECK(adc_input_raw(ADC_SEM_UC, &v) == -2, "TC-AI-074 停摆拍连其它 STM32 通道也不得出数"); - CHECK(adc_input_raw(ADC_SEM_TEMP, &v) == -2, "TC-AI-074B 同上(TEMP 亦 -2)"); + CHECK(stm32_take() == ADC_INPUT_RC_STALL, "TC-ADCIN-072 第二拍无新帧"); + CHECK(adc_input_raw(ADC_SEM_UB, &v) == -2, "TC-ADCIN-073 停摆拍不得沿用上一拍值 -> -2"); + CHECK(adc_input_raw(ADC_SEM_UC, &v) == -2, "TC-ADCIN-074 停摆拍连其它 STM32 通道也不得出数"); + CHECK(adc_input_raw(ADC_SEM_TEMP, &v) == -2, "TC-ADCIN-074B 同上(TEMP 亦 -2)"); dma_beat(200); - CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-AI-075 第三拍恢复成功"); - CHECK((adc_input_raw(ADC_SEM_UB, &v) == 0) && (v == 208), "TC-AI-076 恢复拍重新可取数(自愈)"); + CHECK(stm32_take() == ADC_INPUT_RC_OK, "TC-ADCIN-075 第三拍恢复成功"); + CHECK((adc_input_raw(ADC_SEM_UB, &v) == 0) && (v == 208), "TC-ADCIN-076 恢复拍重新可取数(自愈)"); /* --- 挂载失败支路:同样不得沿用(init 失败后整层无有效数据) --- */ fakes_reset(); s_start_dma_rc = HAL_ERROR; (void)adc_input_init(); - CHECK(adc_input_raw(ADC_SEM_UB, &v) == -2, "TC-AI-078 挂载失败后不得取到任何值 -> -2"); + CHECK(adc_input_raw(ADC_SEM_UB, &v) == -2, "TC-ADCIN-078 挂载失败后不得取到任何值 -> -2"); } -/* ===================== TC-AI-040..045:raw 参数守卫与无数据 ===================== */ +/* ===================== TC-ADCIN-040..045:raw 参数守卫与无数据 ===================== */ static void tc_raw_guards(void) { int32_t v = 0; @@ -442,15 +442,15 @@ static void tc_raw_guards(void) { fakes_reset(); (void)adc_input_init(); - CHECK(adc_input_raw(ADC_SEM_UA, NULL) == -1, "TC-AI-040 out=NULL -> -1"); - CHECK(adc_input_raw(ADC_SEM_COUNT, &v) == -1, "TC-AI-041 ch 越界 -> -1"); - CHECK(adc_input_raw((adc_semantic_t)(-1), &v) == -1, "TC-AI-042 ch 负数 -> -1"); - CHECK(v == 0, "TC-AI-043 参数错时不写 out"); - CHECK(adc_input_raw(ADC_SEM_UA, &v) == -2, "TC-AI-044 TPAFE 无有效帧 -> -2"); - CHECK(adc_input_raw(ADC_SEM_UB, &v) == -2, "TC-AI-045 STM32 无有效扫描 -> -2"); + CHECK(adc_input_raw(ADC_SEM_UA, NULL) == -1, "TC-ADCIN-040 out=NULL -> -1"); + CHECK(adc_input_raw(ADC_SEM_COUNT, &v) == -1, "TC-ADCIN-041 ch 越界 -> -1"); + CHECK(adc_input_raw((adc_semantic_t)(-1), &v) == -1, "TC-ADCIN-042 ch 负数 -> -1"); + CHECK(v == 0, "TC-ADCIN-043 参数错时不写 out"); + CHECK(adc_input_raw(ADC_SEM_UA, &v) == -2, "TC-ADCIN-044 TPAFE 无有效帧 -> -2"); + CHECK(adc_input_raw(ADC_SEM_UB, &v) == -2, "TC-ADCIN-045 STM32 无有效扫描 -> -2"); } -/* ===================== TC-AI-046..04B:raw TPAFE 取数与补码 ===================== */ +/* ===================== TC-ADCIN-046..04B:raw TPAFE 取数与补码 ===================== */ static void tc_raw_tpafe(void) { int32_t v = 0; @@ -468,16 +468,16 @@ static void tc_raw_tpafe(void) { s_fake_tpafe[7] = 1007; s_snapshot_rc = 1; - CHECK(adc_input_poll() == 1, "TC-AI-046 poll 透传 TPAFE 快照码 1"); - CHECK(s_snapshot_count == (uint8_t)ADC_INPUT_TPAFE_CH_NUM, "TC-AI-047 快照请求 8 通道"); - CHECK(s_snapshot_dst != NULL, "TC-AI-048 快照目的缓冲非空"); - CHECK((adc_input_raw(ADC_SEM_UA, &v) == 0) && (v == 3006), "TC-AI-049 UA -> buf[6]=3006"); - CHECK((adc_input_raw(ADC_SEM_UN, &v) == 0) && (v == 2005), "TC-AI-04A UN -> buf[5]=2005"); + CHECK(adc_input_poll() == 1, "TC-ADCIN-046 poll 透传 TPAFE 快照码 1"); + CHECK(s_snapshot_count == (uint8_t)ADC_INPUT_TPAFE_CH_NUM, "TC-ADCIN-047 快照请求 8 通道"); + CHECK(s_snapshot_dst != NULL, "TC-ADCIN-048 快照目的缓冲非空"); + CHECK((adc_input_raw(ADC_SEM_UA, &v) == 0) && (v == 3006), "TC-ADCIN-049 UA -> buf[6]=3006"); + CHECK((adc_input_raw(ADC_SEM_UN, &v) == 0) && (v == 2005), "TC-ADCIN-04A UN -> buf[5]=2005"); CHECK((adc_input_raw(ADC_SEM_IA, &v) == 0) && (v == -1234), - "TC-AI-04B IA -> buf[2]=-1234(补码负值原样保留)"); + "TC-ADCIN-04B IA -> buf[2]=-1234(补码负值原样保留)"); } -/* ===================== TC-AI-050..058:poll 契约 ===================== */ +/* ===================== TC-ADCIN-050..058:poll 契约 ===================== */ static void tc_poll(void) { int32_t v = 0; @@ -487,16 +487,16 @@ static void tc_poll(void) { (void)adc_input_init(); s_snapshot_rc = 0; dma_beat(100); - CHECK(adc_input_poll() == 0, "TC-AI-050 快照无新帧 -> poll 返回 0"); - CHECK(adc_input_raw(ADC_SEM_UA, &v) == -2, "TC-AI-051 无新帧时 TPAFE 侧无效"); - CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_OK, "TC-AI-052 同拍 STM32 取帧照常执行"); + CHECK(adc_input_poll() == 0, "TC-ADCIN-050 快照无新帧 -> poll 返回 0"); + CHECK(adc_input_raw(ADC_SEM_UA, &v) == -2, "TC-ADCIN-051 无新帧时 TPAFE 侧无效"); + CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_OK, "TC-ADCIN-052 同拍 STM32 取帧照常执行"); /* --- 参数错(-1):返回 -1,TPAFE 无效 --- */ fakes_reset(); (void)adc_input_init(); s_snapshot_rc = -1; - CHECK(adc_input_poll() == -1, "TC-AI-053 快照参数错 -> poll 返回 -1"); - CHECK(adc_input_raw(ADC_SEM_UA, &v) == -2, "TC-AI-054 参数错时 TPAFE 侧无效"); + CHECK(adc_input_poll() == -1, "TC-ADCIN-053 快照参数错 -> poll 返回 -1"); + CHECK(adc_input_raw(ADC_SEM_UA, &v) == -2, "TC-ADCIN-054 参数错时 TPAFE 侧无效"); /* --- 已有有效帧后再"无新帧":保持上次有效值(不清零) --- */ fakes_reset(); @@ -507,7 +507,7 @@ static void tc_poll(void) { s_snapshot_rc = 0; (void)adc_input_poll(); CHECK((adc_input_raw(ADC_SEM_UA, &v) == 0) && (v == 777), - "TC-AI-055 已有有效帧后无新帧不清零"); + "TC-ADCIN-055 已有有效帧后无新帧不清零"); /* --- STM32 失败不阻断 TPAFE、不影响 poll 返回值 --- */ fakes_reset(); @@ -515,36 +515,36 @@ static void tc_poll(void) { s_fake_tpafe[2] = 55; s_snapshot_rc = 1; /* 不注入任何 DMA 完成 = STM32 侧停摆 */ - CHECK(adc_input_poll() == 1, "TC-AI-056 STM32 停摆不影响 poll 返回值(仍为 1)"); + CHECK(adc_input_poll() == 1, "TC-ADCIN-056 STM32 停摆不影响 poll 返回值(仍为 1)"); CHECK((adc_input_raw(ADC_SEM_IA, &v) == 0) && (v == 55), - "TC-AI-057 STM32 停摆不影响 TPAFE 取数"); - CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_STALL, "TC-AI-058 STM32 停摆另由状态码暴露"); + "TC-ADCIN-057 STM32 停摆不影响 TPAFE 取数"); + CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_STALL, "TC-ADCIN-058 STM32 停摆另由状态码暴露"); } -/* ===================== TC-AI-060..066:rc / errs 观测 ===================== */ +/* ===================== TC-ADCIN-060..066:rc / errs 观测 ===================== */ static void tc_rc_errs(void) { fakes_reset(); (void)adc_input_init(); - CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_NOT_RUN, "TC-AI-060 init 后未扫描 = NOT_RUN(-3)"); - CHECK(adc_input_stm32_errs() == 0u, "TC-AI-061 init 后失败计数 = 0"); + CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_NOT_RUN, "TC-ADCIN-060 init 后未扫描 = NOT_RUN(-3)"); + CHECK(adc_input_stm32_errs() == 0u, "TC-ADCIN-061 init 后失败计数 = 0"); dma_beat(100); (void)stm32_take(); /* 成功 */ CHECK((adc_input_stm32_rc() == ADC_INPUT_RC_OK) && (adc_input_stm32_errs() == 0u), - "TC-AI-062 成功: rc=OK 且 errs 不变"); + "TC-ADCIN-062 成功: rc=OK 且 errs 不变"); (void)stm32_take(); /* 停摆 1(单拍 = 相位伪影,不计) */ (void)stm32_take(); /* 停摆 2 -> 计 1 */ - CHECK(adc_input_stm32_errs() == 1u, "TC-AI-063 连续两拍停摆累计 = 1"); - CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_STALL, "TC-AI-064 rc = 最近一次(STALL)"); + CHECK(adc_input_stm32_errs() == 1u, "TC-ADCIN-063 连续两拍停摆累计 = 1"); + CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_STALL, "TC-ADCIN-064 rc = 最近一次(STALL)"); dma_beat(200); (void)stm32_take(); /* 恢复成功 */ - CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_OK, "TC-AI-065 恢复成功后 rc=OK"); - CHECK(adc_input_stm32_errs() == 1u, "TC-AI-066 errs 单调递增(不因成功回落)"); - CHECK(adc_input_stm32_seq() == 2u, "TC-AI-067 seq 只由 DMA 完成回调推进"); + CHECK(adc_input_stm32_rc() == ADC_INPUT_RC_OK, "TC-ADCIN-065 恢复成功后 rc=OK"); + CHECK(adc_input_stm32_errs() == 1u, "TC-ADCIN-066 errs 单调递增(不因成功回落)"); + CHECK(adc_input_stm32_seq() == 2u, "TC-ADCIN-067 seq 只由 DMA 完成回调推进"); } /* ===================== main ===================== */ diff --git a/test/host/cfg_file/cfg_file_test.c b/test/host/cfg_file/cfg_file_test.c index 25e587e6..d2212b0c 100644 --- a/test/host/cfg_file/cfg_file_test.c +++ b/test/host/cfg_file/cfg_file_test.c @@ -16,43 +16,43 @@ * * 覆盖点(对应 docs/测试说明/配置文件单元测试说明.md 的 TC-CFG-xxx): * —— 值类型编解码(s_encode / s_decode 经公开 load/save 间接验证 + 直接白盒)—— - * TC-CFG-001 UINT 1/2/4 字节小端往返(含 0 / 最大值) - * TC-CFG-002 UINT 非法:空 / 非数字 / 带后缀 / 超范围 - * TC-CFG-003 IP4 正常与非法(段数不足、>255、前导非数字、多余后缀) - * TC-CFG-004 MAC 三种分隔符 + 大小写 + 非法 - * TC-CFG-005 STR 正常 / 超长拒绝 / 边界(恰好放下) + * TC-CONFIG-001 UINT 1/2/4 字节小端往返(含 0 / 最大值) + * TC-CONFIG-002 UINT 非法:空 / 非数字 / 带后缀 / 超范围 + * TC-CONFIG-003 IP4 正常与非法(段数不足、>255、前导非数字、多余后缀) + * TC-CONFIG-004 MAC 三种分隔符 + 大小写 + 非法 + * TC-CONFIG-005 STR 正常 / 超长拒绝 / 边界(恰好放下) * —— INI 解析(s_split_line / s_match_section / s_key_value / s_parse)—— - * TC-CFG-010 注释(; 与 #)与空行忽略 - * TC-CFG-011 CRLF / LF 混排 - * TC-CFG-012 段名大小写无关匹配、前后空白修剪 - * TC-CFG-013 键名大小写无关、值前后空白修剪 - * TC-CFG-014 未知段 / 未知键留默认(不崩溃) - * TC-CFG-015 键值行出现在段头之前 = 忽略 + * TC-CONFIG-010 注释(; 与 #)与空行忽略 + * TC-CONFIG-011 CRLF / LF 混排 + * TC-CONFIG-012 段名大小写无关匹配、前后空白修剪 + * TC-CONFIG-013 键名大小写无关、值前后空白修剪 + * TC-CONFIG-014 未知段 / 未知键留默认(不崩溃) + * TC-CONFIG-015 键值行出现在段头之前 = 忽略 * —— 注册校验(cfg_file_register)—— - * TC-CFG-020 正常注册 / 重复段名拒绝 / NULL 参数拒绝 - * TC-CFG-021 非法键定义拒绝(UINT len 非 1/2/4、MAC len≠6、STR len>79) - * TC-CFG-022 段名超长拒绝(≥ CFG_NAME_MAX) - * TC-CFG-023 挂回调段 data_size > CFG_SNAP_MAX 拒绝 - * TC-CFG-024 键名超长拒绝(≥ CFG_NAME_MAX);恰好 15 字符(= CFG_FILE_MAX_NAME_LEN)接受 + * TC-CONFIG-020 正常注册 / 重复段名拒绝 / NULL 参数拒绝 + * TC-CONFIG-021 非法键定义拒绝(UINT len 非 1/2/4、MAC len≠6、STR len>79) + * TC-CONFIG-022 段名超长拒绝(≥ CFG_NAME_MAX) + * TC-CONFIG-023 挂回调段 data_size > CFG_SNAP_MAX 拒绝 + * TC-CONFIG-024 键名超长拒绝(≥ CFG_NAME_MAX);恰好 15 字符(= CFG_FILE_MAX_NAME_LEN)接受 * —— load 契约(cfg_file_load)—— - * TC-CFG-030 文件缺失 -> 生成出厂模板写盘 + 返回 0 - * TC-CFG-031 文件存在 -> 解析有效键进 RAM 副本 - * TC-CFG-032 超长文件(> CFG_FILE_MAX_LEN)-> 工厂默认 + 重建模板 + 自检留痕 - * TC-CFG-033 读取失败 -> 返回 -1(RAM 保持工厂默认) - * TC-CFG-034 未注册任何段 -> 返回 -1 + * TC-CONFIG-030 文件缺失 -> 生成出厂模板写盘 + 返回 0 + * TC-CONFIG-031 文件存在 -> 解析有效键进 RAM 副本 + * TC-CONFIG-032 超长文件(> CFG_FILE_MAX_LEN)-> 工厂默认 + 重建模板 + 自检留痕 + * TC-CONFIG-033 读取失败 -> 返回 -1(RAM 保持工厂默认) + * TC-CONFIG-034 未注册任何段 -> 返回 -1 * —— save 契约(cfg_file_save)—— - * TC-CFG-040 文件缺失 -> 重建完整文档 - * TC-CFG-041 外科手术:保留注释/未知段/未知键,受管键原位改写 - * TC-CFG-042 缺失受管段/键补写 - * TC-CFG-043 输出超长 -> 拒绝保存(-1) 且原文件不动 - * TC-CFG-044 受管键行超 CFG_LINE_TEST_MAX -> 拒绝保存(-1) 原文件不动(P2-1); + * TC-CONFIG-040 文件缺失 -> 重建完整文档 + * TC-CONFIG-041 外科手术:保留注释/未知段/未知键,受管键原位改写 + * TC-CONFIG-042 缺失受管段/键补写 + * TC-CONFIG-043 输出超长 -> 拒绝保存(-1) 且原文件不动 + * TC-CONFIG-044 受管键行超 CFG_LINE_TEST_MAX -> 拒绝保存(-1) 原文件不动(P2-1); * 非受管键的超长行照旧放过(原样保留) * —— poll 契约(cfg_file_poll)—— - * TC-CFG-050 首轮建立基线(不重载) - * TC-CFG-051 沉降去抖:连续 2 次稳定才重载 - * TC-CFG-052 与基线一致不重载 - * TC-CFG-053 变更后重载 + 挂回调段差异触发回调 - * TC-CFG-054 溢出到文件超长 -> 工厂默认 + 重建模板 + 自检留痕(不触发回调) + * TC-CONFIG-050 首轮建立基线(不重载) + * TC-CONFIG-051 沉降去抖:连续 2 次稳定才重载 + * TC-CONFIG-052 与基线一致不重载 + * TC-CONFIG-053 变更后重载 + 挂回调段差异触发回调 + * TC-CONFIG-054 溢出到文件超长 -> 工厂默认 + 重建模板 + 自检留痕(不触发回调) * * 通过:全部 TC PASS(main 返回 0)。 * 入口:int main(void),返回 0=PASS / 1=FAIL(由 run 脚本判读)。 @@ -333,9 +333,9 @@ static void register_std(void) { /* ===================== 用例 ===================== */ -/* TC-CFG-001/002:UINT 往返与非法值 */ +/* TC-CONFIG-001/002:UINT 往返与非法值 */ static void tc_uint(void) { - printf("[TC-CFG-001] UINT encode/decode round-trip\n"); + printf("[TC-CONFIG-001] UINT encode/decode round-trip\n"); { uint8_t d1[1]; uint8_t d2[2]; uint8_t d4[4]; CHECK(s_decode_uint(d1, 1u, "255") == 0 && d1[0] == 0xFFu, "u8 max 255"); @@ -349,7 +349,7 @@ static void tc_uint(void) { "u16 0x1234 little-endian order"); } - printf("[TC-CFG-002] UINT illegal values rejected\n"); + printf("[TC-CONFIG-002] UINT illegal values rejected\n"); { uint8_t d[4]; CHECK(s_decode_uint(d, 1u, "") == -1, "empty rejected"); @@ -362,11 +362,11 @@ static void tc_uint(void) { } } -/* TC-CFG-003:IP4 */ +/* TC-CONFIG-003:IP4 */ static void tc_ip4(void) { uint8_t d[4]; - printf("[TC-CFG-003] IPv4 decode\n"); + printf("[TC-CONFIG-003] IPv4 decode\n"); CHECK(s_decode_ip4(d, "0.0.0.0") == 0 && d[0] == 0u && d[3] == 0u, "all-zero"); CHECK(s_decode_ip4(d, "255.255.255.255") == 0 && d[0] == 255u && d[3] == 255u, "all-255"); @@ -380,11 +380,11 @@ static void tc_ip4(void) { CHECK(s_decode_ip4(d, "") == -1, "empty rejected"); } -/* TC-CFG-004:MAC */ +/* TC-CONFIG-004:MAC */ static void tc_mac(void) { uint8_t d[6]; - printf("[TC-CFG-004] MAC decode (separators/case)\n"); + printf("[TC-CONFIG-004] MAC decode (separators/case)\n"); CHECK(s_decode_mac(d, "00:11:22:33:44:55") == 0 && d[0] == 0x00u && d[5] == 0x55u, "colon separator"); CHECK(s_decode_mac(d, "00-11-22-33-44-55") == 0 && @@ -404,11 +404,11 @@ static void tc_mac(void) { CHECK(s_decode_mac(d, "") == -1, "empty rejected"); } -/* TC-CFG-005:STR */ +/* TC-CONFIG-005:STR */ static void tc_str(void) { uint8_t d[8]; - printf("[TC-CFG-005] STR decode (length boundary)\n"); + printf("[TC-CONFIG-005] STR decode (length boundary)\n"); CHECK(s_decode_str(d, 8u, "hello") == 0 && d[0] == 'h' && d[5] == '\0', "normal string + NUL"); CHECK(s_decode_str(d, 8u, "1234567") == 0 && d[6] == '7' && d[7] == '\0', @@ -417,9 +417,9 @@ static void tc_str(void) { CHECK(s_decode_str(d, 8u, "") == 0 && d[0] == '\0', "empty string ok"); } -/* TC-CFG-010~015:INI 解析 */ +/* TC-CONFIG-010~015:INI 解析 */ static void tc_parse(void) { - printf("[TC-CFG-010..015] INI parsing via load\n"); + printf("[TC-CONFIG-010..015] INI parsing via load\n"); { vfs_reset(); register_std(); @@ -446,7 +446,7 @@ static void tc_parse(void) { CHECK(s_sys_data.baud == 9600u, "multi-section: sys parsed"); } - printf("[TC-CFG-012] section/key name case-insensitive + value whitespace trim\n"); + printf("[TC-CONFIG-012] section/key name case-insensitive + value whitespace trim\n"); { vfs_reset(); register_std(); @@ -462,7 +462,7 @@ static void tc_parse(void) { CHECK(s_net_data.ip[0] == 1u && s_net_data.ip[3] == 4u, "value whitespace trimmed"); } - printf("[TC-CFG-011] LF-only line endings\n"); + printf("[TC-CONFIG-011] LF-only line endings\n"); { vfs_reset(); register_std(); @@ -472,7 +472,7 @@ static void tc_parse(void) { CHECK(s_net_data.ip[3] == 8u, "LF: ip parsed"); } - printf("[TC-CFG-015] key-value before any section ignored\n"); + printf("[TC-CONFIG-015] key-value before any section ignored\n"); { vfs_reset(); register_std(); @@ -482,7 +482,7 @@ static void tc_parse(void) { CHECK(s_net_data.ip[0] == 5u, "valid key after section parsed"); } - printf("[TC-CFG-014b] invalid value keeps factory default + logs\n"); + printf("[TC-CONFIG-014b] invalid value keeps factory default + logs\n"); { vfs_reset(); register_std(); @@ -495,9 +495,9 @@ static void tc_parse(void) { } } -/* TC-CFG-020~023:register 校验 */ +/* TC-CONFIG-020~023:register 校验 */ static void tc_register(void) { - printf("[TC-CFG-020] register validation\n"); + printf("[TC-CONFIG-020] register validation\n"); { cfg_section_reg_t r; vfs_reset(); @@ -518,7 +518,7 @@ static void tc_register(void) { CHECK(cfg_file_register(&r) == -1, "NULL p_data rejected"); } - printf("[TC-CFG-021] invalid key definitions rejected\n"); + printf("[TC-CONFIG-021] invalid key definitions rejected\n"); { cfg_section_reg_t r; static const cfg_key_def_t bad_uint[] = { { "k", CFG_VAL_UINT, 0u, 3u } }; @@ -544,7 +544,7 @@ static void tc_register(void) { CHECK(cfg_file_register(&r) == -1, "key len=0 rejected"); } - printf("[TC-CFG-022] section name length limit\n"); + printf("[TC-CONFIG-022] section name length limit\n"); { cfg_section_reg_t r; vfs_reset(); @@ -558,7 +558,7 @@ static void tc_register(void) { CHECK(cfg_file_register(&r) == -1, "section name >= 16 chars rejected"); } - printf("[TC-CFG-023] callback section data_size limit\n"); + printf("[TC-CONFIG-023] callback section data_size limit\n"); { cfg_section_reg_t r; vfs_reset(); @@ -576,7 +576,7 @@ static void tc_register(void) { CHECK(cfg_file_register(&r) == 0, "same section without callback accepted"); } - printf("[TC-CFG-024] key name length limit\n"); + printf("[TC-CONFIG-024] key name length limit\n"); { cfg_section_reg_t r; static const cfg_key_def_t long_key[] = { @@ -602,9 +602,9 @@ static void tc_register(void) { } } -/* TC-CFG-030~034:load 契约 */ +/* TC-CONFIG-030~034:load 契约 */ static void tc_load(void) { - printf("[TC-CFG-030] missing file -> factory template written\n"); + printf("[TC-CONFIG-030] missing file -> factory template written\n"); { vfs_reset(); register_std(); @@ -618,7 +618,7 @@ static void tc_load(void) { CHECK(strstr(vfs_get(), "u8=7") != NULL, "template has default u8=7"); } - printf("[TC-CFG-032] oversized file -> factory default + regenerate + syslog\n"); + printf("[TC-CONFIG-032] oversized file -> factory default + regenerate + syslog\n"); { size_t i; vfs_reset(); @@ -637,7 +637,7 @@ static void tc_load(void) { CHECK(s_vfs_len <= CFG_FILE_MAX_LEN, "file regenerated within limit"); } - printf("[TC-CFG-033] read failure -> -1, RAM keeps factory default\n"); + printf("[TC-CONFIG-033] read failure -> -1, RAM keeps factory default\n"); { vfs_reset(); register_std(); @@ -647,16 +647,16 @@ static void tc_load(void) { CHECK(s_net_data.u8 == s_net_def.u8, "RAM stays factory default"); } - printf("[TC-CFG-034] load with no registered section -> -1\n"); + printf("[TC-CONFIG-034] load with no registered section -> -1\n"); { vfs_reset(); CHECK(cfg_file_load() == -1, "no section registered returns -1"); } } -/* TC-CFG-040~043:save 契约 */ +/* TC-CONFIG-040~043:save 契约 */ static void tc_save(void) { - printf("[TC-CFG-040] save with missing file -> full document\n"); + printf("[TC-CONFIG-040] save with missing file -> full document\n"); { vfs_reset(); register_std(); @@ -668,7 +668,7 @@ static void tc_save(void) { CHECK(strstr(vfs_get(), "baud=38400") != NULL, "second section written"); } - printf("[TC-CFG-041] surgical save preserves comments/unknown\n"); + printf("[TC-CONFIG-041] surgical save preserves comments/unknown\n"); { vfs_reset(); register_std(); @@ -689,7 +689,7 @@ static void tc_save(void) { CHECK(strstr(vfs_get(), "u8=200") != NULL, "managed key rewritten in place"); } - printf("[TC-CFG-042] surgical save appends missing managed section/key\n"); + printf("[TC-CONFIG-042] surgical save appends missing managed section/key\n"); { vfs_reset(); register_std(); @@ -703,7 +703,7 @@ static void tc_save(void) { CHECK(strstr(vfs_get(), "baud=57600") != NULL, "missing key written"); } - printf("[TC-CFG-043] output overflow -> reject, original untouched\n"); + printf("[TC-CONFIG-043] output overflow -> reject, original untouched\n"); { size_t i; vfs_reset(); @@ -725,7 +725,7 @@ static void tc_save(void) { } } - printf("[TC-CFG-044] over-long managed key line -> reject (P2-1)\n"); + printf("[TC-CONFIG-044] over-long managed key line -> reject (P2-1)\n"); { char buf[512]; size_t n; @@ -772,9 +772,9 @@ static void tc_save(void) { } } -/* TC-CFG-050~054:poll 契约 */ +/* TC-CONFIG-050~054:poll 契约 */ static void tc_poll(void) { - printf("[TC-CFG-050] poll first round establishes baseline\n"); + printf("[TC-CONFIG-050] poll first round establishes baseline\n"); { vfs_reset(); register_std(); @@ -784,7 +784,7 @@ static void tc_poll(void) { CHECK(s_base_valid == 1u, "baseline established"); } - printf("[TC-CFG-051/052] settle debounce + no-change skip\n"); + printf("[TC-CONFIG-051/052] settle debounce + no-change skip\n"); { vfs_reset(); register_std(); @@ -801,7 +801,7 @@ static void tc_poll(void) { CHECK(s_net_data.u8 == 88u, "reloaded after settle"); } - printf("[TC-CFG-053] change triggers reload + callback\n"); + printf("[TC-CONFIG-053] change triggers reload + callback\n"); { vfs_reset(); register_std(); @@ -815,7 +815,7 @@ static void tc_poll(void) { CHECK(s_net_cb_count >= 1, "callback fired on section change"); } - printf("[TC-CFG-055] content change without size/mtime token change -> not detected\n"); + printf("[TC-CONFIG-055] content change without size/mtime token change -> not detected\n"); { vfs_reset(); register_std(); @@ -830,7 +830,7 @@ static void tc_poll(void) { "same-token change ignored (size+mtime is the change signal)"); } - printf("[TC-CFG-054] poll detects oversized file -> factory + regenerate + syslog\n"); + printf("[TC-CONFIG-054] poll detects oversized file -> factory + regenerate + syslog\n"); { size_t i; vfs_reset(); diff --git a/test/host/freq/freq_test.c b/test/host/freq/freq_test.c index 75232ab9..344be2ec 100644 --- a/test/host/freq/freq_test.c +++ b/test/host/freq/freq_test.c @@ -22,17 +22,17 @@ * 读数在跳变后 60 ms 内回到 ±0.05 Hz * * 覆盖点: - * TC-FR-001 50 Hz 收敛时序(J3)+ 稳态精度(J1 子集) - * TC-FR-002 扫频 45~55 Hz @0.5 Hz(J1,逐点判 + 最坏值打印) - * TC-FR-003 噪声鲁棒(J2,最坏值打印) - * TC-FR-004 频率阶跃 50->51(J4) - * TC-FR-005 零幅浮空不发散(J5)+ 恢复后重新收敛 - * TC-FR-006 直流偏置抑制(全周傅氏滤直流 -> 测频不受影响) - * TC-FR-007 3/5 次谐波污染抑制(相量基波选择性) - * TC-FR-008 相位跳变假值钳制(J6) - * TC-FR-009 UA 无幅值 -> 自动落 IA 源 - * TC-FR-010 init 幂等 / get 参数守卫 / 未收敛 -2 - * TC-FR-011 幅值门中途失效 -> valid 清零 + 读数保持(J5 中途版) + * TC-FREQ-001 50 Hz 收敛时序(J3)+ 稳态精度(J1 子集) + * TC-FREQ-002 扫频 45~55 Hz @0.5 Hz(J1,逐点判 + 最坏值打印) + * TC-FREQ-003 噪声鲁棒(J2,最坏值打印) + * TC-FREQ-004 频率阶跃 50->51(J4) + * TC-FREQ-005 零幅浮空不发散(J5)+ 恢复后重新收敛 + * TC-FREQ-006 直流偏置抑制(全周傅氏滤直流 -> 测频不受影响) + * TC-FREQ-007 3/5 次谐波污染抑制(相量基波选择性) + * TC-FREQ-008 相位跳变假值钳制(J6) + * TC-FREQ-009 UA 无幅值 -> 自动落 IA 源 + * TC-FREQ-010 init 幂等 / get 参数守卫 / 未收敛 -2 + * TC-FREQ-011 幅值门中途失效 -> valid 清零 + 读数保持(J5 中途版) * * 通过:全部 TC PASS(main 返回 0)。 * 创建日期:2026-10-12(B8) @@ -134,7 +134,7 @@ static void chain_reset(void) { (void)freq_init(); } -/* ===================== TC-FR-001:50 Hz 收敛时序 + 稳态精度 ===================== */ +/* ===================== TC-FREQ-001:50 Hz 收敛时序 + 稳态精度 ===================== */ static void tc_converge_50(void) { float f = 0.0f; uint32_t first_valid_t = 0u, phasor_ready_t = 0u; @@ -155,17 +155,17 @@ static void tc_converge_50(void) { got = 1; } } - CHECK(got, "TC-FR-001 freq becomes valid at 50 Hz"); + CHECK(got, "TC-FREQ-001 freq becomes valid at 50 Hz"); CHECK((first_valid_t >= phasor_ready_t) && ((first_valid_t - phasor_ready_t) <= 40u), - "TC-FR-001 J3: first valid reading <= 40 ms after first phasor"); + "TC-FREQ-001 J3: first valid reading <= 40 ms after first phasor"); (void)freq_get(&f); printf(" [DATA] 50 Hz steady: f=%.4f err=%.4f Hz (first valid @%u ms, phasor @%u ms)\n", (double)f, (double)f - 50.0, (unsigned)first_valid_t, (unsigned)phasor_ready_t); - CHECK(fabsf(f - 50.0f) <= 0.01f, "TC-FR-001 J1(50Hz): |err| <= 0.01 Hz"); + CHECK(fabsf(f - 50.0f) <= 0.01f, "TC-FREQ-001 J1(50Hz): |err| <= 0.01 Hz"); } -/* ===================== TC-FR-002:扫频 45~55 Hz @0.5 Hz(J1) ===================== */ +/* ===================== TC-FREQ-002:扫频 45~55 Hz @0.5 Hz(J1) ===================== */ static void tc_sweep(void) { double worst = 0.0, worst_f = 0.0; int ok = 1; @@ -178,17 +178,17 @@ static void tc_sweep(void) { chain_reset(); drive_n(150u, f_true, 1000.0, 0.0, 0.0, 0.0, 0.0, 1u); - CHECK(freq_get(&f_meas) == 0, "TC-FR-002 freq valid at each sweep point"); + CHECK(freq_get(&f_meas) == 0, "TC-FREQ-002 freq valid at each sweep point"); err = fabs((double)f_meas - f_true); if (err > worst) { worst = err; worst_f = f_true; } if (err > 0.02) { ok = 0; } } printf(" [DATA] sweep 45.00~55.00 Hz step 0.5: worst |err| = %.4f Hz @ %.1f Hz (J1 <= 0.02)\n", worst, worst_f); - CHECK(ok, "TC-FR-002 J1: |f_meas - f_true| <= 0.02 Hz over 45~55 Hz"); + CHECK(ok, "TC-FREQ-002 J1: |f_meas - f_true| <= 0.02 Hz over 45~55 Hz"); } -/* ===================== TC-FR-003:噪声鲁棒(J2) ===================== */ +/* ===================== TC-FREQ-003:噪声鲁棒(J2) ===================== */ static void tc_noise(void) { double worst = 0.0; int ok = 1; @@ -207,10 +207,10 @@ static void tc_noise(void) { if (err > 0.10) { ok = 0; } } printf(" [DATA] noise rms=1%% amp: worst |err| = %.4f Hz (J2 <= 0.10)\n", worst); - CHECK(ok, "TC-FR-003 J2: |err| <= 0.10 Hz with 1% noise"); + CHECK(ok, "TC-FREQ-003 J2: |err| <= 0.10 Hz with 1% noise"); } -/* ===================== TC-FR-004:频率阶跃 50->51(J4) ===================== */ +/* ===================== TC-FREQ-004:频率阶跃 50->51(J4) ===================== */ static void tc_step(void) { float f = 0.0f; uint32_t settle = 0u; @@ -236,12 +236,12 @@ static void tc_step(void) { } printf(" [DATA] step 50->51: settle = %u ms, final f=%.4f err=%.4f\n", (unsigned)settle, (double)f, (double)f - 51.0); - CHECK((settle != 0u) && (settle <= 120u), "TC-FR-004 J4: settle <= 120 ms"); - CHECK(ok, "TC-FR-004 J4: stays within +/-0.05 Hz after settle"); - CHECK(fabsf(f - 51.0f) <= 0.01f, "TC-FR-004 J1(51Hz): steady |err| <= 0.01 Hz"); + CHECK((settle != 0u) && (settle <= 120u), "TC-FREQ-004 J4: settle <= 120 ms"); + CHECK(ok, "TC-FREQ-004 J4: stays within +/-0.05 Hz after settle"); + CHECK(fabsf(f - 51.0f) <= 0.01f, "TC-FREQ-004 J1(51Hz): steady |err| <= 0.01 Hz"); } -/* ===================== TC-FR-005:零幅浮空不发散(J5) ===================== */ +/* ===================== TC-FREQ-005:零幅浮空不发散(J5) ===================== */ static void tc_zero_amp(void) { float f = 123.0f; uint32_t i; @@ -254,17 +254,17 @@ static void tc_zero_amp(void) { (void)freq_get(&f); if (!(f == f)) { no_nan = 0; } /* NaN 自比较为假 */ } - CHECK(never_valid, "TC-FR-005 J5: zero-amplitude never asserts valid"); - CHECK(no_nan && (f == 0.0f), "TC-FR-005 J5: reading stays 0, no divergence/NaN"); + CHECK(never_valid, "TC-FREQ-005 J5: zero-amplitude never asserts valid"); + CHECK(no_nan && (f == 0.0f), "TC-FREQ-005 J5: reading stays 0, no divergence/NaN"); /* 恢复:重新注入波形后应再次收敛 */ drive_n(150u, 49.0, 1000.0, 0.0, 0.0, 0.0, 0.0, 1u); (void)freq_get(&f); printf(" [DATA] recover after float: f=%.4f err=%.4f\n", (double)f, (double)f - 49.0); CHECK((freq_valid() != 0u) && (fabsf(f - 49.0f) <= 0.01f), - "TC-FR-005 recovers and meets J1 after waveform returns"); + "TC-FREQ-005 recovers and meets J1 after waveform returns"); } -/* ===================== TC-FR-006:直流偏置抑制 ===================== */ +/* ===================== TC-FREQ-006:直流偏置抑制 ===================== */ static void tc_dc_offset(void) { float f = 0.0f; @@ -272,10 +272,10 @@ static void tc_dc_offset(void) { drive_n(150u, 50.3, 1000.0, 8000.0, 0.0, 0.0, 0.0, 1u); /* DC = 8000 码 */ (void)freq_get(&f); printf(" [DATA] DC=8000: f=%.4f err=%.4f\n", (double)f, (double)f - 50.3); - CHECK(fabsf(f - 50.3f) <= 0.01f, "TC-FR-006 DC offset rejected: |err| <= 0.01 Hz"); + CHECK(fabsf(f - 50.3f) <= 0.01f, "TC-FREQ-006 DC offset rejected: |err| <= 0.01 Hz"); } -/* ===================== TC-FR-007:3/5 次谐波污染 ===================== */ +/* ===================== TC-FREQ-007:3/5 次谐波污染 ===================== */ static void tc_harmonics(void) { float f = 0.0f; @@ -283,10 +283,10 @@ static void tc_harmonics(void) { drive_n(150u, 48.0, 1000.0, 0.0, 200.0, 100.0, 0.0, 1u); /* 20%/10% 谐波 */ (void)freq_get(&f); printf(" [DATA] h3=20%% h5=10%%: f=%.4f err=%.4f\n", (double)f, (double)f - 48.0); - CHECK(fabsf(f - 48.0f) <= 0.01f, "TC-FR-007 harmonics rejected: |err| <= 0.01 Hz"); + CHECK(fabsf(f - 48.0f) <= 0.01f, "TC-FREQ-007 harmonics rejected: |err| <= 0.01 Hz"); } -/* ===================== TC-FR-008:相位跳变假值钳制(J6) ===================== */ +/* ===================== TC-FREQ-008:相位跳变假值钳制(J6) ===================== */ static void tc_phase_jump(void) { float f = 0.0f; uint32_t i; @@ -306,11 +306,11 @@ static void tc_phase_jump(void) { } printf(" [DATA] after jump: f=%.4f err=%.4f (recover window 60 ms)\n", (double)f, (double)f - 50.0); - CHECK(ok, "TC-FR-008 J6: recovers to +/-0.05 Hz within 60 ms after jump"); - CHECK(freq_valid() != 0u, "TC-FR-008 J6: still valid after clamp path"); + CHECK(ok, "TC-FREQ-008 J6: recovers to +/-0.05 Hz within 60 ms after jump"); + CHECK(freq_valid() != 0u, "TC-FREQ-008 J6: still valid after clamp path"); } -/* ===================== TC-FR-009:UA 无幅值 -> IA 回退 ===================== */ +/* ===================== TC-FREQ-009:UA 无幅值 -> IA 回退 ===================== */ static void tc_src_fallback(void) { float f = 0.0f; @@ -319,39 +319,39 @@ static void tc_src_fallback(void) { (void)freq_get(&f); printf(" [DATA] UA=0 IA=1000: f=%.4f err=%.4f\n", (double)f, (double)f - 52.0); CHECK((freq_valid() != 0u) && (fabsf(f - 52.0f) <= 0.01f), - "TC-FR-009 falls back to IA source when UA below amplitude gate"); + "TC-FREQ-009 falls back to IA source when UA below amplitude gate"); } -/* ===================== TC-FR-010:init 幂等 / 参数守卫 ===================== */ +/* ===================== TC-FREQ-010:init 幂等 / 参数守卫 ===================== */ static void tc_init_guards(void) { float f = 5.0f; chain_reset(); - CHECK(freq_get(&f) == -2, "TC-FR-010 get before convergence -> -2"); - CHECK((f == 0.0f), "TC-FR-010 get -2 writes 0 to out"); - CHECK(freq_get(NULL) == -1, "TC-FR-010 NULL out -> -1"); - CHECK(freq_valid() == 0u, "TC-FR-010 valid=0 before convergence"); - CHECK(freq_last() == 0.0f, "TC-FR-010 last=0 before convergence"); + CHECK(freq_get(&f) == -2, "TC-FREQ-010 get before convergence -> -2"); + CHECK((f == 0.0f), "TC-FREQ-010 get -2 writes 0 to out"); + CHECK(freq_get(NULL) == -1, "TC-FREQ-010 NULL out -> -1"); + CHECK(freq_valid() == 0u, "TC-FREQ-010 valid=0 before convergence"); + CHECK(freq_last() == 0.0f, "TC-FREQ-010 last=0 before convergence"); (void)freq_init(); - CHECK(freq_get(&f) == -2, "TC-FR-010 freq_init idempotent (still -2)"); + CHECK(freq_get(&f) == -2, "TC-FREQ-010 freq_init idempotent (still -2)"); } -/* ===================== TC-FR-011:幅值门中途失效 -> 保持 ===================== */ +/* ===================== TC-FREQ-011:幅值门中途失效 -> 保持 ===================== */ static void tc_gate_hold(void) { float f_before = 0.0f, f_after = 0.0f; chain_reset(); drive_n(150u, 50.0, 1000.0, 0.0, 0.0, 0.0, 0.0, 1u); (void)freq_get(&f_before); - CHECK(freq_valid() == 1u, "TC-FR-011 valid before gate loss"); + CHECK(freq_valid() == 1u, "TC-FREQ-011 valid before gate loss"); drive_n(50u, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1u); /* 波形消失 */ - CHECK(freq_valid() == 0u, "TC-FR-011 J5: valid cleared on gate loss"); + CHECK(freq_valid() == 0u, "TC-FREQ-011 J5: valid cleared on gate loss"); (void)freq_get(&f_after); printf(" [DATA] hold: before=%.4f held=%.4f delta=%.4f\n", (double)f_before, (double)f_after, (double)(f_after - f_before)); CHECK(fabsf(f_after - f_before) <= 0.3f, - "TC-FR-011 J5: reading bounded (|delta| <= 0.3 Hz) during gate loss"); + "TC-FREQ-011 J5: reading bounded (|delta| <= 0.3 Hz) during gate loss"); } int main(void) { diff --git a/test/host/ftp_auth/ftp_auth_test.c b/test/host/ftp_auth/ftp_auth_test.c index 4938e2ac..0f91f267 100644 --- a/test/host/ftp_auth/ftp_auth_test.c +++ b/test/host/ftp_auth/ftp_auth_test.c @@ -13,16 +13,16 @@ * 毫秒级穷举。用户名侧信道路径(错用户名也走哈希)同属纯逻辑。 * * 覆盖点: - * TC-FA-001 user_match:相等 / 大小写不敏感 / 不等 / NULL - * TC-FA-002 正确用户名+正确口令 → OK,计数 0 - * TC-FA-003 错口令 → FAIL,计数 1 - * TC-FA-004 错用户名+对口令 → FAIL(哈希路径已走,时间拉平) - * TC-FA-005 连续 5 次失败 → 第 6 次(锁定期内)LOCKED,对口令也拒 - * TC-FA-006 锁定期满(+60000 tick)→ 对口令 OK,计数清零 - * TC-FA-007 成功清零计数:3 败 + 1 成 → 再 4 败不触发锁定(第 5 败才锁) - * TC-FA-008 tick 32 位回绕:锁定期内回绕点仍 LOCKED,期满回绕点放行 - * TC-FA-009 配置 pwd_hash 非法 hex → 恒 FAIL(fail-closed) - * TC-FA-010 空口令 / NULL 口令 → FAIL;NULL creds/state → FAIL + * TC-FTPAUTH-001 user_match:相等 / 大小写不敏感 / 不等 / NULL + * TC-FTPAUTH-002 正确用户名+正确口令 → OK,计数 0 + * TC-FTPAUTH-003 错口令 → FAIL,计数 1 + * TC-FTPAUTH-004 错用户名+对口令 → FAIL(哈希路径已走,时间拉平) + * TC-FTPAUTH-005 连续 5 次失败 → 第 6 次(锁定期内)LOCKED,对口令也拒 + * TC-FTPAUTH-006 锁定期满(+60000 tick)→ 对口令 OK,计数清零 + * TC-FTPAUTH-007 成功清零计数:3 败 + 1 成 → 再 4 败不触发锁定(第 5 败才锁) + * TC-FTPAUTH-008 tick 32 位回绕:锁定期内回绕点仍 LOCKED,期满回绕点放行 + * TC-FTPAUTH-009 配置 pwd_hash 非法 hex → 恒 FAIL(fail-closed) + * TC-FTPAUTH-010 空口令 / NULL 口令 → FAIL;NULL creds/state → FAIL * * 通过:全部 TC PASS(main 返回 0)。 * 入口:int main(void),返回 0=PASS / 1=FAIL(由 run 脚本判读)。 @@ -54,18 +54,18 @@ static int s_failed; static const ftp_auth_creds_t s_creds = { "admin", DEF_HASH, 1u }; -/* ===================== TC-FA-001:user_match ===================== */ +/* ===================== TC-FTPAUTH-001:user_match ===================== */ static void tc_user_match(void) { - CHECK(ftp_auth_user_match("admin", "admin") == 1, "TC-FA-001a 相等匹配"); - CHECK(ftp_auth_user_match("admin", "ADMIN") == 1, "TC-FA-001b 大小写不敏感"); - CHECK(ftp_auth_user_match("admin", "root") == 0, "TC-FA-001c 不等拒绝"); - CHECK(ftp_auth_user_match("admin", "admin2") == 0, "TC-FA-001d 前缀不算匹配"); - CHECK(ftp_auth_user_match("admin", NULL) == 0, "TC-FA-001e NULL 拒绝"); + CHECK(ftp_auth_user_match("admin", "admin") == 1, "TC-FTPAUTH-001a 相等匹配"); + CHECK(ftp_auth_user_match("admin", "ADMIN") == 1, "TC-FTPAUTH-001b 大小写不敏感"); + CHECK(ftp_auth_user_match("admin", "root") == 0, "TC-FTPAUTH-001c 不等拒绝"); + CHECK(ftp_auth_user_match("admin", "admin2") == 0, "TC-FTPAUTH-001d 前缀不算匹配"); + CHECK(ftp_auth_user_match("admin", NULL) == 0, "TC-FTPAUTH-001e NULL 拒绝"); } -/* ===================== TC-FA-002..004:基本判定 ===================== */ +/* ===================== TC-FTPAUTH-002..004:基本判定 ===================== */ static void tc_basic(void) { @@ -73,20 +73,20 @@ static void tc_basic(void) (void)memset(&st, 0, sizeof(st)); CHECK(ftp_auth_check(&s_creds, 1u, "admin", &st, 1000u) == FTP_AUTH_OK, - "TC-FA-002 对用户名+对口令 → OK"); - CHECK(st.fail_count == 0u, "TC-FA-002b 成功后计数为 0"); + "TC-FTPAUTH-002 对用户名+对口令 → OK"); + CHECK(st.fail_count == 0u, "TC-FTPAUTH-002b 成功后计数为 0"); (void)memset(&st, 0, sizeof(st)); CHECK(ftp_auth_check(&s_creds, 1u, "wrong", &st, 1000u) == FTP_AUTH_FAIL, - "TC-FA-003 错口令 → FAIL"); - CHECK(st.fail_count == 1u, "TC-FA-003b 失败计数 1"); + "TC-FTPAUTH-003 错口令 → FAIL"); + CHECK(st.fail_count == 1u, "TC-FTPAUTH-003b 失败计数 1"); (void)memset(&st, 0, sizeof(st)); CHECK(ftp_auth_check(&s_creds, 0u, "admin", &st, 1000u) == FTP_AUTH_FAIL, - "TC-FA-004 错用户名+对口令 → FAIL(哈希路径已走)"); + "TC-FTPAUTH-004 错用户名+对口令 → FAIL(哈希路径已走)"); } -/* ===================== TC-FA-005..006:锁定与解锁 ===================== */ +/* ===================== TC-FTPAUTH-005..006:锁定与解锁 ===================== */ static void tc_lock(void) { @@ -96,25 +96,25 @@ static void tc_lock(void) (void)memset(&st, 0, sizeof(st)); for (int i = 0; i < 5; i++) { CHECK(ftp_auth_check(&s_creds, 1u, "wrong", &st, t) == FTP_AUTH_FAIL, - "TC-FA-005 第 1..5 次失败 → FAIL"); + "TC-FTPAUTH-005 第 1..5 次失败 → FAIL"); } - CHECK(st.fail_count == 5u, "TC-FA-005b 计数到达 FAIL_MAX"); + CHECK(st.fail_count == 5u, "TC-FTPAUTH-005b 计数到达 FAIL_MAX"); /* 锁定期内:对口令也 LOCKED,且不再计数 */ CHECK(ftp_auth_check(&s_creds, 1u, "admin", &st, t + 1u) == FTP_AUTH_LOCKED, - "TC-FA-005c 锁定期内对口令 → LOCKED"); - CHECK(st.fail_count == 5u, "TC-FA-005d LOCKED 不改变计数"); + "TC-FTPAUTH-005c 锁定期内对口令 → LOCKED"); + CHECK(st.fail_count == 5u, "TC-FTPAUTH-005d LOCKED 不改变计数"); /* 59999 tick:仍在窗内(差值 < 60000) */ CHECK(ftp_auth_check(&s_creds, 1u, "admin", &st, st.lock_until_tick - 1u) == FTP_AUTH_LOCKED, - "TC-FA-005e 窗内最后 1 tick 仍 LOCKED"); + "TC-FTPAUTH-005e 窗内最后 1 tick 仍 LOCKED"); /* 期满:恰好到达 lock_until → 放行 */ CHECK(ftp_auth_check(&s_creds, 1u, "admin", &st, st.lock_until_tick) == FTP_AUTH_OK, - "TC-FA-006 期满对口令 → OK"); - CHECK(st.fail_count == 0u, "TC-FA-006b 解锁成功后计数清零"); + "TC-FTPAUTH-006 期满对口令 → OK"); + CHECK(st.fail_count == 0u, "TC-FTPAUTH-006b 解锁成功后计数清零"); } -/* ===================== TC-FA-007:成功清零计数 ===================== */ +/* ===================== TC-FTPAUTH-007:成功清零计数 ===================== */ static void tc_reset(void) { @@ -126,19 +126,19 @@ static void tc_reset(void) (void)ftp_auth_check(&s_creds, 1u, "wrong", &st, t); } CHECK(ftp_auth_check(&s_creds, 1u, "admin", &st, t) == FTP_AUTH_OK, - "TC-FA-007a 3 败后成功 → OK"); - CHECK(st.fail_count == 0u, "TC-FA-007b 成功清零"); + "TC-FTPAUTH-007a 3 败后成功 → OK"); + CHECK(st.fail_count == 0u, "TC-FTPAUTH-007b 成功清零"); for (int i = 0; i < 4; i++) { CHECK(ftp_auth_check(&s_creds, 1u, "wrong", &st, t) == FTP_AUTH_FAIL, - "TC-FA-007c 清零后再 4 败仍 FAIL(未锁)"); + "TC-FTPAUTH-007c 清零后再 4 败仍 FAIL(未锁)"); } CHECK(ftp_auth_check(&s_creds, 1u, "wrong", &st, t) == FTP_AUTH_FAIL, - "TC-FA-007d 第 5 败 FAIL 并上锁"); + "TC-FTPAUTH-007d 第 5 败 FAIL 并上锁"); CHECK(ftp_auth_check(&s_creds, 1u, "admin", &st, t + 1u) == FTP_AUTH_LOCKED, - "TC-FA-007e 连续 5 败后 LOCKED"); + "TC-FTPAUTH-007e 连续 5 败后 LOCKED"); } -/* ===================== TC-FA-008:tick 32 位回绕 ===================== */ +/* ===================== TC-FTPAUTH-008:tick 32 位回绕 ===================== */ static void tc_wraparound(void) { @@ -150,13 +150,13 @@ static void tc_wraparound(void) st.lock_until_tick = 0xFFFFFFF0u; /* 回绕前 240 tick:仍在窗内 */ CHECK(ftp_auth_check(&s_creds, 1u, "admin", &st, 0xFFFFFF00u) == FTP_AUTH_LOCKED, - "TC-FA-008a 回绕前窗内 → LOCKED"); + "TC-FTPAUTH-008a 回绕前窗内 → LOCKED"); /* 回绕后 32 tick:now=0x10,(int32_t)(0x10-0xFFFFFFF0)=+32 → 期满 */ CHECK(ftp_auth_check(&s_creds, 1u, "admin", &st, 0x00000010u) == FTP_AUTH_OK, - "TC-FA-008b 回绕后期满 → OK(有符号差抗回绕)"); + "TC-FTPAUTH-008b 回绕后期满 → OK(有符号差抗回绕)"); } -/* ===================== TC-FA-009..010:fail-closed 边界 ===================== */ +/* ===================== TC-FTPAUTH-009..010:fail-closed 边界 ===================== */ static void tc_fail_closed(void) { @@ -165,17 +165,17 @@ static void tc_fail_closed(void) (void)memset(&st, 0, sizeof(st)); CHECK(ftp_auth_check(&bad_creds, 1u, "admin", &st, 1000u) == FTP_AUTH_FAIL, - "TC-FA-009 非法 hex 配置 → 恒 FAIL(无人能登录,fail-closed)"); + "TC-FTPAUTH-009 非法 hex 配置 → 恒 FAIL(无人能登录,fail-closed)"); (void)memset(&st, 0, sizeof(st)); CHECK(ftp_auth_check(&s_creds, 1u, "", &st, 1000u) == FTP_AUTH_FAIL, - "TC-FA-010a 空口令 → FAIL"); + "TC-FTPAUTH-010a 空口令 → FAIL"); CHECK(ftp_auth_check(&s_creds, 1u, NULL, &st, 1000u) == FTP_AUTH_FAIL, - "TC-FA-010b NULL 口令 → FAIL"); + "TC-FTPAUTH-010b NULL 口令 → FAIL"); CHECK(ftp_auth_check(NULL, 1u, "admin", &st, 1000u) == FTP_AUTH_FAIL, - "TC-FA-010c NULL creds → FAIL"); + "TC-FTPAUTH-010c NULL creds → FAIL"); CHECK(ftp_auth_check(&s_creds, 1u, "admin", NULL, 1000u) == FTP_AUTH_FAIL, - "TC-FA-010d NULL state → FAIL"); + "TC-FTPAUTH-010d NULL state → FAIL"); } /* ===================== main ===================== */ diff --git a/test/host/iec104/iec104_test.c b/test/host/iec104/iec104_test.c index 3464e93b..f162a1b3 100644 --- a/test/host/iec104/iec104_test.c +++ b/test/host/iec104/iec104_test.c @@ -10,29 +10,29 @@ * 发送经 send_apdu 回调全量捕获,时基由测试注入。 * * 覆盖点(docs/子系统设计/IEC104上行设计说明.md §7): - * TC-104-001 CP56Time2a 往返 / 闰年 / IV / 钳位 - * TC-104-002 IOA 3B 与短浮点小端往返 - * TC-104-003 APCI 重组:半帧 / 粘帧 / 坏起始符 / 坏长度 - * TC-104-004 STARTDT 握手 → RUN - * TC-104-005 OPEN 态 I 帧忽略(序号不消费) - * TC-104-006 总召全流程:actcon→4 分片(首召 COT=4)→actterm;二召 COT=2;RBT→COT=4 - * TC-104-007 遥信变位 COV(COT=3);无效位不触发 - * TC-104-008 遥测死区 COV:死区内不发 / 越死区发 - * TC-104-009 k 窗:12 未确认停发;S 确认后恢复 - * TC-104-010 w 阈:收满 8 发 S - * TC-104-011 t2 到期发 S - * TC-104-012 t3 空闲发 TESTFR act;未答 t1 超时 → IDLE;con 清挂起不误杀 - * TC-104-013 遥控两段式:选择/执行成功;失配 PN;拒绝类选择段即 PN - * TC-104-014 定值两段写(真实 prot_set):越界 PN;执行后 get_f + selfcheck - * TC-104-015 C_RD:YC 命中 / 定值命中 / 未知 IOA COT14+EVI - * TC-104-016 C_CS:clock_sync 收正确 epoch;IV → PN;clock_sync 失败 → PN - * TC-104-017 未知类型 COT12+EVI;错公共地址 COT13+EVI - * TC-104-018 STOPDT:数据停发,TESTFR 仍应答 - * TC-104-019 序号错 → IDLE(链路故障) - * TC-104-020 pts:无效通道 IV / 未就绪 NT / 无效遥信 IV / is_dp / 表尺寸 - * TC-104-021 C_TS / C_RP actcon - * TC-104-022 周期上送 COT=1(YC 组 + 频率) - * TC-104-023 k 窗满 COV 不丢事件(pend 暂存,窗开后补发) + * TC-IEC104-001 CP56Time2a 往返 / 闰年 / IV / 钳位 + * TC-IEC104-002 IOA 3B 与短浮点小端往返 + * TC-IEC104-003 APCI 重组:半帧 / 粘帧 / 坏起始符 / 坏长度 + * TC-IEC104-004 STARTDT 握手 → RUN + * TC-IEC104-005 OPEN 态 I 帧忽略(序号不消费) + * TC-IEC104-006 总召全流程:actcon→4 分片(首召 COT=4)→actterm;二召 COT=2;RBT→COT=4 + * TC-IEC104-007 遥信变位 COV(COT=3);无效位不触发 + * TC-IEC104-008 遥测死区 COV:死区内不发 / 越死区发 + * TC-IEC104-009 k 窗:12 未确认停发;S 确认后恢复 + * TC-IEC104-010 w 阈:收满 8 发 S + * TC-IEC104-011 t2 到期发 S + * TC-IEC104-012 t3 空闲发 TESTFR act;未答 t1 超时 → IDLE;con 清挂起不误杀 + * TC-IEC104-013 遥控两段式:选择/执行成功;失配 PN;拒绝类选择段即 PN + * TC-IEC104-014 定值两段写(真实 prot_set):越界 PN;执行后 get_f + selfcheck + * TC-IEC104-015 C_RD:YC 命中 / 定值命中 / 未知 IOA COT14+EVI + * TC-IEC104-016 C_CS:clock_sync 收正确 epoch;IV → PN;clock_sync 失败 → PN + * TC-IEC104-017 未知类型 COT12+EVI;错公共地址 COT13+EVI + * TC-IEC104-018 STOPDT:数据停发,TESTFR 仍应答 + * TC-IEC104-019 序号错 → IDLE(链路故障) + * TC-IEC104-020 pts:无效通道 IV / 未就绪 NT / 无效遥信 IV / is_dp / 表尺寸 + * TC-IEC104-021 C_TS / C_RP actcon + * TC-IEC104-022 周期上送 COT=1(YC 组 + 频率) + * TC-IEC104-023 k 窗满 COV 不丢事件(pend 暂存,窗开后补发) * * 通过:全部 TC PASS(main 返回 0)。 * 创建日期:2026-10-12(B4) diff --git a/test/host/nand_port/nand_port_test.c b/test/host/nand_port/nand_port_test.c index fb22635c..93e08593 100644 --- a/test/host/nand_port/nand_port_test.c +++ b/test/host/nand_port/nand_port_test.c @@ -21,15 +21,15 @@ * 主机侧由 harness 的 /utf-8 保证注释里的中文被正确解码。 * * 用例前缀:TC-NP-NNN(NP = NAND Port);分组: - * TC-NP-000 假芯片自洽(几何 / 上电态) - * TC-NP-100..108 dhara_nand_is_free 整页扫描(N-12) - * TC-NP-110..112 dhara_nand_is_free 越界守卫(N-13) - * TC-NP-200..207 dhara_nand_prog(越界 / NULL / 往返 / 双编程探针 / 失败注入) - * TC-NP-300..307 dhara_nand_read(越界 / 越窗 offset+length / 部分读 / ECC / E-42) - * TC-NP-400..405 dhara_nand_copy(src 与 dst 双端守卫 / 正常搬页) - * TC-NP-500..504 dhara_nand_erase(越界块零标坏块 / 整块回 0xFF / 失败注入) - * TC-NP-600..605 dhara_nand_is_bad / dhara_nand_mark_bad(越界保守判坏、BBT 不变) - * TC-NP-700 dhara map 级场景(写入 -> 重新 resume,双编程计数为 0) + * TC-NANDPORT-000 假芯片自洽(几何 / 上电态) + * TC-NANDPORT-100..108 dhara_nand_is_free 整页扫描(N-12) + * TC-NANDPORT-110..112 dhara_nand_is_free 越界守卫(N-13) + * TC-NANDPORT-200..207 dhara_nand_prog(越界 / NULL / 往返 / 双编程探针 / 失败注入) + * TC-NANDPORT-300..307 dhara_nand_read(越界 / 越窗 offset+length / 部分读 / ECC / E-42) + * TC-NANDPORT-400..405 dhara_nand_copy(src 与 dst 双端守卫 / 正常搬页) + * TC-NANDPORT-500..504 dhara_nand_erase(越界块零标坏块 / 整块回 0xFF / 失败注入) + * TC-NANDPORT-600..605 dhara_nand_is_bad / dhara_nand_mark_bad(越界保守判坏、BBT 不变) + * TC-NANDPORT-700 dhara map 级场景(写入 -> 重新 resume,双编程计数为 0) * * 通过:全部 CHECK 通过(main 返回 0)。 * 入口:int main(void),返回 0=PASS / 1=FAIL(由 run 脚本判读)。 @@ -402,7 +402,7 @@ static int s_failed; /* dhara 核心(真实源,非桩):nand_ftl.c 引用 dhara_map_*,必须一并纳入才能链接。 * 纳入后本编译单元 = 移植层 + 它服务的 FTL 本体,故 dhara map 级场景 - * (TC-NP-700 写入 -> 重新 resume)测的是真链路。顺序:journal 在 map 之前。 */ + * (TC-NANDPORT-700 写入 -> 重新 resume)测的是真链路。顺序:journal 在 map 之前。 */ #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 4100 4244 4334 4701) @@ -428,7 +428,7 @@ static struct dhara_nand s_ut_nand; * N-12 修复**之前**的 dhara_nand_is_free:只读页首 64 B 就回答"空闲"。 * 本函数按当时的形状内联一份(同样经假芯片的两段式读),用来证明本套件**有牙**: * 对同一页,旧算法答 1(误判空闲)、新实现答 0。将来有人把 is_free 改回只看 - * 页首,TC-NP-105 立刻变红——而不是"测试跟着实现一起改回去"。 + * 页首,TC-NANDPORT-105 立刻变红——而不是"测试跟着实现一起改回去"。 */ static int old_is_free_first64(const struct dhara_nand *n, dhara_page_t p) { uint8_t buf[64]; @@ -449,18 +449,18 @@ static int old_is_free_first64(const struct dhara_nand *n, dhara_page_t p) { return 1; } -/* ===================== TC-NP-100..108:dhara_nand_is_free(整页扫描) ===================== +/* ===================== TC-NANDPORT-100..108:dhara_nand_is_free(整页扫描) ===================== * * N-12:旧实现只看页首 64 B,会把"页首 0xFF、后段有数据"的已编程页误判空闲 * -> dhara 往已编程页再编程 = 数据丢失。本组把"必须扫完整页"钉死, - * 并用 TC-NP-105 的旧算法对照证明这组断言真的能咬人。 + * 并用 TC-NANDPORT-105 的旧算法对照证明这组断言真的能咬人。 */ static void tc_is_free(void) { static uint8_t page_buf[FAKE_PAGE_SIZE]; struct dhara_nand zeroed; - /* TC-NP-100:整页擦除 -> 1 */ - printf("[TC-NP-100] erased page is free\n"); + /* TC-NANDPORT-100:整页擦除 -> 1 */ + printf("[TC-NANDPORT-100] erased page is free\n"); fake_chip_reset(); CHECK(dhara_nand_is_free(&s_ut_nand, 0u) == 1, "erased page -> is_free = 1"); CHECK(g_fake_page_read_cnt == 1u, "one page_read only (no per-byte commands)"); @@ -469,8 +469,8 @@ static void tc_is_free(void) { CHECK(g_fake_isfree_scan_cnt == (FAKE_PAGE_SIZE / 64u), "64B column-read fingerprint calibrated (proves scenario really calls is_free)"); - /* TC-NP-101:第 0 字节有数据 -> 0(快路径) */ - printf("[TC-NP-101] byte 0 programmed -> not free\n"); + /* TC-NANDPORT-101:第 0 字节有数据 -> 0(快路径) */ + printf("[TC-NANDPORT-101] byte 0 programmed -> not free\n"); fake_chip_reset(); (void)memset(page_buf, 0xFF, sizeof(page_buf)); page_buf[0] = 0x00u; @@ -479,10 +479,10 @@ static void tc_is_free(void) { CHECK(g_fake_read_cache_cnt == 1u, "early exit on first chunk = fast path (same cost as the old impl)"); - /* TC-NP-102:N-12 回归用例 + /* TC-NANDPORT-102:N-12 回归用例 * 页首 64 B 全 0xFF、第 1000 字节 = 0x00 -> 必须答"非空"。 * 旧实现只看页首 64 B 会误判空闲,dhara 遂往这一页再编程。 */ - printf("[TC-NP-102] N-12 regression: hole in first 64B, data at byte 1000\n"); + printf("[TC-NANDPORT-102] N-12 regression: hole in first 64B, data at byte 1000\n"); fake_chip_reset(); (void)memset(page_buf, 0xFF, sizeof(page_buf)); page_buf[1000] = 0x00u; @@ -492,8 +492,8 @@ static void tc_is_free(void) { CHECK(g_fake_read_cache_cnt > 1u, "scan continues past the first 64B (old impl stopped here = root cause)"); - /* TC-NP-103:只有最后一个字节非 0xFF -> 0 */ - printf("[TC-NP-103] only last byte programmed -> not free\n"); + /* TC-NANDPORT-103:只有最后一个字节非 0xFF -> 0 */ + printf("[TC-NANDPORT-103] only last byte programmed -> not free\n"); fake_chip_reset(); (void)memset(page_buf, 0xFF, sizeof(page_buf)); page_buf[FAKE_PAGE_SIZE - 1u] = 0x5Au; @@ -503,8 +503,8 @@ static void tc_is_free(void) { CHECK(g_fake_read_cache_cnt == (FAKE_PAGE_SIZE / 64u), "full scan to the page tail before answering (32 column reads)"); - /* TC-NP-104:只有第 64 字节非 0xFF -> 0(旧窗口右边界外的第一个字节) */ - printf("[TC-NP-104] only byte 64 programmed -> not free\n"); + /* TC-NANDPORT-104:只有第 64 字节非 0xFF -> 0(旧窗口右边界外的第一个字节) */ + printf("[TC-NANDPORT-104] only byte 64 programmed -> not free\n"); fake_chip_reset(); (void)memset(page_buf, 0xFF, sizeof(page_buf)); page_buf[64u] = 0x00u; @@ -512,10 +512,10 @@ static void tc_is_free(void) { CHECK(dhara_nand_is_free(&s_ut_nand, 4u) == 0, "only byte 64 (first byte outside the old window) -> is_free = 0"); - /* TC-NP-105:旧算法对照(证明本套件有牙) + /* TC-NANDPORT-105:旧算法对照(证明本套件有牙) * 同一页形态:旧算法答 1 = 误判空闲,新实现答 0。 * 任何人把 is_free 改回"只看页首",这条立刻红。 */ - printf("[TC-NP-105] old-algorithm contrast (test has teeth)\n"); + printf("[TC-NANDPORT-105] old-algorithm contrast (test has teeth)\n"); fake_chip_reset(); (void)memset(page_buf, 0xFF, sizeof(page_buf)); page_buf[1000] = 0x00u; @@ -525,8 +525,8 @@ static void tc_is_free(void) { CHECK(dhara_nand_is_free(&s_ut_nand, 5u) == 0, "new implementation answers not-free -> 0 (opposite verdict = teeth)"); - /* TC-NP-106:读失败保守判非空(E-42 同族) */ - printf("[TC-NP-106] read failure is answered conservatively\n"); + /* TC-NANDPORT-106:读失败保守判非空(E-42 同族) */ + printf("[TC-NANDPORT-106] read failure is answered conservatively\n"); fake_chip_reset(); s_fail_page_read = 1; CHECK(dhara_nand_is_free(&s_ut_nand, 6u) == 0, @@ -536,8 +536,8 @@ static void tc_is_free(void) { CHECK(dhara_nand_is_free(&s_ut_nand, 7u) == 0, "read_from_cache failure -> not free (E-42 family)"); - /* TC-NP-107:NULL / num_blocks = 0 的几何守卫 */ - printf("[TC-NP-107] NULL geometry / zero blocks guard\n"); + /* TC-NANDPORT-107:NULL / num_blocks = 0 的几何守卫 */ + printf("[TC-NANDPORT-107] NULL geometry / zero blocks guard\n"); fake_chip_reset(); CHECK(dhara_nand_is_free(NULL, 0u) == 0, "n = NULL -> not free, no crash"); CHECK(fake_chip_access_total() == 0u, "n = NULL causes zero chip access"); @@ -547,8 +547,8 @@ static void tc_is_free(void) { CHECK(dhara_nand_is_free(&zeroed, 0u) == 0, "num_blocks = 0 -> not free"); CHECK(fake_chip_access_total() == 0u, "num_blocks = 0 causes zero chip access"); - /* TC-NP-108:擦除后重新判空(假芯片语义自洽,防"擦除没生效"假绿) */ - printf("[TC-NP-108] fake chip erase really clears the array\n"); + /* TC-NANDPORT-108:擦除后重新判空(假芯片语义自洽,防"擦除没生效"假绿) */ + printf("[TC-NANDPORT-108] fake chip erase really clears the array\n"); fake_chip_reset(); fake_fill_pattern(page_buf, FAKE_PAGE_SIZE, 7u); fake_poke_page(8u, page_buf, FAKE_PAGE_SIZE); @@ -557,9 +557,9 @@ static void tc_is_free(void) { CHECK(dhara_nand_is_free(&s_ut_nand, 8u) == 1, "after erase -> free (fake chip sane)"); } -/* ===================== TC-NP-110..112:is_free 越界守卫(N-13) ===================== */ +/* ===================== TC-NANDPORT-110..112:is_free 越界守卫(N-13) ===================== */ static void tc_is_free_oob(void) { - printf("[TC-NP-110] is_free out-of-range pages (N-13)\n"); + printf("[TC-NANDPORT-110] is_free out-of-range pages (N-13)\n"); fake_chip_reset(); CHECK(dhara_nand_is_free(&s_ut_nand, DHARA_PAGE_NONE) == 0, @@ -567,13 +567,13 @@ static void tc_is_free_oob(void) { CHECK(fake_chip_access_total() == 0u, "DHARA_PAGE_NONE causes zero chip access (no truncated address)"); - printf("[TC-NP-111] is_free at total_pages boundary\n"); + printf("[TC-NANDPORT-111] is_free at total_pages boundary\n"); fake_chip_reset(); CHECK(dhara_nand_is_free(&s_ut_nand, UT_OOB_PAGE) == 0, "page == total_pages -> is_free = 0"); CHECK(fake_chip_access_total() == 0u, "page == total_pages -> zero chip access"); - printf("[TC-NP-112] is_free beyond total_pages\n"); + printf("[TC-NANDPORT-112] is_free beyond total_pages\n"); fake_chip_reset(); CHECK(dhara_nand_is_free(&s_ut_nand, UT_OOB_PAGE + 1u) == 0, "page == total_pages + 1 -> is_free = 0"); @@ -586,13 +586,13 @@ static int fake_no_write_access(void) { (g_fake_program_exec_cnt == 0u) && (g_fake_block_erase_cnt == 0u); } -/* ===================== TC-NP-200..205:dhara_nand_prog ===================== */ +/* ===================== TC-NANDPORT-200..205:dhara_nand_prog ===================== */ static void tc_prog(void) { static uint8_t page_buf[FAKE_PAGE_SIZE]; dhara_error_t err; - /* TC-NP-200:越界页 -> -1 + CORRUPT_MAP + 零写入 */ - printf("[TC-NP-200] prog out-of-range page -> -1, zero write\n"); + /* TC-NANDPORT-200:越界页 -> -1 + CORRUPT_MAP + 零写入 */ + printf("[TC-NANDPORT-200] prog out-of-range page -> -1, zero write\n"); fake_chip_reset(); fake_fill_pattern(page_buf, FAKE_PAGE_SIZE, 11u); err = DHARA_E_NONE; @@ -602,10 +602,10 @@ static void tc_prog(void) { CHECK(fake_no_write_access(), "prog out-of-range -> zero write access"); CHECK(g_fake_mark_bad_cnt == 0u, "prog out-of-range -> no block marked bad"); - /* TC-NP-201:DHARA_PAGE_NONE -> -1 + CORRUPT_MAP + 零写入 + /* TC-NANDPORT-201:DHARA_PAGE_NONE -> -1 + CORRUPT_MAP + 零写入 * 旧实现会把 0xffffffff 加偏移送进 SPI 命令,被地址位截断成某个真实页 * -> 静默写坏无辜数据;现在必须在守卫处就挡住。 */ - printf("[TC-NP-201] prog DHARA_PAGE_NONE -> -1, zero write (N-13)\n"); + printf("[TC-NANDPORT-201] prog DHARA_PAGE_NONE -> -1, zero write (N-13)\n"); fake_chip_reset(); err = DHARA_E_NONE; CHECK(dhara_nand_prog(&s_ut_nand, DHARA_PAGE_NONE, page_buf, &err) == -1, @@ -613,16 +613,16 @@ static void tc_prog(void) { CHECK(err == DHARA_E_CORRUPT_MAP, "prog DHARA_PAGE_NONE -> DHARA_E_CORRUPT_MAP"); CHECK(fake_chip_access_total() == 0u, "prog DHARA_PAGE_NONE -> zero chip access"); - /* TC-NP-202:data == NULL -> -1(守卫顺带挡住空指针) */ - printf("[TC-NP-202] prog with NULL data -> -1\n"); + /* TC-NANDPORT-202:data == NULL -> -1(守卫顺带挡住空指针) */ + printf("[TC-NANDPORT-202] prog with NULL data -> -1\n"); fake_chip_reset(); err = DHARA_E_NONE; CHECK(dhara_nand_prog(&s_ut_nand, 0u, NULL, &err) == -1, "prog data = NULL -> -1"); CHECK(err == DHARA_E_CORRUPT_MAP, "prog data = NULL -> DHARA_E_CORRUPT_MAP"); CHECK(fake_no_write_access(), "prog data = NULL -> zero write access"); - /* TC-NP-203:正常页 -> 0 且回读一致 */ - printf("[TC-NP-203] prog a valid page -> 0, read-back matches\n"); + /* TC-NANDPORT-203:正常页 -> 0 且回读一致 */ + printf("[TC-NANDPORT-203] prog a valid page -> 0, read-back matches\n"); fake_chip_reset(); err = DHARA_E_NONE; CHECK(dhara_nand_prog(&s_ut_nand, 64u, page_buf, &err) == 0, "prog page 64 -> 0"); @@ -630,8 +630,8 @@ static void tc_prog(void) { CHECK(fake_page_equals(64u, page_buf, FAKE_PAGE_SIZE), "prog page 64 content on chip"); CHECK(g_fake_double_program_cnt == 0u, "prog onto an erased page -> no violation"); - /* TC-NP-204:最后一个合法页(上界内边界) */ - printf("[TC-NP-204] prog last valid page (boundary inside)\n"); + /* TC-NANDPORT-204:最后一个合法页(上界内边界) */ + printf("[TC-NANDPORT-204] prog last valid page (boundary inside)\n"); fake_chip_reset(); err = DHARA_E_NONE; CHECK(dhara_nand_prog(&s_ut_nand, UT_TOTAL_PAGES - 1u, page_buf, &err) == 0, @@ -639,8 +639,8 @@ static void tc_prog(void) { CHECK(fake_page_equals(UT_TOTAL_PAGES - 1u, page_buf, FAKE_PAGE_SIZE), "last valid page content on chip"); - /* TC-NP-205:双编程探针自检——同一页再编程必须被记违规(防探针是死码) */ - printf("[TC-NP-205] double-program probe really fires\n"); + /* TC-NANDPORT-205:双编程探针自检——同一页再编程必须被记违规(防探针是死码) */ + printf("[TC-NANDPORT-205] double-program probe really fires\n"); fake_chip_reset(); err = DHARA_E_NONE; (void)dhara_nand_prog(&s_ut_nand, 128u, page_buf, &err); @@ -648,8 +648,8 @@ static void tc_prog(void) { CHECK(g_fake_double_program_cnt == 1u, "reprogramming a programmed page -> 1 violation"); CHECK(g_fake_last_double_program_page == 128u, "violation records the offending page"); - /* TC-NP-206:编程失败 -> BAD_BLOCK + 标坏该块(错误分类不被守卫改动破坏) */ - printf("[TC-NP-206] program failure -> BAD_BLOCK + mark bad\n"); + /* TC-NANDPORT-206:编程失败 -> BAD_BLOCK + 标坏该块(错误分类不被守卫改动破坏) */ + printf("[TC-NANDPORT-206] program failure -> BAD_BLOCK + mark bad\n"); fake_chip_reset(); s_fail_program_exec = 1; err = DHARA_E_NONE; @@ -659,9 +659,9 @@ static void tc_prog(void) { CHECK(g_fake_mark_bad_cnt == 1u, "program failure marks exactly one block bad"); CHECK(g_fake_mark_bad_log[0] == 2u, "the block marked bad is the page's own block"); - /* TC-NP-207:program_load 失败(装载阶段)-> 同样 BAD_BLOCK + 标坏该块, + /* TC-NANDPORT-207:program_load 失败(装载阶段)-> 同样 BAD_BLOCK + 标坏该块, * 且在 exec 之前就短路(真实芯片:02h 都没成,10h 自然不发) */ - printf("[TC-NP-207] program_load failure -> BAD_BLOCK + mark bad\n"); + printf("[TC-NANDPORT-207] program_load failure -> BAD_BLOCK + mark bad\n"); fake_chip_reset(); s_fail_program_load = 1; err = DHARA_E_NONE; @@ -673,14 +673,14 @@ static void tc_prog(void) { CHECK(g_fake_mark_bad_log[0] == 3u, "the block marked bad is the page's own block"); } -/* ===================== TC-NP-300..307:dhara_nand_read ===================== */ +/* ===================== TC-NANDPORT-300..307:dhara_nand_read ===================== */ static void tc_read(void) { static uint8_t page_buf[FAKE_PAGE_SIZE]; static uint8_t rd[FAKE_PAGE_SIZE]; dhara_error_t err; - /* TC-NP-300/301:越界页 -> -1 + CORRUPT_MAP + 零访问 */ - printf("[TC-NP-300] read out-of-range page -> -1, zero access\n"); + /* TC-NANDPORT-300/301:越界页 -> -1 + CORRUPT_MAP + 零访问 */ + printf("[TC-NANDPORT-300] read out-of-range page -> -1, zero access\n"); fake_chip_reset(); err = DHARA_E_NONE; CHECK(dhara_nand_read(&s_ut_nand, UT_OOB_PAGE, 0u, 512u, rd, &err) == -1, @@ -688,7 +688,7 @@ static void tc_read(void) { CHECK(err == DHARA_E_CORRUPT_MAP, "read out-of-range -> DHARA_E_CORRUPT_MAP"); CHECK(fake_chip_access_total() == 0u, "read out-of-range -> zero chip access"); - printf("[TC-NP-301] read DHARA_PAGE_NONE -> -1, zero access\n"); + printf("[TC-NANDPORT-301] read DHARA_PAGE_NONE -> -1, zero access\n"); fake_chip_reset(); err = DHARA_E_NONE; CHECK(dhara_nand_read(&s_ut_nand, DHARA_PAGE_NONE, 0u, 512u, rd, &err) == -1, @@ -696,8 +696,8 @@ static void tc_read(void) { CHECK(err == DHARA_E_CORRUPT_MAP, "read DHARA_PAGE_NONE -> DHARA_E_CORRUPT_MAP"); CHECK(fake_chip_access_total() == 0u, "read DHARA_PAGE_NONE -> zero chip access"); - /* TC-NP-302:offset + length 越过 2048 -> -1 */ - printf("[TC-NP-302] read spanning past the page end -> -1\n"); + /* TC-NANDPORT-302:offset + length 越过 2048 -> -1 */ + printf("[TC-NANDPORT-302] read spanning past the page end -> -1\n"); fake_chip_reset(); err = DHARA_E_NONE; CHECK(dhara_nand_read(&s_ut_nand, 0u, 2000u, 100u, rd, &err) == -1, @@ -712,16 +712,16 @@ static void tc_read(void) { CHECK(dhara_nand_read(&s_ut_nand, 0u, 0u, FAKE_PAGE_SIZE + 1u, rd, &err) == -1, "read length 2049 -> -1"); - /* TC-NP-303:NULL data -> -1 */ - printf("[TC-NP-303] read with NULL data -> -1\n"); + /* TC-NANDPORT-303:NULL data -> -1 */ + printf("[TC-NANDPORT-303] read with NULL data -> -1\n"); fake_chip_reset(); err = DHARA_E_NONE; CHECK(dhara_nand_read(&s_ut_nand, 0u, 0u, 512u, NULL, &err) == -1, "read data = NULL -> -1"); CHECK(fake_chip_access_total() == 0u, "read data = NULL -> zero chip access"); - /* TC-NP-304:正常部分读 -> 0 且内容正确 */ - printf("[TC-NP-304] partial read returns the right slice\n"); + /* TC-NANDPORT-304:正常部分读 -> 0 且内容正确 */ + printf("[TC-NANDPORT-304] partial read returns the right slice\n"); prep_content_page(page_buf, 21u); err = DHARA_E_NONE; CHECK(dhara_nand_read(&s_ut_nand, UT_SRC_PAGE, 1024u, 512u, rd, &err) == 0, @@ -729,16 +729,16 @@ static void tc_read(void) { CHECK(memcmp(rd, &page_buf[1024], 512u) == 0, "partial read returns the right bytes"); CHECK(g_fake_page_read_cnt == 1u, "partial read issues one page_read"); - /* TC-NP-305:整页读 -> 0 且内容正确(边界 length == 2048) */ - printf("[TC-NP-305] full page read\n"); + /* TC-NANDPORT-305:整页读 -> 0 且内容正确(边界 length == 2048) */ + printf("[TC-NANDPORT-305] full page read\n"); prep_content_page(page_buf, 21u); err = DHARA_E_NONE; CHECK(dhara_nand_read(&s_ut_nand, UT_SRC_PAGE, 0u, FAKE_PAGE_SIZE, rd, &err) == 0, "full page read (length == 2048) -> 0"); CHECK(memcmp(rd, page_buf, FAKE_PAGE_SIZE) == 0, "full page read matches the chip"); - /* TC-NP-306:ECC 不可纠正 -> -1 + DHARA_E_ECC */ - printf("[TC-NP-306] uncorrectable ECC -> -1 + DHARA_E_ECC\n"); + /* TC-NANDPORT-306:ECC 不可纠正 -> -1 + DHARA_E_ECC */ + printf("[TC-NANDPORT-306] uncorrectable ECC -> -1 + DHARA_E_ECC\n"); prep_content_page(page_buf, 21u); s_fail_check_ecc = 1; err = DHARA_E_NONE; @@ -746,8 +746,8 @@ static void tc_read(void) { "check_ecc failure -> -1"); CHECK(err == DHARA_E_ECC, "check_ecc failure -> DHARA_E_ECC"); - /* TC-NP-307:E-42 同族——read_from_cache 失败必须 -1(旧实现返回 0 交垃圾) */ - printf("[TC-NP-307] E-42: read_from_cache failure must not report success\n"); + /* TC-NANDPORT-307:E-42 同族——read_from_cache 失败必须 -1(旧实现返回 0 交垃圾) */ + printf("[TC-NANDPORT-307] E-42: read_from_cache failure must not report success\n"); prep_content_page(page_buf, 21u); s_fail_read_cache = 1; err = DHARA_E_NONE; @@ -756,13 +756,13 @@ static void tc_read(void) { CHECK(err == DHARA_E_ECC, "read_from_cache failure -> DHARA_E_ECC"); } -/* ===================== TC-NP-400..405:dhara_nand_copy ===================== */ +/* ===================== TC-NANDPORT-400..405:dhara_nand_copy ===================== */ static void tc_copy(void) { static uint8_t page_buf[FAKE_PAGE_SIZE]; dhara_error_t err; - /* TC-NP-400:src 越界 -> -1 + CORRUPT_MAP + 零写入 */ - printf("[TC-NP-400] copy with out-of-range src -> -1, zero write\n"); + /* TC-NANDPORT-400:src 越界 -> -1 + CORRUPT_MAP + 零写入 */ + printf("[TC-NANDPORT-400] copy with out-of-range src -> -1, zero write\n"); fake_chip_reset(); err = DHARA_E_NONE; CHECK(dhara_nand_copy(&s_ut_nand, UT_OOB_PAGE, 100u, &err) == -1, @@ -771,8 +771,8 @@ static void tc_copy(void) { CHECK(fake_no_write_access(), "copy bad src -> zero write access"); CHECK(fake_chip_access_total() == 0u, "copy bad src -> zero chip access at all"); - /* TC-NP-401:src = DHARA_PAGE_NONE -> -1 + CORRUPT_MAP */ - printf("[TC-NP-401] copy with DHARA_PAGE_NONE src -> -1\n"); + /* TC-NANDPORT-401:src = DHARA_PAGE_NONE -> -1 + CORRUPT_MAP */ + printf("[TC-NANDPORT-401] copy with DHARA_PAGE_NONE src -> -1\n"); fake_chip_reset(); err = DHARA_E_NONE; CHECK(dhara_nand_copy(&s_ut_nand, DHARA_PAGE_NONE, 100u, &err) == -1, @@ -780,9 +780,9 @@ static void tc_copy(void) { CHECK(err == DHARA_E_CORRUPT_MAP, "copy DHARA_PAGE_NONE src -> DHARA_E_CORRUPT_MAP"); CHECK(fake_chip_access_total() == 0u, "copy DHARA_PAGE_NONE src -> zero chip access"); - /* TC-NP-402:dst 越界 -> -1 + CORRUPT_MAP + 零写入 + 零标坏块 + /* TC-NANDPORT-402:dst 越界 -> -1 + CORRUPT_MAP + 零写入 + 零标坏块 * dst 越界最致命:那是一次写入,旧实现会静默写进被截断出来的无辜页。 */ - printf("[TC-NP-402] copy with out-of-range dst -> -1, zero write, zero mark-bad\n"); + printf("[TC-NANDPORT-402] copy with out-of-range dst -> -1, zero write, zero mark-bad\n"); prep_content_page(page_buf, 31u); err = DHARA_E_NONE; CHECK(dhara_nand_copy(&s_ut_nand, UT_SRC_PAGE, UT_OOB_PAGE, &err) == -1, @@ -791,8 +791,8 @@ static void tc_copy(void) { CHECK(fake_no_write_access(), "copy bad dst -> zero write access"); CHECK(g_fake_mark_bad_cnt == 0u, "copy bad dst -> no block marked bad"); - /* TC-NP-403:dst = DHARA_PAGE_NONE(哨兵漏进来的真实形态) */ - printf("[TC-NP-403] copy with DHARA_PAGE_NONE dst -> -1, zero write\n"); + /* TC-NANDPORT-403:dst = DHARA_PAGE_NONE(哨兵漏进来的真实形态) */ + printf("[TC-NANDPORT-403] copy with DHARA_PAGE_NONE dst -> -1, zero write\n"); prep_content_page(page_buf, 31u); err = DHARA_E_NONE; CHECK(dhara_nand_copy(&s_ut_nand, UT_SRC_PAGE, DHARA_PAGE_NONE, &err) == -1, @@ -801,8 +801,8 @@ static void tc_copy(void) { CHECK(fake_no_write_access(), "copy DHARA_PAGE_NONE dst -> zero write access"); CHECK(g_fake_mark_bad_cnt == 0u, "copy DHARA_PAGE_NONE dst -> zero mark_bad"); - /* TC-NP-404:正常 copy -> 0 且目标页与源一致 */ - printf("[TC-NP-404] normal copy moves the page content\n"); + /* TC-NANDPORT-404:正常 copy -> 0 且目标页与源一致 */ + printf("[TC-NANDPORT-404] normal copy moves the page content\n"); prep_content_page(page_buf, 31u); err = DHARA_E_NONE; CHECK(dhara_nand_copy(&s_ut_nand, UT_SRC_PAGE, 128u, &err) == 0, @@ -811,8 +811,8 @@ static void tc_copy(void) { CHECK(fake_page_equals(128u, page_buf, FAKE_PAGE_SIZE), "dst page equals src content"); CHECK(g_fake_double_program_cnt == 0u, "copy onto an erased page -> no violation"); - /* TC-NP-405:copy 到已编程页 -> 探针记下双编程(场景层的判据基础) */ - printf("[TC-NP-405] copy onto a programmed page is recorded as a violation\n"); + /* TC-NANDPORT-405:copy 到已编程页 -> 探针记下双编程(场景层的判据基础) */ + printf("[TC-NANDPORT-405] copy onto a programmed page is recorded as a violation\n"); prep_content_page(page_buf, 31u); err = DHARA_E_NONE; (void)dhara_nand_copy(&s_ut_nand, UT_SRC_PAGE, 128u, &err); @@ -820,14 +820,14 @@ static void tc_copy(void) { CHECK(g_fake_double_program_cnt == 1u, "second copy onto the same dst -> 1 violation"); } -/* ===================== TC-NP-500..504:dhara_nand_erase ===================== */ +/* ===================== TC-NANDPORT-500..504:dhara_nand_erase ===================== */ static void tc_erase(void) { static uint8_t page_buf[FAKE_PAGE_SIZE]; dhara_error_t err; uint32_t i; - /* TC-NP-500:越界块 -> -1 + CORRUPT_MAP + 零标坏块 */ - printf("[TC-NP-500] erase out-of-range block -> -1, zero mark-bad\n"); + /* TC-NANDPORT-500:越界块 -> -1 + CORRUPT_MAP + 零标坏块 */ + printf("[TC-NANDPORT-500] erase out-of-range block -> -1, zero mark-bad\n"); fake_chip_reset(); err = DHARA_E_NONE; CHECK(dhara_nand_erase(&s_ut_nand, UT_OOB_BLOCK, &err) == -1, @@ -836,8 +836,8 @@ static void tc_erase(void) { CHECK(g_fake_mark_bad_cnt == 0u, "erase out-of-range -> no block marked bad"); CHECK(fake_chip_access_total() == 0u, "erase out-of-range -> zero chip access"); - /* TC-NP-501:块号 = 0xffffffff(哨兵当块号用) */ - printf("[TC-NP-501] erase block 0xffffffff -> -1\n"); + /* TC-NANDPORT-501:块号 = 0xffffffff(哨兵当块号用) */ + printf("[TC-NANDPORT-501] erase block 0xffffffff -> -1\n"); fake_chip_reset(); err = DHARA_E_NONE; CHECK(dhara_nand_erase(&s_ut_nand, 0xFFFFFFFFu, &err) == -1, @@ -846,8 +846,8 @@ static void tc_erase(void) { CHECK(g_fake_mark_bad_cnt == 0u, "erase block 0xffffffff -> zero mark_bad"); CHECK(fake_chip_access_total() == 0u, "erase block 0xffffffff -> zero chip access"); - /* TC-NP-502:正常擦除 -> 0 且该块全页回 0xFF */ - printf("[TC-NP-502] erase a valid block clears every page\n"); + /* TC-NANDPORT-502:正常擦除 -> 0 且该块全页回 0xFF */ + printf("[TC-NANDPORT-502] erase a valid block clears every page\n"); fake_chip_reset(); fake_fill_pattern(page_buf, FAKE_PAGE_SIZE, 41u); for (i = 0; i < FAKE_PAGES_PER_BLOCK; i++) { @@ -860,15 +860,15 @@ static void tc_erase(void) { CHECK(fake_block_all_ff(2u), "after erase every page of block 2 reads 0xFF"); CHECK(g_fake_block_erase_cnt == 1u, "erase issues one block-erase command"); - /* TC-NP-503:最后一个合法块(上界内边界) */ - printf("[TC-NP-503] erase last valid block (boundary inside)\n"); + /* TC-NANDPORT-503:最后一个合法块(上界内边界) */ + printf("[TC-NANDPORT-503] erase last valid block (boundary inside)\n"); fake_chip_reset(); err = DHARA_E_NONE; CHECK(dhara_nand_erase(&s_ut_nand, UT_OOB_BLOCK - 1u, &err) == 0, "erase block == num_blocks - 1 -> 0"); - /* TC-NP-504:擦除失败 -> BAD_BLOCK + 标坏该块 */ - printf("[TC-NP-504] erase failure -> BAD_BLOCK + mark bad\n"); + /* TC-NANDPORT-504:擦除失败 -> BAD_BLOCK + 标坏该块 */ + printf("[TC-NANDPORT-504] erase failure -> BAD_BLOCK + mark bad\n"); fake_chip_reset(); s_fail_block_erase = 1; err = DHARA_E_NONE; @@ -878,10 +878,10 @@ static void tc_erase(void) { CHECK(g_fake_mark_bad_log[0] == 3u, "the block marked bad is the one that failed"); } -/* ===================== TC-NP-600..605:is_bad / mark_bad ===================== */ +/* ===================== TC-NANDPORT-600..605:is_bad / mark_bad ===================== */ static void tc_bad_block(void) { - /* TC-NP-600:越界块 is_bad -> 1 且不碰驱动 */ - printf("[TC-NP-600] is_bad out-of-range block -> 1, zero access\n"); + /* TC-NANDPORT-600:越界块 is_bad -> 1 且不碰驱动 */ + printf("[TC-NANDPORT-600] is_bad out-of-range block -> 1, zero access\n"); fake_chip_reset(); CHECK(dhara_nand_is_bad(&s_ut_nand, UT_OOB_BLOCK) == 1, "is_bad block == num_blocks -> 1 (conservative)"); @@ -889,20 +889,20 @@ static void tc_bad_block(void) { "is_bad block = 0xffffffff -> 1 (conservative)"); CHECK(g_fake_is_bad_cnt == 0u, "is_bad out-of-range never reaches the driver"); - /* TC-NP-601:NULL 几何 is_bad -> 1 */ - printf("[TC-NP-601] is_bad with NULL geometry -> 1\n"); + /* TC-NANDPORT-601:NULL 几何 is_bad -> 1 */ + printf("[TC-NANDPORT-601] is_bad with NULL geometry -> 1\n"); fake_chip_reset(); CHECK(dhara_nand_is_bad(NULL, 0u) == 1, "is_bad n = NULL -> 1, no crash"); CHECK(g_fake_is_bad_cnt == 0u, "is_bad n = NULL -> zero driver access"); - /* TC-NP-602:合法好块 -> 0(透传驱动) */ - printf("[TC-NP-602] is_bad on a valid block passes through\n"); + /* TC-NANDPORT-602:合法好块 -> 0(透传驱动) */ + printf("[TC-NANDPORT-602] is_bad on a valid block passes through\n"); fake_chip_reset(); CHECK(dhara_nand_is_bad(&s_ut_nand, 5u) == 0, "good block -> is_bad = 0"); CHECK(g_fake_is_bad_cnt == 1u, "valid block reaches the driver once"); - /* TC-NP-603/604:越界 mark_bad -> 坏块表不变、计数为 0 */ - printf("[TC-NP-603] mark_bad out-of-range leaves the BBT untouched\n"); + /* TC-NANDPORT-603/604:越界 mark_bad -> 坏块表不变、计数为 0 */ + printf("[TC-NANDPORT-603] mark_bad out-of-range leaves the BBT untouched\n"); fake_chip_reset(); fake_bad_snapshot(); dhara_nand_mark_bad(&s_ut_nand, UT_OOB_BLOCK); @@ -910,7 +910,7 @@ static void tc_bad_block(void) { CHECK(fake_bad_unchanged(), "mark_bad out-of-range -> BBT unchanged"); CHECK(fake_chip_access_total() == 0u, "mark_bad out-of-range -> zero chip access"); - printf("[TC-NP-604] mark_bad with 0xffffffff leaves the BBT untouched\n"); + printf("[TC-NANDPORT-604] mark_bad with 0xffffffff leaves the BBT untouched\n"); fake_chip_reset(); fake_bad_snapshot(); dhara_nand_mark_bad(&s_ut_nand, 0xFFFFFFFFu); @@ -919,8 +919,8 @@ static void tc_bad_block(void) { dhara_nand_mark_bad(NULL, 0u); CHECK(g_fake_mark_bad_cnt == 0u, "mark_bad n = NULL -> driver not called, no crash"); - /* TC-NP-605:合法块 mark_bad -> 驱动收到一次、块号正确、随后 is_bad = 1 */ - printf("[TC-NP-605] mark_bad on a valid block really marks it\n"); + /* TC-NANDPORT-605:合法块 mark_bad -> 驱动收到一次、块号正确、随后 is_bad = 1 */ + printf("[TC-NANDPORT-605] mark_bad on a valid block really marks it\n"); fake_chip_reset(); dhara_nand_mark_bad(&s_ut_nand, 7u); CHECK(g_fake_mark_bad_cnt == 1u, "valid mark_bad reaches the driver once"); @@ -928,7 +928,7 @@ static void tc_bad_block(void) { CHECK(dhara_nand_is_bad(&s_ut_nand, 7u) == 1, "marked block now reports bad"); } -/* ===================== TC-NP-700:dhara map 级场景(真链路) ===================== +/* ===================== TC-NANDPORT-700:dhara map 级场景(真链路) ===================== * * 用真实 dhara_map_* 跑一轮"写入 -> sync -> 重新 resume -> 读回",断言: * - 数据往返一致; @@ -941,7 +941,7 @@ static void tc_dhara_scenario(void) { dhara_error_t err; int rc; - printf("[TC-NP-700] dhara map write -> resume -> read round-trip\n"); + printf("[TC-NANDPORT-700] dhara map write -> resume -> read round-trip\n"); fake_chip_reset(); s_initialized = 0; CHECK(nand_ftl_init() == 0, "first init on a blank chip creates the volume"); @@ -994,10 +994,10 @@ int main(void) { s_ut_nand.num_blocks, (unsigned long)UT_TOTAL_PAGES); fake_chip_reset(); - CHECK(FAKE_TOTAL_PAGES == 2048u, "TC-NP-000 fake chip geometry (32 x 64 pages)"); - CHECK(fake_page_all_ff(0u), "TC-NP-000b power-on state is all 0xFF"); + CHECK(FAKE_TOTAL_PAGES == 2048u, "TC-NANDPORT-000 fake chip geometry (32 x 64 pages)"); + CHECK(fake_page_all_ff(0u), "TC-NANDPORT-000b power-on state is all 0xFF"); CHECK(UT_TOTAL_PAGES == ((dhara_page_t)FAKE_USABLE_BLOCKS * FAKE_PAGES_PER_BLOCK), - "TC-NP-000c guard bound = num_blocks << log2_ppb"); + "TC-NANDPORT-000c guard bound = num_blocks << log2_ppb"); printf("-- dhara_nand_is_free: whole-page scan (N-12) --\n"); tc_is_free(); diff --git a/test/host/phasor/phasor_test.c b/test/host/phasor/phasor_test.c index 0a14e669..cfdc51a2 100644 --- a/test/host/phasor/phasor_test.c +++ b/test/host/phasor/phasor_test.c @@ -15,18 +15,18 @@ * 3. 不占 MCU 的 RAM,毫秒级完成。 * * 覆盖点(对应 docs/算法/继电保护功能复现规划.md §3.2): - * TC-PH-001 L2-1 系数表逐项等于 sin(2πk/N)·(√2/N) / cos(2πk/N)·(√2/N)(防转录错) - * TC-PH-002 L2-1 系数表精确零点(sin@0,10 / cos@5,15)与归一化 Σcoe² = 1/N - * TC-PH-003 L2-3 纯基波:fAmSQ = A/√2(有效值),fAm = √2·fAmSQ(幅值) - * TC-PH-004 L2-3/L2-4 实部虚部与相位:atan2(fIm,fRe) = 注入相角 - * TC-PH-005 直流 + 2/3/5 次谐波被完全滤除(基波读数不变) - * TC-PH-006 任意次谐波提取(索引步进 = 谐波次数):k=2 / k=5 - * TC-PH-007 频率偏离 50 Hz 的幅值误差(±1 Hz ≤ 1.5%,±2 Hz ≤ 3%,见 §9 Q3) - * TC-PH-010 采样环:入环/取窗时序、回绕、饱和、帧计数、参数守卫 - * TC-PH-020 L2-2 实例层:实例数/实例表/未攒满一周波不产出 - * TC-PH-021 L2-6 滑动窗:连续滑动 20 拍基波读数恒定 - * TC-PH-022 L2-7 双区交换:使用区交替 + get 返回**最后一次** run 的结果(非陈旧) - * TC-PH-030..034 phasor_zero 四字段清零 / phasor_init 双区清零 + 使用区与就绪标志复位 + 幂等 + * TC-PHASOR-001 L2-1 系数表逐项等于 sin(2πk/N)·(√2/N) / cos(2πk/N)·(√2/N)(防转录错) + * TC-PHASOR-002 L2-1 系数表精确零点(sin@0,10 / cos@5,15)与归一化 Σcoe² = 1/N + * TC-PHASOR-003 L2-3 纯基波:fAmSQ = A/√2(有效值),fAm = √2·fAmSQ(幅值) + * TC-PHASOR-004 L2-3/L2-4 实部虚部与相位:atan2(fIm,fRe) = 注入相角 + * TC-PHASOR-005 直流 + 2/3/5 次谐波被完全滤除(基波读数不变) + * TC-PHASOR-006 任意次谐波提取(索引步进 = 谐波次数):k=2 / k=5 + * TC-PHASOR-007 频率偏离 50 Hz 的幅值误差(±1 Hz ≤ 1.5%,±2 Hz ≤ 3%,见 §9 Q3) + * TC-PHASOR-010 采样环:入环/取窗时序、回绕、饱和、帧计数、参数守卫 + * TC-PHASOR-020 L2-2 实例层:实例数/实例表/未攒满一周波不产出 + * TC-PHASOR-021 L2-6 滑动窗:连续滑动 20 拍基波读数恒定 + * TC-PHASOR-022 L2-7 双区交换:使用区交替 + get 返回**最后一次** run 的结果(非陈旧) + * TC-PHASOR-030..034 phasor_zero 四字段清零 / phasor_init 双区清零 + 使用区与就绪标志复位 + 幂等 * * 通过:全部 TC PASS(main 返回 0)。 * 入口:int main(void),返回 0=PASS / 1=FAIL(由 run 脚本判读)。 @@ -98,7 +98,7 @@ static void frame_at(float *f, uint32_t t, double amp, double phase) { } } -/* ===================== TC-PH-001/002:L2-1 系数表 ===================== */ +/* ===================== TC-PHASOR-001/002:L2-1 系数表 ===================== */ static void tc_table(void) { const double scale = sqrt(2.0) / (double)PHASOR_N; @@ -136,7 +136,7 @@ static void tc_table(void) { "L2-1 sin[5] == sqrt(2)/N (peak coefficient)"); } -/* ===================== TC-PH-003/004:基波幅值 / 有效值 / 相位 ===================== */ +/* ===================== TC-PHASOR-003/004:基波幅值 / 有效值 / 相位 ===================== */ static void tc_fundamental(void) { static const struct { double amp; double ph; } k_case[] = { @@ -176,7 +176,7 @@ static void tc_fundamental(void) { CHECK(ok_ph, "L2-4/L2-3 atan2(fIm,fRe) == injected phase (6 amp/phase cases)"); } -/* ===================== TC-PH-005:直流与谐波被滤除 ===================== */ +/* ===================== TC-PHASOR-005:直流与谐波被滤除 ===================== */ static void tc_filtering(void) { const double amp = 57.7, exp_rms = amp / sqrt(2.0); @@ -218,7 +218,7 @@ static void tc_filtering(void) { CHECK(ok, "L2-3 DC + 2nd/3rd/5th harmonics fully rejected (5 cases, err <= 1%)"); } -/* ===================== TC-PH-006:任意次谐波提取 ===================== */ +/* ===================== TC-PHASOR-006:任意次谐波提取 ===================== */ static void tc_harmonic(void) { /* 基波 100 + 二次 25 + 五次 12(峰值);三根谱线应各自独立读出 */ @@ -263,7 +263,7 @@ static void tc_harmonic(void) { } } -/* ===================== TC-PH-007:频率敏感性 ===================== */ +/* ===================== TC-PHASOR-007:频率敏感性 ===================== */ static void tc_freqdev(void) { const double amp = 57.7, exp_rms = amp / sqrt(2.0); @@ -302,7 +302,7 @@ static void tc_freqdev(void) { CHECK(ok, "L2-3 frequency sensitivity: 50Hz<=0.1%, +-1Hz<=1.5%, +-2Hz<=3% (worst phase)"); } -/* ===================== TC-PH-010:采样环 ===================== */ +/* ===================== TC-PHASOR-010:采样环 ===================== */ static void tc_ring(void) { float f[ADC_SEM_COUNT]; @@ -360,7 +360,7 @@ static void tc_ring(void) { CHECK(sample_ring_push_frame(f, 3u) == -1, "L2-in ring: wrong frame length rejected"); } -/* ===================== TC-PH-020/021/022:实例层 + 滑动窗 + 双区 ===================== */ +/* ===================== TC-PHASOR-020/021/022:实例层 + 滑动窗 + 双区 ===================== */ static void tc_instances(void) { const double amp = 100.0, exp_rms = amp / sqrt(2.0); @@ -433,7 +433,7 @@ static void tc_instances(void) { CHECK(ok, "L2-2/L2-6 instance results == phasor_calc() on the same ring window"); } -/* ===================== TC-PH-030..034:phasor_zero / init 清零 ===================== */ +/* ===================== TC-PHASOR-030..034:phasor_zero / init 清零 ===================== */ static void tc_zero(void) { phasor_t p; @@ -444,7 +444,7 @@ static void tc_zero(void) { p.fRe = 1.0f; p.fIm = -2.0f; p.fAm = 3.0f; p.fAmSQ = 4.0f; phasor_zero(&p); CHECK((p.fRe == 0.0f) && (p.fIm == 0.0f) && (p.fAm == 0.0f) && (p.fAmSQ == 0.0f), - "TC-PH-030 phasor_zero clears all four fields"); + "TC-PHASOR-030 phasor_zero clears all four fields"); /* 2) 经 phasor_init:先把双区写成脏值,init 后必须全零,使用区复位、就绪标志清 */ for (i = 0u; i < (uint8_t)PHASOR_INST_N; i++) { @@ -463,16 +463,16 @@ static void tc_zero(void) { zones_dirty = 1; } } - CHECK(zones_dirty == 0, "TC-PH-031 phasor_init zeroes both result zones"); - CHECK(s_use_zone == 0u, "TC-PH-032 phasor_init resets use zone to 0"); - CHECK(phasor_get(0u, &p) == -2, "TC-PH-033 phasor_init clears ready (get -> -2)"); + CHECK(zones_dirty == 0, "TC-PHASOR-031 phasor_init zeroes both result zones"); + CHECK(s_use_zone == 0u, "TC-PHASOR-032 phasor_init resets use zone to 0"); + CHECK(phasor_get(0u, &p) == -2, "TC-PHASOR-033 phasor_init clears ready (get -> -2)"); /* 3) 幂等:重复 init 不改变结果 */ (void)phasor_init(); - CHECK((s_use_zone == 0u) && (phasor_get(0u, &p) == -2), "TC-PH-034 phasor_init is idempotent"); + CHECK((s_use_zone == 0u) && (phasor_get(0u, &p) == -2), "TC-PHASOR-034 phasor_init is idempotent"); } -/* ===================== TC-PH-022:L2-7 双区指针原子交换 ===================== */ +/* ===================== TC-PHASOR-022:L2-7 双区指针原子交换 ===================== */ static void tc_dualzone(void) { const double amp = 100.0; diff --git a/test/host/prot_elm/prot_elm_test.c b/test/host/prot_elm/prot_elm_test.c index 325e7432..ab1cdba5 100644 --- a/test/host/prot_elm/prot_elm_test.c +++ b/test/host/prot_elm/prot_elm_test.c @@ -5,24 +5,24 @@ * 被测对象:真实源文件(#include 原样纳入): * prot_elm.c + prot_set.c(判据吃定值 RAM) * phasor.c + sample_ring.c + freq.c(prot_elm.c 链接依赖; - * TC-PE-001~010 走 prot_elm_eval 纯判据路径,TC-PE-013 走 + * TC-PROTELEM-001~010 走 prot_elm_eval 纯判据路径,TC-PROTELEM-013 走 * run() 适配层 = 合成波形跑真实 L2+测频链) * * 覆盖点(docs/算法/继电保护功能复现规划.md §3.3 L3-1/3/4/6、§8 验收): - * TC-PE-001 init:全状态清零、动作位图 0 - * TC-PE-002 过量滞回 + 定时限:1.01× 定值启动、延时到点动作、 + * TC-PROTELEM-001 init:全状态清零、动作位图 0 + * TC-PROTELEM-002 过量滞回 + 定时限:1.01× 定值启动、延时到点动作、 * 返回系数内保持、跌破返回门槛释放(1.2×/0.9× 验收口径的核) - * TC-PE-003 延时 0:启动同拍即动作 - * TC-PE-004 欠量方向(UV):低于定值启动、高于返回门槛释放 - * TC-PE-005 投退=0:不判据、状态复位 - * TC-PE-006 定值闭锁(L5-1 联动):locked → 全元件复位;解锁后恢复 - * TC-PE-007 时基回绕:跨 0xFFFFFFFF 的延时判定仍正确 - * TC-PE-008 动作位图聚合 - * TC-PE-009 守卫:state(NULL)/越界编号、name 越界 - * TC-PE-010 跨上下文复归请求(B5):request 不当拍生效、下一拍 eval 头部消费 - * TC-PE-011 过频 OF(B8/L3-5):越限 + RET_OF 滞回 + 定时限 - * TC-PE-012 低频 UF(B8/L3-5):欠量方向 + RET_UF 滞回 + 方向隔离 - * TC-PE-013 run() 接线(B8):测频驱动 OF 动作;幅值门失效 OF 复位且 + * TC-PROTELEM-003 延时 0:启动同拍即动作 + * TC-PROTELEM-004 欠量方向(UV):低于定值启动、高于返回门槛释放 + * TC-PROTELEM-005 投退=0:不判据、状态复位 + * TC-PROTELEM-006 定值闭锁(L5-1 联动):locked → 全元件复位;解锁后恢复 + * TC-PROTELEM-007 时基回绕:跨 0xFFFFFFFF 的延时判定仍正确 + * TC-PROTELEM-008 动作位图聚合 + * TC-PROTELEM-009 守卫:state(NULL)/越界编号、name 越界 + * TC-PROTELEM-010 跨上下文复归请求(B5):request 不当拍生效、下一拍 eval 头部消费 + * TC-PROTELEM-011 过频 OF(B8/L3-5):越限 + RET_OF 滞回 + 定时限 + * TC-PROTELEM-012 低频 UF(B8/L3-5):欠量方向 + RET_UF 滞回 + 方向隔离 + * TC-PROTELEM-013 run() 接线(B8):测频驱动 OF 动作;幅值门失效 OF 复位且 * 相量类元件仍被评估(不整拍跳过) * * 通过:全部 TC PASS(main 返回 0)。 @@ -65,7 +65,7 @@ static void mk_base(float m[PE_COUNT]) { static void tc_init_clear(void) { prot_set_init(); prot_elm_init(); - CHECK(prot_elm_active_mask() == 0u, "TC-PE-001 init: active mask 0"); + CHECK(prot_elm_active_mask() == 0u, "TC-PROTELEM-001 init: active mask 0"); { prot_elm_state_t st; uint32_t i; @@ -77,7 +77,7 @@ static void tc_init_clear(void) { clean = 0; } } - CHECK(clean, "TC-PE-001 init: all element states clear"); + CHECK(clean, "TC-PROTELEM-001 init: all element states clear"); } } @@ -95,33 +95,33 @@ static void tc_over_hysteresis(void) { prot_elm_eval(1000u, m); prot_elm_state(PE_OC1, &st); CHECK((st.picked == 0u) && (st.enabled != 0u), - "TC-PE-002 0.99x set: no pickup"); + "TC-PROTELEM-002 0.99x set: no pickup"); m[PE_OC1] = 10.1f; prot_elm_eval(1001u, m); prot_elm_state(PE_OC1, &st); CHECK((st.picked != 0u) && (st.asserted == 0u), - "TC-PE-002 1.01x set: pickup before delay"); + "TC-PROTELEM-002 1.01x set: pickup before delay"); prot_elm_eval(1100u, m); /* 1100-1001 = 99 ms */ prot_elm_state(PE_OC1, &st); - CHECK(st.asserted == 0u, "TC-PE-002 not asserted at 99ms"); + CHECK(st.asserted == 0u, "TC-PROTELEM-002 not asserted at 99ms"); prot_elm_eval(1101u, m); /* 100 ms 整 */ prot_elm_state(PE_OC1, &st); - CHECK(st.asserted != 0u, "TC-PE-002 asserted at 100ms"); + CHECK(st.asserted != 0u, "TC-PROTELEM-002 asserted at 100ms"); m[PE_OC1] = 9.7f; /* 返回门槛(9.492)与动作门槛(10)之间 */ prot_elm_eval(1200u, m); prot_elm_state(PE_OC1, &st); CHECK((st.picked != 0u) && (st.asserted != 0u), - "TC-PE-002 hysteresis: holds between return and pickup threshold"); + "TC-PROTELEM-002 hysteresis: holds between return and pickup threshold"); m[PE_OC1] = 9.4f; /* 跌破返回门槛 */ prot_elm_eval(1300u, m); prot_elm_state(PE_OC1, &st); CHECK((st.picked == 0u) && (st.asserted == 0u), - "TC-PE-002 below return threshold: drops out"); + "TC-PROTELEM-002 below return threshold: drops out"); } static void tc_zero_delay(void) { @@ -136,7 +136,7 @@ static void tc_zero_delay(void) { prot_elm_eval(5000u, m); prot_elm_state(PE_OC3, &st); CHECK((st.picked != 0u) && (st.asserted != 0u), - "TC-PE-003 dly=0: asserted on the same beat as pickup"); + "TC-PROTELEM-003 dly=0: asserted on the same beat as pickup"); } static void tc_under_direction(void) { @@ -152,27 +152,27 @@ static void tc_under_direction(void) { m[PE_UV] = 25.0f; prot_elm_eval(2000u, m); prot_elm_state(PE_UV, &st); - CHECK(st.picked == 0u, "TC-PE-004 UV above set: no pickup"); + CHECK(st.picked == 0u, "TC-PROTELEM-004 UV above set: no pickup"); m[PE_UV] = 19.0f; prot_elm_eval(2001u, m); prot_elm_state(PE_UV, &st); - CHECK(st.picked != 0u, "TC-PE-004 UV below set: pickup"); + CHECK(st.picked != 0u, "TC-PROTELEM-004 UV below set: pickup"); prot_elm_eval(2051u, m); /* 50 ms */ prot_elm_state(PE_UV, &st); - CHECK(st.asserted != 0u, "TC-PE-004 UV asserted after delay"); + CHECK(st.asserted != 0u, "TC-PROTELEM-004 UV asserted after delay"); m[PE_UV] = 20.5f; /* 20 与 20.996 之间:保持 */ prot_elm_eval(2100u, m); prot_elm_state(PE_UV, &st); - CHECK(st.asserted != 0u, "TC-PE-004 UV holds below return threshold"); + CHECK(st.asserted != 0u, "TC-PROTELEM-004 UV holds below return threshold"); m[PE_UV] = 21.5f; /* 高于返回门槛:释放 */ prot_elm_eval(2200u, m); prot_elm_state(PE_UV, &st); CHECK((st.picked == 0u) && (st.asserted == 0u), - "TC-PE-004 UV above return threshold: drops out"); + "TC-PROTELEM-004 UV above return threshold: drops out"); } static void tc_disabled(void) { @@ -187,7 +187,7 @@ static void tc_disabled(void) { prot_elm_eval(3000u, m); prot_elm_state(PE_OC2, &st); CHECK((st.enabled == 0u) && (st.picked == 0u) && (st.asserted == 0u), - "TC-PE-005 enable=0: no judgement even at 999x"); + "TC-PROTELEM-005 enable=0: no judgement even at 999x"); } static void tc_set_lock(void) { @@ -201,20 +201,20 @@ static void tc_set_lock(void) { (void)prot_set_set(PS_OC1_DLY, PROT_SET_Q10(0.0)); prot_elm_eval(4000u, m); prot_elm_state(PE_OC1, &st); - CHECK(st.asserted != 0u, "TC-PE-006 pre: element operates while settings valid"); + CHECK(st.asserted != 0u, "TC-PROTELEM-006 pre: element operates while settings valid"); (void)prot_set_set(PS_OC1_CUR, PROT_SET_Q10(9.0)); /* 改值不封存 */ - CHECK(prot_set_selfcheck() == -1, "TC-PE-006 tamper detected by selfcheck"); + CHECK(prot_set_selfcheck() == -1, "TC-PROTELEM-006 tamper detected by selfcheck"); prot_elm_eval(4100u, m); prot_elm_state(PE_OC1, &st); CHECK((st.enabled == 0u) && (st.asserted == 0u), - "TC-PE-006 settings lock resets all elements (L5-1 gating)"); + "TC-PROTELEM-006 settings lock resets all elements (L5-1 gating)"); prot_set_seal(); prot_elm_eval(4200u, m); prot_elm_state(PE_OC1, &st); CHECK((st.enabled != 0u) && (st.asserted != 0u), - "TC-PE-006 unlock restores judgement"); + "TC-PROTELEM-006 unlock restores judgement"); } static void tc_tick_wrap(void) { @@ -228,15 +228,15 @@ static void tc_tick_wrap(void) { m[PE_OC2] = 5.1f; /* OC2 定值 5.0 */ prot_elm_eval(0xFFFFFFF0u, m); /* 启动点贴近回绕 */ prot_elm_state(PE_OC2, &st); - CHECK(st.picked != 0u, "TC-PE-007 pickup near tick wrap"); + CHECK(st.picked != 0u, "TC-PROTELEM-007 pickup near tick wrap"); prot_elm_eval(0x00000010u, m); /* 回绕后 32 ms */ prot_elm_state(PE_OC2, &st); - CHECK(st.asserted == 0u, "TC-PE-007 not asserted at 32ms after wrap"); + CHECK(st.asserted == 0u, "TC-PROTELEM-007 not asserted at 32ms after wrap"); prot_elm_eval(0x00000060u, m); /* 回绕后 112 ms */ prot_elm_state(PE_OC2, &st); - CHECK(st.asserted != 0u, "TC-PE-007 asserted at 112ms across wrap"); + CHECK(st.asserted != 0u, "TC-PROTELEM-007 asserted at 112ms across wrap"); } static void tc_active_mask(void) { @@ -251,7 +251,7 @@ static void tc_active_mask(void) { m[PE_OV] = 130.0f; /* OV 定值 120 */ prot_elm_eval(6000u, m); CHECK(prot_elm_active_mask() == ((1uL << PE_OC1) | (1uL << PE_OV)), - "TC-PE-008 active mask aggregates OC1+OV only"); + "TC-PROTELEM-008 active mask aggregates OC1+OV only"); } static void tc_guards(void) { @@ -261,12 +261,12 @@ static void tc_guards(void) { prot_elm_init(); prot_elm_state(PE_COUNT, &st); CHECK((st.enabled == 0u) && (st.picked == 0u) && (st.asserted == 0u), - "TC-PE-009 out-of-range id -> zero state"); + "TC-PROTELEM-009 out-of-range id -> zero state"); prot_elm_state(PE_OC1, NULL); /* 不得崩溃 */ - CHECK(prot_elm_name(PE_COUNT) != NULL, "TC-PE-009 name out-of-range -> fallback"); - CHECK(prot_elm_name(PE_3U0) != NULL, "TC-PE-009 name valid id -> non-NULL"); + CHECK(prot_elm_name(PE_COUNT) != NULL, "TC-PROTELEM-009 name out-of-range -> fallback"); + CHECK(prot_elm_name(PE_3U0) != NULL, "TC-PROTELEM-009 name valid id -> non-NULL"); prot_elm_eval(7000u, NULL); /* NULL 测量:按 0 处理,不得崩溃 */ - CHECK(1, "TC-PE-009 eval(NULL meas) survives"); + CHECK(1, "TC-PROTELEM-009 eval(NULL meas) survives"); } static void tc_request_reset(void) { @@ -279,11 +279,11 @@ static void tc_request_reset(void) { m[PE_OC1] = 999.0f; /* OC1 默认 dly=0 → 启动同拍动作 */ prot_elm_eval(1000u, m); prot_elm_state(PE_OC1, &st); - CHECK(st.asserted != 0u, "TC-PE-010 pre: OC1 asserted (default dly=0)"); + CHECK(st.asserted != 0u, "TC-PROTELEM-010 pre: OC1 asserted (default dly=0)"); prot_elm_request_reset(); /* 跨上下文请求:不当拍生效 */ prot_elm_state(PE_OC1, &st); - CHECK(st.asserted != 0u, "TC-PE-010 request alone does not reset"); + CHECK(st.asserted != 0u, "TC-PROTELEM-010 request alone does not reset"); /* 下一拍头部消费请求 → 复位;测量落在滞回保持区(9.6 ∈ [返回9.5, 动作10)) * ——不复位则 picked/asserted 保持,复位后保持清零,可区分 */ @@ -291,12 +291,12 @@ static void tc_request_reset(void) { prot_elm_eval(1100u, m); prot_elm_state(PE_OC1, &st); CHECK((st.picked == 0u) && (st.asserted == 0u), - "TC-PE-010 next eval consumes request -> cleared in hysteresis band"); + "TC-PROTELEM-010 next eval consumes request -> cleared in hysteresis band"); } /* ===================== OF/UF(L3-5,B8)===================== */ -/* TC-PE-011:过频——越限 + RET_OF 滞回 + 定时限(判据核级) */ +/* TC-PROTELEM-011:过频——越限 + RET_OF 滞回 + 定时限(判据核级) */ static void tc_of_hysteresis(void) { float m[PE_COUNT]; prot_elm_state_t st; @@ -311,36 +311,36 @@ static void tc_of_hysteresis(void) { prot_elm_eval(1000u, m); prot_elm_state(PE_OF, &st); CHECK((st.picked == 0u) && (st.enabled != 0u), - "TC-PE-011 OF 50.9 (<51): no pickup"); + "TC-PROTELEM-011 OF 50.9 (<51): no pickup"); m[PE_OF] = 51.1f; prot_elm_eval(1001u, m); prot_elm_state(PE_OF, &st); CHECK((st.picked != 0u) && (st.asserted == 0u), - "TC-PE-011 OF 51.1: pickup before delay"); + "TC-PROTELEM-011 OF 51.1: pickup before delay"); prot_elm_eval(1100u, m); prot_elm_state(PE_OF, &st); - CHECK(st.asserted == 0u, "TC-PE-011 OF not asserted at 99ms"); + CHECK(st.asserted == 0u, "TC-PROTELEM-011 OF not asserted at 99ms"); prot_elm_eval(1101u, m); prot_elm_state(PE_OF, &st); - CHECK(st.asserted != 0u, "TC-PE-011 OF asserted at 100ms"); + CHECK(st.asserted != 0u, "TC-PROTELEM-011 OF asserted at 100ms"); m[PE_OF] = 50.7f; /* 50.49 与 51 之间:滞回保持 */ prot_elm_eval(1200u, m); prot_elm_state(PE_OF, &st); CHECK((st.picked != 0u) && (st.asserted != 0u), - "TC-PE-011 OF holds between return(50.49) and pickup(51)"); + "TC-PROTELEM-011 OF holds between return(50.49) and pickup(51)"); m[PE_OF] = 50.4f; /* 跌破返回门槛 */ prot_elm_eval(1300u, m); prot_elm_state(PE_OF, &st); CHECK((st.picked == 0u) && (st.asserted == 0u), - "TC-PE-011 OF below return threshold: drops out"); + "TC-PROTELEM-011 OF below return threshold: drops out"); } -/* TC-PE-012:低频——欠量方向 + RET_UF 滞回(与 OF 系数独立,勿混 0.95/1.05) */ +/* TC-PROTELEM-012:低频——欠量方向 + RET_UF 滞回(与 OF 系数独立,勿混 0.95/1.05) */ static void tc_uf_direction(void) { float m[PE_COUNT]; prot_elm_state_t st; @@ -354,36 +354,36 @@ static void tc_uf_direction(void) { m[PE_UF] = 49.1f; prot_elm_eval(2000u, m); prot_elm_state(PE_UF, &st); - CHECK(st.picked == 0u, "TC-PE-012 UF 49.1 (>49): no pickup"); + CHECK(st.picked == 0u, "TC-PROTELEM-012 UF 49.1 (>49): no pickup"); m[PE_UF] = 48.9f; prot_elm_eval(2001u, m); prot_elm_state(PE_UF, &st); - CHECK(st.picked != 0u, "TC-PE-012 UF 48.9 (<49): pickup"); + CHECK(st.picked != 0u, "TC-PROTELEM-012 UF 48.9 (<49): pickup"); prot_elm_eval(2051u, m); prot_elm_state(PE_UF, &st); - CHECK(st.asserted != 0u, "TC-PE-012 UF asserted after 50ms"); + CHECK(st.asserted != 0u, "TC-PROTELEM-012 UF asserted after 50ms"); m[PE_UF] = 49.3f; /* 49 与 49.49 之间:保持 */ prot_elm_eval(2100u, m); prot_elm_state(PE_UF, &st); - CHECK(st.asserted != 0u, "TC-PE-012 UF holds below return threshold"); + CHECK(st.asserted != 0u, "TC-PROTELEM-012 UF holds below return threshold"); m[PE_UF] = 49.6f; /* 高于返回门槛:释放 */ prot_elm_eval(2200u, m); prot_elm_state(PE_UF, &st); CHECK((st.picked == 0u) && (st.asserted == 0u), - "TC-PE-012 UF above return threshold: drops out"); + "TC-PROTELEM-012 UF above return threshold: drops out"); /* OF 不得被低频误启动(方向隔离);UF 不得被过频误启动 */ m[PE_OF] = 52.0f; m[PE_UF] = 52.0f; prot_elm_eval(2300u, m); prot_elm_state(PE_OF, &st); - CHECK(st.picked != 0u, "TC-PE-012 OF picks at 52 (over direction)"); + CHECK(st.picked != 0u, "TC-PROTELEM-012 OF picks at 52 (over direction)"); prot_elm_state(PE_UF, &st); - CHECK(st.picked == 0u, "TC-PE-012 UF NOT picked at 52 (direction isolation)"); + CHECK(st.picked == 0u, "TC-PROTELEM-012 UF NOT picked at 52 (direction isolation)"); } /* ---- run() 适配层驱动:合成波形跑真实 L2+测频链(同 freq_test 口径) ---- */ @@ -403,7 +403,7 @@ static void drive_beat(double f, double amp) { s_t++; } -/* TC-PE-013:run() 级——freq 有效读数驱动 OF 动作;幅值门失效后 OF 复位 +/* TC-PROTELEM-013:run() 级——freq 有效读数驱动 OF 动作;幅值门失效后 OF 复位 * 且相量类元件仍被评估(不整拍跳过,B5 行为不回归) */ static void tc_run_freq_wiring(void) { prot_elm_state_t st; @@ -424,9 +424,9 @@ static void tc_run_freq_wiring(void) { } prot_elm_state(PE_OF, &st); CHECK((st.picked != 0u) && (st.asserted != 0u), - "TC-PE-013 run(): OF asserted from measured 52.5 Hz"); + "TC-PROTELEM-013 run(): OF asserted from measured 52.5 Hz"); prot_elm_state(PE_UF, &st); - CHECK(st.picked == 0u, "TC-PE-013 run(): UF clear at 52.5 Hz"); + CHECK(st.picked == 0u, "TC-PROTELEM-013 run(): UF clear at 52.5 Hz"); /* 波形消失(浮空):freq 幅值门失效 -> OF 按方向填充复位; * 同时相量 rms=0 -> UV(定值 20,dly=0)启动 = 证明未整拍跳过 */ @@ -436,10 +436,10 @@ static void tc_run_freq_wiring(void) { } prot_elm_state(PE_OF, &st); CHECK((st.picked == 0u) && (st.asserted == 0u), - "TC-PE-013 run(): OF resets when freq source loses amplitude"); + "TC-PROTELEM-013 run(): OF resets when freq source loses amplitude"); prot_elm_state(PE_UV, &st); CHECK(st.picked != 0u, - "TC-PE-013 run(): UV still evaluated with zero-amplitude (no whole-beat skip)"); + "TC-PROTELEM-013 run(): UV still evaluated with zero-amplitude (no whole-beat skip)"); } int main(void) { diff --git a/test/host/prot_set/prot_set_test.c b/test/host/prot_set/prot_set_test.c index 2b85509e..9c64dc2e 100644 --- a/test/host/prot_set/prot_set_test.c +++ b/test/host/prot_set/prot_set_test.c @@ -5,22 +5,22 @@ * 被测对象:真实源文件(#include 原样纳入)。纯逻辑,无需桩。 * * 覆盖点(docs/算法/继电保护功能复现规划.md §5.2 / §3.4 L5-1): - * TC-PS-001 init:默认值装载、越界位图 0、selfcheck 通过、未闭锁 - * TC-PS-002 set:范围内写入生效;越界拒写且原值不动 - * TC-PS-003 校验和封存语义:set 后未 seal → selfcheck 失败并闭锁; + * TC-PROTSET-001 init:默认值装载、越界位图 0、selfcheck 通过、未闭锁 + * TC-PROTSET-002 set:范围内写入生效;越界拒写且原值不动 + * TC-PROTSET-003 校验和封存语义:set 后未 seal → selfcheck 失败并闭锁; * seal → 通过并解锁(L5-1 核心闭环) - * TC-PS-004 load_raw:合法整表装载并封存;含越界项 → 整表不装载 + + * TC-PROTSET-004 load_raw:合法整表装载并封存;含越界项 → 整表不装载 + * bad_mask 指认越界项(定值一致性:宁可全旧不可半新) - * TC-PS-005 Q10 往返精度(±1 LSB) - * TC-PS-006 元数据表自检:min<=max、投退项 0..1、非零通讯地址不重复 - * TC-PS-007 越界编号守卫(get/set) - * TC-PS-008 全局软压板 PS_GLOBAL_EN(B7):默认投入、set_sealed 原子写 + * TC-PROTSET-005 Q10 往返精度(±1 LSB) + * TC-PROTSET-006 元数据表自检:min<=max、投退项 0..1、非零通讯地址不重复 + * TC-PROTSET-007 越界编号守卫(get/set) + * TC-PROTSET-008 全局软压板 PS_GLOBAL_EN(B7):默认投入、set_sealed 原子写 * 不破坏 selfcheck、脏标志三件套(peek/take/mark) - * TC-PS-009 持久化 blob 往返:serialize → init 清场 → parse 恢复 + * TC-PROTSET-009 持久化 blob 往返:serialize → init 清场 → parse 恢复 * (位精确 + 封存自洽 + parse 不置脏) - * TC-PS-010 损坏 blob 整表拒绝(all-or-nothing):值区位翻转/坏 magic/ + * TC-PROTSET-010 损坏 blob 整表拒绝(all-or-nothing):值区位翻转/坏 magic/ * 截断/超长/坏版本/伪造自洽越界 → 全部拒绝且活跃值区一字不动 - * TC-PS-011 OF/UF 定值行(B8):40 项 / blob 版本 2 / 本地项地址 0 / + * TC-PROTSET-011 OF/UF 定值行(B8):40 项 / blob 版本 2 / 本地项地址 0 / * 默认值与范围 / 返回系数独立性 / 64 位 bad_mask(bit 39)/ * B7 旧档(32 项)换代拒绝 * @@ -40,46 +40,46 @@ static int s_total = 0, s_passed = 0, s_failed = 0; #include "prot_set.c" -/* TC-PS-001 */ +/* TC-PROTSET-001 */ static void tc_init(void) { prot_set_init(); - CHECK(prot_set_bad_mask() == 0u, "TC-PS-001 init: no bad items"); - CHECK(prot_set_selfcheck() == 0, "TC-PS-001 init: selfcheck pass"); - CHECK(prot_set_locked() == 0u, "TC-PS-001 init: not locked"); + CHECK(prot_set_bad_mask() == 0u, "TC-PROTSET-001 init: no bad items"); + CHECK(prot_set_selfcheck() == 0, "TC-PROTSET-001 init: selfcheck pass"); + CHECK(prot_set_locked() == 0u, "TC-PROTSET-001 init: not locked"); CHECK(prot_set_get_f(PS_OC1_CUR) > 9.99f && prot_set_get_f(PS_OC1_CUR) < 10.01f, - "TC-PS-001 default OC1 current = 10.0 A"); + "TC-PROTSET-001 default OC1 current = 10.0 A"); CHECK(prot_set_get_ctl(PS_OC3_TRIP) == 0u, - "TC-PS-001 default OC3 = alarm (trip off)"); + "TC-PROTSET-001 default OC3 = alarm (trip off)"); } -/* TC-PS-002 */ +/* TC-PROTSET-002 */ static void tc_set_range(void) { prot_set_init(); CHECK(prot_set_set(PS_OC2_CUR, PROT_SET_Q10(7.5)) == 0, - "TC-PS-002 in-range set accepted"); + "TC-PROTSET-002 in-range set accepted"); CHECK(prot_set_get_f(PS_OC2_CUR) > 7.49f && prot_set_get_f(PS_OC2_CUR) < 7.51f, - "TC-PS-002 value readable after set"); + "TC-PROTSET-002 value readable after set"); CHECK(prot_set_set(PS_OC2_CUR, PROT_SET_Q10(101.0)) == -1, - "TC-PS-002 over-max set rejected"); + "TC-PROTSET-002 over-max set rejected"); CHECK(prot_set_get_f(PS_OC2_CUR) > 7.49f && prot_set_get_f(PS_OC2_CUR) < 7.51f, - "TC-PS-002 rejected set leaves value unchanged"); + "TC-PROTSET-002 rejected set leaves value unchanged"); CHECK(prot_set_set(PS_OC1_EN, PROT_SET_Q10(2)) == -1, - "TC-PS-002 ctl item rejects value 2"); + "TC-PROTSET-002 ctl item rejects value 2"); } -/* TC-PS-003 */ +/* TC-PROTSET-003 */ static void tc_seal_selfcheck(void) { prot_set_init(); - CHECK(prot_set_set(PS_OC1_CUR, PROT_SET_Q10(8.0)) == 0, "TC-PS-003 set ok"); + CHECK(prot_set_set(PS_OC1_CUR, PROT_SET_Q10(8.0)) == 0, "TC-PROTSET-003 set ok"); CHECK(prot_set_selfcheck() == -1, - "TC-PS-003 set-without-seal => selfcheck FAIL (tamper detect)"); - CHECK(prot_set_locked() == 1u, "TC-PS-003 selfcheck failure latches lock"); + "TC-PROTSET-003 set-without-seal => selfcheck FAIL (tamper detect)"); + CHECK(prot_set_locked() == 1u, "TC-PROTSET-003 selfcheck failure latches lock"); prot_set_seal(); - CHECK(prot_set_selfcheck() == 0, "TC-PS-003 seal => selfcheck pass"); - CHECK(prot_set_locked() == 0u, "TC-PS-003 seal clears lock"); + CHECK(prot_set_selfcheck() == 0, "TC-PROTSET-003 seal => selfcheck pass"); + CHECK(prot_set_locked() == 0u, "TC-PROTSET-003 seal clears lock"); } -/* TC-PS-004 */ +/* TC-PROTSET-004 */ static void tc_load_raw(void) { int32_t tbl[PS_ID_COUNT]; uint32_t i; @@ -89,38 +89,38 @@ static void tc_load_raw(void) { tbl[i] = prot_set_get((prot_set_id_t)i); } tbl[PS_OL_CUR] = PROT_SET_Q10(1.5); - CHECK(prot_set_load_raw(tbl) == 0, "TC-PS-004 valid table loads"); + CHECK(prot_set_load_raw(tbl) == 0, "TC-PROTSET-004 valid table loads"); CHECK(prot_set_get_f(PS_OL_CUR) > 1.49f && prot_set_get_f(PS_OL_CUR) < 1.51f, - "TC-PS-004 loaded value visible"); - CHECK(prot_set_selfcheck() == 0, "TC-PS-004 load_raw auto-seals"); + "TC-PROTSET-004 loaded value visible"); + CHECK(prot_set_selfcheck() == 0, "TC-PROTSET-004 load_raw auto-seals"); tbl[PS_OC3_DLY] = PROT_SET_Q10(60001.0); /* 越上限 */ tbl[PS_OL_CUR] = PROT_SET_Q10(2.5); /* 合法改动 */ - CHECK(prot_set_load_raw(tbl) == -1, "TC-PS-004 bad table rejected"); + CHECK(prot_set_load_raw(tbl) == -1, "TC-PROTSET-004 bad table rejected"); CHECK(prot_set_bad_mask() == (1uLL << PS_OC3_DLY), - "TC-PS-004 bad_mask points at the offending item"); + "TC-PROTSET-004 bad_mask points at the offending item"); CHECK(prot_set_get_f(PS_OL_CUR) > 1.49f && prot_set_get_f(PS_OL_CUR) < 1.51f, - "TC-PS-004 rejected load keeps OLD table (all-or-nothing)"); - CHECK(prot_set_load_raw(0) == -1, "TC-PS-004 NULL table rejected"); + "TC-PROTSET-004 rejected load keeps OLD table (all-or-nothing)"); + CHECK(prot_set_load_raw(0) == -1, "TC-PROTSET-004 NULL table rejected"); } -/* TC-PS-005 */ +/* TC-PROTSET-005 */ static void tc_q10_roundtrip(void) { float v = 12.345f; int32_t q; prot_set_init(); q = PROT_SET_Q10(v); - CHECK(prot_set_set(PS_OC1_CUR, q) == 0, "TC-PS-005 set ok"); + CHECK(prot_set_set(PS_OC1_CUR, q) == 0, "TC-PROTSET-005 set ok"); { float back = prot_set_get_f(PS_OC1_CUR); float err = back - v; if (err < 0.0f) { err = -err; } - CHECK(err < 0.001f, "TC-PS-005 Q10 roundtrip error < 1 LSB"); + CHECK(err < 0.001f, "TC-PROTSET-005 Q10 roundtrip error < 1 LSB"); } } -/* TC-PS-006 */ +/* TC-PROTSET-006 */ static void tc_meta_sanity(void) { uint32_t i, j; int ok_range = 1, ok_ctl = 1, ok_addr = 1; @@ -136,40 +136,40 @@ static void tc_meta_sanity(void) { if (g_prot_set_meta[j].comm_addr == m->comm_addr) { ok_addr = 0; } } } - CHECK(ok_range, "TC-PS-006 meta: min<=def<=max for all items"); - CHECK(ok_ctl, "TC-PS-006 meta: ctl items are 0..1"); - CHECK(ok_addr, "TC-PS-006 meta: comm addresses unique"); - CHECK((uint32_t)PS_ID_COUNT <= 64u, "TC-PS-006 item count fits 64-bit bad_mask (B8: 40)"); + CHECK(ok_range, "TC-PROTSET-006 meta: min<=def<=max for all items"); + CHECK(ok_ctl, "TC-PROTSET-006 meta: ctl items are 0..1"); + CHECK(ok_addr, "TC-PROTSET-006 meta: comm addresses unique"); + CHECK((uint32_t)PS_ID_COUNT <= 64u, "TC-PROTSET-006 item count fits 64-bit bad_mask (B8: 40)"); } -/* TC-PS-007 */ +/* TC-PROTSET-007 */ static void tc_id_guard(void) { prot_set_init(); - CHECK(prot_set_get(PS_ID_COUNT) == 0, "TC-PS-007 get out-of-range id -> 0"); - CHECK(prot_set_set(PS_ID_COUNT, 0) == -1, "TC-PS-007 set out-of-range id -> -1"); - CHECK(prot_set_set_sealed(PS_ID_COUNT, 0) == -1, "TC-PS-007 set_sealed id guard"); + CHECK(prot_set_get(PS_ID_COUNT) == 0, "TC-PROTSET-007 get out-of-range id -> 0"); + CHECK(prot_set_set(PS_ID_COUNT, 0) == -1, "TC-PROTSET-007 set out-of-range id -> -1"); + CHECK(prot_set_set_sealed(PS_ID_COUNT, 0) == -1, "TC-PROTSET-007 set_sealed id guard"); } -/* TC-PS-008(B7:全局软压板 + 原子写 + 脏标志) */ +/* TC-PROTSET-008(B7:全局软压板 + 原子写 + 脏标志) */ static void tc_global_plate_dirty(void) { prot_set_init(); - CHECK(prot_set_dirty_peek() == 0u, "TC-PS-008 init not dirty"); - CHECK(prot_set_get_ctl(PS_GLOBAL_EN) == 1u, "TC-PS-008 global plate default IN"); - CHECK(prot_set_set(PS_GLOBAL_EN, PROT_SET_Q10(2)) == -1, "TC-PS-008 plate rejects 2"); - CHECK(prot_set_set_sealed(PS_GLOBAL_EN, 0) == 0, "TC-PS-008 plate OUT via set_sealed"); - CHECK(prot_set_get_ctl(PS_GLOBAL_EN) == 0u, "TC-PS-008 plate OUT readable"); - CHECK(prot_set_selfcheck() == 0, "TC-PS-008 set_sealed leaves selfcheck PASS (no unsealed window)"); - CHECK(prot_set_locked() == 0u, "TC-PS-008 set_sealed no lock"); - CHECK(prot_set_dirty_peek() == 1u, "TC-PS-008 set_sealed marks dirty"); - CHECK(prot_set_dirty_take() == 1u, "TC-PS-008 dirty take consumes"); - CHECK(prot_set_dirty_peek() == 0u, "TC-PS-008 dirty cleared after take"); + CHECK(prot_set_dirty_peek() == 0u, "TC-PROTSET-008 init not dirty"); + CHECK(prot_set_get_ctl(PS_GLOBAL_EN) == 1u, "TC-PROTSET-008 global plate default IN"); + CHECK(prot_set_set(PS_GLOBAL_EN, PROT_SET_Q10(2)) == -1, "TC-PROTSET-008 plate rejects 2"); + CHECK(prot_set_set_sealed(PS_GLOBAL_EN, 0) == 0, "TC-PROTSET-008 plate OUT via set_sealed"); + CHECK(prot_set_get_ctl(PS_GLOBAL_EN) == 0u, "TC-PROTSET-008 plate OUT readable"); + CHECK(prot_set_selfcheck() == 0, "TC-PROTSET-008 set_sealed leaves selfcheck PASS (no unsealed window)"); + CHECK(prot_set_locked() == 0u, "TC-PROTSET-008 set_sealed no lock"); + CHECK(prot_set_dirty_peek() == 1u, "TC-PROTSET-008 set_sealed marks dirty"); + CHECK(prot_set_dirty_take() == 1u, "TC-PROTSET-008 dirty take consumes"); + CHECK(prot_set_dirty_peek() == 0u, "TC-PROTSET-008 dirty cleared after take"); prot_set_dirty_mark(); - CHECK(prot_set_dirty_peek() == 1u, "TC-PS-008 dirty mark re-arms (write-fail retry)"); - CHECK(prot_set_set_sealed(PS_GLOBAL_EN, PROT_SET_Q10(2)) == -1, "TC-PS-008 set_sealed range check"); - CHECK(prot_set_get_ctl(PS_GLOBAL_EN) == 0u, "TC-PS-008 rejected set_sealed keeps value"); + CHECK(prot_set_dirty_peek() == 1u, "TC-PROTSET-008 dirty mark re-arms (write-fail retry)"); + CHECK(prot_set_set_sealed(PS_GLOBAL_EN, PROT_SET_Q10(2)) == -1, "TC-PROTSET-008 set_sealed range check"); + CHECK(prot_set_get_ctl(PS_GLOBAL_EN) == 0u, "TC-PROTSET-008 rejected set_sealed keeps value"); } -/* TC-PS-009(B7:blob 往返) */ +/* TC-PROTSET-009(B7:blob 往返) */ static void tc_store_roundtrip(void) { uint8_t blob[PROT_SET_BLOB_SZ]; uint32_t len = 0u; @@ -180,15 +180,15 @@ static void tc_store_roundtrip(void) { (void)prot_set_set_sealed(PS_GLOBAL_EN, 0); (void)prot_set_dirty_take(); cur = prot_set_get(PS_OC1_CUR); - CHECK(prot_set_store_serialize(blob, sizeof(blob), &len) == 0, "TC-PS-009 serialize ok"); - CHECK(len == (uint32_t)PROT_SET_BLOB_SZ, "TC-PS-009 blob exact size"); + CHECK(prot_set_store_serialize(blob, sizeof(blob), &len) == 0, "TC-PROTSET-009 serialize ok"); + CHECK(len == (uint32_t)PROT_SET_BLOB_SZ, "TC-PROTSET-009 blob exact size"); prot_set_init(); - CHECK(prot_set_get(PS_OC1_CUR) != cur, "TC-PS-009 init wiped to defaults"); - CHECK(prot_set_store_parse(blob, len) == 0, "TC-PS-009 parse ok"); - CHECK(prot_set_get(PS_OC1_CUR) == cur, "TC-PS-009 value round-trip bit-exact"); - CHECK(prot_set_get_ctl(PS_GLOBAL_EN) == 0u, "TC-PS-009 plate state round-trip"); - CHECK(prot_set_selfcheck() == 0, "TC-PS-009 parsed table sealed"); - CHECK(prot_set_dirty_peek() == 0u, "TC-PS-009 parse does not mark dirty"); + CHECK(prot_set_get(PS_OC1_CUR) != cur, "TC-PROTSET-009 init wiped to defaults"); + CHECK(prot_set_store_parse(blob, len) == 0, "TC-PROTSET-009 parse ok"); + CHECK(prot_set_get(PS_OC1_CUR) == cur, "TC-PROTSET-009 value round-trip bit-exact"); + CHECK(prot_set_get_ctl(PS_GLOBAL_EN) == 0u, "TC-PROTSET-009 plate state round-trip"); + CHECK(prot_set_selfcheck() == 0, "TC-PROTSET-009 parsed table sealed"); + CHECK(prot_set_dirty_peek() == 0u, "TC-PROTSET-009 parse does not mark dirty"); } /* 伪造辅助:按 blob 值区重算尾部 sum/sumn(构造"自洽但越界"的对抗样本) */ @@ -205,7 +205,7 @@ static void s_forge_tail(uint8_t *b, uint32_t len) { s_put32(b + len - 4u, inv); } -/* TC-PS-010(B7:损坏 blob 整表拒绝,all-or-nothing) */ +/* TC-PROTSET-010(B7:损坏 blob 整表拒绝,all-or-nothing) */ static void tc_store_corrupt(void) { uint8_t blob[PROT_SET_BLOB_SZ]; uint32_t len = 0u; @@ -214,36 +214,36 @@ static void tc_store_corrupt(void) { prot_set_init(); (void)prot_set_set_sealed(PS_OC2_CUR, PROT_SET_Q10(6.0)); keep = prot_set_get(PS_OC2_CUR); - CHECK(prot_set_store_serialize(blob, sizeof(blob), &len) == 0, "TC-PS-010 serialize ok"); + CHECK(prot_set_store_serialize(blob, sizeof(blob), &len) == 0, "TC-PROTSET-010 serialize ok"); blob[PROT_SET_BLOB_HDR_SZ] ^= 0x01u; /* 值区一位翻转:sum 对不符 */ - CHECK(prot_set_store_parse(blob, len) == -1, "TC-PS-010 flipped value byte rejected (sum pair)"); - CHECK(prot_set_get(PS_OC2_CUR) == keep, "TC-PS-010 reject leaves values untouched"); + CHECK(prot_set_store_parse(blob, len) == -1, "TC-PROTSET-010 flipped value byte rejected (sum pair)"); + CHECK(prot_set_get(PS_OC2_CUR) == keep, "TC-PROTSET-010 reject leaves values untouched"); (void)prot_set_store_serialize(blob, sizeof(blob), &len); blob[0] ^= 0xFFu; /* magic 破坏 */ - CHECK(prot_set_store_parse(blob, len) == -1, "TC-PS-010 bad magic rejected"); + CHECK(prot_set_store_parse(blob, len) == -1, "TC-PROTSET-010 bad magic rejected"); (void)prot_set_store_serialize(blob, sizeof(blob), &len); - CHECK(prot_set_store_parse(blob, len - 4u) == -1, "TC-PS-010 truncated blob rejected"); - CHECK(prot_set_store_parse(blob, len + 4u) == -1, "TC-PS-010 oversized blob rejected"); + CHECK(prot_set_store_parse(blob, len - 4u) == -1, "TC-PROTSET-010 truncated blob rejected"); + CHECK(prot_set_store_parse(blob, len + 4u) == -1, "TC-PROTSET-010 oversized blob rejected"); (void)prot_set_store_serialize(blob, sizeof(blob), &len); blob[5] ^= 0x02u; /* version 高字节:1 -> 0x200 */ - CHECK(prot_set_store_parse(blob, len) == -1, "TC-PS-010 version mismatch rejected"); + CHECK(prot_set_store_parse(blob, len) == -1, "TC-PROTSET-010 version mismatch rejected"); /* 对抗样本:越限定值 + 重算 sum 对(校验全过、范围必拦) */ (void)prot_set_store_serialize(blob, sizeof(blob), &len); s_put32(blob + PROT_SET_BLOB_HDR_SZ + 4u * (uint32_t)PS_OC1_CUR, (uint32_t)(g_prot_set_meta[PS_OC1_CUR].max + 1)); s_forge_tail(blob, len); - CHECK(prot_set_store_parse(blob, len) == -1, "TC-PS-010 forged consistent out-of-range rejected"); - CHECK(prot_set_bad_mask() == (1uLL << PS_OC1_CUR), "TC-PS-010 bad_mask points at item"); - CHECK(prot_set_get(PS_OC1_CUR) == PROT_SET_Q10(10.0), "TC-PS-010 defaults still intact"); - CHECK(prot_set_selfcheck() == 0, "TC-PS-010 active table still self-consistent after all rejects"); + CHECK(prot_set_store_parse(blob, len) == -1, "TC-PROTSET-010 forged consistent out-of-range rejected"); + CHECK(prot_set_bad_mask() == (1uLL << PS_OC1_CUR), "TC-PROTSET-010 bad_mask points at item"); + CHECK(prot_set_get(PS_OC1_CUR) == PROT_SET_Q10(10.0), "TC-PROTSET-010 defaults still intact"); + CHECK(prot_set_selfcheck() == 0, "TC-PROTSET-010 active table still self-consistent after all rejects"); } -/* TC-PS-011(B8:OF/UF 定值行 + 40 项 + 64 位 bad_mask + 换代拒绝) */ +/* TC-PROTSET-011(B8:OF/UF 定值行 + 40 项 + 64 位 bad_mask + 换代拒绝) */ static void tc_of_uf_meta(void) { uint8_t blob[PROT_SET_BLOB_SZ]; uint32_t len = 0u; @@ -251,10 +251,10 @@ static void tc_of_uf_meta(void) { prot_set_init(); /* 结构:40 项、blob 版本 2、尺寸随项数自适应 */ - CHECK((uint32_t)PS_ID_COUNT == 40u, "TC-PS-011 PS_ID_COUNT == 40 (32 + 8 OF/UF)"); - CHECK(PROT_SET_BLOB_VER == 2u, "TC-PS-011 blob version bumped to 2 (B8)"); + CHECK((uint32_t)PS_ID_COUNT == 40u, "TC-PROTSET-011 PS_ID_COUNT == 40 (32 + 8 OF/UF)"); + CHECK(PROT_SET_BLOB_VER == 2u, "TC-PROTSET-011 blob version bumped to 2 (B8)"); CHECK((uint32_t)PROT_SET_BLOB_SZ == (PROT_SET_BLOB_HDR_SZ + 4u * 40u + 8u), - "TC-PS-011 blob size = hdr + 4*40 + tail"); + "TC-PROTSET-011 blob size = hdr + 4*40 + tail"); /* 地址:参考逐项地址不在本仓库 -> 8 项全部本地项(comm_addr=0,104 不可寻址) */ CHECK((g_prot_set_meta[PS_OF_EN].comm_addr == 0u) @@ -265,60 +265,60 @@ static void tc_of_uf_meta(void) { && (g_prot_set_meta[PS_UF_DLY].comm_addr == 0u) && (g_prot_set_meta[PS_RET_OF].comm_addr == 0u) && (g_prot_set_meta[PS_RET_UF].comm_addr == 0u), - "TC-PS-011 OF/UF items all local (comm_addr=0, pending reference table)"); + "TC-PROTSET-011 OF/UF items all local (comm_addr=0, pending reference table)"); /* 投退 = ctl 项(0/1),其余 = 模拟量 Q10 */ CHECK((g_prot_set_meta[PS_OF_EN].is_ctl == 1u) && (g_prot_set_meta[PS_UF_EN].is_ctl == 1u) && (g_prot_set_meta[PS_OF_HZ].is_ctl == 0u) && (g_prot_set_meta[PS_RET_UF].is_ctl == 0u), - "TC-PS-011 EN items are ctl, HZ/DLY/RET are Q10 analog"); + "TC-PROTSET-011 EN items are ctl, HZ/DLY/RET are Q10 analog"); /* 出厂默认(拟定值)与范围 */ - CHECK(prot_set_get(PS_OF_EN) == PROT_SET_Q10(1.0), "TC-PS-011 OF EN default 1"); - CHECK(prot_set_get(PS_UF_EN) == PROT_SET_Q10(1.0), "TC-PS-011 UF EN default 1"); - CHECK(prot_set_get(PS_OF_HZ) == PROT_SET_Q10(51.0), "TC-PS-011 OF default 51.0 Hz"); - CHECK(prot_set_get(PS_UF_HZ) == PROT_SET_Q10(49.0), "TC-PS-011 UF default 49.0 Hz"); - CHECK(prot_set_get(PS_OF_DLY) == PROT_SET_Q10(1000.0), "TC-PS-011 OF default 1000 ms"); - CHECK(prot_set_get(PS_UF_DLY) == PROT_SET_Q10(1000.0), "TC-PS-011 UF default 1000 ms"); - CHECK(prot_set_get(PS_RET_OF) == PROT_SET_Q10(0.99), "TC-PS-011 RET_OF default 0.99"); - CHECK(prot_set_get(PS_RET_UF) == PROT_SET_Q10(1.01), "TC-PS-011 RET_UF default 1.01"); + CHECK(prot_set_get(PS_OF_EN) == PROT_SET_Q10(1.0), "TC-PROTSET-011 OF EN default 1"); + CHECK(prot_set_get(PS_UF_EN) == PROT_SET_Q10(1.0), "TC-PROTSET-011 UF EN default 1"); + CHECK(prot_set_get(PS_OF_HZ) == PROT_SET_Q10(51.0), "TC-PROTSET-011 OF default 51.0 Hz"); + CHECK(prot_set_get(PS_UF_HZ) == PROT_SET_Q10(49.0), "TC-PROTSET-011 UF default 49.0 Hz"); + CHECK(prot_set_get(PS_OF_DLY) == PROT_SET_Q10(1000.0), "TC-PROTSET-011 OF default 1000 ms"); + CHECK(prot_set_get(PS_UF_DLY) == PROT_SET_Q10(1000.0), "TC-PROTSET-011 UF default 1000 ms"); + CHECK(prot_set_get(PS_RET_OF) == PROT_SET_Q10(0.99), "TC-PROTSET-011 RET_OF default 0.99"); + CHECK(prot_set_get(PS_RET_UF) == PROT_SET_Q10(1.01), "TC-PROTSET-011 RET_UF default 1.01"); CHECK((g_prot_set_meta[PS_OF_HZ].min == PROT_SET_Q10(50.0)) && (g_prot_set_meta[PS_OF_HZ].max == PROT_SET_Q10(55.0)), - "TC-PS-011 OF range 50.0~55.0 Hz"); + "TC-PROTSET-011 OF range 50.0~55.0 Hz"); CHECK((g_prot_set_meta[PS_UF_HZ].min == PROT_SET_Q10(45.0)) && (g_prot_set_meta[PS_UF_HZ].max == PROT_SET_Q10(50.0)), - "TC-PS-011 UF range 45.0~50.0 Hz"); + "TC-PROTSET-011 UF range 45.0~50.0 Hz"); /* 频率返回系数与电气量系数独立:返回**门槛** = 定值×系数(Q10 乘积 * /1024)——OF 门槛 < 动作门槛、UF 门槛 > 动作门槛(方向相反) */ CHECK(((int64_t)prot_set_get(PS_OF_HZ) * (int64_t)prot_set_get(PS_RET_OF)) / 1024 < (int64_t)prot_set_get(PS_OF_HZ), - "TC-PS-011 OF return threshold (set x 0.99) below pickup"); + "TC-PROTSET-011 OF return threshold (set x 0.99) below pickup"); CHECK(((int64_t)prot_set_get(PS_UF_HZ) * (int64_t)prot_set_get(PS_RET_UF)) / 1024 > (int64_t)prot_set_get(PS_UF_HZ), - "TC-PS-011 UF return threshold (set x 1.01) above pickup"); + "TC-PROTSET-011 UF return threshold (set x 1.01) above pickup"); /* 投退可经 set_sealed 投/退(YK 口径同 GLOBAL_EN;Q10(2)=2048 越界拒) */ - CHECK(prot_set_set_sealed(PS_OF_EN, 0) == 0, "TC-PS-011 OF EN set_sealed OK"); - CHECK(prot_set_get_ctl(PS_OF_EN) == 0u, "TC-PS-011 OF EN readable after seal"); - CHECK(prot_set_set_sealed(PS_OF_EN, PROT_SET_Q10(2)) == -1, "TC-PS-011 OF EN rejects Q10(2)"); - CHECK(prot_set_selfcheck() == 0, "TC-PS-011 no lock after OF/UF seal ops"); + CHECK(prot_set_set_sealed(PS_OF_EN, 0) == 0, "TC-PROTSET-011 OF EN set_sealed OK"); + CHECK(prot_set_get_ctl(PS_OF_EN) == 0u, "TC-PROTSET-011 OF EN readable after seal"); + CHECK(prot_set_set_sealed(PS_OF_EN, PROT_SET_Q10(2)) == -1, "TC-PROTSET-011 OF EN rejects Q10(2)"); + CHECK(prot_set_selfcheck() == 0, "TC-PROTSET-011 no lock after OF/UF seal ops"); /* 64 位 bad_mask:末项(bit 39 > 31)越界可指认 */ (void)prot_set_set_sealed(PS_OC1_CUR, PROT_SET_Q10(11.0)); (void)prot_set_dirty_take(); - CHECK(prot_set_store_serialize(blob, sizeof(blob), &len) == 0, "TC-PS-011 serialize ok"); + CHECK(prot_set_store_serialize(blob, sizeof(blob), &len) == 0, "TC-PROTSET-011 serialize ok"); s_put32(blob + PROT_SET_BLOB_HDR_SZ + 4u * (uint32_t)PS_RET_UF, (uint32_t)(g_prot_set_meta[PS_RET_UF].max + 1)); s_forge_tail(blob, len); - CHECK(prot_set_store_parse(blob, len) == -1, "TC-PS-011 out-of-range RET_UF rejected"); + CHECK(prot_set_store_parse(blob, len) == -1, "TC-PROTSET-011 out-of-range RET_UF rejected"); CHECK(prot_set_bad_mask() == (1uLL << PS_RET_UF), - "TC-PS-011 bad_mask bit 39 addressable (64-bit mask, B8)"); - CHECK(prot_set_get(PS_RET_UF) == PROT_SET_Q10(1.01), "TC-PS-011 default RET_UF intact"); + "TC-PROTSET-011 bad_mask bit 39 addressable (64-bit mask, B8)"); + CHECK(prot_set_get(PS_RET_UF) == PROT_SET_Q10(1.01), "TC-PROTSET-011 default RET_UF intact"); /* 换代语义:B7 旧档(ver=1 / 32 项 = 144 B)在新固件必被拒 -> 出厂默认 */ CHECK(prot_set_store_parse(blob, 8u + 4u * 32u + 8u) == -1, - "TC-PS-011 legacy 32-item blob length rejected"); - CHECK(prot_set_selfcheck() == 0, "TC-PS-011 active table intact after legacy reject"); + "TC-PROTSET-011 legacy 32-item blob length rejected"); + CHECK(prot_set_selfcheck() == 0, "TC-PROTSET-011 active table intact after legacy reject"); } int main(void) { diff --git a/test/host/sha256/sha256_test.c b/test/host/sha256/sha256_test.c index 160d91c0..590c43bf 100644 --- a/test/host/sha256/sha256_test.c +++ b/test/host/sha256/sha256_test.c @@ -12,14 +12,14 @@ * 看不出哪一步坏;标准向量在主机侧毫秒级钉死。 * * 覆盖点: - * TC-SH-001 FIPS 180-4 向量:空串 - * TC-SH-002 FIPS 180-4 向量:"abc" - * TC-SH-003 FIPS 180-4 向量:56 字节(补位跨分组边界) - * TC-SH-004 FIPS 180-4 向量:1,000,000 × 'a'(流式,长度字段进第二分组) - * TC-SH-005 流式任意切分与一次性计算等价(逐字节喂入) - * TC-SH-006 hex_eq:小写匹配 / 大写匹配 - * TC-SH-007 hex_eq:内容不等 / 非法字符 / 长度 63/65 / NULL → 全 0 - * TC-SH-008 默认口令哈希钉值:SHA256("adminadmin") = FTP_CFG_DEF_HASH 同源值 + * TC-SHA256-001 FIPS 180-4 向量:空串 + * TC-SHA256-002 FIPS 180-4 向量:"abc" + * TC-SHA256-003 FIPS 180-4 向量:56 字节(补位跨分组边界) + * TC-SHA256-004 FIPS 180-4 向量:1,000,000 × 'a'(流式,长度字段进第二分组) + * TC-SHA256-005 流式任意切分与一次性计算等价(逐字节喂入) + * TC-SHA256-006 hex_eq:小写匹配 / 大写匹配 + * TC-SHA256-007 hex_eq:内容不等 / 非法字符 / 长度 63/65 / NULL → 全 0 + * TC-SHA256-008 默认口令哈希钉值:SHA256("adminadmin") = FTP_CFG_DEF_HASH 同源值 * * 通过:全部 TC PASS(main 返回 0)。 * 入口:int main(void),返回 0=PASS / 1=FAIL(由 run 脚本判读)。 @@ -65,7 +65,7 @@ static int hex_eq_vector(const uint8_t d[SHA256_DIGEST_SIZE], const char *want) return strcmp(got, want) == 0; } -/* ===================== TC-SH-001..004:标准向量 ===================== */ +/* ===================== TC-SHA256-001..004:标准向量 ===================== */ static void tc_vectors(void) { @@ -73,15 +73,15 @@ static void tc_vectors(void) sha256_calc("", 0u, d); CHECK(hex_eq_vector(d, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"), - "TC-SH-001 空串向量"); + "TC-SHA256-001 空串向量"); sha256_calc("abc", 3u, d); CHECK(hex_eq_vector(d, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"), - "TC-SH-002 \"abc\" 向量"); + "TC-SHA256-002 \"abc\" 向量"); sha256_calc("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56u, d); CHECK(hex_eq_vector(d, "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"), - "TC-SH-003 56 字节向量(补位跨分组)"); + "TC-SHA256-003 56 字节向量(补位跨分组)"); { sha256_ctx_t ctx; @@ -93,10 +93,10 @@ static void tc_vectors(void) sha256_final(&ctx, d); } CHECK(hex_eq_vector(d, "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"), - "TC-SH-004 1e6 × 'a' 向量(流式)"); + "TC-SHA256-004 1e6 × 'a' 向量(流式)"); } -/* ===================== TC-SH-005:流式等价 ===================== */ +/* ===================== TC-SHA256-005:流式等价 ===================== */ static void tc_stream_equiv(void) { @@ -111,10 +111,10 @@ static void tc_stream_equiv(void) sha256_update(&ctx, &msg[i], 1u); } sha256_final(&ctx, d2); - CHECK(memcmp(d1, d2, sizeof(d1)) == 0, "TC-SH-005 逐字节喂入与一次性等价"); + CHECK(memcmp(d1, d2, sizeof(d1)) == 0, "TC-SHA256-005 逐字节喂入与一次性等价"); } -/* ===================== TC-SH-006..007:hex_eq ===================== */ +/* ===================== TC-SHA256-006..007:hex_eq ===================== */ static void tc_hex_eq(void) { @@ -131,11 +131,11 @@ static void tc_hex_eq(void) } upper[64] = '\0'; - CHECK(sha256_hex_eq(d, lower) == 1, "TC-SH-006a 小写 hex 匹配"); - CHECK(sha256_hex_eq(d, upper) == 1, "TC-SH-006b 大写 hex 匹配(大小写不敏感)"); + CHECK(sha256_hex_eq(d, lower) == 1, "TC-SHA256-006a 小写 hex 匹配"); + CHECK(sha256_hex_eq(d, upper) == 1, "TC-SHA256-006b 大写 hex 匹配(大小写不敏感)"); lower[63] = (char)((lower[63] == '0') ? '1' : '0'); - CHECK(sha256_hex_eq(d, lower) == 0, "TC-SH-007a 内容不等 → 0"); + CHECK(sha256_hex_eq(d, lower) == 0, "TC-SHA256-007a 内容不等 → 0"); lower[63] = (char)((lower[63] == '0') ? '1' : '0'); /* 还原 */ { @@ -144,22 +144,22 @@ static void tc_hex_eq(void) memcpy(bad, lower, 64); bad[64] = '\0'; bad[10] = 'g'; - CHECK(sha256_hex_eq(d, bad) == 0, "TC-SH-007b 非法 hex 字符 → 0"); + CHECK(sha256_hex_eq(d, bad) == 0, "TC-SHA256-007b 非法 hex 字符 → 0"); } memcpy(shortv, lower, 63); shortv[63] = '\0'; - CHECK(sha256_hex_eq(d, shortv) == 0, "TC-SH-007c 长度 63 → 0"); + CHECK(sha256_hex_eq(d, shortv) == 0, "TC-SHA256-007c 长度 63 → 0"); memcpy(longv, lower, 64); longv[64] = 'a'; longv[65] = '\0'; - CHECK(sha256_hex_eq(d, longv) == 0, "TC-SH-007d 长度 65 → 0"); + CHECK(sha256_hex_eq(d, longv) == 0, "TC-SHA256-007d 长度 65 → 0"); - CHECK(sha256_hex_eq(d, NULL) == 0, "TC-SH-007e NULL → 0"); + CHECK(sha256_hex_eq(d, NULL) == 0, "TC-SHA256-007e NULL → 0"); } -/* ===================== TC-SH-008:默认口令哈希钉值 ===================== */ +/* ===================== TC-SHA256-008:默认口令哈希钉值 ===================== */ static void tc_default_hash(void) { @@ -168,7 +168,7 @@ static void tc_default_hash(void) /* 与 ftp_cfg.h FTP_CFG_DEF_HASH 同源钉值(两处若漂移本测试立刻红) */ sha256_calc("adminadmin", 10u, d); CHECK(sha256_hex_eq(d, "d82494f05d6917ba02f7aaa29689ccb444bb73f20380876cb05d1f37537b7892") == 1, - "TC-SH-008 SHA256(\"adminadmin\") = 出厂默认 pwd_hash"); + "TC-SHA256-008 SHA256(\"adminadmin\") = 出厂默认 pwd_hash"); } /* ===================== main ===================== */ diff --git a/test/host/sys_clock/sys_clock_test.c b/test/host/sys_clock/sys_clock_test.c index 4d6e0caf..899fbf93 100644 --- a/test/host/sys_clock/sys_clock_test.c +++ b/test/host/sys_clock/sys_clock_test.c @@ -14,27 +14,27 @@ * - 其余用例用 sys_clock_set(unix, NULL) 建立确定基准(无 RTC 副作用)。 * * 覆盖点(对应 docs/测试说明/系统时钟单元测试说明.md 的 TC-CLK-xxx): - * TC-CLK-000 未初始化:sys_clock_get / get_time / get_str 的无效语义 - * TC-CLK-001 init 正常:RTC 合法 → 返回 0,基准 = 换算 Unix 秒 - * TC-CLK-002 init 闰年换算:2024-02-29 / 2000-02-29(世纪闰)/ 2/29→3/1 间隔 - * TC-CLK-003 init 月末边界:1/31、2/28、4/30 的 Unix 秒精确值 - * TC-CLK-004 init 世纪边界:2000-01-01、2038 上限(0x7FFFFFFF)、Unix 0 经 set - * TC-CLK-005 init RTC 读失败 → 降级默认时间,返回 -1 + 打错误日志 - * TC-CLK-006 init RTC 越界(年份/月/日非法)→ 自愈写回默认时间(返回 0) - * TC-CLK-020 init 越界且写回失败 → 降级默认时间 + 返回 -1 - * TC-CLK-007 init 越界 → 自动写回默认时间并复验(rtc 被修正) - * TC-CLK-008 get 正常推进:tick +1000 → +1 秒(含亚秒截断) - * TC-CLK-009 get 未跨阈值不回绕:tick + 29 天仍线性 - * TC-CLK-010 get 30 天再基准化:窗口清零、墙钟值无损、含亚秒余数结转 - * TC-CLK-011 get tick 回绕(无符号差)安全 - * TC-CLK-012 get 再基准化后长期不漂移(多轮 30 天) - * TC-CLK-013 get_str 格式化 + 未初始化占位串 - * TC-CLK-014 get_time 日历字段(年/月/日/时/分/秒/星期)与已知日期对照 - * TC-CLK-015 get_time NULL 参数被拒 - * TC-CLK-016 set 更新基准 + 写回 RTC(观察 sd2506_set_time 被调) - * TC-CLK-017 set sd_time=NULL 不碰 RTC - * TC-CLK-018 set_unix 写回 RTC 且日历字段正确(含星期) - * TC-CLK-019 星期(Zeller)与已知日期对照穷举(跨世纪/闰/月末) + * TC-SYSCLK-000 未初始化:sys_clock_get / get_time / get_str 的无效语义 + * TC-SYSCLK-001 init 正常:RTC 合法 → 返回 0,基准 = 换算 Unix 秒 + * TC-SYSCLK-002 init 闰年换算:2024-02-29 / 2000-02-29(世纪闰)/ 2/29→3/1 间隔 + * TC-SYSCLK-003 init 月末边界:1/31、2/28、4/30 的 Unix 秒精确值 + * TC-SYSCLK-004 init 世纪边界:2000-01-01、2038 上限(0x7FFFFFFF)、Unix 0 经 set + * TC-SYSCLK-005 init RTC 读失败 → 降级默认时间,返回 -1 + 打错误日志 + * TC-SYSCLK-006 init RTC 越界(年份/月/日非法)→ 自愈写回默认时间(返回 0) + * TC-SYSCLK-020 init 越界且写回失败 → 降级默认时间 + 返回 -1 + * TC-SYSCLK-007 init 越界 → 自动写回默认时间并复验(rtc 被修正) + * TC-SYSCLK-008 get 正常推进:tick +1000 → +1 秒(含亚秒截断) + * TC-SYSCLK-009 get 未跨阈值不回绕:tick + 29 天仍线性 + * TC-SYSCLK-010 get 30 天再基准化:窗口清零、墙钟值无损、含亚秒余数结转 + * TC-SYSCLK-011 get tick 回绕(无符号差)安全 + * TC-SYSCLK-012 get 再基准化后长期不漂移(多轮 30 天) + * TC-SYSCLK-013 get_str 格式化 + 未初始化占位串 + * TC-SYSCLK-014 get_time 日历字段(年/月/日/时/分/秒/星期)与已知日期对照 + * TC-SYSCLK-015 get_time NULL 参数被拒 + * TC-SYSCLK-016 set 更新基准 + 写回 RTC(观察 sd2506_set_time 被调) + * TC-SYSCLK-017 set sd_time=NULL 不碰 RTC + * TC-SYSCLK-018 set_unix 写回 RTC 且日历字段正确(含星期) + * TC-SYSCLK-019 星期(Zeller)与已知日期对照穷举(跨世纪/闰/月末) * * 通过:全部 TC PASS(main 返回 0)。 * 入口:int main(void),返回 0=PASS / 1=FAIL(由 run 脚本判读)。 @@ -189,7 +189,7 @@ static void tc_000_uninitialized(void) { sd2506_time_t t; char buf[32]; - printf("TC-CLK-000 未初始化语义\n"); + printf("TC-SYSCLK-000 未初始化语义\n"); /* 注意:本用例不做 sys_clock_init / sys_clock_set */ CHECK_EQ_U32(sys_clock_get(), UINT32_MAX, "未初始化 get 返回 UINT32_MAX"); CHECK(sys_clock_get_time(&t) == -1, "未初始化 get_time 返回 -1"); @@ -201,7 +201,7 @@ static void tc_000_uninitialized(void) { static void tc_001_init_ok(void) { int rc; - printf("TC-CLK-001 init 正常(RTC 合法)\n"); + printf("TC-SYSCLK-001 init 正常(RTC 合法)\n"); rtc_set(2026, 8, 24, 0, 0, 0); s_rtc_read_rc = SD2506_OK; s_rtc_write_rc = SD2506_OK; @@ -216,7 +216,7 @@ static void tc_001_init_ok(void) { } static void tc_002_init_leap(void) { - printf("TC-CLK-002 init 闰年换算\n"); + printf("TC-SYSCLK-002 init 闰年换算\n"); /* 2024 是闰年:2/29 存在 */ rtc_set(2024, 2, 29, 12, 0, 0); s_rtc_read_rc = SD2506_OK; @@ -240,7 +240,7 @@ static void tc_002_init_leap(void) { } static void tc_003_init_month_end(void) { - printf("TC-CLK-003 init 月末边界\n"); + printf("TC-SYSCLK-003 init 月末边界\n"); rtc_set(2026, 1, 31, 0, 0, 0); s_rtc_read_rc = SD2506_OK; CHECK(sys_clock_init() == 0, "1/31 合法"); CHECK_EQ_U32(sys_clock_get(), ref_unix(2026, 1, 31, 0, 0, 0), "1/31 换算"); @@ -262,7 +262,7 @@ static void tc_003_init_month_end(void) { } static void tc_004_init_epoch_bounds(void) { - printf("TC-CLK-004 init 世纪边界(Unix 下限 / 2038 上限)\n"); + printf("TC-SYSCLK-004 init 世纪边界(Unix 下限 / 2038 上限)\n"); /* * 注意:init 接受的 RTC 年份范围是 2000~2099(越界即判故障并自愈), * 故"Unix 0(1970-01-01)"**不可能经 init 建立**——1970 会被判越界。 @@ -291,7 +291,7 @@ static void tc_004_init_epoch_bounds(void) { } static void tc_005_init_rtc_read_fail(void) { - printf("TC-CLK-005 init RTC 读失败 → 降级默认时间并返回 -1\n"); + printf("TC-SYSCLK-005 init RTC 读失败 → 降级默认时间并返回 -1\n"); s_rtc_read_rc = SD2506_ERROR; /* 注入读故障 */ s_rtc_write_rc = SD2506_OK; clear_obs(); @@ -309,7 +309,7 @@ static void tc_005_init_rtc_read_fail(void) { } static void tc_006_init_out_of_range_selfheal(void) { - printf("TC-CLK-006 init RTC 越界 → 自愈写回默认时间(返回 0)\n"); + printf("TC-SYSCLK-006 init RTC 越界 → 自愈写回默认时间(返回 0)\n"); /* * RTC_DEFAULT_INIT_ENABLE=1 且 FORCE=0 时:越界值触发"写回默认时间", * 写成功且复读合法 → rtc_ok 恢复为 1 → **返回 0**(自愈,非降级)。 @@ -335,7 +335,7 @@ static void tc_006_init_out_of_range_selfheal(void) { } static void tc_020_init_selfheal_fail_degrades(void) { - printf("TC-CLK-020 init 越界且写回失败 → 降级默认时间并返回 -1\n"); + printf("TC-SYSCLK-020 init 越界且写回失败 → 降级默认时间并返回 -1\n"); /* * 组合故障:读成功但值越界(触发写回),写回失败 → 复读仍越界 → * rtc_ok 清 0 → 走降级分支(启用默认值时建基准 + 返回 -1)。 @@ -356,7 +356,7 @@ static void tc_020_init_selfheal_fail_degrades(void) { } static void tc_007_init_corrects_rtc(void) { - printf("TC-CLK-007 init 越界 → 自动写回默认时间并复验\n"); + printf("TC-SYSCLK-007 init 越界 → 自动写回默认时间并复验\n"); rtc_set(1999, 1, 1, 0, 0, 0); /* 越界,触发校时写回 */ s_rtc_read_rc = SD2506_OK; s_rtc_write_rc = SD2506_OK; @@ -372,7 +372,7 @@ static void tc_007_init_corrects_rtc(void) { } static void tc_008_get_advance(void) { - printf("TC-CLK-008 get 正常推进(含亚秒截断)\n"); + printf("TC-SYSCLK-008 get 正常推进(含亚秒截断)\n"); base_at(1000000u, 5000u); CHECK_EQ_U32(sys_clock_get(), 1000000u, "基准时刻 = 基准值"); tick_advance(999u); @@ -384,7 +384,7 @@ static void tc_008_get_advance(void) { } static void tc_009_get_no_rebase_below_threshold(void) { - printf("TC-CLK-009 未达 30 天阈值不触发再基准化\n"); + printf("TC-SYSCLK-009 未达 30 天阈值不触发再基准化\n"); base_at(2000000u, 0u); /* 29 天 < 30 天阈值:线性推进,基准不动 */ tick_advance(29u * 24u * 3600u * 1000u); @@ -393,7 +393,7 @@ static void tc_009_get_no_rebase_below_threshold(void) { } static void tc_010_get_rebase_at_threshold(void) { - printf("TC-CLK-010 30 天惰性再基准化(窗口清零、值无损、余数结转)\n"); + printf("TC-SYSCLK-010 30 天惰性再基准化(窗口清零、值无损、余数结转)\n"); base_at(3000000u, 0u); /* 推进恰好 30 天 + 1500ms(余数 500ms 应结转到新窗) */ @@ -411,7 +411,7 @@ static void tc_010_get_rebase_at_threshold(void) { } static void tc_011_get_tick_wrap(void) { - printf("TC-CLK-011 tick 回绕(无符号差)安全\n"); + printf("TC-SYSCLK-011 tick 回绕(无符号差)安全\n"); /* 基准设在接近 2^32 处 */ base_at(4000000u, 0xFFFFF000u); /* 推进 0x2000 ms(跨越 2^32 回绕):差 = 0x2000 = 8192ms → +8s */ @@ -420,7 +420,7 @@ static void tc_011_get_tick_wrap(void) { } static void tc_012_get_long_run_no_drift(void) { - printf("TC-CLK-012 多轮再基准化长期不漂移\n"); + printf("TC-SYSCLK-012 多轮再基准化长期不漂移\n"); base_at(5000000u, 0u); /* * 惰性再基准化的**正确用法**:周期性调用 get() 让差值窗口始终 < 30 天。 @@ -439,7 +439,7 @@ static void tc_012_get_long_run_no_drift(void) { } static void tc_013_get_str(void) { - printf("TC-CLK-013 get_str 格式化\n"); + printf("TC-SYSCLK-013 get_str 格式化\n"); char buf[32]; base_at(ref_unix(2026, 10, 2, 13, 4, 5), 0u); memset(buf, 0, sizeof(buf)); @@ -453,7 +453,7 @@ static void tc_013_get_str(void) { } static void tc_014_get_time_fields(void) { - printf("TC-CLK-014 get_time 日历字段\n"); + printf("TC-SYSCLK-014 get_time 日历字段\n"); sd2506_time_t t; /* 2026-10-02 是周五(已知) */ base_at(ref_unix(2026, 10, 2, 8, 9, 10), 0u); @@ -465,13 +465,13 @@ static void tc_014_get_time_fields(void) { } static void tc_015_get_time_null(void) { - printf("TC-CLK-015 get_time NULL 参数被拒\n"); + printf("TC-SYSCLK-015 get_time NULL 参数被拒\n"); base_at(6000000u, 0u); CHECK(sys_clock_get_time(NULL) == -1, "p_time == NULL → 返回 -1"); } static void tc_016_set_writes_rtc(void) { - printf("TC-CLK-016 set 更新基准 + 写回 RTC\n"); + printf("TC-SYSCLK-016 set 更新基准 + 写回 RTC\n"); sd2506_time_t sd; memset(&sd, 0, sizeof(sd)); sd.year = 2027; sd.month = 3; sd.day = 15; @@ -497,7 +497,7 @@ static void tc_016_set_writes_rtc(void) { } static void tc_017_set_no_rtc(void) { - printf("TC-CLK-017 set sd_time=NULL 不碰 RTC\n"); + printf("TC-SYSCLK-017 set sd_time=NULL 不碰 RTC\n"); clear_obs(); CHECK(sys_clock_set(8000000u, NULL) == 0, "set(NULL) 返回 0"); CHECK(s_rtc_set_calls == 0, "sd_time == NULL → 不写 RTC"); @@ -505,7 +505,7 @@ static void tc_017_set_no_rtc(void) { } static void tc_018_set_unix_fields(void) { - printf("TC-CLK-018 set_unix 写回 RTC 且字段正确\n"); + printf("TC-SYSCLK-018 set_unix 写回 RTC 且字段正确\n"); sd2506_time_t expect_week; uint32_t u = ref_unix(2026, 10, 2, 15, 30, 45); clear_obs(); @@ -521,7 +521,7 @@ static void tc_018_set_unix_fields(void) { } static void tc_019_week_known_dates(void) { - printf("TC-CLK-019 星期(Zeller)已知日期穷举\n"); + printf("TC-SYSCLK-019 星期(Zeller)已知日期穷举\n"); /* 期望值经 Python datetime 独立核对(0=周日); * 覆盖 1/2 月(Zeller 需上调为上年 13/14 月的分支)与 3~12 月(2026-10-02 * 修正前全部错误),以及世纪闰年、非闰世纪、范围首尾。*/ diff --git a/test/host/time_sync/time_sync_test.c b/test/host/time_sync/time_sync_test.c index 48d7747f..32a3fbfb 100644 --- a/test/host/time_sync/time_sync_test.c +++ b/test/host/time_sync/time_sync_test.c @@ -27,36 +27,36 @@ * * 覆盖点(TC-TS-xxx): * —— time_sync_delay_fed(可喂心跳的分片延时)—— - * TC-TS-001 0ms 不睡眠不喂狗 - * TC-TS-002 恰好一片(50ms) - * TC-TS-003 非整片(120ms)切成 50/50/20,每片喂心跳 - * TC-TS-004 长延时(2000ms)= 40 片 × 50ms,每片喂心跳 - * TC-TS-005 不足一片(49ms)单片处理 - * TC-TS-006 总预算 30s = 600 片(片长上限恒 50ms) + * TC-TIMESYNC-001 0ms 不睡眠不喂狗 + * TC-TIMESYNC-002 恰好一片(50ms) + * TC-TIMESYNC-003 非整片(120ms)切成 50/50/20,每片喂心跳 + * TC-TIMESYNC-004 长延时(2000ms)= 40 片 × 50ms,每片喂心跳 + * TC-TIMESYNC-005 不足一片(49ms)单片处理 + * TC-TIMESYNC-006 总预算 30s = 600 片(片长上限恒 50ms) * —— time_sync_open_listener(监听建立与重试)—— - * TC-TS-010 首次成功:socket/bind/listen 各一次,端口经 net_htons,无退避 - * TC-TS-011 bind 失败 -> 关 socket + 退避 2000ms + 留痕,随后重试成功 - * TC-TS-012 listen 失败 -> 关 socket + 退避 2000ms,随后重试成功 - * TC-TS-013 socket 连续失败 -> 5 次后返回 -1(5 条 ERROR,5×500ms 退避) - * TC-TS-014 第 3 次重试成功并返回新描述符 - * TC-TS-015 每次重试前 + 每片延时各喂一次心跳,且心跳位恒为 TIMESYNC + * TC-TIMESYNC-010 首次成功:socket/bind/listen 各一次,端口经 net_htons,无退避 + * TC-TIMESYNC-011 bind 失败 -> 关 socket + 退避 2000ms + 留痕,随后重试成功 + * TC-TIMESYNC-012 listen 失败 -> 关 socket + 退避 2000ms,随后重试成功 + * TC-TIMESYNC-013 socket 连续失败 -> 5 次后返回 -1(5 条 ERROR,5×500ms 退避) + * TC-TIMESYNC-014 第 3 次重试成功并返回新描述符 + * TC-TIMESYNC-015 每次重试前 + 每片延时各喂一次心跳,且心跳位恒为 TIMESYNC * —— time_sync_handle_conn(时间包重组状态机)—— - * TC-TS-020 8 字节一次收齐 -> 大端解析 epoch + 更新墙钟 + 关连接 - * TC-TS-021 分段送达(4+4)-> 累积后解析;第二次只请求剩余 12 字节 - * TC-TS-022 一次到达 16 字节 -> 只取前 8 字节 - * TC-TS-023 前缀非 "TIME" -> 不更新墙钟,但仍关连接 - * TC-TS-024 对端关闭(n==0)-> 立即退出、不解析 - * TC-TS-025 真错误(n==-1)-> 立即退出、不解析 - * TC-TS-026 只收到 4 字节后 EOF -> 不足 8 字节不解析 - * TC-TS-027 30s 预算耗尽 -> 留痕 "no TIME packet in 30s, drop conn" - * TC-TS-028 剩余预算不足一片 -> 末片按剩余(20ms)切分 - * TC-TS-029 32 位 tick 回绕 -> 预算计算仍正确 + * TC-TIMESYNC-020 8 字节一次收齐 -> 大端解析 epoch + 更新墙钟 + 关连接 + * TC-TIMESYNC-021 分段送达(4+4)-> 累积后解析;第二次只请求剩余 12 字节 + * TC-TIMESYNC-022 一次到达 16 字节 -> 只取前 8 字节 + * TC-TIMESYNC-023 前缀非 "TIME" -> 不更新墙钟,但仍关连接 + * TC-TIMESYNC-024 对端关闭(n==0)-> 立即退出、不解析 + * TC-TIMESYNC-025 真错误(n==-1)-> 立即退出、不解析 + * TC-TIMESYNC-026 只收到 4 字节后 EOF -> 不足 8 字节不解析 + * TC-TIMESYNC-027 30s 预算耗尽 -> 留痕 "no TIME packet in 30s, drop conn" + * TC-TIMESYNC-028 剩余预算不足一片 -> 末片按剩余(20ms)切分 + * TC-TIMESYNC-029 32 位 tick 回绕 -> 预算计算仍正确 * —— time_sync_task(任务主循环)—— - * TC-TS-040 sys_evtHandle==NULL:跳过就绪屏障;accept 轮询->成功->处理->收尾 - * TC-TS-041 就绪屏障:100ms 分片等待 NET_READY(osFlagsNoClear 不消费就绪位) - * TC-TS-042 屏障未就绪期间持续喂心跳(2026-10-02 台架根因的回归防线) - * TC-TS-043 网络代次变化 -> 关闭旧监听并重监听 - * TC-TS-044 监听建立失败 -> 5 次重试后放弃并退避 2000ms + * TC-TIMESYNC-040 sys_evtHandle==NULL:跳过就绪屏障;accept 轮询->成功->处理->收尾 + * TC-TIMESYNC-041 就绪屏障:100ms 分片等待 NET_READY(osFlagsNoClear 不消费就绪位) + * TC-TIMESYNC-042 屏障未就绪期间持续喂心跳(2026-10-02 台架根因的回归防线) + * TC-TIMESYNC-043 网络代次变化 -> 关闭旧监听并重监听 + * TC-TIMESYNC-044 监听建立失败 -> 5 次重试后放弃并退避 2000ms * * 通过:全部 TC PASS(main 返回 0)。 * 入口:int main(void),返回 0=PASS / 1=FAIL(由 run 脚本判读)。 @@ -413,51 +413,51 @@ static int delays_all(uint32_t v, int n) { return 1; } -/* ===================== TC-TS-001..006:delay_fed ===================== */ +/* ===================== TC-TIMESYNC-001..006:delay_fed ===================== */ static void tc_delay_fed(void) { fakes_reset(); time_sync_delay_fed(0U); - CHECK((s_beat_calls == 0) && (s_delay_calls == 0), "TC-TS-001 delay_fed(0) 不睡眠不喂狗"); + CHECK((s_beat_calls == 0) && (s_delay_calls == 0), "TC-TIMESYNC-001 delay_fed(0) 不睡眠不喂狗"); fakes_reset(); time_sync_delay_fed(50U); CHECK((s_beat_calls == 1) && (s_delay_calls == 1) && (s_delays[0] == 50U), - "TC-TS-002 delay_fed(50) = 1 片 50ms + 1 次心跳"); + "TC-TIMESYNC-002 delay_fed(50) = 1 片 50ms + 1 次心跳"); fakes_reset(); time_sync_delay_fed(120U); - CHECK((s_beat_calls == 3) && (s_delay_calls == 3), "TC-TS-003 delay_fed(120) 切成 3 片"); + CHECK((s_beat_calls == 3) && (s_delay_calls == 3), "TC-TIMESYNC-003 delay_fed(120) 切成 3 片"); CHECK((s_delays[0] == 50U) && (s_delays[1] == 50U) && (s_delays[2] == 20U), - "TC-TS-003b 片长 50/50/20(末片为余数)"); + "TC-TIMESYNC-003b 片长 50/50/20(末片为余数)"); fakes_reset(); time_sync_delay_fed(2000U); CHECK((s_delay_calls == 40) && (s_beat_calls == 40) && delays_all(50U, 40), - "TC-TS-004 delay_fed(2000) = 40 片 × 50ms,每片喂一次心跳"); + "TC-TIMESYNC-004 delay_fed(2000) = 40 片 × 50ms,每片喂一次心跳"); fakes_reset(); time_sync_delay_fed(49U); - CHECK((s_beat_calls == 1) && (s_delays[0] == 49U), "TC-TS-005 不足一片(49ms)单片处理"); + CHECK((s_beat_calls == 1) && (s_delays[0] == 49U), "TC-TIMESYNC-005 不足一片(49ms)单片处理"); fakes_reset(); time_sync_delay_fed(30000U); - CHECK(s_delay_calls == 600, "TC-TS-006 总预算 30s = 600 片(片长上限恒 50ms)"); + CHECK(s_delay_calls == 600, "TC-TIMESYNC-006 总预算 30s = 600 片(片长上限恒 50ms)"); } -/* ===================== TC-TS-010..015:open_listener ===================== */ +/* ===================== TC-TIMESYNC-010..015:open_listener ===================== */ static void tc_open_listener(void) { fakes_reset(); { int s = time_sync_open_listener(); - CHECK(s == 5, "TC-TS-010 open_listener 成功返回 socket 描述符"); + CHECK(s == 5, "TC-TIMESYNC-010 open_listener 成功返回 socket 描述符"); CHECK((s_socket_calls == 1) && (s_bind_calls == 1) && (s_listen_calls == 1), - "TC-TS-010b socket / bind / listen 各一次"); - CHECK(s_htons_last == (uint16_t)TIME_SYNC_PORT, "TC-TS-010c 端口经 net_htons(8888)"); - CHECK(s_bind_port == net_htons((uint16_t)TIME_SYNC_PORT), "TC-TS-010d sin_port 为网络序"); - CHECK(s_bind_family == (uint16_t)NET_AF_INET, "TC-TS-010e sin_family = NET_AF_INET"); - CHECK(s_delay_calls == 0, "TC-TS-010f 成功路径无退避延时"); + "TC-TIMESYNC-010b socket / bind / listen 各一次"); + CHECK(s_htons_last == (uint16_t)TIME_SYNC_PORT, "TC-TIMESYNC-010c 端口经 net_htons(8888)"); + CHECK(s_bind_port == net_htons((uint16_t)TIME_SYNC_PORT), "TC-TIMESYNC-010d sin_port 为网络序"); + CHECK(s_bind_family == (uint16_t)NET_AF_INET, "TC-TIMESYNC-010e sin_family = NET_AF_INET"); + CHECK(s_delay_calls == 0, "TC-TIMESYNC-010f 成功路径无退避延时"); } fakes_reset(); @@ -465,10 +465,10 @@ static void tc_open_listener(void) { s_bind_seq_n = 1; { int s = time_sync_open_listener(); - CHECK(s == 5, "TC-TS-011 bind 失败一次后重试成功"); - CHECK((s_close_calls == 1) && (s_close_socks[0] == 5), "TC-TS-011b bind 失败关闭该 socket"); - CHECK(s_delay_calls == 40, "TC-TS-011c bind 失败退避 2000ms(40 片)"); - CHECK(g_tstest_err_count == 1, "TC-TS-011d bind 失败留痕 DBG_ERROR"); + CHECK(s == 5, "TC-TIMESYNC-011 bind 失败一次后重试成功"); + CHECK((s_close_calls == 1) && (s_close_socks[0] == 5), "TC-TIMESYNC-011b bind 失败关闭该 socket"); + CHECK(s_delay_calls == 40, "TC-TIMESYNC-011c bind 失败退避 2000ms(40 片)"); + CHECK(g_tstest_err_count == 1, "TC-TIMESYNC-011d bind 失败留痕 DBG_ERROR"); } fakes_reset(); @@ -476,19 +476,19 @@ static void tc_open_listener(void) { s_listen_seq_n = 1; { int s = time_sync_open_listener(); - CHECK(s == 5, "TC-TS-012 listen 失败一次后重试成功"); - CHECK((s_close_calls == 1) && (s_close_socks[0] == 5), "TC-TS-012b listen 失败关闭该 socket"); - CHECK(s_delay_calls == 40, "TC-TS-012c listen 失败退避 2000ms"); + CHECK(s == 5, "TC-TIMESYNC-012 listen 失败一次后重试成功"); + CHECK((s_close_calls == 1) && (s_close_socks[0] == 5), "TC-TIMESYNC-012b listen 失败关闭该 socket"); + CHECK(s_delay_calls == 40, "TC-TIMESYNC-012c listen 失败退避 2000ms"); } fakes_reset(); s_socket_default = -1; { int s = time_sync_open_listener(); - CHECK(s == -1, "TC-TS-013 socket 连续失败 -> 返回 -1"); - CHECK(s_socket_calls == 5, "TC-TS-013b 重试上限 5 次"); - CHECK(g_tstest_err_count == 5, "TC-TS-013c 每次失败各留痕一条(5 条 DBG_ERROR)"); - CHECK(s_delay_calls == 50, "TC-TS-013d 每次失败退避 500ms(5 × 10 片)"); + CHECK(s == -1, "TC-TIMESYNC-013 socket 连续失败 -> 返回 -1"); + CHECK(s_socket_calls == 5, "TC-TIMESYNC-013b 重试上限 5 次"); + CHECK(g_tstest_err_count == 5, "TC-TIMESYNC-013c 每次失败各留痕一条(5 条 DBG_ERROR)"); + CHECK(s_delay_calls == 50, "TC-TIMESYNC-013d 每次失败退避 500ms(5 × 10 片)"); } fakes_reset(); @@ -498,23 +498,23 @@ static void tc_open_listener(void) { s_socket_seq_n = 3; { int s = time_sync_open_listener(); - CHECK(s == 9, "TC-TS-014 第 3 次重试成功并返回新描述符"); - CHECK(s_socket_calls == 3, "TC-TS-014b 恰好尝试 3 次"); - CHECK(s_delay_calls == 20, "TC-TS-014c 两次失败退避 500ms × 2"); + CHECK(s == 9, "TC-TIMESYNC-014 第 3 次重试成功并返回新描述符"); + CHECK(s_socket_calls == 3, "TC-TIMESYNC-014b 恰好尝试 3 次"); + CHECK(s_delay_calls == 20, "TC-TIMESYNC-014c 两次失败退避 500ms × 2"); } fakes_reset(); s_socket_default = -1; (void)time_sync_open_listener(); - CHECK(s_beat_calls == 55, "TC-TS-015 每轮重试(5) + 每片延时(50) 各喂一次心跳"); - CHECK(s_beat_id_bad == 0, "TC-TS-015b 心跳位恒为 TASK_WD_TIMESYNC"); + CHECK(s_beat_calls == 55, "TC-TIMESYNC-015 每轮重试(5) + 每片延时(50) 各喂一次心跳"); + CHECK(s_beat_id_bad == 0, "TC-TIMESYNC-015b 心跳位恒为 TASK_WD_TIMESYNC"); } -/* ===================== TC-TS-020..029:handle_conn ===================== +/* ===================== TC-TIMESYNC-020..029:handle_conn ===================== * ⚠ 契约变更:handle_conn **不再** net_close * (单连接模式下 conn==listen,close 会连监听一起毁);会话收尾只返回外层, * 由 time_sync_task 在 `conn != ls`(模拟器多连接后端)时才关数据 fd。 - * 故本组断言一律为 s_close_calls == 0;任务级关闭见 TC-TS-040e。 */ + * 故本组断言一律为 s_close_calls == 0;任务级关闭见 TC-TIMESYNC-040e。 */ static void tc_handle_conn(void) { uint8_t pkt[16]; @@ -526,13 +526,13 @@ static void tc_handle_conn(void) { s_recv_seq_n = 1; s_tick = 100U; time_sync_handle_conn(7); - CHECK(s_set_unix_calls == 1, "TC-TS-020 TIME 包一次收齐 -> 更新墙钟一次"); - CHECK(s_set_unix_last == 0x12345678u, "TC-TS-020b epoch 按大端解析"); - CHECK((s_recv_calls == 1) && (s_recv_len_log[0] == 16), "TC-TS-020c 首次请求 16 字节"); - CHECK(s_recv_to_log[0] == 50U, "TC-TS-020d 单次等待片长 = 50ms"); - CHECK(s_close_calls == 0, "TC-TS-020e 处理完**不**关闭连接(close 交外层 conn!=ls 分支)"); - CHECK(s_drop_calls == 0, "TC-TS-020g 成功会话不拆(drop 只用于放弃路径)"); - CHECK(g_tstest_info_count == 1, "TC-TS-020f 留痕 wall clock updated"); + CHECK(s_set_unix_calls == 1, "TC-TIMESYNC-020 TIME 包一次收齐 -> 更新墙钟一次"); + CHECK(s_set_unix_last == 0x12345678u, "TC-TIMESYNC-020b epoch 按大端解析"); + CHECK((s_recv_calls == 1) && (s_recv_len_log[0] == 16), "TC-TIMESYNC-020c 首次请求 16 字节"); + CHECK(s_recv_to_log[0] == 50U, "TC-TIMESYNC-020d 单次等待片长 = 50ms"); + CHECK(s_close_calls == 0, "TC-TIMESYNC-020e 处理完**不**关闭连接(close 交外层 conn!=ls 分支)"); + CHECK(s_drop_calls == 0, "TC-TIMESYNC-020g 成功会话不拆(drop 只用于放弃路径)"); + CHECK(g_tstest_info_count == 1, "TC-TIMESYNC-020f 留痕 wall clock updated"); /* 2) 分段送达:4 + 4 */ fakes_reset(); @@ -541,11 +541,11 @@ static void tc_handle_conn(void) { recv_set(1, 4, pkt + 4, 4, 10U); s_recv_seq_n = 2; time_sync_handle_conn(3); - CHECK((s_set_unix_calls == 1) && (s_set_unix_last == 10u), "TC-TS-021 分段送达累积后解析正确"); - CHECK(s_recv_calls == 2, "TC-TS-021b 读了两次"); + CHECK((s_set_unix_calls == 1) && (s_set_unix_last == 10u), "TC-TIMESYNC-021 分段送达累积后解析正确"); + CHECK(s_recv_calls == 2, "TC-TIMESYNC-021b 读了两次"); CHECK((s_recv_len_log[0] == 16) && (s_recv_len_log[1] == 12), - "TC-TS-021c 第二次只请求剩余 12 字节"); - CHECK((s_recv_to_log[0] == 50U) && (s_recv_to_log[1] == 50U), "TC-TS-021d 每片 50ms(预算充裕)"); + "TC-TIMESYNC-021c 第二次只请求剩余 12 字节"); + CHECK((s_recv_to_log[0] == 50U) && (s_recv_to_log[1] == 50U), "TC-TIMESYNC-021d 每片 50ms(预算充裕)"); /* 3) 16 字节一次到达(只取前 8) */ fakes_reset(); @@ -553,8 +553,8 @@ static void tc_handle_conn(void) { recv_set(0, 16, pkt, 16, 0U); s_recv_seq_n = 1; time_sync_handle_conn(4); - CHECK((s_set_unix_calls == 1) && (s_set_unix_last == 5u), "TC-TS-022 超长包只取前 8 字节"); - CHECK(s_recv_calls == 1, "TC-TS-022b 一次读够即停"); + CHECK((s_set_unix_calls == 1) && (s_set_unix_last == 5u), "TC-TIMESYNC-022 超长包只取前 8 字节"); + CHECK(s_recv_calls == 1, "TC-TIMESYNC-022b 一次读够即停"); /* 4) 前缀不是 TIME */ fakes_reset(); @@ -569,23 +569,23 @@ static void tc_handle_conn(void) { recv_set(0, 8, pkt, 8, 0U); s_recv_seq_n = 1; time_sync_handle_conn(4); - CHECK(s_set_unix_calls == 0, "TC-TS-023 非 TIME 前缀不更新墙钟"); - CHECK(s_close_calls == 0, "TC-TS-023b 非 TIME 前缀也不关闭连接"); + CHECK(s_set_unix_calls == 0, "TC-TIMESYNC-023 非 TIME 前缀不更新墙钟"); + CHECK(s_close_calls == 0, "TC-TIMESYNC-023b 非 TIME 前缀也不关闭连接"); /* 5) 对端关闭(EOF) */ fakes_reset(); recv_set(0, 0, NULL, 0, 0U); s_recv_seq_n = 1; time_sync_handle_conn(6); - CHECK((s_set_unix_calls == 0) && (s_recv_calls == 1), "TC-TS-024 对端关闭(EOF)立即退出不解析"); - CHECK(s_close_calls == 0, "TC-TS-024b EOF 也不关闭连接(net 层 auto_relisten 收口监听)"); + CHECK((s_set_unix_calls == 0) && (s_recv_calls == 1), "TC-TIMESYNC-024 对端关闭(EOF)立即退出不解析"); + CHECK(s_close_calls == 0, "TC-TIMESYNC-024b EOF 也不关闭连接(net 层 auto_relisten 收口监听)"); /* 6) 真错误 */ fakes_reset(); recv_set(0, -1, NULL, 0, 0U); s_recv_seq_n = 1; time_sync_handle_conn(6); - CHECK((s_recv_calls == 1) && (s_set_unix_calls == 0), "TC-TS-025 真错误立即退出不解析"); + CHECK((s_recv_calls == 1) && (s_set_unix_calls == 0), "TC-TIMESYNC-025 真错误立即退出不解析"); /* 7) 4 字节后 EOF */ fakes_reset(); @@ -594,27 +594,27 @@ static void tc_handle_conn(void) { recv_set(1, 0, NULL, 0, 0U); s_recv_seq_n = 2; time_sync_handle_conn(6); - CHECK(s_set_unix_calls == 0, "TC-TS-026 不足 8 字节不解析"); - CHECK(s_recv_calls == 2, "TC-TS-026b 继续等待后续字节"); + CHECK(s_set_unix_calls == 0, "TC-TIMESYNC-026 不足 8 字节不解析"); + CHECK(s_recv_calls == 2, "TC-TIMESYNC-026b 继续等待后续字节"); /* 8) 30s 预算耗尽 */ fakes_reset(); recv_set(0, -2, NULL, 0, 30000U); s_recv_seq_n = 1; time_sync_handle_conn(6); - CHECK(s_recv_calls == 1, "TC-TS-027 预算耗尽后不再读(只读 1 次)"); - CHECK(g_tstest_info_count == 1, "TC-TS-027b 留痕 no TIME packet in 30s, drop conn"); - CHECK(s_close_calls == 0, "TC-TS-027c 预算耗尽也不关闭连接"); - CHECK(s_drop_calls == 1, "TC-TS-027d 预算耗尽主动拆会话(E-02 收口:net_drop_conn 拆连接保监听)"); + CHECK(s_recv_calls == 1, "TC-TIMESYNC-027 预算耗尽后不再读(只读 1 次)"); + CHECK(g_tstest_info_count == 1, "TC-TIMESYNC-027b 留痕 no TIME packet in 30s, drop conn"); + CHECK(s_close_calls == 0, "TC-TIMESYNC-027c 预算耗尽也不关闭连接"); + CHECK(s_drop_calls == 1, "TC-TIMESYNC-027d 预算耗尽主动拆会话(E-02 收口:net_drop_conn 拆连接保监听)"); /* 9) 剩余预算不足一片 */ fakes_reset(); recv_set(0, -2, NULL, 0, 29980U); s_recv_seq_n = 1; time_sync_handle_conn(6); - CHECK(s_recv_calls == 2, "TC-TS-028 两次等待后结束"); + CHECK(s_recv_calls == 2, "TC-TIMESYNC-028 两次等待后结束"); CHECK((s_recv_to_log[0] == 50U) && (s_recv_to_log[1] == 20U), - "TC-TS-028b 第二次片长 = 剩余 20ms"); + "TC-TIMESYNC-028b 第二次片长 = 剩余 20ms"); /* 10) 32 位 tick 回绕 */ fakes_reset(); @@ -623,10 +623,10 @@ static void tc_handle_conn(void) { s_recv_seq_n = 1; time_sync_handle_conn(6); CHECK((s_recv_calls == 2) && (s_recv_to_log[0] == 50U) && (s_recv_to_log[1] == 50U), - "TC-TS-029 32 位 tick 回绕后预算计算仍正确"); + "TC-TIMESYNC-029 32 位 tick 回绕后预算计算仍正确"); } -/* ===================== TC-TS-040..044:time_sync_task ===================== */ +/* ===================== TC-TIMESYNC-040..044:time_sync_task ===================== */ static void tc_task(void) { uint8_t pkt[16]; @@ -646,15 +646,15 @@ static void tc_task(void) { time_sync_task(NULL); } CHECK((s_wd_bind_calls == 1) && (s_wd_bind_id_bad == 0), - "TC-TS-040 任务入口登记心跳位(task_wd_bind 一次)"); - CHECK(s_evt_calls == 0, "TC-TS-040b sys_evtHandle==NULL 时跳过就绪屏障"); - CHECK(s_accept_calls == 3, "TC-TS-040c accept 轮询 3 次(2 次无连接 + 1 次成功)"); - CHECK((s_set_unix_calls == 1) && (s_set_unix_last == 9u), "TC-TS-040d 收到时间包并更新墙钟"); - CHECK(s_close_calls == 1, "TC-TS-040e 连接被关闭一次"); - CHECK(s_delay_calls == 9, "TC-TS-040f 延时片数 = 4+4+1(200+200+50ms)"); - CHECK(delays_all(50U, 9), "TC-TS-040g 所有延时均按 50ms 分片"); - CHECK(s_beat_calls == 13, "TC-TS-040h 心跳次数 = 主循环1 + 退避8 + 收连接1 + 收尾1 + 次轮1"); - CHECK(s_beat_id_bad == 0, "TC-TS-040i 所有心跳均打 TIMESYNC 位"); + "TC-TIMESYNC-040 任务入口登记心跳位(task_wd_bind 一次)"); + CHECK(s_evt_calls == 0, "TC-TIMESYNC-040b sys_evtHandle==NULL 时跳过就绪屏障"); + CHECK(s_accept_calls == 3, "TC-TIMESYNC-040c accept 轮询 3 次(2 次无连接 + 1 次成功)"); + CHECK((s_set_unix_calls == 1) && (s_set_unix_last == 9u), "TC-TIMESYNC-040d 收到时间包并更新墙钟"); + CHECK(s_close_calls == 1, "TC-TIMESYNC-040e 连接被关闭一次"); + CHECK(s_delay_calls == 9, "TC-TIMESYNC-040f 延时片数 = 4+4+1(200+200+50ms)"); + CHECK(delays_all(50U, 9), "TC-TIMESYNC-040g 所有延时均按 50ms 分片"); + CHECK(s_beat_calls == 13, "TC-TIMESYNC-040h 心跳次数 = 主循环1 + 退避8 + 收连接1 + 收尾1 + 次轮1"); + CHECK(s_beat_id_bad == 0, "TC-TIMESYNC-040i 所有心跳均打 TIMESYNC 位"); /* B) 就绪屏障:2 次未就绪 + 1 次就绪 */ fakes_reset(); @@ -667,12 +667,12 @@ static void tc_task(void) { if (setjmp(s_jmp) == 0) { time_sync_task(NULL); } - CHECK(s_evt_calls == 3, "TC-TS-041 就绪屏障轮询 3 次(2 次未就绪 + 1 次就绪)"); - CHECK(s_evt_last_timeout == 100U, "TC-TS-041b 屏障等待按 100ms 分片"); - CHECK(s_evt_last_flags == SYS_EVT_NET_READY, "TC-TS-041c 等待 NET_READY 位"); - CHECK(s_evt_last_options == (osFlagsWaitAny | osFlagsNoClear), "TC-TS-041d 就绪位不被消费"); - CHECK(s_beat_calls == 3, "TC-TS-041e 未就绪的两次各喂一次心跳(+主循环 1 次)"); - CHECK(s_wd_bind_calls == 1, "TC-TS-041f 仍先登记心跳路由"); + CHECK(s_evt_calls == 3, "TC-TIMESYNC-041 就绪屏障轮询 3 次(2 次未就绪 + 1 次就绪)"); + CHECK(s_evt_last_timeout == 100U, "TC-TIMESYNC-041b 屏障等待按 100ms 分片"); + CHECK(s_evt_last_flags == SYS_EVT_NET_READY, "TC-TIMESYNC-041c 等待 NET_READY 位"); + CHECK(s_evt_last_options == (osFlagsWaitAny | osFlagsNoClear), "TC-TIMESYNC-041d 就绪位不被消费"); + CHECK(s_beat_calls == 3, "TC-TIMESYNC-041e 未就绪的两次各喂一次心跳(+主循环 1 次)"); + CHECK(s_wd_bind_calls == 1, "TC-TIMESYNC-041f 仍先登记心跳路由"); /* C) 屏障期间持续喂心跳(就绪位长期不置位) */ fakes_reset(); @@ -682,8 +682,8 @@ static void tc_task(void) { if (setjmp(s_jmp) == 0) { time_sync_task(NULL); } - CHECK(s_evt_calls == 4, "TC-TS-042 屏障等待 4 次均未就绪(循环未挂死)"); - CHECK(s_beat_calls == 3, "TC-TS-042b 每次未就绪后各喂一次心跳(第 4 次跳出前)"); + CHECK(s_evt_calls == 4, "TC-TIMESYNC-042 屏障等待 4 次均未就绪(循环未挂死)"); + CHECK(s_beat_calls == 3, "TC-TIMESYNC-042b 每次未就绪后各喂一次心跳(第 4 次跳出前)"); /* D) 网络代次变化 -> 关闭旧监听并重监听 */ fakes_reset(); @@ -695,12 +695,12 @@ static void tc_task(void) { if (setjmp(s_jmp) == 0) { time_sync_task(NULL); } - CHECK((s_close_calls == 1) && (s_close_socks[0] == 5), "TC-TS-043 代次变化时关闭旧监听"); + CHECK((s_close_calls == 1) && (s_close_socks[0] == 5), "TC-TIMESYNC-043 代次变化时关闭旧监听"); /* INFO 三条:两次 open_listener 成功各一条 "TCP listen on" + 一条 "network re-init, relisten" */ - CHECK(g_tstest_info_count == 3, "TC-TS-043b 留痕 network re-init, relisten(另含 2 条 listen 成功)"); - CHECK(s_accept_calls == 2, "TC-TS-043c 每次循环只轮询一次 accept 即放弃"); + CHECK(g_tstest_info_count == 3, "TC-TIMESYNC-043b 留痕 network re-init, relisten(另含 2 条 listen 成功)"); + CHECK(s_accept_calls == 2, "TC-TIMESYNC-043c 每次循环只轮询一次 accept 即放弃"); CHECK((s_socket_calls == 2) && (s_bind_calls == 2) && (s_listen_calls == 2), - "TC-TS-043d 第二次循环重建了监听"); + "TC-TIMESYNC-043d 第二次循环重建了监听"); /* E) 监听建立失败 -> 5 次重试后放弃并退避 2000ms */ fakes_reset(); @@ -709,11 +709,11 @@ static void tc_task(void) { if (setjmp(s_jmp) == 0) { time_sync_task(NULL); } - CHECK(s_socket_calls == 5, "TC-TS-044 open_listener 内部重试 5 次后放弃"); - CHECK(g_tstest_err_count == 6, "TC-TS-044b 5 条 net_socket FAIL + 1 条 retry later"); - CHECK(s_delay_calls == 90, "TC-TS-044c 退避 5×500ms + 2000ms = 90 片"); - CHECK(s_beat_calls == 97, "TC-TS-044d 心跳次数 = 2 + 5 + 50 + 40"); - CHECK(s_beat_id_bad == 0, "TC-TS-044e 所有心跳均打 TIMESYNC 位"); + CHECK(s_socket_calls == 5, "TC-TIMESYNC-044 open_listener 内部重试 5 次后放弃"); + CHECK(g_tstest_err_count == 6, "TC-TIMESYNC-044b 5 条 net_socket FAIL + 1 条 retry later"); + CHECK(s_delay_calls == 90, "TC-TIMESYNC-044c 退避 5×500ms + 2000ms = 90 片"); + CHECK(s_beat_calls == 97, "TC-TIMESYNC-044d 心跳次数 = 2 + 5 + 50 + 40"); + CHECK(s_beat_id_bad == 0, "TC-TIMESYNC-044e 所有心跳均打 TIMESYNC 位"); } /* ===================== main ===================== */ diff --git a/test/host/vol_lock/vol_lock_test.c b/test/host/vol_lock/vol_lock_test.c index 5c48416d..d2f74c3a 100644 --- a/test/host/vol_lock/vol_lock_test.c +++ b/test/host/vol_lock/vol_lock_test.c @@ -16,20 +16,20 @@ * 3. 不占 MCU 的 RAM,毫秒级完成。 * * 覆盖点: - * TC-VL-001 init 首次调用创建互斥量并返回 0 - * TC-VL-002 init 幂等(重复调用不再创建) - * TC-VL-003 init 在 osMutexNew 失败时返回 -1 - * TC-VL-004 init 失败后可重试成功(s_lock 未被污染) - * TC-VL-005 wait 成功后返回 1,且把 timeout 原样透传给 osMutexWait - * TC-VL-006 wait 超时(osMutexWait != osOK)返回 0 - * TC-VL-007 wait 在锁未创建时自动 init,再正常获取 - * TC-VL-008 ⭐ fail-open:锁未创建且创建失败 -> 返回 1 且**不调用** osMutexWait - * TC-VL-009 fail-open 之后 release 无害(s_lock 仍为 NULL,不调用 osMutexRelease) - * TC-VL-010 已创建时 wait 不再调用 osMutexNew - * TC-VL-011 release 在已持锁时调用 osMutexRelease 一次 - * TC-VL-012 release 在锁未创建时静默返回(不崩溃、不调用) - * TC-VL-013 完整周期 init -> wait -> release -> wait -> release - * TC-VL-014 wait(0) 的 timeout 透传为 0(defaultTask 的 try 语义) + * TC-VOLLOCK-001 init 首次调用创建互斥量并返回 0 + * TC-VOLLOCK-002 init 幂等(重复调用不再创建) + * TC-VOLLOCK-003 init 在 osMutexNew 失败时返回 -1 + * TC-VOLLOCK-004 init 失败后可重试成功(s_lock 未被污染) + * TC-VOLLOCK-005 wait 成功后返回 1,且把 timeout 原样透传给 osMutexWait + * TC-VOLLOCK-006 wait 超时(osMutexWait != osOK)返回 0 + * TC-VOLLOCK-007 wait 在锁未创建时自动 init,再正常获取 + * TC-VOLLOCK-008 ⭐ fail-open:锁未创建且创建失败 -> 返回 1 且**不调用** osMutexWait + * TC-VOLLOCK-009 fail-open 之后 release 无害(s_lock 仍为 NULL,不调用 osMutexRelease) + * TC-VOLLOCK-010 已创建时 wait 不再调用 osMutexNew + * TC-VOLLOCK-011 release 在已持锁时调用 osMutexRelease 一次 + * TC-VOLLOCK-012 release 在锁未创建时静默返回(不崩溃、不调用) + * TC-VOLLOCK-013 完整周期 init -> wait -> release -> wait -> release + * TC-VOLLOCK-014 wait(0) 的 timeout 透传为 0(defaultTask 的 try 语义) * * 通过:全部 TC PASS(main 返回 0)。 * 入口:int main(void),返回 0=PASS / 1=FAIL(由 run 脚本判读)。 @@ -110,76 +110,76 @@ static void fakes_reset(void) { s_lock = NULL; } -/* ===================== TC-VL-001..004:vol_lock_init ===================== */ +/* ===================== TC-VOLLOCK-001..004:vol_lock_init ===================== */ static void tc_init(void) { fakes_reset(); - CHECK(vol_lock_init() == 0, "TC-VL-001 init 首次调用返回 0"); - CHECK(s_new_calls == 1, "TC-VL-001b init 创建互斥量一次(osMutexNew)"); - CHECK(s_lock != NULL, "TC-VL-001c 模块静态态已持有句柄"); + CHECK(vol_lock_init() == 0, "TC-VOLLOCK-001 init 首次调用返回 0"); + CHECK(s_new_calls == 1, "TC-VOLLOCK-001b init 创建互斥量一次(osMutexNew)"); + CHECK(s_lock != NULL, "TC-VOLLOCK-001c 模块静态态已持有句柄"); - CHECK(vol_lock_init() == 0, "TC-VL-002 init 重复调用仍返回 0(幂等)"); - CHECK(s_new_calls == 1, "TC-VL-002b 幂等:不再创建第二个互斥量"); + CHECK(vol_lock_init() == 0, "TC-VOLLOCK-002 init 重复调用仍返回 0(幂等)"); + CHECK(s_new_calls == 1, "TC-VOLLOCK-002b 幂等:不再创建第二个互斥量"); fakes_reset(); s_new_fail = 1; - CHECK(vol_lock_init() == -1, "TC-VL-003 osMutexNew 失败 -> init 返回 -1"); - CHECK(s_lock == NULL, "TC-VL-003b 失败时不留下半初始化句柄"); + CHECK(vol_lock_init() == -1, "TC-VOLLOCK-003 osMutexNew 失败 -> init 返回 -1"); + CHECK(s_lock == NULL, "TC-VOLLOCK-003b 失败时不留下半初始化句柄"); s_new_fail = 0; - CHECK(vol_lock_init() == 0, "TC-VL-004 失败后重试可成功(返回 0)"); - CHECK(s_new_calls == 2, "TC-VL-004b 重试确实再次调用 osMutexNew"); + CHECK(vol_lock_init() == 0, "TC-VOLLOCK-004 失败后重试可成功(返回 0)"); + CHECK(s_new_calls == 2, "TC-VOLLOCK-004b 重试确实再次调用 osMutexNew"); } -/* ===================== TC-VL-005..010:vol_lock_wait ===================== */ +/* ===================== TC-VOLLOCK-005..010:vol_lock_wait ===================== */ static void tc_wait(void) { /* --- 已创建:超时值原样透传 --- */ fakes_reset(); (void)vol_lock_init(); - CHECK(vol_lock_wait(100U) == 1, "TC-VL-005 wait 获取成功返回 1"); - CHECK(s_wait_calls == 1, "TC-VL-005b osMutexWait 被调用一次"); - CHECK(s_last_timeout == 100U, "TC-VL-005c timeout 原样透传给 osMutexWait"); + CHECK(vol_lock_wait(100U) == 1, "TC-VOLLOCK-005 wait 获取成功返回 1"); + CHECK(s_wait_calls == 1, "TC-VOLLOCK-005b osMutexWait 被调用一次"); + CHECK(s_last_timeout == 100U, "TC-VOLLOCK-005c timeout 原样透传给 osMutexWait"); fakes_reset(); (void)vol_lock_init(); - CHECK(vol_lock_wait(0U) == 1, "TC-VL-014 wait(0) 获取成功返回 1(try 语义)"); - CHECK(s_last_timeout == 0U, "TC-VL-014b wait(0) 的 timeout 透传为 0"); + CHECK(vol_lock_wait(0U) == 1, "TC-VOLLOCK-014 wait(0) 获取成功返回 1(try 语义)"); + CHECK(s_last_timeout == 0U, "TC-VOLLOCK-014b wait(0) 的 timeout 透传为 0"); /* --- 超时:osMutexWait != osOK -> 返回 0 --- */ fakes_reset(); (void)vol_lock_init(); s_wait_ok = 0; - CHECK(vol_lock_wait(50U) == 0, "TC-VL-006 osMutexWait 非 osOK -> wait 返回 0"); - CHECK(s_wait_calls == 1, "TC-VL-006b 超时路径确实尝试过等待"); + CHECK(vol_lock_wait(50U) == 0, "TC-VOLLOCK-006 osMutexWait 非 osOK -> wait 返回 0"); + CHECK(s_wait_calls == 1, "TC-VOLLOCK-006b 超时路径确实尝试过等待"); /* --- 锁未创建:自动 init 后正常获取 --- */ fakes_reset(); - CHECK(vol_lock_wait(10U) == 1, "TC-VL-007 锁未创建时 wait 自动 init 并获取"); - CHECK(s_new_calls == 1, "TC-VL-007b 自动 init 创建了互斥量"); - CHECK(s_wait_calls == 1, "TC-VL-007c 随后执行了一次等待"); + CHECK(vol_lock_wait(10U) == 1, "TC-VOLLOCK-007 锁未创建时 wait 自动 init 并获取"); + CHECK(s_new_calls == 1, "TC-VOLLOCK-007b 自动 init 创建了互斥量"); + CHECK(s_wait_calls == 1, "TC-VOLLOCK-007c 随后执行了一次等待"); /* --- ⭐ fail-open:创建失败必须返回 1 且绝不阻塞 --- */ fakes_reset(); s_new_fail = 1; - CHECK(vol_lock_wait(0U) == 1, "TC-VL-008 fail-open:锁创建失败仍返回 1(不阻塞喂狗点)"); - CHECK(s_wait_calls == 0, "TC-VL-008b fail-open 时**不调用** osMutexWait(零阻塞)"); - CHECK(s_lock == NULL, "TC-VL-008c fail-open 后仍无句柄"); + CHECK(vol_lock_wait(0U) == 1, "TC-VOLLOCK-008 fail-open:锁创建失败仍返回 1(不阻塞喂狗点)"); + CHECK(s_wait_calls == 0, "TC-VOLLOCK-008b fail-open 时**不调用** osMutexWait(零阻塞)"); + CHECK(s_lock == NULL, "TC-VOLLOCK-008c fail-open 后仍无句柄"); /* --- fail-open 之后 release 无害 --- */ vol_lock_release(); - CHECK(s_release_calls == 0, "TC-VL-009 fail-open 后 release 不调用 osMutexRelease(判空静默)"); + CHECK(s_release_calls == 0, "TC-VOLLOCK-009 fail-open 后 release 不调用 osMutexRelease(判空静默)"); /* --- 已创建时 wait 不再创建 --- */ fakes_reset(); (void)vol_lock_init(); (void)vol_lock_wait(0U); (void)vol_lock_wait(0U); - CHECK(s_new_calls == 1, "TC-VL-010 多次 wait 不重复创建互斥量"); - CHECK(s_wait_calls == 2, "TC-VL-010b 每次 wait 各等待一次"); + CHECK(s_new_calls == 1, "TC-VOLLOCK-010 多次 wait 不重复创建互斥量"); + CHECK(s_wait_calls == 2, "TC-VOLLOCK-010b 每次 wait 各等待一次"); } -/* ===================== TC-VL-011..013:vol_lock_release ===================== */ +/* ===================== TC-VOLLOCK-011..013:vol_lock_release ===================== */ static void tc_release(void) { /* --- 已持锁:释放一次 --- */ @@ -187,23 +187,23 @@ static void tc_release(void) { (void)vol_lock_init(); (void)vol_lock_wait(0U); vol_lock_release(); - CHECK(s_release_calls == 1, "TC-VL-011 已持锁时 release 调用 osMutexRelease 一次"); + CHECK(s_release_calls == 1, "TC-VOLLOCK-011 已持锁时 release 调用 osMutexRelease 一次"); /* --- 锁未创建:静默返回 --- */ fakes_reset(); vol_lock_release(); - CHECK(s_release_calls == 0, "TC-VL-012 锁未创建时 release 静默返回(不调用、不崩溃)"); + CHECK(s_release_calls == 0, "TC-VOLLOCK-012 锁未创建时 release 静默返回(不调用、不崩溃)"); /* --- 完整周期 --- */ fakes_reset(); - CHECK(vol_lock_init() == 0, "TC-VL-013 周期:init -> 0"); - CHECK(vol_lock_wait(0U) == 1, "TC-VL-013b 周期:wait -> 1"); + CHECK(vol_lock_init() == 0, "TC-VOLLOCK-013 周期:init -> 0"); + CHECK(vol_lock_wait(0U) == 1, "TC-VOLLOCK-013b 周期:wait -> 1"); vol_lock_release(); - CHECK(vol_lock_wait(100U) == 1, "TC-VL-013c 周期:再 wait -> 1(可重复获取)"); + CHECK(vol_lock_wait(100U) == 1, "TC-VOLLOCK-013c 周期:再 wait -> 1(可重复获取)"); vol_lock_release(); - CHECK(s_new_calls == 1, "TC-VL-013d 周期:全程只创建一次互斥量"); - CHECK(s_release_calls == 2, "TC-VL-013e 周期:释放两次"); - CHECK(s_last_timeout == 100U, "TC-VL-013f 周期:第二次 wait 的 timeout 透传正确"); + CHECK(s_new_calls == 1, "TC-VOLLOCK-013d 周期:全程只创建一次互斥量"); + CHECK(s_release_calls == 2, "TC-VOLLOCK-013e 周期:释放两次"); + CHECK(s_last_timeout == 100U, "TC-VOLLOCK-013f 周期:第二次 wait 的 timeout 透传正确"); } /* ===================== main ===================== */ diff --git a/test/host/watchdog/watchdog_test.c b/test/host/watchdog/watchdog_test.c index 4df4bd3a..5755408b 100644 --- a/test/host/watchdog/watchdog_test.c +++ b/test/host/watchdog/watchdog_test.c @@ -11,19 +11,19 @@ * 把模块静态态恢复到"刚上电"。 * * 覆盖点(对应 docs/测试说明/看门狗单元测试说明.md 的 TC-WD-xxx): - * TC-WD-001 未启动时 poll 不做任何判定(也不喂狗) - * TC-WD-002 节流:< 100ms 的 poll 直接返回 - * TC-WD-003 全员到位置位 → 喂狗一次,且位图取走清零 - * TC-WD-004 取走清零语义:旧位不残留(下一轮必须重新置位) - * TC-WD-005 掩码判定:缺任一位不喂,last_mask 精确记录 - * TC-WD-006 连续 1..7 次缺席不喂不报;第 8 次打 [WD] task stall - * TC-WD-007 停喂后 stall 日志持续复报(现状行为,见用例内说明) - * TC-WD-008 恢复:重新全员到位 → 喂狗 + streak 归零 - * TC-WD-009 节流窗口边界 99/100/199/200 - * TC-WD-010 tick 回绕安全(无符号差) - * TC-WD-011 观测接口:last_mask / is_armed - * TC-WD-013 非法任务 ID 被忽略(防位图越界) - * TC-WD-014 start 幂等 + * TC-WATCHDOG-001 未启动时 poll 不做任何判定(也不喂狗) + * TC-WATCHDOG-002 节流:< 100ms 的 poll 直接返回 + * TC-WATCHDOG-003 全员到位置位 → 喂狗一次,且位图取走清零 + * TC-WATCHDOG-004 取走清零语义:旧位不残留(下一轮必须重新置位) + * TC-WATCHDOG-005 掩码判定:缺任一位不喂,last_mask 精确记录 + * TC-WATCHDOG-006 连续 1..7 次缺席不喂不报;第 8 次打 [WD] task stall + * TC-WATCHDOG-007 停喂后 stall 日志持续复报(现状行为,见用例内说明) + * TC-WATCHDOG-008 恢复:重新全员到位 → 喂狗 + streak 归零 + * TC-WATCHDOG-009 节流窗口边界 99/100/199/200 + * TC-WATCHDOG-010 tick 回绕安全(无符号差) + * TC-WATCHDOG-011 观测接口:last_mask / is_armed + * TC-WATCHDOG-013 非法任务 ID 被忽略(防位图越界) + * TC-WATCHDOG-014 start 幂等 * * 通过:全部 TC PASS(main 返回 0)。 * 入口:int main(void),返回 0=PASS / 1=FAIL(由 run 脚本判读)。 @@ -108,7 +108,7 @@ static void poll_advance(uint32_t ms) { /* * 启动并清空喂狗计数:task_wd_start() 内部会先喂一次(让首个抽样窗口从启动 - * 时刻起算,见生产代码注释),该次喂狗由 TC-WD-015 单独断言;其余用例只关心 + * 时刻起算,见生产代码注释),该次喂狗由 TC-WATCHDOG-015 单独断言;其余用例只关心 * "启动之后 poll 的喂狗行为",故此处把计数归零。 */ static void start_and_clear(void) { @@ -131,7 +131,7 @@ static void beat_all(void) { /* ===================== 用例 ===================== */ static void tc_001_not_armed(void) { - printf("TC-WD-001 未启动时 poll 不做判定\n"); + printf("TC-WATCHDOG-001 未启动时 poll 不做判定\n"); beat_all(); poll_advance(1000); CHECK(s_feed_count == 0, "未启动时 poll 不喂狗"); @@ -139,7 +139,7 @@ static void tc_001_not_armed(void) { } static void tc_002_throttle(void) { - printf("TC-WD-002 节流:< 100ms 直接返回\n"); + printf("TC-WATCHDOG-002 节流:< 100ms 直接返回\n"); start_and_clear(); beat_all(); poll_advance(50); /* 50ms < 100ms → 不抽样 */ @@ -149,7 +149,7 @@ static void tc_002_throttle(void) { } static void tc_003_all_beat_feeds(void) { - printf("TC-WD-003 全员到位 → 喂狗一次\n"); + printf("TC-WATCHDOG-003 全员到位 → 喂狗一次\n"); start_and_clear(); beat_all(); poll_advance(100); @@ -158,7 +158,7 @@ static void tc_003_all_beat_feeds(void) { } static void tc_004_take_and_clear(void) { - printf("TC-WD-004 取走清零:旧位不残留\n"); + printf("TC-WATCHDOG-004 取走清零:旧位不残留\n"); start_and_clear(); beat_all(); poll_advance(100); /* 消费位图并喂狗 */ @@ -168,7 +168,7 @@ static void tc_004_take_and_clear(void) { } static void tc_005_mask_required(void) { - printf("TC-WD-005 掩码判定:缺任一位不喂\n"); + printf("TC-WATCHDOG-005 掩码判定:缺任一位不喂\n"); start_and_clear(); /* 故意缺 UI(bit4) */ task_wd_beat(TASK_WD_DEFAULT); @@ -185,7 +185,7 @@ static void tc_005_mask_required(void) { } static void tc_006_stall_8(void) { - printf("TC-WD-006 连续 8 次缺席 → 打 stall 并停喂\n"); + printf("TC-WATCHDOG-006 连续 8 次缺席 → 打 stall 并停喂\n"); start_and_clear(); beat_all(); poll_advance(100); /* streak 清零 */ int err0 = g_wdtest_err_count; @@ -199,7 +199,7 @@ static void tc_006_stall_8(void) { } static void tc_007_stall_repeats_until_reset(void) { - printf("TC-WD-007 停喂后 stall 日志持续复报(当前设计:每 100ms 一条)\n"); + printf("TC-WATCHDOG-007 停喂后 stall 日志持续复报(当前设计:每 100ms 一条)\n"); start_and_clear(); for (int i = 0; i < 8; i++) poll_advance(100); /* 第 8 次触发 */ int err8 = g_wdtest_err_count; @@ -217,7 +217,7 @@ static void tc_007_stall_repeats_until_reset(void) { } static void tc_008_recover(void) { - printf("TC-WD-008 恢复:重新全员到位 → 喂狗 + streak 归零\n"); + printf("TC-WATCHDOG-008 恢复:重新全员到位 → 喂狗 + streak 归零\n"); start_and_clear(); for (int i = 0; i < 8; i++) poll_advance(100); /* 触发 stall */ beat_all(); @@ -229,7 +229,7 @@ static void tc_008_recover(void) { } static void tc_009_throttle_boundary(void) { - printf("TC-WD-009 节流窗口边界 99/100/199/200\n"); + printf("TC-WATCHDOG-009 节流窗口边界 99/100/199/200\n"); start_and_clear(); beat_all(); poll_advance(99); CHECK(s_feed_count == 0, "99ms 不判"); @@ -240,7 +240,7 @@ static void tc_009_throttle_boundary(void) { } static void tc_010_tick_wrap(void) { - printf("TC-WD-010 tick 回绕安全\n"); + printf("TC-WATCHDOG-010 tick 回绕安全\n"); start_and_clear(); s_tick = 0xFFFFFF00u; /* 推到接近 2^32 回绕 */ task_wd_poll(); /* 建立基线(此处可能不判,取决节流) */ @@ -251,7 +251,7 @@ static void tc_010_tick_wrap(void) { } static void tc_011_observers(void) { - printf("TC-WD-011 观测接口语义\n"); + printf("TC-WATCHDOG-011 观测接口语义\n"); start_and_clear(); CHECK(task_wd_is_armed() == 1, "is_armed == 1(已启动)"); beat_all(); @@ -261,7 +261,7 @@ static void tc_011_observers(void) { } static void tc_013_bad_id(void) { - printf("TC-WD-013 非法任务 ID 被忽略\n"); + printf("TC-WATCHDOG-013 非法任务 ID 被忽略\n"); start_and_clear(); task_wd_beat((task_wd_id_t)(TASK_WD_ID_MAX + 3)); /* 非法:应被忽略 */ poll_advance(100); @@ -270,7 +270,7 @@ static void tc_013_bad_id(void) { } static void tc_014_start_idempotent(void) { - printf("TC-WD-014 start 幂等\n"); + printf("TC-WATCHDOG-014 start 幂等\n"); task_wd_start(); task_wd_start(); CHECK(s_start_count == 1, "重复 start 只启动 IWDG 一次"); @@ -278,14 +278,14 @@ static void tc_014_start_idempotent(void) { } static void tc_015_start_feeds_once(void) { - printf("TC-WD-015 start 先喂一次(首个窗口从启动时刻起算)\n"); + printf("TC-WATCHDOG-015 start 先喂一次(首个窗口从启动时刻起算)\n"); task_wd_start(); CHECK(s_start_count == 1, "start 启动 IWDG 一次"); CHECK(s_feed_count == 1, "start 内部先喂狗一次(避免启动即超时)"); } static void tc_016_stall_not_armed_no_feed(void) { - printf("TC-WD-016 未启动时即便全员到位也不喂\n"); + printf("TC-WATCHDOG-016 未启动时即便全员到位也不喂\n"); /* 未 start:poll 直接返回 */ beat_all(); poll_advance(500);