From d6253aa974f4357779d0a94ff24ba66a58abf094 Mon Sep 17 00:00:00 2001 From: super_agent_bot Date: Mon, 2 Nov 2026 18:07:52 +0800 Subject: [PATCH] =?UTF-8?q?fix(ui/wave):=20=E9=92=89=E6=AD=BB=E5=B9=B6?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=9B=9E=E6=94=BE=E9=A1=B5=E6=81=92=E7=A9=BA?= =?UTF-8?q?=E6=A0=B9=E5=9B=A0=E2=80=94=E2=80=94=E8=AF=BB=E4=BE=A7=E7=94=A8?= =?UTF-8?q?=E5=8F=8D=20seg=5Fpath=20=E8=BF=94=E5=9B=9E=E5=A5=91=E7=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FR 埋点构建上板判读(本 boot 串口实录,临时诊断构建 = 上一提交): [UI_TASK] ui wave scan #1 done cnt=7 np=0 tt=0 ac=407 [ERR][UI_TASK] ui wave head #1 path fail idx=6 - 目录枚举一直是好的(cnt=7 = 盘上七段全数入表,锁也拿到,tt=0): 10-31「唯独 ui_task_wave_scan 拿不到目录条目」的定性被推翻。 - 真正坏的在 load_head / seg_win 的拼路径判错:契约 (App/algo/wave_store.h:458)是「成功 = 写入字符数(本形态恒 16), 失败才是负码」,读侧自建成功能起写成 != 0 判失败——每次成功都被 判死,f_open 永远走不到,盘上有段也恒显「无录波段」。写侧 default_task.c 同函数用 <= 0,一直是对的,所以「FTP 六段全见、 写侧枚举正常、唯独回放恒空」的怪象全线得解。 - 模拟器走桩、不编译本文件读侧,黄金参考图与主机单测因此从未覆盖 这条链,此病从建成存活至今(板端首张真机波形图见 PR #67)。 - 两处口径改 <= 0(与写侧一致);表列着的段 f_open 失败补带 FR 码 的永久留痕——该失败态页面无视觉面,10-31 误定性的教训就是静默。 - 临时诊断(#N 序号 / try 闸日志 / 无条件 done 行)收敛删除,留 最小永久集:scan opendir/readdir FR、零条目 INFO、head/win 开档 失败 FR。try 闸恢复静默(看门狗设计说明 §4.3 口径)。 - /keil-build 0 错误 0 警告:Code 247,284 B(较临时诊断构建 −368 B,较修复前 +236 B),RAM 不变;台账 / 同码凭证 / 数字回填 同批刷新。 Refs #38 --- App/task/ui_task.c | 90 +++++++++++++------------- docs/内存管理/RAM使用分析与优化方案.md | 4 +- docs/内存管理/RAM预算台账.md | 4 +- scripts/ram_baseline.tsv | 2 +- scripts/size_attestation.json | 16 ++--- 5 files changed, 58 insertions(+), 58 deletions(-) diff --git a/App/task/ui_task.c b/App/task/ui_task.c index b0e8e698..6f4ece2a 100644 --- a/App/task/ui_task.c +++ b/App/task/ui_task.c @@ -37,8 +37,19 @@ * ui_task_wave_scan 失败不再无条件钉 s_wave_scanned—— * opendir/readdir 失败本轮返 -1(卷忙语义),下一次进页/ * 按键自然重试;失败分支与「FR_OK 零条目」补带 FR 码留痕 - * (DBG_TAG [UIWAVE])供板级远程定性根因。FR_NO_PATH - * (从未录过波)归 0 段并钉表的设计原口径不动。 + * (正文「ui wave scan」前缀,tag 沿用本文件 [UI_TASK]) + * 供板级远程定性根因。FR_NO_PATH(从未录过波)归 0 段 + * 并钉表的设计原口径不动。 + * v1.7 2026-11-02 DTU 项目组 根因修复:wave_store_seg_path 契约是「成功 = + * 写入字符数(恒 16),失败为负码」,读侧两处(load_head + * / seg_win)自建成起把返回值 != 0 当失败——每次成功拼 + * 路径都被判死,回放页开档永远走不到 f_open,盘上有段 + * 也恒显「无录波段」(本 boot FR 埋点钉死:scan done + * cnt=7 + head path fail;写侧同函数用 <= 0 一直是对的; + * 模拟器桩不走本文件,故黄金图从未暴露此病)。口径改 + * <= 0;开档失败补带 FR 码的永久留痕(该失败态页面无 + * 视觉面);第一幕临时诊断(序号/try 闸日志/无条件 + * done 行)收敛删除。 */ #include "ui_task.h" @@ -423,8 +434,6 @@ static const ui_soe_reader_t s_soe_reader = { ui_task_soe_count, ui_task_soe_get static uint8_t s_wave_idx[WAVE_ST_SEG_MAX]; /* 盘上现存段号升序表 */ static uint8_t s_wave_cnt; /* 表内条数 */ static uint8_t s_wave_scanned; /* 表是否有效(manual_req 后作废) */ -static uint8_t s_wave_dbg_seq; /* 诊断留痕(第一幕第二组):本 boot - * 扫描尝试序号,供各行对齐 */ static uint8_t s_wave_cached_idx; /* 段头缓存属于哪一段 */ static uint8_t s_wave_cache_ok; /* 该段已验完整(头+数据 CRC) */ static wave_seg_meta_t s_wave_meta; /* 已验段的头(172B,唯一驻留) */ @@ -461,15 +470,10 @@ static int ui_task_wave_scan(void) { uint8_t i; uint8_t full; /* 1 = 本轮拿到完整事实,允许钉表 */ - s_wave_dbg_seq++; /* 诊断留痕(第一幕第二组):每次尝试一个序号 */ if (vol_lock_wait(0u) == 0u) { - /* try 闸此前无任何留痕(看门狗设计说明 §4.3 只禁「锁层自身」打日志—— - * 这里是消费方的一次性观测,计数走不取锁的 vol_lock_get_stats) */ - vol_lock_stats_t vs; - vol_lock_get_stats(&vs); - DBG_ERROR("ui wave scan #%u try fail tt=%lu ac=%lu fo=%lu", - (unsigned)s_wave_dbg_seq, (unsigned long)vs.try_timeout, - (unsigned long)vs.acquired, (unsigned long)vs.failopen); + /* 卷忙本轮跳过 = 静默(看门狗设计说明 §4.3 口径:消费方在 try 失败 + * 分支不留日志,锁层竞争看 vol_lock_get_stats 计数);下一次进页/ + * 按键自然重试——本轮没拿到事实,绝不钉表 */ return -1; } s_wave_cnt = 0u; @@ -497,29 +501,23 @@ static int ui_task_wave_scan(void) { } (void)f_closedir(&dir); if (full == 0u) { - DBG_ERROR("ui wave scan #%u readdir fail fr=%d got=%u", - (unsigned)s_wave_dbg_seq, (int)rr, (unsigned)s_wave_cnt); + DBG_ERROR("ui wave scan readdir fail fr=%d got=%u", (int)rr, + (unsigned)s_wave_cnt); } } else if (fr == FR_NO_PATH) { full = 1u; /* 从未录过波 = 0 段,完整事实 */ } else { - DBG_ERROR("ui wave scan #%u opendir fail fr=%d", (unsigned)s_wave_dbg_seq, - (int)fr); + DBG_ERROR("ui wave scan opendir fail fr=%d", (int)fr); } vol_lock_release(); if (full == 0u) { s_wave_cnt = 0u; /* 半截计数不外泄:本轮按「无段」显示 */ return -1; } - { - /* 判读表补全(诊断):每一次完成扫描都留一行(含非零条目—— - * 「扫描成功但页面仍空」也要能被排除),随根因修复收敛删减 */ - vol_lock_stats_t vs; - vol_lock_get_stats(&vs); - DBG_INFO("ui wave scan #%u done cnt=%u np=%d tt=%lu ac=%lu", - (unsigned)s_wave_dbg_seq, (unsigned)s_wave_cnt, - (fr == FR_NO_PATH) ? 1 : 0, (unsigned long)vs.try_timeout, - (unsigned long)vs.acquired); + if (s_wave_cnt == 0u) { + /* 判读表第三条(FR_OK 但零条目):钉盘级证据;有段不重复刷 + * (DBG_* 每条调用点约 90B Flash,开页成功态由画面自证) */ + DBG_INFO("ui wave scan done: dir ok, 0 seg entries"); } /* 插入排序:条数上限 100,不引 qsort 的 stdlib 依赖 */ for (i = 1u; i < s_wave_cnt; i++) { @@ -589,22 +587,23 @@ static int ui_task_wave_load_head(uint8_t a_idx) { static FIL f; /* static:FIL = 528B,理由同 soe_store_read */ char path[WAVE_ST_PATH_MAX]; /* 容量 = WAVE_ST_PATH_MAX(17 字节口径, * 自己声明路径缓冲不得写死 16) */ - FRESULT fr = FR_OK; /* 诊断留痕可能未走到任何 f_read 就读它 */ - FRESULT ofr = FR_OK; /* 诊断留痕(第一幕第二组):开档 FR 码 */ + FRESULT fr; + FRESULT ofr; /* 开档 FR 码:开档失败留痕用 */ UINT br = 0u; int rc; if ((s_wave_cache_ok != 0u) && (s_wave_cached_idx == a_idx)) { return UI_WAVE_OK; } - if (wave_store_seg_path(path, (uint32_t)sizeof(path), a_idx) != 0) { - DBG_ERROR("ui wave head #%u path fail idx=%u", (unsigned)s_wave_dbg_seq, - (unsigned)a_idx); + if (wave_store_seg_path(path, (uint32_t)sizeof(path), a_idx) <= 0) { + /* 契约(wave_store.h:458):成功 = 写入字符数(恒 16),失败才是负码。 + * 建成功能起这里写成 != 0,把每次成功都当失败 → 回放页开档永远走不到 + * f_open,盘上明明有段也恒显「无录波段」(2026-11-02 板级 FR 埋点 + * 钉死:scan done cnt=7 + head path fail;写侧 default_task.c 同函数 + * 用 <= 0,一直是对的)。口径取和写侧一致的 <= 0。 */ return UI_WAVE_NONE; } if (vol_lock_wait(0u) == 0u) { - DBG_ERROR("ui wave head #%u try fail idx=%u", (unsigned)s_wave_dbg_seq, - (unsigned)a_idx); return UI_WAVE_NONE; /* 卷忙 = 本轮按无段处理(不阻塞 uiTask) */ } rc = UI_WAVE_NONE; @@ -667,9 +666,12 @@ static int ui_task_wave_load_head(uint8_t a_idx) { s_wave_cache_ok = 1u; } else { s_wave_cache_ok = 0u; - DBG_ERROR("ui wave head #%u rc=%d idx=%u ofr=%d fr=%d br=%u", - (unsigned)s_wave_dbg_seq, rc, (unsigned)a_idx, (int)ofr, - (int)fr, (unsigned)br); + if (ofr != FR_OK) { + /* 表上明明列着这个段、开档却失败:页面只会显示「无录波段」, + * 没有任何视觉面——必须留痕(10-31 半轮栽就栽在这类静默面上) */ + DBG_ERROR("ui wave head idx=%u open fail fr=%d", (unsigned)a_idx, + (int)ofr); + } } return rc; } @@ -811,7 +813,7 @@ static int ui_task_wave_seg_win(uint8_t a_idx, uint8_t a_ch, int16_t *a_codes, int32_t *a_peak_milli) { static FIL f; char path[WAVE_ST_PATH_MAX]; - FRESULT fr = FR_OK; /* 诊断留痕(第一幕第二组):开档 FR 码 */ + FRESULT fr; /* 开档 FR 码:开档失败留痕用 */ UINT br = 0u; uint32_t off; uint32_t want; @@ -842,14 +844,12 @@ static int ui_task_wave_seg_win(uint8_t a_idx, uint8_t a_ch, if (want != UI_WAVE_WIN_PTS * 2u) { return UI_WAVE_BAD; /* 窗口贴不出完整 40 点:显式不可读 */ } - if (wave_store_seg_path(path, (uint32_t)sizeof(path), a_idx) != 0) { - DBG_ERROR("ui wave win #%u path fail idx=%u", (unsigned)s_wave_dbg_seq, - (unsigned)a_idx); + if (wave_store_seg_path(path, (uint32_t)sizeof(path), a_idx) <= 0) { + /* 同 ui_task_wave_load_head:契约成功 = 16,失败是负码;!= 0 的旧写法 + * 把成功当失败,窗口永远贴不出(2026-11-02 根因修复,详见那里注释) */ return UI_WAVE_NONE; } if (vol_lock_wait(0u) == 0u) { - DBG_ERROR("ui wave win #%u try fail idx=%u ch=%u", (unsigned)s_wave_dbg_seq, - (unsigned)a_idx, (unsigned)a_ch); return UI_WAVE_NONE; } rc = UI_WAVE_BAD; @@ -895,10 +895,10 @@ static int ui_task_wave_seg_win(uint8_t a_idx, uint8_t a_ch, } } *a_peak_milli = peak; - } else { - DBG_ERROR("ui wave win #%u rc=%d idx=%u ch=%u ofr=%d br=%u", - (unsigned)s_wave_dbg_seq, rc, (unsigned)a_idx, (unsigned)a_ch, - (int)fr, (unsigned)br); + } else if (fr != FR_OK) { + /* 理由同 load_head 的开档留痕:表列着的段开不出,页面无视觉面 */ + DBG_ERROR("ui wave win idx=%u ch=%u open fail fr=%d", (unsigned)a_idx, + (unsigned)a_ch, (int)fr); } return rc; } diff --git a/docs/内存管理/RAM使用分析与优化方案.md b/docs/内存管理/RAM使用分析与优化方案.md index 9a458b22..4532eee0 100644 --- a/docs/内存管理/RAM使用分析与优化方案.md +++ b/docs/内存管理/RAM使用分析与优化方案.md @@ -47,10 +47,10 @@ dhara 失败类 +84;RO 另 +208,全是该失败类名表)→ `ER_IROM1` | 区域 | 用量 | 容量 | 占比 | |---|---|---|---| -| ER_IROM1 | 277,768 B (271.26 KB) | 1,048,576 B (1024 KB) | 26.5% | +| ER_IROM1 | 277,120 B (270.62 KB) | 1,048,576 B (1024 KB) | 26.4% | | RW_IRAM1 | 94,336 B (92.12 KB) | 131,072 B (128 KB) | 72.0% | | RW_CCM | 57,376 B (56.03 KB) | 65,280 B (64 KB) | 87.9% | -| **Flash (ROM 合计)** | **279,820 B (273.3 KB)** | 1,048,576 B (1024 KB) | **26.7%** | +| **Flash (ROM 合计)** | **279,172 B (272.6 KB)** | 1,048,576 B (1024 KB) | **26.6%** | 各区的容量与常量来源: diff --git a/docs/内存管理/RAM预算台账.md b/docs/内存管理/RAM预算台账.md index 8816b53e..7d9a9c14 100644 --- a/docs/内存管理/RAM预算台账.md +++ b/docs/内存管理/RAM预算台账.md @@ -15,7 +15,7 @@ | 区域 | 用量 | 容量 | 占比 | 门禁(≤92%) | |---|---|---|---|---| -| ER_IROM1 (Flash) | 277,768 B | 1,048,576 B | 26.5% | 参考 | +| ER_IROM1 (Flash) | 277,120 B | 1,048,576 B | 26.4% | 参考 | | RW_CCM | 57,376 B | 65,280 B | 87.9% | PASS | | UNINIT_CCM | 48 B | 256 B | 18.8% | 参考 | | RW_IRAM1 | 94,336 B | 131,072 B | 72.0% | PASS | @@ -24,7 +24,7 @@ |---|---|---|---| | 网络 | 13,702 B | 12 KB | ⚠ 超 1.4 KB | | 存储 | 7,072 B | 12 KB | OK | -| UI | 36,442 B | 16 KB | ⚠ 超 19.6 KB | +| UI | 36,441 B | 16 KB | ⚠ 超 19.6 KB | | RTOS 堆 | 57,376 B | 56 KB | 堆=配额 | | 应用 | 26,333 B | 8 KB | ⚠ 超 17.7 KB | | 其它 | 10,780 B | — | 参考 | diff --git a/scripts/ram_baseline.tsv b/scripts/ram_baseline.tsv index 637b6148..84fff98c 100644 --- a/scripts/ram_baseline.tsv +++ b/scripts/ram_baseline.tsv @@ -14,4 +14,4 @@ date code ro rw zi er_irom1 er_pct iram1 iram1_pct ccm ccm_pct top_rwzi 2026-10-29 238936 29140 1932 141396 268076 25.6 85904 65.5 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;sb_link.o=4364;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4055 2026-10-29 243552 28784 1972 145388 272336 26.0 89936 68.6 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;wave_ring.o=5296;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4055 2026-10-30 246720 29836 2052 149708 276556 26.4 94336 72.0 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6432;nand_ftl.o=6216;wave_ring.o=5296;sb_link.o=4376;ch395f.o=4162;console_log.o=4132 -2026-11-02 247652 30116 2052 149708 277768 26.5 94336 72.0 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6432;nand_ftl.o=6216;wave_ring.o=5296;sb_link.o=4376;ch395f.o=4162;console_log.o=4132 +2026-11-02 247284 29836 2052 149708 277120 26.4 94336 72.0 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6432;nand_ftl.o=6216;wave_ring.o=5296;sb_link.o=4376;ch395f.o=4162;console_log.o=4132 diff --git a/scripts/size_attestation.json b/scripts/size_attestation.json index 2992239f..faf6d720 100644 --- a/scripts/size_attestation.json +++ b/scripts/size_attestation.json @@ -1,17 +1,17 @@ { - "built_at": "2026-11-02T17:39:58+08:00", - "fingerprint": "0dc67e164f92d0074da5390bdd440eef99027e2dd181311a52bd92e6453a44cc", + "built_at": "2026-11-02T18:06:44+08:00", + "fingerprint": "a7a328b45a3ff91fcb9138b919662e893dd8cb9a0a1b080afa7b57d663f7a4de", "fingerprint_files": 1466, "fingerprint_source": "git-index", "gated_regions": [ "RW_IRAM1", "RW_CCM" ], - "git_head": "1b074bc41a9c3b4c8f0f382cb58862ce9d15b0fe", + "git_head": "3e01e9d98e0690e949510f569a502192542492d0", "map": "MDK-ARM/STM32F407-Demo/STM32F407-Demo.map", - "map_mtime": 1793612338, + "map_mtime": 1793613913, "pct": { - "ER_IROM1": 26.49, + "ER_IROM1": 26.43, "RW_CCM": 87.89, "RW_IRAM1": 71.97, "UNINIT_CCM": 18.75 @@ -19,7 +19,7 @@ "regions": { "ER_IROM1": { "max": 1048576, - "size": 277768 + "size": 277120 }, "RW_CCM": { "max": 65280, @@ -37,8 +37,8 @@ "schema": 2, "scope_note": "\u540c\u7801\u51ed\u8bc1\uff1a\u6307\u7eb9\u8986\u76d6\u56fa\u4ef6\u4f53\u79ef\u76f8\u5173\u6e90\u7801\uff0c\u53e3\u5f84\u89c1\u672c\u811a\u672c docstring", "sizes": { - "code": 247652, - "ro_data": 30116, + "code": 247284, + "ro_data": 29836, "rw_data": 2052, "zi_data": 149708 },