Commit Graph

16 Commits

Author SHA1 Message Date
wandering1 90db528032 W1 功能主线完成:内存台账三件套(W1-0) + IEC104 上行(B4) + protectTask 板端接线(B5)
W1-0 台账三件套:scripts/ram_baseline.py(四模式)+ ram_baseline.tsv 趋势 +
docs/内存管理/RAM预算台账.md + pre-commit mem-budget 钩子(RW_IRAM1/RW_CCM >92%
即 FAIL + Top-10 附表);审查报告 §5.5 三条闭环。

B4 IEC 60870-5-104 上行(被控站,TCP 2404):App/protocol/iec104/ 三模块
(asdu 编解码 / pts 点表+数据源 vtable / link APCI+FSM,纯逻辑零 I/O)+
App/task/iec104_serv.c(iec104Task,NET_READY 屏障 100ms 分片喂位)。
82 断言 L0.5 全绿 + iec104-unit-test 钩子(第 31 钩子);
设计说明 docs/子系统设计/IEC104上行设计说明.md 全量回填。

B5 protectTask(L3 板端接线):App/task/protect_task.c——20ms 判据节拍
prot_elm_run + L5-4 采样故障闭锁(adc_health 电平位→元件复位)+ L5-1 定值
校验和巡检;新增 prot_elm_request_reset() 收口跨上下文复归(104 YK11 落请求、
eval 头部消费);定值/元件初始化移入 app_main_init(内核前)。TC-PE-010
(prot_elm 28 用例)。

门禁与内存:TASK_WD_PROTECT=8 入 required_mask(产品 0x77→0x1F7、HW 层
0x1F5,看门狗单测 39 断言同步);FreeRTOS 堆 48→56KB(.ioc L1 参数 +
FreeRTOSConfig.h 同步,RAM预算台账 §6 登记配额 48→56KB)。
ZI 144,008→152,204(+8,196 B = 堆 +8KB,B5 扩容);Code=204,348。
stack_report:protectTask 512 words 静态链 872 B/余 57%、iec104Task
640 words 1456 B/余 43% 均 PASS;RW_IRAM1 73.1% / RW_CCM 87.9%(<92%)。

验证:@build 0 错 0 警;ci_local 全绿(31 钩子 + 13 主机侧单测);
doc-links 135 文档 PASS。登记簿 B4/B5 销项、W1 波次完成;保护规划/看门狗
说明/AGENTS(9 任务)/RAM 三文档全部同步。

遗留(验收窗口,非代码空洞):台架第三方 104 主站往返(送检窗口)、
标准源注入动作判据、@test PROT 锚点 + protect 栈水位 + 新堆 min_ever 复测。
2026-10-12 12:36:23 +08:00
wandering1 d1e6bb4ba7 W5波+N-19收口:FTP鉴权落地、Trap25三连定案修复(N-30)、N-20/N-23/N-26
N-19 FTP 鉴权:
- lftpd_auth(USER/PASS 状态机 + 连续5次失败锁60s)+ SHA-256
  (user||pwd) 口令哈希;config.ini [ftp] 段 user/pwd_hash/write,
  出厂 admin/admin 在用有启动告警;lftpd_log.c 删除并入 lftpd_auth
- ftp_cfg 配置读写;台架 ftp_auth_bench.py 13/13

N-30 / Trap 25(CH395F_Trap_Records.md 四次定案全记录):
- 修复1 closed-with-data accept:客户端发完正常 FIN 后芯片按
  FUN_PARA(0x09) §5.52② 保留 Socket+RX 缓冲,旧代码把 CLOSED 一律
  relisten 自毁缓冲 → STOR 必挂 425;改为接受"已关但可读"连接排空
- 修复2 丢 CONNECT 中断探针 net_lost_connect_probe + last_peer_port
  幽灵甄别(拆链窗口握手完成但中断丢失,双信源去抖补 accept)
- 修复3 send_list/send_nlst 批量单发:背靠背 ~60B 小段毒化芯片 TX
  (芯片报 SEND_OK 但对端全丢),整份目录一次性写入
- 证伪存档:固定沉降/Socket 轮换冷却/listen 门控(台架 v7 矩阵)
- 台架工具 test/board/ch395f_reuse_bench.{c,h} + host 脚本存档
  (不注册编译;实验分支 n30-chip-bench 保留)

N-20:Error_Handler 死循环降级(记录+复位路径)
N-23:scripts/check_registration.py 双端注册反向校验(pre-commit)
N-26:GD5F NAND 直 DMA 调用方缓冲窗口断言

验证:BUILD_OK 0/0;ftp_regression 连跑 4 轮 11/11(修复前
LIST#4/#7 100% 挂、STOR#2 曾 100% 425);ftp_auth_bench 13/13;
@test 启动标记 PASS;ci_local L0+L0.5 全过;doc-links 通过。
登记簿 N-30 已销项。
2026-10-11 18:50:24 +08:00
wandering1 9231a3c22c adcTask 事件驱动消费(P1-5 方案 a)+ 补 F4 ADC 上电自校准 + 修正 2 ms 忙等过期表述
P1-5 方案 a(事件驱动消费,Task #32):
- TIM6 1 kHz ISR 除触发 CONVST 外再调 adc_tick_irq_notify(),置位
  ADC_WAKE_FLAG;adcTask 循环尾改 osThreadFlagsWait(osWaitForever),
  删除 ADC_TASK_BEAT_MS 定时轮询
- adcTask 优先级 Normal(24) -> AboveNormal(32)(Src/freertos.c USER CODE 区)
- 补消费者就绪门(规划未预见):TIM6 在 app_main_init 就启动,比调度器
  早约 100 ms,未就绪时 ISR 不得 osThreadFlagsSet
- 实测 6 次上板:idle 由 1~649 降到 0/20000 拍,frames 1000.0 Hz,
  seq-frames=7 正是就绪窗口;UI 侧 uip/uiw/uis 无退化

补 STM32F4 ADC 上电自校准(此前项目从未做过):
- 核查证实裁剪版 HAL 无 HAL_ADCEx_Calibration_Start、裁剪版 CMSIS 头无
  ADC_CR2_CAL -> 按 RM0090 13.3.6 在 Src/adc.c 的 USER CODE 区手写
  adc1_calibrate(),MX_ADC1_Init() 末尾调用
- 新增 cubemx-survival 审计项 adc1-calibration-call / -impl(清单 21->23)
- 实测校准前后同一拍 STM32 侧 6 路同向偏移 +10~+63 LSB,TPAFE 侧不变

修正两处过期表述(实测反证):
- 原文 9 通道全超时最坏 = 18 ms 连占 有误:stm32_scan() 在首个超时处即
  Stop+return,单拍上界 = 一次超时约 2~3 ms
- adcm 约 2.1 ms 的峰值归因由 ADC 采集改判为每 10 s 一次的心跳日志;
  6 次对照 adcp = 122 us(无超时)/ 2209 us(超时 1 次)
- 同步修正 adc_task.c 两处过期注释;新发现超时拍 STM32 侧静默沿用
  上一拍值的正确性代价,硬化排序记入 4.4 / 10.4(未实施)

验证:@build 0 错 0 警(Code 256728 -> 256868);@test 6/6 PASS;
stack_report 7 任务全 PASS(adcTask 832 B / 余 59%);18 钩子全绿
2026-10-10 22:41:19 +08:00
wandering1 883c9dd0cc feat(adc): B1 实现 ADC 采集链路(adcTask + 看门狗)
B1(ADC 采集链路)落地,消化 P1-1:
- adc_task.c:空桩 -> 真实消费者。每 1ms 触发一次 CONVST,
  用 tpafe5160_snapshot() 原子取数(AGENTS 铁律)+ 帧统计 +
  每 10s 心跳日志。只取数,不做保护运算。
- Src/freertos.c:手工创建 adcTask(512 words / Normal,落
  USER CODE 保护区,同 timeSyncTask 先例)。
- task_watchdog:新增 TASK_WD_ADC;required_mask 产品 0x37 ->
  0x77、ENABLE_HW_LAYER_TESTS 0x35 -> 0x75。
- default_task.c:栈水位探针增列 adcTask(extern + 表项)。
- 脚本:stack_report.py 增 ROOTS/RUNTIME_ALIAS;gen_task_table
  增 adcTask(README/AGENTS 任务表已 --write)。
- 单测:watchdog_test.c beat_all/掩码断言同步(39 断言全绿)。
- 文档:待处理内容/看门狗设计/RAM 方案/继保规划 同步。

验证:@build 0 错 0 警;stack_report 静态最坏链 504B(余 75%);
pre-commit 全绿。剩 @test 实机闭环。
2026-10-10 14:33:32 +08:00
wandering1 0779d3a075 栈整改不抬栈:删旧档迁移、FIL静态化、日志行缓冲按模块收紧、钩子脱离HAL,defaultTask链5312→2776B 2026-10-10 10:17:00 +08:00
wandering1 29df7bf8fb 4 个 Fault Handler 迁入 USER CODE BEGIN 0(L3→L2):生成区恢复 CubeMX 原样,重生成零 diff
CI / L0 静态门禁 (pre-commit) (push) Has been cancelled
CI / L0.5 主机侧单测 (MSVC) (push) Has been cancelled
2026-10-10 02:02:58 +08:00
wandering1 e2e1d0fd42 IWDG 延后启动改走宏改名(L3→L2):生成调用变空操作,重生成后不再需要手工删 2026-10-10 01:30:47 +08:00
wandering1 5eed2151de CubeMX 生成 ADC1(9 通道)+ 复原重生成定制,FreeRTOS 加固迁 L1、钩子落 USER CODE 4/5,门禁豁免生成文件空白改写 2026-10-10 00:53:20 +08:00
wandering1 ed463716f6 netTask 栈 1024→960:按静态最坏链核算并同步 .ioc/README/审计基线
静态最坏链 2664B(日志主导:链上 5 帧各含 192B __con_line + 尾部 696B)
3840B 配置下余量 1176B(30.6%),过 stack_report 规则
net_drain_chip_rx scratch 静态化实测仅省 16B 栈、反增 256B BSS,已回退
.ioc FREERTOS.Tasks01 同步 960(L1 记账,重生成不丢)
2026-10-09 17:14:52 +08:00
wandering1 029437be89 台架执行《实机测试实施指南》步骤 3~7 并闭环
步骤 3/4(IWDG V2/V4/V5 + 堆低水位 S11):
- V2 任务饿死 stall 后 ≤2.5s IWDG 复位;V4 关中断死循环 ~4.9s 稳定复位;
  V5 30min 120×FTP 全 PASS、零 IWDG 复位。堆告警全程未触发(min_ever=4728B)。
- task_watchdog.c:stall 证据写盘会经 nand_ftl_wd_feed 喂狗 → 增 s_stall_evidenced
  每次 stall 仅取一次证据,避免"取证据"本身阻止复位。
- default_task.c:堆低水位告警(HEAP_LOW_WATER_B=3072)。

步骤 5(GD5F 错误通道 S9):gd5f2gq5ue.c/.h + nand_ftl.c 错误码统一为 int32_t 并
全量检查返回值;套件回归 16/16 PASSED。
- test/run_all_suites.py:--forbidden 改为按套件覆盖(GD5F 用 "HardFault;assert")——
  TC-GD5F-704 故意触发 [ERR] 回落轮询,统一默认值会误判 FAIL。

步骤 6(网络稳定性):7.1 正常路径 ✅(V5 证据);7.2 N-2 丢弃可观测性代码已具备、
49s 静默在 V5 未复现(降级低风险观察项);7.3 N-3 待 PC peer。

步骤 7(工程卫生):
- S5:新增 test-cppcheck 钩子(仅 warning,排除模拟器桩)。
- S4:新增 scripts/check_test_traceability.py(默认仅告警)。
- 待核实项 TEST_SUITE_SELECTED 实机核实 = 死代码(无使用点);RTC 套件实际正常执行,
  真缺口 = 缺套件级汇总行 → sd2506_test_task.c 补 === RTC Tests: N/M PASSED === 并
  修正 Phase 级汇总累计问题;test_config.h 补齐 RTC 并注释"当前无引用"。

验证:产品 @build 0/0;pre-commit --all-files 17/17 Passed;
run_all_suites.py --suites RTC → PASS。
文档:实机测试实施指南 / SD2506_Test_Guide / 待处理内容 / 测试与架构改进建议 同步。
2026-10-04 00:35:06 +08:00
wandering1 3cc08f5d53 实机测试规划改造为执行判据说明:删除一次性台架窗口状态(§0.5取证记录)与规划框架,A1~A4代码状态按代码核对改写,16处外部引用重指向模块文档 2026-10-02 23:46:27 +08:00
wandering1 930215f81a 修复IWDG超时未配置与dhara resume回滚:看门狗误复位与复位后写入全部丢失,台架全量自检PASS 2026-10-02 20:48:30 +08:00
wandering1 73941da6b1 看门狗判定状态机增加主机侧单元测试(L0.5 层)
为 task_watchdog.c 的判定逻辑(位图取走清零 / 必需掩码 0x37 判定 /
miss_streak 连续 8 次停喂 / 100ms 抽样节流 / tick 回绕安全)补一层
主机侧纯逻辑单元测试,弥补此前只能靠真机或模拟器才能发现回归的空白。

架构(沿用项目既有"共享核心 + 平台后端"做法,参照 cfg_file_store):
- task_watchdog.h 末段新增"平台后端(内部)"声明 3 个钩子
  (wd_platform_feed / _start / _tick_ms),MCU 端以 __weak 提供默认实现,
  行为与重构前逐字一致(@build 0 错误 0 警告,Flash +20B)。
- 主机侧单测以同名强符号覆盖三钩子,即可离线注入/观测,无需碰 MCU 代码。
- 测试文件 #include 生产源文件本身,保证测的是真代码而非副本。
- 测试专用复位 task_wd_test_reset() 仅 TASK_WATCHDOG_UNIT_TEST 下编入,
  MCU 构建零代码零符号。

测试(test/host/watchdog/,MSVC 离线编译,纯标准库驱动):
- 39 项断言全过(退出码 0);注入故障可复现退出码 1。
- run_unit_test.py 直接拼 INCLUDE/LIB 调 cl.exe,绕开本机被禁的 reg.exe。
- stub/ 三桩头覆盖 main.h / iwdg.h / dbg_log.h。

门禁:pre-commit 新增 watchdog-unit-test 本地钩子(L0.5 层),仅被测文件
或其测试变动时触发;测试开发标准流程.md 新增 L0.5 层说明。

顺带改善:task_watchdog.c 的节流基线 s_last_tick 由函数内 static 提为文件
static(可测性 + 模块状态归一)。
2026-10-01 06:57:01 +08:00
wandering1 8a18e388c7 四个 Fault 全部采集现场:MemManage/BusFault/UsageFault 由空死循环升级
原状:HardFault 已有崩溃采集,但 MemManage / BusFault / UsageFault 仍是空
while(1) —— 这三类故障发生时日志完全静默,且因 SHCSR 默认未使能,实际会
被升级成 HardFault,报告出笼统的 "HARDFAULT"、看不出根因。

改动:

- Src/stm32f4xx_it.c:三个 Handler 升级为手工 __asm 版(取 MSP/PSP 帧指针)
  -> B 到 per-fault C 入口 fault_entry_{mem,bus,usage} -> hard_fault_report()。
  hard_fault_report 增加 tag 参数,日志统一为
  "[ERR] <TAG> PC=.. LR=.. xPSR=.. R0-R3=.. CFSR=.. HFSR=..[/BFAR][/MMFAR]"。
  生成实体经 #define X X_Gen 改名保留,链接器各移除 2 字节(.map 已验)。
  三个各带独立锚点 MEMFAULT/BUSFAULT/USAGEFAULT-ANCHOR。
- 新增 fault_handler_enable()(USER CODE BEGIN 1 区):使能 SHCSR 的
  MEMFAULTENA/BUSFAULTENA/USGFAULTENA。声明入 Inc/stm32f4xx_it.h,调用在
  app_main_init() 第一行(纯寄存器写,不依赖日志/时钟)。
- 刻意不启用 CCR.UNALIGN_TRP / CCR.DIV_0_TRP:会把普通 bug 升级成死机,
  对本项目弊大于利(说明写进函数注释)。

实现约束(本轮踩坑):ARMCC 的 __asm 块取不到 C 的数据符号(ADR r1, xxx_tag
报 A1516E: Bad symbol,去 static 也无效),也无法给 C 函数传字符串参数,
故故障名必须由 C 侧 per-fault 入口带上。

配套:

- check_cubemx_survival.py:新增 fault-handlers-3 / fault-handler-enable 两项,
  UNPROTECTED_LEGACY 清掉三个 Fault(WARN 2->1),清单 16 -> 18 项。
- AGENTS.md:新增"4 个 Fault 全部采集"条目;ARMCC 汇编条目补 A1516E 第 3 坑;
  校验标记补 [ERR](四个 Fault 日志都以它开头 -> 一律判 FAIL,刻意)。
- 看门狗设计说明.md:§6.1 补 4 条 Fault 标记与 @test 禁项关系;
  §10.2 L3 清单与四个 Fault 采集小节;§11 结论表与变更记录。
- 待处理内容.md:新增 N-03d(已完成),N-03c 补第二次重生成结论。

验证:@build 0 错误 0 警告(Flash +156 B,RAM 无变化);pre-commit 13 钩子
全通过;审计 18 通过 / 1 警告 / 0 失败。
2026-09-29 09:16:19 +08:00
wandering1 67d26ac37a 修正 CubeMX 重生成防丢失机制:审计脚本实测有效,恢复 5 处被覆盖定制
第二次重生成验证了审计机制,并证伪了上一轮的一处假设:

- 审计脚本 check_cubemx_survival.py 准确检出全部 5 处覆盖(16 项中 5 FAIL),
  机制有效;Src/main.c 复位原因锁存(USER CODE BEGIN Init 区)完好,
  是"USER CODE 区有效"的正向证据。
- 关键发现:CubeMX 本次换了一代中断函数模板(旧 HardFault_Handler /
  HardFault_Report 自造区 → 新函数体内 HardFault_IRQn 0 / W1_HardFault_IRQn 0),
  "生成区之外的自造标记区"同样不被保留,旧假设被证伪。

恢复方案(第二次升级):

- stm32f4xx_it.c:报告实现迁入 USER CODE BEGIN 0(区名从未变过的标准保护位);
  Handler 本体改为生成区整函数替换,用 #define HardFault_Handler
  HardFault_Handler_Gen 把生成实体改名保留,链接器自动移除(.map 实证
  Removing ... (2 bytes)),向量表指向手工 __asm 版(0x080001a1,18 字节)。
- iwdg.c:去掉 HAL_IWDG_Init() 调用,补 IWDG-DEFER-START-ANCHOR 锚点注释。
- FreeRTOSConfig.h:恢复 FREE_RTOS_CONFIG_HARDENING 块(两个加固宏)。
- freertos.c:补回两处任务栈中文注释(栈值未丢,.ioc 已同步)。

配套:

- check_cubemx_survival.py:hardfault-handler 改 wholefile + 锚点检查;
  UNPROTECTED_LEGACY 清单更新。
- AGENTS.md:新增"CubeMX 换模板"与"ARMCC 内联汇编语法"两条铁律,
  以及"uvprojx 被 Keil 自动改写不入库"条目。
- 看门狗设计说明.md:§10.1 补第二次重生成验证结论与模板换代发现,
  §10.2 L2/L3 全面改写(自造区名不可依赖)。

验证:@build 0 错误 0 警告;pre-commit 13 钩子全通过;审计 16 通过 / 2 警告 / 0 失败。
2026-09-29 07:52:39 +08:00
wandering1 7a18d2ce28 加 CubeMX 重生成存活审计:防标记区外定制被静默覆盖
背景:.ioc 的 KeepUserCode 只保护 USER CODE 标记区,标记之外的手工改动
重生成即被覆盖,且多数不报编译错(2026-09-29 实测一次覆盖 4 处,含
HardFault_Handler 崩溃采集被打回空 while(1)、两个 FreeRTOS 加固宏被删)。

新增 scripts/check_cubemx_survival.py:
- 16 项易失清单(IWDG 延后启动 / 崩溃采集 / 栈溢出检测 / 堆失败钩子 /
  断言改造 / 看门狗模块与工程挂载 / 复位原因锁存 / HAL 驱动与使能 /
  .ioc 关键项),断言前剥掉 C 注释防误报
- 哈希基线漂移检测(.cubemx_survival_baseline.json),--write 重建
- 标记区外存量以 WARN 提示(3 个 Fault 处理函数、栈注释)

已挂 pre-commit cubemx-survival 钩子(改动 .ioc / Src / Inc /
task_watchdog / .uvprojx 时触发)。

文档:看门狗设计说明 §10.2 新增"重生成不丢的三层手段"方法论
(L1 写 .ioc > L2 搬进 USER CODE 区(可自造标记区)> L3 审计兜底)
及 .ioc / USER CODE 区可用位置 / 存量清单三张对照表;AGENTS.md 平台约束
新增该规则;pre-commit 使用说明 §2.12 新增钩子详解。

门禁:build 0 错误 0 警告;pre-commit 全通过。
2026-09-29 07:30:00 +08:00