1 // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #ifndef nvs_storage_hpp
15 #define nvs_storage_hpp
16 
17 #include <memory>
18 #include <unordered_map>
19 #include "nvs.hpp"
20 #include "nvs_types.hpp"
21 #include "nvs_page.hpp"
22 #include "nvs_pagemanager.hpp"
23 #include "partition.hpp"
24 
25 //extern void dumpBytes(const uint8_t* data, size_t count);
26 
27 namespace nvs
28 {
29 
30 class Storage : public intrusive_list_node<Storage>
31 {
32     enum class StorageState : uint32_t {
33         INVALID,
34         ACTIVE,
35     };
36 
37     struct NamespaceEntry : public intrusive_list_node<NamespaceEntry> {
38     public:
39         char mName[Item::MAX_KEY_LENGTH + 1];
40         uint8_t mIndex;
41     };
42 
43     typedef intrusive_list<NamespaceEntry> TNamespaces;
44 
45     struct UsedPageNode: public intrusive_list_node<UsedPageNode> {
46         public: Page* mPage;
47     };
48 
49     typedef intrusive_list<UsedPageNode> TUsedPageList;
50 
51     struct BlobIndexNode: public intrusive_list_node<BlobIndexNode> {
52         public:
53             char key[Item::MAX_KEY_LENGTH + 1];
54             uint8_t nsIndex;
55             uint8_t chunkCount;
56             VerOffset chunkStart;
57     };
58 
59     typedef intrusive_list<BlobIndexNode> TBlobIndexList;
60 
61 public:
62     ~Storage();
63 
Storage(Partition * partition)64     Storage(Partition *partition) : mPartition(partition) {
65         if (partition == nullptr) {
66             abort();
67         }
68     };
69 
70     esp_err_t init(uint32_t baseSector, uint32_t sectorCount);
71 
72     bool isValid() const;
73 
74     esp_err_t createOrOpenNamespace(const char* nsName, bool canCreate, uint8_t& nsIndex);
75 
76     esp_err_t writeItem(uint8_t nsIndex, ItemType datatype, const char* key, const void* data, size_t dataSize);
77 
78     esp_err_t readItem(uint8_t nsIndex, ItemType datatype, const char* key, void* data, size_t dataSize);
79 
80     esp_err_t getItemDataSize(uint8_t nsIndex, ItemType datatype, const char* key, size_t& dataSize);
81 
82     esp_err_t eraseItem(uint8_t nsIndex, ItemType datatype, const char* key);
83 
84     template<typename T>
writeItem(uint8_t nsIndex,const char * key,const T & value)85     esp_err_t writeItem(uint8_t nsIndex, const char* key, const T& value)
86     {
87         return writeItem(nsIndex, itemTypeOf(value), key, &value, sizeof(value));
88     }
89 
90     template<typename T>
readItem(uint8_t nsIndex,const char * key,T & value)91     esp_err_t readItem(uint8_t nsIndex, const char* key, T& value)
92     {
93         return readItem(nsIndex, itemTypeOf(value), key, &value, sizeof(value));
94     }
95 
eraseItem(uint8_t nsIndex,const char * key)96     esp_err_t eraseItem(uint8_t nsIndex, const char* key)
97     {
98         return eraseItem(nsIndex, ItemType::ANY, key);
99     }
100 
101     esp_err_t eraseNamespace(uint8_t nsIndex);
102 
getPart() const103     const Partition *getPart() const
104     {
105         return mPartition;
106     }
107 
getPartName() const108     const char *getPartName() const
109     {
110         return mPartition->get_partition_name();
111     }
112 
getBaseSector()113     uint32_t getBaseSector()
114     {
115         return mPageManager.getBaseSector();
116     }
117 
118     esp_err_t writeMultiPageBlob(uint8_t nsIndex, const char* key, const void* data, size_t dataSize, VerOffset chunkStart);
119 
120     esp_err_t readMultiPageBlob(uint8_t nsIndex, const char* key, void* data, size_t dataSize);
121 
122     esp_err_t cmpMultiPageBlob(uint8_t nsIndex, const char* key, const void* data, size_t dataSize);
123 
124     esp_err_t eraseMultiPageBlob(uint8_t nsIndex, const char* key, VerOffset chunkStart = VerOffset::VER_ANY);
125 
126     void debugDump();
127 
128     void debugCheck();
129 
130     esp_err_t fillStats(nvs_stats_t& nvsStats);
131 
132     esp_err_t calcEntriesInNamespace(uint8_t nsIndex, size_t& usedEntries);
133 
134     bool findEntry(nvs_opaque_iterator_t*, const char* name);
135 
136     bool nextEntry(nvs_opaque_iterator_t* it);
137 
138 protected:
139 
getCurrentPage()140     Page& getCurrentPage()
141     {
142         return mPageManager.back();
143     }
144 
145     void clearNamespaces();
146 
147     esp_err_t populateBlobIndices(TBlobIndexList&);
148 
149     void eraseOrphanDataBlobs(TBlobIndexList&);
150 
151     void fillEntryInfo(Item &item, nvs_entry_info_t &info);
152 
153     esp_err_t findItem(uint8_t nsIndex, ItemType datatype, const char* key, Page* &page, Item& item, uint8_t chunkIdx = Page::CHUNK_ANY, VerOffset chunkStart = VerOffset::VER_ANY);
154 
155 protected:
156     Partition *mPartition;
157     size_t mPageCount;
158     PageManager mPageManager;
159     TNamespaces mNamespaces;
160     CompressedEnumTable<bool, 1, 256> mNamespaceUsage;
161     StorageState mState = StorageState::INVALID;
162 };
163 
164 } // namespace nvs
165 
166 struct nvs_opaque_iterator_t
167 {
168     nvs_type_t type;
169     uint8_t nsIndex;
170     size_t entryIndex;
171     nvs::Storage *storage;
172     intrusive_list<nvs::Page>::iterator page;
173     nvs_entry_info_t entry_info;
174 };
175 
176 #endif /* nvs_storage_hpp */
177