1d4b6a17ce
台架一手证据(boot_log_data/20261026_prod_console_interleave_evidence.txt):两次 「仅复位不重烧」启动里,[PROT] 未标定 INFO 行内分别多出 3 个和 1 个字节,而紧邻其后 的 [NAND_FTL] 行正好缺自己行首同样数量的字节("[20" 与 "[")——串口 framing 错不会 让行变长,字节按原序出现在邻居里 ⇒ 两个写者并发逐字节写 USART1->DR。写者对: protectTask 的未标定闭锁边沿 × defaultTask 的 storage_bring_up(),两者都落在 dbg_console_writer_attach() 之前(attach 排在存储 bring-up 之后),该窗口 s_con_writer_up == 0 ⇒ 任何任务的整行都走零互斥裸发。这是控制台单写者设计说明在册 O1 的**第二个实例**;2026-10-12 那次只补了"自愿门控",而自愿门控挡不住业务边沿留痕 (业务无法预知某条边沿落在哪个窗口),所以这次被同一窗口第二次咬到。 修法是**非阻塞整行独占**:con_tx_try_claim/release 只在几条指令的临界区里 test-and-set,绝不把 7.8 ms 的逐字节发送包进关中断区、绝不等待;IPSR 上下文与调度 器未启动两种情况显式放行(崩溃遗言必须能出去;早期本就单执行流,一条不丢);同任务 按深度嵌套。抢不到独占的那条行**原文入环**延后发——前缀与时间戳在 DBG_* 调用点就 格式化进调用方缓冲,本模块与 drain 都不补前缀、不重打时间戳,所以延后发出的行与当场 直发逐字节相同;[ERR] 只在「抢不到独占且环也放不下」时才红,按 3 次启动命中 2 次的 频率,让路若计 [ERR] 就会把静默缺陷换成常红门禁。顺带堵掉第二处洞:drain 每轮先取 凭证,拿不到就让位且 tail 不推进(旧写法 attach 可以撞上别人已发出的半行)。 新导出 dbg_console_tx_begin()/tx_end() 供 task-26 收口故障钩子的多段裸发。 否决过的两条路写进文档 §4.4.1:提前 attach 会把等串口塞进 mount/mkfs 时序敏感段 或让生产者在整个 bring-up 里堵在满环上;整段进环会让「无看门狗窗口」死机时一个字都 不出(2026-10-02 那几轮正是靠 bring-up 期流式日志取证的)。 判据:test/host/console_log 127 → 152 全绿(M 族 TC-CONLOG-170..179 共 +25,既有 127 条零删除)。唯一换钉法的是 TC-CONLOG-015——旧断言钉的正是缺陷机理本身(裸发 0 次临界区 = 零互斥),现改钉「恰 2 次几条指令的临界区 + 每个上线字节都在临界区之外 + 零等待」;硬红线由假 USART 在每个上线字节处记录临界区深度水位恒 0 来机器守住。四处 注入反证各自转红 11 / 5 / 1 / 3 条并逐字节还原复跑;覆盖率 console_log.c 199/200 行 → 256/257 行、16/16 → 21/21 函数。邻域复跑:task_prof 27/27、sys_log_mcu 137/137、 iec104_serv 37/37。CONLOG 游标抬到 179。 台架复验判据(**本笔尚未上机**,下一轮请台架跑):连续 3~5 次「仅复位不重烧」启动 日志 [ERR] 零命中,且 [PROT] 未标定与 [NAND_FTL] Initializing 两行都完整。 成本:.bss +5 B、Flash 估 +100~150 B,零新增 DBG_* / 零新增缓冲 / 零堆 / 零内核对象。 文档:控制台单写者日志设计说明.md 升 v1.6(O1 改「已处置」含两实例与字节账、新增 §4.4.1、§3.4 并发区间、§4.4 取消「不加锁」口径、§7 失效表、§11 变更记录、API 表)。
test/ — 测试代码与主机端脚本
测试分两部分,物理隔离在两个子目录:
board/—— 板端测试套件(.c/.h,编入固件由 testTask 执行)host/—— 主机端脚本(.py,PC 侧驱动板子并判读结果)
目录结构
| 目录 | 内容 | README |
|---|---|---|
board/ |
板端测试套件(编入 Keil 工程,占 RAM) | board/README.md |
host/ |
PC 端测试/判读脚本(Python) | host/README.md |
run_all_suites.py |
多套件回归编排(改宏 → 构建 → 烧录 → 采集,try/finally 保证还原开关);--check-build = 只编译不烧录(纯离机) |
本文 §多套件回归 |
运行方式
# @test 一键闭环(推荐)
& '.venv\Scripts\python.exe' .dsh/skills/serial-boot-test/scripts/run_boot_test.py
# 单独校验日志
& '.venv\Scripts\python.exe' .dsh/skills/serial-boot-test/scripts/verify_log.py <日志文件>
# 多套件回归编排(需真机;自动改开关 + 构建 + 烧录 + 采集,结束后还原)
& '.venv\Scripts\python.exe' test/run_all_suites.py
& '.venv\Scripts\python.exe' test/run_all_suites.py --suites STORAGE,GD5F
& '.venv\Scripts\python.exe' test/run_all_suites.py --dry-run # 只看计划
# 只编译不烧录(不需要 MCU / 串口 / ST-LINK,验证 4 套件可编译性)
& '.venv\Scripts\python.exe' test/run_all_suites.py --check-build
退出码约定:0=PASS / 1=FAIL / 2=采集或烧录错误 / 3=用法或预检错误。
多套件回归(run_all_suites.py)
套件互斥(编译期 #error)意味着跑 4 个套件要手工循环 4 轮。本脚本把它编排成一条
命令,并且无条件还原 test_config.h——跑完忘还原 = 测试固件进库,这是它存在的
核心理由(与提交期门禁 test-suite-switch 互为独立防线)。
⚠️ 每轮要真机烧录 + 采集,4 套件约数分钟起;破坏性套件还会改设备持久状态。 仅回归窗口用,绝不挂 pre-commit。
--check-build 则相反:只改宏 + @build,不烧录不采集,无需任何硬件,用于防止
"测试套件长期编不过而无人知"(2026-08~09 CH395F 套件实例)。改动 test/board/ 下测试
代码后建议先跑它——实测 4 套件均 BUILD_OK: 0 errors, 0 warnings。
⚠️ 注意
- 本目录被 pre-commit 门禁排除(测试代码不受 C 规范约束)
board/套件占用 RAM,启用前先核算预算(见docs/内存管理/)- Keil 工程已同步:
board/下 7 个.c编入MDK-ARM/STM32F4-Demo.uvprojx, IncludePath 含../test/board;移动文件须同步改工程文件 - 套件选择开关:
board/test_config.h的TEST_SUITE_*(互斥,一次只启用一个) - 测试缓冲用分 Phase 复用静态缓冲(避免
L6406E溢出)
相关文档
docs/测试说明/测试开发标准流程.md— L0~L3 分层与门禁决策表docs/测试说明/自动化测试流程.md—@test细节与失败模式- 各模块测试指南:
docs/测试说明/*_Test_Guide.md docs/测试说明/链路延迟测试说明.md