Settings¶
The settings subsystem gives modules a way to store persistent per-device configuration and runtime state.
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.
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 a 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 two existing backend storages which can be a Flash Circular Buffer
(CONFIG_SETTINGS_FCB
) or a file in the filesystem
(CONFIG_SETTINGS_FS
).
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()
.
Loading data from persisted storage¶
A call to settings_load()
uses an h_set
implementation
to load settings data from storage to volatile memory.
For both FCB and filesystem back-end the most
recent key values are guaranteed by traversing all stored content
and (potentially) overwriting older key values with newer ones.
After all data is loaded, the h_commit
handler is issued,
signalling the application that the settings were successfully
retrieved.
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 filesystem 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 system), the backend removes non-recent key-value pairs records and unnecessary key-delete records.
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;
struct settings_handler my_conf = {
.name = "foo",
.h_set = foo_settings_set,
.h_export = foo_settings_export
};
static int foo_settings_set(int argc, char **argv, settings_read_cb read_cb,
void *cb_arg)
{
int rc;
if (argc == 1) {
if (!strcmp(argv[0], "bar")) {
rc = read_cb(cb_arg, &foo_val, sizeof(foo_val));
if (rc >= 0) {
/* key-value pair was properly read.
* rc contains value length.
* key-value is deleted if length equals 0.
* Let's return success.
*/
if (rc == 0) {
/* set the default value as its key is deleted */
foo_val = DEFAULT_FOO_VAL_VALUE;
}
return 0;
}
/* read-out error */
return rc;
}
}
return -ENOENT;
}
static int foo_settings_export(int (*storage_func)(const char *name,
void *value,
size_t val_len))
{
return storage_func("foo/bar", &foo_val, sizeof(foo_val));
}
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 foo_callout
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.
static int8 foo_val;
struct settings_handler my_conf = {
.name = "foo",
.h_set = foo_settings_set
};
static int foo_settings_set(int argc, char **argv, settings_read_cb read_cb,
void *cb_arg)
{
int rc;
if (argc == 1) {
if (!strcmp(argv[0], "bar")) {
rc = read_cb(cb_arg, &foo_val, sizeof(foo_val));
if (rc >= 0) {
return 0;
}
return rc;
}
}
return -ENOENT;
}
static void foo_callout(struct os_event *ev)
{
struct os_callout *c = (struct os_callout *)ev;
foo_val++;
settings_save_one("foo/bar", &foo_val, sizeof(foo_val));
k_sleep(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)
{
//...
}
static struct settings_store_itf settings_custom_itf = {
.csi_load = settings_custom_load,
.csi_save = settings_custom_save,
};
int settings_backend_init(void)
{
settings_dst_register(&settings_custom_itf);
settings_src_register(&settings_custom_itf);
return 0;
}
API Reference¶
The Settings subsystem APIs are provided by settings.h
:
-
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 createa 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.
- Return
- positive: Number of bytes read, 0: key-value pair is deleted. On error returns -ERRNO code.
- Parameters
cb_arg
: arguments for the read function. Appropriate cb_arg is transferred to h_set handler implementation by the backend.data
: the destination bufferlen
: length of read
Functions
-
int
settings_subsys_init
(void)¶ Initialization of settings and backend
Can be called at application startup. In case the backend is NFFS Remember to call it after FS was mounted. For FCB backend it can be called without such a restriction.
- Return
- 0 on success, non-zero on failure.
-
int
settings_register
(struct settings_handler *cf)¶ Register a handler for settings items stored in RAM.
- Return
- 0 on success, non-zero on failure.
- Parameters
cf
: Structure containing registration info.
-
int
settings_load
(void)¶ Load serialized items from registered persistence sources. Handlers for serialized item subtrees registered earlier will be called for encountered values.
- Return
- 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.
- Return
- 0 on success, non-zero on failure.
- Parameters
subtree
: name of the subtree to be loaded.
-
int
settings_save
(void)¶ Save currently running serialized items. All serialized items which are different from currently persisted values will be saved.
- Return
- 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).
- Return
- 0 on success, non-zero on failure.
- 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.
-
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.
- Return
- 0 on success, non-zero on failure.
- Parameters
name
: Name/key of the settings item.
-
int
settings_commit
(void)¶ Call commit for all settings handler. This should apply all settings which has been set, but not applied yet.
- Return
- 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.
- Return
- 0 on success, non-zero on failure.
- Parameters
subtree
: name of the subtree to be committed.
-
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.
-
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_REGISTER_STATIC().
-