zephyr settings part 2: persistence of multiple key-values (handler)
July 29, 2022•474 words
(modified code from the settings sample https://github.com/nrfconnect/sdk-zephyr/tree/main/samples/subsys/settings )
I wondered how "settings" knew about the keys it had to load. Some tests showed that it "auto-finds" out the keys reading the storage. So be sure to define default values for your new keys because they will only "exist" for "settings" once they have been stored. It is recommended to erase the board once you have made changes to your settings in your code (variable type, keys name...) because it might cause strange behaviors if the stored settings are out of sync with your code.
You can register your handlers manually at runtime with settings_register(&alph_handler);
with:
struct settings_handler alph_handler = {
.name = "alpha",
.h_get = NULL,
.h_set = alpha_handle_set,
.h_commit = alpha_handle_commit,
.h_export = alpha_handle_export
};
or you can do it statically with the SETTINGS_STATIC_HANDLER_DEFINE
macro
SETTINGS_STATIC_HANDLER_DEFINE(alpha, "alpha", NULL,
alpha_handle_set, NULL,
alpha_handle_export);
so you don't need to call settings_register();
5 keys
"alpha/angle"
"alpha/angle/1"
"alpha/length"
"alpha/length/1"
"alpha/length/2"
#include "settings/settings.h"
#include "inttypes.h"
#include <string.h>
//your variables corresponding to the keys
uint8_t angle_val=0;
uint64_t angle_1_val=200;
uint64_t length_val = 100;
uint16_t length_1_val = 40;
char * length_2_val = "old string";
//the following handler will read the value in storage and set the corresponding variable:
int alpha_handle_set(const char *name, size_t len, settings_read_cb read_cb,
void *cb_arg)
{
const char *next;
size_t next_len;
int rc;
printk("name = %s\n", name);
next_len = settings_name_next(name, &next);
//matches alpha/length
if (!strncmp(name, "angle", next_len)) {
next_len = settings_name_next(name, &next);
if (!next) {
rc = read_cb(cb_arg, &angle_val, sizeof(angle_val));
printk("<alpha/angle> = %d\n", angle_val);
angle_val++;
return 0;
}
//matches alpha/length/1
if (!strncmp(next, "1", angle_1_val)) {
rc = read_cb(cb_arg, &angle_1_val,
sizeof(angle_1_val));
angle_1_val++;
printk("<alpha/angle/1> = %" PRId64 "\n", angle_1_val);
return 0;
}
return -ENOENT;
}
next_len = settings_name_next(name, &next);
//matches alpha/length
if (!strncmp(name, "length", next_len)) {
next_len = settings_name_next(name, &next);
if (!next) {
rc = read_cb(cb_arg, &length_val, sizeof(length_val));
printk("<alpha/length> = %" PRId64 "\n", length_val);
length_val++;
return 0;
}
//matches alpha/length/1
if (!strncmp(next, "1", next_len)) {
rc = read_cb(cb_arg, &length_1_val,
sizeof(length_1_val));
printk("<alpha/length/1> = %d\n", length_1_val);
return 0;
}
//matches alpha/length/2
if (!strncmp(next, "2", next_len)) {
rc = read_cb(cb_arg, &length_2_val,
sizeof(length_2_val));
printk("<alpha/length/2> = %s\n", length_2_val);
return 0;
}
return -ENOENT;
}
return -ENOENT;
}
//alpha_handle_export will store the values on the backend:
int alpha_handle_export(int (*cb)(const char *name,
const void *value, size_t val_len))
{
printk("export keys under <alpha> handler\n");
(void)cb("alpha/angle", &angle_val, sizeof(angle_val));
(void)cb("alpha/angle/1", &angle_1_val, sizeof(angle_1_val));
(void)cb("alpha/length", &length_val, sizeof(length_val));
(void)cb("alpha/length/1", &length_1_val, sizeof(length_1_val));
(void)cb("alpha/length/2", &length_2_val, sizeof(length_2_val));
return 0;
}
SETTINGS_STATIC_HANDLER_DEFINE(alpha, "alpha", NULL,
alpha_handle_set, NULL,
alpha_handle_export);
void main(void)
{
int rc;
rc = settings_subsys_init();
if (rc)
{
printk("settings subsys initialization: fail (err %d)\n", rc);
return;
}
settings_load();
printk("angle_val %i\n", angle_val);
angle_val++;
printk("angle_1_val %" PRId64 "\n", angle_1_val);
angle_1_val++;
printk("length_val %" PRId64 "\n", length_val);
length_val++;
printk("length_1_val %i\n", length_1_val);
length_1_val++;
printk("length_2_val %s\n", length_2_val);
if (!strcmp(length_2_val, "old string"))
{
length_2_val = "newstring";
}
else
{
length_2_val = "old string";
}
settings_save();
}