feat(ui/remo): 7003 总线新增 STATUS 身份查询与 GOTO 直达页(#69)

STATUS(命令 4)一帧回答"现在在哪个画面":kind(MENU/PAGE/STANDBY)
+ 菜单路径/选中 + 页 id,布局契约与字节序见 ui_net_sink.h。由 uiTask
轮询驱动,同上下文读静态导航状态:零画面副作用、免锁、不发日志。
新增只读接口 ui_menu_get_nav_state / ui_content_page_current_desc。

GOTO(命令 5)按页 id 查生成表直开内容页,以 VIEW 权限进入(与
"已过查看密码"同档,不代输任何密码)。编译期门控
DTU_BENCH || UI_REMO_ALLOW_GOTO:产品构建恒拒(status=4),模拟器
构建默认开启便于无板验证;执行类页(clear/reset)固件侧同样拒绝
(status=2,与主机 EXEC_PAGE_IDS 同一事实源);待机中拒绝(status=5),
由主机按键唤醒后再来。成功应答带回目标叶节点下标便于对账。

ui_sink 主机单测补导航侧链接假件 + 最小 lvgl 桩(仅本测试目录)。
产品构建 Keil 0 Error 0 Warning;ui_sink 单测 17/17。
This commit is contained in:
2026-11-02 22:19:58 +08:00
parent b8e1de5f2e
commit 493fa6ba0e
13 changed files with 320 additions and 18 deletions
+14
View File
@@ -34,6 +34,8 @@
* 描述符指针、s_open 变指针(NULL = 未打开);7 个页面头包含移交
* ui_page_registry.c;日志页身份改打描述符 id(ASCII 页名,比原
* id=%u 更可定位);绘制/按键/几何一律未动
* 2026-11-02 DTU 项目组 新增 ui_content_page_current_desc(#69 板端导航身份查询:
* 页 id 从"只有串口开/关沿可见"升级为可按帧查询)
*/
/* 头文件包含区 */
@@ -599,3 +601,15 @@ uint16_t ui_content_page_selected_row(void) {
}
return s_sel;
}
/*
* 函数功能:查询当前打开页面的描述符(契约见 ui_content_page.h,Issue #69)
* 入口参数:无
* 返回值:当前页面描述符指针(Flash 常量,只读);无页打开 = NULL
* 限定条件:同上下文(uiTask)读取才有一致性语义;本函数零副作用、不打日志
* 函数说明:与 ui_content_page_is_open 的区别只在于顺带交出身份(desc->id),
* 推流 STATUS 用它把"开着哪一页"随帧带回,不再只有串口开/关沿可见
*/
const content_page_def_t *ui_content_page_current_desc(void) {
return s_open;
}
+9
View File
@@ -124,6 +124,15 @@ void ui_content_page_invalidate(void);
*/
bool ui_content_page_is_open(void);
/*
* 函数功能:查询当前打开页面的描述符(身份查询/调试消费,Issue #69)
* 入口参数:无
* 返回值:当前页面描述符指针(Flash 常量,只读);无页打开 = NULL
* 限定条件:与框架同上下文(uiTask)读取才有一致性语义
* 函数说明:消费方(推流 STATUS)据 desc->id 回答"开着哪一页";零副作用、不打日志
*/
const content_page_def_t *ui_content_page_current_desc(void);
/*
* 函数功能:查询当前打开的页面是否可编辑
* 入口参数:无
+20
View File
@@ -283,3 +283,23 @@ int ui_menu_init(void) {
(unsigned)(mon.total_size - mon.free_size));
return 0;
}
/*
* 函数功能:读取菜单导航状态(契约见 ui_menu.h,Issue #69)
* 入口参数:p_depth / p_path / p_sel - 三个只读出参,任一可为 NULL 表示不取
* 返回值:无
* 限定条件:同上下文(uiTask)读取;本函数零副作用、不打日志(每帧查询不刷日志)
* 函数说明:直接交还静态数组指针(导航状态本身仅 17 B,拷贝反而是第二份要同步的
* 事实);消费方按"深度+1"项数读取,越界由消费方的深度钳位负责
*/
void ui_menu_get_nav_state(uint8_t *p_depth, const uint8_t **p_path, const uint8_t **p_sel) {
if (p_depth != NULL) {
*p_depth = s_depth;
}
if (p_path != NULL) {
*p_path = s_path;
}
if (p_sel != NULL) {
*p_sel = s_sel;
}
}
+18
View File
@@ -11,10 +11,14 @@
* 2026-09-02 王建锋 弃用已废弃的 lv_menu 控件,改为基元控件页面导航
* 2026-09-04 王建锋 重构为"横向级联框"模型(菜单页面设计.md):拆出显示层
* ui_menu_view 与数据层 ui_menu_tab;本层只留导航状态机
* 2026-11-02 DTU 项目组 新增 ui_menu_get_nav_state(#69 板端导航身份查询:
* 主机侧不再只靠像素认屏猜"在哪一列选中哪一项")
*/
#ifndef UI_MENU_H
#define UI_MENU_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
@@ -31,6 +35,20 @@ extern "C" {
*/
int ui_menu_init(void);
/*
* 函数功能:读取菜单导航状态(身份查询/调试消费的只读快照,Issue #69)
* 入口参数:p_depth - 输出当前深度(0 = 根框) uint8_t *,可为 NULL
* p_path - 输出路径数组指针(节点下标) const uint8_t **,可为 NULL
* p_sel - 输出各层选中下标数组指针 const uint8_t **,可为 NULL
* 返回值:无
* 限定条件:与导航同上下文(uiTask/模拟器主循环)调用才有一致性语义;
* ui_menu_init() 前调用返回初始零值,不崩
* 函数说明:输出指针指向本模块静态数组(共 17 B 导航状态,见设计 §7.2),
* 调用方只读、最多读"深度+1"项(上限 MENU_PAGE_MAX)、不得改写;
* 弹框被屏裁时像素认屏看不见选带,本接口是主机侧唯一的菜单真值出口
*/
void ui_menu_get_nav_state(uint8_t *p_depth, const uint8_t **p_path, const uint8_t **p_sel);
#ifdef __cplusplus
}
#endif
+128
View File
@@ -39,6 +39,9 @@
* 在往返边界续命。钩子未注册 = 零行为变化(模拟器/黄金
* 回归不注册)。判读与设计口径见
* docs/UI设计/UI_设计架构.md §5.8
* 2026-11-02 DTU 项目组 #69:新增 STATUS(4) 身份查询应答(kind+菜单路径/选中+页 id,
* v1 契约在 ui_net_sink.h)与 GOTO(5) 直开页(台架/模拟器构建,
* DTU_BENCH / UI_REMO_ALLOW_GOTO 门控;产品构建应答 NOSUPP)
*/
#include "ui_net_sink.h"
@@ -50,6 +53,12 @@
#include "ui_tokens.h" /* 屏幕几何令牌(UI_SCREEN_W/H、UI_FB_SIZE 权威在 ui_port.h) */
#include "test_config.h" /* TEST_LATENCY_PROBE(链路时延探针编译开关) */
#include "net_latency_test.h" /* M3 探针:prod_cycle_mcu(LCDMEM 处理净成本) */
#include "ui_menu.h" /* 菜单导航状态只读快照(STATUS 身份查询,#69) */
#include "ui_menu_view.h" /* MENU_PAGE_MAX(STATUS 深度钳位上界) */
#include "ui_content_page.h" /* 当前内容页描述符(STATUS 页 id,#69) */
#include "ui_standby.h" /* 待机判定(STATUS)/ 待机拒开(GOTO) */
#include "ui_page_registry.h" /* 叶节点→页注册表(GOTO 按 id 直开,#69) */
#include "ui_pwd_def.h" /* UI_PERM_VIEW(GOTO 授只读权限,#69) */
/* (2026-10-02):发送短写/失败告警(MCU=控制台日志,模拟器=printf 桩) */
#define DBG_TAG "[UI_NET_SINK]"
@@ -62,6 +71,8 @@
#define CMD_INIT UI_REMO_CMD_INIT
#define CMD_KEY UI_REMO_CMD_KEY
#define CMD_LCDMEM UI_REMO_CMD_LCDMEM
#define CMD_STATUS UI_REMO_CMD_STATUS
#define CMD_GOTO UI_REMO_CMD_GOTO
/* 屏幕尺寸与帧大小取 ui_tokens.h / ui_port.h 的屏幕令牌(160x160 1bpp = 3200 字节),
* 本模块不再自带同值字面量——显示几何与协议几何必须是同一个事实 */
@@ -71,6 +82,7 @@
static uint8_t g_tx[4 + 4 + UI_FB_SIZE + 1]; /* 发送组帧缓冲:[TAG][CMD][LEN][DATA][CRC] */
static uint8_t g_lcdmem_data[4 + UI_FB_SIZE]; /* LCDMEM 应答缓冲:4B 偏移 + 1bpp 位图 */
static uint8_t g_status_data[32]; /* STATUS 应答缓冲:最大 28 B,见应答注释 */
static uint8_t g_rx[RM_RX_BUF]; /* 接收暂存区:整块 recv 后逐字节喂入状态机 */
static int g_listen = -1; /* 监听 Socket fd(未启动或已停止时为 -1) */
@@ -343,6 +355,122 @@ static void remo_handle(const uint8_t *f, int n) {
}
break;
}
case CMD_STATUS: {
/* 身份查询 v1(#69,2026-11-02):一帧回答"现在在哪个画面"——
* kind + 菜单路径/选中 + 页 id。本模块由 uiTask 轮询驱动(宿主契约
* 见 ui_net_sink.h poll 文档),同上下文读静态导航状态,免锁、只读、
* 零画面副作用。布局:[ver][kind][depth][n][id_len][path n B][sel n B]
* [页 id ASCII id_len B];上界 5 + 2n(≤8) + id_len(≤15) = 28 ≤ 32 */
uint8_t depth = 0u;
const uint8_t *path = NULL;
const uint8_t *sel = NULL;
const content_page_def_t *desc;
uint8_t npath; /* 帧内 [n] 字段:path/sel 公共长度 */
uint8_t id_len;
uint8_t kind;
uint16_t i;
uint16_t p;
ui_menu_get_nav_state(&depth, &path, &sel);
if (depth >= MENU_PAGE_MAX) {
depth = (uint8_t)(MENU_PAGE_MAX - 1u); /* 防御钳位(正常不可达) */
}
npath = (uint8_t)(depth + 1u);
desc = ui_content_page_current_desc();
id_len = 0u;
if (ui_standby_is_active()) {
kind = UI_REMO_ST_STANDBY; /* 待机优先:path 仍为底层菜单态,页 id 不附 */
} else if (desc != NULL) {
kind = UI_REMO_ST_PAGE;
if (desc->id != NULL) {
size_t l = strlen(desc->id);
id_len = (l > UI_REMO_MAX_ID) ? (uint8_t)UI_REMO_MAX_ID : (uint8_t)l;
}
} else {
kind = UI_REMO_ST_MENU;
}
p = 0u;
g_status_data[p++] = UI_REMO_STATUS_VER;
g_status_data[p++] = kind;
g_status_data[p++] = depth;
g_status_data[p++] = npath;
g_status_data[p++] = id_len;
for (i = 0u; i < npath; i++) {
g_status_data[p++] = path[i];
}
for (i = 0u; i < npath; i++) {
g_status_data[p++] = sel[i];
}
if (id_len > 0u) {
memcpy(g_status_data + p, desc->id, id_len);
}
(void)remo_send(CMD_STATUS, g_status_data, (uint16_t)(p + id_len));
break;
}
#if defined(DTU_BENCH) || defined(UI_REMO_ALLOW_GOTO)
case CMD_GOTO: {
/* 直开页(#69,2026-11-02):按页 id 一步开内容页,替代多步按键盲走
* (主机侧 scripts/board_ui_nav.py --goto)。仅台架构建(DTU_BENCH)
* 与模拟器(UI_REMO_ALLOW_GOTO)存在;产品构建走下方 NOSUPP 分支。
* 契约:只读授权——与"过查看密码"的进入态同档;执行页(clear/reset)
* 拒(清单与主机 EXEC_PAGE_IDS 同一事实,动作前拒);待机中先拒
* (STANDBY),主机按键唤醒后再来——不在此处双份判屏。
* 应答 [ver][status][node],node = 目标叶节点下标(成功有意义,余 0xFF)。 */
uint8_t rsp[3];
char want[UI_REMO_MAX_ID + 1u];
uint8_t hit;
uint8_t i;
rsp[0] = UI_REMO_STATUS_VER;
rsp[2] = 0xFFu;
if ((len == 0u) || (len > UI_REMO_MAX_ID)) {
rsp[1] = UI_REMO_GOTO_NO_ID;
(void)remo_send(CMD_GOTO, rsp, 3u);
break;
}
memcpy(want, data, len);
want[len] = '\0';
hit = 0xFFu; /* 哨兵 = 未命中 */
for (i = 0u; i < (uint8_t)UI_PAGE_MAP_COUNT; i++) {
if (strcmp(g_ui_page_map[i].desc->id, want) == 0) {
hit = i;
break;
}
}
if (hit == 0xFFu) {
rsp[1] = UI_REMO_GOTO_NO_ID;
} else if ((strcmp(want, "clear") == 0) || (strcmp(want, "reset") == 0)) {
rsp[1] = UI_REMO_GOTO_EXEC; /* 执行页拒(清单与主机 EXEC_PAGE_IDS 一致) */
} else if (ui_standby_is_active()) {
rsp[1] = UI_REMO_GOTO_STANDBY; /* 先按键唤醒再查(主机侧自动处理) */
} else {
if (ui_content_page_is_open()) {
ui_content_page_close(); /* 先关已开页(open 守卫:同时只开一页) */
}
if (ui_content_page_open(g_ui_page_map[hit].desc, (uint8_t)UI_PERM_VIEW)) {
rsp[1] = UI_REMO_GOTO_OK;
rsp[2] = g_ui_page_map[hit].node;
/* 身份留痕:开页本身有框架自带 "page open: id=" 边沿日志,
* 这里只补 goto 来源一条,便于台架日志对账 */
DBG_INFO("ui jump ok id=%s node=%u", want, (unsigned)rsp[2]);
} else {
rsp[1] = UI_REMO_GOTO_FAIL;
}
}
(void)remo_send(CMD_GOTO, rsp, 3u);
break;
}
#else
case CMD_GOTO: {
/* 产品构建:GOTO 编译期剔除,应答 NOSUPP(主机侧据此回退按键走法) */
uint8_t rsp[3];
rsp[0] = UI_REMO_STATUS_VER;
rsp[1] = UI_REMO_GOTO_NOSUPP;
rsp[2] = 0xFFu;
(void)remo_send(CMD_GOTO, rsp, 3u);
break;
}
#endif
default:
/* 未知命令码:静默丢弃,保持连接等待后续帧 */
break;
+25 -1
View File
@@ -9,6 +9,9 @@
* 2026-08-29 王建锋 修正监听端口为 7003,与 DTU-RemoteLCD 客户端默认端口对齐
* 2026-10-25 DTU 项目组 F3:新增 ui_net_sink_set_beat_cb()(看门狗心跳
* 回调注入,往返返回点喂位;未注册 = 零行为变化)
* 2026-11-02 DTU 项目组 #69:新增 STATUS(4) 身份查询与 GOTO(5) 直开页命令
* (协议契约 UI_REMO_STATUS_VER / UI_REMO_ST_* /
* UI_REMO_GOTO_*,v1;主机侧解析器 = scripts/board_ui_nav.py)
*/
#ifndef UI_NET_SINK_H
#define UI_NET_SINK_H
@@ -26,6 +29,27 @@ extern "C" {
#define UI_REMO_CMD_INIT 1
#define UI_REMO_CMD_KEY 2
#define UI_REMO_CMD_LCDMEM 3
#define UI_REMO_CMD_STATUS 4 /* 身份查询:应答"现在在哪个画面"(v1,2026-11-02) */
#define UI_REMO_CMD_GOTO 5 /* 直开页:按页 id 一步开内容页(台架/模拟器构建,2026-11-02) */
/* STATUS/GOTO 协议契约 v1(#69,2026-11-02;主机侧解析器 = scripts/board_ui_nav.py,
* 两端共用本组常量,禁止各自复制字面量)
* STATUS 应答布局:[ver][kind][depth][n][id_len][path n B][sel n B][页 id ASCII id_len B]
* kind 取值:MENU(菜单屏,path/sel 有效)/ PAGE(内容页开,页 id 尾附)/ STANDBY(待机屏)
* GOTO payload:页 id ASCII(≤ UI_REMO_MAX_ID 字节);应答 [ver][status][node]
* status 取值:OK(node=目标叶节点)/ NO_ID / EXEC(clear、reset 拒)/ FAIL /
* NOSUPP(产品构建,编译期剔除)/ STANDBY(先唤醒再查) */
#define UI_REMO_STATUS_VER 1u
#define UI_REMO_MAX_ID 15u /* 页 id 字符串上限(现最长 wave_manual 10 字符,留余量) */
#define UI_REMO_ST_MENU 0u
#define UI_REMO_ST_PAGE 1u
#define UI_REMO_ST_STANDBY 2u
#define UI_REMO_GOTO_OK 0u
#define UI_REMO_GOTO_NO_ID 1u
#define UI_REMO_GOTO_EXEC 2u
#define UI_REMO_GOTO_FAIL 3u
#define UI_REMO_GOTO_NOSUPP 4u
#define UI_REMO_GOTO_STANDBY 5u
/* UI 推流监听端口(须与 DTU-RemoteLCD 客户端默认端口 7003 一致) */
#define UI_NET_SINK_PORT 7003
@@ -48,7 +72,7 @@ int ui_net_sink_start(uint16_t port);
* 限定条件:ui_net_sink_start() 已成功调用
* 函数说明:1. 无客户端时先门控(net_listener_armed,纯 RAM 读)再尝试接受连接
* 2. 有客户端时先门控(net_can_read)再用 net_recv_nb 非阻塞收帧并解析
* (KEEPLIVE/INIT/KEY/LCDMEM);门控判为无数据时仍每 32 轮兜底收一次
* (KEEPLIVE/INIT/KEY/LCDMEM/STATUS/GOTO);门控判为无数据时仍每 32 轮兜底收一次
* (DONTWAIT 已转正为具名 API;uiTask 受 IWDG 监控,
* 非阻塞是契约义务——见 net_socket.h net_recv 文档契约)
* 3. 对端关闭或异常时复位客户端,等待下次重监听
@@ -47,10 +47,10 @@ dhara 失败类 +84;RO 另 +208,全是该失败类名表)→ `ER_IROM1`
<!-- MEM_SNAPSHOT:BEGIN generated by scripts/check_mem_numbers.py -->
| 区域 | 用量 | 容量 | 占比 |
|---|---|---|---|
| ER_IROM1 | 277,124 B (270.63 KB) | 1,048,576 B (1024 KB) | 26.4% |
| RW_IRAM1 | 94,336 B (92.12 KB) | 131,072 B (128 KB) | 72.0% |
| ER_IROM1 | 277,384 B (270.88 KB) | 1,048,576 B (1024 KB) | 26.5% |
| RW_IRAM1 | 94,368 B (92.16 KB) | 131,072 B (128 KB) | 72.0% |
| RW_CCM | 57,376 B (56.03 KB) | 65,280 B (64 KB) | 87.9% |
| **Flash (ROM 合计)** | **279,176 B (272.6 KB)** | 1,048,576 B (1024 KB) | **26.6%** |
| **Flash (ROM 合计)** | **279,436 B (272.9 KB)** | 1,048,576 B (1024 KB) | **26.6%** |
<!-- MEM_SNAPSHOT:END -->
各区的容量与常量来源:
+3 -3
View File
@@ -15,16 +15,16 @@
<!-- MEM_BUDGET:BEGIN generated by scripts/ram_baseline.py -->
| 区域 | 用量 | 容量 | 占比 | 门禁(≤92%) |
|---|---|---|---|---|
| ER_IROM1 (Flash) | 277,124 B | 1,048,576 B | 26.4% | 参考 |
| ER_IROM1 (Flash) | 277,384 B | 1,048,576 B | 26.5% | 参考 |
| RW_CCM | 57,376 B | 65,280 B | 87.9% | PASS |
| UNINIT_CCM | 48 B | 256 B | 18.8% | 参考 |
| RW_IRAM1 | 94,336 B | 131,072 B | 72.0% | PASS |
| RW_IRAM1 | 94,368 B | 131,072 B | 72.0% | PASS |
| 子系统(静态 RW+ZI;除 RTOS 堆在 CCM 外均在 SRAM1) | 现值 | 配额 | 状态 |
|---|---|---|---|
| 网络 | 13,702 B | 12 KB | ⚠ 超 1.4 KB |
| 存储 | 7,072 B | 12 KB | OK |
| UI | 36,441 B | 16 KB | ⚠ 超 19.6 KB |
| UI | 36,473 B | 16 KB | ⚠ 超 19.6 KB |
| RTOS 堆 | 57,376 B | 56 KB | 堆=配额 |
| 应用 | 26,333 B | 8 KB | ⚠ 超 17.7 KB |
| 其它 | 10,780 B | — | 参考 |
+1 -1
View File
@@ -14,4 +14,4 @@ date code ro rw zi er_irom1 er_pct iram1 iram1_pct ccm ccm_pct top_rwzi
2026-10-29 238936 29140 1932 141396 268076 25.6 85904 65.5 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;sb_link.o=4364;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4055
2026-10-29 243552 28784 1972 145388 272336 26.0 89936 68.6 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;wave_ring.o=5296;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4055
2026-10-30 246720 29836 2052 149708 276556 26.4 94336 72.0 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6432;nand_ftl.o=6216;wave_ring.o=5296;sb_link.o=4376;ch395f.o=4162;console_log.o=4132
2026-11-02 247288 29836 2052 149708 277124 26.4 94336 72.0 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6432;nand_ftl.o=6216;wave_ring.o=5296;sb_link.o=4376;ch395f.o=4162;console_log.o=4132
2026-11-02 247548 29836 2052 149740 277384 26.5 94368 72.0 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6802;ui_port.o=6432;nand_ftl.o=6216;wave_ring.o=5296;sb_link.o=4376;ch395f.o=4162;console_log.o=4132
1 date code ro rw zi er_irom1 er_pct iram1 iram1_pct ccm ccm_pct top_rwzi
14 2026-10-29 238936 29140 1932 141396 268076 25.6 85904 65.5 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;sb_link.o=4364;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4055
15 2026-10-29 243552 28784 1972 145388 272336 26.0 89936 68.6 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;wave_ring.o=5296;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4055
16 2026-10-30 246720 29836 2052 149708 276556 26.4 94336 72.0 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6432;nand_ftl.o=6216;wave_ring.o=5296;sb_link.o=4376;ch395f.o=4162;console_log.o=4132
17 2026-11-02 247288 247548 29836 2052 149708 149740 277124 277384 26.4 26.5 94336 94368 72.0 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6432;nand_ftl.o=6216;wave_ring.o=5296;sb_link.o=4376;ch395f.o=4162;console_log.o=4132 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6802;ui_port.o=6432;nand_ftl.o=6216;wave_ring.o=5296;sb_link.o=4376;ch395f.o=4162;console_log.o=4132
+10 -10
View File
@@ -1,25 +1,25 @@
{
"built_at": "2026-11-02T18:21:27+08:00",
"fingerprint": "a4435f138bc6dc5fe18779977ec5a2515e15e72ceeecb9653ce2930b640e71c2",
"built_at": "2026-11-02T22:19:57+08:00",
"fingerprint": "19f80087a70f1c74afb1d71fb6d754b4b647321da90b312068144a8f31a9a935",
"fingerprint_files": 1466,
"fingerprint_source": "git-index",
"gated_regions": [
"RW_IRAM1",
"RW_CCM"
],
"git_head": "d6253aa974f4357779d0a94ff24ba66a58abf094",
"git_head": "b8e1de5f2e2515b528b0af21bcb8b423a406b8f2",
"map": "MDK-ARM/STM32F407-Demo/STM32F407-Demo.map",
"map_mtime": 1793614877,
"map_mtime": 1793629184,
"pct": {
"ER_IROM1": 26.43,
"ER_IROM1": 26.45,
"RW_CCM": 87.89,
"RW_IRAM1": 71.97,
"RW_IRAM1": 72.0,
"UNINIT_CCM": 18.75
},
"regions": {
"ER_IROM1": {
"max": 1048576,
"size": 277124
"size": 277384
},
"RW_CCM": {
"max": 65280,
@@ -27,7 +27,7 @@
},
"RW_IRAM1": {
"max": 131072,
"size": 94336
"size": 94368
},
"UNINIT_CCM": {
"max": 256,
@@ -37,10 +37,10 @@
"schema": 2,
"scope_note": "\u540c\u7801\u51ed\u8bc1\uff1a\u6307\u7eb9\u8986\u76d6\u56fa\u4ef6\u4f53\u79ef\u76f8\u5173\u6e90\u7801\uff0c\u53e3\u5f84\u89c1\u672c\u811a\u672c docstring",
"sizes": {
"code": 247288,
"code": 247548,
"ro_data": 29836,
"rw_data": 2052,
"zi_data": 149708
"zi_data": 149740
},
"threshold_pct": 92.0,
"worktree_dirt_at_stamp": 0,
+1
View File
@@ -179,6 +179,7 @@ target_compile_definitions(lvgl_sim PRIVATE
LV_LVGL_H_INCLUDE_SIMPLE # ui_font_cn_12.c 内部 include 简化
WIN32_LEAN_AND_MEAN # 防止 Windows.h 拉入 winsock.h(与 winsock2.h 冲突)
NET_NO_OS # 剥离 net_socket.h 的 FreeRTOS 相关接口(纯 BSD Socket)
UI_REMO_ALLOW_GOTO # 模拟器构建启用 GOTO(5) 直开页(#69,2026-11-02;台架 MCU 门控 DTU_BENCH,见 ui_net_sink.c 注释)
)
target_include_directories(lvgl_sim PRIVATE
+56
View File
@@ -0,0 +1,56 @@
#ifndef TEST_UI_SINK_STUB_LVGL_H
#define TEST_UI_SINK_STUB_LVGL_H
/*
* 测试存根 lvgl.h(#69,2026-11-02 新增)
*
* 为什么存在:ui_net_sink.c 新增 STATUS/GOTO 处理(#69 板端导航身份查询)后,
* 间接引用 ui_menu_view.h / ui_content_page.h,两者 include 真实 "lvgl.h"。
* 本单测只覆盖成帧 / 心跳 / 状态机纯逻辑(见 run_unit_test.py 文件头),
* 运行期不触任何 LVGL,故此处仅提供上述头文件声明处用到的最小类型;
* 不模拟任何 LVGL 行为,也不参与 MCU 构建(stub 目录仅本测试使用)。
*
* 维护约定:ui_content_page.h / ui_menu_view.h 的声明若新增 lv_* 类型依赖,
* 在此按需补最小 typedef;禁止在此写真实 LVGL 语义来"凑过"编译。
*/
#include <stdint.h>
typedef struct _lv_obj_t lv_obj_t;
typedef struct _lv_area_t lv_area_t;
typedef struct _lv_layer_t lv_layer_t;
typedef uint32_t lv_key_t;
typedef struct {
uint8_t a;
uint8_t r;
uint8_t g;
uint8_t b;
} lv_color_t;
/* ui_tokens.h 的 UI_COL_* 宏用到;本测试不断言其值,仅需可编译 */
static inline lv_color_t lv_color_white(void)
{
lv_color_t c;
c.a = 0xFFu;
c.r = 0xFFu;
c.g = 0xFFu;
c.b = 0xFFu;
return c;
}
static inline lv_color_t lv_color_black(void)
{
lv_color_t c;
c.a = 0xFFu;
c.r = 0x00u;
c.g = 0x00u;
c.b = 0x00u;
return c;
}
/* ui_content_page.h 注释提及;为防后续声明引用,按真实 LVGL 键码给出 */
#define LV_KEY_LEFT 0x14u
#define LV_KEY_ESC 0x1Bu
#endif /* TEST_UI_SINK_STUB_LVGL_H */
+32
View File
@@ -93,6 +93,38 @@ void ui_net_sink_inject_key(uint8_t k) {
if (s_key_n < 16) { s_keys[s_key_n++] = k; }
}
/* ============ 假件:导航侧(#69 STATUS/GOTO,2026-11-02 新增) ============
* 本单测不发 STATUS/GOTO 帧,以下仅为链接占位:STATUS 恒为根菜单
* depth=0、无页、非待机。若后续要断言 STATUS/GOTO 语义,把这些假件
* 改成可控状态并新增用例,不要动生产分支。 */
#include "ui_menu.h"
#include "ui_content_page.h"
#include "ui_page_registry.h"
#include "ui_standby.h"
static const uint8_t s_nav_zero[4] = { 0u, 0u, 0u, 0u }; /* 根菜单 path/sel */
void ui_menu_get_nav_state(uint8_t *p_depth, const uint8_t **p_path,
const uint8_t **p_sel)
{
if (p_depth != NULL) { *p_depth = 0u; }
if (p_path != NULL) { *p_path = s_nav_zero; }
if (p_sel != NULL) { *p_sel = s_nav_zero; }
}
const content_page_def_t *ui_content_page_current_desc(void) { return NULL; }
bool ui_content_page_open(const content_page_def_t *desc, uint8_t perm)
{
(void)desc; (void)perm; return false;
}
void ui_content_page_close(void) { }
bool ui_standby_is_active(void) { return false; }
/* 生成表占位:尺寸必须按 ui_page_registry.h 的固定条数(本头文件 extern
* 了 g_ui_page_map[UI_PAGE_MAP_COUNT])。静态零初始化 = 全表 {node=0,
* desc=NULL}:本单测从不发 GOTO 帧,生产的 desc 扫描不会被触达 */
const ui_page_entry_t g_ui_page_map[UI_PAGE_MAP_COUNT] = { { 0u,
(const content_page_def_t *)0 } };
/* ===================== 被测代码 ===================== */
#include "ui_net_sink.c"