[LoRaWAN] Improve persistence behaviour, add dwell time error, clear up debug output

This commit is contained in:
StevenCellist 2024-02-19 19:13:53 +01:00
parent 8f47e834f5
commit 7bccb7f25c
2 changed files with 136 additions and 110 deletions

View file

@ -165,7 +165,7 @@ int16_t LoRaWANNode::restore() {
return(this->activeMode); return(this->activeMode);
} }
int16_t LoRaWANNode::restoreFcntUp() { void LoRaWANNode::restoreFcntUp() {
Module* mod = this->phyLayer->getMod(); Module* mod = this->phyLayer->getMod();
uint8_t fcntBuffStart = mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID); uint8_t fcntBuffStart = mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID);
@ -210,7 +210,6 @@ int16_t LoRaWANNode::restoreFcntUp() {
#endif #endif
this->fcntUp = (bits_30_22 << 22) | (bits_22_14 << 14) | (bits_14_7 << 7) | bits_7_0; 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() { int16_t LoRaWANNode::restoreChannels() {
@ -277,7 +276,41 @@ int16_t LoRaWANNode::restoreChannels() {
} }
return(RADIOLIB_ERR_NONE); 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<uint32_t>(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) { void LoRaWANNode::beginCommon(uint8_t joinDr) {
// in case a new session is started while there is an ongoing session // 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(nwkKey, 16);
checkSum ^= LoRaWANNode::checkSum16(appKey, 16); checkSum ^= LoRaWANNode::checkSum16(appKey, 16);
bool validCheckSum = mod->hal->getPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum; bool isValidCheckSum = mod->hal->getPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum;
bool validMode = mod->hal->getPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_MODE_ID) == RADIOLIB_LORAWAN_MODE_OTAA; bool isValidMode = mod->hal->getPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_MODE_ID) == RADIOLIB_LORAWAN_MODE_OTAA;
if(validCheckSum && validMode) { if(isValidCheckSum && isValidMode && !force && this->isActiveSession()) {
if(!force) { return(this->restore());
// 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<uint16_t>(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID);
this->joinNonce = mod->hal->getPersistentParameter<uint32_t>(RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID);
}
} }
if(isValidCheckSum && isValidMode && (force || !this->isActiveSession())) {
// if forced by user, keys are new or changed mode, wipe the previous session this->clearSession();
if(force || !validCheckSum || !validMode) { // the credentials are still the same, so restore the DevNonce and JoinNonce
this->devNonce = mod->hal->getPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID);
this->joinNonce = mod->hal->getPersistentParameter<uint32_t>(RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID);
}
if(!isValidCheckSum || !isValidMode) {
#if RADIOLIB_DEBUG #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:"); RADIOLIB_DEBUG_PRINTLN("First 16 bytes of NVM:");
uint8_t nvmBuff[16]; uint8_t nvmBuff[16];
mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(0), 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); state = this->configureChannel(RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK);
RADIOLIB_ASSERT(state); RADIOLIB_ASSERT(state);
// copy devNonce currently in use
uint16_t devNonceUsed = this->devNonce;
// increment devNonce as we are sending another join-request // increment devNonce as we are sending another join-request
this->devNonce += 1; this->devNonce += 1;
#if !defined(RADIOLIB_EEPROM_UNSUPPORTED)
mod->hal->setPersistentParameter<uint32_t>(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID, this->devNonce);
#endif
// build the join-request message // build the join-request message
uint8_t joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_LEN]; 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; joinRequestMsg[0] = RADIOLIB_LORAWAN_MHDR_MTYPE_JOIN_REQUEST | RADIOLIB_LORAWAN_MHDR_MAJOR_R1;
LoRaWANNode::hton<uint64_t>(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_JOIN_EUI_POS], joinEUI); LoRaWANNode::hton<uint64_t>(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_JOIN_EUI_POS], joinEUI);
LoRaWANNode::hton<uint64_t>(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_EUI_POS], devEUI); LoRaWANNode::hton<uint64_t>(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_EUI_POS], devEUI);
LoRaWANNode::hton<uint16_t>(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_NONCE_POS], this->devNonce); LoRaWANNode::hton<uint16_t>(&joinRequestMsg[RADIOLIB_LORAWAN_JOIN_REQUEST_DEV_NONCE_POS], devNonceUsed);
// add the authentication code // add the authentication code
uint32_t mic = this->generateMIC(joinRequestMsg, RADIOLIB_LORAWAN_JOIN_REQUEST_LEN - sizeof(uint32_t), nwkKey); 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 }; uint8_t micBuff[3*RADIOLIB_AES128_BLOCK_SIZE] = { 0 };
micBuff[0] = RADIOLIB_LORAWAN_JOIN_REQUEST_TYPE; micBuff[0] = RADIOLIB_LORAWAN_JOIN_REQUEST_TYPE;
LoRaWANNode::hton<uint64_t>(&micBuff[1], joinEUI); LoRaWANNode::hton<uint64_t>(&micBuff[1], joinEUI);
LoRaWANNode::hton<uint16_t>(&micBuff[9], this->devNonce); LoRaWANNode::hton<uint16_t>(&micBuff[9], devNonceUsed);
memcpy(&micBuff[11], joinAcceptMsg, lenRx); memcpy(&micBuff[11], joinAcceptMsg, lenRx);
if(!verifyMIC(micBuff, lenRx + 11, this->jSIntKey)) { 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) { if(this->rev == 1) {
// 1.1 version, derive the keys // 1.1 version, derive the keys
LoRaWANNode::hton<uint64_t>(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_EUI_POS], joinEUI); LoRaWANNode::hton<uint64_t>(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_EUI_POS], joinEUI);
LoRaWANNode::hton<uint16_t>(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_NONCE_POS], this->devNonce); LoRaWANNode::hton<uint16_t>(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_NONCE_POS], devNonceUsed);
keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY; keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY;
RadioLibAES128Instance.init(appKey); RadioLibAES128Instance.init(appKey);
@ -636,7 +670,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe
} else { } else {
// 1.0 version, just derive the keys // 1.0 version, just derive the keys
LoRaWANNode::hton<uint32_t>(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], this->homeNetId, 3); LoRaWANNode::hton<uint32_t>(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], this->homeNetId, 3);
LoRaWANNode::hton<uint16_t>(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS], this->devNonce); LoRaWANNode::hton<uint16_t>(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS], devNonceUsed);
keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY; keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY;
RadioLibAES128Instance.init(nwkKey); RadioLibAES128Instance.init(nwkKey);
RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->appSKey); 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) #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 // save the activation keys checksum, device address & keys as well as JoinAccept values; these are only ever set when joining
mod->hal->setPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID, checkSum);
mod->hal->setPersistentParameter<uint32_t>(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<uint32_t>(RADIOLIB_EEPROM_LORAWAN_HOME_NET_ID, this->homeNetId);
mod->hal->setPersistentParameter<uint32_t>(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID, this->devNonce);
mod->hal->setPersistentParameter<uint32_t>(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<uint16_t>(RADIOLIB_EEPROM_TABLE_VERSION_ID, RADIOLIB_EEPROM_TABLE_VERSION); mod->hal->setPersistentParameter<uint16_t>(RADIOLIB_EEPROM_TABLE_VERSION_ID, RADIOLIB_EEPROM_TABLE_VERSION);
mod->hal->setPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID, checkSum);
mod->hal->setPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_MODE_ID, RADIOLIB_LORAWAN_MODE_OTAA); mod->hal->setPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_MODE_ID, RADIOLIB_LORAWAN_MODE_OTAA);
mod->hal->setPersistentParameter<uint32_t>(RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID, this->joinNonce);
#endif #endif
this->activeMode = RADIOLIB_LORAWAN_MODE_OTAA; 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(fNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(fNwkSIntKey, 16); }
if(sNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(sNwkSIntKey, 16); } if(sNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(sNwkSIntKey, 16); }
bool validCheckSum = mod->hal->getPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum; bool isValidCheckSum = mod->hal->getPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum;
bool validMode = mod->hal->getPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_MODE_ID) == RADIOLIB_LORAWAN_MODE_ABP; bool isValidMode = mod->hal->getPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_MODE_ID) == RADIOLIB_LORAWAN_MODE_OTAA;
if(!force && validCheckSum && validMode) { if(isValidCheckSum && isValidMode && !force && this->isActiveSession()) {
// the device has joined already, we can just pull the data from persistent storage
RADIOLIB_DEBUG_PRINTLN("Found existing session; restoring...");
return(this->restore()); return(this->restore());
} else { }
if(isValidCheckSum && isValidMode && (force || !this->isActiveSession())) {
this->clearSession();
}
if(!isValidCheckSum || !isValidMode) {
#if RADIOLIB_DEBUG #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:"); RADIOLIB_DEBUG_PRINTLN("First 16 bytes of NVM:");
uint8_t nvmBuff[16]; uint8_t nvmBuff[16];
mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(0), 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(); state = this->setPhyProperties();
RADIOLIB_ASSERT(state); 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) #if !defined(RADIOLIB_EEPROM_UNSUPPORTED)
// save the activation keys checksum, device address & keys // save the activation keys checksum, device address & keys
mod->hal->setPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID, checkSum);
mod->hal->setPersistentParameter<uint32_t>(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<uint16_t>(RADIOLIB_EEPROM_TABLE_VERSION_ID, RADIOLIB_EEPROM_TABLE_VERSION); mod->hal->setPersistentParameter<uint16_t>(RADIOLIB_EEPROM_TABLE_VERSION_ID, RADIOLIB_EEPROM_TABLE_VERSION);
mod->hal->setPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID, checkSum);
mod->hal->setPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_MODE_ID, RADIOLIB_LORAWAN_MODE_ABP); mod->hal->setPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_MODE_ID, RADIOLIB_LORAWAN_MODE_ABP);
#endif #endif
@ -780,25 +800,24 @@ bool LoRaWANNode::isJoined() {
int16_t LoRaWANNode::saveSession() { int16_t LoRaWANNode::saveSession() {
Module* mod = this->phyLayer->getMod(); Module* mod = this->phyLayer->getMod();
if(mod->hal->getPersistentParameter<uint8_t>(RADIOLIB_EEPROM_LORAWAN_VERSION_ID) != this->rev) // store DevAddr and all keys
mod->hal->setPersistentParameter<uint8_t>(RADIOLIB_EEPROM_LORAWAN_VERSION_ID, this->rev); mod->hal->setPersistentParameter<uint32_t>(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<uint32_t>(RADIOLIB_EEPROM_LORAWAN_HOME_NET_ID, this->homeNetId);
mod->hal->setPersistentParameter<uint8_t>(RADIOLIB_EEPROM_LORAWAN_VERSION_ID, this->rev);
// store all frame counters // store all frame counters
if(mod->hal->getPersistentParameter<uint32_t>(RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID) != this->aFcntDown) mod->hal->setPersistentParameter<uint32_t>(RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID, this->aFcntDown);
mod->hal->setPersistentParameter<uint32_t>(RADIOLIB_EEPROM_LORAWAN_A_FCNT_DOWN_ID, this->aFcntDown); mod->hal->setPersistentParameter<uint32_t>(RADIOLIB_EEPROM_LORAWAN_N_FCNT_DOWN_ID, this->nFcntDown);
mod->hal->setPersistentParameter<uint32_t>(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_UP_ID, this->confFcntUp);
if(mod->hal->getPersistentParameter<uint32_t>(RADIOLIB_EEPROM_LORAWAN_N_FCNT_DOWN_ID) != this->nFcntDown) mod->hal->setPersistentParameter<uint32_t>(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_DOWN_ID, this->confFcntDown);
mod->hal->setPersistentParameter<uint32_t>(RADIOLIB_EEPROM_LORAWAN_N_FCNT_DOWN_ID, this->nFcntDown); mod->hal->setPersistentParameter<uint32_t>(RADIOLIB_EEPROM_LORAWAN_ADR_FCNT_ID, this->adrFcnt);
if(mod->hal->getPersistentParameter<uint32_t>(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_UP_ID) != this->confFcntUp)
mod->hal->setPersistentParameter<uint32_t>(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_UP_ID, this->confFcntUp);
if(mod->hal->getPersistentParameter<uint32_t>(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_DOWN_ID) != this->confFcntDown)
mod->hal->setPersistentParameter<uint32_t>(RADIOLIB_EEPROM_LORAWAN_CONF_FCNT_DOWN_ID, this->confFcntDown);
if(mod->hal->getPersistentParameter<uint32_t>(RADIOLIB_EEPROM_LORAWAN_ADR_FCNT_ID) != this->adrFcnt)
mod->hal->setPersistentParameter<uint32_t>(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 // fcntUp is saved using highly efficient wear-leveling as this is by far going to be written most often
this->saveFcntUp(); this->saveFcntUp();
@ -815,7 +834,7 @@ int16_t LoRaWANNode::saveSession() {
return(RADIOLIB_ERR_NONE); return(RADIOLIB_ERR_NONE);
} }
int16_t LoRaWANNode::saveFcntUp() { void LoRaWANNode::saveFcntUp() {
Module* mod = this->phyLayer->getMod(); Module* mod = this->phyLayer->getMod();
uint8_t fcntBuffStart = mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID); 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; bits_7_0 |= (~(fcntBuff[idx] >> 7)) << 7;
mod->hal->setPersistentParameter<uint8_t>(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID, bits_7_0, idx); mod->hal->setPersistentParameter<uint8_t>(RADIOLIB_EEPROM_LORAWAN_FCNT_UP_ID, bits_7_0, idx);
return(RADIOLIB_ERR_NONE);
} }
#endif // RADIOLIB_EEPROM_UNSUPPORTED #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 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) { 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 // 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_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; 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_PRINTLN("uplinkMsg pre-MIC:");
RADIOLIB_DEBUG_HEXDUMP(uplinkMsg, uplinkMsgLen); 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<uint32_t>(&uplinkMsg[uplinkMsgLen - sizeof(uint32_t)], micF); LoRaWANNode::hton<uint32_t>(&uplinkMsg[uplinkMsgLen - sizeof(uint32_t)], micF);
} }
RADIOLIB_DEBUG_PRINTLN("uplinkMsg:");
RADIOLIB_DEBUG_HEXDUMP(uplinkMsg, uplinkMsgLen);
// perform CSMA if enabled. // perform CSMA if enabled.
if (enableCSMA) { if (enableCSMA) {
performCSMA(); performCSMA();
@ -1224,7 +1241,7 @@ int16_t LoRaWANNode::downlinkCommon() {
// wait for the timeout to complete (and a small additional delay) // wait for the timeout to complete (and a small additional delay)
mod->hal->delay(timeoutHost / 1000 + scanGuard / 2); 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 // check if the IRQ bit for Rx Timeout is set
if(!this->phyLayer->isRxTimeout()) { if(!this->phyLayer->isRxTimeout()) {
@ -1233,6 +1250,7 @@ int16_t LoRaWANNode::downlinkCommon() {
} else if(i == 0) { } else if(i == 0) {
// nothing in the first window, configure for the second // nothing in the first window, configure for the second
this->phyLayer->standby(); this->phyLayer->standby();
RADIOLIB_DEBUG_PRINTLN("PHY: Frequency %cL = %6.3f MHz", 'D', this->rx2.freq);
state = this->phyLayer->setFrequency(this->rx2.freq); state = this->phyLayer->setFrequency(this->rx2.freq);
RADIOLIB_ASSERT(state); RADIOLIB_ASSERT(state);
@ -1742,7 +1760,6 @@ int16_t LoRaWANNode::setupChannelsDyn(bool joinRequest) {
for(; num < 3 && this->band->txFreqs[num].enabled; num++) { 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_UPLINK][num] = this->band->txFreqs[num];
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][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 // 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++) { 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_UPLINK][num] = this->band->txFreqs[num];
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][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++) { for(; num < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; num++) {
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][num] = RADIOLIB_LORAWAN_CHANNEL_NONE; 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); 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.spreadingFactor = ((dataRateBand & 0x70) >> 4) + 6;
dataRate->lora.codingRate = (dataRateBand & 0x03) + 5; dataRate->lora.codingRate = (dataRateBand & 0x03) + 5;
RADIOLIB_DEBUG_PRINTLN("DR %d: LORA (SF: %d, BW: %f, CR: %d)", RADIOLIB_DEBUG_PRINTLN("PHY: SF = %d, BW = %6.3f kHz, CR = 4/%d",
dataRateBand, dataRate->lora.spreadingFactor, dataRate->lora.bandwidth, dataRate->lora.codingRate); dataRate->lora.spreadingFactor, dataRate->lora.bandwidth, dataRate->lora.codingRate);
} }
return(RADIOLIB_ERR_NONE); 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) { int16_t LoRaWANNode::configureChannel(uint8_t dir) {
// set the frequency // set the frequency
RADIOLIB_DEBUG_PRINTLN(""); 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); int state = this->phyLayer->setFrequency(this->currentChannels[dir].freq);
RADIOLIB_ASSERT(state); 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); mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_LINK_ADR_ID), &(cmd->payload[0]), payLen);
} else { // RADIOLIB_LORAWAN_BAND_FIXED } 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 // 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 // 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) { 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 // saved an ADR mask, so re-store counter
mod->hal->setPersistentParameter<uint8_t>(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID, cmd->repeat); mod->hal->setPersistentParameter<uint8_t>(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 #endif
@ -2438,7 +2464,7 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) {
this->phyLayer->setFrequency(this->currentChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK].freq); 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].idx,
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].enabled, this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].enabled,
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][chIndex].freq, 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++) { for(size_t i = 0; i < RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS; i++) {
if(chMaskCntl == 0) { if(chMaskCntl == 0) {
// apply the mask by looking at each channel bit // 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(chMask & (1UL << i)) {
// if it should be enabled but is not currently defined, stop immediately // 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) { 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++) { 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].idx,
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, 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].freq,
@ -2709,7 +2734,6 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool
chnl.drMin = this->band->txSpans[0].drMin; chnl.drMin = this->band->txSpans[0].drMin;
chnl.drMax = this->band->txSpans[0].drMax; chnl.drMax = this->band->txSpans[0].drMax;
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; 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.drMin = this->band->txSpans[1].drMin;
chnl.drMax = this->band->txSpans[1].drMax; chnl.drMax = this->band->txSpans[1].drMax;
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; 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.drMin = this->band->txSpans[0].drMin;
chnl.drMax = this->band->txSpans[0].drMax; chnl.drMax = this->band->txSpans[0].drMax;
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; 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 // enable single channel from second span
uint8_t chNum = 64 + i; 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.drMin = this->band->txSpans[1].drMin;
chnl.drMax = this->band->txSpans[1].drMax; chnl.drMax = this->band->txSpans[1].drMax;
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; 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.drMin = this->band->txSpans[1].drMin;
chnl.drMax = this->band->txSpans[1].drMax; chnl.drMax = this->band->txSpans[1].drMax;
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; 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.drMin = this->band->txSpans[1].drMin;
chnl.drMax = this->band->txSpans[1].drMax; chnl.drMax = this->band->txSpans[1].drMax;
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][idx++] = chnl; 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++) { 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].idx,
this->availableChannels[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i].enabled, 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].freq,

View file

@ -179,6 +179,12 @@
#define RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP (0x0F) #define RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP (0x0F)
#define RADIOLIB_LORAWAN_MAC_PROPRIETARY (0x80) #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 // unused frame counter value
#define RADIOLIB_LORAWAN_FCNT_NONE (0xFFFFFFFF) #define RADIOLIB_LORAWAN_FCNT_NONE (0xFFFFFFFF)
@ -188,10 +194,7 @@
// the maximum number of simultaneously available channels // the maximum number of simultaneously available channels
#define RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS (16) #define RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS (16)
// maximum allowed dwell time on bands that implement dwell time limitations // maximum MAC command sizes
#define RADIOLIB_LORAWAN_DWELL_TIME (400)
// Maximum MAC command sizes
#define RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN (5) #define RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN (5)
#define RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_UP (2) #define RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_UP (2)
#define RADIOLIB_LORAWAN_MAX_NUM_ADR_COMMANDS (8) #define RADIOLIB_LORAWAN_MAX_NUM_ADR_COMMANDS (8)
@ -804,16 +807,20 @@ class LoRaWANNode {
/*! /*!
\brief Save the current uplink frame counter. \brief Save the current uplink frame counter.
Note that the usable frame counter width is 'only' 30 bits for highly efficient wear-levelling. 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. \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. 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 #endif
// wait for, open and listen during Rx1 and Rx2 windows; only performs listening // wait for, open and listen during Rx1 and Rx2 windows; only performs listening