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, 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 the sample.
Note
As of Zephyr release 2.1 the recommended backend for non-filesystem storage is NVS.
Handlers
Settings handlers for subtree implement a set of handler functions.
These are registered using a call to settings_register()
.
- h_get
This gets called when asking for a settings element value by its name using
settings_runtime_get()
from the runtime backend.- h_set
This gets called when the value is loaded from persisted storage with
settings_load()
, or when usingsettings_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
settings_save()
tries to save the settings or transfer to any user-implemented back-end.
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
settings_src_register()
for backends that can load data, and/or
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
settings_load()
.- csi_save
This gets called when saving a single setting to persistent storage using
settings_save_one()
.- csi_save_start
This gets called when starting a save of all current settings using
settings_save()
.- csi_save_end
This gets called after having saved of all current settings using
settings_save()
.
Zephyr Storage Backends
Zephyr has three storage backends: a Flash Circular Buffer
(CONFIG_SETTINGS_FCB
), a file in the filesystem
(CONFIG_SETTINGS_FILE
), or non-volatile storage
(CONFIG_SETTINGS_NVS
).
You can declare multiple sources for settings; settings from
all of these are restored when settings_load()
is called.
There can be only one target for writing settings; this is where
data is stored when you call settings_save()
, or settings_save_one()
.
FCB read target is registered using settings_fcb_src()
, and write target
using settings_fcb_dst()
. As a side-effect, settings_fcb_src()
initializes the FCB area, so it must be called before calling
settings_fcb_dst()
. File read target is registered using
settings_file_src()
, and write target by using settings_file_dst()
.
Non-volatile storage read target is registered using
settings_nvs_src()
, and write target by using
settings_nvs_dst()
.
Storage Location
The FCB and non-volatile storage (NVS) backends both 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 CONFIG_SETTINGS_FILE_PATH
.
Loading data from persisted storage
A call to 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.
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 settings_save_one()
uses a backend implementation to store
settings data to the storage medium. A call to settings_save()
uses an
h_export
implementation to store different data in one operation using
settings_save_one()
.
A key need to be covered by a h_export
only if it is supposed to be stored
by 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).
#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
persisted storage.
In this example, the main
function increments foo_val
, and then
persists the latest number. When the system restarts, the application calls
settings_load()
while initializing, and foo_val
will continue counting
up from where it was before restart.
#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
};
void 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 (CONFIG_SETTINGS_CUSTOM
).
static int settings_custom_load(struct settings_store *cs)
{
//...
}
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 settings.h
:
API for general settings usage
- group settings
Defines
-
SETTINGS_MAX_DIR_DEPTH
-
SETTINGS_MAX_NAME_LEN
-
SETTINGS_MAX_VAL_LEN
-
SETTINGS_NAME_SEPARATOR
-
SETTINGS_NAME_END
-
SETTINGS_EXTRA_LEN
-
SETTINGS_STATIC_HANDLER_DEFINE(_hname, _tree, _get, _set, _commit, _export)
Define a static handler for settings items
This creates a variable hname prepended by settings_handler.
- Parameters
_hname – handler name
_tree – subtree name
_get – get routine (can be NULL)
_set – set routine (can be NULL)
_commit – commit routine (can be NULL)
_export – export routine (can be NULL)
Typedefs
-
typedef ssize_t (*settings_read_cb)(void *cb_arg, void *data, size_t len)
Function used to read the data from the settings storage in h_set handler implementations.
- Param cb_arg
[in] arguments for the read function. Appropriate cb_arg is transferred to h_set handler implementation by the backend.
- Param data
[out] the destination buffer
- Param len
[in] length of read
- Return
positive: Number of bytes read, 0: key-value pair is deleted. On error returns -ERRNO code.
-
typedef int (*settings_load_direct_cb)(const char *key, size_t len, settings_read_cb read_cb, void *cb_arg, void *param)
Callback function used for direct loading. Used by settings_load_subtree_direct function.
- Param key
[in] the name with skipped part that was used as name in handler registration
- Param len
[in] the size of the data found in the backend.
- Param read_cb
[in] function provided to read the data from the backend.
- Param cb_arg
[inout] arguments for the read function provided by the backend.
- Param param
[inout] parameter given to the settings_load_subtree_direct function.
- Return
When nonzero value is returned, further subtree searching is stopped.
Functions
-
int settings_subsys_init(void)
Initialization of settings and backend
Can be called at application startup. In case the backend is a FS Remember to call it after the FS was mounted. For FCB backend it can be called without such a restriction.
- Returns
0 on success, non-zero on failure.
-
int settings_register(struct settings_handler *cf)
Register a handler for settings items stored in RAM.
- Parameters
cf – Structure containing registration info.
- Returns
0 on success, non-zero on failure.
-
int settings_load(void)
Load serialized items from registered persistence sources. Handlers for serialized item subtrees registered earlier will be called for encountered values.
- Returns
0 on success, non-zero on failure.
-
int settings_load_subtree(const char *subtree)
Load limited set of serialized items from registered persistence sources. Handlers for serialized item subtrees registered earlier will be called for encountered values that belong to the subtree.
- Parameters
subtree – [in] name of the subtree to be loaded.
- Returns
0 on success, non-zero on failure.
-
int settings_load_subtree_direct(const char *subtree, settings_load_direct_cb cb, void *param)
Load limited set of serialized items using given callback.
This function bypasses the normal data workflow in settings module. All the settings values that are found are passed to the given callback.
Note
This function does not call commit function. It works as a blocking function, so it is up to the user to call any kind of commit function when this operation ends.
- Parameters
subtree – [in] subtree name of the subtree to be loaded.
cb – [in] pointer to the callback function.
param – [inout] parameter to be passed when callback function is called.
- Returns
0 on success, non-zero on failure.
-
int settings_save(void)
Save currently running serialized items. All serialized items which are different from currently persisted values will be saved.
- Returns
0 on success, non-zero on failure.
-
int settings_save_one(const char *name, const void *value, size_t val_len)
Write a single serialized value to persisted storage (if it has changed value).
- Parameters
name – Name/key of the settings item.
value – Pointer to the value of the settings item. This value will be transferred to the settings_handler::h_export handler implementation.
val_len – Length of the value.
- Returns
0 on success, non-zero on failure.
-
int settings_delete(const char *name)
Delete a single serialized in persisted storage.
Deleting an existing key-value pair in the settings mean to set its value to NULL.
- Parameters
name – Name/key of the settings item.
- Returns
0 on success, non-zero on failure.
-
int settings_commit(void)
Call commit for all settings handler. This should apply all settings which has been set, but not applied yet.
- Returns
0 on success, non-zero on failure.
-
int settings_commit_subtree(const char *subtree)
Call commit for settings handler that belong to subtree. This should apply all settings which has been set, but not applied yet.
- Parameters
subtree – [in] name of the subtree to be committed.
- Returns
0 on success, non-zero on failure.
-
struct settings_handler
- #include <settings.h>
Config handlers for subtree implement a set of handler functions. These are registered using a call to settings_register.
Public Members
-
const char *name
Name of subtree.
-
int (*h_get)(const char *key, char *val, int val_len_max)
Get values handler of settings items identified by keyword names.
Parameters:
key[in] the name with skipped part that was used as name in handler registration
val[out] buffer to receive value.
val_len_max[in] size of that buffer.
Return: length of data read on success, negative on failure.
-
int (*h_set)(const char *key, size_t len, settings_read_cb read_cb, void *cb_arg)
Set value handler of settings items identified by keyword names.
Parameters:
key[in] the name with skipped part that was used as name in handler registration
len[in] the size of the data found in the backend.
read_cb[in] function provided to read the data from the backend.
cb_arg[in] arguments for the read function provided by the backend.
Return: 0 on success, non-zero on failure.
-
int (*h_commit)(void)
This handler gets called after settings has been loaded in full. User might use it to apply setting to the application.
Return: 0 on success, non-zero on failure.
-
int (*h_export)(int (*export_func)(const char *name, const void *val, size_t val_len))
This gets called to dump all current settings items.
This happens when settings_save tries to save the settings. Parameters:
export_func: the pointer to the internal function which appends a single key-value pair to persisted settings. Don’t store duplicated value. The name is subtree/key string, val is the string with value.
Return: 0 on success, non-zero on failure.
Remark
The User might limit a implementations of handler to serving only one keyword at one call - what will impose limit to get/set values using full subtree/key name.
-
sys_snode_t node
Linked list node info for module internal usage.
-
const char *name
-
struct settings_handler_static
- #include <settings.h>
Config handlers without the node element, used for static handlers. These are registered using a call to SETTINGS_STATIC_HANDLER_DEFINE().
Public Members
-
const char *name
Name of subtree.
-
int (*h_get)(const char *key, char *val, int val_len_max)
Get values handler of settings items identified by keyword names.
Parameters:
key[in] the name with skipped part that was used as name in handler registration
val[out] buffer to receive value.
val_len_max[in] size of that buffer.
Return: length of data read on success, negative on failure.
-
int (*h_set)(const char *key, size_t len, settings_read_cb read_cb, void *cb_arg)
Set value handler of settings items identified by keyword names.
Parameters:
key[in] the name with skipped part that was used as name in handler registration
len[in] the size of the data found in the backend.
read_cb[in] function provided to read the data from the backend.
cb_arg[in] arguments for the read function provided by the backend.
Return: 0 on success, non-zero on failure.
-
int (*h_commit)(void)
This handler gets called after settings has been loaded in full. User might use it to apply setting to the application.
-
int (*h_export)(int (*export_func)(const char *name, const void *val, size_t val_len))
This gets called to dump all current settings items.
This happens when settings_save tries to save the settings. Parameters:
export_func: the pointer to the internal function which appends a single key-value pair to persisted settings. Don’t store duplicated value. The name is subtree/key string, val is the string with value.
Return: 0 on success, non-zero on failure.
Remark
The User might limit a implementations of handler to serving only one keyword at one call - what will impose limit to get/set values using full subtree/key name.
-
const char *name
-
SETTINGS_MAX_DIR_DEPTH
API for key-name processing
- group settings_name_proc
API for const name processing.
Functions
-
int settings_name_steq(const char *name, const char *key, const char **next)
Compares the start of name with a key
Some examples: settings_name_steq(“bt/btmesh/iv”, “b”, &next) returns 1, next=”t/btmesh/iv” settings_name_steq(“bt/btmesh/iv”, “bt”, &next) returns 1, next=”btmesh/iv” settings_name_steq(“bt/btmesh/iv”, “bt/”, &next) returns 0, next=NULL settings_name_steq(“bt/btmesh/iv”, “bta”, &next) returns 0, next=NULL
REMARK: This routine could be simplified if the settings_handler names would include a separator at the end.
- Parameters
name – [in] in string format
key – [in] comparison string
next – [out] pointer to remaining of name, when the remaining part starts with a separator the separator is removed from next
- Returns
0: no match 1: match, next can be used to check if match is full
-
int settings_name_next(const char *name, const char **next)
determine the number of characters before the first separator
- Parameters
name – [in] in string format
next – [out] pointer to remaining of name (excluding separator)
- Returns
index of the first separator, in case no separator was found this is the size of name
-
int settings_name_steq(const char *name, const char *key, const char **next)
API for runtime settings manipulation
- group settings_rt
API for runtime settings.
Functions
-
int settings_runtime_set(const char *name, const void *data, size_t len)
Set a value with a specific key to a module handler.
- Parameters
name – Key in string format.
data – Binary value.
len – Value length in bytes.
- Returns
0 on success, non-zero on failure.
-
int settings_runtime_get(const char *name, void *data, size_t len)
Get a value corresponding to a key from a module handler.
- Parameters
name – Key in string format.
data – Returned binary value.
len – requested value length in bytes.
- Returns
length of data read on success, negative on failure.
-
int settings_runtime_commit(const char *name)
Apply settings in a module handler.
- Parameters
name – Key in string format.
- Returns
0 on success, non-zero on failure.
-
int settings_runtime_set(const char *name, const void *data, size_t len)
API of backend interface
- group settings_backend
settings
Functions
-
void settings_src_register(struct settings_store *cs)
Register a backend handler acting as source.
- Parameters
cs – Backend handler node containing handler information.
-
void settings_dst_register(struct settings_store *cs)
Register a backend handler acting as destination.
- Parameters
cs – Backend handler node containing handler information.
-
struct settings_handler_ *settings_parse_and_lookup(const char *name, const char **next)
Parses a key to an array of elements and locate corresponding module handler.
- Parameters
name – [in] in string format
next – [out] remaining of name after matched handler
- Returns
settings_handler_static on success, NULL on failure.
-
int settings_call_set_handler(const char *name, size_t len, settings_read_cb read_cb, void *read_cb_arg, const struct settings_load_arg *load_arg)
Calls settings handler.
- Parameters
name – [in] The name of the data found in the backend.
len – [in] The size of the data found in the backend.
read_cb – [in] Function provided to read the data from the backend.
read_cb_arg – [inout] Arguments for the read function provided by the backend.
load_arg – [inout] Arguments for data loading.
- Returns
0 or negative error code
-
struct settings_store
- #include <settings.h>
Backend handler node for storage handling.
Public Members
-
sys_snode_t cs_next
Linked list node info for internal usage.
-
const struct settings_store_itf *cs_itf
Backend handler structure.
-
sys_snode_t cs_next
-
struct settings_load_arg
- #include <settings.h>
Arguments for data loading. Holds all parameters that changes the way data should be loaded from backend.
Public Members
-
const char *subtree
Name of the subtree to be loaded.
If NULL, all values would be loaded.
-
settings_load_direct_cb cb
Pointer to the callback function.
If NULL then matching registered function would be used.
-
void *param
Parameter for callback function.
Parameter to be passed to the callback function.
-
const char *subtree
-
struct settings_store_itf
- #include <settings.h>
Backend handler functions. Sources are registered using a call to settings_src_register. Destinations are registered using a call to settings_dst_register.
Public Members
-
int (*csi_load)(struct settings_store *cs, const struct settings_load_arg *arg)
Loads values from storage limited to subtree defined by subtree.
Parameters:
cs - Corresponding backend handler node,
arg - Structure that holds additional data for data loading.
Note
Backend is expected not to provide duplicates of the entities. It means that if the backend does not contain any functionality to really delete old keys, it has to filter out old entities and call load callback only on the final entity.
-
int (*csi_save_start)(struct settings_store *cs)
Handler called before an export operation.
Parameters:
cs - Corresponding backend handler node
-
int (*csi_save)(struct settings_store *cs, const char *name, const char *value, size_t val_len)
Save a single key-value pair to storage.
Parameters:
cs - Corresponding backend handler node
name - Key in string format
value - Binary value
val_len - Length of value in bytes.
-
int (*csi_save_end)(struct settings_store *cs)
Handler called after an export operation.
Parameters:
cs - Corresponding backend handler node Get pointer to the storage instance used by the backend.
Parameters:
cs - Corresponding backend handler node
-
int (*csi_load)(struct settings_store *cs, const struct settings_load_arg *arg)
-
void settings_src_register(struct settings_store *cs)