From 60a650c175492e2c079bfe63bb10b101e8b2ac3e Mon Sep 17 00:00:00 2001 From: Wanderingss <1624155937@qq.com> Date: Wed, 21 Oct 2026 22:59:55 +0800 Subject: [PATCH] =?UTF-8?q?fix(adc=5Ftask):=20=E6=8E=A5=E4=B8=8A=E4=BB=8E?= =?UTF-8?q?=E6=9C=AA=E8=A2=AB=E8=B0=83=E7=94=A8=E7=9A=84=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E5=85=A5=E5=8F=A3=EF=BC=88=E5=90=AB?= =?UTF-8?q?=E5=88=A4=E5=AE=9A=E5=B1=82=E5=8F=82=E7=85=A7=E7=B3=BB=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题:adc_task_func 函数头写「限定条件:adc_task_init() 已调用」,但 adc_task_init() 全库无调用点;同类空壳 net_task_init()(体内只有一条 DBG_INFO,函数头却写「创建 TCP Server 监听 Socket」)同样无人调用。 判定层为什么今天还没坏:状态全在 .bss(复位即 0),且 adc_health 的 首拍只建基线、不判定,所以漏调 init 只是「少清一次」。但假契约会让 下一个接手者照它推理,故必须修在成灾之前。 改动: - adc_task_func 进入循环之前(开闸 s_consumer_ready 之前)自己调用 adc_task_init(),不依赖外部接线;init 与首拍之间无抢占窗口 - adc_task_init() 去掉 DBG_INFO 并在函数头标注禁止加日志:它落在 adcTask 静态最坏调用链上,每条 DBG_* 约 216 B 栈,而这条启动行 无诊断价值(存活由首帧日志与 TASK_WD_ADC 心跳证明) - 删除 net_task.c/.h 里的空壳 net_task_init()(声明 + 定义 + 误述) - docs/算法/采样有效性校验设计说明.md §14 与变更记录同步改写: 原来登记的「init 不在产品路径」事实已修复,不留过时结论 实测(任务工作树 adc-health,构建 + 静态分析): - @build 0 错 0 警;Code 213356 → 213424(+68 B) - RW-data 1184 / ZI-data 131480 逐字节不变 ⇒ RAM 零增量 - stack_report:adcTask 静态最坏链 1320 B → 1320 B 不变, 余 1240 B / 48% 仍 PASS(netTask 1912 B、protectTask 872 B 不变) - ADC 有效性单测 31/31 通过(钩子按 adc_task.c 自动触发) - 字节卫生自查:BOM 无 / CR 0 / U+FFFD 0,字符串字面量纯 ASCII (中文只在注释里),新增行无非 ASCII 字面量 gate: only mem-budget/mem-numbers pending lead ledger backfill pre-commit run --all-files = 33 Passed / 2 Failed,失败仅这两条, 均为台账受管区与本树 .map 的 Flash 差异(233,120 → 233,188,即本次 +68 B);RW_IRAM1 75,240 与 RW_CCM 57,376 与台账完全一致。按并行 分支约定本分支不跑 --write,台账由 Lead 合并后统一回填。 另记一处门禁缺口(非本次引入):ui-golden 的黄金参考 simulator/ tests/ref/ 被 .gitignore 排除、从未入库,新工作树里必然失败;本树 用 check_content_pages.py --update 生成 11 页基线后 ui-golden Passed (即本次改动对 UI 像素中性)。是否让基线入库待裁。 --- App/task/adc_task.c | 21 ++++++++++++++++++--- App/task/net_task.c | 16 ++++------------ App/task/net_task.h | 2 +- docs/算法/采样有效性校验设计说明.md | 15 +++++++++++---- 4 files changed, 34 insertions(+), 20 deletions(-) diff --git a/App/task/adc_task.c b/App/task/adc_task.c index c462ca6f..6917bc65 100644 --- a/App/task/adc_task.c +++ b/App/task/adc_task.c @@ -77,6 +77,13 @@ * 恢复打 DBG_INFO;心跳日志增 tgap(TPAFE 侧丢帧, * 与 adc1_gap 对称)。判定不在本文件(A-4:算法与 * I/O 分离),本文件只做"消费计数 → 告警"的编排 + * v3.0 2026-10-21 王建锋 修复"任务初始化入口从未被调用":adc_task_func 进入 + * 循环之前先调 adc_task_init()。原实现下判定层状态靠 + * .bss 清零 + 首拍建基线兜住,功能没错,但函数头写的 + * "限定条件:adc_task_init() 已调用"是假的,会误导后来 + * 者;该入口同时不再打日志——它落在本任务静态最坏链上, + * 每条 DBG_* 约 216 B 栈,而这一行毫无诊断价值(本任务 + * 存活由首帧日志与 TASK_WD_ADC 心跳证明) */ #include "adc_task.h" @@ -230,14 +237,17 @@ static void adc_health_report(const adc_health_status_t *hs) { * 入口参数:无 * 返 回 值:0 - 成功,-1 - 失败 * 限定条件:tpafe5160_init() 已在 app_main_init()(内核启动前)完成 - * 函数说明:驱动初始化不在本任务(见限定条件);此处仅清帧统计。 + * 函数说明:驱动初始化不在本任务(见限定条件);此处清帧统计 + 清判定层参照系 + * (adc_health_init())。由 adc_task_func 进入循环之前调用一次;幂等, + * 可重复调用(运行期要重建判定参照系,走的也是这里)。 + * ⚠ 本函数内禁止加日志:它在 adcTask 的静态最坏调用链上,每条 DBG_* + * 约 216 B 栈,而本任务栈余量按 1024 B ISR 底线核算。 */ int adc_task_init(void) { s_frames_consumed = 0u; s_frames_idle = 0u; s_frames_skip = 0u; adc_health_init(); - DBG_INFO("adc_task_init"); return 0; } @@ -245,7 +255,8 @@ int adc_task_init(void) { * 函数功能:ADC 任务主函数 * 入口参数:arg - FreeRTOS 传入参数(未使用) * 返 回 值:无 - * 限定条件:adc_task_init() 已调用;内核已启动 + * 限定条件:内核已启动。本函数自己在进入循环前调 adc_task_init()——不依赖外部 + * 调用(历史上该入口全库无调用点,判定层状态只靠 .bss 清零兜住) * 函数说明:每拍采集一次(adc_input_poll():TPAFE 原子快照 + 消费一帧 STM32 ADC1 DMA 乒乓缓冲) * 并统计。采样节拍由 TIM3 硬件定时器提供(ISR 内触发 CONVST),本任务不再触发; * **本任务的唤醒同样由该 TIM3 ISR 置位 ADC_WAKE_FLAG 驱动**(事件驱动, @@ -261,6 +272,10 @@ void adc_task_func(void *arg) { (void)arg; + /* 任务自有状态清零(含判定层参照系)。放在开闸之前:此刻 ISR 还不会唤醒 + * 本任务,init 与首拍之间不存在"用半初始化状态做判定"的窗口 */ + (void)adc_task_init(); + /* 开闸:此刻任务已存在、调度器必已运行 → ISR 的唤醒从此生效。 * 放在进入循环之前:置位与等待之间不会漏唤醒(线程标志粘滞) */ s_consumer_ready = 1u; diff --git a/App/task/net_task.c b/App/task/net_task.c index 154e33dc..7d093f06 100644 --- a/App/task/net_task.c +++ b/App/task/net_task.c @@ -21,6 +21,10 @@ * v1.8 2026-10-10 王建锋 任务耗时测量埋点:net_poll() 单独计时—— * 本任务每 ~1ms 分派一次消息队列,若驱动轮询被拉长, * 其它任务(尤其 UI 的 net_accept 往返)的等待随之拉长 + * v1.9 2026-10-21 王建锋 删除 net_task_init():空壳入口(体内只有一条 + * DBG_INFO),全库无调用点,而函数头却写"创建 TCP + * Server 监听 Socket,注册回调等"——描述与实际不符, + * 监听实际在 net_stack_bring_up() 与各服务里做 */ #include @@ -145,18 +149,6 @@ int net_stack_bring_up(void) { return 0; } -/* - * 函数功能:网络任务初始化 - * 入口参数:无 - * 返 回 值:0 - 成功,-1 - 失败 - * 限定条件:CH395F 协议栈已初始化 - * 函数说明:创建 TCP Server 监听 Socket,注册回调等 - */ -int net_task_init(void) { - DBG_INFO("net_task_init"); - return 0; -} - /* * 函数功能:网络任务主函数 * 入口参数:arg - FreeRTOS 传入参数(未使用) diff --git a/App/task/net_task.h b/App/task/net_task.h index ef36fb26..98e75e88 100644 --- a/App/task/net_task.h +++ b/App/task/net_task.h @@ -9,6 +9,7 @@ * v1.1 2026-08-24 王建锋 提取 net_stack_bring_up() 供硬件层/NET 层两种测试模式共用 * v1.2 2026-09-15 王建锋 硬件层模式描述修正:netTask 恒创建(基础线程), * 该模式下自挂起不运行(P1-6 守卫) + * v1.3 2026-10-21 王建锋 删除 net_task_init() 声明(空壳入口、无调用点) */ #ifndef NET_TASK_H @@ -23,7 +24,6 @@ extern "C" { * netTask 自挂起(创建但不运行),由 testTask 调用后独占 CH395F。 */ int net_stack_bring_up(void); -int net_task_init(void); void net_task_func(void const *arg); #ifdef __cplusplus diff --git a/docs/算法/采样有效性校验设计说明.md b/docs/算法/采样有效性校验设计说明.md index 95b063a6..1d0279de 100644 --- a/docs/算法/采样有效性校验设计说明.md +++ b/docs/算法/采样有效性校验设计说明.md @@ -554,10 +554,16 @@ stateDiagram-v2 3. 位图**不复用已冻结位号**:bit0..bit7 已分配,新位从 bit8 起;`events` 与 `sticky` 若要共享 语义就必须共享位号(§7 的去重写法依赖这点)。 -**当前事实登记**(改这段链时会撞上):产品启动路径上 `adc_health_init()` 并未被调用—— -`adc_task_init()` 目前在仓库里没有调用点(只有 `adc_task_func` 被 `Src/freertos.c` 建为任务)。 -判定仍然正确,因为判定层状态全在 `.bss`(复位即 0),而**首拍只建基线**这条设计让 init 变成 -可选动作。但「init 可选」不等于「init 无用」:运行期任何需要重建参照系的场合都必须显式调用。 +**启动路径事实**:`adc_health_init()` 由 `adc_task_init()` 调用,而 `adc_task_init()` 由 +`adc_task_func()` 在进入循环之前自己调用(在「开闸」`s_consumer_ready = 1` 之前,所以 init 与 +首拍之间不存在被抢占的窗口)。三点设计含义: + +- 判定层的正确性**不依赖**这次调用——状态全在 `.bss`(复位即 0),加上**首拍只建基线**, + 漏调一次只是「少清一次」。这正是把 init 设计成幂等 + 首拍建基线换来的韧性。 +- 但入口必须真的存在并被调用:否则函数头的「限定条件」就是假的,而下一个人(或 agent) + 会照着它推理。运行期要重建参照系(例如重新跑了会清零计数的驱动 `*_init()`),调用的就是它。 +- 该入口**禁止加日志**:它在 adcTask 的静态最坏调用链上(栈预算口径见本节表末与 + `docs/内存管理/RAM使用分析与优化方案.md` §1.4)。 --- @@ -580,3 +586,4 @@ stateDiagram-v2 | 日期 | 变更 | 说明 | |---|---|---| | 2026-10-21 | 新建 | 首版单文件深设计:判据推导、四种位语义、闭锁与兜底责任矩阵、验证分工与现场判读手册;新增三张配图生成器(`tools/arch_diagram/gen_adc_health_flow_svg.py`、`gen_adc_health_bitmap_svg.py`、`gen_adc_health_timeline_svg.py`)与产物 SVG | +| 2026-10-21 | §14 更新 | 初始化入口已接线:`adc_task_func()` 进循环前调 `adc_task_init()`(该入口不再打日志);同时删除 `App/task/net_task.c` 里的空壳 `net_task_init()` |