Skip to content

Commit

Permalink
Merge pull request #38 from IRNAS/release/v1.4.0
Browse files Browse the repository at this point in the history
Release v1.4.0
  • Loading branch information
TjazVracko authored Apr 5, 2023
2 parents 72d9668 + 3f4e53b commit 59f80c8
Show file tree
Hide file tree
Showing 17 changed files with 993 additions and 10 deletions.
13 changes: 12 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)

## [Unreleased]

## [1.4.0] - 2023-04-05

### Added

- Flag to indicate if a setting was recently changed.
- Functions to clear the changed recently flag.
- Functions for iterating over settings.
- Submodule for getting and setting user settings via JSON.

## [1.3.4] - 2023-02-16

### Fixed
Expand Down Expand Up @@ -75,7 +84,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- Basic sample.
- Callbacks sample.

[Unreleased]: https://github.com/IRNAS/irnas-usersettings-lib/compare/v1.3.4...HEAD
[Unreleased]: https://github.com/IRNAS/irnas-usersettings-lib/compare/v1.4.0...HEAD

[1.4.0]: https://github.com/IRNAS/irnas-usersettings-lib/compare/v1.3.4...v1.4.0

[1.3.4]: https://github.com/IRNAS/irnas-usersettings-lib/compare/v1.3.3...v1.3.4

Expand Down
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,36 @@ to check if a setting has a valid value by using `user_settings_is_set_with_*()`
To check whether a setting has a default value, `user_settings_has_default_with_*()` can be used.
For this reason, it is suggested that each setting should have a value set (via its default value or directly) during application initialization, so that later code can assume all settings have valid values and can be read directly.

When you change the value of the setting, flag `has_changed_recently` is set. To clear this flag call one of the functions: `user_settings_clear_changed_with_key(char *key)`, `user_settings_clear_changed_with_id(uint16_t id)` or `user_settings_clear_changed(void)`.

## Iterators

You can iterate trough existing settings using iterator functions. Call `user_settings_iter_start()` to reset iteration counters, then call `user_settings_iter_next(key, &id)` repeatedly to iterate trough all settings. When function returns `false` you have reached the end.

You can also iterate only trough recently set settings, i.e. with set flag `has_changed_recently`. Call `user_settings_iter_start()` to reset iteration counters, then call `user_settings_iter_next_changed(key, &id)` repeatedly to iterate trough all settings. When function returns `false` you have reached the end.

## JSON support

One can set multiple settings with JSON structure and export exiting settings, or settings changed recently in JSON structure.

Enable JSON support by setting `CONFIG_USER_SETTINGS_JSON=y`. You will need cJSON support enabled as well. `CONFIG_CJSON_LIB=y`.

To set multiple settings using JSON, create `cJSON *settings` object in the format:
```
{
"t1": true,
"t2": 1000,
"t3": "00000000",
"t4": "banana"
}
```

and pass it to the set `function user_settings_set_from_json(settings)`. Function will set all settings with existing key an correct value type.

To extract settings in JSON format call `user_settings_get_all_json(&settings)` and pass pointer to `cJSON *settings` object. Keep in mind you are responsible to delete the object.

To extract only recently changed settings, i.e. with set flag `has_changed_recently` in JSON format call `user_settings_get_changed_json(&settings)` and pass pointer to `cJSON *settings` object. Keep in mind you are responsible to delete the object. Function will not reset the flag.

## Bluetooth Service

A user setting bluetooth service can be enabled by setting `CONFIG_USER_SETTINGS_BT_SERVICE=y`. See the [bluetooth service sample](./samples/bluetooth_service) for details.
Expand Down
5 changes: 5 additions & 0 deletions library/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ config USER_SETTINGS_SHELL
depends on SHELL
default false

config USER_SETTINGS_JSON
bool "Enable JSON settings encode / decode support"
depends on CJSON_LIB
default false

module = USER_SETTINGS
module-str = User settings
source "subsys/logging/Kconfig.template.log_config"
Expand Down
57 changes: 57 additions & 0 deletions library/include/user_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,63 @@ enum user_setting_type user_settings_get_type_with_key(char *key);
*/
enum user_setting_type user_settings_get_type_with_id(uint16_t id);

/**
* @brief Start iteration over all user settings
*
* Call this before getting elements with user_settings_list_iter_next.
* This will reset an in-progress iteration.
*/
void user_settings_iter_start(void);

/**
* @brief Get next settings ID and KEY in the iteration
*
* @param[out] key The key of the next settings.
* @param[out] id The ID of the next settings.
*
* @return True if we have next setting, false if there are no more.
*/
bool user_settings_iter_next(char **key, uint16_t *id);

/**
* @brief Get next settings ID and KEY in the iteration
*
* Only returns settings wil a set changed flag.
*
* @param[out] key The key of the next changed settings.
* @param[out] id The ID of the next changed settings.
*
* @return True if we have next setting, false if there are no more.
*/
bool user_settings_iter_next_changed(char **key, uint16_t *id);

/**
* @brief Clear "has_changed_recently" flag
*
* This will assert if no setting with the provided key exists.
* If the key input for this function is unknown to the application (i.e. parsed from user), then
* it should first be checked with user_settings_exists_with_key().
*
* @param[in] key A valid user setting key
*/
void user_settings_clear_changed_with_key(char *key);

/**
* @brief Clear "has_changed_recently" flag
*
* This will assert if no setting with the provided id exists.
* If the ID input for this function is unknown to the application (i.e. parsed from user), then
* it should first be checked with user_settings_exists_with_id().
*
* @param[in] id A valid user setting id
*/
void user_settings_clear_changed_with_id(uint16_t id);

/**
* @brief Clears changed flag on all settings
*/
void user_settings_clear_changed(void);

#ifdef __cplusplus
}
#endif
Expand Down
70 changes: 70 additions & 0 deletions library/include/user_settings_json.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/** @file user_settings_json.h
*
* @brief JSON encode/decode module
*
* @par
* COPYRIGHT NOTICE: (c) 2023 Irnas. All rights reserved.
*/

#ifndef USER_SETTINGS_JSON_H
#define USER_SETTINGS_JSON_H

#ifdef __cplusplus
extern "C" {
#endif

#include <zephyr/kernel.h>
#include <user_settings_types.h>
/* JSON parser */
#include <cJSON.h>
#include <cJSON_os.h>

/**
* @brief Set settings from a flat json structure
*
* Does not modify the passed in JSON.
*
* Expected structure looks like:
* {
* "s_key_1": <value>,
* "s_key_2": <value>,
* // ...
* }
*
* @param[in] settings The settings to apply
*
* @retval 0 On success
* @retval -ENOMEM If the new value is larger than the max_size
* @retval -EIO if the setting value could not be stored to NVS
* @retval -EINVAL if the invalid json structure
*/
int user_settings_set_from_json(const cJSON *settings);

/**
* @brief Create a JSON with containing only settings marked changed.
* Function will not clear changed flag.
*
* The caller is expected to free the created cJSON structure.
*
* @param[out] settings Created json
* @retval 0 On success
* @retval -ENOMEM If we failed to allocate JSON struct
*/
int user_settings_get_changed_json(cJSON **settings);

/**
* @brief Create a JSON with containing all settings.
*
* The caller is expected to free the created cJSON structure.
*
* @param[out] settings Created json
* @retval 0 On success
* @retval -ENOMEM If we failed to allocate JSON struct
*/
int user_settings_get_all_json(cJSON **settings);

#ifdef __cplusplus
}
#endif

#endif // USER_SETTINGS_JSON_H
1 change: 1 addition & 0 deletions library/user_settings/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ zephyr_library_include_directories(.)
zephyr_library_sources(${CMAKE_CURRENT_SOURCE_DIR}/user_settings_list.c)
zephyr_library_sources(${CMAKE_CURRENT_SOURCE_DIR}/user_settings.c)
zephyr_library_sources_ifdef(CONFIG_USER_SETTINGS_SHELL ${CMAKE_CURRENT_SOURCE_DIR}/user_settings_shell.c)
zephyr_library_sources_ifdef(CONFIG_USER_SETTINGS_JSON ${CMAKE_CURRENT_SOURCE_DIR}/user_settings_json.c)
70 changes: 70 additions & 0 deletions library/user_settings/user_settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,9 @@ static int prv_user_settings_set(struct user_setting *s, void *data, size_t len)
return -EIO;
}

/* Modify has changed flag */
s->has_changed_recently = 1;

return 0;
}

Expand Down Expand Up @@ -593,3 +596,70 @@ enum user_setting_type user_settings_get_type_with_id(uint16_t id)

return s->type;
}

void user_settings_iter_start(void)
{
user_settings_list_iter_start();
}

bool user_settings_iter_next(char **key, uint16_t *id)
{
struct user_setting *setting;
if ((setting = user_settings_list_iter_next()) != NULL) {
*key = setting->key;
*id = setting->id;
return true;
} else {
return false;
}
}

bool user_settings_iter_next_changed(char **key, uint16_t *id)
{
bool prv_has_changed = 0;
struct user_setting *setting;
while (!prv_has_changed) {
if ((setting = user_settings_list_iter_next()) != NULL) {
prv_has_changed = setting->has_changed_recently;
if (prv_has_changed) {
*key = setting->key;
*id = setting->id;
}
} else {
return false;
}
}

return true;
}

void user_settings_clear_changed_with_key(char *key)
{
__ASSERT(prv_is_loaded, LOAD_ASSERT_TEXT);

struct user_setting *s = user_settings_list_get_by_key(key);
__ASSERT(s, "Key does not exists: %s", key);

s->has_changed_recently = 0;
}

void user_settings_clear_changed_with_id(uint16_t id)
{
__ASSERT(prv_is_loaded, LOAD_ASSERT_TEXT);

struct user_setting *s = user_settings_list_get_by_id(id);
__ASSERT(s, "Id does not exists: %d", id);

s->has_changed_recently = 0;
}

void user_settings_clear_changed(void)
{
__ASSERT(prv_is_loaded, LOAD_ASSERT_TEXT);

user_settings_list_iter_start();
struct user_setting *setting;
while ((setting = user_settings_list_iter_next()) != NULL) {
setting->has_changed_recently = 0;
}
}
Loading

0 comments on commit 59f80c8

Please sign in to comment.