HCoreBase/include/HFlashServer.h
2026-04-30 10:54:37 +08:00

456 lines
15 KiB
C

/**
* 日期: 2025-11-27
* 作者: coffee
* 描述: Flash通用服务模块, 用于保证Flash操作的完备性, 支持任意长度数据读写, 因内部使用延后处理, 需要重启时必须调用同步
*/
#ifndef __H_FLASH_SERVER_H__
#define __H_FLASH_SERVER_H__
// #define USE_STD_MEM
#include <stdint.h>
// 使用位图模块映射保护区
#ifndef HFLASH_USE_BITMAP
#define HFLASH_USE_BITMAP 1
#endif
#if HFLASH_USE_BITMAP
#include "HBitMap.h"
#endif
// 使用HShell
#ifndef HFLASH_USE_HSHELL
#define HFLASH_USE_HSHELL 1
#endif
///< 使用Flash内存映射功能
#ifndef HFLASH_NOT_USE_FLASH_MEM
#define HFLASH_USE_FLASH_MEM
#endif
#ifndef USE_STD_MEM
#ifndef HFLASH_USE_FLASH_MEM
#include "HSendBuffer.h"
#endif // HFLASH_USE_FLASH_MEM
#endif
///< Flash块大小, 按块操作, 2的幂关系
#ifndef HFLASH_BLOCK_SIZE
#define HFLASH_BLOCK_SIZE (4096)
#endif
///< 获取缓存内存, 需要能申请到大于等于(Flash一块大小)
#ifndef HFLASH_USE_FLASH_MEM
#ifndef HFLASH_MALLOC
#ifdef USE_STD_MEM
#define HFLASH_MALLOC(size) malloc(size)
#else
#define HFLASH_MALLOC(size) HSendBufferGet(size)
#endif // USE_STD_MEM
#endif // HFLASH_MALLOC
///< 释放缓存
#ifndef HFLASH_FREE
#ifdef USE_STD_MEM
#define HFLASH_FREE(ptr) free(ptr)
#else
#define HFLASH_FREE(ptr) HSendBufferFree(ptr)
#endif // USE_STD_MEM
#endif // HFLASH_FREE
#endif // HFLASH_USE_FLASH_MEM
///< 定时器ID
#ifndef HFLASH_TIMER_ID
#define HFLASH_TIMER_ID 0
#endif
///< 同步缓存页时间ms
#ifndef HFLASH_SYNC_CACHE_PAGE_TIME
#define HFLASH_SYNC_CACHE_PAGE_TIME 600
#endif
///< 同步页表信息时间ms
#ifndef HFLASH_SYNC_PAGE_INFO_TIME
#define HFLASH_SYNC_PAGE_INFO_TIME 800
#endif
///< 同步备份和备份页表信息时间ms
#ifndef HFLASH_SYNC_BACKUP_TIME
#define HFLASH_SYNC_BACKUP_TIME 1000
#endif
///< Flash地址类型
typedef uint32_t HFlashAddr_t;
///< Flash页表信息
typedef union HFlashPageInfo {
uint8_t reverse[32]; ///< 每页的信息占用32字节
struct __attribute__((packed)) {
HFlashAddr_t addr; ///< 地址
uint32_t crc32; ///< 使用大小内容的CRC32
uint32_t size : 24; ///< 大小
uint32_t useSize : 24; ///< 使用大小
uint16_t version; ///< 当前页数据的版本
uint32_t modifyCount; ///< 修改次数
uint8_t invalid : 1; ///< 无效标志
};
} HFlashPageInfo;
#if HFLASH_USE_BITMAP
///< 计算保护区备份跨度大小, 传入原始保护区 addr/size 即可
#define HFLASH_CALC_PROTECT_SPAN_SIZE(addr, size) \
((uint32_t)((((((uint64_t)(addr)) & ((uint64_t)HFLASH_BLOCK_SIZE - 1u)) + (uint64_t)(size)) + \
(uint64_t)HFLASH_BLOCK_SIZE - 1u) & ~((uint64_t)HFLASH_BLOCK_SIZE - 1u)))
///< 计算保护区位图大小数组, size 需要传保护区备份跨度大小
#define HFLASH_CALC_BITMAP_SIZE(size) \
(HBITMAP_CALC_LEN(((uint32_t)(size) + HFLASH_BLOCK_SIZE - 1u) / HFLASH_BLOCK_SIZE))
///< 直接通过保护区 addr/size 计算位图数组大小
#define HFLASH_CALC_PROTECT_BITMAP_SIZE(addr, size) \
HFLASH_CALC_BITMAP_SIZE(HFLASH_CALC_PROTECT_SPAN_SIZE((addr), (size)))
///< 便于静态定义保护区位图数组
#define HFLASH_PROTECT_BITMAP_DEFINE(name, addr, size) \
HBitMapType name[HFLASH_CALC_PROTECT_BITMAP_SIZE((addr), (size))]
#else
#define HFLASH_CALC_BITMAP_SIZE(size) 0
#define HFLASH_CALC_PROTECT_BITMAP_SIZE(addr, size) 0
#endif
typedef struct HFlashProtectInfo {
HFlashAddr_t addr; ///< 保护区地址
uint32_t size; ///< 保护区大小
HFlashAddr_t backupAddr; ///< 保护区备份地址
#if HFLASH_USE_BITMAP
HBitMapType *bitMap; ///< 保护区需保存的位图, 4k基准
#endif
} HFlashProtectInfo;
typedef struct HFlashCacheInfo {
HFlashPageInfo info; ///< 页表信息
uint32_t pos : 19; ///< 存储页表信息的位置
uint32_t heat : 4; ///< 热度优先级
uint32_t waitWrite : 1; ///< 延后写入, 一般适用于流式操作或者延后复写
uint32_t waitCrc : 1; ///< 延后CRC
} HFlashCacheInfo;
typedef union HFlashVersionInfo {
uint8_t reverse[32]; ///< 每页的信息占用32字节
struct __attribute__((packed)) {
uint32_t flagId; ///< 标识ID, 在无注册地址时, 会直接读取Flash信息
uint16_t version; ///< 当前Flash系统版本
};
} HFlashVersionInfo;
/**
* @brief HFlashEraseCallback 擦除回调
* @param addr Flash地址
* @return 1: 擦除成功 0: 擦除失败
*/
typedef uint8_t (*HFlashEraseCallback)(HFlashAddr_t addr);
/**
* @brief HFlashReadCallback 读取回调
* @param addr Flash地址
* @param data Flash读取写入的缓存数据内存
* @param size 缓存大小
* @return 1: 读取成功 0: 读取失败
*/
typedef uint8_t (*HFlashReadCallback)(HFlashAddr_t addr, void *data, uint32_t size);
/**
* @brief HFlashWriteCallback 写入回调
* @param addr Flash地址
* @param data Flash读取写入的缓存数据内存
* @param size 缓存大小
* @return 1: 写入成功 0: 写入失败
*/
typedef uint8_t (*HFlashWriteCallback)(HFlashAddr_t addr, const void *data, uint32_t size);
/**
* @brief HFlashInitCallback 设置Flash初始化回调
* @param read 读取回调
* @param write 写入回调
* @param erase 擦除回调
*/
void HFlashInitCallback(HFlashReadCallback read, HFlashWriteCallback write, HFlashEraseCallback erase);
/**
* @brief HFlashGetVersion 获取Flash版本号
* @param addr 版本信息的页表地址(可无注册时直接读取, 页表存在就按照页表大小读取, 页表不存在就直接读取Flash)
* @param info 版本信息
* @return 页表版本号, 无效也返回0
*/
uint16_t HFlashGetVersion(HFlashAddr_t addr, HFlashVersionInfo *info);
/**
* @brief HFlashSetPageCache 设置页表缓存, 内部不构建内存, 由外部分配
* @param pageInfo 页表信息缓存
* @param size 大小
*/
void HFlashSetPageCache(HFlashCacheInfo *pageInfo, uint16_t size);
/**
* @brief HFlashInitProtectCache 初始化保护区缓存, 内部不构建内存, 由外部分配
* 需要在设置保护地址前调用, 会将内存清零
* @param protectInfo 保护区描述缓存
* @param bitMap 位图
* @param size 保护区备份跨度大小, 推荐使用 HFLASH_CALC_PROTECT_SPAN_SIZE(addr, size) 计算
*/
void HFlashInitProtectCache(HFlashProtectInfo *protectInfo, void *bitMap, uint32_t size);
/**
* @brief HFlashSetProtectCache 设置保护区描述缓存, 内部不构建内存, 由外部分配
* 需要在设置保护地址前调用
* @param protectInfo 保护区描述缓存
* @param size 大小
*/
void HFlashSetProtectCache(HFlashProtectInfo *protectInfo, uint16_t size);
/**
* @brief HFlashSetPageAddr 设置页表地址
* @param addr 地址
* @param size 大小
*/
void HFlashSetPageAddr(HFlashAddr_t addr, uint32_t size);
/**
* @brief HFlashSetPageBackupAddr 设置页表备份地址, 需要先设置页表再设置备份
* 页表备份地址独立存储, 大小必须和页表地址大小相同
* @param addr 地址
* @param size 大小, 需要4K对齐
*/
void HFlashSetPageBackupAddr(HFlashAddr_t addr, uint32_t size);
/**
* @brief HFlashClearProtectAddr 清空保护地址配置和对应备份映射
*/
void HFlashClearProtectAddr();
/**
* @brief HFlashAddProtectAddr 添加保护地址, 可多次调用追加多个保护区域
* 保护区描述内存由 HFlashSetProtectCache 外部提供
* @param addr 地址
* @param size 大小
* @param backupAddr 备份地址, 会按保护区大小自动建立一条连续备份映射
*/
void HFlashAddProtectAddr(HFlashAddr_t addr, uint32_t size, HFlashAddr_t backupAddr);
/**
* @brief HFlashDelProtectAddr 删除保护地址和对应备份映射
* @param addr 地址
*/
void HFlashDelProtectAddr(HFlashAddr_t addr);
/**
* @brief HFlashInitCheck 在HFlashRegister前需要初始化检查, 用于检查页表是否可用, 不可用则需要初始化
*/
void HFlashInitCheck();
/**
* @brief HFlashRegister 注册地址到页表, 如果大小和之前不一致会丢弃原数据更新
* 但保护区域是特殊的, 请勿缩小保护区域的使用大小
* @param addr 地址
* @param size 该地址占用的大小
*/
void HFlashRegister(HFlashAddr_t addr, uint32_t size);
/**
* @brief HFlashWrite 写入Flash数据
* @param addr 需要注册的地址
* @param data 写入数据
* @param size 写入数据大小
* @return 1: 写入成功 0: 写入失败
*/
uint8_t HFlashWrite(HFlashAddr_t addr, const void *data, uint32_t size);
/**
* @brief HFlashWriteOffset 写入从原始地址偏移后的地方写入数据, 如果偏移后的写入大小超过原未使用, 超出部分会自动写入0填充
* @param addr 需要注册的地址
* @param offset 地址偏移
* @param data 写入数据
* @param size 写入数据大小
* @return 1: 写入成功 0: 写入失败
*/
uint8_t HFlashWriteOffset(HFlashAddr_t addr, uint32_t offset, const void *data, uint32_t size);
/**
* @brief HFlashWriteOffsetValue 写入从原始地址偏移后的地方写入相同值, 超出原未使用部分会自动写入0填充
* @param addr 需要注册的地址
* @param offset 地址偏移
* @param value 写入值
* @param size 写入数据大小
* @return 1: 写入成功 0: 写入失败
*/
uint8_t HFlashWriteOffsetValue(HFlashAddr_t addr, uint32_t offset, uint8_t value, uint32_t size);
/**
* @brief HFlashWriteRawOffset 写入原始地址偏移后的位置写入Flash数据, 超出部分不自动填充, 仅提供给一些库使用, 正常情况请勿使用
* @param addr 需要注册的地址
* @param offset 地址偏移
* @param data 写入数据
* @param size 写入数据大小
* @return 1: 写入成功 0: 写入失败
*/
uint8_t HFlashWriteRawOffset(HFlashAddr_t addr, uint32_t offset, const void *data, uint32_t size);
/**
* @brief HFlashStreamBegin 开始流式写入, 重置使用长度
* @param addr 需要注册的地址
*/
void HFlashStreamBegin(HFlashAddr_t addr);
/**
* @brief HFlashStreamWrite 不断添加数据, 不立刻计算CRC, 调度长度和写入Flash数据即可
* @param addr 需要注册的地址
* @param data 写入数据
* @param size 写入数据大小
* @return 1: 写入成功 0: 写入失败
*/
uint8_t HFlashStreamWrite(HFlashAddr_t addr, const void *data, uint32_t size);
/**
* @brief HFlashStreamEnd 结束流式写入, 计算CRC
* @param addr 需要注册的地址
*/
void HFlashStreamEnd(HFlashAddr_t addr);
/**
* @brief HFlashRawWrite 原始写入Flash数据, 不校验任何东西, 正常情况下不建议使用
* @param addr 地址
* @param data 写入数据
* @param size 写入数据大小
* @return 1: 写入成功 0: 写入失败
*/
uint8_t HFlashRawWrite(HFlashAddr_t addr, const void *data, uint32_t size);
/**
* @brief HFlashRead 读取Flash数据
* @param addr 需要注册的地址
* @param data 读取数据写入的缓存内存
* @param size 读取数据大小
* @return 1: 读取成功 0: 读取失败
*/
uint8_t HFlashRead(HFlashAddr_t addr, void *data, uint32_t size);
/**
* @brief HFlashReadOffset 读取从原始地址偏移后的地方的数据
* @param addr 需要注册的地址
* @param offset 地址偏移
* @param data 读取数据写入的缓存内存
* @param size 读取数据大小
* @return 1: 读取成功 0: 读取失败
*/
uint8_t HFlashReadOffset(HFlashAddr_t addr, uint32_t offset, void *data, uint32_t size);
/**
* @brief HFlashRawRead 原始读取Flash数据, 不校验任何东西, 正常情况下不建议使用
* @param addr 地址
* @param data 读取数据写入的缓存内存
* @param size 读取数据大小
* @return 1: 读取成功 0: 读取失败
*/
uint8_t HFlashRawRead(HFlashAddr_t addr, void *data, uint32_t size);
/**
* @brief HFlashUpdateVersionCallback 更新版本号回调
* @param addr 需要注册的地址
* @param oldVersion 旧版本号
* @param newVersion 新版本号
* @param userData 用户数据
*/
typedef void (*HFlashUpdateVersionCallback)(HFlashAddr_t addr, uint16_t oldVersion, uint16_t newVersion, void *userData);
/**
* @brief HFlashUpdateVersion 更新版本号, 版本号不同时会触发回调
* 如果旧版本比新版本大, 需要考虑使用当前版本的数据来兼容
* 如果旧版本比新版本小, 需要考虑使用将数据升级到新版本去
* @param addr 需要注册的地址
* @param newVersion 新版本号
* @param callback 回调函数
* @param userData 用户数据
*/
void HFlashUpdateVersion(HFlashAddr_t addr, uint16_t newVersion, HFlashUpdateVersionCallback callback, void *userData);
/**
* @brief HFlashUpgradeVersion 升级版本号, 仅在版本升高时触发回调
* 如果旧版本比新版本大或相同, 不处理
* 如果旧版本比新版本小, 会更新记录版本并触发回调, 可用于把数据升级到新版本
* @param addr 需要注册的地址
* @param newVersion 新版本号
* @param callback 回调函数
* @param userData 用户数据
*/
void HFlashUpgradeVersion(HFlashAddr_t addr, uint16_t newVersion, HFlashUpdateVersionCallback callback, void *userData);
/**
* @brief HFlashDefaultUpdateVersion 默认更新版本号回调, 直接删除旧数据
* @param addr 需要注册的地址
* @param oldVersion 旧版本号
* @param newVersion 新版本号
* @param userData 用户数据
*/
void HFlashDefaultUpdateVersion(HFlashAddr_t addr, uint16_t oldVersion, uint16_t newVersion, void *userData);
/**
* @brief HFlashDeleteFile 删除地址内容
* @param addr 需要注册的地址
*/
void HFlashDeleteData(HFlashAddr_t addr);
/**
* @brief HFlashGetUseSize 获取Flash数据的使用大小
* @param addr 需要注册的地址
* @return 使用大小
*/
uint32_t HFlashGetUseSize(HFlashAddr_t addr);
/**
* @brief HFlashSetUseSize 设置Flash数据的使用大小
* @param addr 需要注册的地址
* @param size 使用大小
* @param delayCrc32 是否延迟计算CRC 1: 是 0: 否
* @return 1: 设置成功 0: 设置失败
*/
uint8_t HFlashSetUseSize(HFlashAddr_t addr, uint32_t size, uint8_t delayCrc32);
/**
* @brief HFlashGetSize 获取Flash数据的大小
* @param addr 需要注册的地址
* @return 大小
*/
uint32_t HFlashGetSize(HFlashAddr_t addr);
/**
* @brief HFlashGetCrc32 获取页表记录的CRC32值
* @param addr 需要注册的地址
* @return CRC32
*/
uint32_t HFlashGetCrc32(HFlashAddr_t addr);
/**
* @brief HFlashCalcCrc32 计算Flash数据的CRC32值
* @param addr 需要注册的地址
* @return CRC32
*/
uint32_t HFlashCalcCrc32(HFlashAddr_t addr);
/**
* @brief HFlashSync 执行同步写入Flash数据, 在重启前需要执行
*/
void HFlashSync();
/**
* @brief HFlashFreeCache 释放缓存
*/
void HFlashFreeCache();
/**
* @brief HFlashResetPage 重置页表
*/
void HFlashResetPage();
#endif // __H_FLASH_SERVER_H__