Skip to content

Commit 4616a8a

Browse files
nordicjmnashif
authored andcommitted
settings: Add function for saving (unchanged) single item/subtree
Adds a function that allows saving of a single setting item without changing the value, or saving a subtree of settings, to the storage backend Signed-off-by: Jamie McCrae <[email protected]>
1 parent f1b3ee5 commit 4616a8a

File tree

3 files changed

+109
-0
lines changed

3 files changed

+109
-0
lines changed

include/zephyr/settings/settings.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,24 @@ int settings_commit(void);
405405
*/
406406
int settings_commit_subtree(const char *subtree);
407407

408+
#if defined(CONFIG_SETTINGS_SAVE_SINGLE_SUBTREE_WITHOUT_MODIFICATION) || defined(__DOXYGEN__)
409+
/**
410+
* Save a single currently running serialized value to persisted storage (if it has changed
411+
* value) by reading the value using the get function, or save a whole subtree's currently
412+
* running serialized items out.
413+
*
414+
* @param name Name/key of the settings item or subtree.
415+
* @param save_if_subtree Set to true if the item should be save and it is a subtree.
416+
* @param save_if_single_setting Set to true if the item should be save and it is a single
417+
* setting.
418+
*
419+
* @return 0 on success, non-zero on failure.
420+
*/
421+
int settings_save_subtree_or_single_without_modification(const char *name,
422+
bool save_if_subtree,
423+
bool save_if_single_setting);
424+
#endif
425+
408426
/**
409427
* @} settings
410428
*/

subsys/settings/Kconfig

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,24 @@ config SETTINGS_DYNAMIC_HANDLERS
2727
help
2828
Enables the use of dynamic settings handlers
2929

30+
config SETTINGS_SAVE_SINGLE_SUBTREE_WITHOUT_MODIFICATION
31+
bool "Save single or subtree (without modification) function"
32+
help
33+
Includes the `settings_save_subtree_or_single_without_modification()` function which
34+
allows saving an item that might be a subtree or a single setting, without changing the
35+
value. To save a single setting, the setting must support reading and writing of it
36+
using the `h_get()` function pointer and must support reading it into a large buffer
37+
size.
38+
39+
config SETTINGS_SAVE_SINGLE_SUBTREE_WITHOUT_MODIFICATION_VALUE_SIZE
40+
int "Save single or subtree (without modification) maximum value size"
41+
default 65
42+
depends on SETTINGS_SAVE_SINGLE_SUBTREE_WITHOUT_MODIFICATION
43+
help
44+
The maximum size of a single setting that can be saved using the
45+
`settings_save_subtree_or_single_without_modification()` function - note that this will
46+
use stack memory.
47+
3048
# Hidden option to enable encoding length into settings entry
3149
config SETTINGS_ENCODE_LEN
3250
bool

subsys/settings/src/settings_store.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,3 +303,76 @@ void settings_store_init(void)
303303
{
304304
sys_slist_init(&settings_load_srcs);
305305
}
306+
307+
#ifdef CONFIG_SETTINGS_SAVE_SINGLE_SUBTREE_WITHOUT_MODIFICATION
308+
int settings_save_subtree_or_single_without_modification(const char *name,
309+
bool save_if_subtree,
310+
bool save_if_single_setting)
311+
{
312+
int rc;
313+
int value_size;
314+
uint8_t read_buffer[CONFIG_SETTINGS_SAVE_SINGLE_SUBTREE_WITHOUT_MODIFICATION_VALUE_SIZE];
315+
const char *next = NULL;
316+
struct settings_handler_static *handler;
317+
318+
if (save_if_subtree == false && save_if_single_setting == false) {
319+
return -EINVAL;
320+
}
321+
322+
handler = settings_parse_and_lookup(name, &next);
323+
324+
if (next == NULL) {
325+
/* This is a subtree of settings, bail if user did not request saving it. */
326+
if (save_if_subtree == false) {
327+
return -EPERM;
328+
}
329+
330+
return settings_save_subtree(name);
331+
} else if (save_if_single_setting == false) {
332+
return -EPERM;
333+
}
334+
335+
/*
336+
* For single settings, we need to be able to retrieve the value of the setting, if this
337+
* is not supported then single saving cannot be done with this key.
338+
*/
339+
if (handler->h_get == NULL) {
340+
return -ENOSYS;
341+
}
342+
343+
settings_lock_take();
344+
345+
/*
346+
* Settings does not support getting the size of a setting, therefore attempt to read the
347+
* full buffer size, if that returns that amount of data then we must abort as we cannot
348+
* get the full data with this buffer and would save a truncated value.
349+
*/
350+
value_size = handler->h_get(next, read_buffer, sizeof(read_buffer));
351+
352+
if (value_size < 0) {
353+
rc = value_size;
354+
goto exit;
355+
} else if (value_size == sizeof(read_buffer)) {
356+
rc = -EDOM;
357+
goto exit;
358+
}
359+
360+
rc = settings_save_one(name, read_buffer, value_size);
361+
362+
/*
363+
* Caller just needs to know that it was successful, not the length of the data that was
364+
* saved.
365+
*/
366+
if (rc >= 0) {
367+
rc = 0;
368+
} else if (rc < 0) {
369+
LOG_ERR("Saving single setting '%s' of length %d failed: %d", name, value_size,
370+
rc);
371+
}
372+
373+
exit:
374+
settings_lock_release();
375+
376+
return rc;
377+
}
378+
#endif /* CONFIG_SETTINGS_SAVE_SINGLE_SUBTREE_WITHOUT_MODIFICATION */

0 commit comments

Comments
 (0)