Skip to content
Permalink
Browse files

subsys/settings: Allow to register custom backends in settings subsystem

Major changes are:
- Expose settings backend API to enable custom backend support.
- Add a new CONFIG_SETTINGS_CUSTOM backend to allow registering a custom
backend.
- Change api of the handlers h_set() routines to allow for
backend-specific read callbacks.
- Provide a customizable settings_backend_init() routine for custom
backends.
- Move runtime settings support to be its own backend.

Signed-off-by: François Delawarde <fnde@oticon.com>
  • Loading branch information...
fnde-ot authored and jukkar committed Apr 2, 2019
1 parent 686830b commit 94451b22fcc6a068de2a2982b202772c6bbefae8
Showing with 727 additions and 532 deletions.
  1. +73 −15 doc/reference/storage/settings/settings.rst
  2. +122 −57 include/settings/settings.h
  3. +23 −28 samples/boards/nrf52/mesh/onoff_level_lighting_vnd_app/src/storage.c
  4. +11 −10 subsys/bluetooth/host/gatt.c
  5. +9 −7 subsys/bluetooth/host/keys.c
  6. +74 −54 subsys/bluetooth/host/mesh/settings.c
  7. +12 −12 subsys/bluetooth/host/settings.c
  8. +2 −1 subsys/bluetooth/host/settings.h
  9. +18 −3 subsys/settings/Kconfig
  10. +1 −0 subsys/settings/src/CMakeLists.txt
  11. +10 −119 subsys/settings/src/settings.c
  12. +37 −9 subsys/settings/src/settings_fcb.c
  13. +42 −14 subsys/settings/src/settings_file.c
  14. +27 −21 subsys/settings/src/settings_init.c
  15. +113 −2 subsys/settings/src/settings_line.c
  16. +22 −32 subsys/settings/src/settings_priv.h
  17. +68 −0 subsys/settings/src/settings_runtime.c
  18. +3 −101 subsys/settings/src/settings_store.c
  19. +1 −0 tests/subsys/settings/fcb/base64/prj.conf
  20. +1 −0 tests/subsys/settings/fcb/raw/prj.conf
  21. +24 −19 tests/subsys/settings/fcb/src/settings_test_fcb.c
  22. +1 −0 tests/subsys/settings/fcb_init/prj.conf
  23. +4 −3 tests/subsys/settings/fcb_init/src/settings_test_fcb_init.c
  24. +1 −0 tests/subsys/settings/nffs/base64/prj.conf
  25. +1 −0 tests/subsys/settings/nffs/raw/prj.conf
  26. +10 −8 tests/subsys/settings/nffs/src/settings_test_nffs.c
  27. +4 −4 tests/subsys/settings/src/settings_empty_lookups.c
  28. +3 −3 tests/subsys/settings/src/settings_test_commit.c
  29. +2 −2 tests/subsys/settings/src/settings_test_getset_int.c
  30. +4 −4 tests/subsys/settings/src/settings_test_getset_int64.c
  31. +4 −4 tests/subsys/settings/src/settings_test_getset_unknown.c
@@ -21,13 +21,13 @@ 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_get_value()``.
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 being set using ``settings_set_value()``,
and also when setting is loaded from persisted storage with
``settings_load()``.
This gets called when the value is loaded from persisted storage with
``settings_load()``, or when using ``settings_runtime_set()`` from the
runtime backend.

**h_commit**
This gets called after the settings have been loaded in full.
@@ -40,11 +40,38 @@ These are registered using a call to ``settings_register()``.
when ``settings_save()`` tries to save the settings or transfer to any
user-implemented back-end.

Persistence
***********
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()``.

Backend storage for the settings can be a Flash Circular Buffer (FCB)
or a file in the filesystem.
**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
(:option:`CONFIG_SETTINGS_FCB`) or a file in the filesystem
(:option:`CONFIG_SETTINGS_FS`).

You can declare multiple sources for settings; settings from
all of these are restored when ``settings_load()`` is called.
@@ -89,12 +116,12 @@ export functionality, for example, writing to the shell console).
.h_export = foo_settings_export
};

static int foo_settings_set(int argc, char **argv, void *value_ctx)
static int foo_settings_set(int argc, char **argv, settings_read_cb read_cb,
void *cb_arg)
{
if (argc == 1) {
if (!strcmp(argv[0], "bar")) {
return settings_val_read_cb(value_ctx, &foo_val,
sizeof(foo_val));
return read_cb(cb_arg, &foo_val, sizeof(foo_val));
}
}
@@ -129,12 +156,12 @@ up from where it was before restart.
.h_set = foo_settings_set
};

static int foo_settings_set(int argc, char **argv, void *value_ctx)
static int foo_settings_set(int argc, char **argv, settings_read_cb read_cb,
void *cb_arg)
{
if (argc == 1) {
if (!strcmp(argv[0], "bar")) {
return settings_val_read_cb(value_ctx, &foo_val,
sizeof(foo_val));
return read_cb(cb_arg, &foo_val, sizeof(foo_val));
}
}
@@ -152,6 +179,37 @@ up from where it was before restart.
sys_reboot(SYS_REBOOT_COLD);
}

Example: Custom Backend Implementation
**************************************

This is a simple example showing how to register a simple custom backend
handler (:option:`CONFIG_SETTINGS_CUSTOM`).

.. code-block:: c

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
*************

@@ -33,7 +33,7 @@ extern "C" {
*/
#define SETTINGS_EXTRA_LEN ((SETTINGS_MAX_DIR_DEPTH - 1) + 2)

#define SETTINGS_NMGR_OP 0
typedef ssize_t (*settings_read_cb)(void *cb_arg, void *data, size_t len);

/**
* @struct settings_handler
@@ -57,14 +57,16 @@ struct settings_handler {
* - val_len_max - size of that buffer.
*/

int (*h_set)(int argc, char **argv, void *value_ctx);
int (*h_set)(int argc, char **argv, size_t len,
settings_read_cb read_cb, void *cb_arg);
/**< Set value handler of settings items identified by keyword names.
*
* Parameters:
* - argc - count of item in argv, argv - array of pointers to keyword
* names.
* - value_ctx - pointer to the value context which is used parameter
* for data extracting routine (@ref settings_val_read_cb).
* - argc - count of item in argv.
* - argv - array of pointers to keyword names.
* - len - the size of the data found in the backend.
* - read_cb - function provided to read the data from the backend.
* - cb_arg - arguments for the read function provided by the backend.
*/

int (*h_commit)(void);
@@ -152,86 +154,149 @@ int settings_save_one(const char *name, void *value, size_t val_len);
int settings_delete(const char *name);

/**
* Set settings item identified by @p name to be value @p value.
* This finds the settings handler for this subtree and calls it's
* set handler.
*
* @param name Name/key of the settings item.
* @param value Pointer to the value of the settings item. This value will
* be transferred to the @ref settings_handler::h_set handler implementation.
* @param len Length of value string.
* 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_set_value(char *name, void *value, size_t len);
int settings_commit(void);

/**
* Get value of settings item identified by @p name.
* This calls the settings handler h_get for the subtree.
*
* Configuration handler should copy the string to @p buf, the maximum
* number of bytes it will copy is limited by @p buf_len.
* @} settings
*/


/*
* API for config storage
*/

struct settings_store_itf;

/**
* @struct settings_store
* Backend handler node for storage handling.
*/
struct settings_store {
sys_snode_t cs_next;
/**< Linked list node info for internal usage. */

const struct settings_store_itf *cs_itf;
/**< Backend handler structure. */
};

/**
* @struct settings_store_itf
* Backend handler functions.
* Sources are registered using a call to @ref settings_src_register.
* Destinations are registered using a call to @ref settings_dst_register.
*/
struct settings_store_itf {
int (*csi_load)(struct settings_store *cs);
/**< Loads all values from storage.
*
* Parameters:
* - cs - Corresponding backend handler node
*/

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
*/
};

/**
* Register a backend handler acting as source.
*
* @param name Name/key of the settings item.
* @param cs Backend handler node containing handler information.
*
* @param buf buffer for value of the settings item.
* If value is not string, the value will be filled in *buf.
*/
void settings_src_register(struct settings_store *cs);

/**
* Register a backend handler acting as destination.
*
* @param buf_len size of buf.
* @param cs Backend handler node containing handler information.
*
* @return Positive: Length of copied dat. Negative: -ERCODE
*/
int settings_get_value(char *name, char *buf, int buf_len);
void settings_dst_register(struct settings_store *cs);


/*
* API for handler lookup
*/

/**
* Call commit for all settings handler. This should apply all
* settings which has been set, but not applied yet.
* Parses a key to an array of elements and locate corresponding module handler.
*
* @param name Name of the settings subtree, or NULL to commit everything.
* @param name Key in string format
* @param name_argc Parsed number of elements.
* @param name_argv Parsed array of elements.
*
* @return 0 on success, non-zero on failure.
* @return settings_handler node on success, NULL on failure.
*/
struct settings_handler *settings_parse_and_lookup(char *name, int *name_argc,
char *name_argv[]);


/*
* API for runtime settings
*/
int settings_commit(char *name);

#ifdef CONFIG_SETTINGS_RUNTIME

/**
* Persistent data extracting routine.
*
* This function read and decode data from non-volatile storage to user buffer
* This function should be used inside set handler in order to read the settings
* data from backend storage.
* Set a value with a specific key to a module handler.
*
* @param[in] value_ctx Data context provided by the h_set handler.
* @param[out] buf Buffer for data read.
* @param[in] len Length of @p buf.
* @param name Key in string format.
* @param data Binary value.
* @param len Value length in bytes.
*
* @retval Negative value on failure. 0 and positive: Length of data loaded to
* the @p buf.
* @return 0 on success, non-zero on failure.
*/
int settings_val_read_cb(void *value_ctx, void *buf, size_t len);
int settings_runtime_set(const char *name, void *data, size_t len);

/**
* This function fetch length of decode data.
* This function should be used inside set handler in order to detect the
* settings data length.
* Get a value corresponding to a key from a module handler.
*
* @param[in] value_ctx Data context provided by the h_set handler.
* @param name Key in string format.
* @param data Returned binary value.
* @param len Returned value length in bytes.
*
* @retval length of data.
* @return 0 on success, non-zero on failure.
*/
size_t settings_val_get_len_cb(void *value_ctx);
int settings_runtime_get(const char *name, void *data, size_t len);

/**
* @} settings
* Apply settings in a module handler.
*
* @param name Key in string format.
*
* @return 0 on success, non-zero on failure.
*/
int settings_runtime_commit(const char *name);

#endif /* CONFIG_SETTINGS_RUNTIME */

/*
* Config storage
*/
struct settings_store_itf;
struct settings_store {
sys_snode_t cs_next;
const struct settings_store_itf *cs_itf;
};

#ifdef __cplusplus
}

0 comments on commit 94451b2

Please sign in to comment.
You can’t perform that action at this time.