d64bbdc57f
数据面(App/algo,纯逻辑,双端编译) - wave_ring:8 路 × 320 点列优先环(1 kHz,预触发 160 + 后触发 160),adcTask 唯一写者;触发/冻结/封存/冷却四态,冻结持续到落盘回执才解冻,滞留 2 s 自弃 兜底——下一次真故障无波可录比丢一段更贵 - wave_store:段头编解码 + 拉模式打包游标 + 自带无表位运算 CRC-16/MODBUS(带 锚点自检)+ 段名与整段长度等式;格式不依赖平台类型宽度 - 段头只存原始码值与封存瞬间生效系数,工程量只当单位标签、不进任何算式 - 三套主机单测(环 113 / 编解码 170 / 触发状态机 110),全部无桩、生产源原样 纳入;新文件补 stddef 是 ARMCC 与主机差异,主机侧照不出这条分叉 - test/host/wave_read.py 是按 §6.2 的独立第二实现(dump/fft/shape/plot),92 条 自洽断言;三份合成段互读双校验全过、哈希钉死,格式面双向闭合 - 三套新单测不加专属钩子,由覆盖率总闸全量真跑(沿用既有裁定) 接线(任务层) - adc_cal:新增生效系数的 32 位定点原值入口(与既有浮点入口共用生效视图), 段头按最低有效位精确记账,不经浮点回算 - adcTask:每拍压 8 路语义原始码值并推进状态机,封存那一拍同拍交棒封存瞬间事实; 台架定周期自抓走双层编译门,产品镜像里零存在;串口新增一条 wave: 周期行 - defaultTask:卷空闲后一次心跳整段搬完(try 锁 + 256 字节分片 + 一次完整开档到 关档),成败都回执;失败先删半成品再计错,段号只在成功时推进;持锁超 50 ms 补一条告警并记历史峰值(喂狗余量可核) - Lead 复核补第四道并发陷阱:采集任务优先级高于落盘道,搬段中途它可能正好把滞留 超时的本段自弃、甚至封出下一段——数据区校验和是对「实际读到的字节」算的, 半新半旧的段照样自洽,故关档后复检环侧身份判废:删文件、不补账、段号不推进 - Lead 复核抓到触发挂号不是原子操作(旧实现分三个字节写,消费者可在窗口里读到 上一段的触发源与元件号):已把载荷压进一个字节,越界当场拒且不记任何计数; 段文件字节布局零改动,三份合成段哈希逐字节不变 - protectTask:保护启动上升沿同点请求录波,一拍一次、元件号取最低位;判据本体 零改动 人机(160×160 单色屏) - 菜单树节点 26「手动录波」绑页面 + 记录查询组末新增「录波回放」叶,重跑生成器 得 43 节点 / 34 叶 / 30 已绑,页面映射 28 → 30 - 回放页一屏一路、触发点前后各一周波共 40 点、每点 3 像素阶梯线(只用水平与 垂直两种线段——单色屏斜线会被阈值裁掉);零点虚线、触发光标、窗口峰值、 单位徽标与形状受限徽标;空态与坏段各一句显式文案,绝不用半截波形冒充数据 - ui_data 新增录波注入通道(六件操作表、三态返回);执行侧胶水带段头缓存、 手动请求后连缓存一起作废、逐点走全仓唯一的码值换算入口 - 模拟器接真实环与编解码合成两段(含坏段与空态旗标),6 张新黄金参考,既有 60 张逐字节零漂移未用更新模式;字库 218 → 224 字 / 319 字形 - 两份图形配置里图表组件仍为关;零堆分配;页面池水位不变 - 回放读路径的 uiTask 阻塞上界按实码写清:一次渲染 = 段表刷新 + 未缓存段头最坏 22 次小读;已验段只剩一次开窗读 + 40 点解码;无实测数不编,实测归台架、 仪器用已在跑的单轮工作耗时探针,不新加埋点 台账与文档 - 内存台账:录波环与落盘/回放静态逐条入册,三档对照 81,536 → 88,296 → 89,936 字节(62.2% → 68.6%),累计 +8,400;预估 5.9 KB 与实测 +6,760 的差额点名; 散列文件头注释同步;任务栈表核对后无需抬栈;体积趋势行与同码凭证由权威构建 重打(0 错误 0 警告,四项体积与上一轮相同——本轮改动只有注释与声明位置) - 设计说明:§5 补第四条并发陷阱;§6.3 定字段口径(两份独立实现的共同依据); §7 回填实测;§9 周期行写实;§10 台架判据改两段式且不比绝对相位;§12 补读路径 风险行;抬头状态改成「代码面已交付、未做完的只有板级那一轮」 - 卡片:软件闭环一栏列证据;台架三条按用户裁定保持未完成,不做虚假销项 - 口径同步:数据可信、UI 补齐、页面补齐规划、产品需求、采集短板评测、任务规划 索引与两份 README;陈旧现状句清扫 16 处(带日期戳的历史取数行一律不动) - 门禁说明:nested-comment 记仓库根探测必须兼容 linked worktree 的 gitdir 文件 形态(修前该钩子在任务树里恒报环境错、静默不可用);coding-standard 记 「函数头注释超过 24 行就把函数功能挤出回看窗口」这条机制与本次现场 - 覆盖率基线登记两个新覆盖模块(套件 41 → 44 套);环单测重打后该文件有效行 227 → 226、覆盖行 226 → 225,比率仍 99.6%,是分母变小不是覆盖率回退 为什么是单一提交:文档链接、双端注册、生成器幂等(菜单与字库)、内存数字与 体积事实源、编号门禁这五道整仓门禁要求代码、页面、菜单树、字库、文档与台账 同处一个提交才自洽,按数据面/接线/人机/台账拆成四笔必然红其中至少四道 编号门禁新增行 14 处命中已按语义改写:魔数常量按字符命名、段名样例改由格式串 生成、频谱表头改 f / 2x / 5x 并加一行图例;改写后自洽断言 92 条仍全过
1037 lines
61 KiB
C
1037 lines
61 KiB
C
/*
|
||
* 模块名称:UI 数据快照层(ui_data)
|
||
* 模块功能:App 层 → UI 层唯一数据通道的"存侧"——只持有最新一帧实时量(rt)/
|
||
* 参数(par)/装置信息(info) 快照 + 发布序号,给页面只读访问;
|
||
* 不取数、不格式化、不判断业务含义(职责边界 =
|
||
* docs/UI设计/UI_数据供给设计说明.md §3.2)
|
||
* 适用范围:Drivers/BSP/UI(表现层叶子:不 include 任何 App 头、不 include 任何
|
||
* 页面头、不碰 LVGL——分层方向由 scripts/check_layer_deps.py 守护,
|
||
* BSP → App 反向 include 一律拦提交)
|
||
* 并发模型:写侧 = App/app/ui_data_feed.c(唯一发布者);读侧 = ui_page_* 的绘制/
|
||
* 按键钩子。两侧同在 uiTask 上下文串行执行 → 无锁、无双缓冲、无 seqlock
|
||
* (判据与"将来出现第二发布者"时的扩展路径见
|
||
* docs/UI设计/UI_数据供给设计说明.md §5.1)
|
||
* 页面用法:行缓存按"发布序号变过才整帧拷"门控,勿逐行整帧拷贝
|
||
* (docs/UI设计/UI_数据供给设计说明.md §5.4):
|
||
* static ui_data_rt_t s_rt;
|
||
* static uint32_t s_seq;
|
||
* if (ui_data_rt_seq() != s_seq) {
|
||
* (void)ui_data_rt(&s_rt);
|
||
* s_seq = ui_data_rt_seq();
|
||
* }
|
||
* 作者:王建锋
|
||
* 创建日期: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)
|
||
* v1.1 2026-10-26 DTU 项目组 道F task-1(docs/任务规划/UI补齐.md §2 第 1 行):
|
||
* 新增定值写路径(param_request/param_state/
|
||
* param_drain,契约 §6.2 深度 4 环形队列)+ 参数帧尾
|
||
* 追加 cal_block(UI_DATA_VER 1→2,整定页"未标定"徽标
|
||
* 的数据源);写路径仍不引入任何 App 依赖(执行事实
|
||
* 经 ui_data_param_ops_t 由 App 侧注入,同契约 §7.2
|
||
* 记录页注入式 reader 的路子)
|
||
* v1.2 2026-10-26 DTU 项目组 道F task-3(docs/任务规划/UI补齐.md §2 第 3 行
|
||
* 「装置维护 3 页」的前置):新增通道四——维护写请求
|
||
* (ui_data_maint_*:墙钟设置 / 强制复归 / 清除记录,
|
||
* 常驻注入 ui_data_maint_ops_t)与时钟字段换算
|
||
* (ui_data_clock_*,本地域无时区偏移,兼作"无效值
|
||
* 拒收"的唯一判据处)。三通道快照结构未变 ⇒
|
||
* UI_DATA_VER 仍为 2。仍然零 App include:维护动作的
|
||
* 真源全在 App 侧,本层只转达请求与结果(同 §7.2);
|
||
* ⚠ 页面也不得直调 sys_clock_*——模拟器没链 sys_clock,
|
||
* 那种写法只在模拟器链接期才炸,理由见通道四表注
|
||
*/
|
||
|
||
#ifndef UI_DATA_H
|
||
#define UI_DATA_H
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
#include <stdint.h>
|
||
|
||
/*
|
||
* 契约版本:结构体字段只允许尾部追加,追加即升此值并在写侧填默认值
|
||
* (禁止删除或重排字段——页面按名字取,重排是静默错位;
|
||
* 口径 docs/UI设计/UI_数据供给设计说明.md §4.3)
|
||
*/
|
||
/* v2(2026-10-26,道F task-1):ui_data_par_t 尾追加 cal_block——版本号是页面与
|
||
* 写侧唯一的对齐凭据,追加字段不升版 = 老页面按新帧长 memcpy 时静默错位 */
|
||
#define UI_DATA_VER 2u
|
||
|
||
/* ── 通道数量 ─────────────────────────────────────────────────────────────── */
|
||
|
||
/* 遥测语义通道数:下标序 = adc_semantic_t(UA/UB/UC/UN/IA/IB/IC/IN/TEMP)。
|
||
* BSP 侧不得 include App 头,故"两数相等"的编译期守卫落在写侧
|
||
* App/app/ui_data_feed.c,语义逐项对齐的断言落在 test/host/ui_data/
|
||
* (docs/UI设计/UI_数据供给设计说明.md §9.4 一致性测试) */
|
||
#define UI_DATA_YC_N 9u
|
||
/* 遥信点数:与 104 点表同序(bit i = 第 i 点),页面名表按点表逐行登记 */
|
||
#define UI_DATA_YX_N 33u
|
||
/* 定值项数:与 prot_set 枚举同序(校验和覆盖序),四视图划分不改序 */
|
||
#define UI_DATA_SET_N 40u
|
||
/* 相量实例槽上限:谐波(Ia 二次/五次)不能塞进"语义通道"下标空间——同一通道
|
||
* 的二次/五次谐波会与基波撞位,故实时帧另开一条按**相量实例序**索引的槽位,
|
||
* 供交流量页显示 Ia2/Ia5;实际发布槽数由 ph_n 给出,超出上限的实例本帧不发布
|
||
* (写侧口径见 App/app/ui_data_feed.c 的 fill_rt 函数)。上限取 8 = 现用 5 实例
|
||
* (IA/UA/UN 基波 + IA 二次/五次)+ 遥测谐波轨留位,每槽 8 B */
|
||
#define UI_DATA_PH_MAX 8u
|
||
|
||
/* ── 量纲口径 eng(诚实性字段:数值 val 的单位由它决定)───────────────────── */
|
||
|
||
/*
|
||
* 真值语义(现场口径 = docs/任务规划/数据可信.md §2.6 的承诺边界 + §4.2 三态
|
||
* 可用性;契约文档原先写的"0 = 原始码值(未标定)"是标定落地前的旧口径,
|
||
* 已按本表更正,勿再照抄旧表述):
|
||
* ENG_PIN 引脚电压 V —— 现状:adc_cal 的 ROM 默认系数是「数据可信」量程口径冻结定死
|
||
* 的引脚侧 LSB(TPAFE 152.59 uV/码、STM32 805.66 uV/码),采样环
|
||
* 折算出来的就是 ADC 引脚电压,不是端子二次值
|
||
* ENG_SEC 二次值 —— 电气 8 路 adc_cal_flags() 的 VALID 全置位(拿到端子变比
|
||
* 并完成两点标定)后由写侧升档,页面自动按二次值显示,零改动
|
||
* ENG_PRI 一次值 —— 预留(再乘 PT/CT 变比),当前写侧不会产出
|
||
*/
|
||
#define UI_DATA_ENG_PIN 0u
|
||
#define UI_DATA_ENG_SEC 1u
|
||
#define UI_DATA_ENG_PRI 2u
|
||
|
||
/* ── 品质位(与 104 QDS 语义对齐;页面只消费自己关心的位)─────────────────── */
|
||
|
||
#define UI_DATA_Q_IV 0x01u /* 无效:该通道无源/不可用 → 页面显示 "--" */
|
||
#define UI_DATA_Q_NT 0x02u /* 未就绪:尚未攒满一周波/未收敛 */
|
||
#define UI_DATA_Q_OV 0x04u /* 越限:超过量程/硬件削顶(V0.1 STM32 侧单极性) */
|
||
#define UI_DATA_Q_SB 0x08u /* 取代值(虚拟注入/替身值,页面应带角标) */
|
||
#define UI_DATA_Q_BL 0x10u /* 闭锁:该量被业务闭锁(未标定闭锁/采样闭锁) */
|
||
/* 原始码值域:val 不是工程量而是转换器码值——TEMP 不参与线性标定
|
||
* (docs/任务规划/数据可信.md §4.2 的"TEMP 透传码值"决策),有此位即页面
|
||
* 不得给 val 挂 V/A 单位,也不得与工程量互比 */
|
||
#define UI_DATA_Q_RAW 0x20u
|
||
|
||
/* ── 字符串容量(结构体内定长数组,跨层零指针;容量宏本地化)──────────────── */
|
||
|
||
#define UI_DATA_CLOCK_LEN 20u /* "YYYY-MM-DD HH:MM:SS" 19 + NUL */
|
||
#define UI_DATA_MODEL_LEN 8u /* 终端型号("F30") */
|
||
#define UI_DATA_VERSTR_LEN 16u /* 软件/硬件版本串 */
|
||
#define UI_DATA_DATE_LEN 12u /* 程序日期(编译期 __DATE__,留 NUL 余量) */
|
||
#define UI_DATA_SUM_LEN 8u /* 软件校验(无构建期 CRC 步骤时如实为 "--") */
|
||
#define UI_DATA_FUSER_LEN 16u /* FTP 用户名;与 Drivers/BSP/NETCFG/ftp_cfg.h 的
|
||
* FTP_CFG_USER_MAX 同宽,写侧受该上限约束 */
|
||
|
||
/* ── 通道一:实时量(写侧节拍 200 ms)────────────────────────────────────── */
|
||
|
||
/* 单路遥测:数值 + 品质 */
|
||
typedef struct {
|
||
float val; /* 数值;单位口径由 ui_data_rt_t.eng 决定,RAW 位另说 */
|
||
uint8_t qds; /* 品质位组合(UI_DATA_Q_*) */
|
||
uint8_t rsv[3]; /* 对齐填充(显式命名,勿留匿名空洞) */
|
||
} ui_data_yc_t;
|
||
|
||
/* 实时快照:遥测 9 路 + 遥信位图 + 频率 + 墙钟 */
|
||
typedef struct {
|
||
uint32_t seq; /* 发布序号(本层盖章,单调递增) */
|
||
uint32_t tick_ms; /* 发布时刻(tick 域,差值法可比) */
|
||
uint8_t valid; /* 0 = 尚无首帧(页面全显 "--") */
|
||
uint8_t eng; /* 量纲口径(UI_DATA_ENG_*) */
|
||
uint8_t rsv[2]; /* 预留(对齐填充) */
|
||
ui_data_yc_t yc[UI_DATA_YC_N]; /* 下标 = adc_semantic_t 语义序(基波有效值) */
|
||
uint8_t ph_n; /* 本帧发布的相量实例槽数(0..UI_DATA_PH_MAX) */
|
||
uint8_t rsv4[3]; /* 预留(对齐填充) */
|
||
ui_data_yc_t ph[UI_DATA_PH_MAX]; /* 下标 = 相量实例序(含谐波),见 UI_DATA_PH_MAX 注 */
|
||
uint64_t yx_bits; /* 遥信位图:bit i = 第 i 点"合/动作" */
|
||
uint64_t yx_valid; /* 遥信有效位图: bit i = 1 该点有硬件来源 */
|
||
uint64_t yx_dp; /* 遥信双点位图: bit i = 1 该点是双点型(M_DP)
|
||
* 值列打"合位/分位",单点打"动作/复归"。
|
||
* 为什么下发位图而不让页面自己认定"前 4 点是
|
||
* 双点":单/双点是**104 点表事实**(见
|
||
* App/protocol/iec104/iec104_pts.c 的 YX_DP_N 与
|
||
* iec104_pts_yx_is_dp),抄一份进表现层就是第二
|
||
* 真相——点表把某点改成双点、或把双点段挪到下标
|
||
* 中段,屏上不会报错,只会用错词形容同一个点。
|
||
* V0.1 双点 4 点无开入硬件 → 不在 yx_valid 内,
|
||
* 值列仍是 "--"(本字段不参与无效判定) */
|
||
uint8_t freq_valid; /* 1 = 测频读数新鲜(幅值门 OK 且已收敛) */
|
||
uint8_t rsv2[3]; /* 预留(对齐填充) */
|
||
float freq_hz; /* 测得频率(Hz);freq_valid=0 时不可消费 */
|
||
uint8_t clock_ok; /* 0 = 墙钟无效(RTC 异常/未对时) */
|
||
uint8_t rsv3[3]; /* 预留(对齐填充) */
|
||
char clock[UI_DATA_CLOCK_LEN]; /* "YYYY-MM-DD HH:MM:SS";无效时空串 */
|
||
} ui_data_rt_t;
|
||
|
||
/* ── 通道二:参数(写侧节拍 = 定值校验和变化才发)────────────────────────── */
|
||
|
||
/*
|
||
* 参数快照:40 项定值 Q10 原值 + 封存态
|
||
* 存 Q10 而非 float 的理由:定值是整表校验和覆盖的定点值,快照存浮点会引入
|
||
* "显示值与校验和口径不一致"的二义性(Q10 → 显示小数位换算属表现层,见
|
||
* docs/UI设计/UI_数据供给设计说明.md §8)
|
||
*/
|
||
typedef struct {
|
||
uint32_t seq; /* 发布序号(本层盖章) */
|
||
uint32_t checksum; /* 与 prot_set_checksum() 同值:页面据此判"参数变过" */
|
||
uint8_t valid; /* 0 = 尚无首帧 */
|
||
uint8_t locked; /* 1 = 定值闭锁(校验和自检失败等)→ 页面禁编辑 */
|
||
uint8_t bad_valid; /* 1 = bad_mask 有意义(整表装载/提交失败之后) */
|
||
uint8_t rsv; /* 预留 */
|
||
uint64_t bad_mask; /* 40 位:置 1 = 该定值项越界(页面反显该行) */
|
||
int32_t q10[UI_DATA_SET_N]; /* Q10 原值,下标 = prot_set_id_t 枚举序 */
|
||
/* v2 尾追加:未标定闭锁(整定页"未标定"徽标的数据源)。
|
||
* 1 = UA/UN/IA 三路里至少一路的标定 VALID 未置位 → 保护判据当前停走,页面必须
|
||
* 让用户看见"改了定值也不会动作";0 = 三路全 VALID(判据在跑)。
|
||
* ⚠ 口径**不是** rt.eng:eng 是整帧量纲档(要求电气 8 路全 VALID),V0.1 双
|
||
* 转换器下 UB/UC/IB/IC/IN 永不置位 → eng 恒为引脚档,照 eng 画徽标就成了
|
||
* "标定做完屏上仍永不解锁"。三路口径的权威实现 = App/task/protect_task.c
|
||
* 的 s_cal_locked()(写侧 App/app/ui_data_feed.c 按同一条判据现算,本层只存
|
||
* 真值、不判断)。与上面 locked(定值校验和自检闭锁 = 禁编辑)是两件事,
|
||
* 屏上不得互认(三词三源见 docs/任务规划/数据可信.md §4.3) */
|
||
uint8_t cal_block;
|
||
} ui_data_par_t;
|
||
|
||
/* ── 通道三:装置信息(静态身份 + 通讯参数 + 运行时长)───────────────────── */
|
||
|
||
/*
|
||
* 装置信息快照(通道划分理由见本头文件头,契约侧同一条登记在
|
||
* docs/UI设计/UI_数据供给设计说明.md §4.4——同一事实只在一处详述)
|
||
* 写侧随 rt 同节拍发布(内容基本不变,代价是一次约 90 B 拷贝)
|
||
*/
|
||
typedef struct {
|
||
uint32_t seq; /* 发布序号(本层盖章) */
|
||
uint8_t valid; /* 0 = 尚无首帧 */
|
||
uint8_t rsv[3]; /* 预留(对齐填充) */
|
||
uint32_t uptime_s; /* 开机运行时长(秒;写侧按 tick 差算) */
|
||
uint16_t port_104; /* IEC 60870-5-104 上行监听端口 */
|
||
uint16_t port_disp; /* 远程显示(RemoDispBus)端口 */
|
||
char model[UI_DATA_MODEL_LEN]; /* 终端型号 */
|
||
char sw_ver[UI_DATA_VERSTR_LEN]; /* 软件版本 */
|
||
char hw_ver[UI_DATA_VERSTR_LEN]; /* 硬件版本 */
|
||
char build_date[UI_DATA_DATE_LEN]; /* 程序日期(编译期) */
|
||
char sw_sum[UI_DATA_SUM_LEN]; /* 软件校验;无构建期 CRC 步骤 = "--" */
|
||
char ftp_user[UI_DATA_FUSER_LEN]; /* FTP 登录用户名(只显名,不显口令) */
|
||
/* ── 运行报告四数(2026-10-28 UI 补齐「运行报告」;BSP 侧只搬运、不算第二份,
|
||
* 口径唯一出处 = App/util/boot_stats.h 的四数台账与 App/task/iec104_serv.h
|
||
* 的观测计数注;屏上文案(含"禁写终身次数"这类口径)归 UI 页面侧
|
||
* <Drivers/BSP/UI/ui_page_runreport.c>,分层方向由 layer-deps 门禁守护 ── */
|
||
uint32_t boot_count; /* 上电次数(掉电保持,自 RTC 电池周期起);
|
||
boot_seq_state == 0(UNKNOWN)时不可信 */
|
||
uint8_t boot_seq_state; /* 0 未知 / 1 首次启用 / 2 延续 / 3 电池域掉过重开 */
|
||
uint8_t boot_write_failed; /* 1 = 本次自增没写回 RTC SRAM(账本只会少不会重) */
|
||
uint8_t rst_cause; /* 本次开机复位原因编码(BOOT_STATS_CAUSE_*) */
|
||
uint8_t boot_ready; /* 0 = 开机账本未初始化 → 整组按占位显示,不得读成 0 */
|
||
uint32_t iec104_conn_up; /* 主站接入次数(本次开机以来,跨重连不清零) */
|
||
uint32_t iec104_apdu_tx; /* 成功发出的 APDU 帧数(短写不算,落在 tx_fail) */
|
||
uint32_t iec104_tx_fail; /* 发送短写/失败次数 */
|
||
uint32_t iec104_rx_bytes; /* 收到的**字节**数(帧边界在 link 层,serv 看不见帧) */
|
||
} ui_data_info_t;
|
||
|
||
/* ── 初始化 ───────────────────────────────────────────────────────────────── */
|
||
|
||
/*
|
||
* 函数功能:快照层初始化——三通道清零(valid=0、seq=0),页面即按"无首帧"渲染
|
||
* 入口参数:无
|
||
* 返回值:无
|
||
* 限定条件:内核启动前可调(纯内存操作,零 OS 依赖);可重复调用(幂等)
|
||
* 函数说明:静态存储上电本已清零,本函数的意义是运行期复位(例如"恢复出厂后
|
||
* 重开 UI"这类后续路径),以及让宿主侧测试能随时造出"首帧之前"的状态
|
||
*/
|
||
void ui_data_init(void);
|
||
|
||
/* ── 发布(写侧唯一入口;单写者同上下文,无锁)───────────────────────────── */
|
||
|
||
/*
|
||
* 函数功能:发布一帧实时量快照(覆盖存量并给 seq 盖章 +1)
|
||
* 入口参数:a_snap - 源帧(本层整帧拷入自有存储,调用方可复用其栈/静态空间)
|
||
* const ui_data_rt_t *
|
||
* 返回值:0 - 已发布;-1 - 参数无效(NULL,存量不动) int
|
||
* 限定条件:唯一发布者 = App/app/ui_data_feed.c,uiTask 上下文
|
||
* 函数说明:seq 由本层盖章(写侧不必填);其余字段原样入存,本层不做任何业务
|
||
* 判断与格式化
|
||
*/
|
||
int ui_data_publish_rt(const ui_data_rt_t *a_snap);
|
||
|
||
/*
|
||
* 函数功能:发布一帧参数快照(覆盖存量并给 seq 盖章 +1)
|
||
* 入口参数:a_snap - 源帧 const ui_data_par_t *
|
||
* 返回值:0 - 已发布;-1 - 参数无效(NULL,存量不动) int
|
||
* 限定条件:同上;发布节拍 = 定值校验和变化才发
|
||
* (docs/UI设计/UI_数据供给设计说明.md §5.2)
|
||
*/
|
||
int ui_data_publish_par(const ui_data_par_t *a_snap);
|
||
|
||
/*
|
||
* 函数功能:发布一帧装置信息快照(覆盖存量并给 seq 盖章 +1)
|
||
* 入口参数:a_snap - 源帧 const ui_data_info_t *
|
||
* 返回值:0 - 已发布;-1 - 参数无效(NULL,存量不动) int
|
||
* 限定条件:同上
|
||
*/
|
||
int ui_data_publish_info(const ui_data_info_t *a_snap);
|
||
|
||
/* ── 只读访问(页面侧)───────────────────────────────────────────────────── */
|
||
|
||
/*
|
||
* 函数功能:读最新一帧实时量快照(整帧拷给页面私有缓存)
|
||
* 入口参数:a_out - 输出缓冲(非 NULL) ui_data_rt_t *
|
||
* 返回值:0 - 已拷出;-1 - 尚无首帧(输出不动,页面显示 "--");
|
||
* -2 - 参数无效(NULL) int
|
||
* 限定条件:页面钩子上下文(uiTask);勿在逐行 refresh 里无条件整帧拷贝,
|
||
* 先比 ui_data_rt_seq()(用法见本头文件头)
|
||
*/
|
||
int ui_data_rt(ui_data_rt_t *a_out);
|
||
|
||
/*
|
||
* 函数功能:读最新一帧参数快照
|
||
* 入口参数:a_out - 输出缓冲(非 NULL) ui_data_par_t *
|
||
* 返回值:0 - 已拷出;-1 - 尚无首帧(输出不动);-2 - 参数无效 int
|
||
* 限定条件:同上;定值页同样用 ui_data_par_seq() 门控页面私有缓存
|
||
*/
|
||
int ui_data_par(ui_data_par_t *a_out);
|
||
|
||
/*
|
||
* 函数功能:读最新一帧装置信息快照
|
||
* 入口参数:a_out - 输出缓冲(非 NULL) ui_data_info_t *
|
||
* 返回值:0 - 已拷出;-1 - 尚无首帧(输出不动);-2 - 参数无效 int
|
||
* 限定条件:同上
|
||
*/
|
||
int ui_data_info(ui_data_info_t *a_out);
|
||
|
||
/*
|
||
* 函数功能:查实时帧发布序号(页面缓存失效判据)
|
||
* 入口参数:无
|
||
* 返回值:当前 seq;从未发布 = 0 uint32_t
|
||
* 限定条件:无(只读单字,任意上下文安全)
|
||
* 函数说明:轻量查询——只读一个 uint32,可逐行调用(契约 §5.4 的门控就靠它)
|
||
*/
|
||
uint32_t ui_data_rt_seq(void);
|
||
|
||
/*
|
||
* 函数功能:查参数帧发布序号
|
||
* 入口参数:无
|
||
* 返回值:当前 seq;从未发布 = 0 uint32_t
|
||
* 限定条件:无
|
||
*/
|
||
uint32_t ui_data_par_seq(void);
|
||
|
||
/*
|
||
* 函数功能:查装置信息帧发布序号
|
||
* 入口参数:无
|
||
* 返回值:当前 seq;从未发布 = 0 uint32_t
|
||
* 限定条件:无
|
||
*/
|
||
uint32_t ui_data_info_seq(void);
|
||
|
||
/* ── 写路径:定值整定请求(页面只投递,执行在 App 侧)───────────────────── */
|
||
|
||
/*
|
||
* 请求队列深度(契约 docs/UI设计/UI_数据供给设计说明.md §6.2 定死 4)
|
||
* 为什么是 4 不是 1:整定页"保存"是用户按键,一条请求要等 App 侧 drain 才落定;
|
||
* 深度 1 会让连按两次保存把第二条判成"忙",而 4 格 = 本层 .bss 多
|
||
* 4 × sizeof(ui_data_param_req_t)(168 B/格,主机单测 TC-UIDATA-016 钉住尺寸,
|
||
* 内存台账 docs/内存管理/RAM使用分析与优化方案.md)。加深 = 纯 RAM 代价,
|
||
* 本层不做任何按内存自适应
|
||
*/
|
||
#define UI_DATA_PARAM_QD 4u
|
||
|
||
/*
|
||
* 一条定值写入请求 = "本次保存改了哪些项 + 它们的 Q10 新值"
|
||
*
|
||
* 为什么是「位图 + 定长 40 槽」而不是「项数 + 变长 id 数组」:表现层编辑叠层本就
|
||
* 是一张改动位图(uint64_t)+ 一张工作值表(int32_t[UI_DATA_SET_N]),本形状与它
|
||
* 逐位同构 → 提交侧一次 memcpy、执行侧逐项按位取,两侧都不必再维护第三种表示;
|
||
* 定长还让队列退化成 O(1) 静态环形数组(零堆、零变长拷贝、零 malloc 门禁风险)。
|
||
*
|
||
* ⚠ mask 只有 64 位 → 定值项数硬上限 64;越界位由 ui_data.c 的编译期守卫拦住,
|
||
* 将来项数破 64 必须换表示(不会静默丢项)。
|
||
* ⚠ **mask 未置位的槽本次不提交**:本层与执行侧都不读它——调用方可以只填 mask 内
|
||
* 的槽(整帧 memcpy 入队会把 mask 外的字节一并存下来,但那字节永不被读,不影响
|
||
* 任何判定;先 memset 再填也完全可以,两种写法都安全)。
|
||
* 绝不允许"从显示值回提全表"——Q10 存不下 0.95 这类返回系数(真存 972/1024),
|
||
* 按显示域往返会把用户没动的项顺手改掉
|
||
* (docs/任务规划/UI补齐.md §2 第 2 行判据"值不落盘"的前提)。
|
||
*/
|
||
typedef struct {
|
||
uint64_t mask; /* bit i = 1 → 第 i 项随本请求提交 */
|
||
int32_t q10[UI_DATA_SET_N]; /* Q10 新值;仅 mask 置位的槽有意义 */
|
||
} ui_data_param_req_t;
|
||
|
||
/*
|
||
* 写路径状态(页面保存行显示;语义表 = 契约 §6.3)
|
||
* IDLE - 从未投递 → 页面显 ENTER
|
||
* WAIT - 已投递未落定(队列里还有请求在路上)→ 页面显 WAIT
|
||
* OK - 最近一条已逐项写入并置脏 → 页面显 OK
|
||
* ERR_RANGE - 最近一条整批拒绝:任一项越界 → 一字未写 → 页面显 ERR 并高亮
|
||
* 越界行(越界项经 ui_data_param_err_mask() 取)
|
||
* ERR_LOCKED - 最近一条被定值闭锁拒(写侧自检失败态)→ 页面显 LOCK 并禁编辑
|
||
* ERR_BUSY - 最近一次投递被拒:队列满 → 页面显 ERR、页脚"忙,请重试"
|
||
* 状态变量的三条写入路径(本层唯二写者 = request 与 drain,同在 uiTask):
|
||
* 投递成功 → WAIT;投递被拒(满)→ ERR_BUSY;drain 落定 → 终态,但队列仍有
|
||
* 残留时改写回 WAIT。故"满被拒"看得见(ERR_BUSY),随后逐步 drain 又回到 WAIT
|
||
*/
|
||
#define UI_DATA_PARAM_ST_IDLE 0
|
||
#define UI_DATA_PARAM_ST_WAIT 1
|
||
#define UI_DATA_PARAM_ST_OK 2
|
||
#define UI_DATA_PARAM_ST_ERR_RANGE 3
|
||
#define UI_DATA_PARAM_ST_ERR_LOCKED 4
|
||
#define UI_DATA_PARAM_ST_ERR_BUSY 5
|
||
|
||
/*
|
||
* 执行侧函数表(由 App 在 ui_data_feed_tick() 每次调用时传入;本层不保存副本)
|
||
*
|
||
* 为什么用注入而不是直接调 prot_set:分层方向硬约束——Drivers/BSP 不得 include
|
||
* App 头(scripts/check_layer_deps.py 拦提交),而"什么算越界、写了要不要置脏"
|
||
* 全在 App/algo/prot_set 那侧。同契约 §7.2 记录页的注入式 reader:BSP 声明抽象
|
||
* 函数表,App 给实现,主机单测给桩 → 队列与状态机的**生产代码**能在 PC 上跑
|
||
* 全表(越界不改值 / 闭锁拒写 / 正常往返三条判据都覆盖到真代码,不是副本)。
|
||
* ⚠ 本表不含任何"范围数值"——上下限真源仍是 App/algo/prot_set.c 的
|
||
* g_prot_set_meta,本层只按 check() 的返回值决定整批写不写(不新增第二真源)
|
||
*/
|
||
typedef struct {
|
||
uint8_t (*locked)(void); /* 1 = 定值闭锁中 */
|
||
int (*check)(uint8_t a_id, int32_t a_q10); /* 0 合法 / -1 越界 */
|
||
int (*apply)(uint8_t a_id, int32_t a_q10); /* 0 成功 / -1 失败 */
|
||
} ui_data_param_ops_t;
|
||
|
||
/*
|
||
* 函数功能:投递一条定值写入请求(页面"保存"行的唯一出口——只投递,不执行)
|
||
* 入口参数:a_req - 请求(mask 与 q10 整条拷入队列,调用方可复用其栈空间)
|
||
* const ui_data_param_req_t *
|
||
* 返回值:0 - 已入队(状态转 WAIT);mask 为 0 的空请求也返回 0,但按"无改动可
|
||
* 保存"直接落终态 OK 且**不占槽位**(保存行 ENTER 时一个都没改
|
||
* 是正常操作,报 ERR 会让现场以为设备有问题);
|
||
* -1 - 队列满(状态转 ERR_BUSY,在队请求一条不动);
|
||
* -2 - 参数无效:NULL、或 mask 含 UI_DATA_SET_N 以上的位
|
||
* (状态与队列都不动:调用方的编程错误不该落成屏上的"越界") int
|
||
* 限定条件:uiTask 上下文(页面按键钩子);与 drain 同上下文 → 无锁
|
||
* 函数说明:本函数**不**校验值域(越界与否是执行侧事实,在 drain 里整批预检),
|
||
* 也不碰 prot_set、不碰文件系统(落盘归 defaultTask,AGENTS 模块约定)
|
||
*/
|
||
int ui_data_param_request(const ui_data_param_req_t *a_req);
|
||
|
||
/*
|
||
* 函数功能:取写路径状态(页面保存行显示)
|
||
* 入口参数:无
|
||
* 返回值:UI_DATA_PARAM_ST_* 之一 int
|
||
* 限定条件:无(只读单字,任意上下文安全)
|
||
* 函数说明:ERR_TIMEOUT(契约 §6.3 的"3 s 未取走")本层**不产出**——uiTask 每
|
||
* 10 ms 就 drain 一次,真出现"永不落定"说明 App 侧没接线,属装配缺陷;
|
||
* 页面若要兜底可自己按投递时刻计时(docs/UI设计/UI_数据供给设计说明.md
|
||
* §6.3 已把它列为页面本地可选项)
|
||
*/
|
||
int ui_data_param_state(void);
|
||
|
||
/*
|
||
* 函数功能:取最近一条请求的越界项位图(页面高亮越界行)
|
||
* 入口参数:无
|
||
* 返回值:bit i = 1 → 第 i 项越界;最近终态不是 ERR_RANGE 时恒 0 uint64_t
|
||
* 限定条件:无(只读单字)
|
||
* 函数说明:与 ui_data_par_t.bad_mask 是两条不同来源——bad_mask 是 prot_set 整表
|
||
* 装载/解析留下的越界位图(App 侧事实),本函数是**本次提交**里被预检
|
||
* 挡下的项;页面在 ERR_RANGE 那一帧用本函数,别把两者混成一份
|
||
*/
|
||
uint64_t ui_data_param_err_mask(void);
|
||
|
||
/*
|
||
* 函数功能:处理一条定值写入请求(App 装配层节拍入口;出队 → 判定 → 落定)
|
||
* 入口参数:a_ops - 执行侧函数表(三个函数指针都不得为 NULL)
|
||
* const ui_data_param_ops_t *
|
||
* 返回值:1 - 处理并提交了一条(状态已落终态或转 WAIT);0 - 队列空(状态不动);
|
||
* -1 - 参数无效(ops 或其函数指针为 NULL,队列与状态都不动) int
|
||
* 限定条件:uiTask 上下文,紧跟页面之后调(App/app/ui_data_feed.c 的 tick);
|
||
* 每轮最多处理一条——整定是低频人工事件,一轮一条已够,且把最坏耗时
|
||
* 钉在 40 次 check + 40 次 apply,不会随队列堆积而抖动
|
||
* 函数说明:固定四步(顺序即判据,契约 §6.2)——
|
||
* ① 取队首一条;② ops->locked() 非 0 → ERR_LOCKED,**本条丢弃**(闭锁
|
||
* 是业务态,用户解闭锁后重新提交;不做"排队等解锁",那会让屏上的 WAIT
|
||
* 无限期挂着);③ 按 mask 逐项 ops->check() 整批预检,任一项越界 →
|
||
* ERR_RANGE 且**一字不写**(all-or-nothing,与 prot_set_load_raw 同纪律),
|
||
* 越界项记入 err_mask;④ 预检全过再逐项 ops->apply(),全成 → OK。
|
||
* ④ 中途失败(预检已过仍失败 = 执行侧与预检不一致,理论不可达)不回滚:
|
||
* prot_set 无回滚接口,谎称"整批未写"比如实报 ERR_RANGE 更坏,故按实际
|
||
* 失败项置 err_mask 后报 ERR_RANGE,并在注释里写明可能部分已生效
|
||
*/
|
||
int ui_data_param_drain(const ui_data_param_ops_t *a_ops);
|
||
|
||
/* ── 通道四:装置维护写请求(时钟 / 强制复归 / 清除记录)───────────────────── */
|
||
|
||
/*
|
||
* 执行侧函数表(道F task-3 新增;注入式,与 ui_data_param_ops_t、
|
||
* ui_w_records.h 的 ui_rec_reader_t 同一条路子)
|
||
*
|
||
* 为什么是注入而不是直接调:分层方向硬约束——BSP 层目录 Drivers/BSP 不得反向
|
||
* include App 层的头(scripts/check_layer_deps.py 拦提交),而 sys_clock_set_unix /
|
||
* prot_elm_request_reset / syslog_request_clear 三件事实的属主全在 App 侧。
|
||
* ⚠ **另有一条同样硬的理由**:模拟器根本没有 sys_clock
|
||
* (simulator/dbg_log.h:4「模拟器无 sys_clock/RTC」,CMakeLists 也没这份源),
|
||
* 所以页面里哪怕只用一次 sys_clock_*,也是"MCU 编得过、模拟器链接期爆",
|
||
* 而这种错只在另一端构建时才暴露。写动作一律走本表,两端各给实现。
|
||
* ⚠ 本表刻意不含任何"范围数值/枚举值":什么是有效时间、哪条记录对应哪个文件,
|
||
* 真源仍分别在各属主模块(本层不做第二真源,只转达请求与结果)。
|
||
*/
|
||
typedef struct {
|
||
/*
|
||
* 函数功能:设置系统墙钟(本地域 epoch 秒)
|
||
* 入口参数:unix_epoch - 要设置的秒 uint32_t
|
||
* 返回值:0 - 已生效;-1 - 设置失败 int
|
||
* 限定条件:真机实现**必须**在 sys_clock_set_unix() 之后回读 sys_clock_get()
|
||
* 复核(差值容差见 App 侧实现),不得"调了就算成"
|
||
*/
|
||
int (*clock_set)(uint32_t a_unix_epoch);
|
||
/*
|
||
* 函数功能:请求复归全部保护元件状态
|
||
* 入口参数:无
|
||
* 返回值:0 - 已受理;-1 - 拒收 int
|
||
* 限定条件:真机实现 = prot_elm_request_reset()(只置单字节标志,由
|
||
* protectTask 下一拍消费),本层不等执行结果
|
||
*/
|
||
int (*reset_req)(void);
|
||
/*
|
||
* 函数功能:取当前处于动作态的保护元件数("动作位复归"的观测量)
|
||
* 入口参数:无
|
||
* 返回值:元件数(0 = 无元件动作) uint32_t
|
||
* 限定条件:真机实现 = popcount(prot_elm_active_mask())
|
||
*/
|
||
uint32_t (*active_count)(void);
|
||
/*
|
||
* 函数功能:往"操作记录"投一条留痕(人工在面板上做过一件事)
|
||
* 入口参数:desc - 描述串(NUL 结尾,调用方持有的常量串;投递侧即拷贝)
|
||
* const char *
|
||
* 返回值:无
|
||
* 限定条件:真机实现 = syslog_post_quiet(SYSLOG_OPER, desc)。**谁触发谁投**:
|
||
* 远端 104 遥控那条已由 App/protocol/iec104/iec104_pts.c 投,
|
||
* 本地面板这条由页面在受理成功后投,两边各一条、不得互替
|
||
*/
|
||
void (*oper_note)(const char *a_desc);
|
||
/*
|
||
* 函数功能:请求清除某类记录(只登记请求,不在本上下文删任何东西)
|
||
* 入口参数:log_id - UI 侧记录源编号(UI_W_REC_LOG_*,与 ui_rec_reader_t 同一编号空间) uint8_t
|
||
* 返回值:0 - 请求已登记;-1 - 编号越界或登记失败 int
|
||
* 限定条件:真机实现 = syslog_request_clear(映射后 id)。⚠ 共享代码**严禁**
|
||
* 调 MCU 后端的 syslog_clear_apply()(模拟器无实现 = 链接期报错),
|
||
* 也严禁 UI 直接 f_unlink / 碰卷锁(defaultTask 是唯一写者)
|
||
*/
|
||
int (*clear_req)(uint8_t a_log_id);
|
||
/*
|
||
* 函数功能:查某类记录"清除请求"的状态
|
||
* 入口参数:log_id - 记录源编号 uint8_t
|
||
* 返回值:UI_DATA_CLEAR_ST_NONE / _OK / _WAIT / _FAIL 之一 int
|
||
* 限定条件:真机实现 = syslog_clear_state(映射后 id),返回值直通不改码。
|
||
* ⚠ WAIT 是正常态(删除在 defaultTask 的 syslog_drain() 尾部落地);
|
||
* 模拟器端同步删除,永不出现 WAIT —— 页面两种都要能显示
|
||
*/
|
||
int (*clear_state)(uint8_t a_log_id);
|
||
} ui_data_maint_ops_t;
|
||
|
||
/*
|
||
* 清除状态(与 App/log/sys_log.h 的 SYSLOG_CLEAR_NONE/OK/WAIT/FAIL **逐值相等**;
|
||
* 适配层直通、不做映射表,等值由主机单测在同一 TU 里逐项核对钉住,
|
||
* 同 UI_W_SOE_T_* 的先例——等值只由测试钉,不由文档转述)
|
||
*/
|
||
#define UI_DATA_CLEAR_ST_NONE 0 /* 从未请求过清除 */
|
||
#define UI_DATA_CLEAR_ST_OK 1 /* 已清空:同拍该记录条数必为 0 */
|
||
#define UI_DATA_CLEAR_ST_WAIT (-1) /* 请求排队中(正常态,不是失败) */
|
||
#define UI_DATA_CLEAR_ST_FAIL (-2) /* 落地失败:原记录一条没少,可再发一次请求 */
|
||
|
||
/*
|
||
* 函数功能:注入装置维护执行侧函数表(启动期一次;先于 ui_menu_init)
|
||
* 入口参数:ops - 函数表(六个成员指针都不得为 NULL;生命周期由注入方保证,
|
||
* 本层只存指针不拷贝内容) const ui_data_maint_ops_t *
|
||
* 返回值:0 - 已注入;-1 - ops 为 NULL 或某成员为 NULL(存量不动,页面按
|
||
* "维护能力不可用"渲染,不崩不猜) int
|
||
* 限定条件:uiTask 启动期(与 ui_w_records_bind 同一处);传 NULL = 撤销注入
|
||
* 函数说明:与 ui_data_param_drain() 的"每次调用时传入"不同,本表是**常驻注入**:
|
||
* 维护动作由用户按键触发、无固定节拍,若也走"每次传表"就得在 uiTask
|
||
* 主循环里每轮挂一次,而那一轮并没有任何东西要落定(空转一次函数调用
|
||
* 换不来任何判据)。撤销窗口只在测试里存在
|
||
*/
|
||
int ui_data_maint_bind(const ui_data_maint_ops_t *a_ops);
|
||
|
||
/*
|
||
* 函数功能:请求设置墙钟(时钟设置页"保存"行的唯一出口)
|
||
* 入口参数:unix_epoch - 由 ui_data_clock_to_epoch() 合成、且已整组校验过的秒 uint32_t
|
||
* 返回值:0 - 执行侧受理(终态由执行侧的回读校验给出);-1 - 未注入或执行侧失败;
|
||
* -2 - 参数无效(本层不判日期合法性,那是
|
||
* ui_data_clock_to_epoch() 的活,到这儿只判 0 哨兵) int
|
||
* 限定条件:uiTask 上下文(页面按键钩子)
|
||
*/
|
||
int ui_data_maint_clock_set(uint32_t a_unix_epoch);
|
||
|
||
/*
|
||
* 函数功能:请求复归全部保护元件(强制复归页的执行出口)
|
||
* 入口参数:无
|
||
* 返回值:0 - 已受理;-1 - 未注入或执行侧拒收 int
|
||
* 限定条件:uiTask 上下文;⚠ 操作记录**不在本函数里投**——"这是本地面板发起的"
|
||
* 这一事实只有页面知道,由页面在返 0 之后显式调
|
||
* ui_data_maint_oper_note() 投(拒收时不得投,屏上留痕与记录留痕
|
||
* 必须同一条判据)
|
||
*/
|
||
int ui_data_maint_reset_req(void);
|
||
|
||
/*
|
||
* 函数功能:取当前动作元件数(复归页"保护动作 N"行的数据源;屏上用字须已入子集)
|
||
* 入口参数:无
|
||
* 返回值:元件数;未注入返回 0(= 显示"无元件动作",与真值 0 同形,
|
||
* 但页脚/态标另有 LOCK 提示装配未接好) uint32_t
|
||
* 限定条件:页面绘制路径可直调(一次函数指针调用,无 I/O、无锁)
|
||
* 函数说明:本函数是"动作位复归可证"的**唯一观测量**:复归请求受理后,
|
||
* 页面按帧重读,N 从 >0 变 0 就是屏上可见的证据;复归不掉只可能是
|
||
* 测量仍在越限(元件重新 pickup),不是请求丢了
|
||
*/
|
||
uint32_t ui_data_maint_active_count(void);
|
||
|
||
/*
|
||
* 函数功能:投一条操作记录留痕(页面在本地动作受理后调)
|
||
* 入口参数:desc - 描述串(ASCII,长度受执行侧 SYSLOG_DESC_MAX 约束;NULL = 什么都不做)
|
||
* const char *
|
||
* 返回值:0 - 已投递;-1 - 未注入或 desc 为 NULL int
|
||
* 限定条件:uiTask 上下文;投递本身不阻塞、可能因队列满被丢弃(执行侧口径,
|
||
* 与 syslog_post_quiet 一致——本层不加"投递失败"的第二套显示语义:
|
||
* 留痕丢了不等于操作没发生,把记录通道故障显示成操作失败更坏)
|
||
*/
|
||
int ui_data_maint_oper_note(const char *a_desc);
|
||
|
||
/*
|
||
* 函数功能:请求清除某类记录(清除记录页的执行出口)
|
||
* 入口参数:log_id - 记录源编号(UI_W_REC_LOG_*) uint8_t
|
||
* 返回值:0 - 已受理;-1 - 未注入 / 编号越界 / 执行侧拒绝 int
|
||
* 限定条件:uiTask 上下文;"受理"≠"已清除",终态读 ui_data_maint_clear_state(),
|
||
* 事实复核读记录条数(ui_w_records 的同一枚 reader)
|
||
*/
|
||
int ui_data_maint_clear_req(uint8_t a_log_id);
|
||
|
||
/*
|
||
* 函数功能:查某类记录的清除状态(清除记录页值列的数据源)
|
||
* 入口参数:log_id - 记录源编号 uint8_t
|
||
* 返回值:UI_DATA_CLEAR_ST_NONE / _OK / _WAIT / _FAIL;未注入或编号越界返回 NONE
|
||
* ("从没请求过",页面据此显示条数而不是结果词) int
|
||
* 限定条件:页面绘制路径可直调;返回值直通执行侧、不做二次加工(同
|
||
* ui_data_param_state() 的理由:两处解释同一件事必然漂移)
|
||
*/
|
||
int ui_data_maint_clear_state(uint8_t a_log_id);
|
||
|
||
/* ── 时钟字段换算(本地域,无时区偏移;"无效值拒收"的唯一判据处)─────────── */
|
||
|
||
/*
|
||
* 年份上下限(两条硬约束的交集,不是拍脑袋的整数区间):
|
||
* 下限 2000:SD2506 RTC 年字段是相对值 0~99(+2000,见
|
||
* Drivers/BSP/SD2506/sd2506.h 的 sd2506_time_t.year 注释),
|
||
* 2000 以下写不进 RTC
|
||
* 上限 2038:墙钟 epoch 是 uint32_t 秒,上界 0x7FFFFFFF = 2038-01-19 03:14:07
|
||
* (App/util/sys_clock.h 的 sys_clock_set_unix 取值域一致)
|
||
*/
|
||
#define UI_DATA_CLOCK_YEAR_MIN 2000u
|
||
#define UI_DATA_CLOCK_YEAR_MAX 2038u
|
||
#define UI_DATA_CLOCK_EPOCH_MAX 0x7FFFFFFFu
|
||
#define UI_DATA_CLOCK_TS_LEN 19u /* "YYYY-MM-DD HH:MM:SS"(与 rt.clock 同串型) */
|
||
|
||
/* 时钟日历字段(本地域;数值就是屏上显示的那六个数,不含任何时区语义) */
|
||
typedef struct {
|
||
uint16_t year; /* UI_DATA_CLOCK_YEAR_MIN..UI_DATA_CLOCK_YEAR_MAX */
|
||
uint8_t month; /* 1..12 */
|
||
uint8_t day; /* 1..该月真实天数(闰年由本层判,不交给调用方) */
|
||
uint8_t hour; /* 0..23 */
|
||
uint8_t minute; /* 0..59 */
|
||
uint8_t second; /* 0..59 */
|
||
} ui_data_clock_t;
|
||
|
||
/*
|
||
* 函数功能:取某年某月的天数(含闰年 2 月)
|
||
* 入口参数:year - 年 uint16_t month - 月 1..12 uint8_t
|
||
* 返回值:28 / 29 / 30 / 31;月份越界返回 0(调用方据此判非法,不用第二条错误码) uint8_t
|
||
* 限定条件:闰年规则 = (4 年 && !100 年) || 400 年(与 App/util/sys_clock.c
|
||
* 的 unix_to_sd2506 / sd2506_to_unix 同一判据,两侧都是完整格里历规则;
|
||
* 2100 年不在允许年域内,不需要讨论那个例外)
|
||
*/
|
||
uint8_t ui_data_clock_days_in_month(uint16_t a_year, uint8_t a_month);
|
||
|
||
/*
|
||
* 函数功能:日历字段 → 本地域 epoch 秒(**同时是这组字段的合法性判据**)
|
||
* 入口参数:p_in - 六个字段 const ui_data_clock_t *
|
||
* p_out - 秒 uint32_t *
|
||
* 返回值:0 - 合法并已输出;-1 - 参数为 NULL;-2 - 字段组合非法(年/月/日/时/分/秒
|
||
* 任一越界,含 2 月 30 日、非闰年 2 月 29 日、月 13、时 24 等);
|
||
* -3 - 组合合法但超出取值域(epoch > UI_DATA_CLOCK_EPOCH_MAX) int
|
||
* 限定条件:无(纯整数,零依赖,可在主机单测跑全表)
|
||
* 函数说明:日的当月真实上限**在这里**判,不在字段编辑器里判——编辑器只有静态
|
||
* min/max(日一律 1..31),把闰年规则抄一份进编辑器就是第二真源。
|
||
* ⚠ 不含时区偏移:本工程墙钟的 epoch 域本身就是本地时间
|
||
* (App/util/sys_clock.h 的 sys_clock_set_unix 注明"秒,本地时间",
|
||
* 其正/反换算两头都没有 ±8 运算;App/task/ui_task.c 的 SOE 时标注记
|
||
* 已把"别顺手补 8 小时"钉过一次)。这里加 28800 的结果是"屏上输 08:00、
|
||
* 存进去 16:00",且只在真机上错,模拟器照样自洽
|
||
*/
|
||
int ui_data_clock_to_epoch(const ui_data_clock_t *p_in, uint32_t *p_out);
|
||
|
||
/*
|
||
* 函数功能:本地域 epoch 秒 → 日历字段
|
||
* 入口参数:unix_epoch - 秒 uint32_t p_out - 输出 ui_data_clock_t *
|
||
* 返回值:0 - 已输出;-1 - p_out 为 NULL;-2 - 超出允许年域(< 2000-01-01 或
|
||
* > UI_DATA_CLOCK_EPOCH_MAX) int
|
||
* 限定条件:与 ui_data_clock_to_epoch() 互为反函数(同一套格里历规则,
|
||
* 往返必等;这条往返性是主机单测的断言之一,不是注释里的口头保证)
|
||
*/
|
||
int ui_data_clock_from_epoch(uint32_t a_unix_epoch, ui_data_clock_t *p_out);
|
||
|
||
/*
|
||
* 函数功能:解析 "YYYY-MM-DD HH:MM:SS" 串为日历字段
|
||
* 入口参数:ts - 待解析串(快照 rt.clock 的形状) const char *
|
||
* p_out - 输出 ui_data_clock_t *
|
||
* 返回值:0 - 成功;-1 - 参数 NULL;-2 - 串型不对(长度非 19、分隔位不是
|
||
* '-'/' '/':'、出现非数字);-2 同时覆盖"型对但值非法"
|
||
* (解析出的组合再过 to_epoch()) int
|
||
* 限定条件:时钟无效时快照里是**空串**(ui_data.h:149 的口径),空串走 -2;
|
||
* 调用方据此显示"无时钟"而不是 0000-00-00
|
||
*/
|
||
int ui_data_clock_parse(const char *a_ts, ui_data_clock_t *p_out);
|
||
|
||
/*
|
||
* 函数功能:日历字段 → "YYYY-MM-DD HH:MM:SS"(与 ui_data_clock_parse 同串型)
|
||
* 入口参数:p_in - 字段 const ui_data_clock_t *
|
||
* buf - 输出缓冲 char * len - 缓冲容量(含 NUL;不足则整串不写) uint32_t
|
||
* 返回值:0 - 已写出;-1 - 参数无效或容量不足 int
|
||
* 限定条件:不判字段合法性(调用方刚从 parse/to_epoch 那条链出来);
|
||
* 手写十进制、不引 stdio——本层是零 LVGL 零 App 的叶子,拉进
|
||
* lv_snprintf/stdio 就等于给主机单测加依赖
|
||
*/
|
||
int ui_data_clock_format(const ui_data_clock_t *p_in, char *a_buf, uint32_t a_len);
|
||
|
||
/* ── 通道五:遥测整定注入(死区 / 系数,道F task-7)────────────────────────
|
||
*
|
||
* 为什么又是一张注入表而不是页面直调 run_par / adc_cal:与通道四完全同一组理由
|
||
* ——① 分层方向(Drivers/BSP 不得反向 include App 头,layer-deps 拦提交);
|
||
* ② 模拟器既不链 App/algo/run_par.c 也不链 App/algo/adc_cal.c,页面里用一次
|
||
* 真源函数就是"MCU 编得过、模拟器链接期爆"(通道四表注已记过一次的同族坑);
|
||
* ③ 合法域与"写值 + 置脏"必须原子发生在执行侧(run_par_cal_k_set 的文件头契约:
|
||
* 拆开等于"屏上已改、盘上永不落、且没有任何错误返回"),本表只转达。
|
||
* ⚠ 本表刻意不含任何范围数值的拷贝:lo/hi 由执行侧逐行现给(合法域唯一出口
|
||
* run_par_db_range,系数粗守上限唯一出口 RUN_PAR_K_MAX_UV),页面抄一份数字
|
||
* 就是第二真源——µV 真带(执行段裁)没有公开访问器,也**不许**页面自己补一份。
|
||
*/
|
||
|
||
/* 死区点数:下标 0..7 = 电气语义通道序(UA..IN),8 = 频率(与 104 地址映射表
|
||
* 0x8030~0x8038 同序);系数覆盖点数:电气 8 路(语义枚举前缀段)。
|
||
* 与 App/algo/run_par.h 的 RUN_PAR_DB_N / RUN_PAR_CH_N 等值——BSP 看不到 App 头,
|
||
* 等值由装配层编译期守卫(App/app/ui_data_feed.c)与 TC-UIDATA-027 同时钉住 */
|
||
#define UI_DATA_YT_DB_N 9u
|
||
#define UI_DATA_YT_CH_N 8u
|
||
|
||
/* 量纲代码:unit 是"这行数值本身的物理量纲"(诚实性字段,同 rt 帧 eng 的思路),
|
||
* 归数据源管;把它显示成什么字符串("V"/"Hz"/"uV")才是表现层的事 */
|
||
#define UI_DATA_YT_UNIT_V 0u /* 电压死区,V */
|
||
#define UI_DATA_YT_UNIT_A 1u /* 电流死区,A */
|
||
#define UI_DATA_YT_UNIT_HZ 2u /* 频率死区,Hz */
|
||
#define UI_DATA_YT_UNIT_UV 3u /* 系数 k,µV/码(屏上串用 ASCII "uV") */
|
||
|
||
/* 一行遥测整定项的完整现状(执行侧现给,页面只读) */
|
||
typedef struct {
|
||
float val; /* 当前工程量:死区 V/A/Hz;系数 = adc_cal 当前生效值(µV/码,
|
||
与 104 回显同视图:文件坏值被合法带哨兵回退 ROM 时显 ROM) */
|
||
float lo; /* 粗守下限(含)——合法域唯一出口给,页面不得自造 */
|
||
float hi; /* 粗守上限(含)——同上;真带在执行段另裁,两层互不掩盖 */
|
||
uint8_t unit; /* UI_DATA_YT_UNIT_* */
|
||
uint8_t decimals; /* 显示小数位(**显示域选择**,不是数据源精度,归装配层定) */
|
||
} ui_data_yt_row_t;
|
||
|
||
/*
|
||
* 执行侧函数表(常驻注入;形状与 ui_data_maint_ops_t 同款:整表校验、拒残表)
|
||
*
|
||
* 与定值整定(通道 param 的位图批量 + 工作叠层)**故意不同形**:死区/系数写的是
|
||
* 运行参数档([run_par]/[adc_cal]),语义 setter 本身就是"写 RAM 副本 + 置脏"
|
||
* 的原子出口、单行即提交;落盘确认是独立一问(pending),所以本表没有 commit
|
||
* 一口——保存行按键读的就是 pending()。
|
||
*/
|
||
typedef struct {
|
||
/*
|
||
* 函数功能:死区点数(执行侧真值;未注入时本层返回 0)
|
||
* 返回值:点数 uint8_t
|
||
*/
|
||
uint8_t (*db_n)(void);
|
||
/*
|
||
* 函数功能:读第 idx 行死区现状(工程量 + 粗守域 + 量纲 + 显示小数位)
|
||
* 返回值:0 - 已写出;-1 - idx 越界 / 指针空 / 执行侧无此行 int
|
||
*/
|
||
int (*db_row)(uint8_t a_idx, ui_data_yt_row_t *a_out);
|
||
/*
|
||
* 函数功能:写第 idx 行死区(工程量)——真机 = run_par_deadband_set()
|
||
* 返回值:0 - 副本已写且已置脏;-1 - 粗守或执行侧拒(副本未动、不置脏) int
|
||
*/
|
||
int (*db_set)(uint8_t a_idx, float a_eng);
|
||
/* 函数功能:系数覆盖点数(执行侧真值) 返回值:点数 uint8_t */
|
||
uint8_t (*cal_n)(void);
|
||
/* 函数功能:读第 idx 路系数现状(同 db_row,工程量域为 µV/码) int */
|
||
int (*cal_row)(uint8_t a_idx, ui_data_yt_row_t *a_out);
|
||
/*
|
||
* 函数功能:写第 idx 路系数 k(µV/码)——真机 = run_par_cal_k_set()
|
||
* 返回值:0 - 已写并置脏;-1 - 粗守或执行段真带拒(副本未动、不置脏) int
|
||
*/
|
||
int (*cal_k_set)(uint8_t a_idx, float a_uv);
|
||
/*
|
||
* 函数功能:未标定闭锁徽标源——真机 = adc_cal_prot_blocked()(task-16 单点
|
||
* 访问器,与判据停走同一个判定;这里**不**用 rt 帧 eng 反推)
|
||
* 返回值:1 - 未标定闭锁中;0 - 正常 uint8_t
|
||
*/
|
||
uint8_t (*cal_blocked)(void);
|
||
/*
|
||
* 函数功能:整档落盘脏位探查——真机 = run_par_dirty_peek()
|
||
* 返回值:1 - 有已整定未落盘改动;0 - 干净 uint8_t
|
||
* ⚠ 两条口径必须与页面注释同步(道F task-7 Lead 裁定):
|
||
* ① 脏位是**整档全局**的(一趟落 [run_par] 九键 + [adc_cal] 两段),归零
|
||
* 证明"这一档落盘了",不证明"我这一项单独落盘";
|
||
* ② 他人(104 C_SE)随后再改会重新置脏 ⇒ 页面必须结果锁存,把"我这次动作
|
||
* 的结果"与"档位此刻的状态"分开(clear/clock 页同一条先例)。
|
||
*/
|
||
uint8_t (*pending)(void);
|
||
} ui_data_yt_ops_t;
|
||
|
||
/*
|
||
* 函数功能:注入遥测整定执行侧函数表(启动期一次;形状/语义逐字对齐 ui_data_maint_bind)
|
||
* 入口参数:ops - 函数表(八个成员指针都不得为 NULL);NULL = 撤销注入(只在宿主测试存在)
|
||
* 返回值:0 - 已注入(或已撤销);-1 - ops 非空但成员残缺(存量不动,页面按
|
||
* "整定能力不可用"渲染,不崩不猜) int
|
||
* 限定条件:uiTask 启动期、先于 ui_menu_init()(真机在装配层 ui_data_feed_tick()
|
||
* 首轮懒绑一次——该调用点在 ui_menu_init 之前,时序与通道四绑定等价)
|
||
*/
|
||
int ui_data_yt_bind(const ui_data_yt_ops_t *a_ops);
|
||
|
||
/*
|
||
* 函数功能:死区点数
|
||
* 入口参数:无
|
||
* 返回值:点数;未注入返回 0 uint8_t
|
||
*/
|
||
uint8_t ui_data_yt_db_n(void);
|
||
|
||
/*
|
||
* 函数功能:读第 idx 行死区现状
|
||
* 入口参数:idx - 行下标 uint8_t;a_out - 行现状(返 0 才被整份写出) ui_data_yt_row_t *
|
||
* 返回值:0 - 已写出;-1 - 未注入 / 参数空 / 执行侧无此行 int
|
||
*/
|
||
int ui_data_yt_db_row(uint8_t a_idx, ui_data_yt_row_t *a_out);
|
||
|
||
/*
|
||
* 函数功能:写第 idx 行死区(工程量)
|
||
* 入口参数:idx - 行下标 uint8_t;a_eng - 工程量(V/A/Hz) float
|
||
* 返回值:0 - 已写并置脏;-1 - 未注入或执行侧拒(未注入与拒绝同码:页面都按
|
||
* ERR 显示,装配故障与工况故障的区分归日志不归屏幕) int
|
||
*/
|
||
int ui_data_yt_db_set(uint8_t a_idx, float a_eng);
|
||
|
||
/*
|
||
* 函数功能:系数覆盖点数
|
||
* 入口参数:无
|
||
* 返回值:点数;未注入返回 0 uint8_t
|
||
*/
|
||
uint8_t ui_data_yt_cal_n(void);
|
||
|
||
/*
|
||
* 函数功能:读第 idx 路系数现状(µV/码域)
|
||
* 入口参数:idx - 电气语义通道序 uint8_t;a_out - 行现状 ui_data_yt_row_t *
|
||
* 返回值:0 - 已写出;-1 - 未注入 / 参数空 / 执行侧无此行 int
|
||
*/
|
||
int ui_data_yt_cal_row(uint8_t a_idx, ui_data_yt_row_t *a_out);
|
||
|
||
/*
|
||
* 函数功能:写第 idx 路系数 k(µV/码)
|
||
* 入口参数:idx - 电气语义通道序 uint8_t;a_uv - 新系数(µV/码) float
|
||
* 返回值:0 - 已写并置脏;-1 - 未注入或拒(粗守/真带,副本未动) int
|
||
*/
|
||
int ui_data_yt_cal_k_set(uint8_t a_idx, float a_uv);
|
||
|
||
/*
|
||
* 函数功能:未标定闭锁徽标源
|
||
* 入口参数:无
|
||
* 返回值:1 - 闭锁中;0 - 正常或未注入(宁可不画,不假报) uint8_t
|
||
*/
|
||
uint8_t ui_data_yt_cal_blocked(void);
|
||
|
||
/*
|
||
* 函数功能:整档落盘脏位探查(保存行三态判据)
|
||
* 入口参数:无
|
||
* 返回值:1 - 有已整定未落盘改动;0 - 干净或未注入 uint8_t
|
||
*/
|
||
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);
|
||
|
||
/* ── 通道六:故障录波(wave)────────────────────────────────────────────────
|
||
* 页面零 App include、零存储触点:录波执行侧(触发投递 / 段索引 / 段头字段 /
|
||
* 窗口码值与峰值 mV)全部经本注入表进来,真实现见 App/task/ui_task.c 的
|
||
* s_wave_ops;PC 模拟器绑同一形状的假件(simulator/main.c)。取数口径的
|
||
* 唯一真源是 docs/子系统设计/故障录波设计说明.md §6.3(定点 mV 换算走
|
||
* wave_store_code_to_milli,eng 只做徽标、绝不进算式)。
|
||
*/
|
||
|
||
/* 录波通道数(与段头 ch_count 恒等:电气八路,温度不入波) */
|
||
#define UI_WAVE_CH_CNT 8u
|
||
/* 回放显示窗口点数(两周波;口径推导与设计 §4.2 的触发点位置钉在一起,
|
||
* 窗起点与虚线光标由执行侧与页面各按同一定义实现,页面侧写死 */
|
||
#define UI_WAVE_WIN_PTS 40u
|
||
|
||
/* 通道查询返回态:段存在且可用 */
|
||
#define UI_WAVE_OK 0
|
||
/* 无段(目录扫空 / 卷忙跳过 / 执行侧未注入,页面显示「无录波段」) */
|
||
#define UI_WAVE_NONE 1
|
||
/* 有段但不可读(长度不符 / 版本不符 / 任一段 CRC 不符,页面显示
|
||
* 「该段不可读」——两种态都必须显式说,画直线等于伪造证据(设计 §8.1) */
|
||
#define UI_WAVE_BAD 2
|
||
|
||
/*
|
||
* 录波执行侧注入表(六件齐全;ui_data_wave_bind 拒绝残表)
|
||
* 返回值约定:除 manual_req 外,各件返回 UI_WAVE_OK / NONE / BAD 三态;
|
||
* seg_win 的出参仅在返 UI_WAVE_OK 时可读(通道五同一条出参契约)。
|
||
*/
|
||
typedef struct {
|
||
/* 投一次手动录波请求。返回值:0 - 已受理;非零 - 拒收(含未落段通道
|
||
* 不可用),页面据此走确认链的 ERR 支 */
|
||
int (*manual_req)(void);
|
||
/* 取盘上数值最大的段号(回放页开屏落点;左右键从此起环游)。
|
||
* 回绕后本序不保证时间最新,页顶段号即自证;时间序要靠段头
|
||
* frame_seq/t0,代价是 100 次开文件,本波不做(lead 裁定 2026-10-29) */
|
||
int (*seg_first)(uint8_t *a_idx);
|
||
/* 取比 a_cur 更早一段的段号(到最早端后环回数值最大端) */
|
||
int (*seg_prev)(uint8_t a_cur, uint8_t *a_out);
|
||
/* 取比 a_cur 更新一段的段号(到最大端后环回数值最小端) */
|
||
int (*seg_next)(uint8_t a_cur, uint8_t *a_out);
|
||
/* 读段头并做完整性判定(头 CRC 与数据 CRC 都在执行侧验完)。
|
||
* 出参:eng - 单位口径(UI_DATA_ENG_* 同值域);trig - 触发源
|
||
* (段头 trig_src 原值:手动/保护/定时);clip - 形状受限通道位图
|
||
* (段头 clip 字节,位号 = 通道号) */
|
||
int (*seg_head)(uint8_t a_idx, uint8_t *a_eng, uint8_t *a_trig,
|
||
uint8_t *a_clip);
|
||
/* 读当前显示窗口的码值(已并入 b_codes 偏移)与窗口峰值。
|
||
* 出参:a_codes - UI_WAVE_WIN_PTS 个码值;a_peak_milli - 窗口内
|
||
* 绝对值最大的那一点折算的 mV(定点,执行侧经 code_to_milli 算好,
|
||
* 页面不重复换算式——§6.3 的单一口径条款;b_codes 由 code_to_milli
|
||
* 内部加,与 a_codes 里已并的偏移同一把尺:谁被显示谁被度量) */
|
||
int (*seg_win)(uint8_t a_idx, uint8_t a_ch, int16_t *a_codes,
|
||
int32_t *a_peak_milli);
|
||
} ui_data_wave_ops_t;
|
||
|
||
/*
|
||
* 函数功能:注入录波执行侧函数表(启动期一次;形状对齐 ui_data_comm_bind)
|
||
* 入口参数:ops - 函数表(六件都不得为 NULL);NULL = 撤销注入(宿主测试用)
|
||
* 返回值:0 - 已注入/已撤销;-1 - 残表(存量不动) int
|
||
* 限定条件:uiTask 启动期、先于 ui_menu_init()
|
||
*/
|
||
int ui_data_wave_bind(const ui_data_wave_ops_t *a_ops);
|
||
|
||
/*
|
||
* 函数功能:投一次手动录波请求(录波触发页唯一写出口)
|
||
* 返回值:0 - 已受理;-1 - 未注入或拒收(未注入与拒收同码,同通道五) int
|
||
*/
|
||
int ui_data_wave_manual_req(void);
|
||
|
||
/*
|
||
* 函数功能:取数值最大段号(排序口径见 ui_data.c 同名胶水注释:回绕后本序
|
||
* 不保证时间最新,页顶段号即自证;真时间序要逐段读 frame_seq/t0,
|
||
* 代价 100 次开文件,本波不做)
|
||
* 入口参数:a_idx - 出参,段号(仅返 OK 时可读)
|
||
* 返回值:UI_WAVE_OK / UI_WAVE_NONE / UI_WAVE_BAD(未注入按 NONE 渲染空态,不崩) int
|
||
*/
|
||
int ui_data_wave_seg_first(uint8_t *a_idx);
|
||
|
||
/*
|
||
* 函数功能:取 a_cur 的更早一段段号(环形回绕)
|
||
* 入口参数:a_cur - 当前段号;a_out - 出参(仅返 OK 时可读)
|
||
* 返回值:UI_WAVE_OK / UI_WAVE_NONE / UI_WAVE_BAD int
|
||
*/
|
||
int ui_data_wave_seg_prev(uint8_t a_cur, uint8_t *a_out);
|
||
|
||
/*
|
||
* 函数功能:取 a_cur 的更新一段段号(环形回绕,方向与 prev 相反)
|
||
* 入口参数:a_cur - 当前段号;a_out - 出参(仅返 OK 时可读)
|
||
* 返回值:UI_WAVE_OK / UI_WAVE_NONE / UI_WAVE_BAD int
|
||
*/
|
||
int ui_data_wave_seg_next(uint8_t a_cur, uint8_t *a_out);
|
||
|
||
/*
|
||
* 函数功能:读段头(含执行侧 CRC 完整性判定)——出参仅返 OK 时可读
|
||
* 返回值:UI_WAVE_OK / NONE / BAD(未注入按 NONE) int
|
||
*/
|
||
int ui_data_wave_seg_head(uint8_t a_idx, uint8_t *a_eng, uint8_t *a_trig,
|
||
uint8_t *a_clip);
|
||
|
||
/*
|
||
* 函数功能:读显示窗口码值与峰值 mV——出参仅返 OK 时可读
|
||
* 返回值:UI_WAVE_OK / NONE / BAD(未注入按 NONE) int
|
||
*/
|
||
int ui_data_wave_seg_win(uint8_t a_idx, uint8_t a_ch, int16_t *a_codes,
|
||
int32_t *a_peak_milli);
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
|
||
#endif /* UI_DATA_H */
|