Skip to content

Commit

Permalink
lorawan: Add support for persisting state
Browse files Browse the repository at this point in the history
Add support for storing settings using the settings subsystem.

Signed-off-by: Andreas Sandberg <[email protected]>
  • Loading branch information
andysan committed May 14, 2020
1 parent 0860f1f commit 10db887
Show file tree
Hide file tree
Showing 5 changed files with 250 additions and 10 deletions.
24 changes: 23 additions & 1 deletion include/net/lorawan.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,13 @@ typedef void (*lorawan_recv_callback_t)(u8_t port, const void *data,
*/
int lorawan_config(const struct lorawan_config *config);

/**
* @brief Start the stack
*
* @return 0 if successful, negative errno code if failure
*/
int lorawan_start();

/**
* @brief Restore connection from persistent storage
*
Expand All @@ -132,9 +139,24 @@ int lorawan_config(const struct lorawan_config *config);
* re-establish a connection, if the function fails a full join may be
* required.
*
* If this function fails, the stack will have to be started using the
* lorawan_start() call.
*
* @return 0 if successful, negative errno code if failure
*/
int lorawan_resume();

/**
* @brief Stop the stack and store the persistent state
*
* If the stack has been built with support for the settings
* subsystem, enough state to restore a connection without a full join
* request will be stored to persistent storage. Call this function to
* stop the stack and store the state.
*
* @return 0 if successful, negative errno code if failure
*/
int lorawan_restore_connection();
int lorawan_suspend();

/**
* @brief Join the LoRaWAN network
Expand Down
1 change: 1 addition & 0 deletions subsys/lorawan/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ elseif(CONFIG_LORAMAC_REGION_RU864)
endif()

zephyr_library_sources_ifdef(CONFIG_LORAWAN lorawan.c)
zephyr_library_sources_ifdef(CONFIG_LORAWAN_SETTINGS state_settings.c)
9 changes: 9 additions & 0 deletions subsys/lorawan/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ config LORAWAN_MAX_LISTENERS
of port listeners. Configure this to the maximum number of ports you
expect to listen to in parallel. Does not include the wildcard
listener.

config LORAWAN_SETTINGS
bool "Enable support for storing the MAC state"
default n
depends on SETTINGS
help
Enable support for storing the MAC state to persistent storage using
the settings subsystem.

choice
prompt "LoRaWAN Region Selection"
default LORAMAC_REGION_IN865
Expand Down
37 changes: 28 additions & 9 deletions subsys/lorawan/lorawan.c
Original file line number Diff line number Diff line change
Expand Up @@ -354,13 +354,6 @@ int lorawan_config(const struct lorawan_config *config)
return 0;
}

int lorawan_restore_connection()
{
/* TODO: Unimplemented */
return -ENOENT;
}


static LoRaMacStatus_t lorawan_join_otaa(
const struct lorawan_join_config *join)
{
Expand Down Expand Up @@ -646,6 +639,34 @@ int lorawan_listen(u8_t port, lorawan_recv_callback_t cb)
return 0;
}

int lorawan_start()
{
LoRaMacStatus_t status;

status = LoRaMacStart();
if (status != LORAMAC_STATUS_OK) {
LOG_ERR("Failed to start the LoRaMAC stack: %s",
status2str(status));
return -EINVAL;
}

return 0;
}

#ifndef CONFIG_LORAWAN_SETTINGS

int lorawan_resume()
{
return -ENOENT;
}

int lorawan_suspend()
{
return -ENOENT;
}

#endif

static int lorawan_init(struct device *dev)
{
LoRaMacStatus_t status;
Expand All @@ -667,8 +688,6 @@ static int lorawan_init(struct device *dev)
return -EINVAL;
}

LoRaMacStart();

LOG_DBG("LoRaMAC Initialized");

return 0;
Expand Down
189 changes: 189 additions & 0 deletions subsys/lorawan/state_settings.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/*
* Copyright (c) 2020 Andreas Sandberg
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <net/lorawan.h>
#include <settings/settings.h>
#include <zephyr.h>

#include <LoRaMac.h>

#include <logging/log.h>
LOG_MODULE_REGISTER(lorawan_settings, CONFIG_LORAWAN_LOG_LEVEL);

#define CFG_BASE "lorawan/state"

struct lorawan_load_context {
unsigned int valid;
LoRaMacCtxs_t *mac;
};

enum {
VALID_CryptoNvmCtx = BIT(0),
VALID_SecureElementNvmCtx = BIT(1),
VALID_MacNvmCtx = BIT(2),
VALID_RegionNvmCtx = BIT(3),
VALID_CommandsNvmCtx = BIT(4),
VALID_ClassBNvmCtx = BIT(5),
VALID_ConfirmQueueNvmCtx = BIT(6),
};

#define VALID_REQUIRED (BIT(7) - 1)

#define FOR_EACH_CTX() \
do { \
CTX(CryptoNvmCtx); \
CTX(SecureElementNvmCtx); \
CTX(MacNvmCtx); \
CTX(RegionNvmCtx); \
CTX(CommandsNvmCtx); \
CTX(ClassBNvmCtx); \
CTX(ConfirmQueueNvmCtx); \
} while(0)


static int load_setting(void *tgt, size_t tgt_size,
const char *key, size_t len,
settings_read_cb read_cb, void *cb_arg)
{
if (len != tgt_size) {
LOG_ERR("Can't load '%s' state, size mismatch.",
log_strdup(key));
return -EINVAL;
}

if (!tgt) {
LOG_ERR("Can't load '%s' state, no target.",
log_strdup(key));
return -EINVAL;
}

if (read_cb(cb_arg, tgt, len) != len) {
LOG_ERR("Can't load '%s' state, short read.",
log_strdup(key));
return -EINVAL;
}

return 0;
}
static int setting_load_cb(const char *key, size_t len,
settings_read_cb read_cb,
void *cb_arg, void *param)
{
struct lorawan_load_context *ctx =
(struct lorawan_load_context *)param;
LOG_DBG("Loading '%s'...", log_strdup(key));

#define CTX(PFX) \
do { \
if (!strcmp(#PFX, key)) { \
int ret; \
ret = load_setting(ctx->mac->PFX, \
ctx->mac->PFX ## Size, \
key, len, read_cb, cb_arg); \
ctx->valid |= ret >= 0 ? VALID_ ## PFX : 0; \
return ret; \
} \
} while(0)

FOR_EACH_CTX();

#undef CTX

LOG_WRN("Unknown setting: %s", log_strdup(key));
return 0;
}

int lorawan_resume()
{
MibRequestConfirm_t req;
LoRaMacStatus_t status;
int ret;
struct lorawan_load_context ctx = {};

req.Type = MIB_NVM_CTXS;
status = LoRaMacMibGetRequestConfirm(&req);
if (status != LORAMAC_STATUS_OK) {
LOG_ERR("Failed to get LoRaMAC state: %d", status);
return -EINVAL;
}

ctx.mac = req.Param.Contexts;
ret = settings_load_subtree_direct(CFG_BASE, setting_load_cb,
&ctx);
if (ret < 0) {
LOG_ERR("Failed to load LoRaWAN state");
return ret;
}

if ((ctx.valid & VALID_REQUIRED) != VALID_REQUIRED) {
if (ctx.valid == 0) {
LOG_INF("No context stored");
return -EINVAL;
}
LOG_ERR("Failed to restore all required contexts");
return -EINVAL;
}

req.Type = MIB_NVM_CTXS;
status = LoRaMacMibSetRequestConfirm(&req);
if (status != LORAMAC_STATUS_OK) {
LOG_ERR("Failed to set LoRaMAC state: %d", status);
return -EINVAL;
}

status = LoRaMacStart( );
if (status != LORAMAC_STATUS_OK) {
LOG_ERR("Failed to start the stack: %d", status);
return -EINVAL;
}

return 0;
}

int lorawan_suspend()
{
LoRaMacStatus_t status;
MibRequestConfirm_t req;
LoRaMacCtxs_t *contexts;

status = LoRaMacStop();
if (status != LORAMAC_STATUS_OK) {
LOG_ERR("Failed to stop the LoRaMAC stack: %d", status);
return -EINVAL;
}

req.Type = MIB_NVM_CTXS;
status = LoRaMacMibGetRequestConfirm(&req);
if (status != LORAMAC_STATUS_OK) {
LOG_ERR("Failed to get LoRaMAC state: %d", status);
return -EINVAL;
}

contexts = req.Param.Contexts;

LOG_DBG("Storing contexts...");

#define CTX(PFX) \
do { \
int ret; \
if (contexts->PFX) { \
LOG_DBG("Saving " #PFX); \
ret = settings_save_one( \
CFG_BASE "/" #PFX, \
contexts->PFX, \
contexts->PFX ## Size); \
if (ret != 0) { \
return ret; \
} \
} \
} while(0)

FOR_EACH_CTX();

#undef CTX

return 0;
}

0 comments on commit 10db887

Please sign in to comment.