Files
STM32F4-Base/App/cfg/cfg_file.h
T
super_agent_bot 1a2ca0467d
CI / 静态门禁 (pre-commit) (pull_request) Failing after 6m33s
CI / 主机侧单测 (MSVC) (pull_request) Successful in 35s
CI / 静态门禁 (pre-commit) (push) Failing after 5m7s
CI / 主机侧单测 (MSVC) (push) Failing after 43s
fix(cfg): 视图守卫补内容判据——同尺寸全 0 旧映射块也能拦(#73)
台架(PR #82 head d9303e05,常授权烧写验证)在三点校验版守卫上继续复现
出打回形态:卷层给出的旧映射块与目标文件恰好同长(1064B)且整块全 0,
读长 == st.size 与读前后复 stat 全部通过,解析零错误、RAM 照样打回默认
(15:21 决定性轮:盘文件 RETR 校验七段完好,重载窗口内 s_sntp 三字节段
全 0)。纯令牌层校验对"内容坏"是盲的,必须补内容判据。

处置(引擎侧,与三点校验同族):
- 新增 s_view_bad:重载/保存读到的视图若为空读、或 [0,len) 内任意偏移
  含 NUL 字节即判坏——INI UTF-8 文本约定下任何偏移都不得含 0x00;解析
  器按行切分遇 NUL 即断行,零块之后的内容本就不可达(静默截断同源故障),
  拒之不误伤任何可解析文档。不要求首字节 ';'(手写文档可直接段名起始)。
- poll:坏内容 = 与长度/令牌不符同处置——拒绝应用,RAM 与基线不动,2s
  重试自愈,首次 ERROR + 自检留痕,每 30 趟一条 WARN(限速)。
- save:坏内容同族拒存返回 -1,原文件一字节不动,调用方 dirty 保留重试。
- 边界如实保留:内容合法但陈旧的整卷视图(长度/令牌/内容三者皆一致滞后)
  引擎层无法检出,属卷层(dhara/FTL)课题,重启必然收敛;"改过配置后
  重启一次"在卷层根治前仍是最稳口径。

测试:
- TC-CONFIG-061(poll 同尺寸全 0 块 HELD + 视图刷新自愈 + 零回调)、
  TC-CONFIG-062(save 遇全 0 块拒存、文件字节/写次数不动、追平后重试
  成功);桩新增 vfs_mark_stale_zeros() 注入同长全 0 旧视图。
- cfg_file 套件 259/259;iec104 179/179、run_par 67/67、adc_cal 117/117、
  sntp 98/98、cfg_file_store_mcu 34/34 复跑全绿。
- /keil-build 0 错 0 警:Code 254,784 -> 254,820 B(+36 B);台账与同码
  凭证已同步。台架实录见 PR #82 评论:NUL 注入块实机 HELD(16:55:46)
  + WARN 节拍 30/60 趟命中(16:56:42/16:57:41)+ 视图转新鲜后重载自动
  追平;残余打回事件均为"内容合法但陈旧"整卷视图(15:19:30/16:34:59/
  16:58:38),属已声明守卫边界,盘文件全程未吞段,重启收敛实机确认
  (17:04 RAM 回文件值)。

文档:
- 《配置文件设计说明》§4-(3)/§5.3 守卫描述补内容判据与 15:21 实证形态、
  风险表行更新、变更记录 v1.17 行同步;
- 《配置文件单元测试说明》TC-CONFIG-061/062 行 + 当前结果 259/259 +
  扩展指南补 vfs_mark_stale_zeros()。
2026-11-05 17:08:25 +08:00

163 lines
8.3 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 模块名称:cfg_file
* 模块功能:通用配置文件引擎(双端共享核心)公共接口——INI 段/键表解析校验、
* 外科手术式保存(保留注释/未知内容,缺失段/键写回)、出厂模板生成、
* 沉降去抖轮询与分段变更回调;平台文件操作经 cfg_file_store 后端
* 适用平台:STM32F407ZGTx / PC 模拟器(两端共用)
* 作者:王建锋
* 创建日期:2026-09-14
* 修改记录:
* v1.0 2026-09-14 王建锋 创建初始版本(P3:段键表引擎 + net_cfg 集成)
* v1.1 2026-09-15 王建锋 属主任务由 netTask 改为 defaultTask(配置引擎单一属主)
* v1.2 2026-09-21 王建锋 超长守卫契约同步——poll 沉降
* 后先按真实 st.size 判超长(旧实现查截断后读长恒假)、
* save 输出上限收紧至 CFG_FILE_MAX_LEN、写盘唯一闸口拒写
* 超长;超长处置补自检留痕
* v1.3 2026-10-15 王建锋 新增公开常量
* CFG_FILE_MAX_NAME_LEN(段名/键名上限 15 字符)
* v1.4 2026-10-25 DTU 项目组 「数据可信」有符号零点类型:新增 CFG_VAL_INT 有符号十进制值类型
* (len = 1/2/4,小端补码)——标定零点偏移等负值需有符号
* 落盘,动因与取舍见 docs/任务规划/数据可信.md §4.4
* v1.5 2026-11-05 DTU 项目组 契约同步视图一致性守卫(issue #73 SNTP 补验揪出):
* poll 读视图与 stat 令牌不符或内容坏 = 拒绝应用(RAM/基线不动、2s
* 重试自愈);save 读视图不符 = 拒存返回 -1(原文件不动)。
* 细节见 cfg_file.c v1.6 与《配置文件设计说明》变更节
*/
#ifndef CFG_FILE_H
#define CFG_FILE_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stddef.h>
/* 配置文件长度上限(字节);超过 = 文件损坏,按出厂模板重建
* (load 与 poll 同判:poll 在读取前基于真实 st.size 判定) */
#define CFG_FILE_MAX_LEN 4096u
/* 引擎可注册段数上限 */
#define CFG_FILE_MAX_SECTIONS 8u
/* 段名 / 键名最大字符数(不含结尾 NUL);超长的注册描述符被 cfg_file_register 拒绝。
* 该上限是生成文档每行余量(112 字节)可编译期验证的前提,勿放宽 */
#define CFG_FILE_MAX_NAME_LEN 15u
/* 单段键数上限 */
#define CFG_FILE_MAX_KEYS 16u
/* 沉降去抖:变更基线连续 N 次轮询不变才重载(轮询周期 2s → 4s 沉降) */
#define CFG_FILE_SETTLE_CNT 2u
/*
* 键值类型
* UINT:无符号十进制;len = 目标字段字节数(1/2/4,小端)
* IP4 :点分 IPv4 "a.b.c.d";字段 uint8_t[4]
* MAC :十六进制 MAC "xx:xx:xx:xx:xx:xx"(分隔符兼容 - 与 .);字段 uint8_t[6]
* STR :ASCII 字符串;字段 char[len](len = 缓冲长度,自动补 NUL)
* INT :有符号十进制(可带 + / - 号);len = 目标字段字节数(1/2/4,小端补码,
* 范围按宽度收窄:int8/int16/int32;负值合法,如标定零点偏移)
*/
typedef enum {
CFG_VAL_UINT = 0,
CFG_VAL_IP4,
CFG_VAL_MAC,
CFG_VAL_STR,
CFG_VAL_INT
} cfg_val_type_t;
/* 键定义(offset/len 均相对段 RAM 副本起始) */
typedef struct {
const char *name; /* 键名(小写,≤ CFG_FILE_MAX_NAME_LEN 字符) */
cfg_val_type_t type; /* 值类型 */
size_t offset; /* 字段偏移 */
size_t len; /* 字段长度 */
} cfg_key_def_t;
/* 段注册描述符 */
typedef struct {
const char *name; /* 段名(≤ CFG_FILE_MAX_NAME_LEN 字符) */
void *p_data; /* 段 RAM 副本(模块自有静态区,引擎原地更新) */
const void *p_defaults; /* 工厂默认值(与 p_data 同布局;load 先复位再解析) */
size_t data_size; /* RAM 副本字节数 */
const cfg_key_def_t *p_keys; /* 键表 */
uint8_t key_count; /* 键数(1 ~ CFG_FILE_MAX_KEYS) */
void (*p_cb)(void); /* 变更回调(可空;poll 重载后该段有差异时调用;
注册段 data_size 须 ≤ 64 字节方可挂回调) */
} cfg_section_reg_t;
/*
* 函数功能:注册配置段(引擎建立"段 → RAM 副本 + 键表"映射)
* 入口参数:p_reg - 段注册描述符(不可为 NULL) const cfg_section_reg_t *
* 返回值:0 - 成功;-1 - 参数非法/段名重复/段数超限 int
* 限定条件:启动早期调用一次(重复注册同段名拒绝);
* 注册后 p_data/p_defaults/p_keys 生命周期须覆盖引擎使用期
*/
int cfg_file_register(const cfg_section_reg_t *p_reg);
/*
* 函数功能:从配置文件加载全部段(文件 = 配置唯一来源)
* 入口参数:无
* 返回值:0 - 正常(含回退工厂默认);-1 - 严重错误(RAM 已置工厂默认,仍安全) int
* 限定条件:至少注册一个段
* 函数说明: 1. 各段先复位工厂默认(文件缺失/损坏的键 = 工厂默认)
* 2. 文件缺失 → 按当前 RAM 副本生成出厂模板写盘(首启建文件)
* 3. 文件存在 → 解析:有效键写入 RAM 副本;无效键留工厂默认并留痕
* 4. 文件超长(> CFG_FILE_MAX_LEN)= 损坏 → 工厂默认 + 重建模板
* + 自检留痕(poll 检出运行期超长文件执行同一契约)
*/
int cfg_file_load(void);
/*
* 函数功能:保存全部段到配置文件(外科手术式)
* 入口参数:无
* 返回值:0 - 成功;-1 - 写失败(原文件保持不动) int
* 限定条件:至少注册一个段
* 函数说明:文件存在 → 逐行保留注释/未知段/未知键,受管段/键按 RAM 副本
* 值原位改写,缺失段/键补写;文件缺失/损坏 → 按 RAM 副本重建
* 完整文档(含文件头注释);写盘 = 临时文件 + 原子改名;输出超
* CFG_FILE_MAX_LEN → 拒绝保存返回 -1(原文件不动 + 自检上报,
* 引擎写盘闸口同拒);读视图与 stat 基准不符(空读/截断/读中
* 被改写)或内容坏(INI 文本任意偏移含 NUL——dhara 同尺寸全 0
* 旧映射块 2026-11-05 台架实证)同样拒存返回 -1——防按短/坏视图
* 外科重写把文件写小、非默认段被静默删除(视图一致性守卫,
* 调用方脏位保留 = 下一趟自然重试)
*/
int cfg_file_save(void);
/*
* 函数功能:配置文件变更轮询(沉降去抖 + 重载 + 分段变更回调)
* 入口参数:无
* 返回值:无
* 限定条件:由配置引擎属主任务周期调用(建议 2s;MCU = defaultTask,
* 模拟器 = 主循环);引擎静态状态无跨任务保护,属主唯一即无竞态
* 函数说明:(size, mtime 变更令牌) 相对基线变化且连续 CFG_FILE_SETTLE_CNT
* 次轮询稳定 → 先查 st.size 超 CFG_FILE_MAX_LEN = 损坏 → 工厂默认
* + 重建模板 + 自检留痕(不触发段回调:保留在线修复通道,重启
* 收敛);否则过视图一致性守卫(读长 = st.size、内容无 NUL(dhara
* 同尺寸全 0 旧映射块 2026-11-05 台架实证)且读前后 (size,
* mtime) 不变;不符 = 卷层旧视图/坏块/读中被改写 → 拒绝应用:RAM 与
* 基线不动,2s 重试自愈,持续到重启则由 load 全新挂载收敛;首次
* 拒绝自检留痕,其后每 30 趟一条 WARN)后重载全部段(各段复位
* 工厂默认后解析);挂回调段有差异 → 调用其回调(如触发网络重建);
* 重载后刷新基线(回调触发的写盘不引发二次重载)
*/
void cfg_file_poll(void);
/*
* 函数功能:取段 RAM 副本指针
* 入口参数:p_name - 段名 const char *
* 返回值:段 RAM 副本指针;未注册返回 NULL void *
* 限定条件:无
*/
void *cfg_file_section_data(const char *p_name);
#ifdef __cplusplus
}
#endif
#endif /* CFG_FILE_H */