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:
2026-10-27 11:29:23 +08:00
parent 0ae9c10f24
commit 728d60675f
47 changed files with 2364 additions and 123 deletions
+76
View File
@@ -22,6 +22,8 @@
* 作者:王建锋
* 创建日期:2026-10-25
* 修改记录:
* v1.x 2026-10-27 DTU 项目组 道G task-9:通道六通讯参数注入表
* (ui_data_comm_ops_t,通讯设置页消费)。
* v1.0 2026-10-25 王建锋 创建(道E task-14:契约 §4 快照层落地;相对契约
* 两通道新增第三条 info,划分理由见本头"通道划分"注
* 与契约 §4.4)
@@ -834,6 +836,80 @@ uint8_t ui_data_yt_cal_blocked(void);
*/
uint8_t ui_data_yt_pending(void);
/* ── 通道六:通讯参数([comm])整定注入(道G task-9,通讯设置页)───────
*
* 理由与通道五逐字同构(分层方向 layer-deps / 模拟器不链 App/protocol /
* "写值+置脏"原子性归执行侧),此处只记差异:
* ① 行数不进表——[comm] 就两个键(ca/port),行名与行数是**页面形状**,
* 不是数据源;lo/hi 与值由 row() 现给(合法带唯一出口 = iec104_comm.h
* 的带宏与 getter 守卫),页面不得抄数(通道五"第二真源"条同口径)。
* ② 生效语义与通道五不同档:port 下次重 bind 监听生效、ca **改后重启**
* 生效(页脚与保存行不承诺"立即生效",措辞口径见 ui_page_comm.c 头)。
* ③ 值域 u16 级,但通道口径走 uint32——编辑器值通道是 int32 定点,
* set() 收到 >65535 由执行侧带外拒(副本不动),页面不做二次守卫。
*/
/* 行下标(行序 = 页面行序,装配与页面各自钉死,TC 双向锁) */
#define UI_DATA_COMM_ROW_CA 0u /* 公共地址 1..65535(改后重启生效) */
#define UI_DATA_COMM_ROW_PORT 1u /* 监听端口 1024..65535(下次重 bind 生效) */
#define UI_DATA_COMM_ROW_N 2u
/* 一行通讯参数的现状(执行侧现给;无浮点,uint32 直达) */
typedef struct {
uint32_t val; /* 当前值(RAM 副本 getter) */
uint32_t lo; /* 合法带下限(含)——iec104_comm.h 带宏现给 */
uint32_t hi; /* 合法带上限(含)——同上 */
} ui_data_comm_row_t;
/* 执行侧函数表(常驻注入;整表校验、拒残表——通道四/五同款纪律) */
typedef struct {
/*
* 函数功能:读第 idx 行现状(值 + 合法带)
* 返回值:0 - 已整份写出;-1 - idx 越界 / 指针空 / 未注入侧无此行 int
*/
int (*row)(uint8_t a_idx, ui_data_comm_row_t *a_out);
/*
* 函数功能:写第 idx 行(真机 = iec104_comm_ca_set / iec104_comm_port_set)
* 返回值:0 - 副本已写且已置脏;-1 - 带外拒(副本未动、不置脏) int
*/
int (*set)(uint8_t a_idx, uint32_t a_val);
/*
* 函数功能:段级落盘脏位探查——真机 = iec104_comm_dirty_peek()
* 返回值:1 - 有已改未落盘;0 - 干净。落盘动力 = defaultTask 每轮无条件
* iec104_comm_store_save()(通道五注释里查实的那条链同款)。
* 页面按「结果锁存」画 WAIT/OK(他人 104 侧无自动写者,比通道五
* 更干净,但锁存纪律不变——同一条口径别做两套)
*/
uint8_t (*pending)(void);
} ui_data_comm_ops_t;
/*
* 函数功能:注入通讯参数执行侧函数表(启动期一次;形状对齐 ui_data_yt_bind)
* 入口参数:ops - 函数表(三件都不得为 NULL);NULL = 撤销注入(宿主测试用)
* 返回值:0 - 已注入/已撤销;-1 - 残表(存量不动;页面按"不可用"渲染) int
* 限定条件:uiTask 启动期、先于 ui_menu_init()(真机 = 装配层 tick 首轮懒绑,
* 与通道五同点位相邻)
*/
int ui_data_comm_bind(const ui_data_comm_ops_t *a_ops);
/*
* 函数功能:读第 idx 行通讯参数现状
* 返回值:0 - 已写出;-1 - 未注入 / 参数空 / idx 越界(退化显示,不猜) int
*/
int ui_data_comm_row(uint8_t a_idx, ui_data_comm_row_t *a_out);
/*
* 函数功能:写第 idx 行通讯参数
* 返回值:0 - 已写并置脏;-1 - 未注入或带外拒(未注入与拒绝同码,同通道五) int
*/
int ui_data_comm_set(uint8_t a_idx, uint32_t a_val);
/*
* 函数功能:[comm] 段落盘脏位探查(保存行三态判据)
* 返回值:1 - 有已改未落盘;0 - 干净或未注入 uint8_t
*/
uint8_t ui_data_comm_pending(void);
#ifdef __cplusplus
}
#endif