samples/subsys: add sample for the settings
Added sample for the settings subsystem. The sample shows how to: -initialize and register handler -implement handles -save and load data using registered handlers -load subtree -save or delete a certain value -load subtree values or a value directly - example on how to write data to the setting destination and how to read data from the setting destination using runtime API. Signed-off-by: Andrzej Puzdrowski <andrzej.puzdrowski@nordicsemi.no>
This commit is contained in:
parent
a3e89e84a8
commit
580b0a9155
4 changed files with 564 additions and 0 deletions
9
samples/subsys/settings/CMakeLists.txt
Normal file
9
samples/subsys/settings/CMakeLists.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.13.1)
|
||||
#set(QEMU_EXTRA_FLAGS -s)
|
||||
|
||||
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
|
||||
project(settings_sample)
|
||||
|
||||
target_sources(app PRIVATE src/main.c)
|
2
samples/subsys/settings/boards/qemu_x86.conf
Normal file
2
samples/subsys/settings/boards/qemu_x86.conf
Normal file
|
@ -0,0 +1,2 @@
|
|||
CONFIG_NVS=y
|
||||
CONFIG_SETTINGS_NVS=y
|
7
samples/subsys/settings/prj.conf
Normal file
7
samples/subsys/settings/prj.conf
Normal file
|
@ -0,0 +1,7 @@
|
|||
CONFIG_STDOUT_CONSOLE=y
|
||||
CONFIG_FLASH=y
|
||||
CONFIG_FLASH_PAGE_LAYOUT=y
|
||||
CONFIG_FLASH_MAP=y
|
||||
|
||||
CONFIG_SETTINGS=y
|
||||
CONFIG_SETTINGS_RUNTIME=y
|
546
samples/subsys/settings/src/main.c
Normal file
546
samples/subsys/settings/src/main.c
Normal file
|
@ -0,0 +1,546 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "settings/settings.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/printk.h>
|
||||
|
||||
#define GAMMA_DEFAULT_VAl 0
|
||||
#define FAIL_MSG "fail (err %d)\n"
|
||||
#define SECTION_BEGIN_LINE \
|
||||
"\n=================================================\n"
|
||||
/* Default valuse are assigned to settings valuses consuments
|
||||
* All of them will be overwritten if storage contain proper key-values
|
||||
*/
|
||||
u8_t angle_val;
|
||||
u64_t length_val = 100;
|
||||
u16_t length_1_val = 40;
|
||||
u32_t length_2_val = 60;
|
||||
s32_t voltage_val = -3000;
|
||||
char source_name_val[6] = "";
|
||||
|
||||
int alpha_handle_set(const char *name, size_t len, settings_read_cb read_cb,
|
||||
void *cb_arg);
|
||||
int alpha_handle_commit(void);
|
||||
int alpha_handle_export(int (*cb)(const char *name,
|
||||
const void *value, size_t val_len));
|
||||
|
||||
int beta_handle_set(const char *name, size_t len, settings_read_cb read_cb,
|
||||
void *cb_arg);
|
||||
int beta_handle_commit(void);
|
||||
int beta_handle_export(int (*cb)(const char *name,
|
||||
const void *value, size_t val_len));
|
||||
int beta_handle_get(const char *name, char *val, int val_len_max);
|
||||
|
||||
/* dynamic main tree handler */
|
||||
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
|
||||
};
|
||||
|
||||
/* static subtree handler */
|
||||
SETTINGS_STATIC_HANDLER_DEFINE(beta, "alpha/beta", beta_handle_get,
|
||||
beta_handle_set, beta_handle_commit,
|
||||
beta_handle_export);
|
||||
|
||||
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;
|
||||
|
||||
if (settings_name_steq(name, "angle/1", &next) && !next) {
|
||||
if (len != sizeof(angle_val)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
rc = read_cb(cb_arg, &angle_val, sizeof(angle_val));
|
||||
printk("<alpha/angle/1> = %d\n", angle_val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
next_len = settings_name_next(name, &next);
|
||||
|
||||
if (!next) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
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> = %lld\n", length_val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (!strncmp(next, "2", next_len)) {
|
||||
rc = read_cb(cb_arg, &length_2_val,
|
||||
sizeof(length_2_val));
|
||||
printk("<alpha/length/2> = %d\n", length_2_val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int beta_handle_set(const char *name, size_t len, settings_read_cb read_cb,
|
||||
void *cb_arg)
|
||||
{
|
||||
const char *next;
|
||||
size_t name_len;
|
||||
int rc;
|
||||
|
||||
name_len = settings_name_next(name, &next);
|
||||
|
||||
if (!next) {
|
||||
if (!strncmp(name, "voltage", name_len)) {
|
||||
rc = read_cb(cb_arg, &voltage_val, sizeof(voltage_val));
|
||||
printk("<alpha/beta/voltage> = %d\n", voltage_val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strncmp(name, "source", name_len)) {
|
||||
if (len > sizeof(source_name_val) - 1) {
|
||||
printk("<alpha/beta/source> is not compatible "
|
||||
"with the application\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
rc = read_cb(cb_arg, source_name_val,
|
||||
sizeof(source_name_val));
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
} else if (rc > 0) {
|
||||
printk("<alpha/beta/source> = %s\n",
|
||||
source_name_val);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int alpha_handle_commit(void)
|
||||
{
|
||||
printk("loading all settings under <alpha> handler is done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
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/1", &angle_val, sizeof(angle_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;
|
||||
}
|
||||
|
||||
int beta_handle_export(int (*cb)(const char *name,
|
||||
const void *value, size_t val_len))
|
||||
{
|
||||
printk("export keys under <beta> handler\n");
|
||||
(void)cb("alpha/beta/voltage", &voltage_val, sizeof(voltage_val));
|
||||
(void)cb("alpha/beta/source", source_name_val, strlen(source_name_val) +
|
||||
1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int beta_handle_commit(void)
|
||||
{
|
||||
printk("loading all settings under <beta> handler is done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int beta_handle_get(const char *name, char *val, int val_len_max)
|
||||
{
|
||||
const char *next;
|
||||
|
||||
if (settings_name_steq(name, "source", &next) && !next) {
|
||||
val_len_max = MIN(val_len_max, strlen(source_name_val));
|
||||
memcpy(val, source_name_val, val_len_max);
|
||||
return val_len_max;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static void example_save_and_load_basic(void)
|
||||
{
|
||||
int i, rc;
|
||||
s32_t val_s32;
|
||||
|
||||
printk(SECTION_BEGIN_LINE);
|
||||
printk("basic load and save using registered handlers\n");
|
||||
/* load all key-values at once
|
||||
* In case a key-value doesn't exist in the storage
|
||||
* default valuse should be assigned to settings consuments variable
|
||||
* before any settings load call
|
||||
*/
|
||||
printk("\nload all key-value pairs using registered handlers\n");
|
||||
settings_load();
|
||||
|
||||
val_s32 = voltage_val - 25;
|
||||
/* save certain key-value directly*/
|
||||
printk("\nsave <alpha/beta/voltage> key directly: ");
|
||||
rc = settings_save_one("alpha/beta/voltage", (const void *)&val_s32,
|
||||
sizeof(val_s32));
|
||||
if (rc) {
|
||||
printk(FAIL_MSG, rc);
|
||||
}
|
||||
|
||||
printk("OK.\n");
|
||||
|
||||
printk("\nload <alpha/beta> key-value pairs using registered "
|
||||
"handlers\n");
|
||||
settings_load_subtree("alpha/beta");
|
||||
|
||||
/* save only modified values
|
||||
* or those that were not saved
|
||||
* before
|
||||
*/
|
||||
i = strlen(source_name_val);
|
||||
if (i < sizeof(source_name_val) - 1) {
|
||||
source_name_val[i] = 'a' + i;
|
||||
source_name_val[i + 1] = 0;
|
||||
} else {
|
||||
source_name_val[0] = 0;
|
||||
}
|
||||
|
||||
angle_val += 1;
|
||||
|
||||
printk("\nsave all key-value pairs using registered handlers\n");
|
||||
settings_save();
|
||||
|
||||
if (++length_1_val > 100) {
|
||||
length_1_val = 0;
|
||||
}
|
||||
|
||||
if (--length_2_val > 100) {
|
||||
length_2_val = 100;
|
||||
}
|
||||
|
||||
/*---------------------------
|
||||
* save only modified values
|
||||
* or those that were deleted
|
||||
* before
|
||||
*/
|
||||
printk("\nload all key-value pairs using registered handlers\n");
|
||||
settings_save();
|
||||
}
|
||||
|
||||
struct direct_length_data {
|
||||
u64_t length;
|
||||
u16_t length_1;
|
||||
u32_t length_2;
|
||||
};
|
||||
|
||||
static int direct_loader(const char *name, size_t len, settings_read_cb read_cb,
|
||||
void *cb_arg, void *param)
|
||||
{
|
||||
const char *next;
|
||||
size_t name_len;
|
||||
int rc;
|
||||
struct direct_length_data *dest = (struct direct_length_data *)param;
|
||||
|
||||
printk("direct load: ");
|
||||
|
||||
name_len = settings_name_next(name, &next);
|
||||
|
||||
if (name_len == 0) {
|
||||
rc = read_cb(cb_arg, &(dest->length), sizeof(dest->length));
|
||||
printk("<alpha/length>\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
name_len = settings_name_next(name, &next);
|
||||
if (next) {
|
||||
printk("nothing\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (!strncmp(name, "1", name_len)) {
|
||||
rc = read_cb(cb_arg, &(dest->length_1), sizeof(dest->length_1));
|
||||
printk("<alpha/length/1>\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strncmp(name, "2", name_len)) {
|
||||
rc = read_cb(cb_arg, &(dest->length_2), sizeof(dest->length_2));
|
||||
printk("<alpha/length/2>\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
printk("nothing\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static void example_direct_load_subtree(void)
|
||||
{
|
||||
struct direct_length_data dld;
|
||||
int rc;
|
||||
|
||||
/* load subtree directly using call-specific handler `direct_loader'
|
||||
* This handder loads subtree values to call-speciffic structure of type
|
||||
* 'direct_length_data`.
|
||||
*/
|
||||
printk(SECTION_BEGIN_LINE);
|
||||
printk("loading subtree to destination provided by the caller\n\n");
|
||||
rc = settings_load_subtree_direct("alpha/length", direct_loader,
|
||||
(void *)&dld);
|
||||
if (rc == 0) {
|
||||
printk(" direct.length = %lld\n", dld.length);
|
||||
printk(" direct.length_1 = %d\n", dld.length_1);
|
||||
printk(" direct.length_2 = %d\n", dld.length_2);
|
||||
} else {
|
||||
printk(" direct load fails unexpectedly\n");
|
||||
}
|
||||
}
|
||||
|
||||
struct direct_immediate_value {
|
||||
size_t len;
|
||||
void *dest;
|
||||
u8_t fetched;
|
||||
};
|
||||
|
||||
static int direct_loader_immediate_value(const char *name, size_t len,
|
||||
settings_read_cb read_cb, void *cb_arg,
|
||||
void *param)
|
||||
{
|
||||
const char *next;
|
||||
size_t name_len;
|
||||
int rc;
|
||||
struct direct_immediate_value *one_value =
|
||||
(struct direct_immediate_value *)param;
|
||||
|
||||
name_len = settings_name_next(name, &next);
|
||||
|
||||
if (name_len == 0) {
|
||||
if (len == one_value->len) {
|
||||
rc = read_cb(cb_arg, one_value->dest, len);
|
||||
if (rc >= 0) {
|
||||
one_value->fetched = 1;
|
||||
printk("immediate load: OK.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
printk(FAIL_MSG, rc);
|
||||
return rc;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* other keys aren't served by the calback
|
||||
* Return success in order to skip them
|
||||
* and keep storage processing.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
int load_immediate_value(const char *name, void *dest, size_t len)
|
||||
{
|
||||
int rc;
|
||||
struct direct_immediate_value dov;
|
||||
|
||||
dov.fetched = 0;
|
||||
dov.len = len;
|
||||
dov.dest = dest;
|
||||
|
||||
rc = settings_load_subtree_direct(name, direct_loader_immediate_value,
|
||||
(void *)&dov);
|
||||
if (rc == 0) {
|
||||
if (!dov.fetched) {
|
||||
rc = -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void example_without_handler(void)
|
||||
{
|
||||
u8_t val_u8;
|
||||
int rc;
|
||||
|
||||
printk(SECTION_BEGIN_LINE);
|
||||
printk("Service a key-value pair without dedicated handlers\n\n");
|
||||
rc = load_immediate_value("gamma", &val_u8, sizeof(val_u8));
|
||||
if (rc == -ENOENT) {
|
||||
val_u8 = GAMMA_DEFAULT_VAl;
|
||||
printk("<gamma> = %d (default)\n", val_u8);
|
||||
} else if (rc == 0) {
|
||||
printk("<gamma> = %d\n", val_u8);
|
||||
} else {
|
||||
printk("unexpected"FAIL_MSG, rc);
|
||||
}
|
||||
|
||||
val_u8++;
|
||||
|
||||
printk("save <gamma> key directly: ");
|
||||
rc = settings_save_one("gamma", (const void *)&val_u8,
|
||||
sizeof(val_u8));
|
||||
if (rc) {
|
||||
printk(FAIL_MSG, rc);
|
||||
} else {
|
||||
printk("OK.\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void example_initialization(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = settings_subsys_init();
|
||||
if (rc) {
|
||||
printk("settings subsys initialization: fail (err %d)\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
printk("settings subsys initialization: OK.\n");
|
||||
|
||||
rc = settings_register(&alph_handler);
|
||||
if (rc) {
|
||||
printk("subtree <%s> handler registered: fail (err %d)\n",
|
||||
alph_handler.name, rc);
|
||||
}
|
||||
|
||||
printk("subtree <%s> handler registered: OK\n", alph_handler.name);
|
||||
printk("subtree <alpha/beta> has static handler\n");
|
||||
}
|
||||
|
||||
static void example_delete(void)
|
||||
{
|
||||
u64_t val_u64;
|
||||
int rc;
|
||||
|
||||
printk(SECTION_BEGIN_LINE);
|
||||
printk("Delete a key-value pair\n\n");
|
||||
|
||||
rc = load_immediate_value("alpha/length", &val_u64, sizeof(val_u64));
|
||||
if (rc == 0) {
|
||||
printk(" <alpha/length> value exist in the storage\n");
|
||||
}
|
||||
|
||||
printk("delete <alpha/length>: ");
|
||||
rc = settings_delete("alpha/length");
|
||||
if (rc) {
|
||||
printk(FAIL_MSG, rc);
|
||||
} else {
|
||||
printk("OK.\n");
|
||||
}
|
||||
|
||||
rc = load_immediate_value("alpha/length", &val_u64, sizeof(val_u64));
|
||||
if (rc == -ENOENT) {
|
||||
printk(" Can't to load the <alpha/length> value as "
|
||||
"expected\n");
|
||||
}
|
||||
}
|
||||
|
||||
void example_runtime_usage(void)
|
||||
{
|
||||
int rc;
|
||||
u8_t injected_str[sizeof(source_name_val)] = "RT";
|
||||
|
||||
printk(SECTION_BEGIN_LINE);
|
||||
printk("Inject the value to the setting destination in runtime\n\n");
|
||||
|
||||
rc = settings_runtime_set("alpha/beta/source", (void *) injected_str,
|
||||
strlen(injected_str) + 1);
|
||||
|
||||
printk("injected <alpha/beta/source>: ");
|
||||
if (rc) {
|
||||
printk(FAIL_MSG, rc);
|
||||
} else {
|
||||
printk("OK.\n");
|
||||
}
|
||||
|
||||
printk(" The settings destination off the key <alpha/beta/source> has "
|
||||
"got value: \"%s\"\n\n", source_name_val);
|
||||
|
||||
/* set settins destination value "by hand" for next example */
|
||||
(void) strcpy(source_name_val, "rtos");
|
||||
|
||||
printk(SECTION_BEGIN_LINE);
|
||||
printk("Read a value from the setting destination in runtime\n\n");
|
||||
|
||||
rc = settings_runtime_get("alpha/beta/source", (void *) injected_str,
|
||||
strlen(injected_str) + 1);
|
||||
printk("fetched <alpha/beta/source>: ");
|
||||
if (rc < 0) {
|
||||
printk(FAIL_MSG, rc);
|
||||
} else {
|
||||
printk("OK.\n");
|
||||
}
|
||||
|
||||
printk(" String value \"%s\" was retrieved from the settings "
|
||||
"destination off the key <alpha/beta/source>\n",
|
||||
source_name_val);
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
|
||||
int i;
|
||||
|
||||
printk("\n*** Settings usage example ***\n\n");
|
||||
|
||||
/* settings initialization */
|
||||
example_initialization();
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
printk("\n##############\n");
|
||||
printk("# iteration %d", i);
|
||||
printk("\n##############\n");
|
||||
|
||||
/*---------------------------------------------
|
||||
* basic save and load using registered handler
|
||||
*/
|
||||
example_save_and_load_basic();
|
||||
|
||||
/*-------------------------------------------------
|
||||
*load subtree directly using call-specific handler
|
||||
*/
|
||||
example_direct_load_subtree();
|
||||
|
||||
/*-------------------------
|
||||
* delete certain kay-value
|
||||
*/
|
||||
example_delete();
|
||||
|
||||
/*---------------------------------------
|
||||
* a key-value without dedicated handler
|
||||
*/
|
||||
example_without_handler();
|
||||
}
|
||||
|
||||
/*------------------------------------------------------
|
||||
* write and read settings destination using runtime API
|
||||
*/
|
||||
example_runtime_usage();
|
||||
|
||||
printk("\n*** THE END ***\n");
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue