0b84c43d2e
批 3(LOGO 按用户裁定出局,不实现、sb_proto 的 LOGO 组帧挂待删标注): - 新增 App/algo/sb_led_map.c/h:业务状态 → 屏板 LED 位掩码的唯一映射表 (纯逻辑,主机单测可跑)。ID1 运行心跳 500ms 半周期闪(与主板 LED 同拍)、 ID2 保护动作、ID3 104 链路 RUN、ID4 采样电平故障(不选 sticky——灯要能灭)、 ID5 保护启动 picked;bit0 与 ID 6~19 恒 0。这张表参考源码里没有,属自定, 出处 docs/产品需求/产品需求设计文档.md §5.16.3 ①。 - iec104_serv 新增 iec104_serv_link_run()(透传 link 状态机,不另存镜像量)。 - ui_task.c 帧组装块每拍现采四路状态源(均为任意上下文可读观测口)折算后 传 sb_link_frame_update——替换批 2 的恒 0 占位;掩码变了帧就重组, 复用 busy/dirty 机制,无新通路。 - 主机单测 test/host/sb_led_map 17/17(位语义/恒零位/闪烁相位/tick 回绕/ NULL 契约);注册豁免走 SIM_EXEMPT(模拟器无屏板串口)。 批 4 的 4-1 双通道并发回归(真屏板在线实测): - 新增 test/host/remolcd_pull_test.py:RemoDispBus 拉帧压测客户端 (INIT→LCDMEM 10 Hz、逐帧 XOR+长度校验、往返延迟统计、--dump PBM)。 - 实测:网络侧两轮 2200 拉帧零错零超时(min 35/avg 63/max 131 ms); 屏板侧 60 s 隔离窗口 rx +233 全收、drop 零新增、bad=0、off=0、无 OFFLINE——两侧互不拖。观察项 len=7(断帧尺寸≠6,累计 7 次)出现窗口 无法归因压测、隔离窗口零新增、有效帧零损失,已挂设计说明 §5.7 待查。 附带:sb_link.h frame_update 注释回填实测耗时(509/688 µs 取代旧估算)。 Keil 0 错误 0 警告;ci_local 全绿(SKIP=nested-comment,主树脚本另查 0 新发); Code=239,064 B / RW_IRAM1 65.5 % / RW_CCM 87.9 %;覆盖率 90.1 % / 44 套件。
102 lines
5.9 KiB
C
102 lines
5.9 KiB
C
/*
|
||
* 模块名称:屏板状态灯位映射(业务状态 → LED 位掩码)
|
||
* 模块功能:把装置的业务状态(保护动作 / 保护启动 / 采样故障 / 104 主站在线 /
|
||
* 运行心跳)折算成屏板帧 B `info[0..3]` 的 32 位 LED 掩码。
|
||
* ⚠ 本层**纯逻辑**:不碰 HAL、不读全局、不打日志——输入是调用方
|
||
* (uiTask)采好的状态快照,输出是一个 uint32_t → 主机侧可纯逻辑单测
|
||
* (test/host/sb_led_map/)。与 Drivers/BSP/ScreenLink/sb_proto 同一分层理由。
|
||
* 适用平台:平台无关(纯标准 C)
|
||
* 作者:王建锋
|
||
* 创建日期:2026-10-29
|
||
* 修改记录:
|
||
* 2026-10-29 王建锋 创建初始版本(批 3 的 3-1:映射表落纸,docs/任务规划/屏板链路.md §3)
|
||
*
|
||
* 这张表为什么必须"自定":屏板源码(DTU-LCD LED_Printf)只规定了"位 → 灯号"的
|
||
* 物理口径(bit1~bit19 → ID 1~19,ID 0 电源灯硬件常亮、不看位,bit20~31 未使用),
|
||
* **"哪路状态占哪一位"在参考主机源码里不存在**(参考的 LCD_LED_Update 实现在
|
||
* 未开源的屏板 BSP 库里)。出处 docs/产品需求/产品需求设计文档.md §5.16.3 ①。
|
||
*/
|
||
#ifndef SB_LED_MAP_H
|
||
#define SB_LED_MAP_H
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
#include <stdint.h>
|
||
|
||
/* ============================================================================
|
||
* 一、位定义(屏板物理口径:bit i = 灯 ID i;bit0 被屏板忽略,别指望用它)
|
||
* ==========================================================================*/
|
||
|
||
/* ID 1 = 运行灯:装置活着的心跳,500 ms 半周期闪烁(与主板 LED1~3 心跳节奏同源,
|
||
* docs/产品需求/产品需求设计文档.md §5.8)。它**不取决于任何输入状态**——只要这段
|
||
* 代码还在被调度,灯就在闪;灯不闪 = uiTask 停了,这正是操作员要看的信号。 */
|
||
#define SB_LED_BIT_RUN (1UL << 1)
|
||
|
||
/* ID 2 = 告警灯:任一保护元件处于**动作**态(prot_elm_active_mask != 0)。
|
||
* ⚠ 产品构建处于「未标定闭锁」(App/task/protect_task.c 的 VALID 门禁),
|
||
* 标定前恒灭——与屏上"保护动作 N"同一已知口径,不是本灯的缺陷。 */
|
||
#define SB_LED_BIT_ALARM (1UL << 2)
|
||
|
||
/* ID 3 = 通信灯:IEC 60870-5-104 链路处于 RUN(STARTDT 已确认 = 主站真的在线在
|
||
* 轮询)。选 RUN 而不选"TCP 已建连":连上不发 STARTDT 的扫描器不该点亮它。 */
|
||
#define SB_LED_BIT_COMM (1UL << 3)
|
||
|
||
/* ID 4 = 采样故障灯:ADC 采样有效性**电平**故障位非零(adc_health_flags,
|
||
* 静默/倒退等,当前活跃、可自愈熄灭)。选电平不选 sticky:这盏灯要能熄灭,
|
||
* "曾经故障过"的账在自检记录里,不该用一盏长明灯喊给操作员。 */
|
||
#define SB_LED_BIT_ADC_FAULT (1UL << 4)
|
||
|
||
/* ID 5 = 保护启动灯:任一保护元件处于**启动**(picked)态(prot_elm_pick_mask)。
|
||
* picked 早于 asserted,"越限启动了但没到动作点"这段过程只在这盏灯上可见
|
||
* (与 104「保护启动」记录同一动机,App/algo/prot_elm.h 的 pick_mask 注释)。
|
||
* 同样受未标定闭锁口径约束。 */
|
||
#define SB_LED_BIT_PICKUP (1UL << 5)
|
||
|
||
/* 已赋义位的并集(判据用:掩码里不得出现本表之外的置位)。
|
||
* ID 6~19 保留未用,恒 0;将来扩展从 ID 6 顺序取,跳号留白不回收语义。 */
|
||
#define SB_LED_BITS_DEFINED (SB_LED_BIT_RUN | SB_LED_BIT_ALARM | SB_LED_BIT_COMM | \
|
||
SB_LED_BIT_ADC_FAULT | SB_LED_BIT_PICKUP)
|
||
|
||
/* 运行灯闪烁半周期(ms):0 ~ SB_LED_BLINK_HALF_MS-1 亮,下一个 500 ms 灭,交替。
|
||
* 取 500 是为与主板 LED 心跳(defaultTask 500 ms 翻转)同拍,两套灯闪烁同相。 */
|
||
#define SB_LED_BLINK_HALF_MS (500U)
|
||
|
||
/* ============================================================================
|
||
* 二、状态输入快照(调用方每拍现采,本模块不缓存、不加锁)
|
||
* ==========================================================================*/
|
||
|
||
typedef struct
|
||
{
|
||
uint32_t prot_active; /* prot_elm_active_mask():bit i = 元件 i 动作 */
|
||
uint32_t prot_pick; /* prot_elm_pick_mask():bit i = 元件 i 启动 */
|
||
uint32_t adc_flags; /* adc_health_flags():ADC_HF_* 电平故障位 */
|
||
uint8_t iec104_run; /* 1 = IEC 104 链路 RUN(iec104_serv_link_run()) */
|
||
uint8_t pad[3]; /* 显式补齐:结构体大小固定 16 B,主机/目标端一致 */
|
||
} sb_led_in_t;
|
||
|
||
/* ============================================================================
|
||
* 三、求值入口
|
||
* ==========================================================================*/
|
||
|
||
/*
|
||
* 函数功能:把状态快照折算成屏板 LED 32 位掩码(纯函数,映射表唯一出处见本头 §一)
|
||
* 入口参数:p_in - 状态快照;**允许 NULL**:等价于全零输入(只跑运行灯心跳——
|
||
* 心跳证明的是"这段代码活着",与别的状态无关,不该被空输入连坐)
|
||
* now_ms - 当前毫秒时基(运行灯相位唯一依赖;osKernelGetTickCount 同域)
|
||
* 返回值:32 位 LED 掩码(bit i = 灯 ID i;bit0 与 ID 6~19 恒 0,直接进帧 B info[0..3])
|
||
* 限定条件:任意上下文(纯计算:无分支副作用、不读写任何静态量、时基回绕安全——
|
||
* 回绕瞬间至多把一个半周期截短或延长 1 拍,500 ms 的心跳灯看不出来)
|
||
* 函数说明:闪烁相位 = (now_ms / 500) 的奇偶,偶 = 亮。上电 first 500 ms 为亮,
|
||
* "刚上电灯就在闪"是最直观的自检信号。各状态位相互独立,任一非零即置位,
|
||
* 无优先级、无互斥(告警与通信可以同时亮,那是两件同时在真发生的事)。
|
||
*/
|
||
uint32_t sb_led_map_eval(const sb_led_in_t *p_in, uint32_t now_ms);
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
|
||
#endif /* SB_LED_MAP_H */
|