52e28885cb
三个薄页面模块 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() 待删(只有测试在读 的自检口),排在本笔之后单独一笔。
121 lines
7.7 KiB
C
121 lines
7.7 KiB
C
/*
|
||
* 模块名称:UI 动作确认页(操作页共享实现,ui_page_action)
|
||
* 模块功能:可复用的"确认 -> 二次确认 -> 执行回报"操作页**钩子三件套**——
|
||
* 强制复归 / 手动录波等破坏性叶子共用同一份确认链实现,各自持一份
|
||
* 实例(标题 / 问句 / 结果行 / 执行回调 / 可选观测行);
|
||
* 执行回调只投递请求不阻塞(跨任务交接由执行侧落定),
|
||
* 成功经 done_text 回报后再 ENTER 返回,done_text=NULL 成功即关页;
|
||
* 投递失败显示 ERR,下一次 ENTER 重新走二次确认;
|
||
* 只读权限(查看密码进入)可整页拒执行并显式说"没权限"(need_modify)
|
||
* 适用范围:Drivers/BSP/UI(表单页形态:无浅 V 装饰、无页脚——用户密钥页
|
||
* 跟随实机先例;ESC 恒关页 = 取消,LEFT 亦关页 = 取消)
|
||
* 说明:本组件**不建描述符也不开页**(v1.1 起的形态):内容页框架按描述符
|
||
* **指针**开页,而描述符只能由"一叶一模块"的页面文件导出(真源 =
|
||
* ui_menu_tree.txt 的 #page 注记 + 生成物 ui_page_registry.c)——
|
||
* 旧形态"组件自己 open()"决定了它永远不可能被注册表绑定(构建器不是
|
||
* 描述符,全仓零调用者即其化石证据)。改成 init/draw/key 三个收实例的
|
||
* 钩子后:确认链仍只有一份实现,而页面跳板薄到只剩"一份实例 + 一枚
|
||
* 描述符"(见 ui_page_reset.c),多个操作页各自持实例、互不串态
|
||
* 作者:王建锋
|
||
* 创建日期:2026-10-25
|
||
* 修改记录:
|
||
* v1.0 2026-10-25 王建锋 创建(道B task-5 三组件之一;规格 =
|
||
* 页面扩充详细方案.md §3.4 装置维护操作页 +
|
||
* §4.2 ui_page_action bind(title, prompt, ok_cb)
|
||
* 二次确认、ok_cb 只投递不阻塞)
|
||
* v1.1 2026-10-26 DTU 项目组 道F task-3(装置维护 3 页):改成钩子三件套
|
||
* 形态(init/draw/key 收实例指针),删掉模块单例
|
||
* 与 ui_page_action_open()——构建器开不了注册表
|
||
* 绑定的页(框架按描述符指针开页),旧形态全仓
|
||
* 零调用者;新增 need_modify(只读拒绝执行并显
|
||
* LOCK)与可选观测行(watch_label + watch_cb,
|
||
* 复归页用它把"动作位复归"画在同一屏上);
|
||
* 错误通道由 bsp_err_t 改为无返回 + uint8_t 分发标志
|
||
*/
|
||
#ifndef UI_PAGE_ACTION_H
|
||
#define UI_PAGE_ACTION_H
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
#include <stdbool.h>
|
||
#include <stdint.h>
|
||
|
||
#include "lvgl.h" /* lv_key_t / lv_layer_t:钩子三件套的形参类型(本组件不建对象) */
|
||
|
||
/* 执行回调:只投递请求(事件位/消息队列),立即返回;
|
||
* 返回值:true = 投递被接受(页面转成功回报),false = 拒收(页面显示 ERR) */
|
||
typedef bool (*ui_page_action_ok_fn)(void);
|
||
|
||
/* 操作页实例(配置字段 = Flash 指针与只读回调,运行态 = 本模块写的两个字节);
|
||
* 用法:页面跳板 static 一份、花括号初始化配置,把 init/draw/key 三个钩子直接
|
||
* 转进本组件(v1.1 起本组件不再自己开页——内容页框架按描述符指针开页,
|
||
* 跳板就是那枚描述符的属主,见 ui_page_reset.c) */
|
||
typedef struct {
|
||
/* 页标题不在本结构里:描述符(连 title)由页面跳板 own —— 见 ui_page_reset.c;
|
||
* 两处各留一份标题就是两个真源,改一处屏上另一处不变那种 */
|
||
const char *prompt; /* Flash:确认问句(如"确认复归保护?"——
|
||
问句用字须已入字体子集,否则显示空白方块) */
|
||
const char *done_text; /* Flash:成功后结果行(如"已请求复归");
|
||
NULL = 成功后直接关页回菜单 */
|
||
ui_page_action_ok_fn ok_cb; /* 必填:执行投递(只投递,不等待执行结果) */
|
||
uint8_t need_modify; /* 1 = 只读权限(查看密码进入)时拒绝执行:
|
||
两次 ENTER 都不投递、态标位改显 LOCK。
|
||
破坏性动作必须置 1——只靠"屏上看着像能按"
|
||
拦不住人,必须落在键路上 */
|
||
const char *watch_label; /* Flash:可选观测行的前缀(NULL = 不画该行),
|
||
如"保护动作"。配合 watch_cb 让"复归前 N>0、
|
||
复归后 N=0"在同一屏上看得见 */
|
||
uint32_t (*watch_cb)(void); /* 可选:观测行取值(NULL = 不画该行;与
|
||
watch_label 要么都给要么都不给) */
|
||
uint8_t stage; /* 运行态:0 一次确认 / 1 二次确认 / 2 完成回报 */
|
||
uint8_t err; /* 运行态:1 = 上轮投递被拒(显示 ERR) */
|
||
} ui_page_action_t;
|
||
|
||
/*
|
||
* 函数功能:开页复位确认链(接框架的 init_cb;v1.1 起本组件不再自己开页)
|
||
* 入口参数:inst - 操作页实例(ok_cb 不得为 NULL;配置字段由跳板在编译期填好)
|
||
* ui_page_action_t *
|
||
* 返回值:无
|
||
* 限定条件:内容页框架开页链内调用(uiTask);实例为 NULL 时空操作(防御)
|
||
* 函数说明:每次进入固定从一次确认开始——"上一次按到一半"跨次保留下来就是
|
||
* 第二次进页一按 ENTER 直接执行,那是操作票事故的形状,不是效率优化
|
||
*/
|
||
void ui_page_action_init(ui_page_action_t *a_inst);
|
||
|
||
/*
|
||
* 函数功能:自绘(接框架的 draw_cb:问句 / 态标 / 可选观测行 / 键提示,四行居中)
|
||
* 入口参数:inst - 操作页实例 ui_page_action_t *
|
||
* layer - 绘制层 lv_layer_t *
|
||
* clip - 重绘区 const lv_area_t *
|
||
* 返回值:无
|
||
* 限定条件:框架绘制链末尾调用(本组件只画自己那几行,标题/装饰/页脚归框架);
|
||
* 实例或 prompt 为 NULL 时空操作
|
||
* 函数说明:态标行优先级——只读且需修改权限 > 二次确认 > 投递失败 ERR;
|
||
* 只读那条排最前是刻意的:现场最常见的误读是"我按了没反应",
|
||
* 把"没权限"显出来才不会让人反复按
|
||
*/
|
||
void ui_page_action_draw(ui_page_action_t *a_inst, lv_layer_t *a_layer,
|
||
const lv_area_t *a_clip);
|
||
|
||
/*
|
||
* 函数功能:按键处理(接框架的 key_cb:确认链状态机)
|
||
* 入口参数:inst - 操作页实例 ui_page_action_t *
|
||
* key - LVGL 键值 lv_key_t
|
||
* 返回值:1 = 已消费(框架跳过内置语义);0 = 未消费(交回框架)
|
||
* (键分发标志非错误通道,取 uint8_t 不用 bool——
|
||
* bsp-err/err-type 口径,同 ui_w_editor_key)
|
||
* 限定条件:经描述符 key_cb 挂接;LEFT/ESC 不进本函数(框架恒关页 = 取消)
|
||
* 函数说明:ENTER——stage0 转二次确认;stage1 调 ok_cb 投递:受理且有 done_text
|
||
* 转 stage2 回报、受理且无 done_text 直接关页、拒收置 err 留在 stage1;
|
||
* stage2 关页返回。只读且 need_modify 时任何 ENTER 都不推进也不投递
|
||
*/
|
||
uint8_t ui_page_action_key(ui_page_action_t *a_inst, lv_key_t a_key);
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
|
||
#endif /* UI_PAGE_ACTION_H */
|