/* * Copyright (c) 2018 Nordic Semiconductor ASA * Copyright (c) 2015 Runtime Inc * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include "settings/settings.h" #include "settings_priv.h" #include #include LOG_MODULE_REGISTER(settings, CONFIG_SETTINGS_LOG_LEVEL); #if defined(CONFIG_SETTINGS_DYNAMIC_HANDLERS) sys_slist_t settings_handlers; #endif /* CONFIG_SETTINGS_DYNAMIC_HANDLERS */ K_MUTEX_DEFINE(settings_lock); void settings_store_init(void); void settings_init(void) { #if defined(CONFIG_SETTINGS_DYNAMIC_HANDLERS) sys_slist_init(&settings_handlers); #endif /* CONFIG_SETTINGS_DYNAMIC_HANDLERS */ settings_store_init(); } #if defined(CONFIG_SETTINGS_DYNAMIC_HANDLERS) int settings_register(struct settings_handler *handler) { int rc = 0; Z_STRUCT_SECTION_FOREACH(settings_handler_static, ch) { if (strcmp(handler->name, ch->name) == 0) { return -EEXIST; } } k_mutex_lock(&settings_lock, K_FOREVER); struct settings_handler *ch; SYS_SLIST_FOR_EACH_CONTAINER(&settings_handlers, ch, node) { if (strcmp(handler->name, ch->name) == 0) { rc = -EEXIST; goto end; } } sys_slist_append(&settings_handlers, &handler->node); end: k_mutex_unlock(&settings_lock); return rc; } #endif /* CONFIG_SETTINGS_DYNAMIC_HANDLERS */ int settings_name_steq(const char *name, const char *key, const char **next) { if (next) { *next = NULL; } if ((!name) || (!key)) { return 0; } /* name might come from flash directly, in flash the name would end * with '=' or '\0' depending how storage is done. Flash reading is * limited to what can be read */ while ((*key != '\0') && (*key == *name) && (*name != '\0') && (*name != SETTINGS_NAME_END)) { key++; name++; } if (*key != '\0') { return 0; } if (*name == SETTINGS_NAME_SEPARATOR) { if (next) { *next = name + 1; } return 1; } if ((*name == SETTINGS_NAME_END) || (*name == '\0')) { return 1; } return 0; } int settings_name_next(const char *name, const char **next) { int rc = 0; if (next) { *next = NULL; } if (!name) { return 0; } /* name might come from flash directly, in flash the name would end * with '=' or '\0' depending how storage is done. Flash reading is * limited to what can be read */ while ((*name != '\0') && (*name != SETTINGS_NAME_END) && (*name != SETTINGS_NAME_SEPARATOR)) { rc++; name++; } if (*name == SETTINGS_NAME_SEPARATOR) { if (next) { *next = name + 1; } return rc; } return rc; } struct settings_handler_static *settings_parse_and_lookup(const char *name, const char **next) { struct settings_handler_static *bestmatch; const char *tmpnext; bestmatch = NULL; if (next) { *next = NULL; } Z_STRUCT_SECTION_FOREACH(settings_handler_static, ch) { if (!settings_name_steq(name, ch->name, &tmpnext)) { continue; } if (!bestmatch) { bestmatch = ch; if (next) { *next = tmpnext; } continue; } if (settings_name_steq(ch->name, bestmatch->name, NULL)) { bestmatch = ch; if (next) { *next = tmpnext; } } } #if defined(CONFIG_SETTINGS_DYNAMIC_HANDLERS) struct settings_handler *ch; SYS_SLIST_FOR_EACH_CONTAINER(&settings_handlers, ch, node) { if (!settings_name_steq(name, ch->name, &tmpnext)) { continue; } if (!bestmatch) { bestmatch = (struct settings_handler_static *)ch; if (next) { *next = tmpnext; } continue; } if (settings_name_steq(ch->name, bestmatch->name, NULL)) { bestmatch = (struct settings_handler_static *)ch; if (next) { *next = tmpnext; } } } #endif /* CONFIG_SETTINGS_DYNAMIC_HANDLERS */ return bestmatch; } int settings_call_set_handler(const char *name, size_t len, settings_read_cb read_cb, void *read_cb_arg, const struct settings_load_arg *load_arg) { int rc; const char *name_key = name; if (load_arg && load_arg->subtree && !settings_name_steq(name, load_arg->subtree, &name_key)) { return 0; } if (load_arg && load_arg->cb) { rc = load_arg->cb(name_key, len, read_cb, read_cb_arg, load_arg->param); } else { struct settings_handler_static *ch; ch = settings_parse_and_lookup(name, &name_key); if (!ch) { return 0; } rc = ch->h_set(name_key, len, read_cb, read_cb_arg); if (rc != 0) { LOG_ERR("set-value failure. key: %s error(%d)", log_strdup(name), rc); /* Ignoring the error */ rc = 0; } else { LOG_DBG("set-value OK. key: %s", log_strdup(name)); } } return rc; } int settings_commit(void) { return settings_commit_subtree(NULL); } int settings_commit_subtree(const char *subtree) { int rc; int rc2; rc = 0; Z_STRUCT_SECTION_FOREACH(settings_handler_static, ch) { if (subtree && !settings_name_steq(ch->name, subtree, NULL)) { continue; } if (ch->h_commit) { rc2 = ch->h_commit(); if (!rc) { rc = rc2; } } } #if defined(CONFIG_SETTINGS_DYNAMIC_HANDLERS) struct settings_handler *ch; SYS_SLIST_FOR_EACH_CONTAINER(&settings_handlers, ch, node) { if (subtree && !settings_name_steq(ch->name, subtree, NULL)) { continue; } if (ch->h_commit) { rc2 = ch->h_commit(); if (!rc) { rc = rc2; } } } #endif /* CONFIG_SETTINGS_DYNAMIC_HANDLERS */ return rc; }