zephyr/subsys/lorawan/nvm/lorawan_nvm_settings.c

185 lines
4.6 KiB
C

/*
* Copyright (c) 2022 Intellinium <giuliano.franchetto@intellinium.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <LoRaMac.h>
#include <zephyr/kernel.h>
#include <zephyr/settings/settings.h>
#include "lorawan_nvm.h"
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(lorawan_nvm, CONFIG_LORAWAN_LOG_LEVEL);
#define LORAWAN_SETTINGS_BASE "lorawan/nvm"
struct lorawan_nvm_setting_descr {
const char *name;
const char *setting_name;
size_t size;
off_t offset;
uint16_t flag;
};
#define NVM_SETTING_DESCR(_flag, _member) \
{ \
.flag = _flag, \
.name = STRINGIFY(_member), \
.setting_name = \
LORAWAN_SETTINGS_BASE "/" STRINGIFY(_member), \
.offset = offsetof(LoRaMacNvmData_t, _member), \
.size = sizeof(((LoRaMacNvmData_t *)0)->_member), \
}
static const struct lorawan_nvm_setting_descr nvm_setting_descriptors[] = {
NVM_SETTING_DESCR(LORAMAC_NVM_NOTIFY_FLAG_CRYPTO, Crypto),
NVM_SETTING_DESCR(LORAMAC_NVM_NOTIFY_FLAG_MAC_GROUP1, MacGroup1),
NVM_SETTING_DESCR(LORAMAC_NVM_NOTIFY_FLAG_MAC_GROUP2, MacGroup2),
NVM_SETTING_DESCR(LORAMAC_NVM_NOTIFY_FLAG_SECURE_ELEMENT, SecureElement),
NVM_SETTING_DESCR(LORAMAC_NVM_NOTIFY_FLAG_REGION_GROUP1, RegionGroup1),
NVM_SETTING_DESCR(LORAMAC_NVM_NOTIFY_FLAG_REGION_GROUP2, RegionGroup2),
NVM_SETTING_DESCR(LORAMAC_NVM_NOTIFY_FLAG_CLASS_B, ClassB),
};
static void lorawan_nvm_save_settings(uint16_t nvm_notify_flag)
{
MibRequestConfirm_t mib_req;
LOG_DBG("Saving LoRaWAN settings");
/* Retrieve the actual context */
mib_req.Type = MIB_NVM_CTXS;
if (LoRaMacMibGetRequestConfirm(&mib_req) != LORAMAC_STATUS_OK) {
LOG_ERR("Could not get NVM context");
return;
}
LoRaMacNvmData_t *nvm = mib_req.Param.Contexts;
LOG_DBG("Crypto version: %"PRIu32", DevNonce: %d, JoinNonce: %"PRIu32,
mib_req.Param.Contexts->Crypto.LrWanVersion.Value,
mib_req.Param.Contexts->Crypto.DevNonce,
mib_req.Param.Contexts->Crypto.JoinNonce);
for (uint32_t i = 0; i < ARRAY_SIZE(nvm_setting_descriptors); i++) {
const struct lorawan_nvm_setting_descr *descr =
&nvm_setting_descriptors[i];
if ((nvm_notify_flag & descr->flag) == descr->flag) {
LOG_DBG("Saving configuration %s", descr->setting_name);
int err = settings_save_one(descr->setting_name,
(char *)nvm + descr->offset,
descr->size);
if (err) {
LOG_ERR("Could not save settings %s, error %d",
descr->name, err);
}
}
}
}
void lorawan_nvm_data_mgmt_event(uint16_t flags)
{
if (flags != LORAMAC_NVM_NOTIFY_FLAG_NONE) {
lorawan_nvm_save_settings(flags);
}
}
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.",
key);
return -EINVAL;
}
if (!tgt) {
LOG_ERR("Can't load '%s' state, no target.",
key);
return -EINVAL;
}
if (read_cb(cb_arg, tgt, len) != len) {
LOG_ERR("Can't load '%s' state, short read.",
key);
return -EINVAL;
}
return 0;
}
static int on_setting_loaded(const char *key, size_t len,
settings_read_cb read_cb,
void *cb_arg, void *param)
{
int err;
LoRaMacNvmData_t *nvm = param;
LOG_DBG("Key: %s", key);
for (uint32_t i = 0; i < ARRAY_SIZE(nvm_setting_descriptors); i++) {
const struct lorawan_nvm_setting_descr *descr =
&nvm_setting_descriptors[i];
if (strcmp(descr->name, key) == 0) {
err = load_setting((char *)nvm + descr->offset,
descr->size, key, len, read_cb, cb_arg);
if (err) {
LOG_ERR("Could not read setting %s", descr->name);
}
return err;
}
}
LOG_WRN("Unknown LoRaWAN setting: %s", key);
return 0;
}
int lorawan_nvm_data_restore(void)
{
int err;
LoRaMacStatus_t status;
MibRequestConfirm_t mib_req;
LOG_DBG("Restoring LoRaWAN settings");
/* Retrieve the actual context */
mib_req.Type = MIB_NVM_CTXS;
if (LoRaMacMibGetRequestConfirm(&mib_req) != LORAMAC_STATUS_OK) {
LOG_ERR("Could not get NVM context");
return -EINVAL;
}
err = settings_load_subtree_direct(LORAWAN_SETTINGS_BASE,
on_setting_loaded,
mib_req.Param.Contexts);
if (err) {
LOG_ERR("Could not load LoRaWAN settings, error %d", err);
return err;
}
LOG_DBG("Crypto version: %"PRIu32", DevNonce: %d, JoinNonce: %"PRIu32,
mib_req.Param.Contexts->Crypto.LrWanVersion.Value,
mib_req.Param.Contexts->Crypto.DevNonce,
mib_req.Param.Contexts->Crypto.JoinNonce);
mib_req.Type = MIB_NVM_CTXS;
status = LoRaMacMibSetRequestConfirm(&mib_req);
if (status != LORAMAC_STATUS_OK) {
LOG_ERR("Could not set the NVM context, error %d", status);
return -EINVAL;
}
LOG_DBG("LoRaWAN context restored");
return 0;
}
int lorawan_nvm_init(void)
{
return settings_subsys_init();
}