#include "ConfigBase.h"
#include "Flash.h"
#include "Crc.h"
#define DisableIrq() __disable_irq()
#define EnableIrq() __enable_irq()
// 获取 Config
bool GetConfig(Config_t* cfg,uint addr)
{
// uint addr = GetChipSize(0) - GetFlashBlockSize(0) + GetChipStartAddr(0);
ConfigBase_t* cf = (ConfigBase_t*)addr;
// 魔数 默认为 : 'M' 'a' 'g' '&' 0x4D616726
if (cf->MagicNum != 0x4D616726)return false;
// 计算校验
uint crc = CaclcCRC32B((byte*)cf, sizeof(ConfigBase_t) - sizeof(cf->Crc32));
if (cf->Crc32 != crc)return false;
memcpy(cfg, (byte*)&cf->Config, cf->Length);
// 判断是否完全兼容, 不要求强制升级好了。
// 让用的人自己去区分。
// if (sizeof(Config_t) != cf->Length)
// {
// CleanConfig();
// }
return true;
}
bool SetConfig(Config_t* cfg2, uint addr)
{
// uint addr = GetChipSize(0) - GetFlashBlockSize(0) + GetChipStartAddr(0);
// 硬件要求不能被中断打断 否则会失败
DisableIrq();
ConfigBase_t base;
base.MagicNum = 0x4D616726;
base.Length = sizeof(Config_t);
memcpy((byte*)&base.Config, (byte*)cfg2, sizeof(Config_t));
// 计算校验
uint crc = CaclcCRC32B((byte*)&base, sizeof(ConfigBase_t) - sizeof(base.Crc32));
base.Crc32 = crc;
const int tryCount = 3;
bool stat = false;
int count = 0;
while (true)
{
// 超出擦除失败次数
if (count > tryCount)break;
if (EraseBlock(addr, false))
{
stat = true;
break;
}
count++;
}
EnableIrq();
if (!stat)return stat;
stat = false;
count = 0;
// 硬件要求不能被中断打断 否则会失败
DisableIrq();
while (true)
{
// 超出写入出错次数
if (count > tryCount)break;
if (WriteBlock(addr, (byte*)&base, sizeof(ConfigBase_t), true))
{
stat = true;
break;
}
count++;
}
EnableIrq();
return stat;
}
bool CleanConfig(uint addr)
{
// 硬件要求不能被中断打断 否则会失败
DisableIrq();
// uint addr = GetChipSize(0) - GetFlashBlockSize(0) + GetChipStartAddr(0);
bool rs = EraseBlock(addr, false);
EnableIrq();
return rs;
}
#include "Crc.h"
#include "Array.h"
// Config 有效性 取决于 MagicNum SaveIdx Crc32
typedef struct
{
// 配置实际内容。
Config_t Config;
// 魔数 内部使用。 外部不要碰
// 默认为 : 'M' 'a' 'g' '&' 0x4D616726
uint MagicNum;
// 保存号,也是位置号。内部使用。外部不要碰 0-65535
ushort Index;
// 校验 内部使用。 外部不要碰
ushort Crc16;
}FConfigItem_t;
/**
* @brief 修正内部数据
* @param cfg 配置
* @param idx 必要条件
*/
static void FixFCfg(FConfigItem_t* cfg, ushort idx)
{
cfg->Index = idx;
cfg->MagicNum = 0x4D616726;
byte* p = (byte*)cfg;
int len = offsetof2(FConfigItem_t,Crc16);
cfg->Crc16 = CaclcCRC16_MODBUS(p, len);
// cfg->Crc16 = CaclcCRC16_MODBUS(p,sizeof(FConfigItem_t) - 2);
}
/**
* @brief 检查配置是否有效
* @param cfg
*/
static bool FCfgIsOK(FConfigItem_t* cfg)
{
if(cfg == NULL)return false;
if(cfg->MagicNum != 0x4D616726)return false;
byte* p = (byte*)cfg;
int len = offsetof2(FConfigItem_t,Crc16);
ushort cl = CaclcCRC16_MODBUS(p, len);
// ushort cl = CaclcCRC16_MODBUS(p,sizeof(FConfigItem_t) - 2);
if(cl != cfg->Crc16)return false;
return true;
}
/**
* @brief 所在块的块地址
* @param ctl
* @param idx
*/
static uint FCfgSecAddr(FCfgCtrl_t* ctl,int idx)
{
// 块个数
int sCnt = 1 << ctl->FSecBit;
// 所在块
int sec = idx & (sCnt - 1);
// 块地址
uint addr = ctl->FSecAddrs[sec];
return addr;
}
// #define FSECADDR(ctl,idx) (ctl->FSecAddrs[(idx & ((1 << ctl->FSecBit) - 1)))])
// FSECADDR FCfgSecAddr
/**
* @brief 块内偏移量
* @param ctl
* @param idx
*/
static uint FSecOffset(FCfgCtrl_t* ctl,int idx)
{
// 块内编号
idx >>= ctl->FSecBit;
// 块内个数
int cCnt = 1 << ctl->FSecCfgBit;
// 取余
int sidx = idx & (cCnt - 1);
// 块内偏移
uint offset = sizeof(FConfigItem_t) * sidx;
return offset;
}
// #define FSECOFFSET(ctl,idx) (sizeof(FConfigItem_t) * ((idx >> ctl->FSecBit) & (1 << ctl->FSecCfgBit) - 1))))
// #define FSECOFFSET FSecOffset
/**
* @brief 初始化
* @param ctl
* @param api NOR FLASH 接口
* @param sad FLASH 块地址数组
* @param sadlen 块数组长度
* @param ccnt 块内 存放配置的份数
* @return 0 无错
*/
int FCfgInit(FCfgCtrl_t* ctl, NorFlash_t* api, uint* sad, byte sadlen, byte ccnt)
{
int err = 0;
byte temp = 0;
if(ctl == NULL){ err = __LINE__; goto reserr; }
if(api == NULL){ err = __LINE__; goto reserr; }
if(sad == NULL){ err = __LINE__; goto reserr; }
if(sadlen < 2) { err = __LINE__; goto reserr; }
if(ccnt < 1) { err = __LINE__; goto reserr; }
memcpy(&ctl->FApi,api,sizeof(NorFlash_t));
ctl->FSecAddrs = sad;
// 计算位数
temp = 0;
for (int i = 1; ; i++)
{
int cnt = 1 << i;
if(sadlen >= cnt)temp = i;
else break;
}
ctl->FSecBit = temp;
temp = 0;
for (int i = 0; ; i++)
{
int cnt = 1 << i;
if(ccnt >= cnt)temp = i;
else break;
}
ctl->FSecCfgBit = temp;
return 0;
reserr:
DebugPrintf("%s [%d] ERROR\r\n",__func__,__LINE__);
return err;
}
/**
* @brief 扫描整个 FLASH 存储区,找到最新且有效的配置取出来
* @param ctl
* @param cfg
*/
bool FCfgLoad(FCfgCtrl_t* ctl, Config_t* cfg)
{
if(ctl == NULL)return false;
if(ctl->FSecAddrs == NULL)return false;
if(ctl->FSecBit < 1)return false;
if(cfg == NULL)return false;
// 最大同时存在配置个数
int limit = (1 << ctl->FSecBit) * (1 << ctl->FSecCfgBit);
// 已存在最大IDX
int max = -1;
// 小于limit的,已存在最大IDX
int limitMax = -1;
FConfigItem_t temp;
FConfigItem_t* fp = &temp;
// 块个数
int slen = 1 << ctl->FSecBit;
// 块内配置个数
int sCfgCnt = 1 << ctl->FSecCfgBit;
for (int i = 0; i < slen; i++)
{
// 块首地址
uint base = ctl->FSecAddrs[i];
for (int j = 0; j < sCfgCnt; j++)
{
// 得到地址
uint addr = sizeof(FConfigItem_t) * j + base;
if(ctl->FApi.FlashRead != NULL)
{
// 读取 配置项
memset(fp, 0x00, sizeof(FConfigItem_t));
if(!ctl->FApi.FlashRead(addr,(byte*)fp,sizeof(FConfigItem_t)))continue;
}
else
{
// 直接指针过去
fp = (FConfigItem_t*)addr;
}
// 配置有效性检查
if(!FCfgIsOK(fp))continue;
// 选取最后存入的 idx
ushort idx = fp->Index;
if(idx > max)max = idx;
if(idx < limit)
{
if(idx > limitMax)limitMax = idx;
}
}
}
// 没有任何有效配置
if(max == -1)
{
ctl->CurrIndex = 0;
memset(&ctl->CurrCfg,0x00,sizeof(FConfigItem_t));
return false;
}
// 判定最后写入是哪个
int last = -1;
if((max > 65535 - limit) && (limitMax != -1))
{
// 刚好跨界了。大的被丢弃。使用小的里面最大的。
last = limitMax;
}
else
{
last = max;
}
// 块地址 + 块内偏移
uint addr = FCfgSecAddr(ctl,last) + FSecOffset(ctl,last);
if(ctl->FApi.FlashRead != NULL)
{
// 读取 配置项
memset(fp, 0x00, sizeof(FConfigItem_t));
ctl->FApi.FlashRead(addr,(byte*)fp,sizeof(FConfigItem_t));
}
else
{
// 直接指针过去
fp = (FConfigItem_t*)addr;
}
memcpy(&ctl->CurrCfg,&fp->Config,sizeof(Config_t));
ctl->CurrIndex = fp->Index;
memcpy(cfg,&ctl->CurrCfg,sizeof(Config_t));
return true;
}
/**
* @brief 写配置进去,地址为块首地址的时候擦除块。
* @param ctl
* @param cfg
*/
static bool FCfgWrite(FCfgCtrl_t* ctl, FConfigItem_t* cfg)
{
if(ctl->FApi.FlashWrite == NULL)return false;
int idx = cfg->Index;
// 块地址
uint addr = FCfgSecAddr(ctl,idx);
// 块内偏移
uint offset = FSecOffset(ctl,idx);
if(offset == 0)
{
if(ctl->FApi.FlashErase == NULL)return false;
if(!ctl->FApi.FlashErase(addr))return false;
}
// 写
return ctl->FApi.FlashWrite(addr + offset, (byte*)cfg, sizeof(FConfigItem_t));
}
/**
* @brief 保存配置
* @param ctl
* @param cfg
*/
bool FCfgSave(FCfgCtrl_t* ctl, Config_t* cfg)
{
if(ctl == NULL)return false;
if(ctl->FSecAddrs == NULL)return false;
if(ctl->FSecBit < 1)return false;
if(cfg == NULL)return false;
// 相同,不存。
Config_t* curr = &ctl->CurrCfg;
if(!ArrayEqual((byte*)cfg, (byte*)curr,sizeof(Config_t)))return true;
// 下一个位置保存
ushort idx = ctl->CurrIndex + 1;
FConfigItem_t item;
memcpy(&item.Config,cfg,sizeof(Config_t));
FixFCfg(&item,idx);
bool res = FCfgWrite(ctl, &item);
// 保存完成,更新本地信息
if(res)
{
memcpy(&ctl->CurrCfg,cfg,sizeof(Config_t));
ctl->CurrIndex = item.Index;
}
return res;
}
/**
* @brief 删除一个配置
* @param ctl
* @param idx
*/
bool FCfgClean(FCfgCtrl_t* ctl, int idx)
{
if(ctl->FApi.FlashWrite == NULL)return false;
// 块地址
uint addr = FCfgSecAddr(ctl,idx);
// 块内偏移
uint offset = FSecOffset(ctl,idx);
// 配置内 magic 位置
offset += offsetof2(FConfigItem_t,MagicNum);
// FLASH 擦完是 ff 只能往 00 写
uint magic = 0;
return ctl->FApi.FlashWrite(addr+offset, (byte*)&magic, sizeof(magic));
}
/**
* @brief 擦除所有 FLASH 区域,一个不留
* @param ctl
*/
bool FCfgCleanAll(FCfgCtrl_t* ctl)
{
if(ctl == NULL)return false;
if(ctl->FSecAddrs == NULL)return false;
if(ctl->FSecBit < 1)return false;
if(ctl->FApi.FlashErase == NULL)return false;
int slen = 1 << ctl->FSecBit;
for (int i = 0; i < slen; i++)
{
ctl->FApi.FlashErase(ctl->FSecAddrs[i]);
}
ctl->CurrIndex = 0;
return true;
}
|