W1 功能主线完成:内存台账三件套(W1-0) + IEC104 上行(B4) + protectTask 板端接线(B5)
W1-0 台账三件套:scripts/ram_baseline.py(四模式)+ ram_baseline.tsv 趋势 + docs/内存管理/RAM预算台账.md + pre-commit mem-budget 钩子(RW_IRAM1/RW_CCM >92% 即 FAIL + Top-10 附表);审查报告 §5.5 三条闭环。 B4 IEC 60870-5-104 上行(被控站,TCP 2404):App/protocol/iec104/ 三模块 (asdu 编解码 / pts 点表+数据源 vtable / link APCI+FSM,纯逻辑零 I/O)+ App/task/iec104_serv.c(iec104Task,NET_READY 屏障 100ms 分片喂位)。 82 断言 L0.5 全绿 + iec104-unit-test 钩子(第 31 钩子); 设计说明 docs/子系统设计/IEC104上行设计说明.md 全量回填。 B5 protectTask(L3 板端接线):App/task/protect_task.c——20ms 判据节拍 prot_elm_run + L5-4 采样故障闭锁(adc_health 电平位→元件复位)+ L5-1 定值 校验和巡检;新增 prot_elm_request_reset() 收口跨上下文复归(104 YK11 落请求、 eval 头部消费);定值/元件初始化移入 app_main_init(内核前)。TC-PE-010 (prot_elm 28 用例)。 门禁与内存:TASK_WD_PROTECT=8 入 required_mask(产品 0x77→0x1F7、HW 层 0x1F5,看门狗单测 39 断言同步);FreeRTOS 堆 48→56KB(.ioc L1 参数 + FreeRTOSConfig.h 同步,RAM预算台账 §6 登记配额 48→56KB)。 ZI 144,008→152,204(+8,196 B = 堆 +8KB,B5 扩容);Code=204,348。 stack_report:protectTask 512 words 静态链 872 B/余 57%、iec104Task 640 words 1456 B/余 43% 均 PASS;RW_IRAM1 73.1% / RW_CCM 87.9%(<92%)。 验证:@build 0 错 0 警;ci_local 全绿(31 钩子 + 13 主机侧单测); doc-links 135 文档 PASS。登记簿 B4/B5 销项、W1 波次完成;保护规划/看门狗 说明/AGENTS(9 任务)/RAM 三文档全部同步。 遗留(验收窗口,非代码空洞):台架第三方 104 主站往返(送检窗口)、 标准源注入动作判据、@test PROT 锚点 + protect 栈水位 + 新堆 min_ever 复测。
This commit is contained in:
+10
-2
@@ -62,6 +62,10 @@ extern osThreadId_t timeSyncTaskHandle;
|
||||
extern const osThreadAttr_t timeSyncTask_attributes;
|
||||
extern osThreadId_t adcTaskHandle;
|
||||
extern const osThreadAttr_t adcTask_attributes;
|
||||
extern osThreadId_t iec104TaskHandle;
|
||||
extern const osThreadAttr_t iec104Task_attributes;
|
||||
extern osThreadId_t protectTaskHandle;
|
||||
extern const osThreadAttr_t protectTask_attributes;
|
||||
|
||||
/* Private defines -----------------------------------------------------------*/
|
||||
/* 栈水位观测节奏:首次报告须晚于 bring-up 深链(mount/mkfs/探针/cfg/syslog),
|
||||
@@ -69,9 +73,11 @@ extern const osThreadAttr_t adcTask_attributes;
|
||||
#define STACK_PROBE_FIRST_MS 5000u
|
||||
#define STACK_PROBE_PERIOD_MS 2000u
|
||||
/* S11(2026-10-03):堆低水位告警阈值(B)。
|
||||
* 依据:2026-10-03 上板两次开机的 min_ever 实测下限 3,712 B(configTOTAL_HEAP_SIZE
|
||||
* 依据:2026-10-03 上板两次开机的 min_ever 实测下限 3,712 B(当时 configTOTAL_HEAP_SIZE
|
||||
* = 48KB)——低于此值说明堆余量 <8%,新增任务/缓冲随时可能分配失败(隐性风险)。
|
||||
* 阈值取 3,072 B 留出运行间 ~600B 波动余量,避免把正常波动误报为故障。 */
|
||||
* 阈值取 3,072 B 留出运行间 ~600B 波动余量,避免把正常波动误报为故障。
|
||||
* 2026-10-12(B5):堆扩至 56KB(.ioc configTOTAL_HEAP_SIZE=57344,CCM 腾给
|
||||
* protectTask/iec104Task 栈),阈值**不随堆缩放**——它是绝对字节安全线。 */
|
||||
#define HEAP_LOW_WATER_B 3072u
|
||||
/* E-31 自愈策略(2026-09-21 审计 P0 修复):启动期存储挂载失败后,
|
||||
* 主循环按 2s 周期重跑完整 bring-up 的次数上限;耗尽则维持无存储降级
|
||||
@@ -93,6 +99,8 @@ static const stack_probe_task_t s_stack_probe[] = {
|
||||
{ "ui", &uiTaskHandle, &uiTask_attributes },
|
||||
{ "timesync", &timeSyncTaskHandle, &timeSyncTask_attributes },
|
||||
{ "adc", &adcTaskHandle, &adcTask_attributes },
|
||||
{ "iec104", &iec104TaskHandle, &iec104Task_attributes },
|
||||
{ "protect", &protectTaskHandle, &protectTask_attributes },
|
||||
};
|
||||
|
||||
#define STACK_PROBE_COUNT (sizeof(s_stack_probe) / sizeof(s_stack_probe[0]))
|
||||
|
||||
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* 模块名称:IEC 60870-5-104 被控站服务(板端胶水任务)
|
||||
* 模块功能:2404 监听 + 单连接 socket 收发 + 把字节流喂给 iec104_link 纯逻辑
|
||||
* 层;对时经 sys_clock_set_unix 落墙钟;数据源走 iec104_pts 默认源
|
||||
* (phasor / prot_elm / prot_set)。协议语义全部在 App/protocol/iec104,
|
||||
* 本文件只做 I/O 编排(A-4 约束 1)。
|
||||
* 线程约定:iec104Task 独占(NET_READY 屏障后循环,100ms 节拍 + 看门狗心跳)。
|
||||
* 创建日期:2026-10-12(B4)
|
||||
*/
|
||||
#include "iec104_serv.h"
|
||||
|
||||
#define DBG_LINE_BUF_MAX 128U /* 深链模块日志缓冲收紧(time_sync 先例) */
|
||||
#define DBG_TAG "[I104]"
|
||||
|
||||
#include "iec104_link.h"
|
||||
#include "iec104_pts.h"
|
||||
#include "net_socket.h"
|
||||
#include "sys_clock.h"
|
||||
#include "sys_events.h"
|
||||
#include "task_watchdog.h"
|
||||
#include "dbg_log.h"
|
||||
|
||||
#include "cmsis_os2.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* 服务周期:COV 延迟 ≤100ms(远小于 SOE 5000ms 验收线);心跳间隔同值 */
|
||||
#define IEC104_POLL_MS 100u
|
||||
/* 接收搬运缓冲(静态,不入栈;link 层内部另有 512B 重组缓冲) */
|
||||
#define IEC104_RX_SZ 128u
|
||||
/* 兜底节拍:门控判"无数据"时每 32 轮无条件收一次(ui_net_sink RM 先例,
|
||||
* 防 RECV_OK 中断丢失把数据永久藏住);须为 2 的幂 */
|
||||
#define IEC104_LIVENESS_DIV 32u
|
||||
/* 连续发送失败阈值:同 ui_net_sink E-04(短写=对端收坏帧) */
|
||||
#define IEC104_SEND_FAIL_MAX 3u
|
||||
|
||||
/* ---------------- 服务状态(iec104Task 独占) ---------------- */
|
||||
static iec104_link_t s_link;
|
||||
static int s_listen = -1;
|
||||
static int s_client = -1; /* 单连接模型:MCU 上即 s_listen */
|
||||
static uint32_t s_gen; /* 网络代次(重建自愈,ui_net_sink 先例) */
|
||||
static uint8_t s_rx[IEC104_RX_SZ];
|
||||
static uint8_t s_liveness_ctr;
|
||||
static uint8_t s_send_fail_run;
|
||||
static uint8_t s_conn_dead; /* 发送连败 → 本轮 link 调用返回后拆链 */
|
||||
|
||||
/* 前向声明(cfg 初始化引用) */
|
||||
static void s_send_apdu(void *ctx, const uint8_t *apdu, uint16_t len);
|
||||
static int s_clock_sync(void *ctx, uint64_t epoch_ms);
|
||||
|
||||
/* V0.1 公共地址固定 1(点表口径;可配置项挂二期) */
|
||||
static const iec104_link_cfg_t s_cfg = { 1u, s_send_apdu, s_clock_sync };
|
||||
|
||||
/*
|
||||
* 函数功能:link 层发送回调——经 net_send 串行 RPC 发出一个 APDU
|
||||
* 入口参数:ctx 未用;apdu/len = 完整 APCI 帧
|
||||
* 返回值:无
|
||||
* 限定条件:s_client >= 0(在 link 调用栈内执行,即本任务上下文)
|
||||
* 函数说明:短写/失败累计(E-04 先例);连续 3 次 → 置 s_conn_dead,
|
||||
* 由 s_service_link 在 link 调用返回后统一拆链(严禁在回调里拆)
|
||||
*/
|
||||
static void s_send_apdu(void *ctx, const uint8_t *apdu, uint16_t len) {
|
||||
int ret;
|
||||
|
||||
(void)ctx;
|
||||
if (s_client < 0) {
|
||||
return;
|
||||
}
|
||||
ret = net_send(s_client, apdu, (int)len, 0);
|
||||
if (ret == (int)len) {
|
||||
s_send_fail_run = 0u;
|
||||
return;
|
||||
}
|
||||
if (s_send_fail_run < 255u) {
|
||||
s_send_fail_run++;
|
||||
}
|
||||
DBG_ERROR("i104 send short: ret=%d/%u run=%u", ret, (unsigned)len,
|
||||
(unsigned)s_send_fail_run);
|
||||
if (s_send_fail_run >= IEC104_SEND_FAIL_MAX) {
|
||||
s_conn_dead = 1u;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:link 层对时回调——epoch 毫秒落系统墙钟(含 SD2506 RTC 写回)
|
||||
* 入口参数:ctx 未用;epoch_ms = C_CS 解析出的 UTC 时刻
|
||||
* 返回值:0 成功 / -1 失败(link 层回 actcon+PN)
|
||||
* 函数说明:uint32 秒域上限 2106-02-07,越界显式拒绝(CP56 域到 2127)
|
||||
*/
|
||||
static int s_clock_sync(void *ctx, uint64_t epoch_ms) {
|
||||
uint64_t secs = epoch_ms / 1000ULL;
|
||||
|
||||
(void)ctx;
|
||||
if (secs > 0xFFFFFFFFULL) {
|
||||
return -1;
|
||||
}
|
||||
return sys_clock_set_unix((uint32_t)secs);
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:创建并监听 2404(socket+bind+listen,抄 ui_net_sink bind_listen)
|
||||
* 返回值:0 成功(s_listen 写回)/ -1 失败
|
||||
* 限定条件:net 子系统可用(NET_READY 屏障后)
|
||||
*/
|
||||
static int s_bind_listen(void) {
|
||||
int ls;
|
||||
struct net_sockaddr_in addr;
|
||||
|
||||
ls = net_socket(NET_AF_INET, NET_SOCK_STREAM);
|
||||
if (ls < 0) {
|
||||
return -1;
|
||||
}
|
||||
(void)memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = NET_AF_INET;
|
||||
addr.sin_port = net_htons(IEC104_SERV_PORT);
|
||||
addr.sin_addr.s_addr = NET_INADDR_ANY;
|
||||
if (net_bind(ls, (struct net_sockaddr *)&addr, (int)sizeof(addr)) < 0) {
|
||||
net_close(ls);
|
||||
return -1;
|
||||
}
|
||||
if (net_listen(ls) < 0) {
|
||||
net_close(ls);
|
||||
return -1;
|
||||
}
|
||||
s_listen = ls;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:主动断开当前 104 连接并重建监听(协议故障/t1 超时/发送连败)
|
||||
* 入口参数:why = 日志原因串(ASCII)
|
||||
* 返回值:无
|
||||
* 函数说明:与 EOF 路径不同——协议违例时主站不会自行断开,必须本端 close
|
||||
* 促其重连;单连接模型下 client 即 listen,close 后统一重建
|
||||
* (time_sync 会话收尾先例,非芯片侧 auto_relisten 风暴路径)
|
||||
*/
|
||||
static void s_drop_conn(const char *why) {
|
||||
DBG_ERROR("i104 drop: %s", why);
|
||||
if (s_client >= 0) {
|
||||
net_close(s_client);
|
||||
}
|
||||
s_client = -1;
|
||||
s_listen = -1;
|
||||
iec104_link_close(&s_link);
|
||||
s_send_fail_run = 0u;
|
||||
s_conn_dead = 0u;
|
||||
s_liveness_ctr = 0u;
|
||||
if (s_bind_listen() < 0) {
|
||||
s_listen = -1; /* 主循环下轮重试 */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:link 层节拍服务 + 故障检测(poll 后查 IDLE 跳变/发送连败)
|
||||
* 入口参数:now = 注入时基(tick ms)
|
||||
* 返回值:无
|
||||
*/
|
||||
static void s_service_link(uint32_t now) {
|
||||
iec104_link_poll(&s_link, now);
|
||||
if (s_conn_dead != 0u) {
|
||||
s_drop_conn("send fail");
|
||||
return;
|
||||
}
|
||||
if (iec104_link_state(&s_link) == IEC104_ST_IDLE) {
|
||||
s_drop_conn("protocol fault");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:单次服务循环(代次自愈 → accept → 门控收 → 喂 link → 节拍)
|
||||
* 返回值:无
|
||||
* 限定条件:NET_READY 已置位;s_cfg/s_link 已 init
|
||||
* 函数说明:门控(net_can_accept/net_can_read 纯 RAM 读)+ 兜底节拍照
|
||||
* ui_net_sink I-1/I-2;EOF 时 client==listen 严禁 close(net 层
|
||||
* 已 auto_relisten,close 会连监听一起毁)
|
||||
*/
|
||||
static void s_serv_poll(void) {
|
||||
uint32_t now = osKernelGetTickCount();
|
||||
int n;
|
||||
|
||||
/* 网络重建(代次变化):旧监听/客户端随芯片复位失效 → 重建 */
|
||||
if (net_get_generation() != s_gen) {
|
||||
if ((s_client >= 0) && (s_client != s_listen)) {
|
||||
net_close(s_client);
|
||||
}
|
||||
if (s_listen >= 0) {
|
||||
net_close(s_listen);
|
||||
s_listen = -1;
|
||||
}
|
||||
s_client = -1;
|
||||
iec104_link_close(&s_link);
|
||||
s_send_fail_run = 0u;
|
||||
s_conn_dead = 0u;
|
||||
s_liveness_ctr = 0u;
|
||||
s_gen = net_get_generation();
|
||||
(void)s_bind_listen();
|
||||
return;
|
||||
}
|
||||
|
||||
if (s_listen < 0) {
|
||||
(void)s_bind_listen(); /* 启动失败/被毁:重试 */
|
||||
return;
|
||||
}
|
||||
|
||||
if (s_client < 0) {
|
||||
int c;
|
||||
|
||||
if (net_can_accept(s_listen) == 0) {
|
||||
if (net_get_sock(s_listen) == NULL) {
|
||||
s_listen = -1; /* 控制块消失:交回上方重建 */
|
||||
}
|
||||
return;
|
||||
}
|
||||
c = net_accept(s_listen, NULL, NULL);
|
||||
if (c >= 0) {
|
||||
s_client = c;
|
||||
s_send_fail_run = 0u;
|
||||
s_conn_dead = 0u;
|
||||
s_liveness_ctr = 0u;
|
||||
iec104_link_open(&s_link, now);
|
||||
DBG_INFO("i104: accepted fd=%d", c);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* 门控 + 兜底:无数据多数轮直接走 link 节拍;每 32 轮无条件收一次 */
|
||||
if (net_can_read(s_client) == 0) {
|
||||
if (((++s_liveness_ctr) & (IEC104_LIVENESS_DIV - 1u)) != 0u) {
|
||||
s_service_link(now);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
s_liveness_ctr = 0u;
|
||||
}
|
||||
|
||||
n = net_recv(s_client, s_rx, (int)sizeof(s_rx), NET_MSG_DONTWAIT);
|
||||
if (n > 0) {
|
||||
iec104_link_on_rx(&s_link, s_rx, (uint16_t)n, now);
|
||||
} else if (n == 0) {
|
||||
/* 对端关闭:net 层已 auto_relisten;client==listen 时严禁 close */
|
||||
if (s_client != s_listen) {
|
||||
net_close(s_client); /* 模拟器多连接后端:数据通道独立 */
|
||||
}
|
||||
s_client = -1;
|
||||
s_liveness_ctr = 0u;
|
||||
iec104_link_close(&s_link);
|
||||
if ((net_get_sock(s_listen) == NULL) && (s_bind_listen() < 0)) {
|
||||
s_listen = -1;
|
||||
}
|
||||
return;
|
||||
} else if (net_get_errno() != NET_ERR_WOULDBLOCK) {
|
||||
s_drop_conn("recv err");
|
||||
return;
|
||||
}
|
||||
|
||||
s_service_link(now);
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:iec104Task 任务体(freertos.c USER CODE 区创建)
|
||||
* 入口参数:argument 未用
|
||||
* 返回值:无(不返回)
|
||||
* 函数说明:NET_READY 屏障(100ms 分片 + 每片喂心跳,timeSyncTask 先例)→
|
||||
* 点表/链路 init + 建监听 → 100ms 服务循环(每轮喂看门狗)
|
||||
*/
|
||||
void iec104_serv_task(void *argument) {
|
||||
(void)argument;
|
||||
|
||||
if (sys_evtHandle != NULL) {
|
||||
for (;;) {
|
||||
uint32_t r = osEventFlagsWait(sys_evtHandle, SYS_EVT_NET_READY,
|
||||
osFlagsWaitAny | osFlagsNoClear, 100u);
|
||||
if ((r & osFlagsError) == 0u) {
|
||||
break; /* 就绪位是状态位(NoClear),不消费 */
|
||||
}
|
||||
task_wd_beat(TASK_WD_IEC104);
|
||||
}
|
||||
}
|
||||
|
||||
iec104_pts_init();
|
||||
iec104_link_init(&s_link, &s_cfg, NULL);
|
||||
s_gen = net_get_generation();
|
||||
if (s_bind_listen() < 0) {
|
||||
DBG_ERROR("i104: bind port %u FAIL, retry in loop",
|
||||
(unsigned)IEC104_SERV_PORT);
|
||||
} else {
|
||||
DBG_INFO("i104: listening on %u", (unsigned)IEC104_SERV_PORT);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
task_wd_beat(TASK_WD_IEC104);
|
||||
s_serv_poll();
|
||||
osDelay(IEC104_POLL_MS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 模块名称:IEC 60870-5-104 被控站服务(对外接口)
|
||||
* 模块功能:声明 iec104Task 任务体与监听端口;协议实现在 App/protocol/iec104/,
|
||||
* 本接口仅供 Src/freertos.c 创建任务使用。
|
||||
* 创建日期:2026-10-12(B4)
|
||||
*/
|
||||
#ifndef IEC104_SERV_H
|
||||
#define IEC104_SERV_H
|
||||
|
||||
/* IEC 60870-5-104 被控站监听端口(DL/T 634.5104 标准端口) */
|
||||
#define IEC104_SERV_PORT 2404u
|
||||
|
||||
/*
|
||||
* 函数功能:iec104Task 任务体(在 Src/freertos.c USER CODE 区 osThreadNew 创建)
|
||||
* 入口参数:argument - 未用
|
||||
* 返回值:无(任务不返回)
|
||||
*/
|
||||
void iec104_serv_task(void *argument);
|
||||
|
||||
#endif /* IEC104_SERV_H */
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 模块名称:保护任务(L3 板端接线,B5)——实现
|
||||
* 模块功能:见 protect_task.h。每拍三件事:
|
||||
* ① L5-4 采样故障闭锁:adc_health_flags() 电平位命中 → 元件状态
|
||||
* 复位(防陈旧判据)+ 本拍不 eval;
|
||||
* ② prot_set_selfcheck()(L5-1 定值完整性巡检,31 项 sum32,开销
|
||||
* 可忽略;失配 → prot_set 内部闭锁,eval 自动复位全元件);
|
||||
* ③ prot_elm_run()(phasor rms → 判据步进)+ 动作位图边沿日志。
|
||||
* 定值/元件初始化在 app_main_init(内核前,B5);本任务只消费。
|
||||
* 线程约定:prot_elm_run / prot_set_selfcheck 仅本任务上下文(prot_elm.h);
|
||||
* 跨上下文复归(104 YK11)经 prot_elm_request_reset 落请求。
|
||||
* 创建日期:2026-10-12(B5)
|
||||
*/
|
||||
#include "protect_task.h"
|
||||
|
||||
#include "cmsis_os2.h"
|
||||
|
||||
#define DBG_TAG "[PROT]"
|
||||
#define DBG_LINE_BUF_MAX 128U
|
||||
#include "dbg_log.h"
|
||||
|
||||
#include "adc_health.h"
|
||||
#include "prot_elm.h"
|
||||
#include "prot_set.h"
|
||||
#include "task_watchdog.h"
|
||||
|
||||
/* L5-4 采样故障电平闭锁位:stall(可自愈)+ backward(锁存)都须停判据。
|
||||
* 锁存类(FRSTDATA/HW_ERR 等)不在此列——它们是一次性事件痕迹,不构成
|
||||
* "当前测量不可信";持续 stall/backward 才是。 */
|
||||
#define PROT_HF_LOCK_MASK (ADC_HF_TPAFE_STALL | ADC_HF_STM32_STALL | ADC_HF_SEQ_BACKWARD)
|
||||
|
||||
static uint32_t s_prev_active; /* 上拍动作位图(边沿日志用) */
|
||||
static uint8_t s_prev_hf_lock; /* 上拍采样闭锁态(边沿日志用) */
|
||||
|
||||
/*
|
||||
* 函数功能:动作位图变化沿日志(逐变化元件打名字与状态)
|
||||
* 入口参数:active - 本拍 prot_elm_active_mask()
|
||||
* 函数说明:V0.1 无出口硬件(规划 R7),动作 = 遥信 + 日志;SOE 落盘随 L4。
|
||||
*/
|
||||
static void s_log_active_edge(uint32_t active) {
|
||||
uint32_t chg = active ^ s_prev_active;
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0u; (i < (uint32_t)PE_COUNT) && (chg != 0u); i++) {
|
||||
const uint32_t bit = 1u << i;
|
||||
|
||||
if ((chg & bit) != 0u) {
|
||||
prot_elm_state_t st;
|
||||
|
||||
chg &= ~bit;
|
||||
prot_elm_state((prot_elm_id_t)i, &st);
|
||||
DBG_INFO("elm %s asserted=%u picked=%u",
|
||||
prot_elm_name((prot_elm_id_t)i),
|
||||
(unsigned)st.asserted, (unsigned)st.picked);
|
||||
}
|
||||
}
|
||||
s_prev_active = active;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:protectTask 线程入口
|
||||
* 入口参数:argument - 未用
|
||||
* 返 回 值:无(不返回)
|
||||
* 函数说明:无就绪屏障(判据只依赖 phasor 使用区,未就绪时 prot_elm_run
|
||||
* 整拍自跳;采样闭锁另有 adc_health 电平位兜底)→ 上电即跑。
|
||||
* 每拍喂看门狗(TASK_WD_PROTECT,产品 required_mask 0x1F7)。
|
||||
*/
|
||||
void protect_task(void *argument) {
|
||||
(void)argument;
|
||||
|
||||
DBG_INFO("protect task start: cycle=%ums elm=%u",
|
||||
(unsigned)PROTECT_TASK_CYCLE_MS, (unsigned)PE_COUNT);
|
||||
|
||||
for (;;) {
|
||||
uint32_t now = osKernelGetTickCount();
|
||||
uint32_t hf = adc_health_flags();
|
||||
|
||||
if ((hf & PROT_HF_LOCK_MASK) != 0u) {
|
||||
/* L5-4:测量链不可信 → 复位元件(本任务上下文,直接 init 合法)
|
||||
* 并跳过判据;stall 自愈后下一拍自动恢复 */
|
||||
if (s_prev_hf_lock == 0u) {
|
||||
DBG_ERROR("sampling FAULT -> protection blocked (hf=0x%08lX)",
|
||||
(unsigned long)(hf & PROT_HF_LOCK_MASK));
|
||||
}
|
||||
s_prev_hf_lock = 1u;
|
||||
prot_elm_init();
|
||||
} else {
|
||||
if (s_prev_hf_lock != 0u) {
|
||||
DBG_INFO("sampling recovered -> protection resumed");
|
||||
s_prev_hf_lock = 0u;
|
||||
}
|
||||
/* L5-1 巡检:定值区与封存校验和不符 → prot_set 闭锁(下一拍起
|
||||
* eval 自动复位全元件)。⚠ 与 104 定值写(iec104Task set+seal)
|
||||
* 的竞态窗口为 µs 级:selfcheck 误锁后同一次写的 seal 即清锁
|
||||
* (prot_set.c),V0.1 如实登记,P4 定值持久化时收口。 */
|
||||
(void)prot_set_selfcheck();
|
||||
prot_elm_run(now);
|
||||
}
|
||||
|
||||
s_log_active_edge(prot_elm_active_mask());
|
||||
|
||||
task_wd_beat(TASK_WD_PROTECT);
|
||||
osDelay(PROTECT_TASK_CYCLE_MS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 模块名称:保护任务(L3 板端接线,B5)
|
||||
* 模块功能:protectTask 线程入口——以固定节拍驱动保护判据
|
||||
* (`prot_elm_run()`:phasor rms → 元件步进),并落实 L5-4 采样
|
||||
* 故障闭锁(`adc_health_flags()` 电平位 → 元件状态复位 + 本拍不判据)。
|
||||
* 判据本体在 `App/algo/prot_elm.c`(纯逻辑,L0.5 已覆盖),本文件
|
||||
* 只做消费/编排(AGENTS 目录地图:task 不装算法)。
|
||||
* 线程约定:仅本任务调 prot_elm_run / prot_set_selfcheck(prot_elm.h 线程约定);
|
||||
* prot_set 写在 P4 前无第二写者(104 定值写经 pts→prot_set,见注)。
|
||||
* 创建日期:2026-10-12(B5)
|
||||
*/
|
||||
#ifndef PROTECT_TASK_H
|
||||
#define PROTECT_TASK_H
|
||||
|
||||
/* 判据节拍(ms):V0.1 元件吃 50 Hz 基波 rms(phasor 每工频周更新)→ 20 ms
|
||||
* = 一个工频周;延时精度由 prot_elm 的 now_ms 差值法保证,与节拍无关。
|
||||
* 规划 §4 的"1 ms 高优先级"是参考系统瞬时值元件口径,随 P2 瞬时值元件再评。 */
|
||||
#define PROTECT_TASK_CYCLE_MS 20u
|
||||
|
||||
/*
|
||||
* 函数功能:protectTask 线程入口(freertos.c USER CODE 区创建)
|
||||
*/
|
||||
void protect_task(void *argument);
|
||||
|
||||
#endif /* PROTECT_TASK_H */
|
||||
Reference in New Issue
Block a user