| .. _settings_api: |
| |
| Settings |
| ######## |
| |
| The settings subsystem gives modules a way to store persistent per-device |
| configuration and runtime state. A variety of storage implementations are |
| provided behind a common API using FCB, NVS, ZMS or a file system. These |
| different implementations give the application developer flexibility to select |
| an appropriate storage medium, and even change it later as needs change. This |
| subsystem is used by various Zephyr components and can be used simultaneously by |
| user applications. |
| |
| Settings items are stored as key-value pair strings. By convention, |
| the keys can be organized by the package and subtree defining the key, |
| for example the key ``id/serial`` would define the ``serial`` configuration |
| element for the package ``id``. |
| |
| Convenience routines are provided for converting a key value to |
| and from a string type. |
| |
| For an example of the settings subsystem refer to :zephyr:code-sample:`settings` sample. |
| |
| .. note:: |
| |
| As of Zephyr release 4.1 the recommended backends for non-filesystem |
| storage are :ref:`NVS <nvs_api>` and :ref:`ZMS <zms_api>`. |
| |
| Handlers |
| ******** |
| |
| Settings handlers for subtree implement a set of handler functions. |
| These are registered using a call to :c:func:`settings_register()` for |
| dynamic handlers or defined using a call to :c:macro:`SETTINGS_STATIC_HANDLER_DEFINE()` |
| for static handlers. |
| |
| **h_get** |
| This gets called when asking for a settings element value by its name using |
| :c:func:`settings_runtime_get()` from the runtime backend. |
| |
| **h_set** |
| This gets called when the value is loaded from persistent storage with |
| :c:func:`settings_load()`, or when using :c:func:`settings_runtime_set()` from the |
| runtime backend. |
| |
| **h_commit** |
| This gets called after the settings have been loaded in full. |
| Sometimes you don't want an individual setting value to take |
| effect right away, for example if there are multiple settings |
| which are interdependent. |
| |
| **h_export** |
| This gets called to write all current settings. This happens |
| when :c:func:`settings_save()` tries to save the settings or transfer to any |
| user-implemented back-end. |
| |
| Settings handlers also have a commit priority ``cprio`` that allows to prioritize |
| the ``h_commit`` calls. This can be advantageous when e.g. a subsystem initializes |
| a service that other ``h_commit`` calls depend on. |
| |
| Settings handlers ``h_commit`` routines are by default initialized with ``cprio = 0``, |
| initializing a settings handler with a different priority is done using a call to |
| :c:func:`settings_register_with_cprio()` for dynamic handlers or using a call to |
| :c:macro:`SETTINGS_STATIC_HANDLER_DEFINE_WITH_CPRIO()` for static handlers. The |
| specified ``cprio`` value is an integer where lower values mean higher priority. |
| |
| Backends |
| ******** |
| |
| Backends are meant to load and save data to/from setting handlers, and |
| implement a set of handler functions. These are registered using a call to |
| :c:func:`settings_src_register()` for backends that can load data, and/or |
| :c:func:`settings_dst_register()` for backends that can save data. The current |
| implementation allows for multiple source backends but only a single destination |
| backend. |
| |
| **csi_load** |
| This gets called when loading values from persistent storage using |
| :c:func:`settings_load()`. |
| |
| **csi_load_one** |
| This gets called when loading only one item from persistent storage using |
| :c:func:`settings_load_one()`. |
| |
| **csi_get_val_len** |
| This gets called when getting a value's length from persistent storage using |
| :c:func:`settings_get_val_len()`. |
| |
| **csi_save** |
| This gets called when saving a single setting to persistent storage using |
| :c:func:`settings_save_one()`. |
| |
| **csi_save_start** |
| This gets called when starting a save of all current settings using |
| :c:func:`settings_save()` or :c:func:`settings_save_subtree()`. |
| |
| **csi_save_end** |
| This gets called after having saved of all current settings using |
| :c:func:`settings_save()` or :c:func:`settings_save_subtree()`. |
| |
| Zephyr Storage Backends |
| *********************** |
| |
| Zephyr offers the following storage backends: |
| |
| * Flash Circular Buffer (:kconfig:option:`CONFIG_SETTINGS_FCB`). |
| * A file in the filesystem (:kconfig:option:`CONFIG_SETTINGS_FILE`). |
| * Non-Volatile Storage (:kconfig:option:`CONFIG_SETTINGS_NVS`). |
| * Zephyr Memory Storage (:kconfig:option:`CONFIG_SETTINGS_ZMS`). |
| |
| You can declare multiple sources for settings; settings from |
| all of these are restored when :c:func:`settings_load()` is called. |
| |
| There can be only one target for writing settings; this is where |
| data is stored when you call :c:func:`settings_save()`, or :c:func:`settings_save_one()`. |
| |
| FCB read target is registered using :c:func:`settings_fcb_src()`, and write target |
| using :c:func:`settings_fcb_dst()`. As a side-effect, :c:func:`settings_fcb_src()` |
| initializes the FCB area, so it must be called before calling |
| :c:func:`settings_fcb_dst()`. File read target is registered using |
| :c:func:`settings_file_src()`, and write target by using :c:func:`settings_file_dst()`. |
| |
| Non-volatile storage read target is registered using |
| :c:func:`settings_nvs_src()`, and write target by using |
| :c:func:`settings_nvs_dst()`. |
| |
| Zephyr Memory Storage (ZMS) read target is registered using :c:func:`settings_zms_src()`, |
| and write target is registered using :c:func:`settings_zms_dst()`. |
| |
| ZMS backend has the particularity of using hash functions to hash the settings |
| key before storing it to the persistent storage. This implementation implies |
| that some collisions between key's hashes could occur if a big number of |
| different keys are stored. This number depends on the selected hash function. |
| |
| ZMS backend can handle :math:`2^n` maximum collisions where n is defined by |
| (:kconfig:option:`CONFIG_SETTINGS_ZMS_MAX_COLLISIONS_BITS`). |
| |
| |
| Storage Location |
| **************** |
| |
| The FCB, non-volatile storage (NVS) and ZMS backends look for a fixed |
| partition with label "storage" by default. A different partition can be |
| selected by setting the ``zephyr,settings-partition`` property of the |
| chosen node in the devicetree. |
| |
| The file path used by the file backend to store settings is selected via the |
| option :kconfig:option:`CONFIG_SETTINGS_FILE_PATH`. |
| |
| Loading data from persistent storage |
| ************************************ |
| |
| A call to :c:func:`settings_load()` uses an ``h_set`` implementation |
| to load settings data from storage to volatile memory. |
| After all data is loaded, the ``h_commit`` handler is issued, |
| signalling the application that the settings were successfully |
| retrieved. |
| |
| Alternatively, a call to :c:func:`settings_load_one()` will load only one |
| Settings entry and store it in the provided buffer. |
| |
| Optionally, to get only the value's length associated with the Settings entry, |
| a call to :c:func:`settings_get_val_len()` can be performed. |
| This is used for example by applications that allocates dynamically the data |
| buffer and needs to get the data size before reading it by settings_load_one(). |
| |
| Technically FCB and file backends may store some history of the entities. |
| This means that the newest data entity is stored after any |
| older existing data entities. |
| Starting with Zephyr 2.1, the back-end must filter out all old entities and |
| call the callback with only the newest entity. |
| |
| Storing data to persistent storage |
| ********************************** |
| |
| A call to :c:func:`settings_save_one()` uses a backend implementation to store |
| settings data to the storage medium. A call to :c:func:`settings_save()` uses an |
| ``h_export`` implementation to store different data in one operation using |
| :c:func:`settings_save_one()`. |
| A key needs to be covered by a ``h_export`` only if it is supposed to be stored |
| by :c:func:`settings_save()` call. |
| |
| For both FCB and file back-end only storage requests with data which |
| changes most actual key's value are stored, therefore there is no need to check |
| whether a value changed by the application. Such a storage mechanism implies |
| that storage can contain multiple value assignments for a key , while only the |
| last is the current value for the key. |
| |
| Garbage collection |
| ================== |
| When storage becomes full (FCB) or consumes too much space (file), |
| the backend removes non-recent key-value pairs records and unnecessary |
| key-delete records. |
| |
| Secure domain settings |
| ********************** |
| Currently settings doesn't provide scheme of being secure, and non-secure |
| configuration storage simultaneously for the same instance. |
| It is recommended that secure domain uses its own settings instance and it might |
| provide data for non-secure domain using dedicated interface if needed |
| (case dependent). |
| |
| Example: Device Configuration |
| ***************************** |
| |
| This is a simple example, where the settings handler only implements ``h_set`` |
| and ``h_export``. ``h_set`` is called when the value is restored from storage |
| (or when set initially), and ``h_export`` is used to write the value to |
| storage thanks to ``storage_func()``. The user can also implement some other |
| export functionality, for example, writing to the shell console). |
| |
| .. code-block:: c |
| |
| #define DEFAULT_FOO_VAL_VALUE 1 |
| |
| static int8 foo_val = DEFAULT_FOO_VAL_VALUE; |
| |
| static int foo_settings_set(const char *name, size_t len, |
| settings_read_cb read_cb, void *cb_arg) |
| { |
| const char *next; |
| int rc; |
| |
| if (settings_name_steq(name, "bar", &next) && !next) { |
| if (len != sizeof(foo_val)) { |
| return -EINVAL; |
| } |
| |
| rc = read_cb(cb_arg, &foo_val, sizeof(foo_val)); |
| if (rc >= 0) { |
| /* key-value pair was properly read. |
| * rc contains value length. |
| */ |
| return 0; |
| } |
| /* read-out error */ |
| return rc; |
| } |
| |
| return -ENOENT; |
| } |
| |
| static int foo_settings_export(int (*storage_func)(const char *name, |
| const void *value, |
| size_t val_len)) |
| { |
| return storage_func("foo/bar", &foo_val, sizeof(foo_val)); |
| } |
| |
| struct settings_handler my_conf = { |
| .name = "foo", |
| .h_set = foo_settings_set, |
| .h_export = foo_settings_export |
| }; |
| |
| Example: Persist Runtime State |
| ****************************** |
| |
| This is a simple example showing how to persist runtime state. In this example, |
| only ``h_set`` is defined, which is used when restoring value from |
| persistent storage. |
| |
| In this example, the ``main`` function increments ``foo_val``, and then |
| persists the latest number. When the system restarts, the application calls |
| :c:func:`settings_load()` while initializing, and ``foo_val`` will continue counting |
| up from where it was before restart. |
| |
| .. code-block:: c |
| |
| #include <zephyr/kernel.h> |
| #include <zephyr/sys/reboot.h> |
| #include <zephyr/settings/settings.h> |
| #include <zephyr/sys/printk.h> |
| #include <inttypes.h> |
| |
| #define DEFAULT_FOO_VAL_VALUE 0 |
| |
| static uint8_t foo_val = DEFAULT_FOO_VAL_VALUE; |
| |
| static int foo_settings_set(const char *name, size_t len, |
| settings_read_cb read_cb, void *cb_arg) |
| { |
| const char *next; |
| int rc; |
| |
| if (settings_name_steq(name, "bar", &next) && !next) { |
| if (len != sizeof(foo_val)) { |
| return -EINVAL; |
| } |
| |
| rc = read_cb(cb_arg, &foo_val, sizeof(foo_val)); |
| if (rc >= 0) { |
| return 0; |
| } |
| |
| return rc; |
| } |
| |
| |
| return -ENOENT; |
| } |
| |
| struct settings_handler my_conf = { |
| .name = "foo", |
| .h_set = foo_settings_set |
| }; |
| |
| int main(void) |
| { |
| settings_subsys_init(); |
| settings_register(&my_conf); |
| settings_load(); |
| |
| foo_val++; |
| settings_save_one("foo/bar", &foo_val, sizeof(foo_val)); |
| |
| printk("foo: %d\n", foo_val); |
| |
| k_msleep(1000); |
| sys_reboot(SYS_REBOOT_COLD); |
| } |
| |
| Example: Custom Backend Implementation |
| ************************************** |
| |
| This is a simple example showing how to register a simple custom backend |
| handler (:kconfig:option:`CONFIG_SETTINGS_CUSTOM`). |
| |
| .. code-block:: c |
| |
| static int settings_custom_load(struct settings_store *cs, |
| const struct settings_load_arg *arg) |
| { |
| //... |
| } |
| |
| static int settings_custom_save(struct settings_store *cs, const char *name, |
| const char *value, size_t val_len) |
| { |
| //... |
| } |
| |
| /* custom backend interface */ |
| static struct settings_store_itf settings_custom_itf = { |
| .csi_load = settings_custom_load, |
| .csi_save = settings_custom_save, |
| }; |
| |
| /* custom backend node */ |
| static struct settings_store settings_custom_store = { |
| .cs_itf = &settings_custom_itf |
| }; |
| |
| int settings_backend_init(void) |
| { |
| /* register custom backend */ |
| settings_dst_register(&settings_custom_store); |
| settings_src_register(&settings_custom_store); |
| return 0; |
| } |
| |
| API Reference |
| ************* |
| |
| The Settings subsystem APIs are provided by :zephyr_file:`include/zephyr/settings/settings.h`. |
| |
| API for general settings usage |
| ============================== |
| .. doxygengroup:: settings |
| |
| API for key-name processing |
| =========================== |
| .. doxygengroup:: settings_name_proc |
| |
| API for runtime settings manipulation |
| ===================================== |
| .. doxygengroup:: settings_rt |
| |
| API of backend interface |
| ======================== |
| .. doxygengroup:: settings_backend |