/* * 模块名称:UI Page SOE (SOE 记录内容页) * 模块功能:SOE 记录叶子节点(node 51)的内容页数据——二进制记录的动态列表,每条记录 2 行 * (偶数行 = 时标、奇数行 = 元件名 + 动作/返回;非元件事件把类型名打在名列), * 数据经 ui_w_soe 注入的 reader 取(本文件零 App include、零文件系统 include); * 未绑定 reader 时按"无记录"空态渲染;向框架 ui_content_page 提供页面描述符 * 为什么不在这个文件读盘:SOE 是 /log/soe.log 上的 64 B 定长二进制记录,读盘、卷锁、窗口 * 代数与校验和判定全在 App/log/soe_store 的只读 API 里(App/task/ui_task.c 绑定), * UI 侧只按不透明编号显示——与运行/自检记录页同一分层(分层方向基线 3 条不变) * 适用平台:STM32F407ZGTx / PC 模拟器(两端共用) * 作者:王建锋 * 创建日期:2026-10-25 * 修改记录: * v1.0 2026-10-25 王建锋 创建(道E task-15:SOE 记录页;规格 = * docs/UI设计/页面扩充详细方案.md §3.6「SOE记录」行) */ /* 头文件包含区 */ #include "ui_page_soe.h" #include "ui_tokens.h" #include "ui_w_soe.h" /* 静态变量定义区 */ /* * 本实例自带一条读盘缓存(组件内 cache_valid/last_rec):一条记录画两行, * 奇数行复用同一次读取——与运行/自检记录页同构,但**实例独立**:两页共用一份 * 缓存会互相命中对方的记录号,切页时显示另一页的陈旧行(task-6 的教训) */ static ui_w_soe_t s_soe; /* 函数定义区 */ /* * 函数功能:总行数(每条记录 2 行;未绑定 reader 或无记录 = 单条伪行"无记录") * 入口参数:无 * 返回值:总行数 uint16_t * 限定条件:uiTask 绘制路径(组件内部按记录数换算,不做 I/O 之外的状态依赖) */ static uint16_t pg_count(void) { return ui_w_soe_count(&s_soe); } /* * 函数功能:逐行取数(偶数行 = 时标,奇数行 = "元件 + 事件") * 入口参数:a_row - 全局行下标 uint16_t * a_name - 名输出缓冲(框架 UI_BUF_STRLEN) char * * a_value - 值输出缓冲 char * * 返回值:无 * 限定条件:uiTask 绘制路径;reader 已在两端适配层绑定(未绑定按空态渲染) * 函数说明:类型/元件的**显示名映射在组件里**(UI 侧表现层),二进制编号由 App * 注入的 reader 原样交上来——与"屏幕上的话归 UI、数据归 App"一致 */ static void pg_refresh(uint16_t a_row, char *a_name, char *a_value) { ui_w_soe_refresh(&s_soe, a_row, a_name, a_value); } /* * 页面描述符(外部链接:生成物 ui_page_registry.c 按菜单树 #page=soe 绑定引用): * 动态列表页,每记录 2 行、UI_LIST_ROWS(8) 行/页 = 4 条/页;band_h 必须 >0 * (selectable 页选中行是黑字,无白带即不可见,同记录页约定) */ const content_page_def_t ui_page_soe_desc = { .id = "soe", .title = "SOE记录", .selectable = 1u, .top_y = UI_LIST_TOP, .pitch = UI_ROW_PITCH, .band_h = UI_ROW_BAND_H, .text_dy = 0, .left_x = UI_LIST_LEFT_X, .right_x = UI_LIST_RIGHT_X, .rows_per_page = UI_LIST_ROWS, .count_cb = pg_count, .refresh = pg_refresh, };