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:
@@ -74,6 +74,11 @@
|
||||
* test-cppcheck 抓过,真判据落在 TC-UIDATA-026s)
|
||||
* TC-UIDATA-025 维护通道未注入防御:六口安全返回 + 残表整表拒绝且不覆盖好表
|
||||
* TC-UIDATA-026 注入后转发言行:epoch 0 哨兵不下发、reset_req 自行投操作记录=0 次
|
||||
* TC-UIDATA-027 遥测整定通道未注入防御:八个口一律安全返回、不碰出参;
|
||||
* 残表整表拒绝且不覆盖好表(与 025 同一条纪律的第五张表复刻)
|
||||
* TC-UIDATA-028 遥测整定注入后转发言行:行现状逐字段原样上抛、写口的 idx 与
|
||||
* 工程量原样下传、返回码直通、pending 无状态直读(本层零缓存——
|
||||
* 页面 OK/WAIT 的唯一依据必须是执行侧此刻的脏位)
|
||||
* (谁触发谁投,防"远端 + 本地"双投)、clear 状态码直通不改码
|
||||
*
|
||||
* 通过:全部 TC PASS(main 返回 0)。
|
||||
@@ -1297,6 +1302,184 @@ static void tc_maint_forwarding(void)
|
||||
CHECK(s_stub_clear_state_calls == 2, "TC-UIDATA-026r state queried once per call");
|
||||
}
|
||||
|
||||
/* ── 道F task-7:通道五(遥测整定注入表)桩 ─────────────────────────────── */
|
||||
|
||||
static uint8_t s_yt_db_calls;
|
||||
static uint8_t s_yt_db_last_idx;
|
||||
static float s_yt_db_last_val;
|
||||
static int s_yt_db_set_rc;
|
||||
static uint8_t s_yt_cal_calls;
|
||||
static uint8_t s_yt_cal_last_idx;
|
||||
static float s_yt_cal_last_uv;
|
||||
static int s_yt_cal_set_rc;
|
||||
static uint8_t s_yt_blocked;
|
||||
static uint8_t s_yt_pending_ret;
|
||||
static int s_yt_pending_calls;
|
||||
|
||||
static uint8_t yt_stub_db_n(void)
|
||||
{
|
||||
return UI_DATA_YT_DB_N;
|
||||
}
|
||||
|
||||
static int yt_stub_db_row(uint8_t a_idx, ui_data_yt_row_t *a_out)
|
||||
{
|
||||
if (a_idx >= UI_DATA_YT_DB_N) {
|
||||
return -1;
|
||||
}
|
||||
a_out->val = 0.125f + (float)a_idx;
|
||||
a_out->lo = 0.0f;
|
||||
a_out->hi = 50.0f;
|
||||
a_out->unit = UI_DATA_YT_UNIT_V;
|
||||
a_out->decimals = 3u;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int yt_stub_db_set(uint8_t a_idx, float a_eng)
|
||||
{
|
||||
s_yt_db_calls++;
|
||||
s_yt_db_last_idx = a_idx;
|
||||
s_yt_db_last_val = a_eng;
|
||||
return s_yt_db_set_rc;
|
||||
}
|
||||
|
||||
static uint8_t yt_stub_cal_n(void)
|
||||
{
|
||||
return UI_DATA_YT_CH_N;
|
||||
}
|
||||
|
||||
static int yt_stub_cal_row(uint8_t a_idx, ui_data_yt_row_t *a_out)
|
||||
{
|
||||
if (a_idx >= UI_DATA_YT_CH_N) {
|
||||
return -1;
|
||||
}
|
||||
a_out->val = 152.5f;
|
||||
a_out->lo = 0.0f;
|
||||
a_out->hi = 1000000000.0f;
|
||||
a_out->unit = UI_DATA_YT_UNIT_UV;
|
||||
a_out->decimals = 0u;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int yt_stub_cal_k_set(uint8_t a_idx, float a_uv)
|
||||
{
|
||||
s_yt_cal_calls++;
|
||||
s_yt_cal_last_idx = a_idx;
|
||||
s_yt_cal_last_uv = a_uv;
|
||||
return s_yt_cal_set_rc;
|
||||
}
|
||||
|
||||
static uint8_t yt_stub_blocked(void)
|
||||
{
|
||||
return s_yt_blocked;
|
||||
}
|
||||
|
||||
static uint8_t yt_stub_pending(void)
|
||||
{
|
||||
s_yt_pending_calls++;
|
||||
return s_yt_pending_ret;
|
||||
}
|
||||
|
||||
static const ui_data_yt_ops_t s_yt_stub = {
|
||||
yt_stub_db_n, yt_stub_db_row, yt_stub_db_set, yt_stub_cal_n,
|
||||
yt_stub_cal_row, yt_stub_cal_k_set, yt_stub_blocked, yt_stub_pending
|
||||
};
|
||||
|
||||
/* 残表:只缺最后一口(pending)——八口校验里最容易被"顺手少注一件"漏掉的那个 */
|
||||
static const ui_data_yt_ops_t s_yt_broken = {
|
||||
yt_stub_db_n, yt_stub_db_row, yt_stub_db_set, yt_stub_cal_n,
|
||||
yt_stub_cal_row, yt_stub_cal_k_set, yt_stub_blocked, NULL
|
||||
};
|
||||
|
||||
/*
|
||||
* TC-UIDATA-027 未注入防御(025 的第五张表复刻):八个口一律安全返回;
|
||||
* db_row/cal_row 未注入时**不得碰出参**(页面拿栈上未初始化结构当现状读,
|
||||
* 比返回 -1 更坏——这里用预填哨兵钉住"一个字节都没写")。
|
||||
*/
|
||||
static void tc_yt_not_bound(void)
|
||||
{
|
||||
ui_data_yt_row_t r;
|
||||
float sentinel = -777.0f;
|
||||
|
||||
(void)ui_data_yt_bind(NULL);
|
||||
|
||||
r.val = sentinel;
|
||||
CHECK(ui_data_yt_db_n() == 0u, "TC-UIDATA-027a db_n not bound is 0");
|
||||
CHECK(ui_data_yt_db_row(0u, &r) == -1, "TC-UIDATA-027b db_row not bound is -1");
|
||||
CHECK(r.val == sentinel, "TC-UIDATA-027c db_row not bound wrote nothing");
|
||||
r.val = sentinel;
|
||||
CHECK(ui_data_yt_cal_row(0u, &r) == -1, "TC-UIDATA-027d cal_row not bound is -1");
|
||||
CHECK(r.val == sentinel, "TC-UIDATA-027e cal_row not bound wrote nothing");
|
||||
CHECK(ui_data_yt_cal_n() == 0u, "TC-UIDATA-027f cal_n not bound is 0");
|
||||
CHECK(ui_data_yt_db_set(0u, 1.0f) == -1, "TC-UIDATA-027g db_set not bound is -1");
|
||||
CHECK(ui_data_yt_cal_k_set(0u, 1.0f) == -1, "TC-UIDATA-027h cal_k_set not bound is -1");
|
||||
CHECK(ui_data_yt_cal_blocked() == 0u, "TC-UIDATA-027i blocked not bound is 0 (never fabricate)");
|
||||
CHECK(ui_data_yt_pending() == 0u, "TC-UIDATA-027j pending not bound is 0");
|
||||
CHECK(ui_data_yt_db_row(0u, NULL) == -1, "TC-UIDATA-027k NULL out refused even bound-or-not");
|
||||
CHECK(ui_data_yt_bind(&s_yt_broken) == -1, "TC-UIDATA-027l incomplete table refused");
|
||||
CHECK(ui_data_yt_db_n() == 0u, "TC-UIDATA-027m refused table left channel unbound");
|
||||
CHECK(ui_data_yt_bind(&s_yt_stub) == 0, "TC-UIDATA-027n complete table accepted");
|
||||
CHECK(ui_data_yt_db_n() == UI_DATA_YT_DB_N, "TC-UIDATA-027o bound table forwards count");
|
||||
CHECK(ui_data_yt_bind(&s_yt_broken) == -1, "TC-UIDATA-027p broken refused again");
|
||||
CHECK(ui_data_yt_db_n() == UI_DATA_YT_DB_N, "TC-UIDATA-027q refusal keeps the good table active");
|
||||
}
|
||||
|
||||
/*
|
||||
* TC-UIDATA-028 转发言行(两张页面全部判据的地基):
|
||||
* - 行现状逐字段原样上抛(val/lo/hi/unit/decimals 五样一个不许"顺手加工"——
|
||||
* 合法域是执行侧事实,转发层改一个数就是第二真源)
|
||||
* - 写口 idx 与工程量原样下传,执行侧返回码直通(0/-1 两态,页面按 ERR 显示)
|
||||
* - pending 无状态直读:本层每问一次转发一次(calls 增长)、桩改什么口径立刻
|
||||
* 变什么口径——页面锁存的合法性建立在"本层不缓存"之上
|
||||
* - 越界 idx 由执行侧判(桩返 -1 直通),本层不抄一份行数守卫
|
||||
*/
|
||||
static void tc_yt_forwarding(void)
|
||||
{
|
||||
ui_data_yt_row_t r;
|
||||
|
||||
(void)ui_data_yt_bind(&s_yt_stub);
|
||||
s_yt_db_calls = 0u; s_yt_cal_calls = 0u; s_yt_pending_calls = 0;
|
||||
s_yt_db_set_rc = 0; s_yt_cal_set_rc = 0;
|
||||
|
||||
CHECK(ui_data_yt_db_row(2u, &r) == 0, "TC-UIDATA-028a db_row forwarded");
|
||||
CHECK((r.val == (0.125f + 2.0f)) && (r.lo == 0.0f) && (r.hi == 50.0f) &&
|
||||
(r.unit == UI_DATA_YT_UNIT_V) && (r.decimals == 3u),
|
||||
"TC-UIDATA-028b row fields pass through verbatim (no second source of truth)");
|
||||
CHECK(ui_data_yt_db_row(UI_DATA_YT_DB_N, &r) == -1, "TC-UIDATA-028c executor-side oob idx propagates");
|
||||
|
||||
CHECK((ui_data_yt_db_set(3u, 0.25f) == 0), "TC-UIDATA-028d db_set accepted");
|
||||
CHECK((s_yt_db_calls == 1u) && (s_yt_db_last_idx == 3u) && (s_yt_db_last_val == 0.25f),
|
||||
"TC-UIDATA-028e executor got exact idx and engineering value");
|
||||
s_yt_db_set_rc = -1;
|
||||
CHECK(ui_data_yt_db_set(3u, 0.25f) == -1, "TC-UIDATA-028f executor rejection propagates");
|
||||
|
||||
CHECK((ui_data_yt_cal_n() == UI_DATA_YT_CH_N) && (ui_data_yt_cal_row(7u, &r) == 0) &&
|
||||
(r.unit == UI_DATA_YT_UNIT_UV) && (r.hi == 1000000000.0f) && (r.decimals == 0u),
|
||||
"TC-UIDATA-028g cal row forwards (coarse-guard hi verbatim)");
|
||||
s_yt_cal_set_rc = 0;
|
||||
CHECK(ui_data_yt_cal_k_set(7u, 153.0f) == 0, "TC-UIDATA-028h cal_k_set accepted");
|
||||
CHECK((s_yt_cal_calls == 1u) && (s_yt_cal_last_idx == 7u) && (s_yt_cal_last_uv == 153.0f),
|
||||
"TC-UIDATA-028i cal executor got exact idx and uv value");
|
||||
s_yt_cal_set_rc = -1;
|
||||
CHECK(ui_data_yt_cal_k_set(7u, 0.0f) == -1, "TC-UIDATA-028j cal rejection propagates (k<=0 leg)");
|
||||
|
||||
s_yt_blocked = 1u;
|
||||
CHECK(ui_data_yt_cal_blocked() == 1u, "TC-UIDATA-028k blocked badge forwarded");
|
||||
s_yt_blocked = 0u;
|
||||
CHECK(ui_data_yt_cal_blocked() == 0u, "TC-UIDATA-028l badge clear follows executor immediately");
|
||||
|
||||
s_yt_pending_ret = 1u;
|
||||
CHECK(ui_data_yt_pending() == 1u, "TC-UIDATA-028m pending=dirty forwarded (WAIT leg)");
|
||||
s_yt_pending_ret = 0u;
|
||||
CHECK(ui_data_yt_pending() == 0u, "TC-UIDATA-028n pending follows to clean (OK leg, zero cache)");
|
||||
CHECK(s_yt_pending_calls == 2, "TC-UIDATA-028o every question reaches executor (stateless layer)");
|
||||
|
||||
(void)ui_data_yt_bind(NULL);
|
||||
CHECK(ui_data_yt_pending() == 0u, "TC-UIDATA-028p unbind restores safe defaults");
|
||||
/* 未注入不得把问题漏给桩:计数不涨 = 撤销后桩彻底脱离(028o 只数了绑定期的
|
||||
* 两次,这条把"撤销后一次都不到"补成闭环) */
|
||||
CHECK(s_yt_pending_calls == 2, "TC-UIDATA-028q unbind stops reaching executor entirely");
|
||||
}
|
||||
|
||||
/* ===================== main ===================== */
|
||||
|
||||
int main(void)
|
||||
@@ -1351,6 +1534,10 @@ int main(void)
|
||||
tc_maint_not_bound();
|
||||
printf("-- maint channel: forwarding --\n");
|
||||
tc_maint_forwarding();
|
||||
printf("-- yt channel: not bound --\n");
|
||||
tc_yt_not_bound();
|
||||
printf("-- yt channel: forwarding --\n");
|
||||
tc_yt_forwarding();
|
||||
|
||||
printf("\n=== UI Data Snapshot Tests: %d/%d PASSED (failed=%d) ===\n",
|
||||
s_passed, s_total, s_failed);
|
||||
|
||||
Reference in New Issue
Block a user