flash_data_store.h
源文件路径:
data/resume_data/flash/flash_data_store.h所属模块:data(数据管理) / resume_data / flash —— 运行数据断电续传存储 代码行数:366
1. 文件职责
本头文件为 EMS 运行数据「周期性落盘 + 断点续传导出」子系统的对外契约,配合 flash_data_store.c 使用。它定义了 SPI Flash 中运行数据的存储分区地址(三份写指针备份扇区 + 主数据区 + 扩展数据区)、一条运行记录的完整二进制布局(ParaTab / ParaTab2)、断点续传任务描述结构(RESUME_BUFFER_T)以及存储写指针结构(FlashDataAddr)。同时把 CSV 表头需要的字段顺序抽象成一个 PARAMETER_INDEX_TABLE 枚举,供 GET_VARIABLE_NAME() 宏把字段名转成字符串。对外只暴露 8 个函数声明和 3 个全局变量(SDRAM 导出缓冲、10 条断点指令槽、导出报文长度)。数据流的环节是:各业务模块采集 → 本子系统每 60 s 打包一条 ParaTab 写入 Flash → 云端下发断点指令后从 Flash 二分查找并转成 CSV 经 resume_buff_sdram 上报。
2. 关键数据结构与宏
| 名称 | 类型 | 说明 | |
|---|---|---|---|
DEBUG_FLASH_DATA_STORE | 宏 | 调试开关,(0) 关闭。打开后会在各函数中 printf 大量地址/时间/CRC 信息(本文件 .c 中约 40 处 #if 分支) | |
RESUME_DATA_HEAD1 / RESUME_DATA_HEAD2 | 宏 | 记录起始码的两个字节,0x55 / 0xAA。写入时按 `head1<<8 \ | head2 组成 u16_head=0x55AA,小端存储后字节序为 AA 55,因此搜索时判断 buf[i]==0xAA && buf[i+1]==0x55`(flash_data_store.c:145、1473、1728) |
RESUME_END_CODE | 宏 | 0xB400,数据版本尾码,写入 ParaTab.u16_endcode(偏移 396~397,小端字节为 00 B4)。厂商/版本升级后若读到不匹配即认为历史数据作废,触发擦除 | |
GET_VARIABLE_NAME(variable) | 宏 | #variable 字符串化,用于把 PARAMETER_INDEX_TABLE 的字段名批量生成 CSV 表头(flash_data_store.c:414-464) | |
RUN_DATA_CUR_ADDR_BACKUP1/2/3 | 宏 | 0x206000 / 0x207000 / 0x208000,三个 4 KB 扇区,用于"追加式"保存写指针 FlashDataAddr(每 60 s 追加 4 字节) | |
FLASH_DTATA_ADDR_RECORD_END1/2/3 | 宏 | 上述三个备份扇区的结束地址(0x206FFF / 0x207FFF / 0x208FFF) | |
FLASH_DTATA_RUN_START / FLASH_DTATA_RUN_END | 宏 | 主运行数据环形区,0x209000~0xF62FFF(约 13.35 MB,可存 34990 条约 400 B 记录) | |
FLASH_DTATA2_RUN_START / _END / _OFFSET | 宏 | 32 MB/64 MB Flash 才存在的扩展区,0x12A6000~0x1FFFFFF;_OFFSET=0x109D000 恰为 START2-START,因此第二表用"逻辑地址 + 固定偏移"映射写入(flash_data_store.c:1142、1825) | |
MAX_SEARCH_CYCLE | 宏 | (30),二分查找最大迭代次数,防止死循环 | |
PARAMETER_INDEX_TABLE | 枚举 | 运行数据的逻辑字段顺序表(电网/逆变器/电池/系统状态/能量统计/调度共 6 组)。注意:本枚举在 .c 中并未被真正使用,仅作为字段顺序的自我说明;且与当前 CSV 列顺序已不一致(见第 7 节) | |
FlashDataAddr | 结构体(pack(1)) | 只有一个成员 u32 RunDataStoreCurAddr,即下一个待写入的运行数据地址 | |
RESUME_BUFFER_T | 结构体(pack(1)) | 一条云端断点续传指令:u8_year/month/day/hour/minute/second + u32_length(分钟数)+ u8_finished(本机发送完成标志) | |
ParaTab | 结构体(pack(1),400 B) | 一条完整的运行数据记录:u16_head + time_t Time + 电网 6 项 + 逆变器 34 项 + 电池 56 项(含 18 路电流、18 路 SOC)+ 系统状态 6 项 + 能量统计 20 项 + 调度 4 项 + 2 项动力线温度 + u8_reserve[71] + u16_endcode + u16_crc_code。CRC 覆盖前 398 字节 | |
ParaTab2 | 结构体(pack(1),398 B) | 扩展记录:u16_head + time_t Time + u32_bb_error_code(备电箱故障码)+ u8_reserve[386] + u16_crc_code。与 ParaTab 同地址指针并行写入扩展区 | |
g_u32_resume_data_len | 全局变量 | 上报报文当前长度(含 7 字节协议头,加 CRC 前不含 CRC) | |
g_resume_info[10] | 全局变量 | 断点续传指令队列,由 net/server.c 填充(server.c:2766-2772),本模块消费 | |
resume_buff_sdram[SDRAM_5M] | 全局变量 | 5 MB SDRAM 导出缓冲,通过 __attribute__((at(SDRAM_RESUME_START_ADDR))) 绝对定位在 SDRAM 中,实际每个报文只用前 ~5 KB |
3. 函数清单
本文件为纯声明头文件,不含任何函数定义,仅声明以下 8 个函数(flash_data_store.h:356-364):
| 函数名 | 作用域 | 说明 |
|---|---|---|
store_data_init | 全局(导出) | 初始化写指针与 CSV 表头,由 task_system_data 启动时调用 |
show_search_data | 全局(导出) | 把当前二分查找到的 ParaTab 全部字段 printf 出来(调试用) |
Get_Resume_Status_Current | 全局(导出) | 读取断点续传状态机当前状态(实际转发 g_stEMSInfo.u8ResumeStatusCurr) |
Set_Resume_Status_Current | 全局(导出) | 设置断点续传状态机状态 |
resume_data_handle | 全局(导出) | 本模块主入口,被 task_system_data 每周期调用 |
get_resume_cmd_id_code | 全局(导出) | 返回断点续传指令 ID 缓冲指针 |
set_resume_cmd_id_code | 全局(导出) | 写入断点续传指令 ID(长度上限 16) |
erase_run_data | 全局(导出) | 擦除整片运行数据区并重置写指针 |
.c 文件中还有若干未在本头文件声明的外部可见符号:packet_head、packet_end、ParaTabToArray(见 .c 文档第 5 节)。
4. 核心逻辑解析
本文件是纯声明文件,无算法。以下说明布局层面的关键设计:
4.1 三层冗余的写指针存储
写指针 FlashDataAddr.RunDataStoreCurAddr 共 4 字节,被追加写到三个独立扇区 RUN_DATA_CUR_ADDR_BACKUP1/2/3。每个扇区 4096 B / 4 B = 1024 个槽位,按"首个 4 字节全 FF 处即为空闲槽"的规则定位。上电时 store_data_addr_init() 读三个扇区末槽并做三取二表决,任意两个一致才采信,否则回退到 FLASH_DTATA_RUN_START,并再做一次 [FLASH_DTATA_RUN_START, FLASH_DTATA_RUN_END] 区间合法性判断。写侧 store_data_addr() 要求 ≥2 个扇区写成功 才返回成功。
4.2 记录定长 + 起始码 + 双 CRC 的自描述布局
ParaTab 定长 400 B、ParaTab2 定长 398 B(pack(1) 无填充)。定长是二分查找能按 sizeof(ParaTab) 步进的前提。每条记录以 AA 55 开头,ParaTab 尾部有版本尾码 00 B4 + CRC16/Modbus;ParaTab2 只有 CRC。写入侧对"跨 FLASH_DTATA_RUN_END"做了拆包续写:先写本扇区剩余 secremain 字节到尾部,再把余下部分写到 FLASH_DTATA_RUN_START,形成环形。
4.3 广播式 CSV 上报协议头
Pack_resume_data_buf_head_end() 生成的报文格式为:
| 偏移 | 内容 |
|---|---|
| 0 | EMS = 0x01(设备类型,net/ems.h:75) |
| 1 | REQUEST_COMM = 0x01(请求帧,net/ems.h:88) |
| 2 | CMD_RESUME_INTERFACE = 0x0C(命令字,net/ems.h:104) |
| 3~6 | 数据域长度,大端 32 位,值为 g_u32_resume_data_len - 7(不含头、不含 CRC) |
| 7 ~ 7+L-1 | CSV 文本(表头行 + 若干数据行) |
| 7+L ~ 8+L | CRC16/Modbus 校验值,高字节在前 |
5. 对外接口
本文件导出(被外部引用):
- 函数:
store_data_init、show_search_data、Get_Resume_Status_Current、Set_Resume_Status_Current、resume_data_handle、get_resume_cmd_id_code、set_resume_cmd_id_code、erase_run_data(均在 flash_data_store.h:356-364 声明) - 全局变量:
g_u32_resume_data_len、g_resume_info[10]、resume_buff_sdram[SDRAM_5M](flash_data_store.h:351-353)
本文件引用的外部头文件: chip.h(类型定义)、pcf8563.h(struct RTC_DateTime、time_t 相关)、flash.h(FlashDataAddr 相关地址宏的语义来源)、sdram.h(SDRAM_5M、SDRAM_RESUME_START_ADDR)、<time.h>。
6. 依赖关系
- 依赖:
chip.h、pcf8563.h、flash.h、sdram.h、time.h - 被依赖:
data/resume_data/flash/flash_data_store.c(实现方,唯一 include 点)net/ems.c(使用resume_buff_sdram、g_u32_resume_data_len、Get/Set_Resume_Status_Current,ems.c:4860-5010、5557-5569)net/server.c(使用g_resume_info、set_resume_cmd_id_code、Get/Set_Resume_Status_Current,server.c:2719-2772、6722-6740)midware/ethernt/wireless/wireless_driver.c(用Get_Resume_Status_Current()判定是否处于断点续传阶段,wireless_driver.c:243、497、621)
7. 备注与风险点
PARAMETER_INDEX_TABLE枚举已失效:全工程搜索该枚举名,除定义外无任何引用;且其字段顺序与当前 CSV 实际列顺序已不一致——枚举中是BatV, SOC, Pbat, BatC,而 CSV 输出的是BatV, Pbat, BatC, SOC(flash_data_store.c:2106-2115)。它现在只是"历史注释",容易被误当成权威列序。- 枚举缺少
ErrBackupBox:ErrBackupBox对应ParaTab2.u32_bb_error_code,只在 CSV 表头第二部分条件追加(flash_data_store.c:480),枚举里没有它。 resume_buff_sdram声明尺寸与实际用法严重不匹配:声明为 5 MB(SDRAM_5M),但打包逻辑用5*1024作为上限(flash_data_store.c:2464),每个报文最多约 5 KB。5 MB 的预留空间绝大部分未被使用,且memset(resume_buff_sdram, 0, sizeof(resume_buff_sdram))会清零整 5 MB(flash_data_store.c:2445),在 MCU 上是明显的无谓开销。- 头文件对
resume_buff_sdram的extern声明携带__attribute__((at(...))):该属性用于定义符号的绝对定位;在extern声明上重复出现虽被编译器容忍,但一旦两处地址宏不一致就会产生难以定位的链接/运行问题(当前.c与.h使用同一宏,暂未出错)。 GET_VARIABLE_NAME只做字符串化不做任何校验:CSV 表头列名与实际写入字段完全靠人工对齐,u32_energy_gc_charge(EGCbat)就是被漏掉的一列——它在 flash_data_store.c:1034 被写入 Flash,却既不在表头也不在 CSV 数据输出中,属于"只存不报"。- 地址宏强绑定 16 MB/32 MB Flash:
FLASH_DTATA_RUN_END=0xF62FFF、FLASH_DTATA2_RUN_START=0x12A6000对 8 MB/16 MB 器件是越界值;实际使用受Flash_ReadDensity() > 16(单位 MB)条件保护,逻辑上安全,但宏本身不可独立复用。 - 头文件注释
// 13672KB与地址区间实际长度不符:0xF62FFF-0x209000+1 = 13,996,032 B ≈ 13.35 MB,注释里写的 13672 KB(≈13.35 MB)数值对得上但单位写成 KB 易误读。