Files
STM32F4-Base/Drivers/BSP/UI/ui_w_setlist.h
T
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

215 lines
11 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_setlist)
* 模块功能:把"参数/定值/控制字/软压板"四类视图的列表渲染与整定输入抽象成
* 一份实现——行表 + 数据回调注入(取数/写工作副本/提交/状态回读/
* 越界行查询),同一份组件供多个页面实例复用:
* 查看视图(commit=NULL:无保存行、ENTER 无效)与整定视图
* (commit 非空:末行固定为"保存"行,ENTER 投递整表提交)只差绑定;
* 数值行走 ui_w_editor 逐位编辑(范围校验提交),二态文字行
* (控制字"告警/跳闸"、软压板"投入/退出")ENTER 直接切换;
* 保存失败后的越界行经 bad 回调反显高亮;
* 分页跟随内容页框架内置(8 行/页,UI_LIST_ROWS)
* 适用范围:Drivers/BSP/UI(标准列表页骨架几何:UI_LIST_TOP/ROW_PITCH/
* ROW_BAND_H/LIST_ROWS/RIGHT_X 令牌;页面描述符须 selectable=1、
* key_intercept=1、rows_per_page=UI_LIST_ROWS、text_dy=0)
* 说明:数据绑定全部经回调注入(批 2 ui_data/prot_set 交接时由页面薄跳板
* 提供实现),组件不 include 任何 App 头(分层门禁方向);
* 实例化使用——每个页面文件 static 一份实例,钩子包一层 &inst 转调
* (同 ui_w_records 模式)
* 作者:王建锋
* 创建日期:2026-10-25
* 修改记录:
* v1.0 2026-10-25 王建锋 创建(道B task-5;规格 = 页面扩充详细方案.md
* §3.2 四视图表/§3.2.6 查看与整定差别/§3.2.7 编辑
* 交互/§4.2 bind 要点;保存行 ENTER/WAIT/OK/ERR
* 沿用 ui_page_net_cfg 交接显示先例)
* v1.1 2026-10-26 DTU 项目组 道F task-2(整定 4 页):态枚举尾追加 LOCK
* (值列显 LOCK + ENTER 不消费 = 闭锁禁编辑);
* 查看视图不绑 commit/state,走不到新分支,
* 四张查看页像素零变化(黄金用例 vparam~vplate 为证)
*/
#ifndef UI_W_SETLIST_H
#define UI_W_SETLIST_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdint.h>
#include "ui_content_page.h" /* lvgl(lv_key_t/lv_layer_t)+ 框架类型 */
#include "ui_w_editor.h"
/* 保存交接显示态(值列 ENTER/WAIT/OK/ERR/LOCK,与 net_cfg 保存行同字面)
* ⚠ 新增态一律**尾追加**:前四个值按序被各页与先例使用,中间插入会把后续态的
* 数值整体挪位——数值挪位在 C 里不报错,只会让屏上的词换成另一个词 */
typedef enum {
UI_W_SETLIST_ST_IDLE = 0, /* 空闲:保存行显示 ENTER */
UI_W_SETLIST_ST_WAIT, /* 请求已投递、属主任务处理中:WAIT */
UI_W_SETLIST_ST_OK, /* 上轮提交成功:OK */
UI_W_SETLIST_ST_FAIL, /* 上轮提交失败:ERR */
UI_W_SETLIST_ST_LOCK /* 定值闭锁(= par.locked,校验和自检失败):值列 LOCK
* 且**禁编辑**(组件见 LOCK 即不消费 ENTER)。
* ⚠ 与「未标定」是两件事、屏上两条通道:未标定
* (= par.cal_block)仍可改定值、只是判据停走,
* 用标题右侧徽标表达;LOCK 才是"写不进去"。
* 三词三源 → docs/任务规划/数据可信.md §4.3 */
} ui_w_setlist_st_t;
/* 行种类 */
#define UI_W_SETLIST_KIND_NUM 0u /* 数值行:ui_w_editor 逐位编辑(min/max/decimals 有效) */
#define UI_W_SETLIST_KIND_ENUM 1u /* 二态文字行:ENTER 在 opts 串表内循环切换 */
/*
* 视图行描述(Flash const 表,一行一条)
* 值通道统一 int32_t 定点:
* 数值行 = 工程量 * 10^decimals(如 10.24 A -> 1024)
* 二态行 = opts 串表下标(0/1/...)
*/
typedef struct {
const char *name; /* 中文名 <= 7 字(字体子集已预置) */
uint8_t id; /* 应用侧枚举 ID:组件只透传给回调,不解释语义 */
uint8_t kind; /* UI_W_SETLIST_KIND_NUM / _ENUM */
uint8_t decimals; /* 数值行小数位 0..3(二态行忽略) */
int32_t min; /* 数值行下限(含;>=0;二态行忽略) */
int32_t max; /* 数值行上限(含;二态行忽略) */
const char *const *opts; /* 二态行:NUL 结尾 Flash 字符串串表(数值行 NULL) */
const char *unit; /* 数值行单位后缀(Flash,NULL = 不挂;二态行忽略)
* 单位是"屏上的话",跟视图表走、不进 App 快照;只挂在
* 非编辑态的数值串尾——编辑中是逐位输入串,挂单位会让
* ui_w_editor 的位光标算错列宽(其契约:串内只有数字与点) */
} ui_w_setlist_row_t;
/* 数据回调组(均 uiTask 上下文、页面绘制/按键链内调用;实现由批 2 页面跳板提供,
* 组件不 include 任何 App 头——数据绑定经此注入) */
/*
* 函数功能:读某行当前值(数值行 = 工程量 * 10^decimals;二态行 = 串表下标)
* 入口参数:id - 行表登记的枚举 ID uint8_t
* 返回值:当前值 int32_t
*/
typedef int32_t (*ui_w_setlist_get_fn)(uint8_t a_id);
/*
* 函数功能:写某行 RAM 工作副本(不写盘;落盘统一经 commit 整表提交)
* 入口参数:id - 行枚举 ID uint8_t
* val - 新值(口径同 get) int32_t
* 返回值:无
*/
typedef void (*ui_w_setlist_set_fn)(uint8_t a_id, int32_t a_val);
/*
* 函数功能:整表提交(一次封存一次校验和;实现只投递请求到属主任务,不阻塞)
* 入口参数:无
* 返回值:无(投递结果经 state 回调回读)
*/
typedef void (*ui_w_setlist_commit_fn)(void);
/*
* 函数功能:保存交接态回读(保存行值列显示源)
* 入口参数:无
* 返回值:当前交接态 ui_w_setlist_st_t
*/
typedef ui_w_setlist_st_t (*ui_w_setlist_state_fn)(void);
/*
* 函数功能:查询某数据行是否为"保存失败越界行"(需反显高亮)
* 入口参数:row - 数据行下标(不含保存行) uint16_t
* 返回值:true = 需反显;false = 正常(提问谓词,非错误通道) bool
*/
typedef bool (*ui_w_setlist_bad_fn)(uint16_t a_row);
/*
* 定值表实例
* 用法(页面跳板示例,批 2):
* static ui_w_setlist_t s_sl = { .rows = s_rows, .count = N, .get = get, ... };
* count_cb -> ui_w_setlist_count(&s_sl)
* refresh -> ui_w_setlist_refresh(&s_sl, row, name, value)
* key_cb -> ui_w_setlist_key(&s_sl, key)
* draw_cb -> ui_w_setlist_draw(&s_sl, layer, clip)
* init_cb -> ui_w_setlist_reset(&s_sl)
*/
typedef struct {
const ui_w_setlist_row_t *rows; /* Flash 行表 */
uint16_t count; /* 数据行数(不含保存行) */
ui_w_setlist_get_fn get; /* 必填 */
ui_w_setlist_set_fn set; /* 必填(整定提交前的 RAM 副本写入口) */
ui_w_setlist_commit_fn commit; /* NULL = 查看视图(无保存行、禁编辑) */
ui_w_setlist_state_fn state; /* NULL = 保存行恒显示 ENTER */
ui_w_setlist_bad_fn bad; /* NULL = 不做越界行反显 */
ui_w_editor_t ed; /* 数值编辑实例 */
uint16_t ed_row; /* 编辑中行下标(仅 editing 时有效) */
} ui_w_setlist_t;
/*
* 函数功能:开页复位(清编辑态;接页面 init_cb)
* 入口参数:inst - 定值表实例 ui_w_setlist_t *
* 返回值:无
* 限定条件:无
*/
void ui_w_setlist_reset(ui_w_setlist_t *a_inst);
/*
* 函数功能:总行数(接框架 count_cb:数据行 + 保存行[仅整定视图])
* 入口参数:inst - 定值表实例 const ui_w_setlist_t *
* 返回值:总行数 uint16_t
* 限定条件:rows 非空(空表防御返回 0)
*/
uint16_t ui_w_setlist_count(const ui_w_setlist_t *a_inst);
/*
* 函数功能:逐行取数(接框架 refresh:名 = 行表、值 = 回调读/编辑器实时串/保存态)
* 入口参数:inst - 定值表实例 ui_w_setlist_t *
* row - 全局行下标 uint16_t
* name - 名输出缓冲(UI_BUF_STRLEN) char *
* value - 值输出缓冲(同上) char *
* 返回值:无
* 限定条件:页面打开(框架绘制链内调用)
* 函数说明:编辑中行的值列显示编辑器当前串(实时随 ↑↓ 变,同 net_cfg);
* 保存行(最后一行、整定视图)值 = ENTER/WAIT/OK/ERR(state 回调)
*/
void ui_w_setlist_refresh(ui_w_setlist_t *a_inst, uint16_t a_row,
char *a_name, char *a_value);
/*
* 函数功能:按键处理(接框架 key_cb;配合描述符 key_intercept=1 转发 LEFT)
* 入口参数:inst - 定值表实例 ui_w_setlist_t *
* key - LVGL 键值 lv_key_t
* 返回值:1 = 已消费(框架跳过内置);0 = 交回框架(↑↓ 移选、← 关页等)
* (键分发标志非错误通道,取 uint8_t——BSP 公开 API 约定)
* 限定条件:页面打开(内部经 ui_content_page_selected_row / is_editable 判态)
* 函数说明:1. 数值编辑中:↑↓ 步进 / ←→ 移位 / ENTER 提交(越界拒绝)全由
* ui_w_editor 消费;提交成功即经 set 回调写工作副本
* 2. 正常态 ENTER(可编辑权限):数值行进编辑(光标个位);
* 二态行循环切换;保存行投递整表提交(一次封存一次校验和,
* 整表提交口径见 页面补齐规划.md §3.2)
* 3. 只读权限 ENTER 一律不消费;ESC 恒关页(框架,未提交编辑丢弃,
* 已经 ENTER 提交到工作副本的调整保留、不落盘——net_cfg 先例)
* 4. 整定视图 state()==LOCK(定值闭锁)→ ENTER 同样一律不消费:
* 不进数值编辑、不切二态、不投保存——**为什么闭锁不由组件解释**,
* 它只按 state 回调给的事实收住写交互(闭锁 vs 未标定的分工见
* ui_w_setlist_st_t 的 LOCK 注);已在编辑中的那一格不强制打断,
* 但其值只落在工作副本,投递口已被 LOCK 堵住,落不了盘
*/
uint8_t ui_w_setlist_key(ui_w_setlist_t *a_inst, lv_key_t a_key);
/*
* 函数功能:自绘(接框架 draw_cb:编辑光标反显 + 保存失败越界行反显)
* 入口参数:inst - 定值表实例 ui_w_setlist_t *
* layer - 绘制层 lv_layer_t *
* clip - 重绘区 const lv_area_t *
* 返回值:无
* 限定条件:页面打开;框架内置区块(行/带/页脚)已绘完
* 函数说明:行槽 y 按标准列表骨架 + 当前页窗口换算(与框架 cp_draw_rows 同式:
* first = sel / UI_LIST_ROWS * UI_LIST_ROWS)
*/
void ui_w_setlist_draw(ui_w_setlist_t *a_inst, lv_layer_t *a_layer,
const lv_area_t *a_clip);
#ifdef __cplusplus
}
#endif
#endif /* UI_W_SETLIST_H */