Files
STM32F4-Base/Drivers/BSP/NETCFG/net_cfg.c
T

356 lines
11 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.
/*
* 模块名称:Network Configuration Core (配置核心)
* 模块功能:RAM 配置副本 + 工厂默认 + 加载/保存编排 + 实际 MAC 影子 +
* IPv4 字符串转换;存储经 cfg_file 通用配置文件引擎(INI [network]
* 段:ip/mask/gw/mac);旧版 NCFG 二进制格式归 net_cfg_legacy
* (首启一次性迁移)
* 适用平台:STM32F407ZGTx / PC 模拟器(两端共用)
* 作者:王建锋
* 创建日期:2026-09-10
* 修改记录:
* v1.0 2026-09-10 王建锋 创建初始版本
* v1.1 2026-09-14 王建锋 存储迁移至 cfg_file 引擎(INI);旧 NCFG 代码移至 net_cfg_legacy
* v1.2 2026-09-15 王建锋 保存改跨任务交接(request/state/run + 通知回调);
* 引擎属主 = defaultTask(P1-3 竞态修复)
*/
/* 头文件包含区 */
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include "net_cfg.h"
#include "net_cfg_legacy.h"
#include "cfg_file.h"
#define DBG_TAG "[NET_CFG]"
#include "dbg_log.h"
/* 私有宏定义区 */
/* 工厂默认值(单一来源:s_cfg 初值与 s_defaults 共用,避免两处漂移) */
#define NET_CFG_DEF_IP { 192u, 168u, 1u, 100u }
#define NET_CFG_DEF_MASK { 255u, 255u, 255u, 0u }
#define NET_CFG_DEF_GW { 192u, 168u, 1u, 1u }
#define NET_CFG_DEF_MAC { 0u, 0u, 0u, 0u, 0u, 0u }
/* 静态变量定义区 */
/* RAM 配置副本:以工厂默认值静态初始化(落 .data),自启动即有效——
* 不依赖 net_cfg_load 是否被调用(load 仅在文件有效时覆盖) */
static net_cfg_t s_cfg = {
.ip = NET_CFG_DEF_IP,
.mask = NET_CFG_DEF_MASK,
.gw = NET_CFG_DEF_GW,
.mac = NET_CFG_DEF_MAC,
};
static uint8_t s_active_mac[6]; /* 芯片实际 MAC 影子(netTask 回写) */
static uint8_t s_active_valid; /* 影子有效标志(0 = 尚未回写) */
static net_cfg_apply_cb_t s_apply_cb; /* "立即应用"平台回调(未注册 = 空操作) */
static volatile uint8_t s_save_pending; /* 1 = 有待执行保存请求(UI 投递/属主执行) */
static volatile uint8_t s_save_result; /* 最近一次保存结果:0 = 无;1 = 成功;2 = 失败 */
static net_cfg_save_req_cb_t s_save_req_cb; /* "保存请求"平台通知(未注册 = 空操作) */
/* 工厂默认(引擎注册 p_defaults 指向;与 s_cfg 初值共用宏单一来源) */
static const net_cfg_t s_defaults = {
.ip = NET_CFG_DEF_IP,
.mask = NET_CFG_DEF_MASK,
.gw = NET_CFG_DEF_GW,
.mac = NET_CFG_DEF_MAC,
};
/* [network] 段键表(net_cfg_t 布局内偏移) */
static const cfg_key_def_t s_net_keys[] = {
{ "ip", CFG_VAL_IP4, offsetof(net_cfg_t, ip), 4u },
{ "mask", CFG_VAL_IP4, offsetof(net_cfg_t, mask), 4u },
{ "gw", CFG_VAL_IP4, offsetof(net_cfg_t, gw), 4u },
{ "mac", CFG_VAL_MAC, offsetof(net_cfg_t, mac), 6u },
};
/* 函数定义区 */
/*
* 函数功能:[network] 段变更回调(poll 重载检出差异时由引擎调用)
* 入口参数:无
* 返回值:无
* 限定条件:无(未注册"立即应用"回调时空操作)
* 函数说明:转平台回调(MCU:netTask 置 SYS_EVT_NET_RECONFIG 重建网络)
*/
static void s_net_changed_cb(void) {
if (s_apply_cb != NULL) {
s_apply_cb();
}
}
/*
* 函数功能:向 cfg_file 引擎注册 [network] 段(幂等)
* 入口参数:无
* 返回值:无
* 限定条件:load/save 前调用
* 函数说明:段数据 = s_cfg RAM 副本;工厂默认 = s_defaults;
* 变更回调触发"立即应用"
*/
static void s_net_register(void) {
static uint8_t s_done;
cfg_section_reg_t reg;
if (s_done != 0u) {
return;
}
(void)memset(&reg, 0, sizeof(reg));
reg.name = "network";
reg.p_data = &s_cfg;
reg.p_defaults = &s_defaults;
reg.data_size = sizeof(net_cfg_t);
reg.p_keys = s_net_keys;
reg.key_count = 4u;
reg.p_cb = s_net_changed_cb;
(void)cfg_file_register(&reg);
s_done = 1u;
}
/*
* 函数功能:判断 6 字节 MAC 是否全零
* 入口参数:p_mac - MAC 指针(不可为 NULL) const uint8_t *
* 返回值:true - 全零;false - 非全零
* 限定条件:p_mac 非空
*/
static bool s_mac_is_zero(const uint8_t *p_mac) {
for (int i = 0; i < 6; i++) {
if (p_mac[i] != 0u) {
return false;
}
}
return true;
}
/*
* 函数功能:从存储加载网络配置到 RAM 副本
* 入口参数:无
* 返回值:恒 0(RAM 恒有效:文件缺失/CRC 错回退工厂默认) int
* 限定条件:由配置引擎属主任务调用(MCU = defaultTask,置位
* SYS_EVT_STORAGE_READY 前;模拟器 = 主循环启动期);文件读失败
* 自动回退工厂默认(不阻塞网络启动)
* 函数说明:见 net_cfg.h 同名函数说明
*/
int net_cfg_load(void) {
s_net_register();
/* 首启先迁旧档 NCFG(有效 → 旧值物化进新文件);新文件已存在则跳过 */
(void)net_cfg_legacy_migrate();
if (cfg_file_load() != 0) {
/* 严重错误:引擎已将 RAM 副本复位工厂默认,行为仍安全 */
DBG_ERROR("load: cfg_file_load FAIL");
return 0;
}
DBG_INFO("load: OK ip=%u.%u.%u.%u",
(unsigned)s_cfg.ip[0], (unsigned)s_cfg.ip[1],
(unsigned)s_cfg.ip[2], (unsigned)s_cfg.ip[3]);
return 0;
}
/*
* 函数功能:保存当前 RAM 配置到存储
* 入口参数:无
* 返回值:0 - 成功;-1 - 写失败 int
* 限定条件:仅配置引擎属主任务上下文调用(MCU = defaultTask;模拟器 = 主循环)
* 函数说明:经 cfg_file 引擎写盘(外科手术式保存:保留注释/未知内容,
* 临时文件 + 原子改名);跨任务场景请投递 net_cfg_save_request
*/
int net_cfg_save(void) {
int r;
s_net_register();
r = cfg_file_save();
if (r != 0) {
DBG_ERROR("save: cfg_file_save FAIL");
return -1;
}
DBG_INFO("save: OK (config file written)");
return 0;
}
/*
* 函数功能:注册"立即应用"回调
* 入口参数:cb - 回调函数(NULL = 注销) net_cfg_apply_cb_t
* 返回值:无
* 限定条件:应用启动早期注册一次即可
* 函数说明:见 net_cfg.h 同名函数说明
*/
void net_cfg_set_apply_cb(net_cfg_apply_cb_t cb) {
s_apply_cb = cb;
}
/*
* 函数功能:请求立即应用当前 RAM 配置
* 入口参数:无
* 返回值:无
* 限定条件:无(未注册回调时空操作)
* 函数说明:见 net_cfg.h 同名函数说明
*/
void net_cfg_request_apply(void) {
if (s_apply_cb != NULL) {
s_apply_cb();
}
}
/*
* 函数功能:投递"保存网络配置"请求(跨任务交接的投递端)
* 入口参数:无
* 返回值:恒 0 int
* 限定条件:任意任务上下文(UI 保存行);新值须已落 RAM 副本
* 函数说明:置"待保存"标志后经平台回调唤醒属主任务(MCU:置
* SYS_EVT_CFG_SAVE 事件);写盘与"立即应用"由属主任务执行
* (net_cfg_save_run),本函数不触碰配置文件引擎
*/
int net_cfg_save_request(void) {
s_save_pending = 1u;
if (s_save_req_cb != NULL) {
s_save_req_cb();
}
return 0;
}
/*
* 函数功能:取保存请求交接状态(UI 保存行显示)
* 入口参数:无
* 返回值:NET_CFG_SAVE_ST_IDLE / _WAIT / _OK / _FAIL int
* 限定条件:任意任务上下文(单字节读取,无撕裂)
* 函数说明:见 net_cfg.h 同名函数说明
*/
int net_cfg_save_state(void) {
if (s_save_pending != 0u) {
return (int)NET_CFG_SAVE_ST_WAIT;
}
if (s_save_result == 1u) {
return (int)NET_CFG_SAVE_ST_OK;
}
if (s_save_result == 2u) {
return (int)NET_CFG_SAVE_ST_FAIL;
}
return (int)NET_CFG_SAVE_ST_IDLE;
}
/*
* 函数功能:执行待处理的保存请求(配置文件引擎属主任务)
* 入口参数:无
* 返回值:0 - 无待处理请求或保存成功;-1 - 写盘失败 int
* 限定条件:仅配置引擎属主任务上下文(MCU = defaultTask;模拟器 = 主循环)
* 函数说明:先清"待保存"标志(写盘期间的新请求重位置位,下轮再执行,
* 不丢失);写盘成功 → 置 OK 并触发"立即应用"(netTask 重建
* 网络,无需重启);失败 → 置 FAIL,不触发应用(网络保持)
*/
int net_cfg_save_run(void) {
int r;
if (s_save_pending == 0u) {
return 0; /* 无待处理请求(空醒/周期轮询) */
}
s_save_pending = 0u;
r = net_cfg_save();
if (r == 0) {
s_save_result = 1u;
net_cfg_request_apply();
}
else {
s_save_result = 2u;
}
return r;
}
/*
* 函数功能:注册"保存请求"通知回调
* 入口参数:cb - 回调函数(NULL = 注销) net_cfg_save_req_cb_t
* 返回值:无
* 限定条件:应用启动早期注册一次即可
* 函数说明:MCU 端 defaultTask 注册(置 SYS_EVT_CFG_SAVE 事件立即唤醒);
* 模拟器不注册(主循环每轮查状态,无需唤醒)
*/
void net_cfg_set_save_req_cb(net_cfg_save_req_cb_t cb) {
s_save_req_cb = cb;
}
/*
* 函数功能:取 RAM 配置副本(只读指针)
* 入口参数:无
* 返回值:RAM 配置副本指针(恒非空) const net_cfg_t *
* 限定条件:无
*/
const net_cfg_t *net_cfg_get(void) {
return &s_cfg;
}
/*
* 函数功能:更新 RAM 配置副本(不写盘)
* 入口参数:p_cfg - 新配置指针(不可为 NULL) const net_cfg_t *
* 返回值:无
* 限定条件:p_cfg 非空
*/
void net_cfg_set(const net_cfg_t *p_cfg) {
if (p_cfg == NULL) {
return;
}
s_cfg = *p_cfg;
}
/*
* 函数功能:回写芯片实际 MAC(影子区)
* 入口参数:p_mac - 芯片读回的实际 MAC(不可为 NULL) const uint8_t *
* 返回值:无
* 限定条件:net_init 成功后由 netTask 上下文调用
*/
void net_cfg_set_active_mac(const uint8_t *p_mac) {
if (p_mac == NULL) {
return;
}
memcpy(s_active_mac, p_mac, 6u);
s_active_valid = 1u;
}
/*
* 函数功能:取显示用 MAC
* 入口参数:p_out - 6 字节输出缓冲(不可为 NULL) uint8_t *
* 返回值:无
* 限定条件:p_out 非空
* 函数说明:存储非全零 → 存储值;否则芯片实际(已回写);否则全零
*/
void net_cfg_get_mac(uint8_t *p_out) {
if (p_out == NULL) {
return;
}
if (!s_mac_is_zero(s_cfg.mac)) {
memcpy(p_out, s_cfg.mac, 6u);
}
else if (s_active_valid != 0u) {
memcpy(p_out, s_active_mac, 6u);
}
else {
memset(p_out, 0, 6u);
}
}
/*
* 函数功能:4 字节 IPv4 格式化为点分十进制字符串(每段 3 位补零)
* 入口参数:p_ip - 4 字节 IP(不可为 NULL) const uint8_t *
* p_buf - 输出缓冲(不可为 NULL) char *
* len - 缓冲长度 size_t
* 返回值:无
* 限定条件:p_ip/p_buf 非空;len ≥ 16
* 函数说明:"192.168.001.100"(定长 11 字符,UI 编辑光标按固定偏移定位字节)
*/
void net_cfg_fmt_ipv4(const uint8_t *p_ip, char *p_buf, size_t len) {
if (p_ip == NULL || p_buf == NULL || len == 0u) {
return;
}
(void)snprintf(p_buf, len, "%03u.%03u.%03u.%03u",
(unsigned)p_ip[0], (unsigned)p_ip[1],
(unsigned)p_ip[2], (unsigned)p_ip[3]);
}