nvs_api.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  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. // http://www.apache.org/licenses/LICENSE-2.0
  7. //
  8. // Unless required by applicable law or agreed to in writing, software
  9. // distributed under the License is distributed on an "AS IS" BASIS,
  10. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. #include "nvs.hpp"
  14. #include "nvs_flash.h"
  15. #include "nvs_storage.hpp"
  16. #include "intrusive_list.h"
  17. #include "nvs_platform.hpp"
  18. #include "esp_partition.h"
  19. #include "sdkconfig.h"
  20. #ifdef ESP_PLATFORM
  21. // Uncomment this line to force output from this module
  22. // #define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
  23. #include "esp_log.h"
  24. static const char* TAG = "nvs";
  25. #else
  26. #define ESP_LOGD(...)
  27. #endif
  28. extern "C" void nvs_dump(const char *partName);
  29. extern "C" esp_err_t nvs_flash_init_custom(const char *partName, uint32_t baseSector, uint32_t sectorCount);
  30. class HandleEntry : public intrusive_list_node<HandleEntry>
  31. {
  32. static uint32_t s_nvs_next_handle;
  33. public:
  34. HandleEntry() {}
  35. HandleEntry(bool readOnly, uint8_t nsIndex, nvs::Storage* StoragePtr) :
  36. mHandle(++s_nvs_next_handle), // Begin the handle value with 1
  37. mReadOnly(readOnly),
  38. mNsIndex(nsIndex),
  39. mStoragePtr(StoragePtr)
  40. {
  41. }
  42. nvs_handle mHandle;
  43. uint8_t mReadOnly;
  44. uint8_t mNsIndex;
  45. nvs::Storage* mStoragePtr;
  46. };
  47. #ifdef ESP_PLATFORM
  48. SemaphoreHandle_t nvs::Lock::mSemaphore = NULL;
  49. #endif
  50. using namespace std;
  51. using namespace nvs;
  52. static intrusive_list<HandleEntry> s_nvs_handles;
  53. uint32_t HandleEntry::s_nvs_next_handle;
  54. static intrusive_list<nvs::Storage> s_nvs_storage_list;
  55. static nvs::Storage* lookup_storage_from_name(const char *name)
  56. {
  57. auto it = find_if(begin(s_nvs_storage_list), end(s_nvs_storage_list), [=](Storage& e) -> bool {
  58. return (strcmp(e.getPartName(), name) == 0);
  59. });
  60. if (it == end(s_nvs_storage_list)) {
  61. return NULL;
  62. }
  63. return it;
  64. }
  65. extern "C" void nvs_dump(const char *partName)
  66. {
  67. Lock lock;
  68. nvs::Storage* pStorage;
  69. pStorage = lookup_storage_from_name(partName);
  70. if (pStorage == NULL) {
  71. return;
  72. }
  73. pStorage->debugDump();
  74. return;
  75. }
  76. extern "C" esp_err_t nvs_flash_init_custom(const char *partName, uint32_t baseSector, uint32_t sectorCount)
  77. {
  78. ESP_LOGD(TAG, "nvs_flash_init_custom partition=%s start=%d count=%d", partName, baseSector, sectorCount);
  79. nvs::Storage* new_storage = NULL;
  80. nvs::Storage* storage = lookup_storage_from_name(partName);
  81. if (storage == NULL) {
  82. new_storage = new nvs::Storage((const char *)partName);
  83. storage = new_storage;
  84. }
  85. esp_err_t err = storage->init(baseSector, sectorCount);
  86. if (new_storage != NULL) {
  87. if (err == ESP_OK) {
  88. s_nvs_storage_list.push_back(new_storage);
  89. } else {
  90. delete new_storage;
  91. }
  92. }
  93. return err;
  94. }
  95. #ifdef ESP_PLATFORM
  96. extern "C" esp_err_t nvs_flash_init_partition(const char *part_name)
  97. {
  98. Lock::init();
  99. Lock lock;
  100. nvs::Storage* mStorage;
  101. mStorage = lookup_storage_from_name(part_name);
  102. if (mStorage) {
  103. return ESP_OK;
  104. }
  105. const esp_partition_t* partition = esp_partition_find_first(
  106. ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, part_name);
  107. if (partition == NULL) {
  108. return ESP_ERR_NOT_FOUND;
  109. }
  110. return nvs_flash_init_custom(part_name, partition->address / SPI_FLASH_SEC_SIZE,
  111. partition->size / SPI_FLASH_SEC_SIZE);
  112. }
  113. extern "C" esp_err_t nvs_flash_init(void)
  114. {
  115. return nvs_flash_init_partition(NVS_DEFAULT_PART_NAME);
  116. }
  117. extern "C" esp_err_t nvs_flash_erase_partition(const char *part_name)
  118. {
  119. const esp_partition_t* partition = esp_partition_find_first(
  120. ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, part_name);
  121. if (partition == NULL) {
  122. return ESP_ERR_NOT_FOUND;
  123. }
  124. return esp_partition_erase_range(partition, 0, partition->size);
  125. }
  126. extern "C" esp_err_t nvs_flash_erase()
  127. {
  128. return nvs_flash_erase_partition(NVS_DEFAULT_PART_NAME);
  129. }
  130. #endif // ESP_PLATFORM
  131. extern "C" esp_err_t nvs_flash_deinit_partition(const char* partition_name)
  132. {
  133. Lock::init();
  134. Lock lock;
  135. nvs::Storage* storage = lookup_storage_from_name(partition_name);
  136. if (!storage) {
  137. return ESP_ERR_NVS_NOT_INITIALIZED;
  138. }
  139. /* Clean up handles related to the storage being deinitialized */
  140. auto it = s_nvs_handles.begin();
  141. auto next = it;
  142. while(it != s_nvs_handles.end()) {
  143. next++;
  144. if (it->mStoragePtr == storage) {
  145. ESP_LOGD(TAG, "Deleting handle %d (ns=%d) related to partition \"%s\" (missing call to nvs_close?)",
  146. it->mHandle, it->mNsIndex, partition_name);
  147. s_nvs_handles.erase(it);
  148. delete static_cast<HandleEntry*>(it);
  149. }
  150. it = next;
  151. }
  152. /* Finally delete the storage itself */
  153. s_nvs_storage_list.erase(storage);
  154. delete storage;
  155. return ESP_OK;
  156. }
  157. extern "C" esp_err_t nvs_flash_deinit(void)
  158. {
  159. return nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME);
  160. }
  161. static esp_err_t nvs_find_ns_handle(nvs_handle handle, HandleEntry& entry)
  162. {
  163. auto it = find_if(begin(s_nvs_handles), end(s_nvs_handles), [=](HandleEntry& e) -> bool {
  164. return e.mHandle == handle;
  165. });
  166. if (it == end(s_nvs_handles)) {
  167. return ESP_ERR_NVS_INVALID_HANDLE;
  168. }
  169. entry = *it;
  170. return ESP_OK;
  171. }
  172. extern "C" esp_err_t nvs_open_from_partition(const char *part_name, const char* name, nvs_open_mode open_mode, nvs_handle *out_handle)
  173. {
  174. Lock lock;
  175. ESP_LOGD(TAG, "%s %s %d", __func__, name, open_mode);
  176. uint8_t nsIndex;
  177. nvs::Storage* sHandle;
  178. sHandle = lookup_storage_from_name(part_name);
  179. if (sHandle == NULL) {
  180. return ESP_ERR_NVS_PART_NOT_FOUND;
  181. }
  182. esp_err_t err = sHandle->createOrOpenNamespace(name, open_mode == NVS_READWRITE, nsIndex);
  183. if (err != ESP_OK) {
  184. return err;
  185. }
  186. HandleEntry *handle_entry = new HandleEntry(open_mode==NVS_READONLY, nsIndex, sHandle);
  187. s_nvs_handles.push_back(handle_entry);
  188. *out_handle = handle_entry->mHandle;
  189. return ESP_OK;
  190. }
  191. extern "C" esp_err_t nvs_open(const char* name, nvs_open_mode open_mode, nvs_handle *out_handle)
  192. {
  193. if (s_nvs_storage_list.size() == 0) {
  194. return ESP_ERR_NVS_NOT_INITIALIZED;
  195. }
  196. return nvs_open_from_partition(NVS_DEFAULT_PART_NAME, name, open_mode, out_handle);
  197. }
  198. extern "C" void nvs_close(nvs_handle handle)
  199. {
  200. Lock lock;
  201. ESP_LOGD(TAG, "%s %d", __func__, handle);
  202. auto it = find_if(begin(s_nvs_handles), end(s_nvs_handles), [=](HandleEntry& e) -> bool {
  203. return e.mHandle == handle;
  204. });
  205. if (it == end(s_nvs_handles)) {
  206. return;
  207. }
  208. s_nvs_handles.erase(it);
  209. delete static_cast<HandleEntry*>(it);
  210. }
  211. extern "C" esp_err_t nvs_erase_key(nvs_handle handle, const char* key)
  212. {
  213. Lock lock;
  214. ESP_LOGD(TAG, "%s %s\r\n", __func__, key);
  215. HandleEntry entry;
  216. auto err = nvs_find_ns_handle(handle, entry);
  217. if (err != ESP_OK) {
  218. return err;
  219. }
  220. if (entry.mReadOnly) {
  221. return ESP_ERR_NVS_READ_ONLY;
  222. }
  223. return entry.mStoragePtr->eraseItem(entry.mNsIndex, key);
  224. }
  225. extern "C" esp_err_t nvs_erase_all(nvs_handle handle)
  226. {
  227. Lock lock;
  228. ESP_LOGD(TAG, "%s\r\n", __func__);
  229. HandleEntry entry;
  230. auto err = nvs_find_ns_handle(handle, entry);
  231. if (err != ESP_OK) {
  232. return err;
  233. }
  234. if (entry.mReadOnly) {
  235. return ESP_ERR_NVS_READ_ONLY;
  236. }
  237. return entry.mStoragePtr->eraseNamespace(entry.mNsIndex);
  238. }
  239. template<typename T>
  240. static esp_err_t nvs_set(nvs_handle handle, const char* key, T value)
  241. {
  242. Lock lock;
  243. ESP_LOGD(TAG, "%s %s %d %d", __func__, key, sizeof(T), (uint32_t) value);
  244. HandleEntry entry;
  245. auto err = nvs_find_ns_handle(handle, entry);
  246. if (err != ESP_OK) {
  247. return err;
  248. }
  249. if (entry.mReadOnly) {
  250. return ESP_ERR_NVS_READ_ONLY;
  251. }
  252. return entry.mStoragePtr->writeItem(entry.mNsIndex, key, value);
  253. }
  254. extern "C" esp_err_t nvs_set_i8 (nvs_handle handle, const char* key, int8_t value)
  255. {
  256. return nvs_set(handle, key, value);
  257. }
  258. extern "C" esp_err_t nvs_set_u8 (nvs_handle handle, const char* key, uint8_t value)
  259. {
  260. return nvs_set(handle, key, value);
  261. }
  262. extern "C" esp_err_t nvs_set_i16 (nvs_handle handle, const char* key, int16_t value)
  263. {
  264. return nvs_set(handle, key, value);
  265. }
  266. extern "C" esp_err_t nvs_set_u16 (nvs_handle handle, const char* key, uint16_t value)
  267. {
  268. return nvs_set(handle, key, value);
  269. }
  270. extern "C" esp_err_t nvs_set_i32 (nvs_handle handle, const char* key, int32_t value)
  271. {
  272. return nvs_set(handle, key, value);
  273. }
  274. extern "C" esp_err_t nvs_set_u32 (nvs_handle handle, const char* key, uint32_t value)
  275. {
  276. return nvs_set(handle, key, value);
  277. }
  278. extern "C" esp_err_t nvs_set_i64 (nvs_handle handle, const char* key, int64_t value)
  279. {
  280. return nvs_set(handle, key, value);
  281. }
  282. extern "C" esp_err_t nvs_set_u64 (nvs_handle handle, const char* key, uint64_t value)
  283. {
  284. return nvs_set(handle, key, value);
  285. }
  286. extern "C" esp_err_t nvs_commit(nvs_handle handle)
  287. {
  288. Lock lock;
  289. // no-op for now, to be used when intermediate cache is added
  290. HandleEntry entry;
  291. return nvs_find_ns_handle(handle, entry);
  292. }
  293. extern "C" esp_err_t nvs_set_str(nvs_handle handle, const char* key, const char* value)
  294. {
  295. Lock lock;
  296. ESP_LOGD(TAG, "%s %s %s", __func__, key, value);
  297. HandleEntry entry;
  298. auto err = nvs_find_ns_handle(handle, entry);
  299. if (err != ESP_OK) {
  300. return err;
  301. }
  302. return entry.mStoragePtr->writeItem(entry.mNsIndex, nvs::ItemType::SZ, key, value, strlen(value) + 1);
  303. }
  304. extern "C" esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void* value, size_t length)
  305. {
  306. Lock lock;
  307. ESP_LOGD(TAG, "%s %s %d", __func__, key, length);
  308. HandleEntry entry;
  309. auto err = nvs_find_ns_handle(handle, entry);
  310. if (err != ESP_OK) {
  311. return err;
  312. }
  313. return entry.mStoragePtr->writeItem(entry.mNsIndex, nvs::ItemType::BLOB, key, value, length);
  314. }
  315. template<typename T>
  316. static esp_err_t nvs_get(nvs_handle handle, const char* key, T* out_value)
  317. {
  318. Lock lock;
  319. ESP_LOGD(TAG, "%s %s %d", __func__, key, sizeof(T));
  320. HandleEntry entry;
  321. auto err = nvs_find_ns_handle(handle, entry);
  322. if (err != ESP_OK) {
  323. return err;
  324. }
  325. return entry.mStoragePtr->readItem(entry.mNsIndex, key, *out_value);
  326. }
  327. extern "C" esp_err_t nvs_get_i8 (nvs_handle handle, const char* key, int8_t* out_value)
  328. {
  329. return nvs_get(handle, key, out_value);
  330. }
  331. extern "C" esp_err_t nvs_get_u8 (nvs_handle handle, const char* key, uint8_t* out_value)
  332. {
  333. return nvs_get(handle, key, out_value);
  334. }
  335. extern "C" esp_err_t nvs_get_i16 (nvs_handle handle, const char* key, int16_t* out_value)
  336. {
  337. return nvs_get(handle, key, out_value);
  338. }
  339. extern "C" esp_err_t nvs_get_u16 (nvs_handle handle, const char* key, uint16_t* out_value)
  340. {
  341. return nvs_get(handle, key, out_value);
  342. }
  343. extern "C" esp_err_t nvs_get_i32 (nvs_handle handle, const char* key, int32_t* out_value)
  344. {
  345. return nvs_get(handle, key, out_value);
  346. }
  347. extern "C" esp_err_t nvs_get_u32 (nvs_handle handle, const char* key, uint32_t* out_value)
  348. {
  349. return nvs_get(handle, key, out_value);
  350. }
  351. extern "C" esp_err_t nvs_get_i64 (nvs_handle handle, const char* key, int64_t* out_value)
  352. {
  353. return nvs_get(handle, key, out_value);
  354. }
  355. extern "C" esp_err_t nvs_get_u64 (nvs_handle handle, const char* key, uint64_t* out_value)
  356. {
  357. return nvs_get(handle, key, out_value);
  358. }
  359. static esp_err_t nvs_get_str_or_blob(nvs_handle handle, nvs::ItemType type, const char* key, void* out_value, size_t* length)
  360. {
  361. Lock lock;
  362. ESP_LOGD(TAG, "%s %s", __func__, key);
  363. HandleEntry entry;
  364. auto err = nvs_find_ns_handle(handle, entry);
  365. if (err != ESP_OK) {
  366. return err;
  367. }
  368. size_t dataSize;
  369. err = entry.mStoragePtr->getItemDataSize(entry.mNsIndex, type, key, dataSize);
  370. if (err != ESP_OK) {
  371. return err;
  372. }
  373. if (length == nullptr) {
  374. return ESP_ERR_NVS_INVALID_LENGTH;
  375. } else if (out_value == nullptr) {
  376. *length = dataSize;
  377. return ESP_OK;
  378. } else if (*length < dataSize) {
  379. *length = dataSize;
  380. return ESP_ERR_NVS_INVALID_LENGTH;
  381. }
  382. *length = dataSize;
  383. return entry.mStoragePtr->readItem(entry.mNsIndex, type, key, out_value, dataSize);
  384. }
  385. extern "C" esp_err_t nvs_get_str(nvs_handle handle, const char* key, char* out_value, size_t* length)
  386. {
  387. return nvs_get_str_or_blob(handle, nvs::ItemType::SZ, key, out_value, length);
  388. }
  389. extern "C" esp_err_t nvs_get_blob(nvs_handle handle, const char* key, void* out_value, size_t* length)
  390. {
  391. return nvs_get_str_or_blob(handle, nvs::ItemType::BLOB, key, out_value, length);
  392. }
  393. extern "C" esp_err_t nvs_get_stats(const char* part_name, nvs_stats_t* nvs_stats)
  394. {
  395. Lock lock;
  396. nvs::Storage* pStorage;
  397. if (nvs_stats == NULL) {
  398. return ESP_ERR_INVALID_ARG;
  399. }
  400. nvs_stats->used_entries = 0;
  401. nvs_stats->free_entries = 0;
  402. nvs_stats->total_entries = 0;
  403. nvs_stats->namespace_count = 0;
  404. pStorage = lookup_storage_from_name((part_name == NULL) ? NVS_DEFAULT_PART_NAME : part_name);
  405. if (pStorage == NULL) {
  406. return ESP_ERR_NVS_NOT_INITIALIZED;
  407. }
  408. if(!pStorage->isValid()){
  409. return ESP_ERR_NVS_INVALID_STATE;
  410. }
  411. return pStorage->fillStats(*nvs_stats);
  412. }
  413. extern "C" esp_err_t nvs_get_used_entry_count(nvs_handle handle, size_t* used_entries)
  414. {
  415. Lock lock;
  416. if(used_entries == NULL){
  417. return ESP_ERR_INVALID_ARG;
  418. }
  419. *used_entries = 0;
  420. HandleEntry entry;
  421. auto err = nvs_find_ns_handle(handle, entry);
  422. if (err != ESP_OK) {
  423. return err;
  424. }
  425. size_t used_entry_count;
  426. err = entry.mStoragePtr->calcEntriesInNamespace(entry.mNsIndex, used_entry_count);
  427. if(err == ESP_OK){
  428. *used_entries = used_entry_count;
  429. }
  430. return err;
  431. }