Skip to content

Commit

Permalink
subsys: settings: Reworked settings module
Browse files Browse the repository at this point in the history
Preparation to fix zephyrproject-rtos#12160 - settings NVS backend

To allow easier integration of backends the settings module has been
reworked. Major changes are:

1. Change to the api: the set() routines are now of the form:
	''set(int argc, char **argv, size_t len, read_cb read, void *cb_arg)''
	the length that was found in the backend in len, and the data
	can be read using: ''read(data, len, cb_arg);
2. The reading of data in the set routines is directly reading in the
backend.
3. The records no longer need to be in the line format
4. The runtime interface has been removed (temporarily). A runtime
backend will be added.
5. Only the fcb backend is supported at the moment
6. A sample is added under samples/subsys/nsettings

Signed-off-by: Laczen JMS <laczenjms@gmail.com>
  • Loading branch information
Laczen committed Jan 10, 2019
1 parent 0fbcf03 commit 2e632d8
Show file tree
Hide file tree
Showing 16 changed files with 1,506 additions and 0 deletions.
185 changes: 185 additions & 0 deletions include/nsettings/settings.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
/*
* Copyright (c) 2018 Nordic Semiconductor ASA
* Copyright (c) 2015 Runtime Inc
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef ZEPHYR_INCLUDE_SETTINGS_SETTINGS_H_
#define ZEPHYR_INCLUDE_SETTINGS_SETTINGS_H_

#include <sys/types.h>
#include <misc/util.h>
#include <misc/slist.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
* @defgroup settings Settings subsystem
* @ingroup file_system_storage
* @{
*/

#define SETTINGS_MAX_DIR_DEPTH 8 /* max depth of settings tree */
#define SETTINGS_MAX_NAME_LEN (8 * SETTINGS_MAX_DIR_DEPTH)
#define SETTINGS_MAX_VAL_LEN 256
#define SETTINGS_NAME_SEPARATOR "/"

/* pleace for settings additions:
* up to 7 separators, '=', '\0'
*/
#define SETTINGS_EXTRA_LEN ((SETTINGS_MAX_DIR_DEPTH - 1) + 2)

#define SETTINGS_NMGR_OP 0

typedef ssize_t (*read_cb)(void *data, size_t len, void *cb_arg);

/**
* @struct settings_handler
* Config handlers for subtree implement a set of handler functions.
* These are registered using a call to @ref settings_register.
*/
struct settings_handler {
sys_snode_t node;
/**< Linked list node info for module internal usage. */

char *name;
/**< Name of subtree. */

int (*h_get)(int argc, char **argv, char *val, int val_len_max);
/**< Get values handler of settings items identified by keyword names.
*
* Parameters:
* - argc - count of item in argv.
* - argv - array of pointers to keyword names.
* - val - buffer for a value.
* - val_len_max - size of that buffer.
*/

int (*h_set)(int argc, char **argv, size_t len, read_cb read,
void *cb_arg);
/**< Set value handler of settings items identified by keyword names.
*
* Parameters:
* - argc - count of item in argv, argv - array of pointers to keyword
* names.
* - len - the size of the data found in the backend
* - read - function provided to read the data from the backend
* - cb_arg - arguments for the read function provided by the backend
*/

int (*h_commit)(void);
/**< This handler gets called after settings has been loaded in full.
* User might use it to apply setting to the application.
*/

int (*h_export)(int (*export_func)(const char *name, void *val,
size_t val_len));
/**< This gets called to dump all current settings items.
*
* This happens when @ref settings_save tries to save the settings.
* Parameters:
* - export_func: the pointer to the internal function which appends
* a single key-value pair to persisted settings. Don't store
* duplicated value. The name is subtree/key string, val is the string
* with value.
*
* @remarks The User might limit a implementations of handler to serving
* only one keyword at one call - what will impose limit to get/set
* values using full subtree/key name.
*/
};

/**
* Initialization of settings and backend
*
* Can be called at application startup.
* In case the backend is NFFS Remember to call it after FS was mounted.
* For FCB backend it can be called without such a restriction.
*
* @return 0 on success, non-zero on failure.
*/
int settings_subsys_init(void);

/**
* Register a handler for settings items.
*
* @param cf Structure containing registration info.
*
* @return 0 on success, non-zero on failure.
*/
int settings_register(struct settings_handler *cf);

/**
* Load serialized items from registered persistence sources. Handlers for
* serialized item subtrees registered earlier will be called for encountered
* values.
*
* @return 0 on success, non-zero on failure.
*/
int settings_load(void);

/**
* Save currently running serialized items. All serialized items which are
* different from currently persisted values will be saved.
*
* @return 0 on success, non-zero on failure.
*/
int settings_save(void);

/**
* Write a single serialized value to persisted storage (if it has
* changed value).
*
* @param name Name/key of the settings item.
* @param value Pointer to the value of the settings item. This value will
* be transferred to the @ref settings_handler::h_export handler implementation.
* @param val_len Length of the value.
*
* @return 0 on success, non-zero on failure.
*/
int settings_save_one(const char *name, void *value, size_t val_len);

/**
* Delete a single serialized in persisted storage.
*
* Deleting an existing key-value pair in the settings mean
* to set its value to NULL.
*
* @param name Name/key of the settings item.
*
* @return 0 on success, non-zero on failure.
*/
int settings_delete(const char *name);

/**
* Call commit for all settings handler. This should apply all
* settings which has been set, but not applied yet.
*
* @param name Name of the settings subtree, or NULL to commit everything.
*
* @return 0 on success, non-zero on failure.
*/
int settings_commit(char *name);

/**
* @} settings
*/

/*
* Config storage
*/
struct settings_store_itf;
struct settings_store {
sys_snode_t cs_next;
const struct settings_store_itf *cs_itf;
};

#ifdef __cplusplus
}
#endif

#endif /* ZEPHYR_INCLUDE_SETTINGS_SETTINGS_H_ */
6 changes: 6 additions & 0 deletions samples/subsys/nsettings/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 3.8.2)
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
project(nsetting)

FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})
68 changes: 68 additions & 0 deletions samples/subsys/nsettings/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
.. _nvs-sample:

NVS: Non-Volatile Storage
#########################

Overview
********

This is a simple application demonstrating use of the NVS
module for non-volatile (flash) storage. In this application,
a counter is incremented on every reboot and stored in flash,
the application reboots, and the reboot counter data is retrieved.

Requirements
************

* A board with flash support

Building and Running
********************

This sample can be found under :file:`samples/subsys/nvs` in the Zephyr tree.

The sample can be build for several platforms, the following commands build the
application for the nrf51_pca10028 board.

.. zephyr-app-commands::
:zephyr-app: samples/subsys/nvs
:board: nrf51_pca10028
:goals: build flash
:compact:

After flashing the image to the board the output on the console shows the
reboot counter and the boards reboots several times to show the reboot counter
is incremented.

Sample Output
=============

.. code-block:: console
***** Booting Zephyr OS v1.12.0-rc1-176-gf091be783 *****
[fs/nvs] [DBG] nvs_reinit: (Re)Initializing sectors
[fs/nvs] [DBG] _nvs_sector_init: f->write_location set to c
[fs/nvs] [INF] nvs_init: maximum storage length 256 byte
[fs/nvs] [INF] nvs_init: write-align: 1, write-addr: c
[fs/nvs] [INF] nvs_init: entry sector: 0, entry sector ID: 1
No address found, adding 192.168.1.1 at id 1
No key found, adding it at id 2
No Reboot counter found, adding it at id 3
Id: 4 not found, adding it
Longarray not found, adding it as id 4
Reboot counter history: ...0
Oldest reboot counter: 0
Rebooting in ...5...4...3...2...1
***** Booting Zephyr OS v1.12.0-rc1-176-gf091be783 *****
[fs/nvs] [INF] nvs_init: maximum storage length 256 byte
[fs/nvs] [INF] nvs_init: write-align: 1, write-addr: c7
[fs/nvs] [INF] nvs_init: entry sector: 0, entry sector ID: 1
Entry: 1, Address: 192.168.1.1
Id: 2, Key: ff fe fd fc fb fa f9 f8
Id: 3, Reboot_counter: 1
Id: 4, Data: DATA
Id: 5, Longarray: 0 1 2 3 4 5 6 7 8 9 a b c d e f 10 11 12 13 14 15 16 17 18
Reboot counter history: ...1...0
Oldest reboot counter: 0
Rebooting in ...5...4...3...2...1
...
10 changes: 10 additions & 0 deletions samples/subsys/nsettings/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CONFIG_FLASH=y
CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_FLASH_MAP=y
CONFIG_FCB=y
CONFIG_NSETTINGS=y
CONFIG_NSETTINGS_FCB=y

CONFIG_LOG=y
CONFIG_REBOOT=y
CONFIG_MPU_ALLOW_FLASH_WRITE=y
7 changes: 7 additions & 0 deletions samples/subsys/nsettings/sample.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
sample:
name: Settings Sample

tests:
test:
tags: settings
depends_on: nsettings
96 changes: 96 additions & 0 deletions samples/subsys/nsettings/src/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* NSETTINGS Sample for Zephyr
*
* Copyright (c) 2018 Laczen
*
* SPDX-License-Identifier: Apache-2.0
*/


#include <zephyr.h>
#include <misc/reboot.h>
#include <device.h>
#include <string.h>
#include <nsettings/settings.h>

/* 1000 msec = 1 sec */
#define SLEEP_TIME 10000

u8_t reset_counter;

static int ps_set(int argc, char **argv, size_t len, read_cb read, void *cb_arg)
{
int rc;

if (argc == 1) {
if (!strcmp(argv[0], "ra0")) {
rc = read(&reset_counter, sizeof(reset_counter),
cb_arg);
printk("ra0 found\n");
}
if (!strcmp(argv[0], "ra1")) {
printk("ra1 found\n");
}
if (!strcmp(argv[0], "ra2")) {
printk("ra2 found\n");
}
if (!strcmp(argv[0], "rb")) {
printk("rb found\n");
}
return (len < 0) ? len : 0;
}

return -ENOENT;
}

static struct settings_handler ps_settings = {
.name = "ps",
.h_set = ps_set,
};

int ps_settings_init(void)
{
int err;

err = settings_subsys_init();
if (err) {
printk("settings_subsys_init failed (err %d)\n", err);
return err;
}

err = settings_register(&ps_settings);
if (err) {
printk("ps_settings_register failed (err %d)\n", err);
return err;
}
return 0;
}

void main(void)
{
reset_counter = 0U;
ps_settings_init();
settings_load();

while (reset_counter < 6) {
k_sleep(SLEEP_TIME);
reset_counter++;
printk("Reset counter %u\n", reset_counter);
settings_save_one("ps/ra0", &reset_counter,
sizeof(reset_counter));
settings_save_one("ps/ra1", &reset_counter,
sizeof(reset_counter));
settings_save_one("ps/ra2", &reset_counter,
sizeof(reset_counter));
settings_save_one("ps/rb", &reset_counter,
sizeof(reset_counter));
if (reset_counter == 2) {
settings_delete("ps/rb");
}
if (reset_counter == 4) {
settings_delete("ps/r");
}
sys_reboot(0);
}
printk("Finished");
}
1 change: 1 addition & 0 deletions subsys/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ add_subdirectory_ifdef(CONFIG_USB usb)
add_subdirectory(random)
add_subdirectory(storage)
add_subdirectory_ifdef(CONFIG_SETTINGS settings)
add_subdirectory_ifdef(CONFIG_NSETTINGS nsettings)
add_subdirectory_ifdef(CONFIG_PM_CONTROL_OS power)
add_subdirectory(fb)
add_subdirectory(stats)
2 changes: 2 additions & 0 deletions subsys/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ source "subsys/storage/Kconfig"

source "subsys/settings/Kconfig"

source "subsys/nsettings/Kconfig"

source "subsys/app_memory/Kconfig"

source "subsys/power/Kconfig"
Expand Down
Loading

0 comments on commit 2e632d8

Please sign in to comment.