net: openthread: Use settings subsystem
OpenThread settings implementation built on top of Zepyhr settings submodule. With this solution, OpenThread settings are identified with keys of the following format: `ot/id/instance`, where `id` is assigned by OpenThread stack, and `instance` is a 32-bit random number, both in hex. The implementation makes use of `settings_load_subtree_direct` function to iterate over settings instances. This allows the OpenThread settings layer to be a fully transparent shim layer between OpenThread/Zephyr APIs. Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
This commit is contained in:
parent
b0bdf91e11
commit
b3a1ede830
|
@ -33,10 +33,13 @@ CONFIG_NET_CONFIG_PEER_IPV6_ADDR="fdde:ad00:beef::2"
|
|||
CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=6
|
||||
CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=8
|
||||
|
||||
# Other OpenThread dependencies (flash for OT persistent storage)
|
||||
# Other OpenThread dependencies
|
||||
CONFIG_FLASH=y
|
||||
CONFIG_FLASH_PAGE_LAYOUT=y
|
||||
CONFIG_FLASH_MAP=y
|
||||
CONFIG_MPU_ALLOW_FLASH_WRITE=y
|
||||
CONFIG_NVS=y
|
||||
CONFIG_SETTINGS=y
|
||||
|
||||
CONFIG_REBOOT=y
|
||||
|
||||
|
|
|
@ -33,10 +33,13 @@ CONFIG_NET_CONFIG_PEER_IPV6_ADDR="fdde:ad00:beef::1"
|
|||
CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=6
|
||||
CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=8
|
||||
|
||||
# Other OpenThread dependencies (flash for OT persistent storage)
|
||||
# Other OpenThread dependencies
|
||||
CONFIG_FLASH=y
|
||||
CONFIG_FLASH_PAGE_LAYOUT=y
|
||||
CONFIG_FLASH_MAP=y
|
||||
CONFIG_MPU_ALLOW_FLASH_WRITE=y
|
||||
CONFIG_NVS=y
|
||||
CONFIG_SETTINGS=y
|
||||
|
||||
CONFIG_REBOOT=y
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ menuconfig NET_L2_OPENTHREAD
|
|||
depends on FLASH_PAGE_LAYOUT
|
||||
depends on CPLUSPLUS
|
||||
depends on REBOOT
|
||||
depends on SETTINGS
|
||||
select OPENTHREAD_PLAT
|
||||
select MBEDTLS
|
||||
select MBEDTLS_ENABLE_HEAP
|
||||
|
|
|
@ -4,11 +4,11 @@ zephyr_library_named(openthread_platform)
|
|||
zephyr_library_sources(
|
||||
alarm.c
|
||||
entropy.c
|
||||
flash.c
|
||||
logging.c
|
||||
misc.c
|
||||
platform.c
|
||||
radio.c
|
||||
settings.c
|
||||
spi.c
|
||||
)
|
||||
|
||||
|
|
311
subsys/net/lib/openthread/platform/settings.c
Normal file
311
subsys/net/lib/openthread/platform/settings.c
Normal file
|
@ -0,0 +1,311 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <kernel.h>
|
||||
#include <logging/log.h>
|
||||
#include <settings/settings.h>
|
||||
|
||||
#include <openthread/platform/settings.h>
|
||||
|
||||
LOG_MODULE_REGISTER(net_otPlat_settings, CONFIG_OPENTHREAD_L2_LOG_LEVEL);
|
||||
|
||||
#define OT_SETTINGS_ROOT_KEY "ot"
|
||||
#define OT_SETTINGS_MAX_PATH_LEN 32
|
||||
|
||||
struct ot_setting_delete_ctx {
|
||||
/* Setting subtree to delete. */
|
||||
const char *subtree;
|
||||
|
||||
/* Current entry index, used to iterate over multiple setting
|
||||
* instances.
|
||||
*/
|
||||
int index;
|
||||
|
||||
/* Target index to delete. -1 to delete entire subtree. */
|
||||
int target_index;
|
||||
|
||||
/* Operation result. */
|
||||
int status;
|
||||
};
|
||||
|
||||
static int ot_setting_delete_cb(const char *key, size_t len,
|
||||
settings_read_cb read_cb, void *cb_arg,
|
||||
void *param)
|
||||
{
|
||||
int ret;
|
||||
char path[OT_SETTINGS_MAX_PATH_LEN];
|
||||
struct ot_setting_delete_ctx *ctx =
|
||||
(struct ot_setting_delete_ctx *)param;
|
||||
|
||||
ARG_UNUSED(len);
|
||||
ARG_UNUSED(read_cb);
|
||||
ARG_UNUSED(cb_arg);
|
||||
|
||||
if ((ctx->target_index != -1) && (ctx->target_index != ctx->index)) {
|
||||
ctx->index++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = snprintk(path, sizeof(path), "%s%s%s", ctx->subtree,
|
||||
key ? "/" : "", key ? key : "");
|
||||
__ASSERT(ret < sizeof(path), "Setting path buffer too small.");
|
||||
|
||||
LOG_DBG("Removing: %s", log_strdup(path));
|
||||
|
||||
ret = settings_delete(path);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to remove setting %s, ret %d", log_strdup(path),
|
||||
ret);
|
||||
}
|
||||
|
||||
ctx->status = 0;
|
||||
|
||||
if (ctx->target_index == ctx->index) {
|
||||
/* Break the loop on index match, otherwise it was -1
|
||||
* (delete all).
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ot_setting_delete_subtree(int key, int index)
|
||||
{
|
||||
int ret;
|
||||
char subtree[OT_SETTINGS_MAX_PATH_LEN];
|
||||
struct ot_setting_delete_ctx delete_ctx = {
|
||||
.subtree = subtree,
|
||||
.status = -ENOENT,
|
||||
.target_index = index
|
||||
};
|
||||
|
||||
if (key == -1) {
|
||||
ret = snprintk(subtree, sizeof(subtree), "%s",
|
||||
OT_SETTINGS_ROOT_KEY);
|
||||
} else {
|
||||
ret = snprintk(subtree, sizeof(subtree), "%s/%x",
|
||||
OT_SETTINGS_ROOT_KEY, key);
|
||||
}
|
||||
__ASSERT(ret < sizeof(subtree), "Setting path buffer too small.");
|
||||
|
||||
ret = settings_load_subtree_direct(subtree, ot_setting_delete_cb,
|
||||
&delete_ctx);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to delete OT subtree %s, index %d, ret %d",
|
||||
subtree, index, ret);
|
||||
}
|
||||
|
||||
return delete_ctx.status;
|
||||
}
|
||||
|
||||
static int ot_setting_exists_cb(const char *key, size_t len,
|
||||
settings_read_cb read_cb, void *cb_arg,
|
||||
void *param)
|
||||
{
|
||||
bool *exists = (bool *)param;
|
||||
|
||||
ARG_UNUSED(len);
|
||||
ARG_UNUSED(read_cb);
|
||||
ARG_UNUSED(cb_arg);
|
||||
ARG_UNUSED(key);
|
||||
|
||||
*exists = true;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool ot_setting_exists(const char *path)
|
||||
{
|
||||
bool exists = false;
|
||||
|
||||
(void)settings_load_subtree_direct(path, ot_setting_exists_cb, &exists);
|
||||
|
||||
return exists;
|
||||
}
|
||||
|
||||
struct ot_setting_read_ctx {
|
||||
/* Buffer for the setting. */
|
||||
u8_t *value;
|
||||
|
||||
/* Buffer length on input, setting length read on output. */
|
||||
u16_t *length;
|
||||
|
||||
/* Current entry index, used to iterate over multiple setting
|
||||
* instances.
|
||||
*/
|
||||
int index;
|
||||
|
||||
/* Target instnace to read. */
|
||||
int target_index;
|
||||
|
||||
/* Operation result. */
|
||||
int status;
|
||||
};
|
||||
|
||||
static int ot_setting_read_cb(const char *key, size_t len,
|
||||
settings_read_cb read_cb, void *cb_arg,
|
||||
void *param)
|
||||
{
|
||||
int ret;
|
||||
struct ot_setting_read_ctx *ctx = (struct ot_setting_read_ctx *)param;
|
||||
|
||||
ARG_UNUSED(len);
|
||||
ARG_UNUSED(read_cb);
|
||||
ARG_UNUSED(cb_arg);
|
||||
|
||||
if (ctx->target_index != ctx->index) {
|
||||
ctx->index++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Found setting, break the loop. */
|
||||
|
||||
if ((ctx->value == NULL) || (ctx->length == NULL)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (*(ctx->length) < len) {
|
||||
len = *(ctx->length);
|
||||
}
|
||||
|
||||
ret = read_cb(cb_arg, ctx->value, len);
|
||||
if (ret <= 0) {
|
||||
LOG_ERR("Failed to read the setting, ret: %d", ret);
|
||||
ctx->status = -EIO;
|
||||
return 1;
|
||||
}
|
||||
|
||||
out:
|
||||
if (ctx->length != NULL) {
|
||||
*(ctx->length) = len;
|
||||
}
|
||||
|
||||
ctx->status = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* OpenThread APIs */
|
||||
|
||||
void otPlatSettingsInit(otInstance *aInstance)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ARG_UNUSED(aInstance);
|
||||
|
||||
ret = settings_subsys_init();
|
||||
if (ret != 0) {
|
||||
LOG_ERR("settings_subsys_init failed (ret %d)", ret);
|
||||
}
|
||||
}
|
||||
|
||||
otError otPlatSettingsGet(otInstance *aInstance, uint16_t aKey, int aIndex,
|
||||
uint8_t *aValue, uint16_t *aValueLength)
|
||||
{
|
||||
int ret;
|
||||
char path[OT_SETTINGS_MAX_PATH_LEN];
|
||||
struct ot_setting_read_ctx read_ctx = {
|
||||
.value = aValue,
|
||||
.length = (u16_t *)aValueLength,
|
||||
.status = -ENOENT,
|
||||
.target_index = aIndex
|
||||
};
|
||||
|
||||
ARG_UNUSED(aInstance);
|
||||
|
||||
LOG_DBG("%s Entry aKey %u aIndex %d", __func__, aKey, aIndex);
|
||||
|
||||
ret = snprintk(path, sizeof(path), "%s/%x", OT_SETTINGS_ROOT_KEY, aKey);
|
||||
__ASSERT(ret < sizeof(path), "Setting path buffer too small.");
|
||||
|
||||
ret = settings_load_subtree_direct(path, ot_setting_read_cb, &read_ctx);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to load OT setting aKey %d, aIndex %d, ret %d",
|
||||
aKey, aIndex, ret);
|
||||
}
|
||||
|
||||
if (read_ctx.status != 0) {
|
||||
LOG_DBG("aKey %u aIndex %d not found", aKey, aIndex);
|
||||
return OT_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
otError otPlatSettingsSet(otInstance *aInstance, uint16_t aKey,
|
||||
const uint8_t *aValue, uint16_t aValueLength)
|
||||
{
|
||||
int ret;
|
||||
char path[OT_SETTINGS_MAX_PATH_LEN];
|
||||
|
||||
ARG_UNUSED(aInstance);
|
||||
|
||||
LOG_DBG("%s Entry aKey %u", __func__, aKey);
|
||||
|
||||
(void)ot_setting_delete_subtree(aKey, -1);
|
||||
|
||||
ret = snprintk(path, sizeof(path), "%s/%x/%08x", OT_SETTINGS_ROOT_KEY,
|
||||
aKey, sys_rand32_get());
|
||||
__ASSERT(ret < sizeof(path), "Setting path buffer too small.");
|
||||
|
||||
ret = settings_save_one(path, aValue, aValueLength);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to store setting %d, ret %d", aKey, ret);
|
||||
return OT_ERROR_NO_BUFS;
|
||||
}
|
||||
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
otError otPlatSettingsAdd(otInstance *aInstance, uint16_t aKey,
|
||||
const uint8_t *aValue, uint16_t aValueLength)
|
||||
{
|
||||
int ret;
|
||||
char path[OT_SETTINGS_MAX_PATH_LEN];
|
||||
|
||||
ARG_UNUSED(aInstance);
|
||||
|
||||
LOG_DBG("%s Entry aKey %u", __func__, aKey);
|
||||
|
||||
do {
|
||||
ret = snprintk(path, sizeof(path), "%s/%x/%08x",
|
||||
OT_SETTINGS_ROOT_KEY, aKey, sys_rand32_get());
|
||||
__ASSERT(ret < sizeof(path), "Setting path buffer too small.");
|
||||
} while (ot_setting_exists(path));
|
||||
|
||||
ret = settings_save_one(path, aValue, aValueLength);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to store setting %d, ret %d", aKey, ret);
|
||||
return OT_ERROR_NO_BUFS;
|
||||
}
|
||||
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
otError otPlatSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ARG_UNUSED(aInstance);
|
||||
|
||||
LOG_DBG("%s Entry aKey %u aIndex %d", __func__, aKey, aIndex);
|
||||
|
||||
ret = ot_setting_delete_subtree(aKey, aIndex);
|
||||
if (ret != 0) {
|
||||
LOG_DBG("Entry not found aKey %u aIndex %d", aKey, aIndex);
|
||||
return OT_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
void otPlatSettingsWipe(otInstance *aInstance)
|
||||
{
|
||||
ARG_UNUSED(aInstance);
|
||||
|
||||
(void)ot_setting_delete_subtree(-1, -1);
|
||||
}
|
2
west.yml
2
west.yml
|
@ -95,7 +95,7 @@ manifest:
|
|||
revision: 29e516ec585b1a909af2b5f1c60d83e7d4d563e3
|
||||
path: modules/lib/loramac-node
|
||||
- name: openthread
|
||||
revision: 05aaccc6e0db0fe17ac4beed2a2aacc9a9af167c
|
||||
revision: 3c6191eb4e8ca44b5f4eeaa696837bce14e83c69
|
||||
path: modules/lib/openthread
|
||||
- name: segger
|
||||
revision: 6fcf61606d6012d2c44129edc033f59331e268bc
|
||||
|
|
Loading…
Reference in a new issue