From e1d52c26de11e8f796e3cb0760cc653015baccbf Mon Sep 17 00:00:00 2001 From: coffee Date: Tue, 2 Dec 2025 01:09:13 +0800 Subject: [PATCH] =?UTF-8?q?1.=20=E5=A2=9E=E5=8A=A0=E5=AE=8C=E5=A4=87Flash?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/HFlashServer.h | 79 ++++++++++++---- src/HFlashServer.c | 208 +++++++++++++++++++++++++++++++---------- 2 files changed, 219 insertions(+), 68 deletions(-) diff --git a/include/HFlashServer.h b/include/HFlashServer.h index 105149f..d13fb0a 100644 --- a/include/HFlashServer.h +++ b/include/HFlashServer.h @@ -1,20 +1,21 @@ /** * 日期: 2025-11-27 * 作者: coffee - * 描述: Flash通用服务模块, 用于保证性Flash操作 + * 描述: Flash通用服务模块, 用于保证Flash操作的完备性, 支持任意长度数据读写 */ #ifndef __H_FLASH_SERVER_H__ #define __H_FLASH_SERVER_H__ +#include ///< Flash块大小, 按块操作, 2的幂关系 #ifndef HFLASH_BLOCK_SIZE #define HFLASH_BLOCK_SIZE (4096) #endif -///< 获取缓存内存, 需要大于Flash一块大小 +///< 获取缓存内存, 需要能申请到大于等于Flash一块大小 #ifndef HFLASH_MALLOC #define HFLASH_MALLOC(size) malloc(size) #endif @@ -34,9 +35,6 @@ #define HFLASH_SYNC_TIME 2000 #endif -#include -#include - ///< Flash地址类型 typedef uint32_t HFlashAddr_t; @@ -54,9 +52,10 @@ typedef union HFlashPageInfo { } HFlashPageInfo; typedef struct HFlashCacheInfo { - HFlashPageInfo info; ///< 页表信息 - uint32_t pos : 19; ///< 存储页表信息的位置 - uint32_t heat : 4; ///< 热度优先级 + HFlashPageInfo info; ///< 页表信息 + uint32_t pos : 19; ///< 存储页表信息的位置 + uint32_t heat : 4; ///< 热度优先级 + uint32_t waitWrite : 1; ///< 延后写入, 一般适用于流式操作或者延后复写 } HFlashCacheInfo; @@ -115,18 +114,18 @@ void HFlashSetPageAddr(HFlashAddr_t addr, uint32_t size); void HFlashSetPageBackupAddr(HFlashAddr_t addr, uint32_t size); /** - * @brief HFlashProtectAddr 设置保护地址, 内部会使用双备份区域 + * @brief HFlashSetProtectAddr 设置保护地址, 内部会使用双备份区域 * @param addr 地址 * @param size 大小 */ -void HFlashProtectAddr(HFlashAddr_t addr, uint32_t size); +void HFlashSetProtectAddr(HFlashAddr_t addr, uint32_t size); /** - * @brief HFlashProtectBackupAddr 设置保护备份地址 + * @brief HFlashSetProtectBackupAddr 设置保护备份地址 * @param addr 地址 * @param size 大小, 必须和保护地址大小相同 */ -void HFlashProtectBackupAddr(HFlashAddr_t addr, uint32_t size); +void HFlashSetProtectBackupAddr(HFlashAddr_t addr, uint32_t size); /** * @brief HFlashInitCheck 在HFlashRegister前需要初始化检查, 用于检查页表是否可用, 不可用则需要初始化 @@ -145,8 +144,9 @@ void HFlashRegister(HFlashAddr_t addr, uint32_t size); * @param addr 需要注册的地址 * @param data 写入数据 * @param size 写入数据大小 + * @return 1: 写入成功 0: 写入失败 */ -void HFlashWrite(HFlashAddr_t addr, void *data, uint32_t size); +uint8_t HFlashWrite(HFlashAddr_t addr, void *data, uint32_t size); /** * @brief HFlashWriteOffset 写入从原始地址偏移后的地方写入数据, 如果偏移后的写入大小超过原未使用, 超出部分会自动写入0填充 @@ -154,16 +154,39 @@ void HFlashWrite(HFlashAddr_t addr, void *data, uint32_t size); * @param offset 地址偏移 * @param data 写入数据 * @param size 写入数据大小 + * @return 1: 写入成功 0: 写入失败 */ -void HFlashWriteOffset(HFlashAddr_t addr, uint32_t offset, void *data, uint32_t size); +uint8_t HFlashWriteOffset(HFlashAddr_t addr, uint32_t offset, 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, 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: 写入失败 */ -void HFlashRawWrite(HFlashAddr_t addr, void *data, uint32_t size); +uint8_t HFlashRawWrite(HFlashAddr_t addr, void *data, uint32_t size); /** * @brief HFlashRead 读取Flash数据 @@ -172,7 +195,7 @@ void HFlashRawWrite(HFlashAddr_t addr, void *data, uint32_t size); * @param size 读取数据大小 * @return 1: 读取成功 0: 读取失败 */ -void HFlashRead(HFlashAddr_t addr, void *data, uint32_t size); +uint8_t HFlashRead(HFlashAddr_t addr, void *data, uint32_t size); /** * @brief HFlashReadOffset 读取从原始地址偏移后的地方的数据 @@ -182,15 +205,35 @@ void HFlashRead(HFlashAddr_t addr, void *data, uint32_t size); * @param size 读取数据大小 * @return 1: 读取成功 0: 读取失败 */ -void HFlashReadOffset(HFlashAddr_t addr, uint32_t offset, void *data, uint32_t size); +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: 读取失败 */ -void HFlashRawRead(HFlashAddr_t addr, void *data, uint32_t size); +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 HFlashGetCrc32 获取Flash数据的CRC32值 diff --git a/src/HFlashServer.c b/src/HFlashServer.c index 9d2aca6..86efc0d 100644 --- a/src/HFlashServer.c +++ b/src/HFlashServer.c @@ -26,11 +26,16 @@ uint32_t HSCrc32Get() } #endif +// 计算最小值 #define FLASH_MIN(type, a, b) ((b) ^ (((a) ^ (b)) & (-(type)((a) < (b))))) // #define FATAL_ERROR(format, ...) LogE(format, ##__VA_ARGS__); while(1); #define FATAL_ERROR(format, ...) LogE(format, ##__VA_ARGS__); +// 最大热度 +#define MAX_HEAT ((1 << 4) - 1) + +// 检查是不是4对齐 #define IS_NOT_4(size) ((size & (4 - 1)) != 0) union PageInfo { @@ -84,7 +89,7 @@ static uint8_t IsProtect(HFlashAddr_t addr, uint32_t size) } if (addrEnd > sInfo.protectAddr + sInfo.protectSize) { - FATAL_ERROR("addr[0x%08x] size[%d] overflow protect", addr, size); + FATAL_ERROR("addr[0x%08x][0x%08x] size[%d][%d] overflow protect", addr, sInfo.protectAddr, size, sInfo.protectSize); return 0; } @@ -222,6 +227,7 @@ static uint8_t WriteFlashValue(uint32_t addr, uint32_t size, uint8_t value) static void SyncBackup() { + LogD("Start sync Backup"); if (sBackupTimer != HTIMER_INVALID) { HTimerRemove(sBackupTimer); sBackupTimer = HTIMER_INVALID; @@ -234,7 +240,7 @@ static void SyncBackup() for (uint16_t i = 0; i < HVectorGetUseLen(sNeedBackupOffset); ++i) { const uint32_t addr = HVectorGetData(sNeedBackupOffset, i); - const uint32_t destAddr = sInfo.protectAddr + (addr - sInfo.pageAddr); + const uint32_t destAddr = sInfo.protectBackupAddr + (addr - sInfo.protectAddr); RestoreBackup(addr, destAddr, HFLASH_BLOCK_SIZE); } @@ -245,7 +251,7 @@ static void SyncBackup() sPageInfo.needBackupPage = 0; } -static void _AddBackupAddr(uint32_t addr) +static void StartBackupTimer() { if (sBackupTimer != HTIMER_INVALID) { HTimerRemove(sBackupTimer); @@ -253,20 +259,30 @@ static void _AddBackupAddr(uint32_t addr) } sBackupTimer = HTimerAdd(HFLASH_TIMER_ID, HFLASH_SYNC_TIME, SyncBackup, kHTimerOnce); - const HVectorLenType index = HVectorFindData(sNeedBackupOffset, addr); - if (index == HVECTOR_ERROR) { - return ; - } +} - if (HVectorAddData(sNeedBackupOffset, addr)) { - return ; - } +static void _AddBackupAddr(uint32_t addr) +{ + do { + const HVectorLenType index = HVectorFindData(sNeedBackupOffset, addr); + if (index != HVECTOR_ERROR) { + break; + } - // 添加数据失败, 缓存已满, 需要先同步再添加 - SyncBackup(); - if (HVectorAddData(sNeedBackupOffset, addr) == 0) { - LogE("add wait sync addr[0x%08x], faild", addr); - } + if (HVectorAddData(sNeedBackupOffset, addr)) { + break; + } + + // 添加数据失败, 缓存已满, 需要先同步再添加 + SyncBackup(); + if (HVectorAddData(sNeedBackupOffset, addr) == 0) { + LogE("add wait sync addr[0x%08x], faild", addr); + break; + } + } while (0); + + LogD("Add wait sync addr[0x%08x], size[%d]", addr, HVectorGetUseLen(sNeedBackupOffset)); + StartBackupTimer(); } static void AddBackupAddr(uint32_t addr, uint32_t size) @@ -346,7 +362,7 @@ static uint8_t RestoreBackup(HFlashAddr_t srcAddr, HFlashAddr_t dstAddr, uint32_ result = 1; _FlashError: HFLASH_FREE(buff); - LogD("Restore srcAddr[0x%08x], dstAddr[0x%08x], size[%d], result[%d]", srcAddr, dstAddr, size, !result); + LogD("Restore srcAddr[0x%08x], dstAddr[0x%08x], size[%d], result[%d]", srcAddr, dstAddr, size, result); return result; } @@ -410,6 +426,13 @@ static void WritePage(uint32_t index, HFlashPageInfo *info) UpdatePageInfo(); } +static void WriteCachePage(HFlashCacheInfo *info) +{ + ++info->info.modifyCount; + info->waitWrite = 0; + WritePage(info->pos, &info->info); +} + /// 检查是否重叠, 重叠返回1, 非重叠返回0 static uint8_t IsOverLap(HFlashAddr_t srcAddr, uint32_t size, HFlashAddr_t dstAddr, uint32_t dstSize) { @@ -530,15 +553,16 @@ static uint8_t _FindCacheHelper(uint32_t index, HFlashPageInfo *info, void *user static HFlashCacheInfo *FindCache(HFlashAddr_t addr) { uint8_t currMin = 0xFF; + uint8_t fastCoolDown = 0; HFlashCacheInfo cache; for (uint16_t i = 0; i < sInfo.pageCacheUseNum; ++i) { currMin = FLASH_MIN(uint8_t, currMin, sInfo.pageCache[i].heat); + fastCoolDown = fastCoolDown || sInfo.pageCache[i].heat >= MAX_HEAT; if (sInfo.pageCache[i].info.addr != addr) { continue; } - sInfo.pageCache[i].heat = FLASH_MIN(uint8_t, sInfo.pageCache[i].heat + 1, ((1 << 5) - 1)); - + sInfo.pageCache[i].heat = FLASH_MIN(uint8_t, sInfo.pageCache[i].heat + 1, MAX_HEAT); if (i == 0) { return &sInfo.pageCache[i]; } @@ -555,9 +579,11 @@ static HFlashCacheInfo *FindCache(HFlashAddr_t addr) } // 没有找到, 先降低温度 - if (sInfo.pageCacheUseNum && currMin > 0) { + if (sInfo.pageCacheUseNum && (currMin > 0 || fastCoolDown)) { + // 达到最大热度, 需要快速降温 + const uint16_t mask = -((uint16_t)fastCoolDown); for (uint16_t i = 0; i < sInfo.pageCacheUseNum; ++i) { - sInfo.pageCache[i].heat -= currMin; + sInfo.pageCache[i].heat = ((sInfo.pageCache[i].heat >> 1) & mask) | ((sInfo.pageCache[i].heat - currMin) & ~mask); } } @@ -570,6 +596,11 @@ static HFlashCacheInfo *FindCache(HFlashAddr_t addr) ++sInfo.pageCacheUseNum; } + // 如果是延迟写入的, 需要先写入再替换 + if (sInfo.pageCache[index].waitWrite) { + WriteCachePage(&sInfo.pageCache[index]); + } + memcpy(&sInfo.pageCache[index], &cache, sizeof(HFlashCacheInfo)); return &sInfo.pageCache[index]; } @@ -607,13 +638,13 @@ void HFlashSetPageBackupAddr(HFlashAddr_t addr, uint32_t size) sInfo.pageSize = size; } -void HFlashProtectAddr(HFlashAddr_t addr, uint32_t size) +void HFlashSetProtectAddr(HFlashAddr_t addr, uint32_t size) { sInfo.protectAddr = addr; sInfo.protectSize = size; } -void HFlashProtectBackupAddr(HFlashAddr_t addr, uint32_t size) +void HFlashSetProtectBackupAddr(HFlashAddr_t addr, uint32_t size) { if (sInfo.protectSize != size) { FATAL_ERROR("protect size not match[%d][%d]", sInfo.protectSize, size); @@ -697,8 +728,8 @@ void HFlashRegister(HFlashAddr_t addr, uint32_t size) } sPageInfo.needBackupPage = 1; - cache = FindCache(addr); - RestoreBackup(sInfo.protectAddr, sInfo.protectBackupAddr, sInfo.protectSize); + StartBackupTimer(); + // RestoreBackup(sInfo.protectAddr, sInfo.protectBackupAddr, sInfo.protectSize); return ; } @@ -734,26 +765,25 @@ void HFlashRegister(HFlashAddr_t addr, uint32_t size) LogE("addr[0x%08x] size[%d] crc32 not match", cache->info.addr, cache->info.size); cache->info.useSize = 0; cache->info.crc32 = GetFlashCrc32(cache->info.addr, cache->info.useSize); - WritePage(cache->pos, &cache->info); + WriteCachePage(cache); } -void HFlashWrite(HFlashAddr_t addr, void *data, uint32_t size) +uint8_t HFlashWrite(HFlashAddr_t addr, void *data, uint32_t size) { // 检查是否存在致命性错误, 使用的地址不在注册页表中 + uint8_t result = 0; HFlashCacheInfo *cache = FindCache(addr); if (cache == NULL) { FATAL_ERROR("addr[0x%08x] not register", addr); - return ; + return result; } // 检查写入数据大小是否超出注册提供的大小范围 if (cache->info.size < size) { FATAL_ERROR("addr[0x%08x] size[%d] overflow", addr, size); - return ; + return result; } - ++cache->info.modifyCount; - // 更新使用长度 if (cache->info.useSize < size) { cache->info.useSize = size; @@ -764,32 +794,33 @@ void HFlashWrite(HFlashAddr_t addr, void *data, uint32_t size) HSCrc32Update((uint8_t *)data, size); cache->info.crc32 = HSCrc32Get(); - WriteFlash(addr, data, size); - WritePage(cache->pos, &cache->info); + result = WriteFlash(addr, data, size); + WriteCachePage(cache); // 检查是否在保护区域, 需要的话需要写入等待备份 if (IsProtect(addr, size)) { AddBackupAddr(addr, size); } + + return result; } -void HFlashWriteOffset(HFlashAddr_t addr, uint32_t offset, void *data, uint32_t size) +uint8_t HFlashWriteOffset(HFlashAddr_t addr, uint32_t offset, void *data, uint32_t size) { + uint8_t result = 0; HFlashCacheInfo *cache = FindCache(addr); if (cache == NULL) { FATAL_ERROR("addr[0x%08x] not register", addr); - return ; + return result; } const uint32_t useSize = offset + size; // 检查写入数据大小是否超出注册提供的大小范围 if (cache->info.size < useSize) { FATAL_ERROR("addr[0x%08x] size[%d] overflow", addr, useSize); - return ; + return result; } - ++cache->info.modifyCount; - // 更新使用长度, 将跨越的部分填充0 if (cache->info.useSize < useSize) { if (cache->info.useSize < offset) { @@ -800,27 +831,79 @@ void HFlashWriteOffset(HFlashAddr_t addr, uint32_t offset, void *data, uint32_t } cache->info.crc32 = GetFlashCrc32(addr, useSize); - WriteFlash(addr + offset, data, size); - WritePage(cache->pos, &cache->info); + result = WriteFlash(addr + offset, data, size); + WriteCachePage(cache); // 检查是否在保护区域, 需要的话需要写入等待备份 if (IsProtect(addr, size)) { AddBackupAddr(addr, useSize); } + + return result; } -void HFlashRawWrite(HFlashAddr_t addr, void *data, uint32_t size) +void HFlashStreamBegin(HFlashAddr_t addr) { - WriteFlash(addr, data, size); + HFlashCacheInfo *cache = FindCache(addr); + if (cache == NULL) { + FATAL_ERROR("addr[0x%08x] not register", addr); + return ; + } + + cache->waitWrite = 1; + cache->info.crc32 = 0xFFFFFFFF; + cache->info.useSize = 0; } -void HFlashRead(HFlashAddr_t addr, void *data, uint32_t size) +uint8_t HFlashStreamWrite(HFlashAddr_t addr, void *data, uint32_t size) +{ + uint8_t result = 0; + HFlashCacheInfo *cache = FindCache(addr); + if (cache == NULL) { + FATAL_ERROR("addr[0x%08x] not register", addr); + return result; + } + + if (cache->info.useSize + size > cache->info.size) { + LogE("addr[0x%08x] size[%d][%d] overflow", addr, cache->info.useSize + size, cache->info.size); + return result; + } + + WriteFlash(addr + cache->info.useSize, data, size); + cache->info.useSize += size; + ++cache->info.modifyCount; + return result; +} + +void HFlashStreamEnd(HFlashAddr_t addr) +{ + HFlashCacheInfo *cache = FindCache(addr); + if (cache == NULL) { + FATAL_ERROR("addr[0x%08x] not register", addr); + return ; + } + + cache->waitWrite = 0; + cache->info.crc32 = GetFlashCrc32(addr, cache->info.useSize); + if (IsProtect(addr, cache->info.useSize)) { + AddBackupAddr(addr, cache->info.useSize); + } + + WriteCachePage(cache); +} + +uint8_t HFlashRawWrite(HFlashAddr_t addr, void *data, uint32_t size) +{ + return WriteFlash(addr, data, size); +} + +uint8_t HFlashRead(HFlashAddr_t addr, void *data, uint32_t size) { HFlashCacheInfo *cache = FindCache(addr); if (cache == NULL) { FATAL_ERROR("addr[0x%08x] not register", addr); memset(data, 0, size); - return ; + return 0; } // 超出部分填充0 @@ -829,22 +912,22 @@ void HFlashRead(HFlashAddr_t addr, void *data, uint32_t size) } const uint32_t readSize = FLASH_MIN(uint32_t, size, cache->info.useSize); - ReadFlash(addr, data, readSize); + return ReadFlash(addr, data, readSize); } -void HFlashReadOffset(HFlashAddr_t addr, uint32_t offset, void *data, uint32_t size) +uint8_t HFlashReadOffset(HFlashAddr_t addr, uint32_t offset, void *data, uint32_t size) { HFlashCacheInfo *cache = FindCache(addr); if (cache == NULL) { FATAL_ERROR("addr[0x%08x] not register", addr); memset(data, 0, size); - return ; + return 0; } // 读取的偏移量超出使用长度 if (cache->info.useSize < offset) { memset(data, 0, size); - return ; + return 0; } // 读取的数据超出使用长度, 将使用长度后面填充0 @@ -854,12 +937,36 @@ void HFlashReadOffset(HFlashAddr_t addr, uint32_t offset, void *data, uint32_t s memset((uint8_t *)data + size - remain, 0, remain); } - ReadFlash(addr, data, size - remain); + return ReadFlash(addr + offset, data, size - remain); } -void HFlashRawRead(HFlashAddr_t addr, void *data, uint32_t size) +uint8_t HFlashRawRead(HFlashAddr_t addr, void *data, uint32_t size) { - ReadFlash(addr, data, size); + return ReadFlash(addr, data, size); +} + +void HFlashUpdateVersion(HFlashAddr_t addr, uint16_t newVersion, HFlashUpdateVersionCallback callback, void *userData) +{ + HFlashCacheInfo *cache = FindCache(addr); + if (cache == NULL) { + FATAL_ERROR("addr[0x%08x] not register", addr); + return ; + } + + if (cache->info.version == newVersion) { + return ; + } + + const uint16_t oldVersion = cache->info.version; + cache->waitWrite = 1; + cache->info.version = newVersion; + if (callback) { + callback(addr, oldVersion, newVersion, userData); + } + + if (cache->waitWrite) { + WriteCachePage(cache); + } } uint32_t HFlashGetCrc32(HFlashAddr_t addr) @@ -872,3 +979,4 @@ uint32_t HFlashGetCrc32(HFlashAddr_t addr) return cache->info.crc32; } +