blob: 6fd1051fe57d47e3fba4c5ee15ab17030eb2a388 [file] [log] [blame]
/*
* Copyright (c) 2019 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include <zephyr/settings/settings.h>
#include <errno.h>
#include <zephyr/sys/printk.h>
#if IS_ENABLED(CONFIG_SETTINGS_FS)
#include <zephyr/fs/fs.h>
#include <zephyr/fs/littlefs.h>
#endif
#define GAMMA_DEFAULT_VAl 0
#define FAIL_MSG "fail (err %d)\n"
#define SECTION_BEGIN_LINE \
"\n=================================================\n"
/* Default values are assigned to settings values consuments
* All of them will be overwritten if storage contain proper key-values
*/
uint8_t angle_val;
uint64_t length_val = 100;
uint16_t length_1_val = 40;
uint32_t length_2_val = 60;
int32_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> = %" PRId64 "\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;
int32_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 values 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 {
uint64_t length;
uint16_t length_1;
uint32_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 handler loads subtree values to call-specific 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 = %" PRId64 "\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;
uint8_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 callback
* 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)
{
uint8_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;
#if IS_ENABLED(CONFIG_SETTINGS_FS)
FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(cstorage);
/* mounting info */
static struct fs_mount_t littlefs_mnt = {
.type = FS_LITTLEFS,
.fs_data = &cstorage,
.storage_dev = (void *)FLASH_AREA_ID(storage),
.mnt_point = "/ff"
};
rc = fs_mount(&littlefs_mnt);
if (rc != 0) {
printk("mounting littlefs error: [%d]\n", rc);
} else {
rc = fs_unlink(CONFIG_SETTINGS_FS_FILE);
if ((rc != 0) && (rc != -ENOENT)) {
printk("can't delete config file%d\n", rc);
} else {
printk("FS initialized: OK\n");
}
}
#endif
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)
{
uint64_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;
uint8_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 settings 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");
}