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:
Robert Lubos 2019-10-10 09:26:09 +02:00 committed by Maureen Helm
parent b0bdf91e11
commit b3a1ede830
6 changed files with 322 additions and 4 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
)

View 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);
}

View file

@ -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