-
Notifications
You must be signed in to change notification settings - Fork 8k
Settings reworked to const char processing #16711
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,7 +26,8 @@ extern "C" { | |
#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 "/" | ||
#define SETTINGS_NAME_SEPARATOR '/' | ||
#define SETTINGS_NAME_END '=' | ||
|
||
/* pleace for settings additions: | ||
* up to 7 separators, '=', '\0' | ||
|
@@ -47,26 +48,27 @@ struct settings_handler { | |
char *name; | ||
/**< Name of subtree. */ | ||
|
||
int (*h_get)(int argc, char **argv, char *val, int val_len_max); | ||
int (*h_get)(const char *key, char *val, int val_len_max); | ||
/**< Get values handler of settings items identified by keyword names. | ||
* | ||
* Parameters: | ||
* - argc - count of item in argv. | ||
* - argv - array of pointers to keyword names. | ||
* - val - buffer for a value. | ||
* - val_len_max - size of that buffer. | ||
* - key[in] the name with skipped part that was used as name in | ||
* handler registration | ||
* - val[out] buffer to receive value. | ||
* - val_len_max[in] size of that buffer. | ||
*/ | ||
|
||
int (*h_set)(int argc, char **argv, size_t len, | ||
settings_read_cb read_cb, void *cb_arg); | ||
int (*h_set)(const char *key, size_t len, settings_read_cb read_cb, | ||
void *cb_arg); | ||
/**< Set value handler of settings items identified by keyword names. | ||
* | ||
* Parameters: | ||
* - argc - count of item in argv. | ||
* - argv - array of pointers to keyword names. | ||
* - len - the size of the data found in the backend. | ||
* - read_cb - function provided to read the data from the backend. | ||
* - cb_arg - arguments for the read function provided by the backend. | ||
* - key[in] the name with skipped part that was used as name in | ||
* handler registration | ||
* - len[in] the size of the data found in the backend. | ||
* - read_cb[in] function provided to read the data from the backend. | ||
* - cb_arg[in] arguments for the read function provided by the | ||
* backend. | ||
*/ | ||
|
||
int (*h_commit)(void); | ||
|
@@ -121,8 +123,18 @@ int settings_register(struct settings_handler *cf); | |
int settings_load(void); | ||
|
||
/** | ||
* Save currently running serialized items. All serialized items which are different | ||
* from currently persisted values will be saved. | ||
* Load limited set of serialized items from registered persistence sources. | ||
* Handlers for serialized item subtrees registered earlier will be called for | ||
* encountered values that belong to the subtree. | ||
* | ||
* @param[in] subtree name of the subtree to be loaded. | ||
* @return 0 on success, non-zero on failure. | ||
*/ | ||
int settings_load_subtree(const char *subtree); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this something I could call on bt_init? What if the application is also calling settings_load by itself then? Would that cause the handler to be called once again? I guess we should clearly state on the documentation this sort of behavior. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes you could, the mutex would not stop the handler to be called again. For the documentation it should be clear: But maybe your are asking something else: I have a handler that I want to call myself, and nobody else, how do I do this ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My question was that if this would cause the handler to be called multiple times, one by load and another by load_subtree that may cause extra loading from no reason, I guess the idea is that each subsystem calls load_substree and load would take care of the remaining settings which most likely are just app specific, this way the more natural sequence would be subsystem blah settings_load_subtree("blah") (marked it as loaded)... -> app settings_load() There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oops, sorry forgot to answer the question: Yes, it would be called several times. There is no requirement on how to use it, the idea is that it would be needed to call a settings_load_subtree() as a result of a connection request so that only limited RAM would be occupied for storing this information. Your natural sequence could also be done: using option 2 from above settings_load_handler(&blah_handler): registers blah, loads blah elements, unregister blah (this is the marked as loaded). Do this for each subsystem and finally call settings_load for all app related stuff. Should I add a settings_load_handler() like defined above ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It depends on how we wish the system to be designed. I believe that the full settings load should be called only once - on system start. And it should be left to the module implementation to decide how we wish to tread incoming data (for example, any CCCD data may be ignored if we do not have an active connection already). Then when the system works, we can call settings_load_subtree (or load_selected from #16609) whenever needed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we even need a settings_load()? Couldn't each module just call settings_load_subtree() when appropriate on init (or on demand)? The app can always have its own subtree (fx. "app/") and use settings_load_subtree(). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @fnde-ot, completely agree, we could remove the settings_load() completely. Combining this with the remark from @Vudentz in #16676 would open a lot of opportunities. There of course would be
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And you cannot agree with my proposal as it requires too much of rework inside modules. I ask you not to go that direction here - separate this idea and offer it in another PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Laczen @rakons, Sounds to me more like a backend problem. On-demand or subtree loading should not require significant changes to existing modules, appart from adding calls to settings_load_subtree(...) in the appropriate init functions. The multiple-read would not be an issue if the backend properly separated settings from different modules (not a flash expert, but maybe using multiple files or grouping settings from a single module together and reading from a specific offset). But then again, this could require to rethink the way existing backends work, which would be out of scope for this PR. We can still remove settings_load from this PR and rework the backends in another one. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @rakons, I cannot agree with your proposal because: I have accepted doing the rework inside the modules by not introducing the setiings_name_separate(), but there is a very specific reason for this: reducing RAM usage in the case where a dynamic name would be used at the top of some tree where most entries under this would have a fixed part (e.g. This however has nothing to do with the discussion above: the proposal has triggered other (new) ideas to make the proposal even simpler (remove registering of handlers and looking up handlers) and it would be a pity not to take these ideas into account. |
||
|
||
/** | ||
* 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. | ||
*/ | ||
|
@@ -161,6 +173,16 @@ int settings_delete(const char *name); | |
*/ | ||
int settings_commit(void); | ||
|
||
/** | ||
* Call commit for settings handler that belong to subtree. | ||
* This should apply all settings which has been set, but not applied yet. | ||
* | ||
* @param[in] subtree name of the subtree to be committed. | ||
* | ||
* @return 0 on success, non-zero on failure. | ||
*/ | ||
int settings_commit_subtree(const char *subtree); | ||
|
||
/** | ||
* @} settings | ||
*/ | ||
|
@@ -191,8 +213,9 @@ struct settings_store { | |
* Destinations are registered using a call to @ref settings_dst_register. | ||
*/ | ||
struct settings_store_itf { | ||
int (*csi_load)(struct settings_store *cs); | ||
/**< Loads all values from storage. | ||
int (*csi_load)(struct settings_store *cs, const char *subtree); | ||
/**< Loads values from storage limited to subtree defined by subtree. If | ||
* subtree = NULL loads all values. | ||
* | ||
* Parameters: | ||
* - cs - Corresponding backend handler node | ||
|
@@ -248,16 +271,53 @@ void settings_dst_register(struct settings_store *cs); | |
/** | ||
* Parses a key to an array of elements and locate corresponding module handler. | ||
* | ||
* @param name Key in string format | ||
* @param name_argc Parsed number of elements. | ||
* @param name_argv Parsed array of elements. | ||
* @param[in] name in string format | ||
* @param[out] next remaining of name after matched handler | ||
* | ||
* @return settings_handler node on success, NULL on failure. | ||
*/ | ||
struct settings_handler *settings_parse_and_lookup(char *name, int *name_argc, | ||
char *name_argv[]); | ||
struct settings_handler *settings_parse_and_lookup(const char *name, | ||
const char **next); | ||
|
||
|
||
/* | ||
* API for const name processing | ||
*/ | ||
|
||
/** | ||
* Compares the start of name with a key | ||
* | ||
* @param[in] name in string format | ||
* @param[in] key comparison string | ||
* @param[out] next pointer to remaining of name, when the remaining part | ||
* starts with a separator the separator is removed from next | ||
* | ||
* Some examples: | ||
* settings_name_steq("bt/btmesh/iv", "b", &next) returns 1, next="t/btmesh/iv" | ||
* settings_name_steq("bt/btmesh/iv", "bt", &next) returns 1, next="btmesh/iv" | ||
* settings_name_steq("bt/btmesh/iv", "bt/", &next) returns 0, next=NULL | ||
* settings_name_steq("bt/btmesh/iv", "bta", &next) returns 0, next=NULL | ||
* | ||
* REMARK: This routine could be simplified if the settings_handler names | ||
* would include a separator at the end. | ||
* | ||
* @return 0: no match | ||
* 1: match, next can be used to check if match is full | ||
*/ | ||
int settings_name_steq(const char *name, const char *key, const char **next); | ||
|
||
/** | ||
* determine the number of characters before the first separator | ||
* | ||
* @param[in] name in string format | ||
* @param[out] next pointer to remaining of name (excluding separator) | ||
* | ||
* @return index of the first separator, in case no separator was found this | ||
* is the size of name | ||
* | ||
*/ | ||
int settings_name_next(const char *name, const char **next); | ||
|
||
/* | ||
* API for runtime settings | ||
*/ | ||
|
Uh oh!
There was an error while loading. Please reload this page.