feat(UI): 遥测死区与系数 2 页——注入表第四张、三态用脏位、WAIT 与 OK 各出一张黄金

这两页是「UI补齐」里唯一带**持久化语义**的一档,所以整笔的设计重心不在画面上,而在**页面如何诚实表达
「已受理」与「已落盘」**——这一点由 setpage-scout 在开工前的只读查实钉下来:cfg_file_save() 全仓唯一调用
者是 run_par_store_save(),而 default_task.c:246 **每轮无条件**调它、函数首行 s_dirty==0 就直接返回
⇒
落盘动力本来就在 defaultTask,不在 104 会话、也不在事件位。因此本笔走 A2(UI 不当授权写者),不需要
新事件位、不需要新同步口。

页面三态判据 = run_par_dirty_peek():ENTER / WAIT(脏位仍在 = 已受理未落盘)/ OK(脏位归零 = 整档已外科
保存成功)/ 写被拒 = ERR。两条限制写在页面注释里没藏:脏位是**整档全局**的(一趟落 [run_par] 9 键 +
[adc_cal] 两段,归零只证明「这一档落盘了」,不证明「我这一项单独落盘」);他人随后再改会重新置脏 ⇒ 沿用
clear/clock 页的结果锁存,把「我这次动作的结果」与「档位此刻的状态」分开。

**为什么黄金必须出两张**(这条是本轮最有价值的防假证据规则):模拟器假件**保留脏位**、全仓唯一的
s_yt_dirty=0 写点是 sim_yt_pump()(setter 只置不清),于是 WAIT 与 OK 各出一帧——两组同键序、唯一差别是
EXTRA 里的 --yt-nopump。若假件同步清脏位,真机的 WAIT 态永远不会被像素回归覆盖,黄金就成了「只钉住最
好看那一帧」。TC-UIDATA-028o 另钉住 ui_data 层零缓存。

形状:新增 ui_data 第四张注入表(八字段整表校验、拒残表),实现落在装配层 App/app/ui_data_feed.c,
页面零 App include(分层方向 + 模拟器不链 run_par 两条老理由都成立);共用视图模型 ui_w_ytview 承载两页。
合法域一律由执行侧出口给(run_par_db_range / RUN_PAR_K_MAX_UV),页面不抄第二真源——系数页 v1 只用粗守
并在注释写明两层守卫互不掩盖,µV/码 ×[0.5,2.0] 那条真带的出口器归 task-43,**没有**在页面里抄常量。

取舍与遗留(如实):系数行 d=0 整 µV(1e9 装不下两位小数,注释写了「要小数改哪、不收紧假上限」);b 覆盖
无口未做;徽标只画系数页;行名因「率」缺字改为 Hz死区(font-charset 机器先抓到的,不是我目测判的)。

实测:@build 0 错误 0 警告(Code=233,900 / RW-data=1,536);ui_data 单测 277/277、run_par
67/67 零回归;
内容页黄金 47 页全过、**存量 40 张逐字节零漂移**(git 里只有 7 张新增);menu_rows / 池水位 / font-charset
/
bom / mojibake / nested-comment / cppcheck / coding-standard / layer-deps /
bsp-err 全 0 新增;编号五项式
refs 8,778 / dec 7,622 / und **1,156**(上限 1,166)/ 比值 86.83%(基线 86.0% 之上)/ 错误差值
0,注释零裸形
字母+数字。generated-fresh 与 registration-check 本地 PASS;新增 6 只源文件按规矩**双端注册同笔**(叶子
+
registry 19→21 + uvprojx + CMakeLists),uvprojx 这次属「真的增删源文件」才入库。

移交三条不混进本笔:① 全量 --selftest 现 exit 1 是 task-41 硬闸在模拟器上也拒 reset/clear(既有红,快检档
不受影响),归台架道定夺;② 内容页 40→47 的全仓文档计数改写由 Lead 派;③ run_par_deadband_set 的限定
条件语措辞(「iec104Task 上下文」已被装配层裁定覆盖)归算法层下一笔。
This commit is contained in:
2026-10-27 05:07:18 +08:00
parent 1d39571114
commit 48a8ef0564
27 changed files with 1682 additions and 11 deletions
+148
View File
@@ -267,6 +267,143 @@ static const ui_data_maint_ops_t s_maint_ops = {
sim_maint_clear_req,
sim_maint_clear_state
};
/*
* ======================= 道F task-7:遥测整定注入表假件(镜像 ui_data_feed.c 形状)
*
* 初值/合法域 = App/algo/run_par.c 工厂 ROM 与 RUN_PAR_DB_MAX_* 档位的镜像
* (模拟器不链 run_par,真源抄不来只能镜像;变更纪律同 s_sim_log_map 那条:
* 执行侧改档不改这里,屏上会呈现"档位与量纲自相矛盾"的肉眼可见错,黄金像素兜底)。
* ⚠ 脏位口径是这一家的存在理由:**写成功只置脏、绝不同步清**,清脏的唯一去处是
* sim_yt_pump()(镜像 defaultTask 每轮无条件 run_par_store_save())。同步清 =
* WAIT 态在模拟器里永不出现,"落盘确认"三态就只剩最好看那一帧被黄金钉住
* (Lead 裁定④原文的理由,别顺手"优化"成同步)。
*/
static float s_yt_db[UI_DATA_YT_DB_N] = {
0.5f, 0.5f, 0.5f, 0.5f, /* 电压死区 0.5 V(工厂额定档) */
0.005f, 0.005f, 0.005f, 0.005f, /* 电流死区 0.005 A */
0.5f /* 频率死区 0.5 Hz(绝对档) */
};
static float s_yt_k[UI_DATA_YT_CH_N] = {
152.587890625f, 152.587890625f, 152.587890625f, 152.587890625f,
152.587890625f, 152.587890625f, 152.587890625f, 152.587890625f
}; /* = adc_cal ROM 的 TPAFE 系数(µV/码);显示小数位 0 的量化后果见真机侧装配注 */
static uint8_t s_yt_dirty; /* 镜像 run_par 的整档脏位(页面上 WAIT 的唯一来源) */
static int s_yt_nopump; /* --yt-nopump:拍 WAIT 态黄金专用(截图前不清脏) */
/* 死区粗守上限(工程量):镜像 RUN_PAR_DB_MAX_U/I/F 三档;分档与 feed 的 unit
* 分档必须同序(同一条对表纪律) */
/* 函数功能:假死区粗守上限(工程量档,镜像 RUN_PAR_DB_MAX_U/I/F) 返回值:上限 float */
static float sim_yt_db_hi(uint8_t a_idx) {
if (a_idx < 4u) {
return 50.0f;
}
if (a_idx < (UI_DATA_YT_DB_N - 1u)) {
return 1.0f;
}
if (a_idx == (UI_DATA_YT_DB_N - 1u)) {
return 5.0f;
}
return 0.0f;
}
/* 函数功能:假死区点数(镜像 RUN_PAR_DB_N) 返回值:点数 uint8_t */
static uint8_t sim_yt_db_n(void) {
return (uint8_t)UI_DATA_YT_DB_N;
}
/* 函数功能:假死区行现状(值现取自家数组、档位分档与 feed 同序) 返回值:0 / -1 int */
static int sim_yt_db_row(uint8_t a_idx, ui_data_yt_row_t *a_out) {
if ((a_out == NULL) || (a_idx >= UI_DATA_YT_DB_N)) {
return -1;
}
a_out->val = s_yt_db[a_idx];
a_out->lo = 0.0f;
a_out->hi = sim_yt_db_hi(a_idx);
a_out->decimals = 3u;
a_out->unit = (a_idx < 4u) ? UI_DATA_YT_UNIT_V
: ((a_idx < (UI_DATA_YT_DB_N - 1u)) ? UI_DATA_YT_UNIT_A : UI_DATA_YT_UNIT_HZ);
return 0;
}
/* 函数功能:假写死区——写守卫与执行侧同款语义:越界拒 = 值不动、**不置脏**
* (置了脏就是"屏上没改、却要落盘"的空承诺);接受 = 落值 + 置脏,
* 同一函数内发生。 返回值:0 / -1 int */
static int sim_yt_db_set(uint8_t a_idx, float a_eng) {
if ((a_idx >= UI_DATA_YT_DB_N) || (a_eng < 0.0f) || (a_eng > sim_yt_db_hi(a_idx))) {
return -1;
}
s_yt_db[a_idx] = a_eng;
s_yt_dirty = 1u;
return 0;
}
/* 函数功能:假系数点数(镜像 RUN_PAR_CH_N) 返回值:点数 uint8_t */
static uint8_t sim_yt_cal_n(void) {
return (uint8_t)UI_DATA_YT_CH_N;
}
/* 函数功能:假系数行现状(hi = RUN_PAR_K_MAX_UV 的镜像;见上注变更纪律) 返回值:0 / -1 int */
static int sim_yt_cal_row(uint8_t a_idx, ui_data_yt_row_t *a_out) {
if ((a_out == NULL) || (a_idx >= UI_DATA_YT_CH_N)) {
return -1;
}
a_out->val = s_yt_k[a_idx];
a_out->lo = 0.0f;
a_out->hi = 1000000000.0f; /* = RUN_PAR_K_MAX_UV 的镜像(粗守上限) */
a_out->decimals = 0u;
a_out->unit = UI_DATA_YT_UNIT_UV;
return 0;
}
/* 函数功能:假写系数 k(同 db_set 的"写值与置脏成对"语义) 返回值:0 / -1 int */
static int sim_yt_cal_k_set(uint8_t a_idx, float a_uv) {
if ((a_idx >= UI_DATA_YT_CH_N) || !(a_uv > 0.0f) || (a_uv > 1000000000.0f)) {
return -1; /* k<=0 与超粗守都拒;真带这一层模拟器不复刻(执行段的事) */
}
s_yt_k[a_idx] = a_uv;
s_yt_dirty = 1u;
return 0;
}
/* 函数功能:假未标定徽标源(恒已标定,理由见函数体注) 返回值:0 uint8_t */
static uint8_t sim_yt_cal_blocked(void) {
/* 模拟器恒"已标定":徽标腿的像素证据由整定四页黄金覆盖(同一注入式画法);
* 要拍"未标定 + 系数页"的组合另立带旗标的黄金态,本批不扩表 */
return 0u;
}
/* 函数功能:假整档脏位(页面上 WAIT 的唯一来源) 返回值:脏位 uint8_t */
static uint8_t sim_yt_pending(void) {
return s_yt_dirty;
}
static const ui_data_yt_ops_t s_yt_ops = {
sim_yt_db_n,
sim_yt_db_row,
sim_yt_db_set,
sim_yt_cal_n,
sim_yt_cal_row,
sim_yt_cal_k_set,
sim_yt_cal_blocked,
sim_yt_pending
};
/*
* 函数功能:落盘脏位的唯一清去处(镜像 defaultTask 每轮无条件 run_par_store_save)
* 入口参数:无
* 返回值:无
* 限定条件:主循环 / 无头注键尾各一处;--yt-nopump(拍 WAIT 黄金)时整函数空转
* 函数说明:真机"保存成功"的语义 = cfg_file_save 返 0 才清脏;模拟器无失败面,
* pump 即落盘——ERR 腿不复刻(拍不出来也别假拍,屏上 ERR 由写被拒触发,
* 那条模拟器能真拍:见黄金 cal_reject)
*/
static void sim_yt_pump(void) {
if (s_yt_nopump != 0) {
return;
}
s_yt_dirty = 0u;
}
/*
* 函数功能:SOE 记录假源——固定 3 条(镜像 App/task/ui_task.c 真机绑定的形态)
* 入口参数:无
@@ -584,6 +721,9 @@ static int run_headless(const char * keys, const char * path, int standby) {
printf("[sim] UI maint bind: FAIL\n");
}
ui_w_soe_bind(&s_soe_reader); /* task-15:SOE 记录页假源(形态镜像真机绑定) */
if (ui_data_yt_bind(&s_yt_ops) != 0) {
printf("[sim] UI yt bind: FAIL\n");
}
/* task-14 数据快照:镜像 ui_task.c 的 ui_data_init + 首帧发布(先于建页,
* 页面任何时刻打开都拿得到帧,不必等装配节拍) */
sim_publish_data_frames();
@@ -617,6 +757,7 @@ static int run_headless(const char * keys, const char * path, int standby) {
* 无头模式没有那个节拍,不在此当场排空,截图就会停在 WAIT(终态拍不到,
* OK/ERR/LOCK 三条判据的像素证据也就全都不成立) */
sim_param_pump();
sim_yt_pump(); /* 道F task-7:截图前清脏 = 拍 OK 黄金;--yt-nopump 停转 = 拍 WAIT 黄金(Lead 裁定④:两态都要有像素证据) */
/* --standby:注键后强制进入待机屏(截图前) */
if (standby != 0) {
@@ -1009,6 +1150,9 @@ int main(int argc, char **argv) {
if (strcmp(argv[i], "--noclock") == 0) {
s_noclock = 1; /* 把这台机器装成"墙钟无效"(RTC 异常/未对时) */
}
if (strcmp(argv[i], "--yt-nopump") == 0) {
s_yt_nopump = 1; /* 落盘 pump 停转:拍"已受理未落盘"(WAIT)黄金专用 */
}
}
/* 截图/自检模式:--screenshot / --keys / --standby / --cfgtest / --logtest */
@@ -1080,6 +1224,9 @@ int main(int argc, char **argv) {
printf("[sim] UI maint bind: FAIL\n");
}
ui_w_soe_bind(&s_soe_reader); /* task-15:SOE 记录页假源(形态镜像真机绑定) */
if (ui_data_yt_bind(&s_yt_ops) != 0) {
printf("[sim] UI yt bind: FAIL\n");
}
/* task-14 数据快照:镜像 ui_task.c 的 ui_data_init + 首帧发布(先于建页,
* 页面任何时刻打开都拿得到帧,不必等装配节拍) */
sim_publish_data_frames();
@@ -1128,6 +1275,7 @@ int main(int argc, char **argv) {
/* 落定定值整定请求(镜像真机 ui_data_feed_tick 里的 ui_data_param_drain:
* 出队 → prot_set 落值 → 重发参数帧);队列空时只是一次计数判断 */
sim_param_pump();
sim_yt_pump(); /* 道F task-7:窗口模式同样每轮无条件清脏(真机 50 ms 落盘的镜像) */
/* 配置文件轮询(2s 周期:外部文件变更 4s 沉降后自动重载) */
uint32_t now_ms = (uint32_t)SDL_GetTicks();