feat(UI/采集/104): 通讯设置页 + 开机账本 + adc_cal 可诊断化——三车道同树一次构建入库
三条道在同一棵树上交付,故合并成**一次权威构建**(@build 0 错 0 警,Code=235236 RO=26308 RW=1572
ZI=136924)后同笔入库;台账已按该构建回填(`ram_baseline.py --update` + `--write`、`chec
k_mem_numbers.py
--write`),凭证与实际 .map 同源。归属如下:
· **通讯设置页**(道G task-9):新增 `Drivers/BSP/UI/ui_page_comm.{c,h}`(通道六注入,与死
区页同骨架同纪
律),`#page=comm` 绑定使 bound **21 → 22**、内容页黄金 **47 → 53**(旧 47 页字节零变化,
新增六态含
WAIT/OK 两张);`iec104_comm` 脏位 + store_save(**无事件位**)挂 defaultTask 同点位
轮询;`port_104` 由
宏改走 getter、`IEC104_SERV_PORT` 删除;字体 +听/监(185 字全覆)。**实机链已闭环**:FTP 外改
[comm]
的 ca/port → 复位 → 串口出现 `section 'comm' (2 keys)` 与 `i104: listening o
n 9004` → 还原 2404,全程无
FAIL ⇒「重启即生效 + 端口真值」不是推断是实测。上限核对 6/8 段、2/16 键,超限现象由 TC-CONFIG-056/057
钉死(注册 -1 + `comm init: FAIL` 锚 + getter 回 ROM),**不抬宏**。
· **开机账本**(道F task-12):新增 `App/util/boot_stats.{c,h}`——上电次数落 SD2506 用户
SRAM(magic +
小端计数 + 版本 + 异或校验),一次上电 = 1 读 + ≤1 写,**零 NAND、零卷锁、零配置段**;四态互斥
UNKNOWN / FRESH / CONTINUED / RESTARTED(BLF=1 才算电池域掉过电),**读失败绝不回写**;
文案口径「自 RTC
电池周期起」,**禁写终身次数**。复位原因优先级链从 `app_main.c` 的 if-else 收进一份真源(串口与屏幕同
源);104 四个只增不清计数 + `iec104_serv_get_stats()` 留在 serv、未塞进 link(会被 open
/close 洗掉)。
运行时长按用户裁定 = **只报本次开机以来**,零新增代码。新套件 `test/host/boot_stats` 21/21,五处注入
**全部有牙**(含「漂一字节被校验和挡下而不是报 256 倍错账」)。
· **adc_cal 可诊断化**(道E task-43):三个 volatile 计数 + `adc_cal_get_stats()`
/ `adc_cal_note_persisted()`
(水位**盖写非自增**,因为一次 save 覆盖整档,数 save 会留假未落盘);「差额 × 脏位」三态语义唯一落在
`adc_cal.h`,其中「差额 > 0 且脏位恒 0」= 绕过语义 setter 的静默丢失;TC-ADCCAL-019~023。
三条**必须留档的自纠**(都是执行道自己报的,我不替他们润色):
① stdint 那条断链是**宿主套件抓到、通讯道先修**,采集道承认自己是重复添加者并删掉自己那份;
② 「exit 2 不是证据,断言变红才是」——采集道第一版反证注入了未声明标识符导致编译错,差点当成功;
③ 套件汇总行原写 `s_total/s_total`,失败时会打印「21/21 PASSED (failed=1)」这种自相矛盾的行,已改。
另修:`check_registration.py` 的 `SIM_EXEMPT` 加一行豁免 `App/util/boot_stats.c
`(依赖 I2C 与 RCC 位掩码,
MCU 专属;核过 `sys_clock.c`/`sha256.c` 同形态先例),注册反向校验 exit 1 → 0。发号 TC-IEC1
04-034、
TC-UIDATA-029 已实抬游标(`TC-IEC104-033→034`、`TC-UIDATA-026→029`)。
门禁:id-check --strict 与 plain 均 rc=0、doc-links --all rc=0、注册校验 0、cppche
ck / coding-standard /
bom-drift 0;iec104 179/179、ui_data 295/295、boot_stats 21/21、adc_cal 11
7/117、run_par 67/67;菜单 8 状态
池 5368 不变、内容页 53/53。**已知遗留**:内容页数 47 → 53 的全仓文本同步尚未做(另卡跟踪),本笔只保
证代码与黄金一致;面板注键真机那一腿缺 CLI,交台架道补。
This commit is contained in:
@@ -36,6 +36,14 @@
|
||||
* 闭锁 / 两路齐第三路缺仍闭锁(全或无)/ 三路齐放行且 UB 仍无 VALID
|
||||
* (证明它是"三路"而不是 feed_eng 那个"8 路")/ 复位后立刻回闭锁
|
||||
* (现查、无自有状态可残留)
|
||||
* —— 以下四项是"改了没落盘"的可诊断化(道G task-43 第②项;四态**定义只在
|
||||
* App/algo/adc_cal.h 一处**,本表只描述断言、不重定义)——
|
||||
* TC-ADCCAL-019 观测件不得反过来制造故障:get_stats(NULL) 静默返回、随时可读
|
||||
* TC-ADCCAL-020 一次成功整定 → set_ok +1、水位不动 ⇒ 未落盘差额 = 1(改盘上没跟上,看得见)
|
||||
* TC-ADCCAL-021 多次整定 + 一次落盘回执 → 差额归 0(水位是**盖写**不是自增:一次 save
|
||||
* 覆盖整档,若自增会留下"假未落盘"——这条就是那个坑的回归锁)
|
||||
* TC-ADCCAL-022 被拒整定(非法通道 / 越出合法带)只加 set_reject,不污染 set_ok 与差额
|
||||
* TC-ADCCAL-023 空转回执不倒挂:水位永不越过 set_ok(uint32 相减一绕回就是巨大的假差额)
|
||||
*
|
||||
* 通过:全部 TC PASS(main 返回 0)。
|
||||
* 创建日期:2026-10-25(道A 卡 2/卡 4)
|
||||
@@ -524,6 +532,67 @@ static void tc_018_prot_blocked(void) {
|
||||
CHECK(adc_cal_prot_blocked() == 1u, "repeat call stable (idempotent pure read)");
|
||||
}
|
||||
|
||||
/* ============ 观测计数(改了没落盘 → 可诊断,道G task-43 第②项) ============ */
|
||||
/*
|
||||
* 四态定义只在 App/algo/adc_cal.h 一处;本用例**全部按增量断言**——静态计数跨用例
|
||||
* 累计,任何"绝对值等于几"的写法都会因为前面 TC 调过多少次 adc_cal_set() 而假失败
|
||||
* (也与 vol_lock 套件同一套写法先例)。
|
||||
*/
|
||||
static void tc_019_023_persist_obs(void) {
|
||||
adc_cal_stats_t s;
|
||||
uint32_t ok0;
|
||||
uint32_t rj0;
|
||||
|
||||
printf("-- TC-ADCCAL-019..023 persist observability --\n");
|
||||
|
||||
/* TC-ADCCAL-019:观测件不得反过来制造故障 */
|
||||
adc_cal_get_stats(NULL);
|
||||
CHECK(1, "get_stats(NULL) returns silently (an observer must not create a fault)");
|
||||
|
||||
/* 先立基线:把"到目前为止的改写"记为已落盘,后面全部按增量看 */
|
||||
adc_cal_note_persisted();
|
||||
adc_cal_get_stats(&s);
|
||||
CHECK(s.set_ok == s.persisted_set_ok, "after a sync point water catches count (gap == 0)");
|
||||
|
||||
/* TC-ADCCAL-020:一次成功整定 → 差额 1,水位不动 */
|
||||
ok0 = s.set_ok;
|
||||
rj0 = s.set_reject;
|
||||
CHECK(adc_cal_set(ADC_SEM_UA, ADC_CAL_K_Q16_TPAFE * 2, 100L) == 0, "in-band set accepted");
|
||||
adc_cal_get_stats(&s);
|
||||
CHECK(s.set_ok == ok0 + 1u, "set_ok incremented by exactly one");
|
||||
CHECK(s.set_reject == rj0, "set_reject untouched by a successful set");
|
||||
CHECK(s.persisted_set_ok == ok0, "water still at the old level (nothing saved yet)");
|
||||
CHECK(s.set_ok - s.persisted_set_ok == 1u, "gap == 1: RAM changed, disk not (the diagnosable fact)");
|
||||
|
||||
/* TC-ADCCAL-021:多次整定 + 一次落盘回执 → 差额归 0(水位是盖写不是自增) */
|
||||
CHECK(adc_cal_set(ADC_SEM_UN, ADC_CAL_K_Q16_TPAFE, -50L) == 0, "second channel set accepted");
|
||||
/* 合法带是 ROM 系数的 [0.5x, 2x](含端点,TC-ADCCAL-008 已钉)——这里必须留在带内,
|
||||
* 否则第二次改写被拒,差额就不是我声称的 3 了(写用例时踩过一次,改成 2x 上界) */
|
||||
CHECK(adc_cal_set(ADC_SEM_IA, ADC_CAL_K_Q16_TPAFE * 2, 7L) == 0, "third channel set accepted (band upper end)");
|
||||
adc_cal_get_stats(&s);
|
||||
CHECK(s.set_ok - s.persisted_set_ok == 3u, "three pending sets before the single save");
|
||||
adc_cal_note_persisted(); /* 一次 save 覆盖整档:等价 run_par_store_save() 成功路径 */
|
||||
adc_cal_get_stats(&s);
|
||||
CHECK(s.set_ok - s.persisted_set_ok == 0u, "one save clears all three pending sets (water is a snapshot, not a tick)");
|
||||
|
||||
/* TC-ADCCAL-022:被拒的两类整定只加 set_reject,不污染差额 */
|
||||
ok0 = s.set_ok;
|
||||
rj0 = s.set_reject;
|
||||
CHECK(adc_cal_set(ADC_SEM_TEMP, ADC_CAL_K_Q16_TPAFE, 0L) == -1, "TEMP rejected");
|
||||
CHECK(adc_cal_set(ADC_SEM_UA, ADC_CAL_K_Q16_TPAFE * 100, 0L) == -1, "out-of-band k rejected (RAM untouched)");
|
||||
adc_cal_get_stats(&s);
|
||||
CHECK(s.set_reject == rj0 + 2u, "set_reject counts both reject reasons");
|
||||
CHECK(s.set_ok == ok0, "rejected sets never inflate set_ok");
|
||||
CHECK(s.set_ok == s.persisted_set_ok, "gap stays zero across rejected attempts (no phantom pending write)");
|
||||
|
||||
/* TC-ADCCAL-023:空转回执不倒挂 */
|
||||
adc_cal_note_persisted();
|
||||
adc_cal_note_persisted();
|
||||
adc_cal_get_stats(&s);
|
||||
CHECK(s.persisted_set_ok == s.set_ok, "idle acks keep water exactly at the level (never overrun)");
|
||||
CHECK(s.set_ok >= s.persisted_set_ok, "subtraction can never wrap (gap stays non-negative)");
|
||||
}
|
||||
|
||||
/* ===================== main ===================== */
|
||||
int main(void) {
|
||||
printf("=== ADC Cal Layer Tests ===\n");
|
||||
@@ -544,6 +613,7 @@ int main(void) {
|
||||
tc_012_file_corrupt();
|
||||
tc_013_section_missing();
|
||||
tc_018_prot_blocked();
|
||||
tc_019_023_persist_obs();
|
||||
|
||||
printf("\n=== ADC Cal Layer Tests: %d/%d PASSED (failed=%d) ===\n",
|
||||
s_passed, s_total, s_failed);
|
||||
|
||||
Reference in New Issue
Block a user