配置子系统,链式保存管理多配置段。

1,每个配置段都有固定长度的头部,包括签名、校验、名称等,数据紧跟其后
2,借助签名和双校验确保是有效配置段
3,根据名称查找更新配置段

编译通过,未测试
This commit is contained in:
Stone 2015-10-14 18:00:56 +00:00
parent 8643bdd288
commit 64c992c6db
2 changed files with 203 additions and 2 deletions

View File

@ -1,6 +1,165 @@
#include "Config.h" #include "Config.h"
#include "..\Security\Crc.h"
//TConfig Config; Storage* ConfigBlock::Device = NULL;
void* ConfigBlock::BaseAddress = NULL;
bool ConfigBlock::IsGoodBlock() const
{
if(Signature != c_Version || HeaderCRC == 0) return false;
// 计算头部 CRC。从数据CRC开始包括大小和名称
ushort crc = Crc::Hash16(&DataCRC, sizeof(*this) - offsetof(ConfigBlock, DataCRC));
return crc == HeaderCRC;
}
bool ConfigBlock::IsGoodData() const
{
// 计算数据块CRC
ushort crc = Crc::Hash16(Data(), Size);
return crc == DataCRC;
}
const ConfigBlock* ConfigBlock::Next() const
{
if(!IsGoodBlock()) return NULL;
// 确保数据部分2字节对齐便于Flash操作
uint s = (Size + 1) & ~1;
return (const ConfigBlock*)((byte*)Data() + s);
}
// 数据所在地址,紧跟头部后面
const void* ConfigBlock::Data() const
{
return (const void*)&this[1];
}
//--//
// 构造一个新的配置块
bool ConfigBlock::Init(const char* name, const ByteArray& bs)
{
if(name == NULL || strlen(name) >= sizeof(Name)) return false;
//memset(this, 0, sizeof(*this));
// 数据长度为0表明是置为无效
if(bs.Length() > 0)
DataCRC = Crc::Hash16(bs.GetBuffer(), bs.Length());
else
DataCRC = 0;
/*// 只有首次允许设置名字和大小,避免后面随意扩张引起越界覆盖
if(IsGoodBlock())
{
if(bs.Length() > Size) return false;
}
else*/
{
Signature = c_Version;
Size = bs.Length();
memset(Name, 0, ArrayLength(Name));
memcpy(Name, name, ArrayLength(Name));
}
// 计算头部CRC。包括数据CRC、大小、名称
HeaderCRC = Crc::Hash16(&DataCRC, sizeof(*this) - offsetof(ConfigBlock, DataCRC));
return true;
}
//--//
// 循环查找配置块
const ConfigBlock* ConfigBlock::Find(const char* name, bool fAppend) const
{
const ConfigBlock* ptr = this;
// 遍历链表,找到同名块
while(ptr->IsGoodBlock())
{
if(ptr->IsGoodData() && name && strcmp(name, ptr->Name) == 0)
{
return ptr;
}
ptr = ptr->Next();
}
// 如果需要添加,返回最后一个非法块的地址
return fAppend ? ptr : NULL;
}
// 更新块
bool ConfigBlock::Write(const void* addr, const ByteArray& bs)
{
if(bs.Length() > Size) return false;
bool rs = true;
// 先写入头部,然后写入数据
uint len = sizeof(ConfigBlock) - offsetof(ConfigBlock, Signature);
rs &= Device->Write((uint)addr, ByteArray((byte*)&Signature, len));
if(bs.Length() > 0)
rs &= Device->Write((uint)addr + len, ByteArray(bs.GetBuffer(), Size));
return rs;
}
// 废弃
bool ConfigBlock::Invalid(const char* name, const void* addr)
{
return Set(name, ByteArray(0), addr);
}
// 根据名称更新块
bool ConfigBlock::Set(const char* name, const ByteArray& bs, const void* addr)
{
if(name == NULL) return false;
if(!addr) addr = BaseAddress;
const ConfigBlock* cfg = (const ConfigBlock*)addr;
if(cfg) cfg = cfg->Find(name, true);
if(cfg)
{
// 重新搞一个配置头,使用新的数据去重新初始化
ConfigBlock header;
header.Init(name, bs);
return header.Write(cfg, bs);
}
return false;
}
// 获取配置数据
bool ConfigBlock::Get(const char* name, ByteArray& bs, const void* addr)
{
if(name == NULL) return false;
if(!addr) addr = BaseAddress;
const ConfigBlock* cfg = (const ConfigBlock*)addr;
if(cfg) cfg = cfg->Find(name, false);
if(cfg)
{
if(cfg->Size <= bs.Capacity())
{
bs.Copy((byte*)cfg->Data(), 0, cfg->Size);
bs.SetLength(cfg->Size);
return true;
}
}
return false;
}
// 初始化 // 初始化
TConfig::TConfig() TConfig::TConfig()
@ -15,7 +174,7 @@ void TConfig::LoadDefault()
{ {
Kind = Sys.Code; Kind = Sys.Code;
//Server = 0x01; //Server = 0x01;
PingTime = 15; PingTime = 15;
OfflineTime = 60; OfflineTime = 60;
} }

View File

@ -3,6 +3,41 @@
#include "Sys.h" #include "Sys.h"
#include "Stream.h" #include "Stream.h"
#include "..\Storage\Storage.h"
class ConfigBlock
{
private:
static const uint c_Version = 0x534F5453; // STOS
public:
static Storage* Device;
static void* BaseAddress;
public:
uint Signature;
ushort HeaderCRC;
ushort DataCRC;
uint Size;
char Name[16];
bool IsGoodBlock() const;
bool IsGoodData () const;
const ConfigBlock* Next() const;
const void* Data() const;
bool Init(const char* name, const ByteArray& bs);
const ConfigBlock* Find(const char* name, bool fAppend = false) const;
bool Write(const void* addr, const ByteArray& bs);
// 废弃
static bool Invalid(const char* name, const void* addr = NULL);
// 设置配置数据
static bool Set(const char* name, const ByteArray& bs, const void* addr = NULL);
// 获取配置数据
static bool Get(const char* name, ByteArray& bs, const void* addr = NULL);
};
// 必须设定为1字节对齐否则offsetof会得到错误的位置 // 必须设定为1字节对齐否则offsetof会得到错误的位置
#pragma pack(push) // 保存对齐状态 #pragma pack(push) // 保存对齐状态
@ -38,4 +73,11 @@ public:
//extern TConfig Config; //extern TConfig Config;
/*
1
2
3
*/
#endif #endif