1
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
108
109
110
111
114
115
116
117
120
121
122
123
126
127
131
132
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
159
160
161
162
163
164
165
166
167
168
169
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
199
200
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
/* ... */
#ifndef nvs_page_hpp
#define nvs_page_hpp
#include "nvs.h"
#include "nvs_types.hpp"
#include <cstdint>
#include <type_traits>
#include <cstring>
#include <algorithm>
#include "compressed_enum_table.hpp"
#include "intrusive_list.h"
#include "nvs_item_hash_list.hpp"
#include "nvs_memory_management.hpp"
#include "partition.hpp"
#include "nvs_constants.h"12 includes
namespace nvs
{
class Page : public intrusive_list_node<Page>, public ExceptionlessAllocatable
{
public:
static const uint32_t PSB_INIT = NVS_CONST_PSB_INIT;
static const uint32_t PSB_FULL = NVS_CONST_PSB_FULL;
static const uint32_t PSB_FREEING = NVS_CONST_PSB_FREEING;
static const uint32_t PSB_CORRUPT = NVS_CONST_PSB_CORRUPT;
static const uint32_t ESB_WRITTEN = NVS_CONST_ESB_WRITTEN;
static const uint32_t ESB_ERASED = NVS_CONST_ESB_ERASED;
static const uint32_t SEC_SIZE;
static const size_t ENTRY_SIZE = NVS_CONST_ENTRY_SIZE;
static const size_t ENTRY_COUNT = NVS_CONST_ENTRY_COUNT;
static const uint32_t INVALID_ENTRY = NVS_CONST_INVALID_ENTRY;
static const size_t CHUNK_MAX_SIZE = ENTRY_SIZE * (ENTRY_COUNT - 1);
static const uint8_t NS_INDEX = NVS_CONST_NS_INDEX;
static const uint8_t NS_ANY = NVS_CONST_NS_ANY;
static const uint8_t CHUNK_ANY = Item::CHUNK_ANY;
static const uint8_t NVS_VERSION = NVS_CONST_NVS_VERSION;
enum class PageState : uint32_t {
UNINITIALIZED = NVS_CONST_PAGE_STATE_UNINITIALIZED,
ACTIVE = NVS_CONST_PAGE_STATE_ACTIVE,
FULL = NVS_CONST_PAGE_STATE_FULL,
FREEING = NVS_CONST_PAGE_STATE_FREEING,
CORRUPT = NVS_CONST_PAGE_STATE_CORRUPT,
INVALID = 0
}{...};
Page();
PageState state() const
{
return mState;
}{...}
esp_err_t load(Partition *partition, uint32_t sectorNumber);
esp_err_t getSeqNumber(uint32_t& seqNumber) const;
esp_err_t setSeqNumber(uint32_t seqNumber);
esp_err_t setVersion(uint8_t version);
esp_err_t writeItem(uint8_t nsIndex, ItemType datatype, const char* key, const void* data, size_t dataSize, uint8_t chunkIdx = CHUNK_ANY);
esp_err_t readItem(uint8_t nsIndex, ItemType datatype, const char* key, void* data, size_t dataSize, uint8_t chunkIdx = CHUNK_ANY, VerOffset chunkStart = VerOffset::VER_ANY);
esp_err_t cmpItem(uint8_t nsIndex, ItemType datatype, const char* key, const void* data, size_t dataSize, uint8_t chunkIdx = CHUNK_ANY, VerOffset chunkStart = VerOffset::VER_ANY);
esp_err_t eraseItem(uint8_t nsIndex, ItemType datatype, const char* key, uint8_t chunkIdx = CHUNK_ANY, VerOffset chunkStart = VerOffset::VER_ANY);
esp_err_t findItem(uint8_t nsIndex, ItemType datatype, const char* key, uint8_t chunkIdx = CHUNK_ANY, VerOffset chunkStart = VerOffset::VER_ANY);
esp_err_t findItem(uint8_t nsIndex, ItemType datatype, const char* key, size_t &itemIndex, Item& item, uint8_t chunkIdx = CHUNK_ANY, VerOffset chunkStart = VerOffset::VER_ANY);
esp_err_t eraseEntryAndSpan(size_t index);
template<typename T>
esp_err_t writeItem(uint8_t nsIndex, const char* key, const T& value)
{
return writeItem(nsIndex, itemTypeOf(value), key, &value, sizeof(value));
}{...}
template<typename T>
esp_err_t readItem(uint8_t nsIndex, const char* key, T& value)
{
return readItem(nsIndex, itemTypeOf(value), key, &value, sizeof(value));
}{...}
template<typename T>
esp_err_t cmpItem(uint8_t nsIndex, const char* key, const T& value)
{
return cmpItem(nsIndex, itemTypeOf(value), key, &value, sizeof(value));
}{...}
template<typename T>
esp_err_t eraseItem(uint8_t nsIndex, const char* key)
{
return eraseItem(nsIndex, itemTypeOf<T>(), key);
}{...}
size_t getUsedEntryCount() const
{
return mUsedEntryCount;
}{...}
size_t getErasedEntryCount() const
{
return mErasedEntryCount;
}{...}
size_t getVarDataTailroom() const ;
esp_err_t markFull();
esp_err_t markFreeing();
esp_err_t copyItems(Page& other);
esp_err_t erase();
void debugDump() const;
esp_err_t calcEntries(nvs_stats_t &nvsStats);
...
protected:
class Header
{
public:
Header()
{
std::fill_n(mReserved, sizeof(mReserved)/sizeof(mReserved[0]), UINT8_MAX);
}{ ... }
PageState mState;
uint32_t mSeqNumber;
uint8_t mVersion;
uint8_t mReserved[19];
uint32_t mCrc32;
uint32_t calculateCrc32();...
}{ ... };
enum class EntryState {
EMPTY = NVS_CONST_ENTRY_STATE_EMPTY,
WRITTEN = NVS_CONST_ENTRY_STATE_WRITTEN,
ERASED = NVS_CONST_ENTRY_STATE_ERASED,
ILLEGAL = NVS_CONST_ENTRY_STATE_ILLEGAL,
INVALID = NVS_CONST_ENTRY_STATE_INVALID
}{ ... };
esp_err_t mLoadEntryTable();
esp_err_t initialize();
esp_err_t alterEntryState(size_t index, EntryState state);
esp_err_t alterEntryRangeState(size_t begin, size_t end, EntryState state);
esp_err_t alterPageState(PageState state);
esp_err_t readEntry(size_t index, Item& dst) const;
esp_err_t writeEntry(const Item& item);
esp_err_t writeEntryData(const uint8_t* data, size_t size);
esp_err_t updateFirstUsedEntry(size_t index, size_t span);
static constexpr size_t getAlignmentForType(ItemType type)
{
return static_cast<uint8_t>(type) & 0x0f;
}{ ... }
esp_err_t getEntryAddress(size_t entry, uint32_t *address) const
{
NVS_ASSERT_OR_RETURN(entry < ENTRY_COUNT, ESP_FAIL);
*address = mBaseAddress + ENTRY_DATA_OFFSET + static_cast<uint32_t>(entry) * ENTRY_SIZE;
return ESP_OK;
}{...}
static const char* pageStateToName(PageState ps);
...
protected:
uint32_t mBaseAddress = 0;
PageState mState = PageState::INVALID;
uint32_t mSeqNumber = UINT32_MAX;
uint8_t mVersion = NVS_VERSION;
typedef CompressedEnumTable<EntryState, 2, ENTRY_COUNT> TEntryTable;
TEntryTable mEntryTable;
size_t mNextFreeEntry = INVALID_ENTRY;
size_t mFirstUsedEntry = INVALID_ENTRY;
uint16_t mUsedEntryCount = 0;
uint16_t mErasedEntryCount = 0;
/* ... */
HashList mHashList;
Partition *mPartition;
static const uint32_t HEADER_OFFSET = NVS_CONST_PAGE_HEADER_OFFSET;
static const uint32_t ENTRY_TABLE_OFFSET = NVS_CONST_PAGE_ENTRY_TABLE_OFFSET;
static const uint32_t ENTRY_DATA_OFFSET = NVS_CONST_PAGE_ENTRY_DATA_OFFSET;
static_assert(sizeof(Header) == 32, "header size must be 32 bytes");
static_assert(ENTRY_TABLE_OFFSET % 32 == 0, "entry table offset should be aligned");
static_assert(ENTRY_DATA_OFFSET % 32 == 0, "entry data offset should be aligned");
...
}{...};
}{...}
/* ... */
#endif