feat(protect): B7 定值持久化 + 全局软压板 + L5-1 竞态收口(W1 代码腿完成)

- prot_set:新增 PS_GLOBAL_EN(枚举尾追加);值区双缓冲 + 单字交换,
  prot_set_set_sealed 原子写+封存;selfcheck 改 seqlock 式复核
  (提交撞见 = 本轮跳过)→ 收口 B5 登记的 µs 级误锁窗口
- 持久化:新增 App/cfg/prot_set_store.c/h,/prot_set.bin blob
  (magic+版本+计数+值区+sum32 正/反码对,144 B)走 cfg_store_write_atomic;
  uvprojx 注册 + 模拟器豁免点名(check_registration 同步)
- 写路径:C_SE/YK12 执行段置脏 → iec104Task 投递 SYS_EVT_PROT_SET_SAVE
  (事件位 bit7)→ defaultTask(配置引擎属主)落盘,写失败脏回置 = 天然
  重试;装载 = STORAGE_READY 屏障前整表原子 parse(损坏保出厂默认 +
  自检留痕 prot set corrupt;文件缺失 = 首启静默)
- YK12 转真:两段式(选择段校验 DPC / 执行段 set_sealed),protectTask
  下一拍读退出态 → 复位元件 + 停判据(global plate OUT/IN 边沿日志);
  本地定值项 comm_addr=0 显式不可寻址(防 IOA=0 误命中首个本地项)
- 单测:prot_set 63 断言(+33:软压板/原子写/脏握手/blob 往返/损坏拒绝/
  伪造自洽越界对抗样本)、iec104 94 断言(+7:YK12 两段转真/置脏/本地项
  C_RD EVI)
- 文档:IEC104 设计说明 §3.3/§3.4/§7、保护规划 §3.5 L5-1/§7 P4/变更记录、
  App/algo 与 App/cfg README、W1 任务卡 B7→🟦(台架腿 🔴 待窗口,随 B6 同窗)
- 验证:@build 0 错 0 警(Code=205500,ZI +280 = 双缓冲+blob 缓冲);
  ci_local 全绿(L0 27 钩子 + L0.5 13 套件 826 断言);ram_baseline 台账
  受管区与内存快照已同步;19 个改动文件无 BOM / LF / 零乱码
This commit is contained in:
2026-10-12 15:01:49 +08:00
parent d3107f374f
commit 1fe163ba7b
22 changed files with 655 additions and 71 deletions
+64
View File
@@ -0,0 +1,64 @@
/*
* 模块名称:prot_set_store(B7 定值持久化)——实现
* 模块功能:见 prot_set_store.h。blob 格式/校验/原子装载全在 prot_set.c
* (纯逻辑,主机单测覆盖),本文件只做"读文件→parse、
* serialize→原子写"的平台胶水。
* 文件口径:"/prot_set.bin"(卷根,8.3 合规,FF_USE_LFN=0 约束);
* 原子写临时名由 cfg_store_write_atomic 按目标目录推导
* (固定 config.TMP),与 /config.ini 的保存同在 defaultTask
* 串行执行,无并发竞争。
* 创建日期:2026-10-12(B7)
*/
#include "prot_set_store.h"
#include <stddef.h>
#include "cfg_file_store.h"
#include "prot_set.h"
#define PROT_SET_STORE_PATH "/prot_set.bin"
/* blob 收发缓冲(静态:defaultTask 栈深已是全项目最深链,勿再压 144 B 局部) */
static uint8_t s_blob[PROT_SET_BLOB_SZ];
/*
* 函数功能:开机装载定值 blob
* 入口参数:无
* 返 回 值:0 已装载 / 1 文件缺失或读失败(保持默认)/ -1 损坏被拒
* 函数说明:读失败与"文件不存在"同归 1——启动期卷锁无竞争(本任务独占
* bring-up),try-lock 失败即真 I/O 故障,此时保持出厂默认并让
* 调用方按"无档"处理是安全侧(定值仍封存自洽,L5-1 不误锁)。
*/
int prot_set_store_load(void) {
size_t nread = 0u;
if (cfg_store_read(PROT_SET_STORE_PATH, s_blob, sizeof(s_blob), &nread) != 0) {
return 1;
}
if (prot_set_store_parse(s_blob, (uint32_t)nread) != 0) {
return -1;
}
return 0;
}
/*
* 函数功能:落盘当前定值(消费脏标志;失败回置等重试)
* 入口参数:无
* 返 回 值:0 无待写或成功 / -1 写失败
*/
int prot_set_store_save(void) {
uint32_t len = 0u;
if (prot_set_dirty_take() == 0u) {
return 0;
}
if (prot_set_store_serialize(s_blob, (uint32_t)sizeof(s_blob), &len) != 0) {
prot_set_dirty_mark();
return -1;
}
if (cfg_store_write_atomic(PROT_SET_STORE_PATH, s_blob, (size_t)len) != 0) {
prot_set_dirty_mark(); /* 卷忙/写失败:脏保留,iec104Task 下轮再通知 */
return -1;
}
return 0;
}