diff --git a/Config.cpp b/Config.cpp index b1bac6d0..628172ba 100644 --- a/Config.cpp +++ b/Config.cpp @@ -1,6 +1,165 @@ #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() @@ -15,7 +174,7 @@ void TConfig::LoadDefault() { Kind = Sys.Code; //Server = 0x01; - + PingTime = 15; OfflineTime = 60; } diff --git a/Config.h b/Config.h index c8368be6..6d3e74ac 100644 --- a/Config.h +++ b/Config.h @@ -3,6 +3,41 @@ #include "Sys.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会得到错误的位置 #pragma pack(push) // 保存对齐状态 @@ -38,4 +73,11 @@ public: //extern TConfig Config; +/* +配置子系统,链式保存管理多配置段。 +1,每个配置段都有固定长度的头部,包括签名、校验、名称等,数据紧跟其后 +2,借助签名和双校验确保是有效配置段 +3,根据名称查找更新配置段 +*/ + #endif