/* * 模块名称: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 #define DBG_TAG "[CFG]" #include "dbg_log.h" #include "cfg_file_store.h" #include "prot_set.h" #define PROT_SET_STORE_PATH "/prot_set.bin" /* blob 收发缓冲(静态:defaultTask 栈深已是全项目最深链,勿再压局部 blob; * B8 定值表 32→40 项 → blob 144→176 B,随 PROT_SET_BLOB_SZ 自动适配) */ static uint8_t s_blob[PROT_SET_BLOB_SZ]; /* * 函数功能:从小端缓冲读 16 位值(仅头部判别用,与 prot_set.c 内部同字节序) * 入口参数:p - 读位置 * 返 回 值:值 uint16_t */ static uint16_t s_ld16(const uint8_t *p) { return (uint16_t)((uint32_t)p[0] | ((uint32_t)p[1] << 8)); } /* * 函数功能:从小端缓冲读 32 位值 * 入口参数:p - 读位置 * 返 回 值:值 uint32_t */ static uint32_t s_ld32(const uint8_t *p) { return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24); } /* * 函数功能:开机装载定值 blob * 入口参数:无 * 返 回 值:0 已装载 / 1 文件缺失或读失败(保持默认)/ * 2 版本或项数换代(旧档被拒,保持默认;本函数已落 INFO 日志)/ * -1 损坏被拒 * 函数说明:读失败与"文件不存在"同归 1——启动期卷锁无竞争(本任务独占 * bring-up),try-lock 失败即真 I/O 故障,此时保持出厂默认并让 * 调用方按"无档"处理是安全侧(定值仍封存自洽,定值校验和不误锁)。 * **换代与损坏分开**(B8):magic 完好但 ver/cnt 与当前固件不符 = * 定值表升级(如 B8 32→40 项),是**预期升级路径**不是损坏 → * 归 2 并打 INFO("version change"措辞),调用方不得按 CORRUPT * 报 ERROR/自检留痕;magic 或校验对被破坏才是 -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 0; } /* 拒绝原因分流:头部 magic 完好 + 版本/项数与当前固件不符 = 换代 */ if ((nread >= (size_t)PROT_SET_BLOB_HDR_SZ) && (s_ld32(s_blob) == (uint32_t)PROT_SET_BLOB_MAGIC) && ((s_ld16(s_blob + 4u) != (uint16_t)PROT_SET_BLOB_VER) || (s_ld16(s_blob + 6u) != (uint16_t)PS_ID_COUNT))) { DBG_INFO("prot set blob version change (ver=%u cnt=%u), defaults in use", (unsigned)s_ld16(s_blob + 4u), (unsigned)s_ld16(s_blob + 6u)); return 2; } return -1; } /* * 函数功能:落盘当前定值(消费脏标志;失败回置等重试) * 入口参数:无 * 返 回 值: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; }