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:
parent
f965b9c685
commit
6c2add5445
9 changed files with 288 additions and 49 deletions
|
@ -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);
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue