settings: Direct loading functionality

This commit allows loading data from settings permanent storage
directly to the given callback function.

Signed-off-by: Radoslaw Koppel <radoslaw.koppel@nordicsemi.no>
This commit is contained in:
Radoslaw Koppel 2019-09-09 16:27:02 +02:00 committed by Ioannis Glaropoulos
commit 6c2add5445
9 changed files with 288 additions and 49 deletions

View file

@ -226,6 +226,59 @@ int settings_load(void);
*/
int settings_load_subtree(const char *subtree);
/**
* Callback function used for direct loading.
* Used by @ref settings_load_subtree_direct function.
*
* @param[in] key the name with skipped part that was used as name in
* handler registration
* @param[in] len the size of the data found in the backend.
* @param[in] read_cb function provided to read the data from the backend.
* @param[in,out] cb_arg arguments for the read function provided by the
* backend.
* @param[in,out] param parameter given to the
* @ref settings_load_subtree_direct function.
*
* - 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 When nonzero value is returned, further subtree searching is stopped.
* Use with care as some settings backends would iterate through old
* values, and the current value is returned last.
*/
typedef int (*settings_load_direct_cb)(
const char *key,
size_t len,
settings_read_cb read_cb,
void *cb_arg,
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.
*
* @param[in] subtree subtree name of the subtree to be loaded.
* @param[in] cb pointer to the callback function.
* @param[in,out] param parameter to be passed when callback
* function is called.
* @return 0 on success, non-zero on failure.
*/
int settings_load_subtree_direct(
const char *subtree,
settings_load_direct_cb cb,
void *param);
/**
* Save currently running serialized items. All serialized items which are
* different from currently persisted values will be saved.
@ -307,12 +360,17 @@ struct settings_store {
* Destinations are registered using a call to @ref settings_dst_register.
*/
struct settings_store_itf {
int (*csi_load)(struct settings_store *cs, const char *subtree);
/**< Loads values from storage limited to subtree defined by subtree. If
* subtree = NULL loads all values.
int (*csi_load)(struct settings_store *cs, const char *subtree,
settings_load_direct_cb cb, void *param);
/**< Loads values from storage limited to subtree defined by subtree.
*
* Parameters:
* - cs - Corresponding backend handler node
* - subtree - subtree name of the subtree to be loaded,
* if NULL loads all values.
* - cb - pointer to the callback function,
* if NULL then matching registered function would be used.
* - param - parameter to be passed when callback function is called.
*/
int (*csi_save_start)(struct settings_store *cs);

View file

@ -46,7 +46,9 @@ static struct bt_conn_cb conn_callbacks = {
};
static int zephyr_settings_fw_load(struct settings_store *cs,
const char *subtree);
const char *subtree,
settings_load_direct_cb cb,
void *param);
static const struct settings_store_itf zephyr_settings_fw_itf = {
.csi_load = zephyr_settings_fw_load,
@ -57,9 +59,13 @@ static struct settings_store zephyr_settings_fw_store = {
};
static int zephyr_settings_fw_load(struct settings_store *cs,
const char *subtree)
const char *subtree,
settings_load_direct_cb cb,
void *param)
{
/* Ignore subtree and direct loading */
if (subtree || cb)
return 0;
#if defined(CONFIG_BT_GATT_DIS_SETTINGS)
settings_runtime_set("bt/dis/model",
"Zephyr Model",

View file

@ -23,7 +23,8 @@ struct settings_fcb_load_cb_arg {
void *cb_arg;
};
static int settings_fcb_load(struct settings_store *cs, const char *subtree);
static int settings_fcb_load(struct settings_store *cs, const char *subtree,
settings_load_direct_cb cb, void *param);
static int settings_fcb_save(struct settings_store *cs, const char *name,
const char *value, size_t val_len);
@ -117,10 +118,15 @@ static int settings_fcb_load_priv(struct settings_store *cs, line_load_cb cb,
return 0;
}
static int settings_fcb_load(struct settings_store *cs, const char *subtree)
static int settings_fcb_load(struct settings_store *cs, const char *subtree,
settings_load_direct_cb cb, void *param)
{
return settings_fcb_load_priv(cs, settings_line_load_cb,
(void *)subtree);
struct settings_line_load_arg arg = {
.subtree = subtree,
.direct_cb = cb,
.param = param
};
return settings_fcb_load_priv(cs, settings_line_load_cb, &arg);
}

View file

@ -14,7 +14,8 @@
#include "settings/settings_file.h"
#include "settings_priv.h"
static int settings_file_load(struct settings_store *cs, const char *subtree);
static int settings_file_load(struct settings_store *cs, const char *subtree,
settings_load_direct_cb cb, void *param);
static int settings_file_save(struct settings_store *cs, const char *name,
const char *value, size_t val_len);
@ -109,10 +110,15 @@ static int settings_file_load_priv(struct settings_store *cs, line_load_cb cb,
/*
* Called to load configuration items.
*/
static int settings_file_load(struct settings_store *cs, const char *subtree)
static int settings_file_load(struct settings_store *cs, const char *subtree,
settings_load_direct_cb cb, void *param)
{
return settings_file_load_priv(cs, settings_line_load_cb,
(void *)subtree);
struct settings_line_load_arg arg = {
.subtree = subtree,
.direct_cb = cb,
.param = param
};
return settings_file_load_priv(cs, settings_line_load_cb, &arg);
}
static void settings_tmpfile(char *dst, const char *src, char *pfx)

View file

@ -497,7 +497,7 @@ static int settings_line_cmp(char const *val, size_t val_len,
return rc;
}
void settings_line_dup_check_cb(const char *name, void *val_read_cb_ctx,
int settings_line_dup_check_cb(const char *name, void *val_read_cb_ctx,
off_t off, void *cb_arg)
{
struct settings_line_dup_check_arg *cdca;
@ -505,7 +505,7 @@ void settings_line_dup_check_cb(const char *name, void *val_read_cb_ctx,
cdca = (struct settings_line_dup_check_arg *)cb_arg;
if (strcmp(name, cdca->name)) {
return;
return 0;
}
len_read = settings_line_val_get_len(off, val_read_cb_ctx);
@ -521,6 +521,7 @@ void settings_line_dup_check_cb(const char *name, void *val_read_cb_ctx,
cdca->is_dup = 0;
}
}
return 0;
}
static ssize_t settings_line_read_cb(void *cb_arg, void *data, size_t len)
@ -540,29 +541,34 @@ static ssize_t settings_line_read_cb(void *cb_arg, void *data, size_t len)
return -1;
}
void settings_line_load_cb(const char *name, void *val_read_cb_ctx, off_t off,
int settings_line_load_cb(const char *name, void *val_read_cb_ctx, off_t off,
void *cb_arg)
{
const char *name_key;
struct settings_handler_static *ch;
struct settings_line_read_value_cb_ctx value_ctx;
struct settings_line_load_arg *arg = cb_arg;
int rc;
size_t len;
if (cb_arg && !settings_name_steq(name, cb_arg, NULL)) {
return;
}
ch = settings_parse_and_lookup(name, &name_key);
if (!ch) {
return;
if (arg && arg->subtree &&
!settings_name_steq(name, arg->subtree, &name_key)) {
return 0;
}
value_ctx.read_cb_ctx = val_read_cb_ctx;
value_ctx.off = off;
len = settings_line_val_get_len(off, val_read_cb_ctx);
if (arg && arg->direct_cb) {
rc = arg->direct_cb(name_key, len, settings_line_read_cb,
(void *)&value_ctx, arg->param);
} else {
ch = settings_parse_and_lookup(name, &name_key);
if (!ch) {
return 0;
}
rc = ch->h_set(name_key, len, settings_line_read_cb,
(void *)&value_ctx);
@ -573,5 +579,6 @@ void settings_line_load_cb(const char *name, void *val_read_cb_ctx, off_t off,
LOG_DBG("set-value OK. key: %s",
log_strdup(name));
}
(void)rc;
}
return rc;
}

View file

@ -20,7 +20,8 @@ struct settings_nvs_read_fn_arg {
u16_t id;
};
static int settings_nvs_load(struct settings_store *cs, const char *subtree);
static int settings_nvs_load(struct settings_store *cs, const char *subtree,
settings_load_direct_cb cb, void *param);
static int settings_nvs_save(struct settings_store *cs, const char *name,
const char *value, size_t val_len);
@ -62,7 +63,8 @@ int settings_nvs_dst(struct settings_nvs *cf)
return 0;
}
static int settings_nvs_load(struct settings_store *cs, const char *subtree)
static int settings_nvs_load(struct settings_store *cs, const char *subtree,
settings_load_direct_cb cb, void *param)
{
struct settings_nvs *cf = (struct settings_nvs *)cs;
struct settings_nvs_read_fn_arg read_fn_arg;
@ -113,20 +115,29 @@ static int settings_nvs_load(struct settings_store *cs, const char *subtree)
/* Found a name, this might not include a trailing \0 */
name[rc1] = '\0';
if (subtree && !settings_name_steq(name, subtree, NULL)) {
continue;
}
ch = settings_parse_and_lookup(name, &name_argv);
if (!ch) {
if (subtree && !settings_name_steq(name, subtree, &name_argv)) {
continue;
}
read_fn_arg.fs = &cf->cf_nvs;
read_fn_arg.id = name_id + NVS_NAME_ID_OFFSET;
if (cb) {
int ret;
ret = cb(name_argv, rc2, settings_nvs_read_fn,
(void *) &read_fn_arg, param);
if (ret)
return ret;
} else {
ch = settings_parse_and_lookup(name, &name_argv);
if (!ch) {
continue;
}
ch->h_set(name_argv, rc2, settings_nvs_read_fn,
(void *) &read_fn_arg);
}
}
return 0;
}

View file

@ -11,6 +11,7 @@
#include <sys/types.h>
#include <sys/slist.h>
#include <errno.h>
#include <settings/settings.h>
#ifdef __cplusplus
extern "C" {
@ -36,15 +37,21 @@ int settings_line_write(const char *name, const char *value, size_t val_len,
/* Get len of record without alignment to write-block-size */
int settings_line_len_calc(const char *name, size_t val_len);
void settings_line_dup_check_cb(const char *name, void *val_read_cb_ctx,
int settings_line_dup_check_cb(const char *name, void *val_read_cb_ctx,
off_t off, void *cb_arg);
void settings_line_load_cb(const char *name, void *val_read_cb_ctx,
int settings_line_load_cb(const char *name, void *val_read_cb_ctx,
off_t off, void *cb_arg);
typedef void (*line_load_cb)(const char *name, void *val_read_cb_ctx,
typedef int (*line_load_cb)(const char *name, void *val_read_cb_ctx,
off_t off, void *cb_arg);
struct settings_line_load_arg {
const char *subtree;
settings_load_direct_cb direct_cb;
void *param;
};
struct settings_line_read_value_cb_ctx {
void *read_cb_ctx;
off_t off;

View file

@ -60,13 +60,34 @@ int settings_load_subtree(const char *subtree)
*/
k_mutex_lock(&settings_lock, K_FOREVER);
SYS_SLIST_FOR_EACH_CONTAINER(&settings_load_srcs, cs, cs_next) {
cs->cs_itf->csi_load(cs, subtree);
cs->cs_itf->csi_load(cs, subtree, NULL, NULL);
}
rc = settings_commit_subtree(subtree);
k_mutex_unlock(&settings_lock);
return rc;
}
int settings_load_subtree_direct(
const char *subtree,
settings_load_direct_cb cb,
void *param)
{
struct settings_store *cs;
/*
* for every config store
* load config
* apply config
* commit all
*/
k_mutex_lock(&settings_lock, K_FOREVER);
SYS_SLIST_FOR_EACH_CONTAINER(&settings_load_srcs, cs, cs_next) {
cs->cs_itf->csi_load(cs, subtree, cb, param);
}
k_mutex_unlock(&settings_lock);
return 0;
}
/*
* Append a single value to persisted config. Don't store duplicate value.
*/

View file

@ -322,12 +322,129 @@ static void test_register_and_loading(void)
zassert_true(rc, "deregistering val1_settings failed");
}
int val123_set(const char *key, size_t len,
settings_read_cb read_cb, void *cb_arg)
{
int rc;
u8_t val;
zassert_equal(1, len, "Unexpected size");
rc = read_cb(cb_arg, &val, sizeof(val));
zassert_equal(sizeof(val), rc, "read_cb failed");
if (!strcmp("1", key)) {
data.val1 = val;
data.en1 = true;
return 0;
}
if (!strcmp("2", key)) {
data.val2 = val;
data.en2 = true;
return 0;
}
if (!strcmp("3", key)) {
data.val3 = val;
data.en3 = true;
return 0;
}
zassert_unreachable("Unexpected key value: %s", key);
return 0;
}
static struct settings_handler val123_settings = {
.name = "val",
.h_set = val123_set,
};
unsigned int direct_load_cnt;
u8_t val_directly_loaded;
int direct_loader(
const char *key,
size_t len,
settings_read_cb read_cb,
void *cb_arg,
void *param)
{
int rc;
u8_t val;
zassert_equal(0x1234, (size_t)param, NULL);
zassert_equal(1, len, NULL);
zassert_is_null(key, "Unexpected key: %s", key);
zassert_not_null(cb_arg, NULL);
rc = read_cb(cb_arg, &val, sizeof(val));
zassert_equal(sizeof(val), rc, NULL);
val_directly_loaded = val;
direct_load_cnt += 1;
return 0;
}
static void test_direct_loading(void)
{
int rc;
u8_t val;
val = 11;
settings_save_one("val/1", &val, sizeof(u8_t));
val = 23;
settings_save_one("val/2", &val, sizeof(u8_t));
val = 35;
settings_save_one("val/3", &val, sizeof(u8_t));
rc = settings_register(&val123_settings);
zassert_true(rc == 0, NULL);
memset(&data, 0, sizeof(data));
rc = settings_load();
zassert_true(rc == 0, NULL);
zassert_equal(11, data.val1, NULL);
zassert_equal(23, data.val2, NULL);
zassert_equal(35, data.val3, NULL);
/* Load subtree */
memset(&data, 0, sizeof(data));
rc = settings_load_subtree("val/2");
zassert_true(rc == 0, NULL);
zassert_equal(0, data.val1, NULL);
zassert_equal(23, data.val2, NULL);
zassert_equal(0, data.val3, NULL);
/* Direct loading now */
memset(&data, 0, sizeof(data));
val_directly_loaded = 0;
direct_load_cnt = 0;
rc = settings_load_subtree_direct(
"val/2",
direct_loader,
(void *)0x1234);
zassert_true(rc == 0, NULL);
zassert_equal(0, data.val1, NULL);
zassert_equal(0, data.val2, NULL);
zassert_equal(0, data.val3, NULL);
zassert_equal(1, direct_load_cnt, NULL);
zassert_equal(23, val_directly_loaded, NULL);
}
void test_main(void)
{
ztest_test_suite(settings_test_suite,
ztest_unit_test(test_clear_settings),
ztest_unit_test(test_support_rtn),
ztest_unit_test(test_register_and_loading)
ztest_unit_test(test_register_and_loading),
ztest_unit_test(test_direct_loading)
);
ztest_run_test_suite(settings_test_suite);