UI 内容页框架加实时页自动刷新机制(交流量页启用,300ms)
- ui_content_page:描述符尾部追加 auto_ms/auto_seq 可选字段(缺省=0/NULL= 旧行为逐位不变);页打开期间框架持一只 lv_timer,仅当发布序号变过才整页 失效(零空转失效),关页即销;新 API ui_content_page_auto_poll - ui_page_ac.c:.auto_ms=300(≥200ms 发布节拍、避 400=2×200 锁相、300= 15×20ms LVGL 整刷周期;最坏屏上滞后 500ms;完整取值账目在代码注释) - simulator:rt 帧装配收口 sim_fill_rt_frame(n=0 冻结帧保 74 张黄金逐字节 一致,n≥1 确定性斜坡);新增 --rtlive 两态自检 + 窗口模式 200ms 节拍发布; check_content_pages.py 增 [rtlive] 零按键 A≠B 落屏断言 - docs/UI设计:供给说明新增 §5.5 自动刷新口径;内容页架构 §3.1/§四/§九 同步 (并修正 s_open 判定旧描述) - 台账:Keil 构建后按固定顺序回填(Code=256,588 / RW_IRAM1 +8B / UI +8B) 验证:模拟器 0错0警;菜单 8 状态 + 内容页 74 张 + rtlive(A≠B 30 字节)PASS (lead 独立复跑 RC=0);Keil 0错0警;mem-budget --gate / mem-numbers --scan 绿。
This commit is contained in:
@@ -340,6 +340,26 @@ static void pg_refresh(uint16_t row, char *name, char *value) {
|
||||
|
||||
> 用 `ui_data_rt_seq()` 门控而不是"row==0 才刷新",是为了避免依赖"框架总从第 0 行开始绘制"这一隐式时序假设——框架换绘制顺序时页面不会静默出错。
|
||||
|
||||
### 5.5 框架级自动失效(实时页不靠按键也有新数)
|
||||
|
||||
§5.4 的 seq 门解决"取数不冗余",不解决"什么时候该重绘":框架旧行为是**按键触发绘制才走 `refresh()`**——`rt` 帧每 200 ms 在发,人停在「交流量」页不动按键,屏上数值就是冻结的。
|
||||
|
||||
新机制(task-2):`content_page_def_t` 尾部新增两个可选字段,定时器由**框架 `ui_content_page` 统一持有**(开页创建、关页销毁,同时最多一只),页面模块禁止自造轮询定时器:
|
||||
|
||||
| 字段 | 语义 |
|
||||
|---|---|
|
||||
| `uint16_t auto_ms` | 0 = 关闭(保持旧行为;指定初始化未写即 0);>0 = 该页打开期间的轮询周期 |
|
||||
| `uint32_t (*auto_seq)(void)` | 新鲜度来源;NULL(缺省)= `ui_data_rt_seq()`;读 `info` 通道的页面可填 `ui_data_info_seq()` |
|
||||
|
||||
每拍框架调 `ui_content_page_auto_poll()`(回调经 uiTask 主循环 `lv_timer_handler` 触发,与绘制钩子同上下文):**序号变了才整页失效,没变零动作**——不拷帧、不失效、不重绘,稳态开销与旧行为一致;取数门控仍走 §5.4 的页面私有 seq 缓存,失效只是把"下次按键才有机会读新帧"变成"到点就有机会读新帧"。
|
||||
|
||||
当前口径:
|
||||
|
||||
- **已启用**:`ac` 交流量页 `.auto_ms = AC_AUTO_MS`(300 ms;250~500 ms 允许区间的取值账目详述在 `ui_page_ac.c` 的 `AC_AUTO_MS` 注释——要点:轮询不得快于 200 ms 发布节拍、避开 400 ms 与其锁相、300 = 15 × LVGL 整刷周期 20 ms(两端 `LV_DEF_REFR_PERIOD` 同值),最坏屏上滞后 200 + 300 = 500 ms)。
|
||||
- **不迁移**:待机屏 `ui_standby.c`(自持 1 s 整屏定时器 + seq 门控)、整定视图 `ui_w_setview.c`(`sv_poll` 定时器盯 `par` 通道)——两处各自已有节拍,纳入框架只会多一只定时器。
|
||||
- **未接入(待 lead/用户裁定)**:`dc`/`yx`/`clock`(读 `rt`)与 `device_info`/`runreport`(读 `info`)仍是"按键才取新数";接入只差描述符一行 `.auto_ms`(info 页另加 `.auto_seq`)。
|
||||
|
||||
**回归确定性**:无头模式(`--keys`/74 张黄金参考)从不跑 `lv_timer_handler`,定时器不可能在截屏前触发,且仿真仍是"一次发布冻结帧"——黄金参考逐字节不变(`check_content_pages.py` 实证)。自动失效路径的验证走新开关 `--rtlive <键序> <A.bin> <B.bin>`:开页截 A → 发布第 1 号确定性斜坡帧 → **直接调用** `ui_content_page_auto_poll()`(等价定时器到点)→ 截 B;A≠B 即证明"零按键、新帧落屏"。窗口模式(真机行为仿真)每 200 ms 发一帧斜坡值,屏上数值自己会走。
|
||||
---
|
||||
|
||||
## 6. 写路径(定值整定)
|
||||
|
||||
+14
-3
@@ -96,15 +96,19 @@ flowchart TD
|
||||
| `bool ui_content_page_open(id)` | 开页 | ① 查 `s_defs[id]`:NULL → 打 `ERROR` 日志并返回 false(枚举/表漂移防护)② `lv_obj_create(NULL)` 建屏 + 全屏容器(flat 常量样式 + `IGNORE_LAYOUT` + `CLICK_FOCUSABLE`)③ 容器**先**入默认输入组并获焦 ⓸ `lv_screen_load` 切屏 |
|
||||
| `void ui_content_page_close()` | 关页 | ① 焦点**先**回菜单持久容器(防输入组焦点悬空)② 切回菜单屏(菜单屏对象未动,原样还原)③ 再删容器+屏,池内存回落 |
|
||||
| `void ui_content_page_invalidate()` | 整页重绘 | 失效页面容器;供表单/操作页自身状态变化后调用(无页打开时空操作) |
|
||||
| `bool ui_content_page_is_open()` | 查询 | `s_open != CONTENT_PAGE_COUNT` |
|
||||
| `void ui_content_page_auto_poll()` | 自动失效轮询 | 供框架定时器(`auto_ms>0` 的页打开期间才存在)每拍调用:发布序号(`auto_seq()`,NULL = `ui_data_rt_seq()`)与上一拍不同才整页失效,没变零动作;无页打开 / `auto_ms=0` 时空操作。模拟器 `--rtlive` 直接调它做确定性验证(机制见 `UI_数据供给设计说明.md` §5.5) |
|
||||
| `bool ui_content_page_is_open()` | 查询 | `s_open != NULL` |
|
||||
|
||||
框架持有的运行状态(全部 4 个变量,约 20 B):
|
||||
框架持有的运行状态(基础 5 个 + 自动失效 2 个,与 ui_content_page.c 静态块一致):
|
||||
|
||||
```c
|
||||
static content_page_id_t s_open; /* 当前打开的页(CONTENT_PAGE_COUNT = 未打开) */
|
||||
static const content_page_def_t *s_open; /* 当前打开页的描述符(NULL = 未打开) */
|
||||
static uint16_t s_sel; /* 列表页选中行(全局下标,跨页连续;每次进入清零) */
|
||||
static uint8_t s_perm; /* 本次开页授予的权限(ui_perm_t;开页时装载,关页重置) */
|
||||
static lv_obj_t *s_scr; /* 页面屏幕(进入时建、返回时毁) */
|
||||
static lv_obj_t *s_cont; /* 页面全屏容器(焦点/键入口 + 自绘载体) */
|
||||
static lv_timer_t *s_auto_timer; /* 自动失效轮询定时器(仅 auto_ms>0 的页打开期间存在;关页即销) */
|
||||
static uint32_t s_auto_seq; /* 上一拍见到的发布序号(开页时装基准,开页本身不多刷一帧) */
|
||||
```
|
||||
|
||||
### 3.2 页面生命周期:一次 ENTER → 一次 ESC
|
||||
@@ -249,6 +253,9 @@ typedef struct {
|
||||
uint16_t (*count_cb)(void); /* 动态行数(记录页) */
|
||||
void (*draw_cb)(lv_layer_t *layer, const lv_area_t *clip); /* 表单/操作页:自定义内容 */
|
||||
bool (*key_cb)(lv_key_t key); /* 页面自有键;true = 页已处理 */
|
||||
/* —— 自动失效轮询(auto_ms=0 = 只在按键重绘,未订阅页行为逐位不变;见 UI_数据供给设计说明.md §5.5)—— */
|
||||
uint16_t auto_ms; /* 轮询周期(ms);0 = 不启用自动刷新 */
|
||||
uint32_t (*auto_seq)(void); /* 新鲜度序号源;NULL = ui_data_rt_seq() */
|
||||
} content_page_def_t;
|
||||
```
|
||||
|
||||
@@ -273,6 +280,7 @@ typedef struct {
|
||||
| `rows` | `const cp_row_t *` | 静态数据表(Flash) | 6 行 | 24 行 | 3 行 | NULL |
|
||||
| `fixed_cur_page` / `fixed_total_pages` | `uint8_t` | 信息页页脚固定值 | 10 / 1 | — | — | — |
|
||||
| `refresh` / `count_cb` / `draw_cb` / `key_cb` | 函数指针 | 扩展钩子 | 全 NULL | 全 NULL | 全 NULL | draw_cb + key_cb(余 NULL) |
|
||||
| `auto_ms` / `auto_seq` | `uint16_t` / 函数指针 | 自动失效轮询周期 / 新鲜度源(`UI_数据供给设计说明.md` §5.5) | 0 / NULL | **300 / NULL** | 0 / NULL | 0 / NULL |
|
||||
|
||||
扩展钩子(机制已实现;密码页用 `draw_cb` + `key_cb`,其余 3 页未用):
|
||||
|
||||
@@ -283,6 +291,8 @@ typedef struct {
|
||||
| `draw_cb` | `void (lv_layer_t *layer, const lv_area_t *clip)` | 绘制链末尾(内置区块之后) | 表单/操作页自定义内容 |
|
||||
| `key_cb` | `bool (lv_key_t key)` | 键分发时(ESC 之后、内置 ↑↓ 之前) | 页面自有键(ENTER 确认等);返回 true = 页已处理 |
|
||||
|
||||
> 自动失效(`auto_ms`/`auto_seq`)**不是页面钩子**:定时器、轮询节拍与序号比较全在框架(`ui_content_page_auto_poll`),页面只声明周期与可选序号源;口径见 `UI_数据供给设计说明.md` §5.5。
|
||||
|
||||
### 4.1 表单/操作页首个应用:密码页(已落地)
|
||||
|
||||
实机(淮源电力 F30)已有"用户密钥"页:进入某些子叶面前须先输入密码(实机照片见
|
||||
@@ -493,3 +503,4 @@ extern const content_page_def_t ui_page_device_info_desc; /* 描述符(Flash
|
||||
| 2026-10-26 | 验证与回归段的页数口径修正为 **27 页**黄金参考(`simulator/tests/ref/` 入库 27 个 `shot_*.bin`,含整定 9 态);上方变更记录里的「11 页」是当时事实不动 |
|
||||
| 2026-10-26 | 门禁常量修正为 5368 B / 5448 B(= 两个回归脚本头部现值);本文件正文表早已是 5368/5448,只这一处残留 2026-10-11 裁剪 LVGL 控件类之前的 4784/4864 |
|
||||
| 2026-10-26 | 验证与回归段的黄金参考页数 **27 → 40 页**(UI 三页落地后 `simulator/tests/ref/` 实数 40 张);上方变更记录里的 11 / 27 是各当时下限,保留 |
|
||||
| 2026-11-13 | 框架级自动失效(task-2):描述符尾部新增 `auto_ms`/`auto_seq`(当前仅 ac 页启用 300 ms),新增框架 API `ui_content_page_auto_poll()`(§3.1);§3.1 静态块与代码同步(补 `s_perm` 与自动失效 2 变量);回归脚本新增 `--rtlive` 零按键落屏检查(74 张黄金参考逐字节不变,实测 PASS);机制详述在 `UI_数据供给设计说明.md` §5.5 |
|
||||
|
||||
@@ -47,10 +47,10 @@ dhara 失败类 +84;RO 另 +208,全是该失败类名表)→ `ER_IROM1`
|
||||
<!-- MEM_SNAPSHOT:BEGIN generated by scripts/check_mem_numbers.py -->
|
||||
| 区域 | 用量 | 容量 | 占比 |
|
||||
|---|---|---|---|
|
||||
| ER_IROM1 | 288,148 B (281.39 KB) | 1,048,576 B (1024 KB) | 27.5% |
|
||||
| RW_IRAM1 | 97,240 B (94.96 KB) | 131,072 B (128 KB) | 74.2% |
|
||||
| ER_IROM1 | 288,624 B (281.86 KB) | 1,048,576 B (1024 KB) | 27.5% |
|
||||
| RW_IRAM1 | 97,248 B (94.97 KB) | 131,072 B (128 KB) | 74.2% |
|
||||
| RW_CCM | 57,376 B (56.03 KB) | 65,280 B (64 KB) | 87.9% |
|
||||
| **Flash (ROM 合计)** | **290,228 B (283.4 KB)** | 1,048,576 B (1024 KB) | **27.7%** |
|
||||
| **Flash (ROM 合计)** | **290,712 B (283.9 KB)** | 1,048,576 B (1024 KB) | **27.7%** |
|
||||
<!-- MEM_SNAPSHOT:END -->
|
||||
|
||||
各区的容量与常量来源:
|
||||
|
||||
@@ -15,16 +15,16 @@
|
||||
<!-- MEM_BUDGET:BEGIN generated by scripts/ram_baseline.py -->
|
||||
| 区域 | 用量 | 容量 | 占比 | 门禁(≤92%) |
|
||||
|---|---|---|---|---|
|
||||
| ER_IROM1 (Flash) | 288,148 B | 1,048,576 B | 27.5% | 参考 |
|
||||
| ER_IROM1 (Flash) | 288,624 B | 1,048,576 B | 27.5% | 参考 |
|
||||
| RW_CCM | 57,376 B | 65,280 B | 87.9% | PASS |
|
||||
| UNINIT_CCM | 48 B | 256 B | 18.8% | 参考 |
|
||||
| RW_IRAM1 | 97,240 B | 131,072 B | 74.2% | PASS |
|
||||
| RW_IRAM1 | 97,248 B | 131,072 B | 74.2% | PASS |
|
||||
|
||||
| 子系统(静态 RW+ZI;除 RTOS 堆在 CCM 外均在 SRAM1) | 现值 | 配额 | 状态 |
|
||||
|---|---|---|---|
|
||||
| 网络 | 13,958 B | 12 KB | ⚠ 超 1.6 KB |
|
||||
| 存储 | 9,144 B | 12 KB | OK |
|
||||
| UI | 36,723 B | 16 KB | ⚠ 超 19.9 KB |
|
||||
| UI | 36,731 B | 16 KB | ⚠ 超 19.9 KB |
|
||||
| RTOS 堆 | 57,376 B | 56 KB | 堆=配额 |
|
||||
| 应用 | 26,609 B | 8 KB | ⚠ 超 18.0 KB |
|
||||
| 其它 | 10,792 B | — | 参考 |
|
||||
|
||||
Reference in New Issue
Block a user