From 652607b9a8fdedc4b8c331dfdfa2611709b160d7 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Fri, 1 Jun 2018 11:26:33 +0800 Subject: [PATCH 1/2] feat(util): Bring esp_err.h from esp-idf --- components/util/component.mk | 6 ++ components/util/include/esp_err.h | 116 ++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 components/util/component.mk create mode 100644 components/util/include/esp_err.h diff --git a/components/util/component.mk b/components/util/component.mk new file mode 100644 index 00000000..5b1ef9e2 --- /dev/null +++ b/components/util/component.mk @@ -0,0 +1,6 @@ +# +# Component Makefile +# + +COMPONENT_ADD_INCLUDEDIRS := include + diff --git a/components/util/include/esp_err.h b/components/util/include/esp_err.h new file mode 100644 index 00000000..b38a723b --- /dev/null +++ b/components/util/include/esp_err.h @@ -0,0 +1,116 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int32_t esp_err_t; + +/* Definitions for error constants. */ + +#define ESP_OK 0 +#define ESP_FAIL -1 + +#define ESP_ERR_NO_MEM 0x101 +#define ESP_ERR_INVALID_ARG 0x102 +#define ESP_ERR_INVALID_STATE 0x103 +#define ESP_ERR_INVALID_SIZE 0x104 +#define ESP_ERR_NOT_FOUND 0x105 +#define ESP_ERR_NOT_SUPPORTED 0x106 +#define ESP_ERR_TIMEOUT 0x107 +#define ESP_ERR_INVALID_RESPONSE 0x108 +#define ESP_ERR_INVALID_CRC 0x109 +#define ESP_ERR_INVALID_VERSION 0x10A +#define ESP_ERR_INVALID_MAC 0x10B + +#define ESP_ERR_WIFI_BASE 0x3000 /*!< Starting number of WiFi error codes */ +#define ESP_ERR_MESH_BASE 0x4000 /*!< Starting number of MESH error codes */ + +/** + * @brief Returns string for esp_err_t error codes + * + * This function finds the error code in a pre-generated lookup-table and + * returns its string representation. + * + * The function is generated by the Python script + * tools/gen_esp_err_to_name.py which should be run each time an esp_err_t + * error is modified, created or removed from the IDF project. + * + * @param code esp_err_t error code + * @return string error message + */ +const char *esp_err_to_name(esp_err_t code); + +/** + * @brief Returns string for esp_err_t and system error codes + * + * This function finds the error code in a pre-generated lookup-table of + * esp_err_t errors and returns its string representation. If the error code + * is not found then it is attempted to be found among system errors. + * + * The function is generated by the Python script + * tools/gen_esp_err_to_name.py which should be run each time an esp_err_t + * error is modified, created or removed from the IDF project. + * + * @param code esp_err_t error code + * @param[out] buf buffer where the error message should be written + * @param buflen Size of buffer buf. At most buflen bytes are written into the buf buffer (including the terminating null byte). + * @return buf containing the string error message + */ +const char *esp_err_to_name_r(esp_err_t code, char *buf, size_t buflen); + +void _esp_error_check_failed(esp_err_t rc, const char *file, int line, const char *function, const char *expression) __attribute__((noreturn)); + +#ifndef __ASSERT_FUNC +/* This won't happen on IDF, which defines __ASSERT_FUNC in assert.h, but it does happen when building on the host which + uses /usr/include/assert.h or equivalent. +*/ +#ifdef __ASSERT_FUNCTION +#define __ASSERT_FUNC __ASSERT_FUNCTION /* used in glibc assert.h */ +#else +#define __ASSERT_FUNC "??" +#endif +#endif + +/** + * Macro which can be used to check the error code, + * and terminate the program in case the code is not ESP_OK. + * Prints the error code, error location, and the failed statement to serial output. + * + * Disabled if assertions are disabled. + */ +#ifdef NDEBUG +#define ESP_ERROR_CHECK(x) do { \ + esp_err_t __err_rc = (x); \ + (void) sizeof(__err_rc); \ + } while(0); +#else +#define ESP_ERROR_CHECK(x) do { \ + esp_err_t __err_rc = (x); \ + if (__err_rc != ESP_OK) { \ + _esp_error_check_failed(__err_rc, __FILE__, __LINE__, \ + __ASSERT_FUNC, #x); \ + } \ + } while(0); +#endif + +#ifdef __cplusplus +} +#endif From 455eeb7499bf5818562c8792db165823a1ada6d9 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Fri, 1 Jun 2018 11:27:33 +0800 Subject: [PATCH 2/2] feat(nvs_flash): Bring nvs_flash header file from esp-idf Add empty function just to pass compiling. --- components/nvs_flash/.gitignore | 7 + components/nvs_flash/README.rst | 224 ++++++++++++ components/nvs_flash/component.mk | 7 + components/nvs_flash/include/nvs.h | 447 +++++++++++++++++++++++ components/nvs_flash/include/nvs_flash.h | 107 ++++++ components/nvs_flash/src/nvs.c | 165 +++++++++ components/nvs_flash/src/nvs_flash.c | 50 +++ 7 files changed, 1007 insertions(+) create mode 100644 components/nvs_flash/.gitignore create mode 100644 components/nvs_flash/README.rst create mode 100644 components/nvs_flash/component.mk create mode 100644 components/nvs_flash/include/nvs.h create mode 100644 components/nvs_flash/include/nvs_flash.h create mode 100644 components/nvs_flash/src/nvs.c create mode 100644 components/nvs_flash/src/nvs_flash.c diff --git a/components/nvs_flash/.gitignore b/components/nvs_flash/.gitignore new file mode 100644 index 00000000..3318e406 --- /dev/null +++ b/components/nvs_flash/.gitignore @@ -0,0 +1,7 @@ +test_nvs_host/test_nvs +test_nvs_host/coverage_report +test_nvs_host/coverage.info +**/*.gcno +**/*.gcda +**/*.gcov +**/*.o diff --git a/components/nvs_flash/README.rst b/components/nvs_flash/README.rst new file mode 100644 index 00000000..b58a0b2a --- /dev/null +++ b/components/nvs_flash/README.rst @@ -0,0 +1,224 @@ +Non-volatile storage library +============================ + +Introduction +------------ + +Non-volatile storage (NVS) library is designed to store key-value pairs in flash. This sections introduces some concepts used by NVS. + +Underlying storage +^^^^^^^^^^^^^^^^^^ + +Currently NVS uses a portion of main flash memory through ``spi_flash_{read|write|erase}`` APIs. The library uses the all the partitions with ``data`` type and ``nvs`` subtype. The application can choose to use the partition with label ``nvs`` through ``nvs_open`` API or any of the other partition by specifying its name through ``nvs_open_from_part`` API. + +Future versions of this library may add other storage backends to keep data in another flash chip (SPI or I2C), RTC, FRAM, etc. + +.. note:: if an NVS partition is truncated (for example, when the partition table layout is changed), its contents should be erased. ESP-IDF build system provides a ``make erase_flash`` target to erase all contents of the flash chip. + +.. note:: NVS works best for storing many small values, rather than a few large values of type 'string' and 'blob'. If storing large blobs or strings is required, consider using the facilities provided by the FAT filesystem on top of the wear levelling library. + +Keys and values +^^^^^^^^^^^^^^^ + +NVS operates on key-value pairs. Keys are ASCII strings, maximum key length is currently 15 characters. Values can have one of the following types: + +- integer types: ``uint8_t``, ``int8_t``, ``uint16_t``, ``int16_t``, ``uint32_t``, ``int32_t``, ``uint64_t``, ``int64_t`` +- zero-terminated string +- variable length binary data (blob) + +.. note:: + String and blob values are currently limited to 1984 bytes. For strings, this includes the null terminator. + +Additional types, such as ``float`` and ``double`` may be added later. + +Keys are required to be unique. Writing a value for a key which already exists behaves as follows: + +- if the new value is of the same type as old one, value is updated +- if the new value has different data type, an error is returned + +Data type check is also performed when reading a value. An error is returned if data type of read operation doesn’t match the data type of the value. + +Namespaces +^^^^^^^^^^ + +To mitigate potential conflicts in key names between different components, NVS assigns each key-value pair to one of namespaces. Namespace names follow the same rules as key names, i.e. 15 character maximum length. Namespace name is specified in the ``nvs_open`` or ``nvs_open_from_part`` call. This call returns an opaque handle, which is used in subsequent calls to ``nvs_read_*``, ``nvs_write_*``, and ``nvs_commit`` functions. This way, handle is associated with a namespace, and key names will not collide with same names in other namespaces. +Please note that the namespaces with same name in different NVS partitions are considered as separate namespaces. + +Security, tampering, and robustness +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +NVS library doesn't implement tamper prevention measures. It is possible for anyone with physical access to the flash chip to alter, erase, or add key-value pairs. + +NVS is not currently compatible with the ESP32 flash encryption system. + +The library does try to recover from conditions when flash memory is in an inconsistent state. In particular, one should be able to power off the device at any point and time and then power it back on. This should not result in loss of data, expect for the new key-value pair if it was being written at the moment of power off. The library should also be able to initialize properly with any random data present in flash memory. + +Internals +--------- + +Log of key-value pairs +^^^^^^^^^^^^^^^^^^^^^^ + +NVS stores key-value pairs sequentially, with new key-value pairs being added at the end. When a value of any given key has to be updated, new key-value pair is added at the end of the log and old key-value pair is marked as erased. + +Pages and entries +^^^^^^^^^^^^^^^^^ + +NVS library uses two main entities in its operation: pages and entries. Page is a logical structure which stores a portion of the overall log. Logical page corresponds to one physical sector of flash memory. Pages which are in use have a *sequence number* associated with them. Sequence numbers impose an ordering on pages. Higher sequence numbers correspond to pages which were created later. Each page can be in one of the following states: + +Empty/uninitialized + Flash storage for the page is empty (all bytes are ``0xff``). Page isn't used to store any data at this point and doesn’t have a sequence number. + +Active + Flash storage is initialized, page header has been written to flash, page has a valid sequence number. Page has some empty entries and data can be written there. At most one page can be in this state at any given moment. + +Full + Flash storage is in a consistent state and is filled with key-value pairs. + Writing new key-value pairs into this page is not possible. It is still possible to mark some key-value pairs as erased. + +Erasing + Non-erased key-value pairs are being moved into another page so that the current page can be erased. This is a transient state, i.e. page should never stay in this state when any API call returns. In case of a sudden power off, move-and-erase process will be completed upon next power on. + +Corrupted + Page header contains invalid data, and further parsing of page data was canceled. Any items previously written into this page will not be accessible. Corresponding flash sector will not be erased immediately, and will be kept along with sectors in *uninitialized* state for later use. This may be useful for debugging. + +Mapping from flash sectors to logical pages doesn't have any particular order. Library will inspect sequence numbers of pages found in each flash sector and organize pages in a list based on these numbers. + +:: + + +--------+ +--------+ +--------+ +--------+ + | Page 1 | | Page 2 | | Page 3 | | Page 4 | + | Full +---> | Full +---> | Active | | Empty | <- states + | #11 | | #12 | | #14 | | | <- sequence numbers + +---+----+ +----+---+ +----+---+ +---+----+ + | | | | + | | | | + | | | | + +---v------+ +-----v----+ +------v---+ +------v---+ + | Sector 3 | | Sector 0 | | Sector 2 | | Sector 1 | <- physical sectors + +----------+ +----------+ +----------+ +----------+ + +Structure of a page +^^^^^^^^^^^^^^^^^^^ + +For now we assume that flash sector size is 4096 bytes and that ESP32 flash encryption hardware operates on 32-byte blocks. It is possible to introduce some settings configurable at compile-time (e.g. via menuconfig) to accommodate flash chips with different sector sizes (although it is not clear if other components in the system, e.g. SPI flash driver and SPI flash cache can support these other sizes). + +Page consists of three parts: header, entry state bitmap, and entries themselves. To be compatible with ESP32 flash encryption, entry size is 32 bytes. For integer types, entry holds one key-value pair. For strings and blobs, an entry holds part of key-value pair (more on that in the entry structure description). + +The following diagram illustrates page structure. Numbers in parentheses indicate size of each part in bytes. :: + + +-----------+--------------+-------------+-----------+ + | State (4) | Seq. no. (4) | Unused (20) | CRC32 (4) | Header (32) + +-----------+--------------+-------------+-----------+ + | Entry state bitmap (32) | + +----------------------------------------------------+ + | Entry 0 (32) | + +----------------------------------------------------+ + | Entry 1 (32) | + +----------------------------------------------------+ + / / + / / + +----------------------------------------------------+ + | Entry 125 (32) | + +----------------------------------------------------+ + +Page header and entry state bitmap are always written to flash unencrypted. Entries are encrypted if flash encryption feature of the ESP32 is used. + +Page state values are defined in such a way that changing state is possible by writing 0 into some of the bits. Therefore it not necessary to erase the page to change page state, unless that is a change to *erased* state. + +CRC32 value in header is calculated over the part which doesn't include state value (bytes 4 to 28). Unused part is currently filled with ``0xff`` bytes. Future versions of the library may store format version there. + +The following sections describe structure of entry state bitmap and entry itself. + +Entry and entry state bitmap +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Each entry can be in one of the following three states. Each state is represented with two bits in the entry state bitmap. Final four bits in the bitmap (256 - 2 * 126) are unused. + +Empty (2'b11) + Nothing is written into the specific entry yet. It is in an uninitialized state (all bytes ``0xff``). + +Written (2'b10) + A key-value pair (or part of key-value pair which spans multiple entries) has been written into the entry. + +Erased (2'b00) + A key-value pair in this entry has been discarded. Contents of this entry will not be parsed anymore. + + +Structure of entry +^^^^^^^^^^^^^^^^^^ + +For values of primitive types (currently integers from 1 to 8 bytes long), entry holds one key-value pair. For string and blob types, entry holds part of the whole key-value pair. In case when a key-value pair spans multiple entries, all entries are stored in the same page. + +:: + + +--------+----------+----------+---------+-----------+---------------+----------+ + | NS (1) | Type (1) | Span (1) | Rsv (1) | CRC32 (4) | Key (16) | Data (8) | + +--------+----------+----------+---------+-----------+---------------+----------+ + + +--------------------------------+ + +-> Fixed length: | Data (8) | + | +--------------------------------+ + Data format ---+ + | +----------+---------+-----------+ + +-> Variable length: | Size (2) | Rsv (2) | CRC32 (4) | + +----------+---------+-----------+ + + +Individual fields in entry structure have the following meanings: + +NS + Namespace index for this entry. See section on namespaces implementation for explanation of this value. + +Type + One byte indicating data type of value. See ``ItemType`` enumeration in ``nvs_types.h`` for possible values. + +Span + Number of entries used by this key-value pair. For integer types, this is equal to 1. For strings and blobs this depends on value length. + +Rsv + Unused field, should be ``0xff``. + +CRC32 + Checksum calculated over all the bytes in this entry, except for the CRC32 field itself. + +Key + Zero-terminated ASCII string containing key name. Maximum string length is 15 bytes, excluding zero terminator. + +Data + For integer types, this field contains the value itself. If the value itself is shorter than 8 bytes it is padded to the right, with unused bytes filled with ``0xff``. For string and blob values, these 8 bytes hold additional data about the value, described next: + +Size + (Only for strings and blobs.) Size, in bytes, of actual data. For strings, this includes zero terminator. + +CRC32 + (Only for strings and blobs.) Checksum calculated over all bytes of data. + +Variable length values (strings and blobs) are written into subsequent entries, 32 bytes per entry. `Span` field of the first entry indicates how many entries are used. + + +Namespaces +^^^^^^^^^^ + +As mentioned above, each key-value pair belongs to one of the namespaces. Namespaces identifiers (strings) are stored as keys of key-value pairs in namespace with index 0. Values corresponding to these keys are indexes of these namespaces. + +:: + + +-------------------------------------------+ + | NS=0 Type=uint8_t Key="wifi" Value=1 | Entry describing namespace "wifi" + +-------------------------------------------+ + | NS=1 Type=uint32_t Key="channel" Value=6 | Key "channel" in namespace "wifi" + +-------------------------------------------+ + | NS=0 Type=uint8_t Key="pwm" Value=2 | Entry describing namespace "pwm" + +-------------------------------------------+ + | NS=2 Type=uint16_t Key="channel" Value=20 | Key "channel" in namespace "pwm" + +-------------------------------------------+ + + +Item hash list +^^^^^^^^^^^^^^ + +To reduce the number of reads performed from flash memory, each member of Page class maintains a list of pairs: (item index; item hash). This list makes searches much quicker. Instead of iterating over all entries, reading them from flash one at a time, ``Page::findItem`` first performs search for item hash in the hash list. This gives the item index within the page, if such an item exists. Due to a hash collision it is possible that a different item will be found. This is handled by falling back to iteration over items in flash. + +Each node in hash list contains a 24-bit hash and 8-bit item index. Hash is calculated based on item namespace and key name. CRC32 is used for calculation, result is truncated to 24 bits. To reduce overhead of storing 32-bit entries in a linked list, list is implemented as a doubly-linked list of arrays. Each array holds 29 entries, for the total size of 128 bytes, together with linked list pointers and 32-bit count field. Minimal amount of extra RAM useage per page is therefore 128 bytes, maximum is 640 bytes. + diff --git a/components/nvs_flash/component.mk b/components/nvs_flash/component.mk new file mode 100644 index 00000000..de18804a --- /dev/null +++ b/components/nvs_flash/component.mk @@ -0,0 +1,7 @@ +# +# Component Makefile +# + +COMPONENT_ADD_INCLUDEDIRS := include + +COMPONENT_SRCDIRS := source diff --git a/components/nvs_flash/include/nvs.h b/components/nvs_flash/include/nvs.h new file mode 100644 index 00000000..c58f62f9 --- /dev/null +++ b/components/nvs_flash/include/nvs.h @@ -0,0 +1,447 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef ESP_NVS_H +#define ESP_NVS_H + +#include +#include +#include +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Opaque pointer type representing non-volatile storage handle + */ +typedef uint32_t nvs_handle; + +#define ESP_ERR_NVS_BASE 0x1100 /*!< Starting number of error codes */ +#define ESP_ERR_NVS_NOT_INITIALIZED (ESP_ERR_NVS_BASE + 0x01) /*!< The storage driver is not initialized */ +#define ESP_ERR_NVS_NOT_FOUND (ESP_ERR_NVS_BASE + 0x02) /*!< Id namespace doesn’t exist yet and mode is NVS_READONLY */ +#define ESP_ERR_NVS_TYPE_MISMATCH (ESP_ERR_NVS_BASE + 0x03) /*!< The type of set or get operation doesn't match the type of value stored in NVS */ +#define ESP_ERR_NVS_READ_ONLY (ESP_ERR_NVS_BASE + 0x04) /*!< Storage handle was opened as read only */ +#define ESP_ERR_NVS_NOT_ENOUGH_SPACE (ESP_ERR_NVS_BASE + 0x05) /*!< There is not enough space in the underlying storage to save the value */ +#define ESP_ERR_NVS_INVALID_NAME (ESP_ERR_NVS_BASE + 0x06) /*!< Namespace name doesn’t satisfy constraints */ +#define ESP_ERR_NVS_INVALID_HANDLE (ESP_ERR_NVS_BASE + 0x07) /*!< Handle has been closed or is NULL */ +#define ESP_ERR_NVS_REMOVE_FAILED (ESP_ERR_NVS_BASE + 0x08) /*!< The value wasn’t updated because flash write operation has failed. The value was written however, and update will be finished after re-initialization of nvs, provided that flash operation doesn’t fail again. */ +#define ESP_ERR_NVS_KEY_TOO_LONG (ESP_ERR_NVS_BASE + 0x09) /*!< Key name is too long */ +#define ESP_ERR_NVS_PAGE_FULL (ESP_ERR_NVS_BASE + 0x0a) /*!< Internal error; never returned by nvs_ API functions */ +#define ESP_ERR_NVS_INVALID_STATE (ESP_ERR_NVS_BASE + 0x0b) /*!< NVS is in an inconsistent state due to a previous error. Call nvs_flash_init and nvs_open again, then retry. */ +#define ESP_ERR_NVS_INVALID_LENGTH (ESP_ERR_NVS_BASE + 0x0c) /*!< String or blob length is not sufficient to store data */ +#define ESP_ERR_NVS_NO_FREE_PAGES (ESP_ERR_NVS_BASE + 0x0d) /*!< NVS partition doesn't contain any empty pages. This may happen if NVS partition was truncated. Erase the whole partition and call nvs_flash_init again. */ +#define ESP_ERR_NVS_VALUE_TOO_LONG (ESP_ERR_NVS_BASE + 0x0e) /*!< String or blob length is longer than supported by the implementation */ +#define ESP_ERR_NVS_PART_NOT_FOUND (ESP_ERR_NVS_BASE + 0x0f) /*!< Partition with specified name is not found in the partition table */ + +#define NVS_DEFAULT_PART_NAME "nvs" /*!< Default partition name of the NVS partition in the partition table */ +/** + * @brief Mode of opening the non-volatile storage + * + */ +typedef enum { + NVS_READONLY, /*!< Read only */ + NVS_READWRITE /*!< Read and write */ +} nvs_open_mode; + +/** + * @brief Open non-volatile storage with a given namespace from the default NVS partition + * + * Multiple internal ESP-IDF and third party application modules can store + * their key-value pairs in the NVS module. In order to reduce possible + * conflicts on key names, each module can use its own namespace. + * The default NVS partition is the one that is labelled "nvs" in the partition + * table. + * + * @param[in] name Namespace name. Maximal length is determined by the + * underlying implementation, but is guaranteed to be + * at least 15 characters. Shouldn't be empty. + * @param[in] open_mode NVS_READWRITE or NVS_READONLY. If NVS_READONLY, will + * open a handle for reading only. All write requests will + * be rejected for this handle. + * @param[out] out_handle If successful (return code is zero), handle will be + * returned in this argument. + * + * @return + * - ESP_OK if storage handle was opened successfully + * - ESP_ERR_NVS_NOT_INITIALIZED if the storage driver is not initialized + * - ESP_ERR_NVS_PART_NOT_FOUND if the partition with label "nvs" is not found + * - ESP_ERR_NVS_NOT_FOUND id namespace doesn't exist yet and + * mode is NVS_READONLY + * - ESP_ERR_NVS_INVALID_NAME if namespace name doesn't satisfy constraints + * - other error codes from the underlying storage driver + */ +esp_err_t nvs_open(const char* name, nvs_open_mode open_mode, nvs_handle *out_handle); + +/** + * @brief Open non-volatile storage with a given namespace from specified partition + * + * The behaviour is same as nvs_open() API. However this API can operate on a specified NVS + * partition instead of default NVS partition. Note that the specified partition must be registered + * with NVS using nvs_flash_init_partition() API. + * + * @param[in] part_name Label (name) of the partition of interest for object read/write/erase + * @param[in] name Namespace name. Maximal length is determined by the + * underlying implementation, but is guaranteed to be + * at least 15 characters. Shouldn't be empty. + * @param[in] open_mode NVS_READWRITE or NVS_READONLY. If NVS_READONLY, will + * open a handle for reading only. All write requests will + * be rejected for this handle. + * @param[out] out_handle If successful (return code is zero), handle will be + * returned in this argument. + * + * @return + * - ESP_OK if storage handle was opened successfully + * - ESP_ERR_NVS_NOT_INITIALIZED if the storage driver is not initialized + * - ESP_ERR_NVS_PART_NOT_FOUND if the partition with specified name is not found + * - ESP_ERR_NVS_NOT_FOUND id namespace doesn't exist yet and + * mode is NVS_READONLY + * - ESP_ERR_NVS_INVALID_NAME if namespace name doesn't satisfy constraints + * - other error codes from the underlying storage driver + */ +esp_err_t nvs_open_from_partition(const char *part_name, const char* name, nvs_open_mode open_mode, nvs_handle *out_handle); + +/**@{*/ +/** + * @brief set value for given key + * + * This family of functions set value for the key, given its name. Note that + * actual storage will not be updated until nvs_commit function is called. + * + * @param[in] handle Handle obtained from nvs_open function. + * Handles that were opened read only cannot be used. + * @param[in] key Key name. Maximal length is determined by the underlying + * implementation, but is guaranteed to be at least + * 15 characters. Shouldn't be empty. + * @param[in] value The value to set. + * For strings, the maximum length (including null character) is + * 1984 bytes. + * + * @return + * - ESP_OK if value was set successfully + * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL + * - ESP_ERR_NVS_READ_ONLY if storage handle was opened as read only + * - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints + * - ESP_ERR_NVS_NOT_ENOUGH_SPACE if there is not enough space in the + * underlying storage to save the value + * - ESP_ERR_NVS_REMOVE_FAILED if the value wasn't updated because flash + * write operation has failed. The value was written however, and + * update will be finished after re-initialization of nvs, provided that + * flash operation doesn't fail again. + * - ESP_ERR_NVS_VALUE_TOO_LONG if the string value is too long + */ +esp_err_t nvs_set_i8 (nvs_handle handle, const char* key, int8_t value); +esp_err_t nvs_set_u8 (nvs_handle handle, const char* key, uint8_t value); +esp_err_t nvs_set_i16 (nvs_handle handle, const char* key, int16_t value); +esp_err_t nvs_set_u16 (nvs_handle handle, const char* key, uint16_t value); +esp_err_t nvs_set_i32 (nvs_handle handle, const char* key, int32_t value); +esp_err_t nvs_set_u32 (nvs_handle handle, const char* key, uint32_t value); +esp_err_t nvs_set_i64 (nvs_handle handle, const char* key, int64_t value); +esp_err_t nvs_set_u64 (nvs_handle handle, const char* key, uint64_t value); +esp_err_t nvs_set_str (nvs_handle handle, const char* key, const char* value); +/**@}*/ + +/** + * @brief set variable length binary value for given key + * + * This family of functions set value for the key, given its name. Note that + * actual storage will not be updated until nvs_commit function is called. + * + * @param[in] handle Handle obtained from nvs_open function. + * Handles that were opened read only cannot be used. + * @param[in] key Key name. Maximal length is 15 characters. Shouldn't be empty. + * @param[in] value The value to set. + * @param[in] length length of binary value to set, in bytes; Maximum length is + * 1984 bytes. + * + * @return + * - ESP_OK if value was set successfully + * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL + * - ESP_ERR_NVS_READ_ONLY if storage handle was opened as read only + * - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints + * - ESP_ERR_NVS_NOT_ENOUGH_SPACE if there is not enough space in the + * underlying storage to save the value + * - ESP_ERR_NVS_REMOVE_FAILED if the value wasn't updated because flash + * write operation has failed. The value was written however, and + * update will be finished after re-initialization of nvs, provided that + * flash operation doesn't fail again. + * - ESP_ERR_NVS_VALUE_TOO_LONG if the value is too long + */ +esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void* value, size_t length); + +/**@{*/ +/** + * @brief get value for given key + * + * These functions retrieve value for the key, given its name. If key does not + * exist, or the requested variable type doesn't match the type which was used + * when setting a value, an error is returned. + * + * In case of any error, out_value is not modified. + * + * All functions expect out_value to be a pointer to an already allocated variable + * of the given type. + * + * \code{c} + * // Example of using nvs_get_i32: + * int32_t max_buffer_size = 4096; // default value + * esp_err_t err = nvs_get_i32(my_handle, "max_buffer_size", &max_buffer_size); + * assert(err == ESP_OK || err == ESP_ERR_NVS_NOT_FOUND); + * // if ESP_ERR_NVS_NOT_FOUND was returned, max_buffer_size will still + * // have its default value. + * + * \endcode + * + * @param[in] handle Handle obtained from nvs_open function. + * @param[in] key Key name. Maximal length is determined by the underlying + * implementation, but is guaranteed to be at least + * 15 characters. Shouldn't be empty. + * @param out_value Pointer to the output value. + * May be NULL for nvs_get_str and nvs_get_blob, in this + * case required length will be returned in length argument. + * + * @return + * - ESP_OK if the value was retrieved successfully + * - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist + * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL + * - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints + * - ESP_ERR_NVS_INVALID_LENGTH if length is not sufficient to store data + */ +esp_err_t nvs_get_i8 (nvs_handle handle, const char* key, int8_t* out_value); +esp_err_t nvs_get_u8 (nvs_handle handle, const char* key, uint8_t* out_value); +esp_err_t nvs_get_i16 (nvs_handle handle, const char* key, int16_t* out_value); +esp_err_t nvs_get_u16 (nvs_handle handle, const char* key, uint16_t* out_value); +esp_err_t nvs_get_i32 (nvs_handle handle, const char* key, int32_t* out_value); +esp_err_t nvs_get_u32 (nvs_handle handle, const char* key, uint32_t* out_value); +esp_err_t nvs_get_i64 (nvs_handle handle, const char* key, int64_t* out_value); +esp_err_t nvs_get_u64 (nvs_handle handle, const char* key, uint64_t* out_value); +/**@}*/ + +/** + * @brief get value for given key + * + * These functions retrieve value for the key, given its name. If key does not + * exist, or the requested variable type doesn't match the type which was used + * when setting a value, an error is returned. + * + * In case of any error, out_value is not modified. + * + * All functions expect out_value to be a pointer to an already allocated variable + * of the given type. + * + * nvs_get_str and nvs_get_blob functions support WinAPI-style length queries. + * To get the size necessary to store the value, call nvs_get_str or nvs_get_blob + * with zero out_value and non-zero pointer to length. Variable pointed to + * by length argument will be set to the required length. For nvs_get_str, + * this length includes the zero terminator. When calling nvs_get_str and + * nvs_get_blob with non-zero out_value, length has to be non-zero and has to + * point to the length available in out_value. + * It is suggested that nvs_get/set_str is used for zero-terminated C strings, and + * nvs_get/set_blob used for arbitrary data structures. + * + * \code{c} + * // Example (without error checking) of using nvs_get_str to get a string into dynamic array: + * size_t required_size; + * nvs_get_str(my_handle, "server_name", NULL, &required_size); + * char* server_name = malloc(required_size); + * nvs_get_str(my_handle, "server_name", server_name, &required_size); + * + * // Example (without error checking) of using nvs_get_blob to get a binary data + * into a static array: + * uint8_t mac_addr[6]; + * size_t size = sizeof(mac_addr); + * nvs_get_blob(my_handle, "dst_mac_addr", mac_addr, &size); + * \endcode + * + * @param[in] handle Handle obtained from nvs_open function. + * @param[in] key Key name. Maximal length is determined by the underlying + * implementation, but is guaranteed to be at least + * 15 characters. Shouldn't be empty. + * @param out_value Pointer to the output value. + * May be NULL for nvs_get_str and nvs_get_blob, in this + * case required length will be returned in length argument. + * @param[inout] length A non-zero pointer to the variable holding the length of out_value. + * In case out_value a zero, will be set to the length + * required to hold the value. In case out_value is not + * zero, will be set to the actual length of the value + * written. For nvs_get_str this includes zero terminator. + * + * @return + * - ESP_OK if the value was retrieved successfully + * - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist + * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL + * - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints + * - ESP_ERR_NVS_INVALID_LENGTH if length is not sufficient to store data + */ +/**@{*/ +esp_err_t nvs_get_str (nvs_handle handle, const char* key, char* out_value, size_t* length); +esp_err_t nvs_get_blob(nvs_handle handle, const char* key, void* out_value, size_t* length); +/**@}*/ + +/** + * @brief Erase key-value pair with given key name. + * + * Note that actual storage may not be updated until nvs_commit function is called. + * + * @param[in] handle Storage handle obtained with nvs_open. + * Handles that were opened read only cannot be used. + * + * @param[in] key Key name. Maximal length is determined by the underlying + * implementation, but is guaranteed to be at least + * 15 characters. Shouldn't be empty. + * + * @return + * - ESP_OK if erase operation was successful + * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL + * - ESP_ERR_NVS_READ_ONLY if handle was opened as read only + * - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist + * - other error codes from the underlying storage driver + */ +esp_err_t nvs_erase_key(nvs_handle handle, const char* key); + +/** + * @brief Erase all key-value pairs in a namespace + * + * Note that actual storage may not be updated until nvs_commit function is called. + * + * @param[in] handle Storage handle obtained with nvs_open. + * Handles that were opened read only cannot be used. + * + * @return + * - ESP_OK if erase operation was successful + * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL + * - ESP_ERR_NVS_READ_ONLY if handle was opened as read only + * - other error codes from the underlying storage driver + */ +esp_err_t nvs_erase_all(nvs_handle handle); + +/** + * @brief Write any pending changes to non-volatile storage + * + * After setting any values, nvs_commit() must be called to ensure changes are written + * to non-volatile storage. Individual implementations may write to storage at other times, + * but this is not guaranteed. + * + * @param[in] handle Storage handle obtained with nvs_open. + * Handles that were opened read only cannot be used. + * + * @return + * - ESP_OK if the changes have been written successfully + * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL + * - other error codes from the underlying storage driver + */ +esp_err_t nvs_commit(nvs_handle handle); + +/** + * @brief Close the storage handle and free any allocated resources + * + * This function should be called for each handle opened with nvs_open once + * the handle is not in use any more. Closing the handle may not automatically + * write the changes to nonvolatile storage. This has to be done explicitly using + * nvs_commit function. + * Once this function is called on a handle, the handle should no longer be used. + * + * @param[in] handle Storage handle to close + */ +void nvs_close(nvs_handle handle); + +/** + * @note Info about storage space NVS. + */ +typedef struct { + size_t used_entries; /**< Amount of used entries. */ + size_t free_entries; /**< Amount of free entries. */ + size_t total_entries; /**< Amount all available entries. */ + size_t namespace_count; /**< Amount name space. */ +} nvs_stats_t; + +/** + * @brief Fill structure nvs_stats_t. It provides info about used memory the partition. + * + * This function calculates to runtime the number of used entries, free entries, total entries, + * and amount namespace in partition. + * + * \code{c} + * // Example of nvs_get_stats() to get the number of used entries and free entries: + * nvs_stats_t nvs_stats; + * nvs_get_stats(NULL, &nvs_stats); + * printf("Count: UsedEntries = (%d), FreeEntries = (%d), AllEntries = (%d)\n", + nvs_stats.used_entries, nvs_stats.free_entries, nvs_stats.total_entries); + * \endcode + * + * @param[in] part_name Partition name NVS in the partition table. + * If pass a NULL than will use NVS_DEFAULT_PART_NAME ("nvs"). + * + * @param[out] nvs_stats Returns filled structure nvs_states_t. + * It provides info about used memory the partition. + * + * + * @return + * - ESP_OK if the changes have been written successfully. + * Return param nvs_stats will be filled. + * - ESP_ERR_NVS_PART_NOT_FOUND if the partition with label "name" is not found. + * Return param nvs_stats will be filled 0. + * - ESP_ERR_NVS_NOT_INITIALIZED if the storage driver is not initialized. + * Return param nvs_stats will be filled 0. + * - ESP_ERR_INVALID_ARG if nvs_stats equal to NULL. + * - ESP_ERR_INVALID_STATE if there is page with the status of INVALID. + * Return param nvs_stats will be filled not with correct values because + * not all pages will be counted. Counting will be interrupted at the first INVALID page. + */ +esp_err_t nvs_get_stats(const char* part_name, nvs_stats_t* nvs_stats); + +/** + * @brief Calculate all entries in a namespace. + * + * Note that to find out the total number of records occupied by the namespace, + * add one to the returned value used_entries (if err is equal to ESP_OK). + * Because the name space entry takes one entry. + * + * \code{c} + * // Example of nvs_get_used_entry_count() to get amount of all key-value pairs in one namespace: + * nvs_handle handle; + * nvs_open("namespace1", NVS_READWRITE, &handle); + * ... + * size_t used_entries; + * size_t total_entries_namespace; + * if(nvs_get_used_entry_count(handle, &used_entries) == ESP_OK){ + * // the total number of records occupied by the namespace + * total_entries_namespace = used_entries + 1; + * } + * \endcode + * + * @param[in] handle Handle obtained from nvs_open function. + * + * @param[out] used_entries Returns amount of used entries from a namespace. + * + * + * @return + * - ESP_OK if the changes have been written successfully. + * Return param used_entries will be filled valid value. + * - ESP_ERR_NVS_NOT_INITIALIZED if the storage driver is not initialized. + * Return param used_entries will be filled 0. + * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL. + * Return param used_entries will be filled 0. + * - ESP_ERR_INVALID_ARG if nvs_stats equal to NULL. + * - Other error codes from the underlying storage driver. + * Return param used_entries will be filled 0. + */ +esp_err_t nvs_get_used_entry_count(nvs_handle handle, size_t* used_entries); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif //ESP_NVS_H + diff --git a/components/nvs_flash/include/nvs_flash.h b/components/nvs_flash/include/nvs_flash.h new file mode 100644 index 00000000..a7ef7f45 --- /dev/null +++ b/components/nvs_flash/include/nvs_flash.h @@ -0,0 +1,107 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef nvs_flash_h +#define nvs_flash_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include "nvs.h" + +/** + * @brief Initialize the default NVS partition. + * + * This API initialises the default NVS partition. The default NVS partition + * is the one that is labeled "nvs" in the partition table. + * + * @return + * - ESP_OK if storage was successfully initialized. + * - ESP_ERR_NVS_NO_FREE_PAGES if the NVS storage contains no empty pages + * (which may happen if NVS partition was truncated) + * - ESP_ERR_NOT_FOUND if no partition with label "nvs" is found in the partition table + * - one of the error codes from the underlying flash storage driver + */ +esp_err_t nvs_flash_init(void); + +/** + * @brief Initialize NVS flash storage for the specified partition. + * + * @param[in] partition_label Label of the partition. Note that internally a reference to + * passed value is kept and it should be accessible for future operations + * + * @return + * - ESP_OK if storage was successfully initialized. + * - ESP_ERR_NVS_NO_FREE_PAGES if the NVS storage contains no empty pages + * (which may happen if NVS partition was truncated) + * - ESP_ERR_NOT_FOUND if specified partition is not found in the partition table + * - one of the error codes from the underlying flash storage driver + */ +esp_err_t nvs_flash_init_partition(const char *partition_label); + +/** + * @brief Deinitialize NVS storage for the default NVS partition + * + * Default NVS partition is the partition with "nvs" label in the partition table. + * + * @return + * - ESP_OK on success (storage was deinitialized) + * - ESP_ERR_NVS_NOT_INITIALIZED if the storage was not initialized prior to this call + */ +esp_err_t nvs_flash_deinit(void); + +/** + * @brief Deinitialize NVS storage for the given NVS partition + * + * @param[in] partition_label Label of the partition + * + * @return + * - ESP_OK on success + * - ESP_ERR_NVS_NOT_INITIALIZED if the storage for given partition was not + * initialized prior to this call + */ +esp_err_t nvs_flash_deinit_partition(const char* partition_label); + +/** + * @brief Erase the default NVS partition + * + * This function erases all contents of the default NVS partition (one with label "nvs") + * + * @return + * - ESP_OK on success + * - ESP_ERR_NOT_FOUND if there is no NVS partition labeled "nvs" in the + * partition table + */ +esp_err_t nvs_flash_erase(void); + +/** + * @brief Erase specified NVS partition + * + * This function erases all contents of specified NVS partition + * + * @param[in] part_name Name (label) of the partition to be erased + * + * @return + * - ESP_OK on success + * - ESP_ERR_NOT_FOUND if there is no NVS partition with the specified name + * in the partition table + */ +esp_err_t nvs_flash_erase_partition(const char *part_name); + +#ifdef __cplusplus +} +#endif + + +#endif /* nvs_flash_h */ diff --git a/components/nvs_flash/src/nvs.c b/components/nvs_flash/src/nvs.c new file mode 100644 index 00000000..df003b53 --- /dev/null +++ b/components/nvs_flash/src/nvs.c @@ -0,0 +1,165 @@ +#include "nvs.h" + +esp_err_t nvs_open(const char* name, nvs_open_mode open_mode, nvs_handle *out_handle) +{ + return 0; +} + +/** + * @brief Open non-volatile storage with a given namespace from specified partition + */ +esp_err_t nvs_open_from_partition(const char *part_name, const char* name, nvs_open_mode open_mode, nvs_handle *out_handle) +{ + return 0; +} + +/**@{*/ +/** + * @brief set value for given key + */ +esp_err_t nvs_set_i8 (nvs_handle handle, const char* key, int8_t value) +{ + return 0; +} +esp_err_t nvs_set_u8 (nvs_handle handle, const char* key, uint8_t value) +{ + return 0; +} +esp_err_t nvs_set_i16 (nvs_handle handle, const char* key, int16_t value) +{ + return 0; +} +esp_err_t nvs_set_u16 (nvs_handle handle, const char* key, uint16_t value) +{ + return 0; +} +esp_err_t nvs_set_i32 (nvs_handle handle, const char* key, int32_t value) +{ + return 0; +} +esp_err_t nvs_set_u32 (nvs_handle handle, const char* key, uint32_t value) +{ + return 0; +} +esp_err_t nvs_set_i64 (nvs_handle handle, const char* key, int64_t value) +{ + return 0; +} +esp_err_t nvs_set_u64 (nvs_handle handle, const char* key, uint64_t value) +{ + return 0; +} +esp_err_t nvs_set_str (nvs_handle handle, const char* key, const char* value) +{ + return 0; +} +/**@}*/ + +/** + * @brief set variable length binary value for given key + */ +esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void* value, size_t length) +{ + return 0; +} + +/**@{*/ +/** + * @brief get value for given key + */ +esp_err_t nvs_get_i8 (nvs_handle handle, const char* key, int8_t* out_value) +{ + return 0; +} +esp_err_t nvs_get_u8 (nvs_handle handle, const char* key, uint8_t* out_value) +{ + return 0; +} +esp_err_t nvs_get_i16 (nvs_handle handle, const char* key, int16_t* out_value) +{ + return 0; +} +esp_err_t nvs_get_u16 (nvs_handle handle, const char* key, uint16_t* out_value) +{ + return 0; +} +esp_err_t nvs_get_i32 (nvs_handle handle, const char* key, int32_t* out_value) +{ + return 0; +} +esp_err_t nvs_get_u32 (nvs_handle handle, const char* key, uint32_t* out_value) +{ + return 0; +} +esp_err_t nvs_get_i64 (nvs_handle handle, const char* key, int64_t* out_value) +{ + return 0; +} +esp_err_t nvs_get_u64 (nvs_handle handle, const char* key, uint64_t* out_value) +{ + return 0; +} +/**@}*/ + +/** + * @brief get value for given key + */ +/**@{*/ +esp_err_t nvs_get_str (nvs_handle handle, const char* key, char* out_value, size_t* length) +{ + return 0; +} +esp_err_t nvs_get_blob(nvs_handle handle, const char* key, void* out_value, size_t* length) +{ + return 0; +} +/**@}*/ + +/** + * @brief Erase key-value pair with given key name. + */ +esp_err_t nvs_erase_key(nvs_handle handle, const char* key) +{ + return 0; +} + +/** + * @brief Erase all key-value pairs in a namespace + */ +esp_err_t nvs_erase_all(nvs_handle handle) +{ + return 0; +} + +/** + * @brief Write any pending changes to non-volatile storage + */ +esp_err_t nvs_commit(nvs_handle handle) +{ + return 0; +} + +/** + * @brief Close the storage handle and free any allocated resources + */ +void nvs_close(nvs_handle handle) +{ + +} + + +/** + * @brief Fill structure nvs_stats_t. It provides info about used memory the partition. + */ +esp_err_t nvs_get_stats(const char* part_name, nvs_stats_t* nvs_stats) +{ + return 0; +} + +/** + * @brief Calculate all entries in a namespace. + */ +esp_err_t nvs_get_used_entry_count(nvs_handle handle, size_t* used_entries) +{ + return 0; +} diff --git a/components/nvs_flash/src/nvs_flash.c b/components/nvs_flash/src/nvs_flash.c new file mode 100644 index 00000000..ff3537ed --- /dev/null +++ b/components/nvs_flash/src/nvs_flash.c @@ -0,0 +1,50 @@ +#include "nvs_flash.h" + + +/** + * @brief Initialize the default NVS partition. + */ +esp_err_t nvs_flash_init(void) +{ + return 0; +} + +/** + * @brief Initialize NVS flash storage for the specified partition. + */ +esp_err_t nvs_flash_init_partition(const char *partition_label) +{ + return 0; +} + +/** + * @brief Deinitialize NVS storage for the default NVS partition + */ +esp_err_t nvs_flash_deinit(void) +{ + return 0; +} + +/** + * @brief Deinitialize NVS storage for the given NVS partition + */ +esp_err_t nvs_flash_deinit_partition(const char* partition_label) +{ + return 0; +} + +/** + * @brief Erase the default NVS partition + */ +esp_err_t nvs_flash_erase(void) +{ + return 0; +} + +/** + * @brief Erase specified NVS partition + */ +esp_err_t nvs_flash_erase_partition(const char *part_name) +{ + return 0; +}