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