/* * 模块名称:UI Page reset (强制复归内容页) * 模块功能:装置维护 → 强制复归 叶子(node 25,#P 受密码保护)的内容页—— * 复用 ui_page_action 共享确认链(一次确认 → 二次确认 → 执行回报), * 并在同一屏画一行"保护动作 N"(N = 当前处于动作态的保护元件个数): * 复归前 N > 0、复归请求被 protectTask 消费后 N 归 0,这个变化就是 * "动作位真的复归了"的屏上证据,不用翻页、不用外接表; * 执行只做两件事:投复归请求 + 补一条本地操作记录留痕; * 只读进入(查看密码)整页拒执行并显式说"没权限"(LOCK)—— * 破坏性动作不给"看着像能按"的第二次机会; * 本文件零 App include、零存储触点(分层方向由注入表守住) * 为什么这么薄:确认链的形态(含二次确认与回报)是共享件,四个维护/操作类叶子 * 共用一份实现;本文件只把"这一页问什么、执行什么、观测什么"三项 * 配置接进框架的描述符骨架(同 ui_page_runlog 之于 ui_w_records) * 适用平台:STM32F407ZGTx / PC 模拟器(两端共用) * 作者:DTU 项目组 * 创建日期:2026-10-26 * 修改记录: * v1.0 2026-10-26 DTU 项目组 创建(道F task-3;判据 docs/任务规划/UI补齐.md * §2 第 3 行「强制复归确认后动作位复归且有 SOE」) */ /* 头文件包含区 */ #include "ui_page_reset.h" #include "ui_content_page.h" #include "ui_data.h" #include "ui_page_action.h" /* 私有宏定义区 */ /* * 本地这条操作记录的描述串:ASCII 20 字节 < SYSLOG_DESC_MAX(28)。 * 与远端那条(App/protocol/iec104/iec104_pts.c 的 "force reset")**刻意不同串**—— * 操作记录是审计面,两条一样就再也分不出"是主站下发的还是现场有人按面板", * 而那正是查遥控事故时第一个要问的问题。 * 为什么由页面投而不是由 prot_elm_request_reset() 投:那条函数在 algo 层, * 在那里投会把 sys_log.h 拽进算法层(并把记录通道的依赖摊到 test/host/prot_dim * 的 include 路径上);而"这是本地发起的"这个事实只有页面知道(口径真源 * App/log/README.md 五类记录表 + task-10 结论)。 */ #define RS_OPER_NOTE "force reset by panel" /* 私有函数声明区(静态初始化器要引用下面两个函数的地址,故先声明) */ static bool rs_ok(void); static uint32_t rs_watch(void); /* 静态变量定义区 */ /* * 本页操作页实例(配置全为 Flash 字面量与函数地址;运行态两字节由组件写)。 * 字段顺序 = ui_page_action_t 声明序(ARMCC v5 = C99 要求指定顺序一致)。 */ static ui_page_action_t s_act = { "确认复归保护?", /* prompt:问句用字已在字库(确/认/复/归/保/护 + '?') */ "已请求复归", /* done_text:回报"请求已受理",不谎称"已复归完成" */ rs_ok, /* ok_cb */ 1u, /* need_modify:只读进入一律拒执行 */ "保护动作", /* watch_label(用字全在既有子集内;曾拟"动作元件", 其中"元"不在子集 —— 见本行下方注释与终报) */ rs_watch, /* watch_cb */ 0u, /* stage(运行态初值) */ 0u /* err (运行态初值) */ }; /* 函数定义区 */ /* * 函数功能:执行投递——请求复归,受理成功后补投本地操作记录 * 入口参数:无 * 返回值:true = 已受理(组件转成功回报);false = 拒收(组件显示 ERR) bool * 限定条件:由 ui_page_action_key 在第二次 ENTER 时调用(uiTask 上下文) * 函数说明:两条腿的次序即判据——**先请求后留痕**:请求被拒时一条记录都不投, * 给一次没发生过的操作写审计记录,比少一条记录坏得多(同 * App/task/iec104_serv.c 对时留痕"只在真改成功之后才投"那条纪律)。 * 维护通道未注入(装配缺一半)也走拒收这条腿:屏上显 ERR, * 比"按了像成功其实什么都没发生"诚实 */ static bool rs_ok(void) { if (ui_data_maint_reset_req() != 0) { return false; } (void)ui_data_maint_oper_note(RS_OPER_NOTE); return true; } /* * 函数功能:取当前处于动作态的保护元件数(观测行 "保护动作 N" 的 N) * 入口参数:无 * 返回值:元件数(未注入时 0) uint32_t * 限定条件:绘制路径可直调(一次转发,零 I/O、零锁) * 函数说明:⚠ 台架判据的前提要写清:产品构建现处"未标定闭锁" * (App/task/protect_task.c 停走判据),闭锁态下元件本就是复位态, * "N 从 >0 变 0"这一眼要等两点标定解卡后才成立;解卡前该判据 * 退化为"页面受理 + 操作记录落一条",不得把闭锁态报成复归无效 */ static uint32_t rs_watch(void) { return ui_data_maint_active_count(); } /* * 函数功能:开页复位确认链(框架 init_cb) * 入口参数:无 * 返回值:无 * 限定条件:框架开页链内调用 * 函数说明:复位由组件做(stage/err 是它的运行态),本页不重复清一遍 */ static void pg_init(void) { ui_page_action_init(&s_act); } /* * 函数功能:自绘(框架 draw_cb;四行居中全由组件画) * 入口参数:a_layer / a_clip - 契约见 ui_content_page.h * 返回值:无 * 限定条件:框架绘制链末尾调用 */ static void pg_draw(lv_layer_t *a_layer, const lv_area_t *a_clip) { ui_page_action_draw(&s_act, a_layer, a_clip); } /* * 函数功能:按键转发(框架 key_cb) * 入口参数:a_key - LVGL 键值 lv_key_t * 返回值:true = 本页已消费;false = 交回框架 bool * 限定条件:框架按键链内 * 函数说明:确认链的判定全在组件里(含只读拒执行),本页只如实透传返回值, * 不在这层"顺手"加判据——两处各判一次早晚分家 */ static bool pg_key(lv_key_t a_key) { return (ui_page_action_key(&s_act, a_key) != 0u); } /* * 页面描述符(外部链接:生成物 ui_page_registry.c 按菜单树 #page=reset 绑定引用) * 表单/操作页形态:无浅 V、无页脚、无行列表(用户密钥页与网口设置页先例); * edit_capable=1 是**能不能改**的那半,另半(本次进入授予的权限)由 * ui_content_page_is_editable() 给——两半都在,组件才能判出"只读"; * key_intercept=0:LEFT 不拦截,关页 = 取消(本链没有"编辑到一半"的状态要保) */ const content_page_def_t ui_page_reset_desc = { .id = "reset", .title = "强制复归", .hide_deco = 1u, .hide_footer = 1u, .selectable = 0u, .key_intercept = 0u, .edit_capable = 1u, .init_cb = pg_init, .draw_cb = pg_draw, .key_cb = pg_key, };