| /* |
| * 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); |
| } |
| } |
| } |
| |
| settings_save(); |
| } |
| |
| 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(); |
| } |