diff --git a/sys/configuration/Makefile.dep b/sys/configuration/Makefile.dep index 105eb71d975e..2cc7c22321aa 100644 --- a/sys/configuration/Makefile.dep +++ b/sys/configuration/Makefile.dep @@ -36,3 +36,7 @@ ifneq (,$(filter configuration_delta_encoding_decoding,$(USEMODULE))) USEMODULE += configuration_delta_encoding USEMODULE += configuration_delta_decoding endif + +ifneq (,$(filter configuration_key_subkey,$(USEMODULE))) + USEMODULE += configuration_handler_parent +endif diff --git a/sys/configuration/Makefile.include b/sys/configuration/Makefile.include index 29001793c591..6955d36fa11a 100644 --- a/sys/configuration/Makefile.include +++ b/sys/configuration/Makefile.include @@ -24,3 +24,6 @@ PSEUDOMODULES += configuration_delta_decoding # alias for configuration_delta_encoding and configuration_delta_decoding PSEUDOMODULES += configuration_delta_encoding_decoding + +# be able to export sub items which don't have a backend configured +PSEUDOMODULES += configuration_key_subkey diff --git a/sys/configuration/configuration.c b/sys/configuration/configuration.c index 70a37e64cc8b..b3dcfebe8b43 100644 --- a/sys/configuration/configuration.c +++ b/sys/configuration/configuration.c @@ -302,6 +302,9 @@ static int _configuration_prepare_sid(const conf_handler_t **next_handler, conf_ { key->offset = 0; key->sid_normal = key->sid; +#if IS_USED(MODULE_CONFIGURATION_KEY_SUBKEY) + key->subkey = NULL; +#endif #if IS_USED(MODULE_CONFIGURATION_STRINGS) if (key_buf) { memset(key_buf, 0, key_buf_len); @@ -616,12 +619,40 @@ static int _configuration_handler_export_internal(const conf_handler_t *root, if (_configuration_prepare_sid(&root, key, _KEY_BUF(key), _KEY_BUF_LEN(key)) < 0) { return -ENOENT; } + const conf_backend_t *be; +#if IS_USED(MODULE_CONFIGURATION_KEY_SUBKEY) + /* if export node has no backend, find first parent node which has a backend */ + conf_key_range_t subkey = { .sid_lower = key->sid, .sid_upper = key->sid }; + if (root->conf_flags.handles_array) { + if (key->sid == root->array_id->sid_lower) { + subkey.sid_upper += (root->array_id->sid_upper - root->array_id->sid_lower); + } + else { + subkey.sid_upper = key->sid + root->array_id->sid_stride - 1; + } + } + else if (!root->conf_flags.handles_primitive) { + subkey.sid_upper += (root->node_id->sid_upper - root->node_id->sid_lower); + } + be = *configuration_get_dst_backend(root); + while ((!be || !be->ops || !be->ops->be_store) && root && root->parent) { + be = *configuration_get_dst_backend((root = root->parent)); + } + if (!root || !be || !be->ops || !be->ops->be_store) { + return -ENOTSUP; + } + else { + key->sid = root->node_id->sid_lower; + _configuration_prepare_sid(&root, key, _KEY_BUF(key), _KEY_BUF_LEN(key)); + key->subkey = &subkey; + } +#endif int ret = 0; conf_path_iterator_t iter; conf_iterator_restore_t restore = _configuration_path_iterator_init(&iter, root, key, _KEY_BUF(key)); conf_handler_t *handler; while ((handler = _configuration_path_sid_iterator_next(&iter, key, &restore.sid))) { - const conf_backend_t *be = *configuration_get_dst_backend(handler); + be = *configuration_get_dst_backend(handler); if (!be || !be->ops || !be->ops->be_store) { continue; } @@ -874,6 +905,16 @@ int configuration_encode_internal(conf_path_iterator_t *iter, conf_iterator_rest } conf_handler_t *handler; while ((handler = _configuration_handler_encode_iterator_next(iter, key, &restore->sid))) { +#if IS_USED(MODULE_CONFIGURATION_KEY_SUBKEY) + if (key->subkey) { + if (key->sid == key->subkey->sid_lower) { + return -ENOBUFS; /* flush encoding buffer */ + } + if (key->sid > key->subkey->sid_upper) { + return 0; + } + } +#endif const conf_backend_t *be = *configuration_get_dst_backend(iter->root); /* do not export a subnode which has an own backend set because this would export the same data to two backends */ diff --git a/sys/configuration/default_handlers.c b/sys/configuration/default_handlers.c index 95e845ad4737..c1b6e3979e0e 100644 --- a/sys/configuration/default_handlers.c +++ b/sys/configuration/default_handlers.c @@ -189,6 +189,15 @@ int configuration_import_handler_default(const conf_handler_t *handler, return 0; } +static bool _check_subkey(const conf_key_buf_t *key) +{ + (void)key; +#if IS_USED(MODULE_CONFIGURATION_KEY_SUBKEY) + return !key->subkey || key->sid > key->subkey->sid_lower; +#endif + return true; +} + int configuration_export_handler_default(const conf_handler_t *handler, conf_key_buf_t *key) { @@ -220,9 +229,11 @@ int configuration_export_handler_default(const conf_handler_t *handler, if (err == -ENOBUFS) { /* need to flush */ sz = sizeof(_enc_buffer) - enc_size; - if ((err = be->ops->be_store(be, key, enc_data, &sz, total, &flg))) { - DEBUG("configuration: backend exporting key %s failed (%d)\n", - configuration_key_buf(key), err); + if (_check_subkey(&enc_key)) { + if ((err = be->ops->be_store(be, key, enc_data, &sz, total, &flg))) { + DEBUG("configuration: backend exporting key %s failed (%d)\n", + configuration_key_buf(key), err); + } } total += sz; enc_data = _enc_buffer; diff --git a/sys/include/configuration.h b/sys/include/configuration.h index c22a1500d2dc..3e3276367093 100644 --- a/sys/include/configuration.h +++ b/sys/include/configuration.h @@ -344,6 +344,14 @@ struct { \ unsigned offset; \ } +/** + * @brief A range of keys, used to select a subkey range to export + */ +typedef struct { + conf_sid_t sid_lower; /**< Lower SID of the range */ + conf_sid_t sid_upper; /**< Upper SID of the range */ +} conf_key_range_t; + /** * @brief Key buffer type with a static maximum key length * @@ -352,6 +360,7 @@ struct { \ #define CONF_KEY_T(len) \ struct { \ _CONF_KEY_BASE_T; \ + conf_key_range_t *subkey; \ _CONF_KEY_BUF_LEN \ _CONF_KEY_BUF(len) \ }