| /* |
| * 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> |
| |
| #if IS_ENABLED(CONFIG_SETTINGS_FS) |
| #include <fs/fs.h> |
| #include <fs/littlefs.h> |
| #endif |
| |
| #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; |
| |
| #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 *)DT_FLASH_AREA_STORAGE_ID, |
| .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 initiqalized: 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) |
| { |
| 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"); |
| } |