Files
STM32F4-Base/App/cfg/cfg_file.h
T
wandering1 007f6a0e2f docs(cfg): 配置设计档重写为现状版,删除旧二进制档叙述
原「配置文件设计说明.md」是 2026-09 的规划文档(P1~P8 实施计划、D1~D15
决策表、差距调研、模块清单动作列、已终结的开放问题),与现在跑的系统
已有明显出入。改写成只描述当前状态的「配置文件设计.md」。

新文档 9 节:概览 / 文件格式(路径与容量、语法、出厂模板原文、值类型)/
运行时机制(上电加载、外科手术式保存、2s 轮询与沉降、视图一致性守卫、
写者归属)/ 段与键表(8 段全满、注册顺序、接入新段模板、段回调)/
接口(引擎 API、平台后端)/ 内存占用(编译期钉死的 9217B 暂存)/
异常与恢复 / 双端差异 / 已知限制。

顺带修正一处事实错误:旧文档称 FTP STOR 是「写 .TMP 再 rename 原子更新」,
实际 lftpd receive_file 是原地覆写,已按代码现状改写。

旧二进制档(NCFG)的叙述按裁定从全仓移除:文档只描述当前状态,不再
交代旧版本兼容性。删掉网络配置说明 §3.2 整节(后续小节重排为 3.2~3.5),
并清理 README / 架构总览 / 产品需求 / 部署环境等 11 处同类叙述。

同步:
- 8 段注册、FTP 原地覆写、2s FAT mtime 粒度等数据更新进配置分层架构图,
  重跑后与生成器逐字节一致,check_generated_fresh 里这条存量基线下架
- 全仓 24 处引用改用新文档名,旧节号逐条映射到新节号
- 文档规范 §7.1 变更记录例外名单 4 篇减为 3 篇(该档实际无变更记录表)

验证:48 个提交期钩子全通过;Keil 构建 0 错误 0 警告;
check_doc_links / check_mermaid / check_generated_fresh 均通过。
2026-11-15 20:55:04 +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 §13.8
* v1.5 2026-11-05 DTU 项目组 契约同步视图一致性守卫(issue #73 SNTP 补验揪出):
* poll 读视图与 stat 令牌不符或内容坏 = 拒绝应用(RAM/基线不动、2s
* 重试自愈);save 读视图不符 = 拒存返回 -1(原文件不动)。
* 细节见 cfg_file.c v1.6 与《配置文件设计》第 5 节视图守卫
*/
#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 */