libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
raw_sequential.cpp
1#include "raw_sequential.hpp"
2
3#include <cstddef>
4#include <cstdint>
5
6#include "libxr_def.hpp"
7#include "libxr_mem.hpp"
8
9using namespace LibXR;
10
12 : flash_(flash), max_buffer_size_(max_buffer_size)
13{
14 ASSERT(flash.MinEraseSize() * 2 <= flash.Size());
15 ASSERT(max_buffer_size <= flash.Size() / 2);
16 auto block_num = static_cast<size_t>(flash.Size() / flash.MinEraseSize());
17 block_size_ = block_num / 2 * flash.MinEraseSize();
18 buffer_ = new uint8_t[max_buffer_size];
19
20 Init();
21}
22
23DatabaseRawSequential::KeyInfo::KeyInfo() : raw_data(0xFFFFFFFF) {}
24
25DatabaseRawSequential::KeyInfo::KeyInfo(bool nextKey, uint8_t nameLength,
26 uint32_t dataSize)
27 : raw_data(0)
28{
29 SetNextKeyExist(nextKey);
30 SetNameLength(nameLength);
31 SetDataSize(dataSize);
32}
33
34void DatabaseRawSequential::KeyInfo::SetNextKeyExist(bool value)
35{
36 raw_data = (raw_data & 0x7FFFFFFF) | (static_cast<uint32_t>(value & 0x1) << 31);
37}
38
39bool DatabaseRawSequential::KeyInfo::GetNextKeyExist() const
40{
41 return (raw_data >> 31) & 0x1;
42}
43
44void DatabaseRawSequential::KeyInfo::SetNameLength(uint8_t len)
45{
46 raw_data = (raw_data & 0x80FFFFFF) | (static_cast<uint32_t>(len & 0x7F) << 24);
47}
48
49uint8_t DatabaseRawSequential::KeyInfo::GetNameLength() const
50{
51 return (raw_data >> 24) & 0x7F;
52}
53
54void DatabaseRawSequential::KeyInfo::SetDataSize(uint32_t size)
55{
56 raw_data = (raw_data & 0xFF000000) | (size & 0x00FFFFFF);
57}
58
59uint32_t DatabaseRawSequential::KeyInfo::GetDataSize() const
60{
61 return raw_data & 0x00FFFFFF;
62}
63
64void DatabaseRawSequential::ReadFlashOrExit(size_t offset, RawData data)
65{
66 [[maybe_unused]] const auto flash_io_result = flash_.Read(offset, data);
67 REQUIRE(flash_io_result == ErrorCode::OK);
68}
69
70void DatabaseRawSequential::WriteFlashOrExit(size_t offset, ConstRawData data)
71{
72 [[maybe_unused]] const auto flash_io_result = flash_.Write(offset, data);
73 REQUIRE(flash_io_result == ErrorCode::OK);
74}
75
76void DatabaseRawSequential::EraseFlashOrExit(size_t offset, size_t size)
77{
78 [[maybe_unused]] const auto flash_io_result = flash_.Erase(offset, size);
79 REQUIRE(flash_io_result == ErrorCode::OK);
80}
81
83{
84 Memory::FastSet(buffer_, 0xFF, max_buffer_size_);
85 FlashInfo* flash_data_ = reinterpret_cast<FlashInfo*>(buffer_);
86 flash_data_->header = FLASH_HEADER;
87 flash_data_->key = {0, 0, 0};
88 buffer_[max_buffer_size_ - 1] = CHECKSUM_BYTE;
89
90 if (!IsBlockInited(BlockType::BACKUP) || IsBlockError(BlockType::BACKUP))
91 {
92 InitBlock(BlockType::BACKUP);
93 }
94
95 if (IsBlockError(BlockType::MAIN))
96 {
97 if (IsBlockEmpty(BlockType::BACKUP))
98 {
99 InitBlock(BlockType::MAIN);
100 }
101 else
102 {
103 ReadFlashOrExit(block_size_, {buffer_, max_buffer_size_});
104 EraseFlashOrExit(0, block_size_);
105 WriteFlashOrExit(0, {buffer_, max_buffer_size_});
106 }
107 }
108
109 Load();
110}
111
113{
114 EraseFlashOrExit(block_size_, block_size_);
115 WriteFlashOrExit(block_size_, {buffer_, max_buffer_size_});
116
117 EraseFlashOrExit(0, block_size_);
118 WriteFlashOrExit(0, {buffer_, max_buffer_size_});
119}
120
121void DatabaseRawSequential::Load() { ReadFlashOrExit(0, {buffer_, max_buffer_size_}); }
122
124{
125 Memory::FastSet(buffer_, 0xFF, max_buffer_size_);
126 FlashInfo* flash_data_ = reinterpret_cast<FlashInfo*>(buffer_);
127 flash_data_->header = FLASH_HEADER;
128 flash_data_->key = {0, 0, 0};
129 buffer_[max_buffer_size_ - 1] = CHECKSUM_BYTE;
130 EraseFlashOrExit(0, block_size_);
131 EraseFlashOrExit(block_size_, block_size_);
132 WriteFlashOrExit(0, {buffer_, max_buffer_size_});
133 WriteFlashOrExit(block_size_, {buffer_, max_buffer_size_});
134}
135
137{
138 auto ans = SearchKey(key.name_);
139 if (!ans)
140 {
142 }
143
144 KeyInfo key_buffer;
145 ReadFlashOrExit(ans, key_buffer);
146
147 if (key.raw_data_.size_ != key_buffer.GetDataSize())
148 {
149 return ErrorCode::FAILED;
150 }
151
152 GetKeyData(ans, key.raw_data_);
153
154 return ErrorCode::OK;
155}
156
157void DatabaseRawSequential::InitBlock(BlockType block)
158{
159 size_t offset = 0;
160 if (block == BlockType::BACKUP)
161 {
162 offset = block_size_;
163 }
164
165 EraseFlashOrExit(offset, block_size_);
166 WriteFlashOrExit(offset, {buffer_, max_buffer_size_});
167}
168
175bool DatabaseRawSequential::IsBlockInited(BlockType block)
176{
177 size_t offset = 0;
178 if (block == BlockType::BACKUP)
179 {
180 offset = block_size_;
181 }
182 FlashInfo flash_data_;
183 ReadFlashOrExit(offset, flash_data_);
184 return flash_data_.header == FLASH_HEADER;
185}
186
192bool DatabaseRawSequential::IsBlockEmpty(BlockType block)
193{
194 size_t offset = 0;
195 if (block == BlockType::BACKUP)
196 {
197 offset = block_size_;
198 }
199 FlashInfo flash_data_;
200 ReadFlashOrExit(offset, flash_data_);
201 return flash_data_.key.GetNameLength() == 0;
202}
203
209bool DatabaseRawSequential::IsBlockError(BlockType block)
210{
211 size_t offset = 0;
212 if (block == BlockType::BACKUP)
213 {
214 offset = block_size_;
215 }
216 uint8_t checksum_byte = 0;
217 ReadFlashOrExit(offset + max_buffer_size_ / sizeof(CHECKSUM_BYTE) - 1, checksum_byte);
218 return checksum_byte != CHECKSUM_BYTE;
219}
220
221bool DatabaseRawSequential::HasLastKey(size_t offset)
222{
223 KeyInfo key;
224 ReadFlashOrExit(offset, key);
225 return key.GetNextKeyExist();
226}
227
228size_t DatabaseRawSequential::GetKeySize(size_t offset)
229{
230 KeyInfo key;
231 ReadFlashOrExit(offset, key);
232 return sizeof(KeyInfo) + key.GetNameLength() + key.GetDataSize();
233}
234
235size_t DatabaseRawSequential::GetNextKey(size_t offset)
236{
237 return offset + GetKeySize(offset);
238}
239
240size_t DatabaseRawSequential::GetLastKey(BlockType block)
241{
242 if (IsBlockEmpty(block))
243 {
244 return 0;
245 }
246
247 size_t offset = LibXR::OffsetOf(&FlashInfo::key);
248 while (HasLastKey(offset))
249 {
250 offset = GetNextKey(offset);
251 }
252 return offset;
253}
254
255void DatabaseRawSequential::SetNestKeyExist(size_t offset, bool exist)
256{
257 KeyInfo key;
258 ReadFlashOrExit(offset, key);
259 key.SetNextKeyExist(exist);
260 LibXR::Memory::FastCopy(buffer_ + offset, &key, sizeof(KeyInfo));
261}
262
263bool DatabaseRawSequential::KeyDataCompare(size_t offset, const void* data, size_t size)
264{
265 KeyInfo key;
266 ReadFlashOrExit(offset, key);
267 size_t key_data_offset = offset + sizeof(KeyInfo) + key.GetNameLength();
268 uint8_t data_buffer;
269 for (size_t i = 0; i < size; i++)
270 {
271 ReadFlashOrExit(key_data_offset + i, data_buffer);
272 if (data_buffer != ((uint8_t*)data)[i])
273 {
274 return true;
275 }
276 }
277 return false;
278}
279
280bool DatabaseRawSequential::KeyNameCompare(size_t offset, const char* name)
281{
282 KeyInfo key;
283 ReadFlashOrExit(offset, key);
284 for (size_t i = 0; i < key.GetNameLength(); i++)
285 {
286 uint8_t data_buffer;
287 ReadFlashOrExit(offset + sizeof(KeyInfo) + i, data_buffer);
288 if (data_buffer != name[i])
289 {
290 return true;
291 }
292 }
293 return false;
294}
295
296ErrorCode DatabaseRawSequential::AddKey(const char* name, const void* data, size_t size)
297{
298 if (auto ans = SearchKey(name))
299 {
300 return SetKey(ans, data, size);
301 }
302
303 const uint32_t NAME_LEN = strlen(name) + 1;
304 size_t last_key_offset = GetLastKey(BlockType::MAIN);
305 size_t key_buf_offset =
306 last_key_offset ? GetNextKey(last_key_offset) : LibXR::OffsetOf(&FlashInfo::key);
307
308 size_t end_pos_offset = key_buf_offset + sizeof(KeyInfo) + NAME_LEN + size;
309 if (end_pos_offset > max_buffer_size_ - 1)
310 {
311 return ErrorCode::FULL;
312 }
313
314 size_t data_ptr_offset = key_buf_offset + sizeof(KeyInfo);
315 LibXR::Memory::FastCopy(buffer_ + data_ptr_offset, name, NAME_LEN);
316 LibXR::Memory::FastCopy(buffer_ + data_ptr_offset + NAME_LEN, data, size);
317
318 KeyInfo key_buf = {0, static_cast<uint8_t>(NAME_LEN), static_cast<uint32_t>(size)};
319 LibXR::Memory::FastCopy(buffer_ + key_buf_offset, &key_buf, sizeof(KeyInfo));
320 if (last_key_offset)
321 {
322 SetNestKeyExist(last_key_offset, 1);
323 }
324
325 Save();
326 return ErrorCode::OK;
327}
328
329ErrorCode DatabaseRawSequential::SetKey(const char* name, const void* data, size_t size)
330{
331 if (size_t key_offset = SearchKey(name))
332 {
333 return SetKey(key_offset, data, size);
334 }
335 return ErrorCode::FAILED;
336}
337
338ErrorCode DatabaseRawSequential::SetKey(size_t offset, const void* data, size_t size)
339{
340 DEV_ASSERT(offset != 0);
341
342 KeyInfo key;
343 ReadFlashOrExit(offset, key);
344
345 if (key.GetDataSize() == size)
346 {
347 if (KeyDataCompare(offset, data, size))
348 {
349 LibXR::Memory::FastCopy(buffer_ + offset + sizeof(KeyInfo) + key.GetNameLength(),
350 data, size);
351 Save();
352 }
353 return ErrorCode::OK;
354 }
355
356 return ErrorCode::FAILED;
357}
358
359ErrorCode DatabaseRawSequential::GetKeyData(size_t offset, RawData data)
360{
361 KeyInfo key;
362 ReadFlashOrExit(offset, key);
363 if (key.GetDataSize() > data.size_)
364 {
365 return ErrorCode::FAILED;
366 }
367 auto data_offset = offset + sizeof(KeyInfo) + key.GetNameLength();
368 ReadFlashOrExit(data_offset, {data.addr_, key.GetDataSize()});
369 return ErrorCode::OK;
370}
371
372size_t DatabaseRawSequential::SearchKey(const char* name)
373{
374 if (IsBlockEmpty(BlockType::MAIN))
375 {
376 return 0;
377 }
378
379 size_t key_offset = LibXR::OffsetOf(&FlashInfo::key);
380 while (true)
381 {
382 if (KeyNameCompare(key_offset, name) == 0)
383 {
384 return key_offset;
385 }
386 if (!HasLastKey(key_offset))
387 {
388 break;
389 }
390 key_offset = GetNextKey(key_offset);
391 }
392 return 0;
393}
只读原始数据视图 / Immutable raw data view
键的基类,存储键名及其数据 Base class for keys, storing key name and associated data.
Definition interface.hpp:31
RawData raw_data_
原始数据 / Raw data associated with the key.
Definition interface.hpp:34
const char * name_
键名 / Key name.
Definition interface.hpp:33
void Save()
保存当前缓冲区内容到 Flash Save the current buffer content to Flash.
ErrorCode Get(Database::KeyBase &key) override
获取数据库中的键值 Retrieve the key's value from the database.
void Init()
初始化数据库存储区,确保主备块正确 Initialize database storage, ensuring main and backup blocks are valid.
void Restore()
还原存储数据,清空 Flash 区域 Restore storage data, clearing Flash memory area.
void Load()
从 Flash 加载数据到缓冲区 Load data from Flash into the buffer.
DatabaseRawSequential(Flash &flash, size_t max_buffer_size=256)
构造函数,初始化 Flash 存储和缓冲区 Constructor initializing Flash storage and buffer.
抽象基类,表示闪存接口。 Abstract base class representing a flash memory interface.
Definition flash.hpp:32
size_t Size() const
获取闪存存储区域的大小 / Returns the size of the flash memory area.
Definition flash.hpp:90
virtual ErrorCode Erase(size_t offset, size_t size)=0
擦除闪存的指定区域 / Erases a section of the flash memory.
virtual ErrorCode Write(size_t offset, ConstRawData data)=0
向闪存写入数据 / Writes data to the flash memory.
virtual ErrorCode Read(size_t offset, RawData data)
从闪存中读取数据 / Reads data from the flash memory.
Definition flash.cpp:14
size_t MinEraseSize() const
获取最小可擦除块大小(字节)。 Returns the minimum erasable block size in bytes.
Definition flash.hpp:76
static void FastSet(void *dst, uint8_t value, size_t size)
快速内存填充 / Fast memory fill
static void FastCopy(void *dst, const void *src, size_t size)
快速内存拷贝 / Fast memory copy
可写原始数据视图 / Mutable raw data view
size_t size_
数据字节数 / Data size in bytes
void * addr_
数据起始地址 / Data start address
LibXR 命名空间 / LibXR namespace.
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举 / Defines an enumeration for error codes
@ NOT_FOUND
未找到 / Not found
@ FAILED
操作失败 / Operation failed
@ FULL
已满 / Full
@ OK
操作成功 / Operation successful
size_t OffsetOf(MemberType OwnerType::*member) noexcept
计算成员在宿主对象中的偏移量 Computes the offset of a member within the owning object
Definition libxr_def.hpp:95
Flash 存储的块信息结构 Structure representing a Flash storage block.
Definition layout.hpp:177
KeyInfo key
Definition layout.hpp:199
uint32_t header
Flash 块头签名 / Flash block-header signature.
Definition layout.hpp:195
键信息结构,存储键的元数据 Structure containing key metadata.
Definition layout.hpp:119
uint32_t GetDataSize() const
获取数据字节数 / Get the payload size in bytes.
Definition layout.hpp:167
uint8_t GetNameLength() const
获取键名长度 / Get the key name length.
Definition layout.hpp:152