7b05d7bfd4
按用户裁定(2026-11-10)把 docs/任务规划/ 从"全量待办表"收成两个文件: 1. 登记簿.md 只记 V0.1 硬件缺陷 → V0.2 改版要求(双转换器无共同采样触发、 IA 前端差分滤波限制谐波带宽)。原 §1/§2/§4/§5/§6/§7/§8/§9 的待办按 "待办跟着所属模块走"清空,四类事实在删除前先落到新归属: - 两点标定开工前要先拍板的三件事 → 算法层设计说明 §13.13(新节) - 通讯设置页真机判据 → 网络配置说明 §3.6 内联 - 缩堆迁 CCM 后半、开入开出重开条件 → 原本各模块文档即唯一权威 2. 暂缓-RS485.md 删除,其唯一不可丢的"采集链路测试可验证性约束"三条与 完成判据并入 产品需求设计文档 §5.10。 3. 任务规划/README.md 去掉全部历史叙述(UI 补齐销项流水、net 收口过程、 故障录波近千字台账),只留:怎么用、条目规则、生成物单写者纪律、 推进顺序表(每行只写当前状态与卡点)、维护约定。 同步改写全库引用(约 60 处):AGENTS.md、docs/README.md、产品需求、UI、 子系统设计、内存管理、环境与部署、算法、测试说明、门禁说明、问题记录, 以及 App/ 与 Drivers/BSP/ 的头注释、脚本与 .pre-commit-config.yaml 注释。 顺带修掉三处已失效的引用目标:链路延迟测试的队列往返重验项改指实机测试 实施指南 §7.3;并行工作树的 <ID> 行去掉已退役的 N-x/S-x/T-x 编号族; 任务规划 README 的 §1 旧编号在技能示例里的引用。 门禁:check_doc_links --all --sections-strict 214 篇通过、无法判定 0; pre-commit 全 Passed(doc-links / mermaid / 任务表 / 内存数字 / BOM / UI 像素回归 / generated-fresh / layer-deps / bsp-err / skill-size); keil-build 0 错误 0 警告(Code=255160 RO=31204 RW=2080 ZI=152152), RAM 预算门禁 PASS(RW_IRAM1 73.9%、RW_CCM 87.9%)。
279 lines
11 KiB
C
279 lines
11 KiB
C
/*
|
||
* 模块名称:UI Page Comm (通讯设置内容页)
|
||
* 模块功能:通讯参数 → 通讯设置 叶子(#P 受密码保护)的内容页——两行数值表
|
||
* (公共地址 CA / 监听端口)+ 保存行;本文件零 App include:行现状
|
||
* (值/合法带)经 ui_data.h 通道六注入表现取,写与落盘确认全走
|
||
* ui_w_setlist 组件 + 本页自带的 60 行胶水(写记账/落盘锁存——
|
||
* ui_w_ytview 是 [run_par] 档专用形态(float 域 + 徽标),两档语义
|
||
* 不同不硬并)
|
||
* 两态一页:123 修改权限 → 可编辑(编辑器 + 保存行);000 查看权限 → 只读
|
||
* (attach 内不绑 commit → 无保存行,key_cb 整页交回框架——死区页
|
||
* 同一条分派纪律)
|
||
* 生效语义(屏上必须诚实的地方):保存行 OK 只证明 **落盘完成**,不证明
|
||
* "已在新值上运行"——端口 = 下一次重 bind 监听生效(拆链/网络代次
|
||
* 重建自然到位,不必整机重启),公共地址 = **改后重启生效**
|
||
* (iec104Task 启动时取一次 getter;docs/子系统设计/
|
||
* IEC104上行设计说明.md §8)。页面上不加"立即生效"字样,也不为
|
||
* ca 画第二枚徽标——生效时刻的完整口径归上面那份设计说明。
|
||
* 徽标说明:本页不画"未标定"类徽标(与两点标定无关,稀释真告警——死区页
|
||
* 同条纪律)
|
||
* 适用平台:STM32F407ZGTx / PC 模拟器(共用源码)
|
||
* 作者:DTU 项目组
|
||
* 创建日期:2026-10-27
|
||
* 修改记录:
|
||
* v1.0 2026-10-27 DTU 项目组 创建(道G task-9;验收口径 = 本页须
|
||
* 「重启即生效 + 104 侧读回真值 + 段数键数上限核对」,
|
||
* 台架判据见 docs/子系统设计/网络配置说明.md §3.6 与
|
||
* IEC104上行设计说明.md §8)
|
||
*/
|
||
/* 头文件包含区 */
|
||
#include <string.h>
|
||
|
||
#include "ui_page_comm.h"
|
||
|
||
#include "ui_data.h" /* 通道六:行现状/写入口/脏位(本层唯一的数与守卫的来源) */
|
||
#include "ui_tokens.h"
|
||
#include "ui_w_setlist.h"
|
||
|
||
/* 私有宏定义区 */
|
||
|
||
/* 保存行显示态(值与 ui_w_ytview 的 YT_ST_* 同序同义,胶水面独立一份) */
|
||
#define CM_ST_ENTER 0u /* 空闲:保存行显示 ENTER */
|
||
#define CM_ST_WAIT 1u /* 按过保存、脏位仍在:WAIT */
|
||
#define CM_ST_OK 2u /* 脏位归零(或按时无脏):OK,锁存不回退 */
|
||
#define CM_ST_ERR 3u /* 最近一次写被执行侧拒:粘滞 ERR */
|
||
#define CM_BAD_ALL 0x03u /* 两行反显位图全掩码 */
|
||
|
||
/* 静态变量定义区 */
|
||
|
||
/* 行表在 RAM 现建(合法带唯一出口在执行侧,本文件零范围字面量——通道六
|
||
* 表注第①条;行名是本机界面文案归本页,行序即 UI_DATA_COMM_ROW_* 下标) */
|
||
static const char *const k_comm_name[UI_DATA_COMM_ROW_N] = {
|
||
"公共地址",
|
||
"监听端口"
|
||
};
|
||
static ui_w_setlist_row_t s_rows[UI_DATA_COMM_ROW_N];
|
||
static uint8_t s_n; /* 实际建出行数(半表纪律:读失败即停) */
|
||
static uint8_t s_st; /* 保存行显示态 CM_ST_* */
|
||
static uint8_t s_badmap; /* 写被拒行反显位图(bit0=CA bit1=PORT) */
|
||
|
||
/* 本页定值表实例(组件状态独占一份,勿跨页共用) */
|
||
static ui_w_setlist_t s_sl;
|
||
|
||
/* 函数定义区 */
|
||
|
||
/*
|
||
* 函数功能:写结果记账(成功/被拒共一个入口——死区页 yt_note_write 同款)
|
||
* 入口参数:a_id - 行下标 uint8_t;a_rc - 注入口返回值 int
|
||
* 返回值:无
|
||
* 限定条件:set 回调链内(uiTask 按键)
|
||
* 函数说明:拒绝 → 该行反显 + 粘滞 ERR;成功 → 只清这一行反显 + 作废上一次
|
||
* 保存结果(改过任何一位,上一轮的 OK/ERR 都不该再挂屏)
|
||
*/
|
||
static void cm_note_write(uint8_t a_id, int a_rc) {
|
||
if (a_rc != 0) {
|
||
s_badmap = (uint8_t)(s_badmap | (uint8_t)(1u << a_id));
|
||
s_st = CM_ST_ERR;
|
||
} else {
|
||
s_badmap = (uint8_t)(s_badmap & (uint8_t)~(1u << a_id));
|
||
s_st = CM_ST_ENTER;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* 函数功能:保存行按键(值早在逐行 ENTER 时写入副本并置脏;这里只是落盘
|
||
* 确认的起点)
|
||
* 入口参数:无
|
||
* 返回值:无
|
||
* 限定条件:可编辑态、保存行 ENTER;uiTask 按键链
|
||
* 函数说明:先清反显再评估;脏位仍在 → WAIT 锁存观察,无脏 → 直接 OK。
|
||
* 真机落盘 = defaultTask 每轮无条件 iec104_comm_store_save(),
|
||
* WAIT 窗口 ≤50 ms;模拟器假件刻意不自动清脏(由无头 pump 清),
|
||
* 否则 WAIT 态永远不会被像素回归覆盖(道F 裁定④同一条理由)
|
||
*/
|
||
static void cm_commit(void) {
|
||
s_badmap = 0u;
|
||
s_st = (ui_data_comm_pending() != 0u) ? CM_ST_WAIT : CM_ST_OK;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:保存行值列回读(WAIT → OK 边沿在此收尾)
|
||
* 入口参数:无
|
||
* 返回值:组件态枚举 ui_w_setlist_st_t
|
||
* 限定条件:绘制链内
|
||
* 函数说明:锁存 = 只前进不回退("我这次动作的结果"与"档位此刻的状态"分开;
|
||
* 通道六里 ca/port 没有 104 侧自动写者,比通道五更干净,但锁存
|
||
* 纪律不做两套)
|
||
*/
|
||
static ui_w_setlist_st_t cm_state(void) {
|
||
if ((s_st == CM_ST_WAIT) && (ui_data_comm_pending() == 0u)) {
|
||
s_st = CM_ST_OK;
|
||
}
|
||
switch (s_st) {
|
||
case CM_ST_WAIT:
|
||
return UI_W_SETLIST_ST_WAIT;
|
||
case CM_ST_OK:
|
||
return UI_W_SETLIST_ST_OK;
|
||
case CM_ST_ERR:
|
||
return UI_W_SETLIST_ST_FAIL;
|
||
default:
|
||
return UI_W_SETLIST_ST_IDLE;
|
||
}
|
||
}
|
||
|
||
/* 函数功能:某行是否需越界反显(写被拒的账挂在这行值上) 返回值:反显 bool */
|
||
static bool cm_bad(uint16_t a_row) {
|
||
if (a_row >= 8u) {
|
||
return false;
|
||
}
|
||
return ((s_badmap >> a_row) & 0x1u) != 0u;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:读某行当前值(int32 定点通道,decimals 恒 0 = u16 域直达)
|
||
* 入口参数:a_id - 行下标 uint8_t
|
||
* 返回值:当前值 int32_t
|
||
* 函数说明:读失败回 0 不回旧缓存——组件零缓存,0 是唯一诚实的退化值
|
||
* (ui_data 通道五同口径)
|
||
*/
|
||
static int32_t cm_get(uint8_t a_id) {
|
||
ui_data_comm_row_t r;
|
||
|
||
if ((a_id >= s_n) || (ui_data_comm_row(a_id, &r) != 0)) {
|
||
return 0;
|
||
}
|
||
return (int32_t)r.val;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:写某行(经通道六 → iec104_comm_*_set;守卫与置脏在带内执行侧)
|
||
* 入口参数:a_id - 行下标 uint8_t;a_val - 编辑器提交的整数 int32_t
|
||
* 返回值:无(结果经 cm_note_write 记账)
|
||
* 限定条件:set 回调链内
|
||
* 函数说明:负数(编辑器理论不产)原样送 setter 拒掉,本页不做第二次守卫
|
||
* ——合法带唯一出口在 iec104_comm.h,抄一份就是第二真源
|
||
*/
|
||
static void cm_write(uint8_t a_id, int32_t a_val) {
|
||
if (a_id >= s_n) {
|
||
return;
|
||
}
|
||
cm_note_write(a_id, ui_data_comm_set(a_id, (uint32_t)a_val));
|
||
}
|
||
|
||
/*
|
||
* 函数功能:开页建表 + 绑视图(接 init_cb)
|
||
* 入口参数:无
|
||
* 返回值:无
|
||
* 限定条件:框架开页链内(本次进入权限已装载——先装权限再调 init_cb 的
|
||
* 时序依据见 ui_page_view_param.c 同位置注释)
|
||
* 函数说明:两行逐行现取(lo/hi/值全现给);读到第 i 行失败停在 i 行——
|
||
* 半张表比空表危险的反面论证同 ui_w_ytview.yt_fill;未注入 =
|
||
* 0 行空表页,一个像素都不画假数据
|
||
*/
|
||
static void pg_init(void) {
|
||
uint8_t i;
|
||
|
||
s_st = CM_ST_ENTER;
|
||
s_badmap = 0u;
|
||
s_n = 0u;
|
||
for (i = 0u; i < (uint8_t)UI_DATA_COMM_ROW_N; i++) {
|
||
ui_data_comm_row_t r;
|
||
|
||
if (ui_data_comm_row(i, &r) != 0) {
|
||
break;
|
||
}
|
||
s_rows[i].name = k_comm_name[i];
|
||
s_rows[i].id = i;
|
||
s_rows[i].kind = UI_W_SETLIST_KIND_NUM;
|
||
s_rows[i].decimals = 0u;
|
||
s_rows[i].min = (int32_t)r.lo;
|
||
s_rows[i].max = (int32_t)r.hi;
|
||
s_rows[i].opts = NULL;
|
||
s_rows[i].unit = NULL; /* CA 与端口都不是物理量,不挂单位 */
|
||
s_n++;
|
||
}
|
||
(void)memset(&s_sl, 0, sizeof(s_sl));
|
||
s_sl.rows = s_rows;
|
||
s_sl.count = s_n;
|
||
s_sl.get = cm_get;
|
||
s_sl.set = cm_write;
|
||
s_sl.bad = cm_bad;
|
||
if (ui_content_page_is_editable() != false) {
|
||
s_sl.commit = cm_commit;
|
||
s_sl.state = cm_state;
|
||
}
|
||
ui_w_setlist_reset(&s_sl);
|
||
}
|
||
|
||
/*
|
||
* 函数功能:总行数(数据行实给 + 可编辑态才有保存行;接 count_cb)
|
||
* 入口参数:无
|
||
* 返回值:总行数 uint16_t
|
||
* 限定条件:框架绘制/翻页链内
|
||
*/
|
||
static uint16_t pg_count(void) {
|
||
return ui_w_setlist_count(&s_sl);
|
||
}
|
||
|
||
/*
|
||
* 函数功能:逐行取数(行现状在组件与注入表里现取,本层无缓存)
|
||
* 入口参数:a_row / a_name / a_value - 契约见 ui_content_page.h
|
||
* 返回值:无
|
||
* 限定条件:框架绘制链内
|
||
*/
|
||
static void pg_refresh(uint16_t a_row, char *a_name, char *a_value) {
|
||
ui_w_setlist_refresh(&s_sl, a_row, a_name, a_value);
|
||
}
|
||
|
||
/*
|
||
* 函数功能:自绘层(编辑光标反显 + 写被拒行反显)
|
||
* 入口参数:a_layer / a_clip - 契约见 ui_content_page.h
|
||
* 返回值:无
|
||
* 限定条件:框架绘制链内,内置区块画完之后
|
||
*/
|
||
static void pg_draw(lv_layer_t *a_layer, const lv_area_t *a_clip) {
|
||
ui_w_setlist_draw(&s_sl, a_layer, a_clip);
|
||
}
|
||
|
||
/*
|
||
* 函数功能:按键转发(接 key_cb)
|
||
* 入口参数:a_key - LVGL 键值 lv_key_t
|
||
* 返回值:true - 本页已消费;false - 交回框架(↑↓ 移选、← 关页)
|
||
* 限定条件:描述符 edit_capable=1 + key_intercept=1(编辑中 ←→ 移数字光标,
|
||
* 必须先给页面——整定四页同款实证)
|
||
* 函数说明:第一条门 = 只读进入(未绑 commit)整页交回框架,与"本页没有
|
||
* key_cb"逐字等价(黄金只读态为证)
|
||
*/
|
||
static bool pg_key(lv_key_t a_key) {
|
||
if (s_sl.commit == NULL) {
|
||
return false;
|
||
}
|
||
return (ui_w_setlist_key(&s_sl, a_key) != 0u);
|
||
}
|
||
|
||
/*
|
||
* 页面描述符(外部链接:生成物 ui_page_registry.c 按菜单树 #page=comm 绑定引用)
|
||
* 列表页骨架 + 可编辑 + ← 拦截;row_count 给静态上限(2 数据行 + 保存行 = 3),
|
||
* 运行时以注入表现报为准;band_h>0 选中反显(死区页同款几何令牌)
|
||
*/
|
||
const content_page_def_t ui_page_comm_desc = {
|
||
.id = "comm",
|
||
.title = "通讯设置",
|
||
.selectable = 1u,
|
||
.edit_capable = 1u,
|
||
.key_intercept = 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,
|
||
.row_count = 3u,
|
||
.init_cb = pg_init,
|
||
.count_cb = pg_count,
|
||
.refresh = pg_refresh,
|
||
.draw_cb = pg_draw,
|
||
.key_cb = pg_key,
|
||
};
|