Files
wandering1 77779d49d6 feat(ui+记录): 整定写路径与四类页落地,五类记录写入方补齐
UI 面:ui_data 增加深度 4 参数写队列(请求 168 B、队列 .bss 672 B)与状态机
OK/ERR_RANGE/ERR_LOCKED/ERR_BUSY,ui_data_feed 出队后按注入 ops 走「闭锁 → 整批
预检 → 逐项 prot_set_set_sealed」,只提交改动位图;par 帧尾追加 cal_block
(口径 = UA/UN/IA 三路 ADC_CAL_F_VALID,与 protect_task 判据同构,不用 rt.eng
反推,V0.1 下 eng 恒 0)、UI_DATA_VER 升到 2。参数/定值/控制字/软压板四叶绑定
内容页(UI_PAGE_MAP_COUNT 12→16,复用四个查看模块,零新增 .c),编辑态按
is_editable 分派,LOCK(写不进去)与「未标定」(仍可改值)两源两通道两词。

记录面:syslog_request_clear/state/apply 三段式删除 API(UI 只发请求,落地在
defaultTask 的 drain 尾部且必须后置,卷锁一律 try,幂等只认 FR_NO_FILE);
事故/告警/启动/操作/遥控五类各有一个真实写入点,记录类型 = 日志 ID 本身
(一类一个 /log 严格 8.3 文件;64B 定长体没有类型字段位,塞字段会砸掉既有读者)。
为守 protectTask 872 B 静态最坏链另拆 syslog_post_quiet()(无 DBG 的投递核,
丢弃留痕挪到 drain 侧差值补发),syslog_post 对外语义逐字不变。

为什么两道合成一笔而不是各一笔(实测,不是省事):simulator/main.c 同时消费
两道新增 API(整定 pump 与 logtest 清除用例),按道切文件会让中间提交编不过;
RAM 受管快照与体积同码凭证描述的是合并后的 .map,拆开必落在「台账与 .map 不同
码」这条红线上。pre-commit 跑钩子前会 stash 未 staged 部分,这类耦合没法绕。

实测:@build 0 错误 0 警告;Code 228,260 / RO 24,960 / RW 1,440 / ZI 135,976 B;
RW_IRAM1 79,992 B = 61.0%、RW_CCM 87.9%(阈值 92%);九个任务静态最坏链全 PASS,
protectTask 872 B / 57% 改前后逐字节不变(记录投递没垫栈)。主机单测 ui_data 82→
164、sys_log_mcu 106→137、prot_elm 47→60、iec104 141→154、iec104_serv 28→34,
既有断言零删改;48 个钩子 --all-files 全绿;编号门禁可判定 86.34%(基线 86.0%)、
不可判定 1,153 处低于上限 1,166;doc-links 无法判定 0;UI 黄金 18 页扩到 27 页
连跑两次逐字节一致;字库 diff 空。

顺手修掉三处既有缺陷(都是本轮第一个消费者才暴露):sim_syslog.c 的 s_paths 行宽
16 而 "sim_selftest.log" 正好 16 字符没有 NUL 位(stat/remove 读越过数组尾,此前
靠后面 .rodata 碰巧为 0);ui_w_setlist 二态行 ENTER 不回绕(控制字与软压板出厂值
全在最后一项,按了像没反应而叠层里已是越界值);生成物 ui_menu_tab.h 与 gen_menu.py
模板漂移(上一笔改了模板没重跑生成器),现随生成器输出对齐。

未收口(不算完成):保存后重启值保持与主站 C_RD 读回两条只能上板,台架窗口执行;
LOCK 屏显与越界反显的页面侧在模拟器造不出来(模拟器不跑定值自检、无 NAND),
已由生成侧单测与代码注释点名差距;同类页数与钩子数陈述残留另立待办。
2026-10-26 15:51:12 +08:00

171 lines
9.9 KiB
C
Raw Permalink 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_setview)
* 模块功能:参数 / 定值 / 控制字 / 软压板**四张视图表**与它们的取数、越界反显——
* 把"40 项定值怎么分组上屏、Q10 怎么换算成带小数位的显示值"收在一处,
* 供四个查看页薄跳板(ui_page_view_*)共用;**同一批表**再经
* ui_w_setview_attach_edit() 供整定页复用(道F task-2 已落:查看与整定
* 只差绑不绑 set/commit/state)。行表只有一份,界内界外就不会两套口径
* 写方向:整定页的"保存"经 Drivers/BSP/UI/ui_data.h 的 param_request 投递
* (位图 + Q10 批量请求,队列深度 4),执行与落盘在 App 侧——本模块
* 仍然零 App include:越界与否、写不写得进去都由快照层回读
* 分层:本模块只读 Drivers/BSP/UI/ui_data.h 的参数快照,**不 include 任何 App 头**
* (行表里的 id 是**裸数字** + 注释标注 PS_* 名,因为 prot_set_id_t 属 App 层)
* ——id 与 App/algo/prot_set.h 枚举序的一致性由 test/host/ui_data 的主机单测
* 在两侧头文件同时可见的地方钉住(BSP 侧看不到 App 头,物理上无法自证)
* 值语义:q10[i] = 工程量 × 1024(App/app/ui_data_feed.c 只搬原值不换算,换算属表现层,
* docs/UI设计/UI_数据供给设计说明.md §8),本模块按行表 decimals 换算成
* "工程量 × 10^decimals" 交给 ui_w_setlist(其值通道契约)
* 适用平台:STM32F407ZGTx / PC 模拟器(共用源码)
* 作者:王建锋
* 创建日期:2026-10-25
* 修改记录:
* v1.0 2026-10-25 王建锋 创建(道E task-15 批 3;规格 =
* docs/UI设计/页面扩充详细方案.md §3.2.1~§3.2.3/§3.2.6)
* v1.1 2026-10-26 DTU 项目组 道F task-2:新增整定侧三件事——attach_edit
* (改动位图叠层 + 只提交改动 id + 保存态锁存)、
* key 转发(两态统一门)、标题"未标定"徽标;
* 四张行表与查看路径逐字未变(像素零变化)
*/
#ifndef UI_W_SETVIEW_H
#define UI_W_SETVIEW_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdint.h>
#include "ui_w_setlist.h"
/* 四个视图编号 */
typedef enum {
UI_W_SETVIEW_PARAM = 0, /* 参数视图 8 行(PT/CT 额定 + 4 个返回系数) */
UI_W_SETVIEW_SET, /* 定值视图 18 行(电流/电压/频率/延时) */
UI_W_SETVIEW_WORD, /* 控制字视图 4 行(*_TRIP:告警/跳闸) */
UI_W_SETVIEW_PLATE, /* 软压板视图 10 行(*_EN + 保护总投:投入/退出) */
UI_W_SETVIEW_VIEWS /* 哨兵 = 视图个数(不是有效视图号) */
} ui_w_setview_t;
/*
* 函数功能:绑定一个查看视图到定值表实例(rows/count/get/bad 一次配齐)
* 入口参数:a_inst - 页面持有的实例(static,一页一份) ui_w_setlist_t *
* a_view - 视图编号 ui_w_setview_t
* 返回值:无
* 限定条件:页面 init_cb 内调用(uiTask 上下文)
* 函数说明:查看视图与整定视图的**唯一**差别就是这里绑不绑 set/commit/state:
* commit=NULL → 组件不画保存行、ENTER 无效(§3.2.6 查看列口径);
* set 契约写"必填",故绑一个空实现而不是 NULL——组件在只读态确实不会调它,
* 但把"当前不会调"当成"可以是 NULL"等于把安全性押在下一次重构上
*/
void ui_w_setview_attach(ui_w_setlist_t *a_inst, ui_w_setview_t a_view);
/*
* 函数功能:把一个**整定**视图绑到定值表实例(行表与 attach 同一批,另绑
* set/commit/state 三个回调 —— 组件据此画保存行并放开编辑)
* 入口参数:a_inst - 页面持有的实例 ui_w_setlist_t *
* a_view - 视图编号 ui_w_setview_t
* 返回值:无
* 限定条件:页面 init_cb 内调用,且**只在 ui_content_page_is_editable() 为真时**调
* (只读权限走 attach,本函数根本不该被绑上)
* 函数说明:整定与查看的唯一差别就是绑不绑这三个回调(§3.2.6 口径)。三个新增点:
* 1. 编辑叠层:改动位图 s_wch + 工作值表 s_wq(工程量 × 10^dec),
* get 优先读叠层、未改的行跟随参数帧 —— 用户改到一半退出页面即弃稿
* (ESC 关页不投递,同 net_cfg);开页 attach 一律清稿,不带上次的改动
* 2. 提交只投**改动位图内的 id**(绝不从显示值回提全表):Q10 存不下
* 0.95 这类返回系数(真存 972/1024),按显示域往返会把用户没动的项
* 顺手改掉——"越界值不落盘"与"改哪条只落哪条"两条判据都靠这个 mask
* 3. 保存行显示态由 sv_state() 锁存(见 .c 内 s_disp 的注),
* 闭锁 → LOCK(组件据此禁 ENTER),未标定 → 标题右侧徽标(下面那个)
*/
void ui_w_setview_attach_edit(ui_w_setlist_t *a_inst, ui_w_setview_t a_view);
/*
* 函数功能:整定/查看两态统一的按键转发(页面 key_cb 一行转过来即可)
* 入口参数:a_inst - 已 attach 的实例 ui_w_setlist_t *
* a_key - LVGL 键值 lv_key_t
* 返回值:1 - 本页已消费(框架跳过内置);0 - 交回框架(↑↓ 移选、← 关页)
* (键分发标志非错误通道,取 uint8_t——BSP 公开 API 的 err-type 约定)
* 限定条件:uiTask 按键链内(框架 key_cb)
* 函数说明:门在这里而不是散在四个页面文件里,为的是"四页同一条规矩":
* 1. 只读视图(未绑 commit)一律交回框架 —— 查看页按键行为逐字不变,
* 这是"绑了 key_cb 也不会动像素"的依据(黄金用例 vparam~vplate 仍绿)
* 2. 参数帧未就位时**不接受任何写交互**:值列此刻打的是 "--",
* 拿 "--" 去 begin 编辑等于把"还不知道"当成 0 让人改,改完还能投出去
*/
uint8_t ui_w_setview_key(ui_w_setlist_t *a_inst, lv_key_t a_key);
/*
* 函数功能:整定页标题右侧画"未标定"徽标(未标定闭锁的屏上表达)
* 入口参数:a_layer - 绘制层 lv_layer_t *
* a_clip - 重绘区 const lv_area_t *
* 返回值:无
* 限定条件:页面 draw_cb 内调用(框架内置区块之后);三个条件全满足才落墨:
* 当前是整定视图(attach_edit)+ 参数帧已就位 + par.cal_block 非 0
* 函数说明:为什么值得占标题带一个角:整定页的存在就是"让用户改保护定值",
* 而产品构建下 UA/UN/IA 未标定 → 判据恒停走 → **改完也不会动作**。
* 不写这件事,页面就是在暗示"改了就算数"(UI补齐.md §4 末段"保护闭锁
* 必须可见";口径 docs/任务规划/数据可信.md §4.3)。
* ⚠ 与保存行的 LOCK 是两件事:LOCK = 定值闭锁(写不进去、禁编辑),
* 徽标 = 未标定(仍可改,只是判据停走)——合成一个词就等于互相冒充。
* ⚠ 查看页不画(s_edit=0):那四页是既有黄金参考,像素零变化是硬约束
*/
void ui_w_setview_draw_cal_badge(lv_layer_t *a_layer, const lv_area_t *a_clip);
/*
* 函数功能:按发布序号取参数帧快照(页面 refresh 前调用)
* 入口参数:无
* 返回值:无
* 限定条件:uiTask 上下文(页面绘制链内)
* 函数说明:序号没变就不重拷(一帧约 184 B;四个查看页共用这一份缓存——同屏只可能
* 开着一页,缓存互相之间不存在并发读者)
*/
void ui_w_setview_sync(void);
/*
* 函数功能:参数帧是否已就位
* 入口参数:无
* 返回值:1 = 有有效帧可显示;0 = 尚无首帧或读取失败 uint8_t(取 uint8_t 是 BSP 公开
* API 的 err-type 约定,不是错误通道;定义处有完整理由)
* 限定条件:uiTask 上下文;纯查询,无副作用
* 函数说明:页面据此决定值列打 "--" 还是打换算值——**无数据不许打 0**:
* "0.00A" 会被读成"这台装置的定值就是 0",与"还不知道"是两件事
*/
uint8_t ui_w_setview_ready(void);
/*
* 函数功能:逐行取数(接框架 refresh;内含 ui_w_setview_sync() 与无帧占位)
* 入口参数:a_inst - 已 attach 的实例 ui_w_setlist_t *
* a_row - 全局行下标 uint16_t
* a_name - 名输出缓冲(UI_BUF_STRLEN) char *
* a_value - 值输出缓冲 char *
* 返回值:无
* 限定条件:框架绘制链内调用(uiTask)
* 函数说明:页面**不要**直接调 ui_w_setlist_refresh()——那样会绕过"无帧打 --"
* 这一步,参数帧还没到就把 0 当成定值显示出去
*/
void ui_w_setview_refresh(ui_w_setlist_t *a_inst, uint16_t a_row,
char *a_name, char *a_value);
/*
* 函数功能:取某视图的行表与行数(供主机单测做结构自测;页面正常不需要调用)
* 入口参数:a_view - 视图编号 ui_w_setview_t;a_n - 行数输出(不可为 NULL) uint16_t *
* 返回值:行表首地址;视图号非法或 a_n 为空返回 NULL const ui_w_setlist_row_t *
* 限定条件:只读
*/
const ui_w_setlist_row_t *ui_w_setview_table(ui_w_setview_t a_view, uint16_t *a_n);
/*
* 函数功能:取 id → 显示小数位查表(供主机单测核对行表与查表一致)
* 入口参数:a_n - 表长输出(= UI_DATA_SET_N) uint16_t *
* 返回值:表首地址 const uint8_t *
* 限定条件:只读
*/
const uint8_t *ui_w_setview_dec_table(uint16_t *a_n);
#ifdef __cplusplus
}
#endif
#endif /* UI_W_SETVIEW_H */