From 7bccb7f25c69f4721c4aca7e58e9e313dd911452 Mon Sep 17 00:00:00 2001 From: StevenCellist Date: Mon, 19 Feb 2024 19:13:53 +0100 Subject: [PATCH] [LoRaWAN] Improve persistence behaviour, add dwell time error, clear up debug output --- src/protocols/LoRaWAN/LoRaWAN.cpp | 223 ++++++++++++++++-------------- src/protocols/LoRaWAN/LoRaWAN.h | 23 +-- 2 files changed, 136 insertions(+), 110 deletions(-) diff --git a/src/protocols/LoRaWAN/LoRaWAN.cpp b/src/protocols/LoRaWAN/LoRaWAN.cpp index 6a038746..dd36f289 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.cpp +++ b/src/protocols/LoRaWAN/LoRaWAN.cpp @@ -165,7 +165,7 @@ int16_t LoRaWANNode::restore() { return(this->activeMode); } -int16_t LoRaWANNode::restoreFcntUp() { +void LoRaWANNode::restoreFcntUp() { Module* mod = this->phyLayer->getMod(); uint8_t fcntBuffStart = mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID); @@ -210,7 +210,6 @@ int16_t LoRaWANNode::restoreFcntUp() { #endif this->fcntUp = (bits_30_22 << 22) | (bits_22_14 << 14) | (bits_14_7 << 7) | bits_7_0; - return(RADIOLIB_ERR_NONE); } int16_t LoRaWANNode::restoreChannels() { @@ -277,7 +276,41 @@ int16_t LoRaWANNode::restoreChannels() { } return(RADIOLIB_ERR_NONE); } -#endif + +void LoRaWANNode::clearSession() { + Module* mod = this->phyLayer->getMod(); + uint8_t zeroes[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID), zeroes, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID), zeroes, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID), zeroes, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID), zeroes, RADIOLIB_AES128_BLOCK_SIZE); +} + +bool LoRaWANNode::isActiveSession() { + Module* mod = this->phyLayer->getMod(); + this->devAddr = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID); + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID), this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); + + uint8_t mask = 0; + for(size_t i = 0; i < RADIOLIB_AES128_BLOCK_SIZE; i++) { + mask |= this->appSKey[i]; + } + for(size_t i = 0; i < RADIOLIB_AES128_BLOCK_SIZE; i++) { + mask |= this->nwkSEncKey[i]; + } + for(size_t i = 0; i < RADIOLIB_AES128_BLOCK_SIZE; i++) { + mask |= this->fNwkSIntKey[i]; + } + for(size_t i = 0; i < RADIOLIB_AES128_BLOCK_SIZE; i++) { + mask |= this->sNwkSIntKey[i]; + } + return(mask > 0); +} + +#endif // RADIOLIB_EEPROM_UNSUPPORTED void LoRaWANNode::beginCommon(uint8_t joinDr) { // in case a new session is started while there is an ongoing session @@ -400,26 +433,21 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe checkSum ^= LoRaWANNode::checkSum16(nwkKey, 16); checkSum ^= LoRaWANNode::checkSum16(appKey, 16); - bool validCheckSum = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum; - bool validMode = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID) == RADIOLIB_LORAWAN_MODE_OTAA; + bool isValidCheckSum = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum; + bool isValidMode = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID) == RADIOLIB_LORAWAN_MODE_OTAA; - if(validCheckSum && validMode) { - if(!force) { - // the device has joined already, we can just pull the data from persistent storage - RADIOLIB_DEBUG_PRINTLN("Found existing session; restoring..."); - return(this->restore()); - - } else { - // the credentials are still the same, so restore only DevNonce and JoinNonce - this->devNonce = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID); - this->joinNonce = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID); - } + if(isValidCheckSum && isValidMode && !force && this->isActiveSession()) { + return(this->restore()); } - - // if forced by user, keys are new or changed mode, wipe the previous session - if(force || !validCheckSum || !validMode) { + if(isValidCheckSum && isValidMode && (force || !this->isActiveSession())) { + this->clearSession(); + // the credentials are still the same, so restore the DevNonce and JoinNonce + this->devNonce = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID); + this->joinNonce = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID); + } + if(!isValidCheckSum || !isValidMode) { #if RADIOLIB_DEBUG - RADIOLIB_DEBUG_PRINTLN("Didn't restore session (checksum: %d, mode: %d)", validCheckSum, validMode); + RADIOLIB_DEBUG_PRINTLN("Didn't restore session (checksum: %d, mode: %d)", isValidCheckSum, isValidMode); RADIOLIB_DEBUG_PRINTLN("First 16 bytes of NVM:"); uint8_t nvmBuff[16]; mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(0), nvmBuff, 16); @@ -458,9 +486,15 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK); RADIOLIB_ASSERT(state); + // copy devNonce currently in use + uint16_t devNonceUsed = this->devNonce; // increment devNonce as we are sending another join-request this->devNonce += 1; +#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID, this->devNonce); +#endif + // build the join-request message uint8_t joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_LEN]; @@ -468,7 +502,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe joinRequestMsg[0] = RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_REQUEST | RADIOLIB_LORAWAN_MHDR_MAJOR_R1; LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_JOIN_EUI_POS], joinEUI); LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_EUI_POS], devEUI); - LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_NONCE_POS], this->devNonce); + LoRaWANNode::hton(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_NONCE_POS], devNonceUsed); // add the authentication code uint32_t mic = this->generateMIC(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN - sizeof(uint32_t), nwkKey); @@ -554,7 +588,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe uint8_t micBuff[3*RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; micBuff[0] = RADIOLIB_LORAWAN_JOIN_REQUEST_TYPE; LoRaWANNode::hton(&micBuff[1], joinEUI); - LoRaWANNode::hton(&micBuff[9], this->devNonce); + LoRaWANNode::hton(&micBuff[9], devNonceUsed); memcpy(&micBuff[11], joinAcceptMsg, lenRx); if(!verifyMIC(micBuff, lenRx + 11, this->jSIntKey)) { @@ -605,7 +639,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe if(this->rev == 1) { // 1.1 version, derive the keys LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_EUI_POS], joinEUI); - LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_NONCE_POS], this->devNonce); + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_NONCE_POS], devNonceUsed); keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY; RadioLibAES128Instance.init(appKey); @@ -636,7 +670,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe } else { // 1.0 version, just derive the keys LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], this->homeNetId, 3); - LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS], this->devNonce); + LoRaWANNode::hton(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS], devNonceUsed); keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY; RadioLibAES128Instance.init(nwkKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->appSKey); @@ -660,23 +694,10 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) // save the activation keys checksum, device address & keys as well as JoinAccept values; these are only ever set when joining - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID, checkSum); - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID, this->devAddr); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID), this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); - - // save join-request parameters - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_HOME_NET_ID, this->homeNetId); - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID, this->devNonce); - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID, this->joinNonce); - - this->saveSession(); - - // everything written to NVM, write current table version to persistent storage and set mode mod->hal->setPersistentParameter(RADIOLIB_EEPROM_TABLE_VERSION_ID, RADIOLIB_EEPROM_TABLE_VERSION); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID, checkSum); mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID, RADIOLIB_LORAWAN_MODE_OTAA); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID, this->joinNonce); #endif this->activeMode = RADIOLIB_LORAWAN_MODE_OTAA; @@ -697,17 +718,18 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, if(fNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(fNwkSIntKey, 16); } if(sNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(sNwkSIntKey, 16); } - bool validCheckSum = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum; - bool validMode = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID) == RADIOLIB_LORAWAN_MODE_ABP; + bool isValidCheckSum = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum; + bool isValidMode = mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID) == RADIOLIB_LORAWAN_MODE_OTAA; - if(!force && validCheckSum && validMode) { - // the device has joined already, we can just pull the data from persistent storage - RADIOLIB_DEBUG_PRINTLN("Found existing session; restoring..."); - + if(isValidCheckSum && isValidMode && !force && this->isActiveSession()) { return(this->restore()); - } else { + } + if(isValidCheckSum && isValidMode && (force || !this->isActiveSession())) { + this->clearSession(); + } + if(!isValidCheckSum || !isValidMode) { #if RADIOLIB_DEBUG - RADIOLIB_DEBUG_PRINTLN("Didn't restore session (checksum: %d, mode: %d)", validCheckSum, validMode); + RADIOLIB_DEBUG_PRINTLN("Didn't restore session (checksum: %d, mode: %d)", isValidCheckSum, isValidMode); RADIOLIB_DEBUG_PRINTLN("First 16 bytes of NVM:"); uint8_t nvmBuff[16]; mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(0), nvmBuff, 16); @@ -750,20 +772,18 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey, state = this->setPhyProperties(); RADIOLIB_ASSERT(state); + // reset all frame counters + this->fcntUp = 0; + this->aFcntDown = 0; + this->nFcntDown = 0; + this->confFcntUp = RADIOLIB_LORAWAN_FCNT_NONE; + this->confFcntDown = RADIOLIB_LORAWAN_FCNT_NONE; + this->adrFcnt = 0; + #if !defined(RADIOLIB_EEPROM_UNSUPPORTED) // save the activation keys checksum, device address & keys - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID, checkSum); - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID, this->devAddr); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID), this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); - mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); - - // save all new frame counters - this->saveSession(); - - // everything written to NVM, write current table version to persistent storage and set mode mod->hal->setPersistentParameter(RADIOLIB_EEPROM_TABLE_VERSION_ID, RADIOLIB_EEPROM_TABLE_VERSION); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID, checkSum); mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_MODE_ID, RADIOLIB_LORAWAN_MODE_ABP); #endif @@ -780,25 +800,24 @@ bool LoRaWANNode::isJoined() { int16_t LoRaWANNode::saveSession() { Module* mod = this->phyLayer->getMod(); - if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_VERSION_ID) != this->rev) - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_VERSION_ID, this->rev); + // store DevAddr and all keys + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID, this->devAddr); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID), this->appSKey, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); + mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); + + // store network parameters + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_HOME_NET_ID, this->homeNetId); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_VERSION_ID, this->rev); // store all frame counters - if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID) != this->aFcntDown) - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID, this->aFcntDown); - - if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_N_FCNT_DOWN_ID) != this->nFcntDown) - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_N_FCNT_DOWN_ID, this->nFcntDown); - - if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_UP_ID) != this->confFcntUp) - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_UP_ID, this->confFcntUp); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID, this->aFcntDown); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_N_FCNT_DOWN_ID, this->nFcntDown); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_UP_ID, this->confFcntUp); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_DOWN_ID, this->confFcntDown); + mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_ADR_FCNT_ID, this->adrFcnt); - if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_DOWN_ID) != this->confFcntDown) - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_DOWN_ID, this->confFcntDown); - - if(mod->hal->getPersistentParameter(RADIOLIB_EEPROM_LORAWAN_ADR_FCNT_ID) != this->adrFcnt) - mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_ADR_FCNT_ID, this->adrFcnt); - // fcntUp is saved using highly efficient wear-leveling as this is by far going to be written most often this->saveFcntUp(); @@ -815,7 +834,7 @@ int16_t LoRaWANNode::saveSession() { return(RADIOLIB_ERR_NONE); } -int16_t LoRaWANNode::saveFcntUp() { +void LoRaWANNode::saveFcntUp() { Module* mod = this->phyLayer->getMod(); uint8_t fcntBuffStart = mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID); @@ -878,7 +897,6 @@ int16_t LoRaWANNode::saveFcntUp() { bits_7_0 |= (~(fcntBuff[idx] >> 7)) << 7; mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID, bits_7_0, idx); - return(RADIOLIB_ERR_NONE); } #endif // RADIOLIB_EEPROM_UNSUPPORTED @@ -1008,7 +1026,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf // if dwell time is imposed, calculated expected time on air and cancel if exceeds if(this->dwellTimeEnabledUp && this->phyLayer->getTimeOnAir(RADIOLIB_LORAWAN_FRAME_LEN(len, foptsLen) - 16)/1000 > this->dwellTimeUp) { - return(RADIOLIB_ERR_PACKET_TOO_LONG); + return(RADIOLIB_ERR_DWELL_TIME_EXCEEDED); } // build the uplink message @@ -1109,6 +1127,8 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf block1[RADIOLIB_LORAWAN_MIC_DATA_RATE_POS] = this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]; block1[RADIOLIB_LORAWAN_MIC_CH_INDEX_POS] = this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK].idx; + RADIOLIB_DEBUG_PRINTLN("FcntUp: %d", this->fcntUp); + RADIOLIB_DEBUG_PRINTLN("uplinkMsg pre-MIC:"); RADIOLIB_DEBUG_HEXDUMP(uplinkMsg, uplinkMsgLen); @@ -1126,9 +1146,6 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf LoRaWANNode::hton(&uplinkMsg[uplinkMsgLen - sizeof(uint32_t)], micF); } - RADIOLIB_DEBUG_PRINTLN("uplinkMsg:"); - RADIOLIB_DEBUG_HEXDUMP(uplinkMsg, uplinkMsgLen); - // perform CSMA if enabled. if (enableCSMA) { performCSMA(); @@ -1224,7 +1241,7 @@ int16_t LoRaWANNode::downlinkCommon() { // wait for the timeout to complete (and a small additional delay) mod->hal->delay(timeoutHost / 1000 + scanGuard / 2); - RADIOLIB_DEBUG_PRINTLN("closing"); + RADIOLIB_DEBUG_PRINTLN("Closing Rx%d window", i+1); // check if the IRQ bit for Rx Timeout is set if(!this->phyLayer->isRxTimeout()) { @@ -1233,6 +1250,7 @@ int16_t LoRaWANNode::downlinkCommon() { } else if(i == 0) { // nothing in the first window, configure for the second this->phyLayer->standby(); + RADIOLIB_DEBUG_PRINTLN("PHY: Frequency %cL = %6.3f MHz", 'D', this->rx2.freq); state = this->phyLayer->setFrequency(this->rx2.freq); RADIOLIB_ASSERT(state); @@ -1742,7 +1760,6 @@ int16_t LoRaWANNode::setupChannelsDyn(bool joinRequest) { for(; num < 3 && this->band->txFreqs[num].enabled; num++) { this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = this->band->txFreqs[num]; this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][num] = this->band->txFreqs[num]; - RADIOLIB_DEBUG_PRINTLN("Channel UL/DL %d frequency = %f MHz", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq); } // if we're about to send a join-request, copy the join-request channels to the next slots @@ -1751,7 +1768,6 @@ int16_t LoRaWANNode::setupChannelsDyn(bool joinRequest) { for(; numJR < 3 && this->band->txJoinReq[num].enabled; numJR++, num++) { this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = this->band->txFreqs[num]; this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][num] = this->band->txFreqs[num]; - RADIOLIB_DEBUG_PRINTLN("Channel UL/DL %d frequency = %f MHz", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num].freq); } } @@ -1759,6 +1775,22 @@ int16_t LoRaWANNode::setupChannelsDyn(bool joinRequest) { for(; num < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; num++) { this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = RADIOLIB_LORAWAN_CHANNEL_NONE; } + + for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { + RADIOLIB_DEBUG_PRINTLN("UL: %d %d %6.3f (%d - %d) | DL: %d %d %6.3f (%d - %d)", + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].drMax, + + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].idx, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].enabled, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].freq, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMin, + this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i].drMax + ); + } return(RADIOLIB_ERR_NONE); } @@ -2083,8 +2115,8 @@ int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { dataRate->lora.spreadingFactor = ((dataRateBand & 0x70) >> 4) + 6; dataRate->lora.codingRate = (dataRateBand & 0x03) + 5; - RADIOLIB_DEBUG_PRINTLN("DR %d: LORA (SF: %d, BW: %f, CR: %d)", - dataRateBand, dataRate->lora.spreadingFactor, dataRate->lora.bandwidth, dataRate->lora.codingRate); + RADIOLIB_DEBUG_PRINTLN("PHY: SF = %d, BW = %6.3f kHz, CR = 4/%d", + dataRate->lora.spreadingFactor, dataRate->lora.bandwidth, dataRate->lora.codingRate); } return(RADIOLIB_ERR_NONE); @@ -2093,7 +2125,7 @@ int16_t LoRaWANNode::findDataRate(uint8_t dr, DataRate_t* dataRate) { int16_t LoRaWANNode::configureChannel(uint8_t dir) { // set the frequency RADIOLIB_DEBUG_PRINTLN(""); - RADIOLIB_DEBUG_PRINTLN("Channel frequency %cL = %f MHz", dir ? 'D' : 'U', this->currentChannels[dir].freq); + RADIOLIB_DEBUG_PRINTLN("PHY: Frequency %cL = %6.3f MHz", dir ? 'D' : 'U', this->currentChannels[dir].freq); int state = this->phyLayer->setFrequency(this->currentChannels[dir].freq); RADIOLIB_ASSERT(state); @@ -2314,9 +2346,6 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID), &(cmd->payload[0]), payLen); } else { // RADIOLIB_LORAWAN_BAND_FIXED - RADIOLIB_DEBUG_PRINTLN("[1] Repeat: %d, RFU: %d, payload: %02X %02X %02X %02X", - cmd->repeat, (cmd->payload[3] >> 7), - cmd->payload[0], cmd->payload[1], cmd->payload[2], cmd->payload[3]); // if RFU bit is set, this is just a change in Datarate or TxPower // so read bytes 1..3 from last stored ADR command into the current MAC payload and re-store it if((cmd->payload[3] >> 7) == 1) { @@ -2333,9 +2362,6 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { // saved an ADR mask, so re-store counter mod->hal->setPersistentParameter(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID, cmd->repeat); } - RADIOLIB_DEBUG_PRINTLN("[2] Repeat: %d, RFU: %d, payload: %02X %02X %02X %02X", - cmd->repeat, (cmd->payload[3] >> 7), - cmd->payload[0], cmd->payload[1], cmd->payload[2], cmd->payload[3]); } } #endif @@ -2438,7 +2464,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) { this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].freq); } - RADIOLIB_DEBUG_PRINTLN("UL: %d %d %5.2f (%d - %d) | DL: %d %d %5.2f (%d - %d)", + RADIOLIB_DEBUG_PRINTLN("UL: %d %d %6.3f (%d - %d) | DL: %d %d %6.3f (%d - %d)", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].enabled, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].freq, @@ -2641,7 +2667,6 @@ bool LoRaWANNode::applyChannelMaskDyn(uint8_t chMaskCntl, uint16_t chMask) { for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { if(chMaskCntl == 0) { // apply the mask by looking at each channel bit - RADIOLIB_DEBUG_PRINTLN("ADR channel %d: %d --> %d", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, (chMask >> i) & 0x01); if(chMask & (1UL << i)) { // if it should be enabled but is not currently defined, stop immediately if(this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx == RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { @@ -2662,7 +2687,7 @@ bool LoRaWANNode::applyChannelMaskDyn(uint8_t chMaskCntl, uint16_t chMask) { } for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - RADIOLIB_DEBUG_PRINTLN("UL: %d %d %5.2f (%d - %d) | DL: %d %d %5.2f (%d - %d)", + RADIOLIB_DEBUG_PRINTLN("UL: %d %d %6.3f (%d - %d) | DL: %d %d %6.3f (%d - %d)", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, @@ -2709,7 +2734,6 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool chnl.drMin = this->band->txSpans[0].drMin; chnl.drMax = this->band->txSpans[0].drMax; this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; - RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", chnl.idx, idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx-1].freq); } } @@ -2732,7 +2756,6 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool chnl.drMin = this->band->txSpans[1].drMin; chnl.drMax = this->band->txSpans[1].drMax; this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; - RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", chnl.idx, idx-1, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx-1].freq); } } @@ -2752,7 +2775,6 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool chnl.drMin = this->band->txSpans[0].drMin; chnl.drMax = this->band->txSpans[0].drMax; this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; - RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", chnl.idx, idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx-1].freq); } // enable single channel from second span uint8_t chNum = 64 + i; @@ -2762,7 +2784,6 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool chnl.drMin = this->band->txSpans[1].drMin; chnl.drMax = this->band->txSpans[1].drMax; this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; - RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", chnl.idx, idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx-1].freq); } } @@ -2785,7 +2806,6 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool chnl.drMin = this->band->txSpans[1].drMin; chnl.drMax = this->band->txSpans[1].drMax; this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; - RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", chnl.idx, idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx-1].freq); } } @@ -2810,14 +2830,13 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool chnl.drMin = this->band->txSpans[1].drMin; chnl.drMax = this->band->txSpans[1].drMax; this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; - RADIOLIB_DEBUG_PRINTLN("Channel UL %d (%d) frequency = %f MHz", chnl.idx, idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx-1].freq); } } } for (int i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) { - RADIOLIB_DEBUG_PRINTLN("UL: %d %d %5.2f (%d - %d) | DL: %d %d %5.2f (%d - %d)", + RADIOLIB_DEBUG_PRINTLN("UL: %d %d %6.3f (%d - %d) | DL: %d %d %6.3f (%d - %d)", this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].idx, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].freq, diff --git a/src/protocols/LoRaWAN/LoRaWAN.h b/src/protocols/LoRaWAN/LoRaWAN.h index 157945a0..8b9141bb 100644 --- a/src/protocols/LoRaWAN/LoRaWAN.h +++ b/src/protocols/LoRaWAN/LoRaWAN.h @@ -179,6 +179,12 @@ #define RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP (0x0F) #define RADIOLIB_LORAWAN_MAC_PROPRIETARY (0x80) +// maximum allowed dwell time on bands that implement dwell time limitations +#define RADIOLIB_LORAWAN_DWELL_TIME (400) + +// unused LoRaWAN version +#define RADIOLIB_LORAWAN_VERSION_NONE (0xFF) + // unused frame counter value #define RADIOLIB_LORAWAN_FCNT_NONE (0xFFFFFFFF) @@ -188,10 +194,7 @@ // the maximum number of simultaneously available channels #define RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS (16) -// maximum allowed dwell time on bands that implement dwell time limitations -#define RADIOLIB_LORAWAN_DWELL_TIME (400) - -// Maximum MAC command sizes +// maximum MAC command sizes #define RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN (5) #define RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_UP (2) #define RADIOLIB_LORAWAN_MAX_NUM_ADR_COMMANDS (8) @@ -804,16 +807,20 @@ class LoRaWANNode { /*! \brief Save the current uplink frame counter. Note that the usable frame counter width is 'only' 30 bits for highly efficient wear-levelling. - \returns \ref status_codes */ - int16_t saveFcntUp(); + void saveFcntUp(); /*! \brief Restore frame counter for uplinks from persistent storage. Note that the usable frame counter width is 'only' 30 bits for highly efficient wear-levelling. - \returns \ref status_codes */ - int16_t restoreFcntUp(); + void restoreFcntUp(); + + // set all keys to zero + void clearSession(); + + // test if saved keys are non-zero + bool isActiveSession(); #endif // wait for, open and listen during Rx1 and Rx2 windows; only performs listening