subsys: Add a new settings subsystem
Adapt the MyNewt non-volatile configuration system to become a settings system in Zephyr. The original code was modifed in the following ways: * Renamed from config to settings * Use the zephyr FCB, FS API, and base64 subsystems * lltoa like function was added to sources as it was required but not included in Zephyr itself. * The original code was modified to use Zephyr's slist.h as single linked list implementation. * Reworked code which was using strtok_r, added function for decoding a string to a s64_t value. * Thank to the above the settings subsys doesn't require newlibc anymore. Signed-off-by: Andrzej Puzdrowski <andrzej.puzdrowski@nordicsemi.no> Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>
This commit is contained in:
parent
e33aa5509a
commit
94ff339cbf
45 changed files with 3526 additions and 0 deletions
268
include/settings/settings.h
Normal file
268
include/settings/settings.h
Normal file
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __SETTINGS_H_
|
||||
#define __SETTINGS_H_
|
||||
|
||||
#include <misc/util.h>
|
||||
#include <misc/slist.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup settings system
|
||||
* @{
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
/**
|
||||
* Type of settings value.
|
||||
*/
|
||||
enum settings_type {
|
||||
SETTINGS_NONE = 0,
|
||||
SETTINGS_INT8,
|
||||
SETTINGS_INT16,
|
||||
SETTINGS_INT32,
|
||||
SETTINGS_INT64,
|
||||
SETTINGS_STRING,
|
||||
SETTINGS_BYTES,
|
||||
SETTINGS_FLOAT,
|
||||
SETTINGS_DOUBLE,
|
||||
SETTINGS_BOOL,
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/**
|
||||
* Parameter to commit handler describing where data is going to.
|
||||
*/
|
||||
enum settings_export_tgt {
|
||||
SETTINGS_EXPORT_PERSIST, /* Value is to be persisted. */
|
||||
SETTINGS_EXPORT_SHOW /* Value is to be displayed. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct settings_handler
|
||||
* Config handlers for subtree implement a set of handler functions.
|
||||
* These are registered using a call to settings_register().
|
||||
*
|
||||
* @param settings_handler::node Linked list node info for module internal usage.
|
||||
*
|
||||
* @param settings_handler::name Name of subtree.
|
||||
*
|
||||
* @param settings_handler::h_get 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.
|
||||
*
|
||||
* @param settings_handler::h_set Sey value handler of settings items
|
||||
* identified by keyword names. Parameters:
|
||||
* - argc - count of item in argv, argv - array of pointers to keyword names.
|
||||
* - val- pointer to value to be set.
|
||||
*
|
||||
* @param settings_handler::h_commit This handler gets called after settings
|
||||
* has been loaded in full. User might use it to apply setting to
|
||||
* the application.
|
||||
*
|
||||
* @param settings_handler::h_export This gets called to dump all current
|
||||
* settings items.
|
||||
* This happens when settings_save() tries to save the settings. Parameters:
|
||||
* - tgt: indicates where data is going to.
|
||||
* - Export_function: 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.
|
||||
*/
|
||||
struct settings_handler {
|
||||
sys_snode_t node;
|
||||
char *name;
|
||||
char *(*h_get)(int argc, char **argv, char *val, int val_len_max);
|
||||
int (*h_set)(int argc, char **argv, char *val);
|
||||
int (*h_commit)(void);
|
||||
int (*h_export)(void (*export_func)(char *name, char *val),
|
||||
enum settings_export_tgt tgt);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
void 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 var Value of the settings item.
|
||||
*
|
||||
* @return 0 on success, non-zero on failure.
|
||||
*/
|
||||
int settings_save_one(const char *name, char *var);
|
||||
|
||||
/**
|
||||
* Set settings item identified by @p name to be value @p val_str.
|
||||
* This finds the settings handler for this subtree and calls it's
|
||||
* set handler.
|
||||
*
|
||||
* @param name Name/key of the settings item.
|
||||
* @param val_str Value of the settings item.
|
||||
*
|
||||
* @return 0 on success, non-zero on failure.
|
||||
*/
|
||||
int settings_set_value(char *name, char *val_str);
|
||||
|
||||
/**
|
||||
* Get value of settings item identified by @p name.
|
||||
* This calls the settings handler h_get for the subtree.
|
||||
*
|
||||
* Configuration handler can copy the string to @p buf, the maximum
|
||||
* number of bytes it will copy is limited by @p buf_len.
|
||||
*
|
||||
* @param name Name/key of the settings item.
|
||||
*
|
||||
* @param buf buffer for value of the settings item.
|
||||
* If value is not string, the value will be filled in *buf.
|
||||
*
|
||||
* @param buf_len size of buf.
|
||||
*
|
||||
* @return value will be pointer to beginning of the buf,
|
||||
* except for string it will pointer to beginning of string source.
|
||||
*/
|
||||
char *settings_get_value(char *name, char *buf, int buf_len);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Convenience routine for converting value passed as a string to native
|
||||
* data type.
|
||||
*
|
||||
* @param val_str Value of the settings item as string.
|
||||
* @param type Type of the value to convert to.
|
||||
* @param vp Pointer to variable to fill with the decoded value.
|
||||
* @param maxlen the vp buffer size.
|
||||
*
|
||||
* @return 0 on success, non-zero on failure.
|
||||
*/
|
||||
int settings_value_from_str(char *val_str, enum settings_type type, void *vp,
|
||||
int maxlen);
|
||||
|
||||
/**
|
||||
* Convenience routine for converting byte array passed as a base64
|
||||
* encoded string.
|
||||
*
|
||||
* @param val_str Value of the settings item as string.
|
||||
* @param vp Pointer to variable to fill with the decoded value.
|
||||
* @param len Size of that variable. On return the number of bytes in the array.
|
||||
*
|
||||
* @return 0 on success, non-zero on failure.
|
||||
*/
|
||||
int settings_bytes_from_str(char *val_str, void *vp, int *len);
|
||||
|
||||
/**
|
||||
* Convenience routine for converting native data type to a string.
|
||||
*
|
||||
* @param type Type of the value to convert from.
|
||||
* @param vp Pointer to variable to convert.
|
||||
* @param buf Buffer where string value will be stored.
|
||||
* @param buf_len Size of the buffer.
|
||||
*
|
||||
* @return 0 on success, non-zero on failure.
|
||||
*/
|
||||
char *settings_str_from_value(enum settings_type type, void *vp, char *buf,
|
||||
int buf_len);
|
||||
#define SETTINGS_STR_FROM_BYTES_LEN(len) (((len) * 4 / 3) + 4)
|
||||
|
||||
/**
|
||||
* Convenience routine for converting byte array into a base64
|
||||
* encoded string.
|
||||
*
|
||||
* @param vp Pointer to variable to convert.
|
||||
* @param vp_len Number of bytes to convert.
|
||||
* @param buf Buffer where string value will be stored.
|
||||
* @param buf_len Size of the buffer.
|
||||
*
|
||||
* @return 0 on success, non-zero on failure.
|
||||
*/
|
||||
char *settings_str_from_bytes(void *vp, int vp_len, char *buf, int buf_len);
|
||||
|
||||
#define SETTINGS_VALUE_SET(str, type, val) \
|
||||
settings_value_from_str((str), (type), &(val), sizeof(val))
|
||||
|
||||
/**
|
||||
* @} 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 /* __SETTINGS_H_ */
|
|
@ -12,3 +12,4 @@ add_subdirectory_ifdef(CONFIG_NET_BUF net)
|
|||
add_subdirectory_ifdef(CONFIG_USB usb)
|
||||
add_subdirectory(random)
|
||||
add_subdirectory(storage)
|
||||
add_subdirectory_ifdef(CONFIG_SETTINGS settings)
|
||||
|
|
|
@ -32,3 +32,5 @@ source "subsys/dfu/Kconfig"
|
|||
source "subsys/random/Kconfig"
|
||||
|
||||
source "subsys/storage/Kconfig"
|
||||
|
||||
source "subsys/settings/Kconfig"
|
||||
|
|
4
subsys/settings/CMakeLists.txt
Normal file
4
subsys/settings/CMakeLists.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
add_subdirectory(src)
|
||||
zephyr_include_directories(
|
||||
include
|
||||
)
|
87
subsys/settings/Kconfig
Normal file
87
subsys/settings/Kconfig
Normal file
|
@ -0,0 +1,87 @@
|
|||
#
|
||||
# Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
menuconfig SETTINGS
|
||||
bool
|
||||
default n
|
||||
prompt "Enable settings subsystem with non-volatile storage"
|
||||
depends on FILE_SYSTEM || FCB
|
||||
select BASE64
|
||||
help
|
||||
The settings subsystem allows its users to serialize and
|
||||
deserialize state in memory into and from non-volatile memory.
|
||||
It supports several back-ends to store and load serialized data from
|
||||
and it can do so atomically for all involved modules.
|
||||
|
||||
choice
|
||||
prompt "Storage back-end"
|
||||
default SETTINGS_FCB if FCB
|
||||
depends on SETTINGS
|
||||
help
|
||||
Storage back-end to be used by the settings subsystem.
|
||||
|
||||
config SETTINGS_FCB
|
||||
bool "FCB"
|
||||
depends on FCB
|
||||
help
|
||||
Use FCB as a settings storage back-end.
|
||||
|
||||
config SETTINGS_FS
|
||||
bool "File System"
|
||||
depends on FILE_SYSTEM
|
||||
help
|
||||
Use a file system as a settings storage back-end.
|
||||
endchoice
|
||||
|
||||
config SETTINGS_FCB_NUM_AREAS
|
||||
int
|
||||
default 8
|
||||
depends on SETTINGS && SETTINGS_FCB
|
||||
prompt "Number of flash areas used by the settings subsystem "
|
||||
help
|
||||
Number of areas to allocate in the settings FCB. A smaller number is
|
||||
used if the flash hardware cannot support this value.
|
||||
|
||||
config SETTINGS_FCB_MAGIC
|
||||
hex
|
||||
prompt "FCB magic for the settings subsystem"
|
||||
default 0xc0ffeeee
|
||||
depends on SETTINGS && SETTINGS_FCB
|
||||
help
|
||||
Magic 32-bit word for to identify valid settings area
|
||||
|
||||
config SETTINGS_FCB_FLASH_AREA
|
||||
int
|
||||
prompt "Flash area id used for settings"
|
||||
default 4
|
||||
depends on SETTINGS && SETTINGS_FCB
|
||||
help
|
||||
Id of the Flash area where FCB instance used for settings is
|
||||
expected to operate.
|
||||
|
||||
config SETTINGS_FS_DIR
|
||||
string
|
||||
prompt "Serialization directory"
|
||||
default "/settings"
|
||||
depends on SETTINGS && SETTINGS_FS
|
||||
help
|
||||
Directory where the settings data is stored
|
||||
|
||||
config SETTINGS_FS_FILE
|
||||
string
|
||||
prompt "Default settings file"
|
||||
default "/settings/run"
|
||||
depends on SETTINGS && SETTINGS_FS
|
||||
help
|
||||
Full path to the default settings file.
|
||||
|
||||
config SETTINGS_FS_MAX_LINES
|
||||
int
|
||||
prompt "Compression threshold"
|
||||
default 32
|
||||
depends on SETTINGS && SETTINGS_FS
|
||||
help
|
||||
'Limit how many items stored in a file before compressing'
|
30
subsys/settings/include/settings/settings_fcb.h
Normal file
30
subsys/settings/include/settings/settings_fcb.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __SETTINGS_FCB_H_
|
||||
#define __SETTINGS_FCB_H_
|
||||
|
||||
#include <fcb.h>
|
||||
#include "settings/settings.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct settings_fcb {
|
||||
struct settings_store cf_store;
|
||||
struct fcb cf_fcb;
|
||||
};
|
||||
|
||||
extern int settings_fcb_src(struct settings_fcb *cf);
|
||||
extern int settings_fcb_dst(struct settings_fcb *cf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __SETTINGS_FCB_H_ */
|
36
subsys/settings/include/settings/settings_file.h
Normal file
36
subsys/settings/include/settings/settings_file.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __SETTINGS_FILE_H_
|
||||
#define __SETTINGS_FILE_H_
|
||||
|
||||
#include "settings/settings.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SETTINGS_FILE_NAME_MAX 32 /* max length for settings filename */
|
||||
|
||||
struct settings_file {
|
||||
struct settings_store cf_store;
|
||||
const char *cf_name; /* filename */
|
||||
int cf_maxlines; /* max # of lines before compressing */
|
||||
int cf_lines; /* private */
|
||||
};
|
||||
|
||||
/* register file to be source of settings */
|
||||
int settings_file_src(struct settings_file *cf);
|
||||
|
||||
/* settings saves go to a file */
|
||||
int settings_file_dst(struct settings_file *cf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __SETTINGS_FILE_H_ */
|
11
subsys/settings/src/CMakeLists.txt
Normal file
11
subsys/settings/src/CMakeLists.txt
Normal file
|
@ -0,0 +1,11 @@
|
|||
zephyr_include_directories($ENV{ZEPHYR_BASE}/ext/fs/nffs/include)
|
||||
|
||||
zephyr_sources(
|
||||
settings_store.c
|
||||
settings.c
|
||||
settings_init.c
|
||||
settings_line.c
|
||||
)
|
||||
|
||||
zephyr_sources_ifdef(CONFIG_SETTINGS_FS settings_file.c)
|
||||
zephyr_sources_ifdef(CONFIG_SETTINGS_FCB settings_fcb.c)
|
388
subsys/settings/src/settings.c
Normal file
388
subsys/settings/src/settings.c
Normal file
|
@ -0,0 +1,388 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "base64.h"
|
||||
|
||||
#include "settings/settings.h"
|
||||
#include "settings_priv.h"
|
||||
#include <zephyr/types.h>
|
||||
|
||||
/* mbedtls-base64 lib encodes data to null-terminated string */
|
||||
#define BASE64_ENCODE_SIZE(in_size) ((((((in_size) - 1) / 3) * 4) + 4) + 1)
|
||||
|
||||
sys_slist_t settings_handlers;
|
||||
|
||||
static u8_t settings_cmd_inited;
|
||||
|
||||
void settings_store_init(void);
|
||||
static void s64_to_dec(char *ptr, int buf_len, s64_t value, int base);
|
||||
static s64_t dec_to_s64(char *p_str, char **e_ptr);
|
||||
|
||||
void settings_init(void)
|
||||
{
|
||||
if (!settings_cmd_inited) {
|
||||
sys_slist_init(&settings_handlers);
|
||||
settings_store_init();
|
||||
|
||||
settings_cmd_inited = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int settings_register(struct settings_handler *handler)
|
||||
{
|
||||
sys_slist_prepend(&settings_handlers, &handler->node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find settings_handler based on name.
|
||||
*/
|
||||
struct settings_handler *settings_handler_lookup(char *name)
|
||||
{
|
||||
struct settings_handler *ch;
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER(&settings_handlers, ch, node) {
|
||||
if (!strcmp(name, ch->name)) {
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Separate string into argv array.
|
||||
*/
|
||||
int settings_parse_name(char *name, int *name_argc, char *name_argv[])
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (name) {
|
||||
name_argv[i++] = name;
|
||||
|
||||
while (1) {
|
||||
if (*name == '\0') {
|
||||
name = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (*name == *SETTINGS_NAME_SEPARATOR) {
|
||||
*name = '\0';
|
||||
name++;
|
||||
break;
|
||||
}
|
||||
name++;
|
||||
}
|
||||
}
|
||||
|
||||
*name_argc = i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct settings_handler *settings_parse_and_lookup(char *name,
|
||||
int *name_argc,
|
||||
char *name_argv[])
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = settings_parse_name(name, name_argc, name_argv);
|
||||
if (rc) {
|
||||
return NULL;
|
||||
}
|
||||
return settings_handler_lookup(name_argv[0]);
|
||||
}
|
||||
|
||||
int settings_value_from_str(char *val_str, enum settings_type type, void *vp,
|
||||
int maxlen)
|
||||
{
|
||||
s32_t val;
|
||||
s64_t val64;
|
||||
char *eptr;
|
||||
|
||||
if (!val_str) {
|
||||
goto err;
|
||||
}
|
||||
switch (type) {
|
||||
case SETTINGS_INT8:
|
||||
case SETTINGS_INT16:
|
||||
case SETTINGS_INT32:
|
||||
case SETTINGS_BOOL:
|
||||
val = strtol(val_str, &eptr, 0);
|
||||
if (*eptr != '\0') {
|
||||
goto err;
|
||||
}
|
||||
if (type == SETTINGS_BOOL) {
|
||||
if (val < 0 || val > 1) {
|
||||
goto err;
|
||||
}
|
||||
*(bool *)vp = val;
|
||||
} else if (type == SETTINGS_INT8) {
|
||||
if (val < INT8_MIN || val > UINT8_MAX) {
|
||||
goto err;
|
||||
}
|
||||
*(int8_t *)vp = val;
|
||||
} else if (type == SETTINGS_INT16) {
|
||||
if (val < INT16_MIN || val > UINT16_MAX) {
|
||||
goto err;
|
||||
}
|
||||
*(int16_t *)vp = val;
|
||||
} else if (type == SETTINGS_INT32) {
|
||||
*(s32_t *)vp = val;
|
||||
}
|
||||
break;
|
||||
case SETTINGS_INT64:
|
||||
val64 = dec_to_s64(val_str, &eptr);
|
||||
if (*eptr != '\0') {
|
||||
goto err;
|
||||
}
|
||||
*(s64_t *)vp = val64;
|
||||
break;
|
||||
case SETTINGS_STRING:
|
||||
val = strlen(val_str);
|
||||
if (val + 1 > maxlen) {
|
||||
goto err;
|
||||
}
|
||||
strcpy(vp, val_str);
|
||||
break;
|
||||
default:
|
||||
goto err;
|
||||
}
|
||||
return 0;
|
||||
err:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int settings_bytes_from_str(char *val_str, void *vp, int *len)
|
||||
{
|
||||
int err;
|
||||
int rc;
|
||||
|
||||
err = base64_decode(vp, *len, &rc, val_str, strlen(val_str));
|
||||
|
||||
if (err) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*len = rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *settings_str_from_value(enum settings_type type, void *vp, char *buf,
|
||||
int buf_len)
|
||||
{
|
||||
s32_t val;
|
||||
|
||||
if (type == SETTINGS_STRING) {
|
||||
return vp;
|
||||
}
|
||||
switch (type) {
|
||||
case SETTINGS_INT8:
|
||||
case SETTINGS_INT16:
|
||||
case SETTINGS_INT32:
|
||||
case SETTINGS_BOOL:
|
||||
if (type == SETTINGS_BOOL) {
|
||||
val = *(bool *)vp;
|
||||
} else if (type == SETTINGS_INT8) {
|
||||
val = *(int8_t *)vp;
|
||||
} else if (type == SETTINGS_INT16) {
|
||||
val = *(int16_t *)vp;
|
||||
} else {
|
||||
val = *(s32_t *)vp;
|
||||
}
|
||||
snprintf(buf, buf_len, "%ld", (long)val);
|
||||
return buf;
|
||||
case SETTINGS_INT64:
|
||||
s64_to_dec(buf, buf_len, *(s64_t *)vp, 10);
|
||||
return buf;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void u64_to_dec(char *ptr, int buf_len, u64_t value, int base)
|
||||
{
|
||||
u64_t t = 0, res = 0;
|
||||
u64_t tmp = value;
|
||||
int count = 0;
|
||||
|
||||
if (ptr == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tmp == 0) {
|
||||
count++;
|
||||
}
|
||||
|
||||
while (tmp > 0) {
|
||||
tmp = tmp/base;
|
||||
count++;
|
||||
}
|
||||
|
||||
ptr += count;
|
||||
|
||||
*ptr = '\0';
|
||||
|
||||
do {
|
||||
res = value - base * (t = value / base);
|
||||
if (res < 10) {
|
||||
*--ptr = '0' + res;
|
||||
} else if ((res >= 10) && (res < 16)) {
|
||||
*--ptr = 'A' - 10 + res;
|
||||
}
|
||||
value = t;
|
||||
} while (value != 0);
|
||||
}
|
||||
|
||||
static void s64_to_dec(char *ptr, int buf_len, s64_t value, int base)
|
||||
{
|
||||
u64_t val64;
|
||||
|
||||
if (ptr == NULL || buf_len < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (value < 0) {
|
||||
*ptr = '-';
|
||||
ptr++;
|
||||
buf_len--;
|
||||
val64 = value * (-1);
|
||||
} else {
|
||||
val64 = value;
|
||||
}
|
||||
|
||||
u64_to_dec(ptr, buf_len, val64, base);
|
||||
}
|
||||
|
||||
static s64_t dec_to_s64(char *p_str, char **e_ptr)
|
||||
{
|
||||
u64_t val = 0, prev_val = 0;
|
||||
bool neg = false;
|
||||
int digit;
|
||||
|
||||
if (*p_str == '-') {
|
||||
neg = true;
|
||||
p_str++;
|
||||
} else if (*p_str == '+') {
|
||||
p_str++;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (*p_str >= '0' && *p_str <= '9') {
|
||||
digit = *p_str - '0';
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
val *= 10;
|
||||
val += digit;
|
||||
|
||||
/* this is only a fuse */
|
||||
if (val < prev_val) {
|
||||
break;
|
||||
}
|
||||
|
||||
prev_val = val;
|
||||
p_str++;
|
||||
}
|
||||
|
||||
if (e_ptr != 0)
|
||||
*e_ptr = p_str;
|
||||
|
||||
if (neg) {
|
||||
return -val;
|
||||
} else {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
char *settings_str_from_bytes(void *vp, int vp_len, char *buf, int buf_len)
|
||||
{
|
||||
if (BASE64_ENCODE_SIZE(vp_len) > buf_len) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t enc_len;
|
||||
|
||||
base64_encode(buf, buf_len, &enc_len, vp, vp_len);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
int settings_set_value(char *name, char *val_str)
|
||||
{
|
||||
int name_argc;
|
||||
char *name_argv[SETTINGS_MAX_DIR_DEPTH];
|
||||
struct settings_handler *ch;
|
||||
|
||||
ch = settings_parse_and_lookup(name, &name_argc, name_argv);
|
||||
if (!ch) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ch->h_set(name_argc - 1, &name_argv[1], val_str);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get value in printable string form. If value is not string, the value
|
||||
* will be filled in *buf.
|
||||
* Return value will be pointer to beginning of that buffer,
|
||||
* except for string it will pointer to beginning of string.
|
||||
*/
|
||||
char *settings_get_value(char *name, char *buf, int buf_len)
|
||||
{
|
||||
int name_argc;
|
||||
char *name_argv[SETTINGS_MAX_DIR_DEPTH];
|
||||
struct settings_handler *ch;
|
||||
|
||||
ch = settings_parse_and_lookup(name, &name_argc, name_argv);
|
||||
if (!ch) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!ch->h_get) {
|
||||
return NULL;
|
||||
}
|
||||
return ch->h_get(name_argc - 1, &name_argv[1], buf, buf_len);
|
||||
}
|
||||
|
||||
int settings_commit(char *name)
|
||||
{
|
||||
int name_argc;
|
||||
char *name_argv[SETTINGS_MAX_DIR_DEPTH];
|
||||
struct settings_handler *ch;
|
||||
int rc;
|
||||
int rc2;
|
||||
|
||||
if (name) {
|
||||
ch = settings_parse_and_lookup(name, &name_argc, name_argv);
|
||||
if (!ch) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (ch->h_commit) {
|
||||
return ch->h_commit();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
rc = 0;
|
||||
SYS_SLIST_FOR_EACH_CONTAINER(&settings_handlers, ch, node) {
|
||||
if (ch->h_commit) {
|
||||
rc2 = ch->h_commit();
|
||||
if (!rc) {
|
||||
rc = rc2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
}
|
257
subsys/settings/src/settings_fcb.c
Normal file
257
subsys/settings/src/settings_fcb.c
Normal file
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcb.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "settings/settings.h"
|
||||
#include "settings/settings_fcb.h"
|
||||
#include "settings_priv.h"
|
||||
|
||||
#define SETTINGS_FCB_VERS 1
|
||||
|
||||
struct settings_fcb_load_cb_arg {
|
||||
load_cb cb;
|
||||
void *cb_arg;
|
||||
};
|
||||
|
||||
static int settings_fcb_load(struct settings_store *cs, load_cb cb,
|
||||
void *cb_arg);
|
||||
static int settings_fcb_save(struct settings_store *cs, const char *name,
|
||||
const char *value);
|
||||
|
||||
static struct settings_store_itf settings_fcb_itf = {
|
||||
.csi_load = settings_fcb_load,
|
||||
.csi_save = settings_fcb_save,
|
||||
};
|
||||
|
||||
int settings_fcb_src(struct settings_fcb *cf)
|
||||
{
|
||||
int rc;
|
||||
|
||||
cf->cf_fcb.f_version = SETTINGS_FCB_VERS;
|
||||
cf->cf_fcb.f_scratch_cnt = 1;
|
||||
|
||||
while (1) {
|
||||
rc = fcb_init(CONFIG_SETTINGS_FCB_FLASH_AREA, &cf->cf_fcb);
|
||||
if (rc) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if system was reset in middle of emptying a sector.
|
||||
* This situation is recognized by checking if the scratch block
|
||||
* is missing.
|
||||
*/
|
||||
if (fcb_free_sector_cnt(&cf->cf_fcb) < 1) {
|
||||
|
||||
rc = flash_area_erase(cf->cf_fcb.fap,
|
||||
cf->cf_fcb.f_active.fe_sector->fs_off,
|
||||
cf->cf_fcb.f_active.fe_sector->fs_size);
|
||||
|
||||
if (rc) {
|
||||
return -EIO;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cf->cf_store.cs_itf = &settings_fcb_itf;
|
||||
settings_src_register(&cf->cf_store);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int settings_fcb_dst(struct settings_fcb *cf)
|
||||
{
|
||||
cf->cf_store.cs_itf = &settings_fcb_itf;
|
||||
settings_dst_register(&cf->cf_store);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int settings_fcb_load_cb(struct fcb_entry_ctx *entry_ctx, void *arg)
|
||||
{
|
||||
struct settings_fcb_load_cb_arg *argp;
|
||||
char buf[SETTINGS_MAX_NAME_LEN + SETTINGS_MAX_VAL_LEN +
|
||||
SETTINGS_EXTRA_LEN];
|
||||
char *name_str;
|
||||
char *val_str;
|
||||
int rc;
|
||||
int len;
|
||||
|
||||
argp = (struct settings_fcb_load_cb_arg *)arg;
|
||||
|
||||
len = entry_ctx->loc.fe_data_len;
|
||||
if (len >= sizeof(buf)) {
|
||||
len = sizeof(buf) - 1;
|
||||
}
|
||||
|
||||
rc = flash_area_read(entry_ctx->fap,
|
||||
FCB_ENTRY_FA_DATA_OFF(entry_ctx->loc), buf, len);
|
||||
|
||||
if (rc) {
|
||||
return 0;
|
||||
}
|
||||
buf[len] = '\0';
|
||||
|
||||
rc = settings_line_parse(buf, &name_str, &val_str);
|
||||
if (rc) {
|
||||
return 0;
|
||||
}
|
||||
argp->cb(name_str, val_str, argp->cb_arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int settings_fcb_load(struct settings_store *cs, load_cb cb,
|
||||
void *cb_arg)
|
||||
{
|
||||
struct settings_fcb *cf = (struct settings_fcb *)cs;
|
||||
struct settings_fcb_load_cb_arg arg;
|
||||
int rc;
|
||||
|
||||
arg.cb = cb;
|
||||
arg.cb_arg = cb_arg;
|
||||
rc = fcb_walk(&cf->cf_fcb, 0, settings_fcb_load_cb, &arg);
|
||||
if (rc) {
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int settings_fcb_var_read(struct fcb_entry_ctx *entry_ctx, char *buf,
|
||||
char **name, char **val)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = flash_area_read(entry_ctx->fap,
|
||||
FCB_ENTRY_FA_DATA_OFF(entry_ctx->loc), buf,
|
||||
entry_ctx->loc.fe_data_len);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
buf[entry_ctx->loc.fe_data_len] = '\0';
|
||||
rc = settings_line_parse(buf, name, val);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void settings_fcb_compress(struct settings_fcb *cf)
|
||||
{
|
||||
int rc;
|
||||
char buf1[SETTINGS_MAX_NAME_LEN + SETTINGS_MAX_VAL_LEN +
|
||||
SETTINGS_EXTRA_LEN];
|
||||
char buf2[SETTINGS_MAX_NAME_LEN + SETTINGS_MAX_VAL_LEN +
|
||||
SETTINGS_EXTRA_LEN];
|
||||
struct fcb_entry_ctx loc1;
|
||||
struct fcb_entry_ctx loc2;
|
||||
char *name1, *val1;
|
||||
char *name2, *val2;
|
||||
int copy;
|
||||
|
||||
rc = fcb_append_to_scratch(&cf->cf_fcb);
|
||||
if (rc) {
|
||||
return; /* XXX */
|
||||
}
|
||||
|
||||
loc1.fap = cf->cf_fcb.fap;
|
||||
|
||||
loc1.loc.fe_sector = NULL;
|
||||
loc1.loc.fe_elem_off = 0;
|
||||
while (fcb_getnext(&cf->cf_fcb, &loc1.loc) == 0) {
|
||||
if (loc1.loc.fe_sector != cf->cf_fcb.f_oldest) {
|
||||
break;
|
||||
}
|
||||
rc = settings_fcb_var_read(&loc1, buf1, &name1, &val1);
|
||||
if (rc) {
|
||||
continue;
|
||||
}
|
||||
loc2 = loc1;
|
||||
copy = 1;
|
||||
while (fcb_getnext(&cf->cf_fcb, &loc2.loc) == 0) {
|
||||
rc = settings_fcb_var_read(&loc2, buf2, &name2, &val2);
|
||||
if (rc) {
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(name1, name2)) {
|
||||
copy = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!copy) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Can't find one. Must copy.
|
||||
*/
|
||||
rc = flash_area_read(loc1.fap, FCB_ENTRY_FA_DATA_OFF(loc1.loc),
|
||||
buf1, loc1.loc.fe_data_len);
|
||||
if (rc) {
|
||||
continue;
|
||||
}
|
||||
rc = fcb_append(&cf->cf_fcb, loc1.loc.fe_data_len, &loc2.loc);
|
||||
if (rc) {
|
||||
continue;
|
||||
}
|
||||
rc = flash_area_write(loc2.fap, FCB_ENTRY_FA_DATA_OFF(loc2.loc),
|
||||
buf1, loc1.loc.fe_data_len);
|
||||
if (rc) {
|
||||
continue;
|
||||
}
|
||||
fcb_append_finish(&cf->cf_fcb, &loc2.loc);
|
||||
}
|
||||
rc = fcb_rotate(&cf->cf_fcb);
|
||||
|
||||
__ASSERT(rc == 0, "Failed to fcb rotate.\n");
|
||||
}
|
||||
|
||||
static int settings_fcb_append(struct settings_fcb *cf, char *buf, int len)
|
||||
{
|
||||
int rc;
|
||||
int i;
|
||||
struct fcb_entry loc;
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
rc = fcb_append(&cf->cf_fcb, len, &loc);
|
||||
if (rc != FCB_ERR_NOSPACE) {
|
||||
break;
|
||||
}
|
||||
settings_fcb_compress(cf);
|
||||
}
|
||||
if (rc) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = flash_area_write(cf->cf_fcb.fap, FCB_ENTRY_FA_DATA_OFF(loc),
|
||||
buf, len);
|
||||
if (rc) {
|
||||
return -EINVAL;
|
||||
}
|
||||
fcb_append_finish(&cf->cf_fcb, &loc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int settings_fcb_save(struct settings_store *cs, const char *name,
|
||||
const char *value)
|
||||
{
|
||||
struct settings_fcb *cf = (struct settings_fcb *)cs;
|
||||
char buf[SETTINGS_MAX_NAME_LEN + SETTINGS_MAX_VAL_LEN +
|
||||
SETTINGS_EXTRA_LEN];
|
||||
int len;
|
||||
|
||||
if (!name) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
len = settings_line_make(buf, sizeof(buf), name, value);
|
||||
if (len < 0 || len + 2 > sizeof(buf)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
return settings_fcb_append(cf, buf, len);
|
||||
}
|
302
subsys/settings/src/settings_file.c
Normal file
302
subsys/settings/src/settings_file.c
Normal file
|
@ -0,0 +1,302 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <zephyr.h>
|
||||
|
||||
#include <fs.h>
|
||||
|
||||
#include "settings/settings.h"
|
||||
#include "settings/settings_file.h"
|
||||
#include "settings_priv.h"
|
||||
|
||||
static int settings_file_load(struct settings_store *cs, load_cb cb,
|
||||
void *cb_arg);
|
||||
static int settings_file_save(struct settings_store *cs, const char *name,
|
||||
const char *value);
|
||||
|
||||
static struct settings_store_itf settings_file_itf = {
|
||||
.csi_load = settings_file_load,
|
||||
.csi_save = settings_file_save,
|
||||
};
|
||||
|
||||
/*
|
||||
* Register a file to be a source of configuration.
|
||||
*/
|
||||
int settings_file_src(struct settings_file *cf)
|
||||
{
|
||||
if (!cf->cf_name) {
|
||||
return -EINVAL;
|
||||
}
|
||||
cf->cf_store.cs_itf = &settings_file_itf;
|
||||
settings_src_register(&cf->cf_store);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int settings_file_dst(struct settings_file *cf)
|
||||
{
|
||||
if (!cf->cf_name) {
|
||||
return -EINVAL;
|
||||
}
|
||||
cf->cf_store.cs_itf = &settings_file_itf;
|
||||
settings_dst_register(&cf->cf_store);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int settings_getnext_line(struct fs_file_t *file, char *buf, int blen,
|
||||
off_t *loc)
|
||||
{
|
||||
int rc;
|
||||
char *end;
|
||||
|
||||
rc = fs_seek(file, *loc, FS_SEEK_SET);
|
||||
if (rc < 0) {
|
||||
*loc = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = fs_read(file, buf, blen);
|
||||
if (rc <= 0) {
|
||||
*loc = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rc == blen) {
|
||||
rc--;
|
||||
}
|
||||
buf[rc] = '\0';
|
||||
|
||||
end = strchr(buf, '\n');
|
||||
if (end) {
|
||||
*end = '\0';
|
||||
} else {
|
||||
end = strchr(buf, '\0');
|
||||
}
|
||||
blen = end - buf;
|
||||
*loc += (blen + 1);
|
||||
return blen;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called to load configuration items. cb must be called for every configuration
|
||||
* item found.
|
||||
*/
|
||||
static int settings_file_load(struct settings_store *cs, load_cb cb,
|
||||
void *cb_arg)
|
||||
{
|
||||
struct settings_file *cf = (struct settings_file *)cs;
|
||||
struct fs_file_t file;
|
||||
off_t loc;
|
||||
char tmpbuf[SETTINGS_MAX_NAME_LEN + SETTINGS_MAX_VAL_LEN +
|
||||
SETTINGS_EXTRA_LEN];
|
||||
char *name_str;
|
||||
char *val_str;
|
||||
int rc;
|
||||
int lines;
|
||||
|
||||
rc = fs_open(&file, cf->cf_name);
|
||||
if (rc != 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
loc = 0;
|
||||
lines = 0;
|
||||
while (1) {
|
||||
rc = settings_getnext_line(&file, tmpbuf, sizeof(tmpbuf), &loc);
|
||||
if (loc == 0) {
|
||||
break;
|
||||
}
|
||||
if (rc < 0) {
|
||||
continue;
|
||||
}
|
||||
rc = settings_line_parse(tmpbuf, &name_str, &val_str);
|
||||
if (rc != 0) {
|
||||
continue;
|
||||
}
|
||||
lines++;
|
||||
cb(name_str, val_str, cb_arg);
|
||||
}
|
||||
rc = fs_close(&file);
|
||||
cf->cf_lines = lines;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void settings_tmpfile(char *dst, const char *src, char *pfx)
|
||||
{
|
||||
int len;
|
||||
int pfx_len;
|
||||
|
||||
len = strlen(src);
|
||||
pfx_len = strlen(pfx);
|
||||
if (len + pfx_len >= SETTINGS_FILE_NAME_MAX) {
|
||||
len = SETTINGS_FILE_NAME_MAX - pfx_len - 1;
|
||||
}
|
||||
memcpy(dst, src, len);
|
||||
memcpy(dst + len, pfx, pfx_len);
|
||||
dst[len + pfx_len] = '\0';
|
||||
}
|
||||
|
||||
static int settings_file_create_or_replace(struct fs_file_t *zfp,
|
||||
const char *file_name)
|
||||
{
|
||||
struct fs_dirent entry;
|
||||
|
||||
if (fs_stat(file_name, &entry) == 0) {
|
||||
if (entry.type == FS_DIR_ENTRY_FILE) {
|
||||
if (fs_unlink(file_name)) {
|
||||
return -EIO;
|
||||
}
|
||||
} else {
|
||||
return -EISDIR;
|
||||
}
|
||||
}
|
||||
|
||||
return fs_open(zfp, file_name);
|
||||
}
|
||||
/*
|
||||
* Try to compress configuration file by keeping unique names only.
|
||||
*/
|
||||
void settings_file_compress(struct settings_file *cf)
|
||||
{
|
||||
int rc;
|
||||
struct fs_file_t rf;
|
||||
struct fs_file_t wf;
|
||||
char tmp_file[SETTINGS_FILE_NAME_MAX];
|
||||
char buf1[SETTINGS_MAX_NAME_LEN + SETTINGS_MAX_VAL_LEN +
|
||||
SETTINGS_EXTRA_LEN];
|
||||
char buf2[SETTINGS_MAX_NAME_LEN + SETTINGS_MAX_VAL_LEN +
|
||||
SETTINGS_EXTRA_LEN];
|
||||
off_t loc1, loc2;
|
||||
char *name1, *val1;
|
||||
char *name2, *val2;
|
||||
int copy;
|
||||
int len, len2;
|
||||
int lines;
|
||||
|
||||
if (fs_open(&rf, cf->cf_name) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
settings_tmpfile(tmp_file, cf->cf_name, ".cmp");
|
||||
|
||||
if (settings_file_create_or_replace(&wf, tmp_file)) {
|
||||
fs_close(&rf);
|
||||
return;
|
||||
}
|
||||
|
||||
loc1 = 0;
|
||||
lines = 0;
|
||||
while (1) {
|
||||
len = settings_getnext_line(&rf, buf1, sizeof(buf1), &loc1);
|
||||
if (loc1 == 0 || len < 0) {
|
||||
break;
|
||||
}
|
||||
rc = settings_line_parse(buf1, &name1, &val1);
|
||||
if (rc) {
|
||||
continue;
|
||||
}
|
||||
loc2 = loc1;
|
||||
copy = 1;
|
||||
while ((len2 = settings_getnext_line(&rf, buf2, sizeof(buf2),
|
||||
&loc2)) > 0) {
|
||||
rc = settings_line_parse(buf2, &name2, &val2);
|
||||
if (rc) {
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(name1, name2)) {
|
||||
copy = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!copy) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Can't find one. Must copy.
|
||||
*/
|
||||
len = settings_line_make(buf2, sizeof(buf2), name1, val1);
|
||||
if (len < 0 || len + 2 > sizeof(buf2)) {
|
||||
continue;
|
||||
}
|
||||
buf2[len++] = '\n';
|
||||
if (fs_write(&wf, buf2, len) != len) {
|
||||
ARG_UNUSED(fs_close(&rf));
|
||||
ARG_UNUSED(fs_close(&wf));
|
||||
return;
|
||||
}
|
||||
lines++;
|
||||
}
|
||||
|
||||
len = fs_close(&wf);
|
||||
len2 = fs_close(&rf);
|
||||
if (len == 0 && len2 == 0 && fs_unlink(cf->cf_name) == 0) {
|
||||
ARG_UNUSED(fs_rename(tmp_file, cf->cf_name));
|
||||
cf->cf_lines = lines;
|
||||
/*
|
||||
* XXX at settings_file_load(), look for .cmp if actual file does not
|
||||
* exist.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Called to save configuration.
|
||||
*/
|
||||
static int settings_file_save(struct settings_store *cs, const char *name,
|
||||
const char *value)
|
||||
{
|
||||
struct settings_file *cf = (struct settings_file *)cs;
|
||||
struct fs_file_t file;
|
||||
char buf[SETTINGS_MAX_NAME_LEN + SETTINGS_MAX_VAL_LEN +
|
||||
SETTINGS_EXTRA_LEN];
|
||||
int len;
|
||||
int rc2;
|
||||
int rc;
|
||||
|
||||
if (!name) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (cf->cf_maxlines && (cf->cf_lines + 1 >= cf->cf_maxlines)) {
|
||||
/*
|
||||
* Compress before config file size exceeds
|
||||
* the max number of lines.
|
||||
*/
|
||||
settings_file_compress(cf);
|
||||
}
|
||||
len = settings_line_make(buf, sizeof(buf), name, value);
|
||||
if (len < 0 || len + 2 > sizeof(buf)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
buf[len++] = '\n';
|
||||
|
||||
/*
|
||||
* Open the file to add this one value.
|
||||
*/
|
||||
rc = fs_open(&file, cf->cf_name);
|
||||
if (rc == 0) {
|
||||
rc = fs_seek(&file, 0, FS_SEEK_END);
|
||||
if (rc == 0) {
|
||||
rc2 = fs_write(&file, buf, len);
|
||||
if (rc2 == len) {
|
||||
cf->cf_lines++;
|
||||
}
|
||||
}
|
||||
|
||||
rc2 = fs_close(&file);
|
||||
if (rc == 0) {
|
||||
rc = rc2;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
112
subsys/settings/src/settings_init.c
Normal file
112
subsys/settings/src/settings_init.c
Normal file
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "settings/settings.h"
|
||||
#include "settings/settings_file.h"
|
||||
#include <zephyr.h>
|
||||
|
||||
void settings_init(void);
|
||||
|
||||
#ifdef CONFIG_SETTINGS_FS
|
||||
#include <fs.h>
|
||||
|
||||
static struct settings_file config_init_settings_file = {
|
||||
.cf_name = CONFIG_SETTINGS_FS_FILE,
|
||||
.cf_maxlines = CONFIG_SETTINGS_FS_MAX_LINES
|
||||
};
|
||||
|
||||
static void settings_init_fs(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = settings_file_src(&config_init_settings_file);
|
||||
if (rc) {
|
||||
k_panic();
|
||||
}
|
||||
|
||||
rc = settings_file_dst(&config_init_settings_file);
|
||||
if (rc) {
|
||||
k_panic();
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_SETTINGS_FCB)
|
||||
#include "fcb.h"
|
||||
#include "settings/settings_fcb.h"
|
||||
|
||||
static struct flash_sector settings_fcb_area[CONFIG_SETTINGS_FCB_NUM_AREAS + 1];
|
||||
|
||||
static struct settings_fcb config_init_settings_fcb = {
|
||||
.cf_fcb.f_magic = CONFIG_SETTINGS_FCB_MAGIC,
|
||||
.cf_fcb.f_sectors = settings_fcb_area,
|
||||
};
|
||||
|
||||
static void settings_init_fcb(void)
|
||||
{
|
||||
u32_t cnt = CONFIG_SETTINGS_FCB_NUM_AREAS + 1;
|
||||
int rc;
|
||||
const struct flash_area *fap;
|
||||
|
||||
rc = flash_area_get_sectors(CONFIG_SETTINGS_FCB_FLASH_AREA, &cnt,
|
||||
settings_fcb_area);
|
||||
if (rc != 0 && rc != -ENOMEM) {
|
||||
k_panic();
|
||||
}
|
||||
|
||||
config_init_settings_fcb.cf_fcb.f_sector_cnt = cnt;
|
||||
|
||||
rc = settings_fcb_src(&config_init_settings_fcb);
|
||||
|
||||
if (rc != 0) {
|
||||
k_panic();
|
||||
}
|
||||
|
||||
rc = flash_area_open(CONFIG_SETTINGS_FCB_FLASH_AREA, &fap);
|
||||
|
||||
if (rc == 0) {
|
||||
rc = flash_area_erase(fap, 0, fap->fa_size);
|
||||
flash_area_close(fap);
|
||||
}
|
||||
|
||||
if (rc != 0) {
|
||||
k_panic();
|
||||
} else {
|
||||
rc = settings_fcb_src(&config_init_settings_fcb);
|
||||
}
|
||||
|
||||
rc = settings_fcb_dst(&config_init_settings_fcb);
|
||||
|
||||
if (rc != 0) {
|
||||
k_panic();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void settings_subsys_init(void)
|
||||
{
|
||||
settings_init();
|
||||
|
||||
#ifdef CONFIG_SETTINGS_FS
|
||||
settings_init_fs();
|
||||
|
||||
/*
|
||||
* Must be called after root FS has been initialized.
|
||||
*/
|
||||
fs_mkdir(CONFIG_SETTINGS_FS_DIR);
|
||||
#elif defined(CONFIG_SETTINGS_FCB)
|
||||
settings_init_fcb();
|
||||
#endif
|
||||
}
|
89
subsys/settings/src/settings_line.c
Normal file
89
subsys/settings/src/settings_line.c
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "settings/settings.h"
|
||||
#include "settings_priv.h"
|
||||
|
||||
int settings_line_parse(char *buf, char **namep, char **valp)
|
||||
{
|
||||
char *cp;
|
||||
enum {
|
||||
FIND_NAME,
|
||||
FIND_NAME_END,
|
||||
FIND_VAL,
|
||||
FIND_VAL_END
|
||||
} state = FIND_NAME;
|
||||
|
||||
*valp = NULL;
|
||||
for (cp = buf; *cp != '\0'; cp++) {
|
||||
switch (state) {
|
||||
case FIND_NAME:
|
||||
if (!isspace((unsigned char)*cp)) {
|
||||
*namep = cp;
|
||||
state = FIND_NAME_END;
|
||||
}
|
||||
break;
|
||||
case FIND_NAME_END:
|
||||
if (*cp == '=') {
|
||||
*cp = '\0';
|
||||
state = FIND_VAL;
|
||||
} else if (isspace((unsigned char)*cp)) {
|
||||
*cp = '\0';
|
||||
}
|
||||
break;
|
||||
case FIND_VAL:
|
||||
if (!isspace((unsigned char)*cp)) {
|
||||
*valp = cp;
|
||||
state = FIND_VAL_END;
|
||||
}
|
||||
break;
|
||||
case FIND_VAL_END:
|
||||
if (isspace((unsigned char)*cp)) {
|
||||
*cp = '\0';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (state == FIND_VAL_END || state == FIND_VAL) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int settings_line_make(char *dst, int dlen, const char *name, const char *value)
|
||||
{
|
||||
int nlen;
|
||||
int vlen;
|
||||
int off;
|
||||
|
||||
nlen = strlen(name);
|
||||
|
||||
if (value) {
|
||||
vlen = strlen(value);
|
||||
} else {
|
||||
vlen = 0;
|
||||
}
|
||||
|
||||
if (nlen + vlen + 2 > dlen) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(dst, name, nlen);
|
||||
off = nlen;
|
||||
dst[off++] = '=';
|
||||
|
||||
memcpy(dst + off, value, vlen);
|
||||
off += vlen;
|
||||
dst[off] = '\0';
|
||||
|
||||
return off;
|
||||
}
|
50
subsys/settings/src/settings_priv.h
Normal file
50
subsys/settings/src/settings_priv.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __SETTINGS_PRIV_H_
|
||||
#define __SETTINGS_PRIV_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int settings_cli_register(void);
|
||||
int settings_nmgr_register(void);
|
||||
|
||||
struct mgmt_cbuf;
|
||||
int settings_cbor_line(struct mgmt_cbuf *cb, char *name, int nlen, char *value,
|
||||
int vlen);
|
||||
|
||||
int settings_line_parse(char *buf, char **namep, char **valp);
|
||||
int settings_line_make(char *dst, int dlen, const char *name, const char *val);
|
||||
int settings_line_make2(char *dst, int dlen, const char *name,
|
||||
const char *value);
|
||||
|
||||
/*
|
||||
* API for config storage.
|
||||
*/
|
||||
typedef void (*load_cb)(char *name, char *val, void *cb_arg);
|
||||
struct settings_store_itf {
|
||||
int (*csi_load)(struct settings_store *cs, load_cb cb, void *cb_arg);
|
||||
int (*csi_save_start)(struct settings_store *cs);
|
||||
int (*csi_save)(struct settings_store *cs, const char *name,
|
||||
const char *value);
|
||||
int (*csi_save_end)(struct settings_store *cs);
|
||||
};
|
||||
|
||||
void settings_src_register(struct settings_store *cs);
|
||||
void settings_dst_register(struct settings_store *cs);
|
||||
|
||||
extern sys_slist_t settings_load_srcs;
|
||||
extern sys_slist_t settings_handlers;
|
||||
extern struct settings_store *settings_save_dst;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __SETTINGS_PRIV_H_ */
|
161
subsys/settings/src/settings_store.c
Normal file
161
subsys/settings/src/settings_store.c
Normal file
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <zephyr/types.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "settings/settings.h"
|
||||
#include "settings_priv.h"
|
||||
|
||||
struct settings_dup_check_arg {
|
||||
const char *name;
|
||||
const char *val;
|
||||
int is_dup;
|
||||
};
|
||||
|
||||
sys_slist_t settings_load_srcs;
|
||||
struct settings_store *settings_save_dst;
|
||||
|
||||
void settings_src_register(struct settings_store *cs)
|
||||
{
|
||||
sys_snode_t *prev, *cur;
|
||||
|
||||
prev = NULL;
|
||||
|
||||
SYS_SLIST_FOR_EACH_NODE(&settings_load_srcs, cur) {
|
||||
prev = cur;
|
||||
}
|
||||
|
||||
sys_slist_insert(&settings_load_srcs, prev, &cs->cs_next);
|
||||
}
|
||||
|
||||
void settings_dst_register(struct settings_store *cs)
|
||||
{
|
||||
settings_save_dst = cs;
|
||||
}
|
||||
|
||||
static void settings_load_cb(char *name, char *val, void *cb_arg)
|
||||
{
|
||||
settings_set_value(name, val);
|
||||
}
|
||||
|
||||
int settings_load(void)
|
||||
{
|
||||
struct settings_store *cs;
|
||||
|
||||
/*
|
||||
* for every config store
|
||||
* load config
|
||||
* apply config
|
||||
* commit all
|
||||
*/
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER(&settings_load_srcs, cs, cs_next) {
|
||||
cs->cs_itf->csi_load(cs, settings_load_cb, NULL);
|
||||
}
|
||||
return settings_commit(NULL);
|
||||
}
|
||||
|
||||
static void settings_dup_check_cb(char *name, char *val, void *cb_arg)
|
||||
{
|
||||
struct settings_dup_check_arg *cdca = (struct settings_dup_check_arg *)
|
||||
cb_arg;
|
||||
|
||||
if (strcmp(name, cdca->name)) {
|
||||
return;
|
||||
}
|
||||
if (!val) {
|
||||
if (!cdca->val || cdca->val[0] == '\0') {
|
||||
cdca->is_dup = 1;
|
||||
} else {
|
||||
cdca->is_dup = 0;
|
||||
}
|
||||
} else {
|
||||
if (cdca->val && !strcmp(val, cdca->val)) {
|
||||
cdca->is_dup = 1;
|
||||
} else {
|
||||
cdca->is_dup = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Append a single value to persisted config. Don't store duplicate value.
|
||||
*/
|
||||
int settings_save_one(const char *name, char *value)
|
||||
{
|
||||
struct settings_store *cs;
|
||||
struct settings_dup_check_arg cdca;
|
||||
|
||||
cs = settings_save_dst;
|
||||
if (!cs) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if we're writing the same value again.
|
||||
*/
|
||||
cdca.name = name;
|
||||
cdca.val = value;
|
||||
cdca.is_dup = 0;
|
||||
cs->cs_itf->csi_load(cs, settings_dup_check_cb, &cdca);
|
||||
if (cdca.is_dup == 1) {
|
||||
return 0;
|
||||
}
|
||||
return cs->cs_itf->csi_save(cs, name, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Walk through all registered subsystems, and ask them to export their
|
||||
* config variables. Persist these settings.
|
||||
*/
|
||||
static void settings_store_one(char *name, char *value)
|
||||
{
|
||||
settings_save_one(name, value);
|
||||
}
|
||||
|
||||
int settings_save(void)
|
||||
{
|
||||
struct settings_store *cs;
|
||||
struct settings_handler *ch;
|
||||
int rc;
|
||||
int rc2;
|
||||
|
||||
cs = settings_save_dst;
|
||||
if (!cs) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (cs->cs_itf->csi_save_start) {
|
||||
cs->cs_itf->csi_save_start(cs);
|
||||
}
|
||||
rc = 0;
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER(&settings_handlers, ch, node) {
|
||||
if (ch->h_export) {
|
||||
rc2 = ch->h_export(settings_store_one,
|
||||
SETTINGS_EXPORT_PERSIST);
|
||||
if (!rc) {
|
||||
rc = rc2;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cs->cs_itf->csi_save_end) {
|
||||
cs->cs_itf->csi_save_end(cs);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
void settings_store_init(void)
|
||||
{
|
||||
sys_slist_init(&settings_load_srcs);
|
||||
}
|
16
tests/subsys/settings/fcb/CMakeLists.txt
Normal file
16
tests/subsys/settings/fcb/CMakeLists.txt
Normal file
|
@ -0,0 +1,16 @@
|
|||
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
|
||||
project(NONE)
|
||||
|
||||
FILE(GLOB app_sources src/*.c ../src/*c)
|
||||
target_sources(app PRIVATE ${app_sources})
|
||||
zephyr_include_directories(
|
||||
$ENV{ZEPHYR_BASE}/subsys/settings/include
|
||||
$ENV{ZEPHYR_BASE}/subsys/settings/src
|
||||
$ENV{ZEPHYR_BASE}/tests/subsys/settings/fcb/src
|
||||
)
|
||||
|
||||
if(TEST)
|
||||
target_compile_definitions(app PRIVATE
|
||||
-DTEST_${TEST}
|
||||
)
|
||||
endif()
|
14
tests/subsys/settings/fcb/prj.conf
Normal file
14
tests/subsys/settings/fcb/prj.conf
Normal file
|
@ -0,0 +1,14 @@
|
|||
CONFIG_ZTEST=y
|
||||
CONFIG_STDOUT_CONSOLE=y
|
||||
CONFIG_FLASH=y
|
||||
CONFIG_SOC_FLASH_NRF5=y
|
||||
CONFIG_FLASH_PAGE_LAYOUT=y
|
||||
CONFIG_FLASH_MAP=y
|
||||
CONFIG_ARM_CORE_MPU=n
|
||||
CONFIG_ARM_MPU=n
|
||||
CONFIG_ARM_MPU_NRF52X=n
|
||||
CONFIG_FCB=y
|
||||
|
||||
CONFIG_SETTINGS=y
|
||||
CONFIG_SETTINGS_FCB=y
|
||||
CONFIG_SETTINGS_FCB_FLASH_AREA=3
|
56
tests/subsys/settings/fcb/src/settings_test.h
Normal file
56
tests/subsys/settings/fcb/src/settings_test.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _SETTINGS_TEST_FCB_H
|
||||
#define _SETTINGS_TEST_FCB_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ztest.h>
|
||||
|
||||
#include "settings/settings.h"
|
||||
#include "flash_map.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#extern "C" {
|
||||
#endif
|
||||
|
||||
#define SETTINGS_TEST_FCB_VAL_STR_CNT 64
|
||||
#define SETTINGS_TEST_FCB_FLASH_CNT 4
|
||||
|
||||
extern u8_t val8;
|
||||
extern u32_t val32;
|
||||
extern u64_t val64;
|
||||
|
||||
extern int test_get_called;
|
||||
extern int test_set_called;
|
||||
extern int test_commit_called;
|
||||
extern int test_export_block;
|
||||
|
||||
extern int c2_var_count;
|
||||
|
||||
extern struct flash_sector fcb_sectors[SETTINGS_TEST_FCB_FLASH_CNT];
|
||||
|
||||
extern char val_string[SETTINGS_TEST_FCB_VAL_STR_CNT][SETTINGS_MAX_VAL_LEN];
|
||||
extern char test_ref_value[SETTINGS_TEST_FCB_VAL_STR_CNT][SETTINGS_MAX_VAL_LEN];
|
||||
|
||||
extern struct settings_handler c_test_handlers[];
|
||||
|
||||
void ctest_clear_call_state(void);
|
||||
int ctest_get_call_state(void);
|
||||
|
||||
void config_wipe_srcs(void);
|
||||
void config_wipe_fcb(struct flash_sector *fs, int cnt);
|
||||
|
||||
void test_config_fill_area(
|
||||
char test_value[SETTINGS_TEST_FCB_VAL_STR_CNT][SETTINGS_MAX_VAL_LEN],
|
||||
int iteration);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* _SETTINGS_TEST_FCB_H */
|
88
tests/subsys/settings/fcb/src/settings_test_compress_reset.c
Normal file
88
tests/subsys/settings/fcb/src/settings_test_compress_reset.c
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "settings_test.h"
|
||||
#include "settings/settings_fcb.h"
|
||||
|
||||
void test_config_compress_reset(void)
|
||||
{
|
||||
int rc;
|
||||
struct settings_fcb cf;
|
||||
struct flash_sector *fa;
|
||||
int elems[4];
|
||||
int i;
|
||||
|
||||
config_wipe_srcs();
|
||||
config_wipe_fcb(fcb_sectors, ARRAY_SIZE(fcb_sectors));
|
||||
|
||||
cf.cf_fcb.f_magic = CONFIG_SETTINGS_FCB_MAGIC;
|
||||
cf.cf_fcb.f_sectors = fcb_sectors;
|
||||
cf.cf_fcb.f_sector_cnt = ARRAY_SIZE(fcb_sectors);
|
||||
|
||||
rc = settings_fcb_src(&cf);
|
||||
zassert_true(rc == 0, "can't register FCB as configuration source\n");
|
||||
|
||||
rc = settings_fcb_dst(&cf);
|
||||
zassert_true(rc == 0,
|
||||
"can't register FCB as configuration destination\n");
|
||||
|
||||
c2_var_count = 1;
|
||||
memset(elems, 0, sizeof(elems));
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
test_config_fill_area(test_ref_value, i);
|
||||
memcpy(val_string, test_ref_value, sizeof(val_string));
|
||||
|
||||
rc = settings_save();
|
||||
zassert_true(rc == 0, "fcb write error\n");
|
||||
|
||||
if (cf.cf_fcb.f_active.fe_sector == &fcb_sectors[2]) {
|
||||
/*
|
||||
* Started using space just before scratch.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
memset(val_string, 0, sizeof(val_string));
|
||||
|
||||
rc = settings_load();
|
||||
zassert_true(rc == 0, "fcb read error\n");
|
||||
zassert_true(!memcmp(val_string, test_ref_value,
|
||||
SETTINGS_MAX_VAL_LEN),
|
||||
"bad value read\n");
|
||||
}
|
||||
|
||||
fa = cf.cf_fcb.f_active.fe_sector;
|
||||
rc = fcb_append_to_scratch(&cf.cf_fcb);
|
||||
zassert_true(rc == 0, "fcb_append_to_scratch call failure\n");
|
||||
zassert_true(fcb_free_sector_cnt(&cf.cf_fcb) == 0,
|
||||
"expected non of free sectors\n");
|
||||
zassert_true(fa != cf.cf_fcb.f_active.fe_sector,
|
||||
"active page should change\n");
|
||||
|
||||
config_wipe_srcs();
|
||||
|
||||
memset(&cf, 0, sizeof(cf));
|
||||
|
||||
cf.cf_fcb.f_magic = CONFIG_SETTINGS_FCB_MAGIC;
|
||||
cf.cf_fcb.f_sectors = fcb_sectors;
|
||||
cf.cf_fcb.f_sector_cnt = ARRAY_SIZE(fcb_sectors);
|
||||
|
||||
rc = settings_fcb_src(&cf);
|
||||
zassert_true(rc == 0, "can't register FCB as configuration source\n");
|
||||
|
||||
rc = settings_fcb_dst(&cf);
|
||||
zassert_true(rc == 0,
|
||||
"can't register FCB as configuration destination\n");
|
||||
|
||||
|
||||
zassert_true(fcb_free_sector_cnt(&cf.cf_fcb) == 1,
|
||||
"expected one free sector\n");
|
||||
zassert_true(fa == cf.cf_fcb.f_active.fe_sector,
|
||||
"active sector should become free after garbage collection");
|
||||
|
||||
c2_var_count = 0;
|
||||
}
|
33
tests/subsys/settings/fcb/src/settings_test_empty_fcb.c
Normal file
33
tests/subsys/settings/fcb/src/settings_test_empty_fcb.c
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "settings_test.h"
|
||||
#include "settings/settings_fcb.h"
|
||||
|
||||
void test_config_empty_fcb(void)
|
||||
{
|
||||
int rc;
|
||||
struct settings_fcb cf;
|
||||
|
||||
config_wipe_srcs();
|
||||
config_wipe_fcb(fcb_sectors, ARRAY_SIZE(fcb_sectors));
|
||||
|
||||
cf.cf_fcb.f_magic = CONFIG_SETTINGS_FCB_MAGIC;
|
||||
cf.cf_fcb.f_sectors = fcb_sectors;
|
||||
cf.cf_fcb.f_sector_cnt = ARRAY_SIZE(fcb_sectors);
|
||||
|
||||
rc = settings_fcb_src(&cf);
|
||||
zassert_true(rc == 0, "settings_fcb_src call should succeed\n");
|
||||
|
||||
/*
|
||||
* No values
|
||||
*/
|
||||
settings_load();
|
||||
|
||||
config_wipe_srcs();
|
||||
ctest_clear_call_state();
|
||||
}
|
351
tests/subsys/settings/fcb/src/settings_test_fcb.c
Normal file
351
tests/subsys/settings/fcb/src/settings_test_fcb.c
Normal file
|
@ -0,0 +1,351 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "settings_test.h"
|
||||
#include "settings_priv.h"
|
||||
#include "flash_map.h"
|
||||
|
||||
u8_t val8;
|
||||
u32_t val32;
|
||||
u64_t val64;
|
||||
|
||||
int test_get_called;
|
||||
int test_set_called;
|
||||
int test_commit_called;
|
||||
int test_export_block;
|
||||
|
||||
int c2_var_count = 1;
|
||||
|
||||
char *c1_handle_get(int argc, char **argv, char *val, int val_len_max);
|
||||
int c1_handle_set(int argc, char **argv, char *val);
|
||||
int c1_handle_commit(void);
|
||||
int c1_handle_export(void (*cb)(char *name, char *value),
|
||||
enum settings_export_tgt tgt);
|
||||
|
||||
char *c2_handle_get(int argc, char **argv, char *val, int val_len_max);
|
||||
int c2_handle_set(int argc, char **argv, char *val);
|
||||
int c2_handle_export(void (*cb)(char *name, char *value),
|
||||
enum settings_export_tgt tgt);
|
||||
|
||||
char *c3_handle_get(int argc, char **argv, char *val, int val_len_max);
|
||||
int c3_handle_set(int argc, char **argv, char *val);
|
||||
int c3_handle_export(void (*cb)(char *name, char *value),
|
||||
enum settings_export_tgt tgt);
|
||||
|
||||
struct settings_handler c_test_handlers[] = {
|
||||
{
|
||||
.name = "myfoo",
|
||||
.h_get = c1_handle_get,
|
||||
.h_set = c1_handle_set,
|
||||
.h_commit = c1_handle_commit,
|
||||
.h_export = c1_handle_export
|
||||
},
|
||||
{
|
||||
.name = "2nd",
|
||||
.h_get = c2_handle_get,
|
||||
.h_set = c2_handle_set,
|
||||
.h_commit = NULL,
|
||||
.h_export = c2_handle_export
|
||||
},
|
||||
{
|
||||
.name = "3",
|
||||
.h_get = c3_handle_get,
|
||||
.h_set = c3_handle_set,
|
||||
.h_commit = NULL,
|
||||
.h_export = c3_handle_export
|
||||
}
|
||||
};
|
||||
|
||||
char val_string[SETTINGS_TEST_FCB_VAL_STR_CNT][SETTINGS_MAX_VAL_LEN];
|
||||
char test_ref_value[SETTINGS_TEST_FCB_VAL_STR_CNT][SETTINGS_MAX_VAL_LEN];
|
||||
|
||||
char *c1_handle_get(int argc, char **argv, char *val, int val_len_max)
|
||||
{
|
||||
test_get_called = 1;
|
||||
|
||||
if (argc == 1 && !strcmp(argv[0], "mybar")) {
|
||||
return settings_str_from_value(SETTINGS_INT8, &val8, val,
|
||||
val_len_max);
|
||||
}
|
||||
|
||||
if (argc == 1 && !strcmp(argv[0], "mybar64")) {
|
||||
return settings_str_from_value(SETTINGS_INT64, &val64, val,
|
||||
val_len_max);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int c1_handle_set(int argc, char **argv, char *val)
|
||||
{
|
||||
u8_t newval;
|
||||
u64_t newval64;
|
||||
int rc;
|
||||
|
||||
test_set_called = 1;
|
||||
if (argc == 1 && !strcmp(argv[0], "mybar")) {
|
||||
rc = SETTINGS_VALUE_SET(val, SETTINGS_INT8, newval);
|
||||
zassert_true(rc == 0, "SETTINGS_VALUE_SET callback");
|
||||
val8 = newval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (argc == 1 && !strcmp(argv[0], "mybar64")) {
|
||||
rc = SETTINGS_VALUE_SET(val, SETTINGS_INT64, newval64);
|
||||
zassert_true(rc == 0, "SETTINGS_VALUE_SET callback");
|
||||
val64 = newval64;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int c1_handle_commit(void)
|
||||
{
|
||||
test_commit_called = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int c1_handle_export(void (*cb)(char *name, char *value),
|
||||
enum settings_export_tgt tgt)
|
||||
{
|
||||
char value[32];
|
||||
|
||||
if (test_export_block) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
settings_str_from_value(SETTINGS_INT8, &val8, value, sizeof(value));
|
||||
cb("myfoo/mybar", value);
|
||||
|
||||
settings_str_from_value(SETTINGS_INT64, &val64, value, sizeof(value));
|
||||
cb("myfoo/mybar64", value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ctest_clear_call_state(void)
|
||||
{
|
||||
test_get_called = 0;
|
||||
test_set_called = 0;
|
||||
test_commit_called = 0;
|
||||
}
|
||||
|
||||
int ctest_get_call_state(void)
|
||||
{
|
||||
return test_get_called + test_set_called + test_commit_called;
|
||||
}
|
||||
|
||||
void config_wipe_srcs(void)
|
||||
{
|
||||
sys_slist_init(&settings_load_srcs);
|
||||
settings_save_dst = NULL;
|
||||
}
|
||||
|
||||
struct flash_sector fcb_sectors[SETTINGS_TEST_FCB_FLASH_CNT] = {
|
||||
[0] = {
|
||||
.fs_off = 0x00000000,
|
||||
.fs_size = 16 * 1024
|
||||
},
|
||||
[1] = {
|
||||
.fs_off = 0x00004000,
|
||||
.fs_size = 16 * 1024
|
||||
},
|
||||
[2] = {
|
||||
.fs_off = 0x00008000,
|
||||
.fs_size = 16 * 1024
|
||||
},
|
||||
[3] = {
|
||||
.fs_off = 0x0000c000,
|
||||
.fs_size = 16 * 1024
|
||||
}
|
||||
};
|
||||
|
||||
void config_wipe_fcb(struct flash_sector *fs, int cnt)
|
||||
{
|
||||
const struct flash_area *fap;
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
rc = flash_area_open(CONFIG_SETTINGS_FCB_FLASH_AREA, &fap);
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
rc = flash_area_erase(fap, fs[i].fs_off, fs[i].fs_size);
|
||||
zassert_true(rc == 0, "Can't get flash area\n");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test_config_fill_area(char test_value[SETTINGS_TEST_FCB_VAL_STR_CNT]
|
||||
[SETTINGS_MAX_VAL_LEN],
|
||||
int iteration)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (j = 0; j < 64; j++) {
|
||||
for (i = 0; i < SETTINGS_MAX_VAL_LEN; i++) {
|
||||
test_value[j][i] = ((j * 2) + i + iteration) % 10 + '0';
|
||||
}
|
||||
test_value[j][sizeof(test_value[j]) - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
char *c2_var_find(char *name)
|
||||
{
|
||||
int idx = 0;
|
||||
int len;
|
||||
char *eptr;
|
||||
|
||||
len = strlen(name);
|
||||
zassert_true(len > 6, "string type expected\n");
|
||||
zassert_true(!strncmp(name, "string", 6), "string type expected\n");
|
||||
|
||||
idx = strtoul(&name[6], &eptr, 10);
|
||||
zassert_true(*eptr == '\0', "EOF\n");
|
||||
zassert_true(idx < c2_var_count,
|
||||
"var index greather than any exporter\n");
|
||||
|
||||
return val_string[idx];
|
||||
}
|
||||
|
||||
char *c2_handle_get(int argc, char **argv, char *val, int val_len_max)
|
||||
{
|
||||
int len;
|
||||
char *valptr;
|
||||
|
||||
if (argc == 1) {
|
||||
valptr = c2_var_find(argv[0]);
|
||||
if (!valptr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len = strlen(val_string[0]);
|
||||
if (len > val_len_max) {
|
||||
len = val_len_max;
|
||||
}
|
||||
|
||||
strncpy(val, valptr, len);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int c2_handle_set(int argc, char **argv, char *val)
|
||||
{
|
||||
char *valptr;
|
||||
|
||||
if (argc == 1) {
|
||||
valptr = c2_var_find(argv[0]);
|
||||
if (!valptr) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (val) {
|
||||
strncpy(valptr, val, sizeof(val_string[0]));
|
||||
} else {
|
||||
memset(valptr, 0, sizeof(val_string[0]));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int c2_handle_export(void (*cb)(char *name, char *value),
|
||||
enum settings_export_tgt tgt)
|
||||
{
|
||||
int i;
|
||||
char name[32];
|
||||
|
||||
for (i = 0; i < c2_var_count; i++) {
|
||||
snprintf(name, sizeof(name), "2nd/string%d", i);
|
||||
cb(name, val_string[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *c3_handle_get(int argc, char **argv, char *val, int val_len_max)
|
||||
{
|
||||
if (argc == 1 && !strcmp(argv[0], "v")) {
|
||||
return settings_str_from_value(SETTINGS_INT32, &val32, val,
|
||||
val_len_max);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int c3_handle_set(int argc, char **argv, char *val)
|
||||
{
|
||||
u32_t newval;
|
||||
int rc;
|
||||
|
||||
if (argc == 1 && !strcmp(argv[0], "v")) {
|
||||
rc = SETTINGS_VALUE_SET(val, SETTINGS_INT32, newval);
|
||||
zassert_true(rc == 0, "SETTINGS_VALUE_SET callback");
|
||||
val32 = newval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int c3_handle_export(void (*cb)(char *name, char *value),
|
||||
enum settings_export_tgt tgt)
|
||||
{
|
||||
char value[32];
|
||||
|
||||
settings_str_from_value(SETTINGS_INT32, &val32, value, sizeof(value));
|
||||
cb("3/v", value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void config_empty_lookups(void);
|
||||
void test_config_insert(void);
|
||||
void test_config_getset_unknown(void);
|
||||
void test_config_getset_int(void);
|
||||
void test_config_getset_bytes(void);
|
||||
void test_config_getset_int64(void);
|
||||
void test_config_commit(void);
|
||||
|
||||
void test_config_empty_fcb(void);
|
||||
void test_config_save_1_fcb(void);
|
||||
void test_config_insert2(void);
|
||||
void test_config_save_2_fcb(void);
|
||||
void test_config_insert3(void);
|
||||
void test_config_save_3_fcb(void);
|
||||
void test_config_compress_reset(void);
|
||||
void test_config_save_one_fcb(void);
|
||||
|
||||
void test_main(void *p1, void *p2, void *p3)
|
||||
{
|
||||
ztest_test_suite(test_config_fcb,
|
||||
/* Config tests */
|
||||
ztest_unit_test(config_empty_lookups),
|
||||
ztest_unit_test(test_config_insert),
|
||||
ztest_unit_test(test_config_getset_unknown),
|
||||
ztest_unit_test(test_config_getset_int),
|
||||
ztest_unit_test(test_config_getset_bytes),
|
||||
ztest_unit_test(test_config_getset_int64),
|
||||
ztest_unit_test(test_config_commit),
|
||||
/* FCB as backing storage*/
|
||||
ztest_unit_test(test_config_empty_fcb),
|
||||
ztest_unit_test(test_config_save_1_fcb),
|
||||
ztest_unit_test(test_config_insert2),
|
||||
ztest_unit_test(test_config_save_2_fcb),
|
||||
ztest_unit_test(test_config_insert3),
|
||||
ztest_unit_test(test_config_save_3_fcb),
|
||||
ztest_unit_test(test_config_compress_reset),
|
||||
ztest_unit_test(test_config_save_one_fcb)
|
||||
);
|
||||
|
||||
ztest_run_test_suite(test_config_fcb);
|
||||
}
|
38
tests/subsys/settings/fcb/src/settings_test_save_1_fcb.c
Normal file
38
tests/subsys/settings/fcb/src/settings_test_save_1_fcb.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "settings_test.h"
|
||||
#include "settings/settings_fcb.h"
|
||||
|
||||
void test_config_save_1_fcb(void)
|
||||
{
|
||||
int rc;
|
||||
struct settings_fcb cf;
|
||||
|
||||
config_wipe_srcs();
|
||||
|
||||
cf.cf_fcb.f_magic = CONFIG_SETTINGS_FCB_MAGIC;
|
||||
cf.cf_fcb.f_sectors = fcb_sectors;
|
||||
cf.cf_fcb.f_sector_cnt = ARRAY_SIZE(fcb_sectors);
|
||||
|
||||
rc = settings_fcb_src(&cf);
|
||||
zassert_true(rc == 0, "can't register FCB as configuration source\n");
|
||||
|
||||
rc = settings_fcb_dst(&cf);
|
||||
zassert_true(rc == 0,
|
||||
"can't register FCB as configuration destination\n");
|
||||
|
||||
val8 = 33;
|
||||
rc = settings_save();
|
||||
zassert_true(rc == 0, "fcb write error\n");
|
||||
|
||||
val8 = 0;
|
||||
|
||||
rc = settings_load();
|
||||
zassert_true(rc == 0, "fcb redout error\n");
|
||||
zassert_true(val8 == 33, "bad value read\n");
|
||||
}
|
77
tests/subsys/settings/fcb/src/settings_test_save_2_fcb.c
Normal file
77
tests/subsys/settings/fcb/src/settings_test_save_2_fcb.c
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "settings_test.h"
|
||||
#include "settings/settings_fcb.h"
|
||||
|
||||
#ifdef TEST_LONG
|
||||
#define TESTS_S2_FCB_ITERATIONS 32
|
||||
#else
|
||||
#define TESTS_S2_FCB_ITERATIONS 2
|
||||
#endif
|
||||
|
||||
void test_config_save_2_fcb(void)
|
||||
{
|
||||
int rc;
|
||||
struct settings_fcb cf;
|
||||
|
||||
int i;
|
||||
|
||||
config_wipe_srcs();
|
||||
|
||||
cf.cf_fcb.f_magic = CONFIG_SETTINGS_FCB_MAGIC;
|
||||
cf.cf_fcb.f_sectors = fcb_sectors;
|
||||
cf.cf_fcb.f_sector_cnt = ARRAY_SIZE(fcb_sectors);
|
||||
|
||||
rc = settings_fcb_src(&cf);
|
||||
zassert_true(rc == 0, "can't register FCB as configuration source\n");
|
||||
|
||||
rc = settings_fcb_dst(&cf);
|
||||
zassert_true(rc == 0,
|
||||
"can't register FCB as configuration destination\n");
|
||||
|
||||
test_config_fill_area(test_ref_value, 0);
|
||||
memcpy(val_string, test_ref_value, sizeof(val_string));
|
||||
|
||||
val8 = 42;
|
||||
rc = settings_save();
|
||||
zassert_true(rc == 0, "fcb write error\n");
|
||||
|
||||
val8 = 0;
|
||||
memset(val_string[0], 0, sizeof(val_string[0]));
|
||||
rc = settings_load();
|
||||
zassert_true(rc == 0, "fcb read error\n");
|
||||
zassert_true(val8 == 42, "bad value read\n");
|
||||
zassert_true(!strcmp(val_string[0], test_ref_value[0]),
|
||||
"bad value read\n");
|
||||
test_export_block = 1;
|
||||
|
||||
/*
|
||||
* Now add the number of settings to max. Keep adjusting the test_data,
|
||||
* check that rollover happens when it's supposed to.
|
||||
*/
|
||||
c2_var_count = 64;
|
||||
|
||||
for (i = 0; i < TESTS_S2_FCB_ITERATIONS; i++) {
|
||||
test_config_fill_area(test_ref_value, i);
|
||||
memcpy(val_string, test_ref_value, sizeof(val_string));
|
||||
|
||||
rc = settings_save();
|
||||
zassert_true(rc == 0, "fcb write error\n");
|
||||
|
||||
memset(val_string, 0, sizeof(val_string));
|
||||
|
||||
val8 = 0;
|
||||
rc = settings_load();
|
||||
zassert_true(rc == 0, "fcb read error\n");
|
||||
zassert_true(!memcmp(val_string, test_ref_value,
|
||||
sizeof(val_string)),
|
||||
"bad value read\n");
|
||||
zassert_true(val8 == 42, "bad value read\n");
|
||||
}
|
||||
c2_var_count = 0;
|
||||
}
|
49
tests/subsys/settings/fcb/src/settings_test_save_3_fcb.c
Normal file
49
tests/subsys/settings/fcb/src/settings_test_save_3_fcb.c
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "settings_test.h"
|
||||
#include "settings/settings_fcb.h"
|
||||
|
||||
#ifdef TEST_LONG
|
||||
#define TESTS_S3_FCB_ITERATIONS 4096
|
||||
#else
|
||||
#define TESTS_S3_FCB_ITERATIONS 100
|
||||
#endif
|
||||
|
||||
void test_config_save_3_fcb(void)
|
||||
{
|
||||
int rc;
|
||||
struct settings_fcb cf;
|
||||
int i;
|
||||
|
||||
config_wipe_srcs();
|
||||
config_wipe_fcb(fcb_sectors, ARRAY_SIZE(fcb_sectors));
|
||||
|
||||
cf.cf_fcb.f_magic = CONFIG_SETTINGS_FCB_MAGIC;
|
||||
cf.cf_fcb.f_sectors = fcb_sectors;
|
||||
cf.cf_fcb.f_sector_cnt = 4;
|
||||
|
||||
rc = settings_fcb_src(&cf);
|
||||
zassert_true(rc == 0, "can't register FCB as configuration source\n");
|
||||
|
||||
rc = settings_fcb_dst(&cf);
|
||||
zassert_true(rc == 0,
|
||||
"can't register FCB as configuration destination\n");
|
||||
|
||||
for (i = 0; i < TESTS_S3_FCB_ITERATIONS; i++) {
|
||||
val32 = i;
|
||||
|
||||
rc = settings_save();
|
||||
zassert_true(rc == 0, "fcb write error\n");
|
||||
|
||||
val32 = 0;
|
||||
|
||||
rc = settings_load();
|
||||
zassert_true(rc == 0, "fcb read error\n");
|
||||
zassert_true(val32 == i, "bad value read\n");
|
||||
}
|
||||
}
|
47
tests/subsys/settings/fcb/src/settings_test_save_one_fcb.c
Normal file
47
tests/subsys/settings/fcb/src/settings_test_save_one_fcb.c
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "settings_test.h"
|
||||
#include "settings/settings_fcb.h"
|
||||
|
||||
void test_config_save_one_fcb(void)
|
||||
{
|
||||
int rc;
|
||||
struct settings_fcb cf;
|
||||
|
||||
config_wipe_srcs();
|
||||
config_wipe_fcb(fcb_sectors, ARRAY_SIZE(fcb_sectors));
|
||||
|
||||
cf.cf_fcb.f_magic = CONFIG_SETTINGS_FCB_MAGIC;
|
||||
cf.cf_fcb.f_sectors = fcb_sectors;
|
||||
cf.cf_fcb.f_sector_cnt = ARRAY_SIZE(fcb_sectors);
|
||||
|
||||
rc = settings_fcb_src(&cf);
|
||||
zassert_true(rc == 0, "can't register FCB as configuration source\n");
|
||||
|
||||
rc = settings_fcb_dst(&cf);
|
||||
zassert_true(rc == 0,
|
||||
"can't register FCB as configuration destination\n");
|
||||
|
||||
val8 = 33;
|
||||
rc = settings_save();
|
||||
zassert_true(rc == 0, "fcb write error\n");
|
||||
|
||||
rc = settings_save_one("myfoo/mybar", "42");
|
||||
zassert_true(rc == 0, "fcb one item write error\n");
|
||||
|
||||
rc = settings_load();
|
||||
zassert_true(rc == 0, "fcb read error\n");
|
||||
zassert_true(val8 == 42, "bad value read\n");
|
||||
|
||||
rc = settings_save_one("myfoo/mybar", "44");
|
||||
zassert_true(rc == 0, "fcb one item write error\n");
|
||||
|
||||
rc = settings_load();
|
||||
zassert_true(rc == 0, "fcb read error\n");
|
||||
zassert_true(val8 == 44, "bad value read\n");
|
||||
}
|
5
tests/subsys/settings/fcb/testcase.yaml
Normal file
5
tests/subsys/settings/fcb/testcase.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
tests:
|
||||
test:
|
||||
build_only: true
|
||||
platform_whitelist: nrf52840_pca10056, nrf52_pca10040
|
||||
tags: settings_fcb
|
16
tests/subsys/settings/nffs/CMakeLists.txt
Normal file
16
tests/subsys/settings/nffs/CMakeLists.txt
Normal file
|
@ -0,0 +1,16 @@
|
|||
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
|
||||
project(NONE)
|
||||
|
||||
FILE(GLOB app_sources src/*.c ../src/*c)
|
||||
target_sources(app PRIVATE ${app_sources})
|
||||
zephyr_include_directories(
|
||||
$ENV{ZEPHYR_BASE}/subsys/settings/include
|
||||
$ENV{ZEPHYR_BASE}/subsys/settings/src
|
||||
$ENV{ZEPHYR_BASE}/tests/subsys/settings/nffs/src
|
||||
)
|
||||
|
||||
if(TEST)
|
||||
target_compile_definitions(app PRIVATE
|
||||
-DTEST_${TEST}
|
||||
)
|
||||
endif()
|
28
tests/subsys/settings/nffs/prj.conf
Normal file
28
tests/subsys/settings/nffs/prj.conf
Normal file
|
@ -0,0 +1,28 @@
|
|||
CONFIG_ZTEST=y
|
||||
CONFIG_STDOUT_CONSOLE=y
|
||||
CONFIG_FLASH=y
|
||||
CONFIG_SOC_FLASH_NRF5=y
|
||||
CONFIG_FLASH_PAGE_LAYOUT=y
|
||||
CONFIG_FLASH_MAP=y
|
||||
CONFIG_ARM_CORE_MPU=n
|
||||
CONFIG_ARM_MPU=n
|
||||
CONFIG_ARM_MPU_NRF52X=n
|
||||
|
||||
CONFIG_ZTEST_STACKSIZE=2048
|
||||
CONFIG_MAIN_STACK_SIZE=1024
|
||||
CONFIG_HEAP_MEM_POOL_SIZE=1024
|
||||
|
||||
CONFIG_FILE_SYSTEM=y
|
||||
CONFIG_FILE_SYSTEM_NFFS=y
|
||||
CONFIG_FS_NFFS_FLASH_DEV_NAME="NRF_FLASH_DRV_NAME"
|
||||
CONFIG_FS_NFFS_NUM_FILES=4
|
||||
CONFIG_FS_NFFS_NUM_DIRS=4
|
||||
CONFIG_FS_NFFS_NUM_INODES=1024
|
||||
CONFIG_FS_NFFS_NUM_BLOCKS=1024
|
||||
CONFIG_FS_NFFS_NUM_CACHE_INODES=1
|
||||
CONFIG_FS_NFFS_NUM_CACHE_BLOCKS=1
|
||||
CONFIG_FILE_SYSTEM_NFFS=y
|
||||
CONFIG_NFFS_FILESYSTEM_MAX_AREAS=12
|
||||
|
||||
CONFIG_SETTINGS=y
|
||||
CONFIG_SETTINGS_FS=y
|
39
tests/subsys/settings/nffs/src/settings_setup_nffs.c
Normal file
39
tests/subsys/settings/nffs/src/settings_setup_nffs.c
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "settings_test.h"
|
||||
#include <device.h>
|
||||
#include <fs.h>
|
||||
|
||||
/* NFFS work area strcut */
|
||||
static struct nffs_flash_desc flash_desc;
|
||||
|
||||
/* mounting info */
|
||||
static struct fs_mount_t nffs_mnt = {
|
||||
.type = FS_NFFS,
|
||||
.mnt_point = TEST_FS_MPTR,
|
||||
.fs_data = &flash_desc,
|
||||
};
|
||||
|
||||
void config_setup_nffs(void)
|
||||
{
|
||||
struct device *flash_dev;
|
||||
int rc;
|
||||
|
||||
flash_dev = device_get_binding(CONFIG_FS_NFFS_FLASH_DEV_NAME);
|
||||
zassert_not_null(flash_dev, "Can't bind to the flash device\n");
|
||||
|
||||
/* set backend storage dev */
|
||||
nffs_mnt.storage_dev = flash_dev;
|
||||
|
||||
rc = fs_mount(&nffs_mnt);
|
||||
zassert_true(rc == 0, "mounting nffs [%d]\n", rc);
|
||||
|
||||
rc = fs_unlink(TEST_CONFIG_DIR);
|
||||
zassert_true(rc == 0 || rc == -ENOENT,
|
||||
"can't delete config directory%d\n", rc);
|
||||
}
|
51
tests/subsys/settings/nffs/src/settings_test.h
Normal file
51
tests/subsys/settings/nffs/src/settings_test.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _SETTINGS_TEST_FCB_H
|
||||
#define _SETTINGS_TEST_FCB_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ztest.h>
|
||||
#include <fs.h>
|
||||
|
||||
#include "settings/settings.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#extern "C" {
|
||||
#endif
|
||||
|
||||
#define TEST_FS_MPTR "/nffs"
|
||||
#define TEST_CONFIG_DIR TEST_FS_MPTR"/config"
|
||||
|
||||
extern u8_t val8;
|
||||
extern u32_t val32;
|
||||
extern u64_t val64;
|
||||
|
||||
extern int test_get_called;
|
||||
extern int test_set_called;
|
||||
extern int test_commit_called;
|
||||
extern int test_export_block;
|
||||
|
||||
extern int c2_var_count;
|
||||
|
||||
extern struct settings_handler c_test_handlers[];
|
||||
|
||||
void ctest_clear_call_state(void);
|
||||
int ctest_get_call_state(void);
|
||||
|
||||
void config_wipe_srcs(void);
|
||||
|
||||
int fsutil_read_file(const char *path, off_t offset, size_t len, void *dst,
|
||||
size_t *out_len);
|
||||
int fsutil_write_file(const char *path, const void *data, size_t len);
|
||||
int settings_test_file_strstr(const char *fname, char *string);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* _SETTINGS_TEST_FCB_H */
|
104
tests/subsys/settings/nffs/src/settings_test_compress_file.c
Normal file
104
tests/subsys/settings/nffs/src/settings_test_compress_file.c
Normal file
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "settings_test.h"
|
||||
#include "settings/settings_file.h"
|
||||
|
||||
int file_str_cmp(const char *fname, char *string);
|
||||
|
||||
void test_config_compress_file(void)
|
||||
{
|
||||
int rc;
|
||||
struct settings_file cf;
|
||||
|
||||
config_wipe_srcs();
|
||||
|
||||
rc = fs_mkdir(TEST_CONFIG_DIR);
|
||||
zassert_true(rc == 0 || rc == -EEXIST, "can't create directory\n");
|
||||
|
||||
cf.cf_name = TEST_CONFIG_DIR "/korwin";
|
||||
cf.cf_maxlines = 24;
|
||||
rc = settings_file_src(&cf);
|
||||
zassert_true(rc == 0, "can't register FS as configuration source\n");
|
||||
|
||||
rc = settings_file_dst(&cf);
|
||||
zassert_true(rc == 0,
|
||||
"can't register FS as configuration destination\n");
|
||||
|
||||
val64 = 1125;
|
||||
|
||||
for (int i = 0; i < 22; i++) {
|
||||
val8 = i;
|
||||
rc = settings_save();
|
||||
zassert_true(rc == 0, "fs write error\n");
|
||||
|
||||
val8 = 0xff;
|
||||
settings_load();
|
||||
zassert_true(val8 == i, "Bad value loaded\n");
|
||||
}
|
||||
|
||||
val64 = 37;
|
||||
rc = settings_save();
|
||||
zassert_true(rc == 0, "fs write error\n");
|
||||
|
||||
/* check 1st compression */
|
||||
rc = file_str_cmp(cf.cf_name, "myfoo/mybar64=1125\n" \
|
||||
"myfoo/mybar=21\n" \
|
||||
"myfoo/mybar64=37\n");
|
||||
zassert_true(rc == 0, "bad value read\n");
|
||||
|
||||
for (int i = 0; i < 21; i++) {
|
||||
val64 = i;
|
||||
rc = settings_save();
|
||||
zassert_true(rc == 0, "fs write error\n");
|
||||
|
||||
val64 = 0xff;
|
||||
settings_load();
|
||||
zassert_true(val64 == i, "Bad value loaded\n");
|
||||
}
|
||||
|
||||
/* check subsequent compression */
|
||||
rc = file_str_cmp(cf.cf_name, "myfoo/mybar=21\n" \
|
||||
"myfoo/mybar64=19\n" \
|
||||
"myfoo/mybar64=20\n");
|
||||
zassert_true(rc == 0, "bad value read\n");
|
||||
}
|
||||
|
||||
int file_str_cmp(const char *fname, char *string)
|
||||
{
|
||||
int rc;
|
||||
u32_t len;
|
||||
u32_t rlen;
|
||||
char *buf;
|
||||
struct fs_dirent entry;
|
||||
|
||||
rc = fs_stat(fname, &entry);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (entry.size != strlen(string)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = entry.size;
|
||||
buf = (char *)k_malloc(len + 1);
|
||||
zassert_not_null(buf, "out of memory\n");
|
||||
|
||||
rc = fsutil_read_file(fname, 0, len, buf, &rlen);
|
||||
zassert_true(rc == 0, "can't access the file\n'");
|
||||
zassert_true(rc == 0, "not enough data read\n'");
|
||||
buf[rlen] = '\0';
|
||||
|
||||
if (strcmp(buf, string)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return -0;
|
||||
}
|
49
tests/subsys/settings/nffs/src/settings_test_empty_file.c
Normal file
49
tests/subsys/settings/nffs/src/settings_test_empty_file.c
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "settings_test.h"
|
||||
#include "settings/settings_file.h"
|
||||
#include <fs.h>
|
||||
|
||||
void test_config_empty_file(void)
|
||||
{
|
||||
int rc;
|
||||
struct settings_file cf_mfg;
|
||||
struct settings_file cf_running;
|
||||
const char cf_mfg_test[] = "";
|
||||
const char cf_running_test[] = "\n\n";
|
||||
|
||||
config_wipe_srcs();
|
||||
|
||||
cf_mfg.cf_name = TEST_CONFIG_DIR "/mfg";
|
||||
cf_running.cf_name = TEST_CONFIG_DIR "/running";
|
||||
|
||||
rc = settings_file_src(&cf_mfg);
|
||||
zassert_true(rc == 0, "can't register FS as configuration source\n");
|
||||
rc = settings_file_src(&cf_running);
|
||||
zassert_true(rc == 0, "can't register FS as configuration source\n");
|
||||
|
||||
/*
|
||||
* No files
|
||||
*/
|
||||
settings_load();
|
||||
|
||||
rc = fs_mkdir(TEST_CONFIG_DIR);
|
||||
zassert_true(rc == 0, "can't create directory\n");
|
||||
|
||||
rc = fsutil_write_file(TEST_CONFIG_DIR "/mfg", cf_mfg_test,
|
||||
sizeof(cf_mfg_test));
|
||||
zassert_true(rc == 0, "can't write to file\n");
|
||||
|
||||
rc = fsutil_write_file(TEST_CONFIG_DIR "/running", cf_running_test,
|
||||
sizeof(cf_running_test));
|
||||
zassert_true(rc == 0, "can't write to file\n");
|
||||
|
||||
settings_load();
|
||||
config_wipe_srcs();
|
||||
ctest_clear_call_state();
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "settings_test.h"
|
||||
#include "settings/settings_file.h"
|
||||
|
||||
void test_config_multiple_in_file(void)
|
||||
{
|
||||
int rc;
|
||||
struct settings_file cf_mfg;
|
||||
const char cf_mfg_test1[] =
|
||||
"myfoo/mybar=1\n"
|
||||
"myfoo/mybar=14";
|
||||
const char cf_mfg_test2[] =
|
||||
"myfoo/mybar=1\n"
|
||||
"myfoo/mybar=15\n"
|
||||
"\n";
|
||||
|
||||
config_wipe_srcs();
|
||||
|
||||
cf_mfg.cf_name = TEST_CONFIG_DIR "/mfg";
|
||||
rc = settings_file_src(&cf_mfg);
|
||||
zassert_true(rc == 0, "can't register FS as configuration source\n");
|
||||
|
||||
rc = fsutil_write_file(TEST_CONFIG_DIR "/mfg", cf_mfg_test1,
|
||||
sizeof(cf_mfg_test1));
|
||||
zassert_true(rc == 0, "can't write to file\n");
|
||||
|
||||
settings_load();
|
||||
zassert_true(test_set_called, "the SET handler wasn't called\n");
|
||||
zassert_true(val8 == 14,
|
||||
"SET handler: was called with wrong parameters\n");
|
||||
|
||||
rc = fsutil_write_file(TEST_CONFIG_DIR "/mfg", cf_mfg_test2,
|
||||
sizeof(cf_mfg_test2));
|
||||
zassert_true(rc == 0, "can't write to file\n");
|
||||
|
||||
settings_load();
|
||||
zassert_true(test_set_called, "the SET handler wasn't called\n");
|
||||
zassert_true(val8 == 15,
|
||||
"SET handler: was called with wrong parameters\n");
|
||||
}
|
233
tests/subsys/settings/nffs/src/settings_test_nffs.c
Normal file
233
tests/subsys/settings/nffs/src/settings_test_nffs.c
Normal file
|
@ -0,0 +1,233 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "settings_test.h"
|
||||
#include "settings_priv.h"
|
||||
|
||||
|
||||
u8_t val8;
|
||||
u64_t val64;
|
||||
|
||||
int test_get_called;
|
||||
int test_set_called;
|
||||
int test_commit_called;
|
||||
int test_export_block;
|
||||
|
||||
int c2_var_count = 1;
|
||||
|
||||
char *c1_handle_get(int argc, char **argv, char *val, int val_len_max);
|
||||
int c1_handle_set(int argc, char **argv, char *val);
|
||||
int c1_handle_commit(void);
|
||||
int c1_handle_export(void (*cb)(char *name, char *value),
|
||||
enum settings_export_tgt tgt);
|
||||
|
||||
struct settings_handler c_test_handlers[] = {
|
||||
{
|
||||
.name = "myfoo",
|
||||
.h_get = c1_handle_get,
|
||||
.h_set = c1_handle_set,
|
||||
.h_commit = c1_handle_commit,
|
||||
.h_export = c1_handle_export
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
|
||||
char *c1_handle_get(int argc, char **argv, char *val, int val_len_max)
|
||||
{
|
||||
test_get_called = 1;
|
||||
|
||||
if (argc == 1 && !strcmp(argv[0], "mybar")) {
|
||||
return settings_str_from_value(SETTINGS_INT8, &val8, val,
|
||||
val_len_max);
|
||||
}
|
||||
|
||||
if (argc == 1 && !strcmp(argv[0], "mybar64")) {
|
||||
return settings_str_from_value(SETTINGS_INT64, &val64, val,
|
||||
val_len_max);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int c1_handle_set(int argc, char **argv, char *val)
|
||||
{
|
||||
u8_t newval;
|
||||
u64_t newval64;
|
||||
int rc;
|
||||
|
||||
test_set_called = 1;
|
||||
if (argc == 1 && !strcmp(argv[0], "mybar")) {
|
||||
rc = SETTINGS_VALUE_SET(val, SETTINGS_INT8, newval);
|
||||
zassert_true(rc == 0, "SETTINGS_VALUE_SET callback");
|
||||
val8 = newval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (argc == 1 && !strcmp(argv[0], "mybar64")) {
|
||||
rc = SETTINGS_VALUE_SET(val, SETTINGS_INT64, newval64);
|
||||
zassert_true(rc == 0, "SETTINGS_VALUE_SET callback");
|
||||
val64 = newval64;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int c1_handle_commit(void)
|
||||
{
|
||||
test_commit_called = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int c1_handle_export(void (*cb)(char *name, char *value),
|
||||
enum settings_export_tgt tgt)
|
||||
{
|
||||
char value[32];
|
||||
|
||||
if (test_export_block) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
settings_str_from_value(SETTINGS_INT8, &val8, value, sizeof(value));
|
||||
cb("myfoo/mybar", value);
|
||||
|
||||
settings_str_from_value(SETTINGS_INT64, &val64, value, sizeof(value));
|
||||
cb("myfoo/mybar64", value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ctest_clear_call_state(void)
|
||||
{
|
||||
test_get_called = 0;
|
||||
test_set_called = 0;
|
||||
test_commit_called = 0;
|
||||
}
|
||||
|
||||
int ctest_get_call_state(void)
|
||||
{
|
||||
return test_get_called + test_set_called + test_commit_called;
|
||||
}
|
||||
|
||||
void config_wipe_srcs(void)
|
||||
{
|
||||
sys_slist_init(&settings_load_srcs);
|
||||
settings_save_dst = NULL;
|
||||
}
|
||||
|
||||
int fsutil_read_file(const char *path, off_t offset, size_t len, void *dst,
|
||||
size_t *out_len)
|
||||
{
|
||||
struct fs_file_t file;
|
||||
int rc;
|
||||
ssize_t r_len = 0;
|
||||
|
||||
rc = fs_open(&file, path);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
r_len = fs_read(&file, dst, len);
|
||||
if (r_len < 0) {
|
||||
rc = -EIO;
|
||||
} else {
|
||||
*out_len = r_len;
|
||||
}
|
||||
|
||||
fs_close(&file);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int fsutil_write_file(const char *path, const void *data, size_t len)
|
||||
{
|
||||
struct fs_file_t file;
|
||||
int rc;
|
||||
|
||||
rc = fs_open(&file, path);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (fs_write(&file, data, len) != len) {
|
||||
rc = -EIO;
|
||||
}
|
||||
|
||||
fs_close(&file);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int settings_test_file_strstr(const char *fname, char *string)
|
||||
{
|
||||
int rc;
|
||||
u32_t len;
|
||||
u32_t rlen;
|
||||
char *buf;
|
||||
struct fs_dirent entry;
|
||||
|
||||
rc = fs_stat(fname, &entry);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
len = entry.size;
|
||||
buf = (char *)k_malloc(len + 1);
|
||||
zassert_not_null(buf, "out of memory\n");
|
||||
|
||||
rc = fsutil_read_file(fname, 0, len, buf, &rlen);
|
||||
zassert_true(rc == 0, "can't access the file\n'");
|
||||
zassert_true(rc == 0, "not enough data read\n'");
|
||||
buf[rlen] = '\0';
|
||||
|
||||
if (strstr(buf, string)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void config_empty_lookups(void);
|
||||
void test_config_insert(void);
|
||||
void test_config_getset_unknown(void);
|
||||
void test_config_getset_int(void);
|
||||
void test_config_getset_bytes(void);
|
||||
void test_config_getset_int64(void);
|
||||
void test_config_commit(void);
|
||||
|
||||
void config_setup_nffs(void);
|
||||
void test_config_empty_file(void);
|
||||
void test_config_small_file(void);
|
||||
void test_config_multiple_in_file(void);
|
||||
void test_config_save_in_file(void);
|
||||
void test_config_save_one_file(void);
|
||||
void test_config_compress_file(void);
|
||||
|
||||
void test_main(void *p1, void *p2, void *p3)
|
||||
{
|
||||
ztest_test_suite(test_config_fcb,
|
||||
/* Config tests */
|
||||
ztest_unit_test(config_empty_lookups),
|
||||
ztest_unit_test(test_config_insert),
|
||||
ztest_unit_test(test_config_getset_unknown),
|
||||
ztest_unit_test(test_config_getset_int),
|
||||
ztest_unit_test(test_config_getset_bytes),
|
||||
ztest_unit_test(test_config_getset_int64),
|
||||
ztest_unit_test(test_config_commit),
|
||||
/* NFFS as backing storage. */
|
||||
ztest_unit_test(config_setup_nffs),
|
||||
ztest_unit_test(test_config_empty_file),
|
||||
ztest_unit_test(test_config_small_file),
|
||||
ztest_unit_test(test_config_multiple_in_file),
|
||||
ztest_unit_test(test_config_save_in_file),
|
||||
ztest_unit_test(test_config_save_one_file),
|
||||
ztest_unit_test(test_config_compress_file)
|
||||
);
|
||||
|
||||
ztest_run_test_suite(test_config_fcb);
|
||||
}
|
42
tests/subsys/settings/nffs/src/settings_test_save_in_file.c
Normal file
42
tests/subsys/settings/nffs/src/settings_test_save_in_file.c
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "settings_test.h"
|
||||
#include "settings/settings_file.h"
|
||||
|
||||
void test_config_save_in_file(void)
|
||||
{
|
||||
int rc;
|
||||
struct settings_file cf;
|
||||
|
||||
config_wipe_srcs();
|
||||
|
||||
rc = fs_mkdir(TEST_CONFIG_DIR);
|
||||
zassert_true(rc == 0 || rc == -EEXIST, "can't create directory\n");
|
||||
|
||||
cf.cf_name = TEST_CONFIG_DIR "/blah";
|
||||
rc = settings_file_src(&cf);
|
||||
zassert_true(rc == 0, "can't register FS as configuration source\n");
|
||||
|
||||
rc = settings_file_dst(&cf);
|
||||
zassert_true(rc == 0,
|
||||
"can't register FS as configuration destination\n");
|
||||
|
||||
val8 = 8;
|
||||
rc = settings_save();
|
||||
zassert_true(rc == 0, "fs write error\n");
|
||||
|
||||
rc = settings_test_file_strstr(cf.cf_name, "myfoo/mybar=8\n");
|
||||
zassert_true(rc == 0, "bad value read\n");
|
||||
|
||||
val8 = 43;
|
||||
rc = settings_save();
|
||||
zassert_true(rc == 0, "fs write error\n");
|
||||
|
||||
rc = settings_test_file_strstr(cf.cf_name, "myfoo/mybar=43\n");
|
||||
zassert_true(rc == 0, "bad value read\n");
|
||||
}
|
45
tests/subsys/settings/nffs/src/settings_test_save_one_file.c
Normal file
45
tests/subsys/settings/nffs/src/settings_test_save_one_file.c
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "settings_test.h"
|
||||
#include "settings/settings_file.h"
|
||||
|
||||
void test_config_save_one_file(void)
|
||||
{
|
||||
int rc;
|
||||
struct settings_file cf;
|
||||
|
||||
config_wipe_srcs();
|
||||
rc = fs_mkdir(TEST_CONFIG_DIR);
|
||||
zassert_true(rc == 0 || rc == -EEXIST, "can't create directory\n");
|
||||
|
||||
cf.cf_name = TEST_CONFIG_DIR "/blah";
|
||||
rc = settings_file_src(&cf);
|
||||
zassert_true(rc == 0, "can't register FS as configuration source\n");
|
||||
|
||||
rc = settings_file_dst(&cf);
|
||||
zassert_true(rc == 0,
|
||||
"can't register FS as configuration destination\n");
|
||||
|
||||
val8 = 33;
|
||||
rc = settings_save();
|
||||
zassert_true(rc == 0, "fs write error\n");
|
||||
|
||||
rc = settings_save_one("myfoo/mybar", "42");
|
||||
zassert_equal(rc, 0, "fs one item write error\n");
|
||||
|
||||
rc = settings_load();
|
||||
zassert_true(rc == 0, "fs redout error\n");
|
||||
zassert_true(val8 == 42, "bad value read\n");
|
||||
|
||||
rc = settings_save_one("myfoo/mybar", "44");
|
||||
zassert_true(rc == 0, "fs one item write error\n");
|
||||
|
||||
rc = settings_load();
|
||||
zassert_true(rc == 0, "fs redout error\n");
|
||||
zassert_true(val8 == 44, "bad value read\n");
|
||||
}
|
50
tests/subsys/settings/nffs/src/settings_test_small_file.c
Normal file
50
tests/subsys/settings/nffs/src/settings_test_small_file.c
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "settings_test.h"
|
||||
#include "settings/settings_file.h"
|
||||
|
||||
void test_config_small_file(void)
|
||||
{
|
||||
int rc;
|
||||
struct settings_file cf_mfg;
|
||||
struct settings_file cf_running;
|
||||
const char cf_mfg_test[] = "myfoo/mybar=1";
|
||||
const char cf_running_test[] = " myfoo/mybar = 8 ";
|
||||
|
||||
config_wipe_srcs();
|
||||
|
||||
cf_mfg.cf_name = TEST_CONFIG_DIR "/mfg";
|
||||
cf_running.cf_name = TEST_CONFIG_DIR "/running";
|
||||
|
||||
rc = settings_file_src(&cf_mfg);
|
||||
zassert_true(rc == 0, "can't register FS as configuration source\n");
|
||||
rc = settings_file_src(&cf_running);
|
||||
zassert_true(rc == 0, "can't register FS as configuration source\n");
|
||||
|
||||
rc = fsutil_write_file(TEST_CONFIG_DIR "/mfg", cf_mfg_test,
|
||||
sizeof(cf_mfg_test));
|
||||
zassert_true(rc == 0, "can't write to file\n");
|
||||
|
||||
settings_load();
|
||||
zassert_true(test_set_called, "the SET handler wasn't called\n");
|
||||
zassert_true(val8 == 1,
|
||||
"SET handler: was called with wrong parameters\n");
|
||||
|
||||
ctest_clear_call_state();
|
||||
|
||||
rc = fsutil_write_file(TEST_CONFIG_DIR "/running", cf_running_test,
|
||||
sizeof(cf_running_test));
|
||||
zassert_true(rc == 0, "can't write to file\n");
|
||||
|
||||
settings_load();
|
||||
zassert_true(test_set_called, "the SET handler wasn't called\n");
|
||||
zassert_true(val8 == 8,
|
||||
"SET handler: was called with wrong parameters\n");
|
||||
|
||||
ctest_clear_call_state();
|
||||
}
|
5
tests/subsys/settings/nffs/testcase.yaml
Normal file
5
tests/subsys/settings/nffs/testcase.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
tests:
|
||||
test:
|
||||
build_only: true
|
||||
platform_whitelist: nrf52840_pca10056, nrf52_pca10040
|
||||
tags: settings_fs
|
23
tests/subsys/settings/src/settings_empty_lookups.c
Normal file
23
tests/subsys/settings/src/settings_empty_lookups.c
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "settings_test.h"
|
||||
|
||||
void config_empty_lookups(void)
|
||||
{
|
||||
int rc;
|
||||
char name[80];
|
||||
char tmp[64], *str;
|
||||
|
||||
strcpy(name, "foo/bar");
|
||||
rc = settings_set_value(name, "tmp");
|
||||
zassert_true(rc != 0, "settings_set_value callback");
|
||||
|
||||
strcpy(name, "foo/bar");
|
||||
str = settings_get_value(name, tmp, sizeof(tmp));
|
||||
zassert_true(str == NULL, "settings_get_value callback");
|
||||
}
|
33
tests/subsys/settings/src/settings_test_commit.c
Normal file
33
tests/subsys/settings/src/settings_test_commit.c
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "settings_test.h"
|
||||
|
||||
void test_config_commit(void)
|
||||
{
|
||||
char name[80];
|
||||
int rc;
|
||||
|
||||
strcpy(name, "bar");
|
||||
rc = settings_commit(name);
|
||||
zassert_true(rc, "commit-nonexisting-tree call should succeed\n");
|
||||
zassert_true(ctest_get_call_state() == 0,
|
||||
"a handler was called unexpectedly\n");
|
||||
|
||||
rc = settings_commit(NULL);
|
||||
zassert_true(rc == 0, "commit-All call should succeed");
|
||||
zassert_true(test_commit_called == 1,
|
||||
"the COMMIT handler wasn't called\n");
|
||||
ctest_clear_call_state();
|
||||
|
||||
strcpy(name, "myfoo");
|
||||
rc = settings_commit(name);
|
||||
zassert_true(rc == 0, "commit-a-tree call should succeed\n");
|
||||
zassert_true(test_commit_called == 1,
|
||||
"the COMMIT handler wasn't called\n");
|
||||
ctest_clear_call_state();
|
||||
}
|
39
tests/subsys/settings/src/settings_test_getset_bytes.c
Normal file
39
tests/subsys/settings/src/settings_test_getset_bytes.c
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "settings_test.h"
|
||||
|
||||
void test_config_getset_bytes(void)
|
||||
{
|
||||
char orig[32];
|
||||
char bytes[32];
|
||||
char str[48];
|
||||
char *ret;
|
||||
int j, i;
|
||||
int tmp;
|
||||
int rc;
|
||||
|
||||
for (j = 1; j < sizeof(orig); j++) {
|
||||
for (i = 0; i < j; i++) {
|
||||
orig[i] = i + j + 1;
|
||||
}
|
||||
ret = settings_str_from_bytes(orig, j, str, sizeof(str));
|
||||
zassert_not_null(ret, "string base64 encodding\n");
|
||||
tmp = strlen(str);
|
||||
zassert_true(tmp < sizeof(str), "encoded string is to long\n");
|
||||
|
||||
memset(bytes, 0, sizeof(bytes));
|
||||
tmp = sizeof(bytes);
|
||||
|
||||
tmp = sizeof(bytes);
|
||||
rc = settings_bytes_from_str(str, bytes, &tmp);
|
||||
zassert_true(rc == 0, "base64 to string decodding\n");
|
||||
zassert_true(tmp == j, "decoded string bad length\n");
|
||||
zassert_true(!memcmp(orig, bytes, j),
|
||||
"decoded string not match to origin\n");
|
||||
}
|
||||
}
|
30
tests/subsys/settings/src/settings_test_getset_int.c
Normal file
30
tests/subsys/settings/src/settings_test_getset_int.c
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "settings_test.h"
|
||||
|
||||
void test_config_getset_int(void)
|
||||
{
|
||||
char name[80];
|
||||
char tmp[64], *str;
|
||||
int rc;
|
||||
|
||||
strcpy(name, "myfoo/mybar");
|
||||
rc = settings_set_value(name, "42");
|
||||
zassert_true(rc == 0, "can not set key value\n");
|
||||
zassert_true(test_set_called == 1, "the SET handler wasn't called\n");
|
||||
zassert_true(val8 == 42,
|
||||
"SET handler: was called with wrong parameters\n");
|
||||
ctest_clear_call_state();
|
||||
|
||||
strcpy(name, "myfoo/mybar");
|
||||
str = settings_get_value(name, tmp, sizeof(tmp));
|
||||
zassert_not_null(str, "the key value should been available\n");
|
||||
zassert_true(test_get_called == 1, "the GET handler wasn't called\n");
|
||||
zassert_true(!strcmp("42", tmp), "unexpected value fetched\n");
|
||||
ctest_clear_call_state();
|
||||
}
|
48
tests/subsys/settings/src/settings_test_getset_int64.c
Normal file
48
tests/subsys/settings/src/settings_test_getset_int64.c
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "settings_test.h"
|
||||
|
||||
void test_config_getset_int64(void)
|
||||
{
|
||||
char name[80];
|
||||
char tmp[64], *str;
|
||||
int rc;
|
||||
s64_t cmp;
|
||||
|
||||
strcpy(name, "myfoo/mybar64");
|
||||
rc = settings_set_value(name, "-9218247941279444428");
|
||||
zassert_true(rc == 0, "can't set value\n");
|
||||
zassert_true(test_set_called == 1, "the SET handler wasn't called\n");
|
||||
cmp = 0x8012345678901234;
|
||||
zassert_true(memcmp(&val64, &cmp, sizeof(val64)) == 0,
|
||||
"SET handler: was called with wrong parameters\n");
|
||||
ctest_clear_call_state();
|
||||
|
||||
strcpy(name, "myfoo/mybar64");
|
||||
str = settings_get_value(name, tmp, sizeof(tmp));
|
||||
zassert_not_null(str, "the key value should been available\n");
|
||||
zassert_true(test_get_called == 1, "the GET handler wasn't called\n");
|
||||
zassert_true(!strcmp("-9218247941279444428", tmp),
|
||||
"unexpected value fetched %s\n", tmp);
|
||||
ctest_clear_call_state();
|
||||
|
||||
strcpy(name, "myfoo/mybar64");
|
||||
rc = settings_set_value(name, "1");
|
||||
zassert_true(rc == 0, "can't set value\n");
|
||||
zassert_true(test_set_called == 1, "the SET handler wasn't called\n");
|
||||
zassert_true(val64 == 1,
|
||||
"SET handler: was called with wrong parameters\n");
|
||||
ctest_clear_call_state();
|
||||
|
||||
strcpy(name, "myfoo/mybar64");
|
||||
str = settings_get_value(name, tmp, sizeof(tmp));
|
||||
zassert_not_null(str, "the key value should been available\n");
|
||||
zassert_true(test_get_called == 1, "the GET handler wasn't called\n");
|
||||
zassert_true(!strcmp("1", tmp), "unexpected value fetched\n");
|
||||
ctest_clear_call_state();
|
||||
}
|
42
tests/subsys/settings/src/settings_test_getset_unknown.c
Normal file
42
tests/subsys/settings/src/settings_test_getset_unknown.c
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "settings_test.h"
|
||||
#include <errno.h>
|
||||
|
||||
void test_config_getset_unknown(void)
|
||||
{
|
||||
char name[80];
|
||||
char tmp[64], *str;
|
||||
int rc;
|
||||
|
||||
strcpy(name, "foo/bar");
|
||||
rc = settings_set_value(name, "tmp");
|
||||
zassert_true(rc != 0, "set value should fail\n");
|
||||
zassert_true(ctest_get_call_state() == 0,
|
||||
"a handler was called unexpectedly\n");
|
||||
|
||||
strcpy(name, "foo/bar");
|
||||
str = settings_get_value(name, tmp, sizeof(tmp));
|
||||
zassert_true(str == NULL, "value should been unreachable\n");
|
||||
zassert_true(ctest_get_call_state() == 0,
|
||||
"a handler was called unexpectedly\n");
|
||||
|
||||
strcpy(name, "myfoo/bar");
|
||||
rc = settings_set_value(name, "tmp");
|
||||
zassert_true(rc == -ENOENT, "unexpected failure retval\n");
|
||||
zassert_true(test_set_called == 1,
|
||||
"the GET handler wasn't called\n");
|
||||
ctest_clear_call_state();
|
||||
|
||||
strcpy(name, "myfoo/bar");
|
||||
str = settings_get_value(name, tmp, sizeof(tmp));
|
||||
zassert_true(str == NULL, "value should been unreachable\n");
|
||||
zassert_true(test_get_called == 1,
|
||||
"the SET handler wasn't called\n");
|
||||
ctest_clear_call_state();
|
||||
}
|
31
tests/subsys/settings/src/settings_test_insert.c
Normal file
31
tests/subsys/settings/src/settings_test_insert.c
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015 Runtime Inc
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "settings_test.h"
|
||||
|
||||
void test_config_insert_x(int idx)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = settings_register(&c_test_handlers[idx]);
|
||||
zassert_true(rc == 0, "settings_register fail");
|
||||
}
|
||||
|
||||
void test_config_insert(void)
|
||||
{
|
||||
test_config_insert_x(0);
|
||||
}
|
||||
|
||||
void test_config_insert2(void)
|
||||
{
|
||||
test_config_insert_x(1);
|
||||
}
|
||||
|
||||
void test_config_insert3(void)
|
||||
{
|
||||
test_config_insert_x(2);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue