EMS 知识库
首页 / knowledge/代码解析/data/resume_data/flash

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() 生成的报文格式为:

偏移内容
0EMS = 0x01(设备类型,net/ems.h:75)
1REQUEST_COMM = 0x01(请求帧,net/ems.h:88)
2CMD_RESUME_INTERFACE = 0x0C(命令字,net/ems.h:104)
3~6数据域长度,大端 32 位,值为 g_u32_resume_data_len - 7(不含头、不含 CRC)
7 ~ 7+L-1CSV 文本(表头行 + 若干数据行)
7+L ~ 8+LCRC16/Modbus 校验值,高字节在前

5. 对外接口

本文件导出(被外部引用):

本文件引用的外部头文件: chip.h(类型定义)、pcf8563.h(struct RTC_DateTime、time_t 相关)、flash.h(FlashDataAddr 相关地址宏的语义来源)、sdram.h(SDRAM_5M、SDRAM_RESUME_START_ADDR)、<time.h>。

6. 依赖关系

7. 备注与风险点

  1. PARAMETER_INDEX_TABLE 枚举已失效:全工程搜索该枚举名,除定义外无任何引用;且其字段顺序与当前 CSV 实际列顺序已不一致——枚举中是 BatV, SOC, Pbat, BatC,而 CSV 输出的是 BatV, Pbat, BatC, SOC(flash_data_store.c:2106-2115)。它现在只是"历史注释",容易被误当成权威列序。
  2. 枚举缺少 ErrBackupBox:ErrBackupBox 对应 ParaTab2.u32_bb_error_code,只在 CSV 表头第二部分条件追加(flash_data_store.c:480),枚举里没有它。
  3. 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 上是明显的无谓开销。
  4. 头文件对 resume_buff_sdram 的 extern 声明携带 __attribute__((at(...))):该属性用于定义符号的绝对定位;在 extern 声明上重复出现虽被编译器容忍,但一旦两处地址宏不一致就会产生难以定位的链接/运行问题(当前 .c 与 .h 使用同一宏,暂未出错)。
  5. GET_VARIABLE_NAME 只做字符串化不做任何校验:CSV 表头列名与实际写入字段完全靠人工对齐,u32_energy_gc_charge(EGCbat)就是被漏掉的一列——它在 flash_data_store.c:1034 被写入 Flash,却既不在表头也不在 CSV 数据输出中,属于"只存不报"。
  6. 地址宏强绑定 16 MB/32 MB Flash:FLASH_DTATA_RUN_END=0xF62FFF、FLASH_DTATA2_RUN_START=0x12A6000 对 8 MB/16 MB 器件是越界值;实际使用受 Flash_ReadDensity() > 16(单位 MB)条件保护,逻辑上安全,但宏本身不可独立复用。
  7. 头文件注释 // 13672KB 与地址区间实际长度不符:0xF62FFF-0x209000+1 = 13,996,032 B ≈ 13.35 MB,注释里写的 13672 KB(≈13.35 MB)数值对得上但单位写成 KB 易误读。