From 64c992c6db34ae505736f48c958b8a32b806f9c0 Mon Sep 17 00:00:00 2001 From: Stone Date: Wed, 14 Oct 2015 18:00:56 +0000 Subject: [PATCH] =?UTF-8?q?=E9=85=8D=E7=BD=AE=E5=AD=90=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=EF=BC=8C=E9=93=BE=E5=BC=8F=E4=BF=9D=E5=AD=98=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E5=A4=9A=E9=85=8D=E7=BD=AE=E6=AE=B5=E3=80=82=201=EF=BC=8C?= =?UTF-8?q?=E6=AF=8F=E4=B8=AA=E9=85=8D=E7=BD=AE=E6=AE=B5=E9=83=BD=E6=9C=89?= =?UTF-8?q?=E5=9B=BA=E5=AE=9A=E9=95=BF=E5=BA=A6=E7=9A=84=E5=A4=B4=E9=83=A8?= =?UTF-8?q?=EF=BC=8C=E5=8C=85=E6=8B=AC=E7=AD=BE=E5=90=8D=E3=80=81=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E3=80=81=E5=90=8D=E7=A7=B0=E7=AD=89=EF=BC=8C=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E7=B4=A7=E8=B7=9F=E5=85=B6=E5=90=8E=202=EF=BC=8C?= =?UTF-8?q?=E5=80=9F=E5=8A=A9=E7=AD=BE=E5=90=8D=E5=92=8C=E5=8F=8C=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E7=A1=AE=E4=BF=9D=E6=98=AF=E6=9C=89=E6=95=88=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E6=AE=B5=203=EF=BC=8C=E6=A0=B9=E6=8D=AE=E5=90=8D?= =?UTF-8?q?=E7=A7=B0=E6=9F=A5=E6=89=BE=E6=9B=B4=E6=96=B0=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 编译通过,未测试 --- Config.cpp | 163 ++++++++++++++++++++++++++++++++++++++++++++++++++++- Config.h | 42 ++++++++++++++ 2 files changed, 203 insertions(+), 2 deletions(-) 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