Files
STM32F4-Base/Drivers/BSP/UI/ui_w_records.c
T
wandering1 52e28885cb feat(UI): 装置维护 3 页落地(时钟 / 强制复归 / 清除记录),内容页黄金 27→40
三个薄页面模块 ui_page_clock / ui_page_reset / ui_page_clear,页面注册由生成器
自动写双端(裁定 A-1:「三叶各绑一页」与「零新增 .c」不可兼得,选薄页面加生成器,
不写手写 node switch——那种分发在增删叶子时会静默换功能,且没有任何门禁照得到)。

数据侧是注入式函数表:UI 不 include App 层的头。两条硬理由都实测过——分层方向
(layer-deps)之外,模拟器根本不链 sys_clock,ALLOW 豁免挡得住 layer-deps,
挡不住模拟器链接期。面板对时的唯一真判据是回读 RTC:sys_clock_set() 恒返 0
(RTC 写失败只打日志),所以真机侧写 1 后回读 1,最坏约 200 ms 落在一次「保存」
按键上,IWDG 800 ms 窗有余;上界与依据都写进注释。

「无时钟」徽标位置有两个像素级实测坑:放标题带右侧会被 4 字标题连成「时钟设置
无时钟」一句话;放页脚带左侧 x=7 会压住页脚——页脚从 x=6 起排,不是居中。
最终落在清单末行与页脚之间的空带 y=124。clear_done 那张顺带给出像素证据:
清 run.log 之后「操作记录」那一行从 2 变 3,页面上没缓存、没撒谎。

ui_w_records 的 UI_W_REC_LOG_* 顺序必须等于 syslog_id_t 顺序(7 类,只准尾追加),
已加编译期顺序守卫;执行侧 7 条映射表同样带编译期守卫。

测试与真值:内容页黄金 27 → 40 页(+13),文本断言 +68、反向断言 ABSENT +19;
27 张旧参考 git diff 为空 = 逐字节未变。往返池 5448 B 与菜单常驻堆 5368 B 均未变;
字库未扩(源码在用 171 并 KEEP_EXTRA 39 = 清单 183),font-charset 与 cn-chars、
cn-font 字节一致。@build 0 错误 0 警告;uiTask 静态最坏链 1,336 B / 16,384
(余 91%)与基线相同,页面钩子没进最坏链。

一条测试学结论单独留痕:反向断言不能当「位置不重叠」的证据——本脚本的字形匹配
把 y 带判得比字面宽(徽标在 125..136、页脚在 144..155,仍被 (140,160) 判命中)。
该防线改由正向断言「页脚未被徽标压住」承担(压字那一版实测过不了它)。

两条自我更正一并记档(作者自报,按真值而非原口径):
① 先前报「文案零新增汉字」是错的——观测行拟用「动作元件」,「元」不在子集,
cn-chars 与 font-charset 如实红;最终改「保护动作 N」才让「零新增」成为事实。
顺序是:先按机器红,再按真值写结论。
② 先前报「6 个文件 BOM 逐个核过」被 bom-guard 证伪:丢 BOM 发生在上一次编译之后,
正是 AGENTS 那句「历史 0 警告不代表安全」的活例;此后一律以退出码为准。

未覆盖项不假装:台架「N>0 → N=0」在产品构建的未标定闭锁期拿不到(闭锁期 N 恒 0),
判据显式退化为「页面受理 + 落一条操作记录」,写在 rs_watch 注释里。

生成物入库例外照用:uvprojx 只加 3 个 ui_page_ 的 FilePath(真增删源文件),
CMakeLists 同批;两处都由 gen_menu.py 自己写,没手写。

本笔先走了一次真钩子:20 条钩子实跑通过(ui-golden 菜单 8 状态加内容页 40 页、
generated-fresh、registration-check、font-charset、ui-data 单测、cppcheck、
coding-standard、bom、mojibake、id-check、doc-links 等),只有 mem-numbers 与
mem-budget 两条红——磁盘上的 .map 出自 20:39 那次构建、含三条在飞道的代码,
与 HEAD 台账必然不同码。按仓库既有约定(这两条等台账回填时允许 --no-verify 并
正文留证)落这一笔;回填由我统一在收尾一笔做。

三条在飞道(task-26 崩溃证据路径、task-16 与 task-17 谓词收敛和卷锁观测、
task-36 台架工具)的未暂存改动被 autostash 暂时收走,钩子看到的是 HEAD 加本笔;
过程中曾把 comm 道未跟踪的 iec104_comm.c 临时移出(它不在 stash 覆盖面内),
那次移出反而让 ui-golden 撞见 CMake 缓存里的悬空引用而红——已改用「先落 comm
那笔、再落本笔」的顺序消掉这个中间态。ui_data_maint_ready() 待删(只有测试在读
的自检口),排在本笔之后单独一笔。
2026-10-26 22:43:54 +08:00

108 lines
4.1 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 模块名称:UI 记录页共享组件实现
* 模块功能:见 ui_w_records.h(逻辑照搬合并前的 ui_page_runlog.c / ui_page_selftest.c,
* 两文件差异仅为记录源编号与符号名,其余逐字相同;数据经注入 reader 取)
* 适用范围:Drivers/BSP/UI
* 作者:王建锋
* 创建日期:2026-10-20
* 修改记录:
* v1.0 2026-10-20 王建锋 创建(W6)
* v2.0 2026-10-25 王建锋 reader 注入(道B task-6):syslog_count/syslog_get_record
* 直调改为 s_reader 函数表调用;未注入按空态渲染
*/
#include <string.h>
#include "ui_w_records.h"
#include "ui_tokens.h"
/* 静态变量定义区 */
/* 注入的记录 reader(模块级单例,理由见头注;NULL = 未注入 → 空态) */
static const ui_rec_reader_t *s_reader;
/* 函数定义区 */
/*
* 函数功能:注入记录 reader
*/
void ui_w_records_bind(const ui_rec_reader_t *a_reader) {
s_reader = a_reader;
}
/*
* 函数功能:按记录源编号查条数(不经行缓存的裸计数)
* 入口参数:log_id - 记录源编号(UI_W_REC_LOG_*) uint8_t
* 返回值:条数;未注入 reader 或编号未知一律 0,即空态,调用方按"无记录"显示
* uint16_t
* 限定条件:uiTask 上下文(记录侧绘制/按键链)
* 函数说明:为什么开这个口子——清除记录页要在 7 行上分行显示各类条数(点完
* "清除"之后条数归零就是它唯一的真反馈),而 reader 是本组件私有
* 的注入表;不开放一个只读入口,页面就只能自己去注第二份 reader,
* 那正好把 task-6 刚削掉的分层反向边又接回来(口径见
* docs/UI设计/UI_数据供给设计说明.md §7.2/§7.3)。
* 本函数不带行缓存:缓存属于"某一条记录的字段",与条数无关
*/
uint16_t ui_w_records_count_of(uint8_t a_log_id) {
if (s_reader == NULL) {
return 0u;
}
return s_reader->count(a_log_id);
}
/*
* 函数功能:总行数(动态;每条记录 2 行,空日志 = 单条伪行"无记录")
* 入口参数:a_inst - 记录页实例 ui_w_records_t *
* 返回值:总行数 uint16_t
* 函数说明:未注入 reader 视同 0 条(空态伪行),两端启动期绑定前的开页窗口
* 也被覆盖(防御不崩)
*/
uint16_t ui_w_records_count(ui_w_records_t *a_inst) {
uint32_t n = (s_reader != NULL) ? s_reader->count(a_inst->log_id) : 0u;
if (n == 0u) {
return 1u; /* 空态伪行(页脚"共 1 页",避免"共 0 页") */
}
return (uint16_t)(n * 2u);
}
/*
* 函数功能:逐行取数(偶数行 = 时间戳、奇数行 = 描述;值列恒空)
* 入口参数:a_inst - 记录页实例 ui_w_records_t *
* a_row - 全局行下标 uint16_t
* a_name - 名输出缓冲 char *
* a_value- 值输出缓冲(恒写空串) char *
* 限定条件:页面打开中(框架绘制/按键上下文,uiTask)
*/
void ui_w_records_refresh(ui_w_records_t *a_inst, uint16_t a_row, char *a_name, char *a_value) {
uint32_t n = (s_reader != NULL) ? s_reader->count(a_inst->log_id) : 0u;
a_value[0] = '\0';
if (n == 0u) {
(void)memcpy(a_name, "无记录", sizeof("无记录"));
return;
}
{
uint32_t rec = a_row / 2u;
if (!a_inst->cache_valid || rec != a_inst->last_rec) {
if ((s_reader->get)(a_inst->log_id, rec, a_inst->ts, sizeof(a_inst->ts),
a_inst->desc, sizeof(a_inst->desc)) != 0) {
a_inst->cache_valid = 0u;
a_name[0] = '\0'; /* 读失败(越界/存储异常):空行防御 */
return;
}
a_inst->last_rec = rec;
a_inst->cache_valid = 1u;
}
if ((a_row % 2u) == 0u) {
(void)memcpy(a_name, a_inst->ts, sizeof(a_inst->ts));
}
else {
(void)memcpy(a_name, a_inst->desc, sizeof(a_inst->desc));
}
}
}