[LoRaWAN] Fully persistent channel management

pull/1573/head
StevenCellist 2025-08-22 18:03:37 +02:00
rodzic 25df076b16
commit e11e5f1286
3 zmienionych plików z 162 dodań i 136 usunięć

Wyświetl plik

@ -67,7 +67,7 @@ void handleTS009(uint8_t* dataDown, size_t lenDown) {
case(RADIOLIB_LORAWAN_TS009_DUT_JOIN): { case(RADIOLIB_LORAWAN_TS009_DUT_JOIN): {
RADIOLIB_DEBUG_PRINTLN("Reverting to Join state"); RADIOLIB_DEBUG_PRINTLN("Reverting to Join state");
node.resetSession(); node.clearSession();
reply = false; reply = false;
} break; } break;

Wyświetl plik

@ -73,7 +73,7 @@ int16_t LoRaWANNode::sendReceive(const uint8_t* dataUp, size_t lenUp, uint8_t fP
if(this->fCntUp == (1UL << this->adrLimitExp)) { if(this->fCntUp == (1UL << this->adrLimitExp)) {
state = this->getMacPayload(RADIOLIB_LORAWAN_MAC_REKEY, this->fOptsUp, this->fOptsUpLen, NULL, RADIOLIB_LORAWAN_UPLINK); state = this->getMacPayload(RADIOLIB_LORAWAN_MAC_REKEY, this->fOptsUp, this->fOptsUpLen, NULL, RADIOLIB_LORAWAN_UPLINK);
if(state == RADIOLIB_ERR_NONE) { if(state == RADIOLIB_ERR_NONE) {
this->resetSession(); this->clearSession();
} }
} }
@ -248,8 +248,7 @@ void LoRaWANNode::clearNonces() {
this->keyCheckSum = 0; this->keyCheckSum = 0;
this->devNonce = 0; this->devNonce = 0;
this->joinNonce = 0; this->joinNonce = 0;
this->isActive = false; this->sessionStatus = RADIOLIB_LORAWAN_SESSION_NONE;
this->rev = 0;
} }
uint8_t* LoRaWANNode::getBufferNonces() { uint8_t* LoRaWANNode::getBufferNonces() {
@ -272,6 +271,12 @@ int16_t LoRaWANNode::setBufferNonces(const uint8_t* persistentBuffer) {
return(RADIOLIB_ERR_NONE); return(RADIOLIB_ERR_NONE);
} }
// // this code can be used in case breaking chances must be caught:
// uint8_t nvm_table_version = this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION];
// if (RADIOLIB_LORAWAN_NONCES_VERSION_VAL > nvm_table_version) {
// // set default values for variables that are new or something
// }
int16_t state = LoRaWANNode::checkBufferCommon(persistentBuffer, RADIOLIB_LORAWAN_NONCES_BUF_SIZE); int16_t state = LoRaWANNode::checkBufferCommon(persistentBuffer, RADIOLIB_LORAWAN_NONCES_BUF_SIZE);
RADIOLIB_ASSERT(state); RADIOLIB_ASSERT(state);
@ -294,19 +299,13 @@ int16_t LoRaWANNode::setBufferNonces(const uint8_t* persistentBuffer) {
this->devNonce = LoRaWANNode::ntoh<uint16_t>(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_DEV_NONCE]); this->devNonce = LoRaWANNode::ntoh<uint16_t>(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_DEV_NONCE]);
this->joinNonce = LoRaWANNode::ntoh<uint32_t>(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_JOIN_NONCE], 3); this->joinNonce = LoRaWANNode::ntoh<uint32_t>(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_JOIN_NONCE], 3);
// revert to inactive as long as no session is restored
this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)false;
this->isActive = false;
return(state); return(state);
} }
void LoRaWANNode::resetSession() { void LoRaWANNode::clearSession() {
memset(this->bufferSession, 0, RADIOLIB_LORAWAN_SESSION_BUF_SIZE); memset(this->bufferSession, 0, RADIOLIB_LORAWAN_SESSION_BUF_SIZE);
memset(this->fOptsUp, 0, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN); memset(this->fOptsUp, 0, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN);
memset(this->fOptsDown, 0, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN); memset(this->fOptsDown, 0, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN);
this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)false;
this->isActive = false;
// reset all frame counters // reset all frame counters
this->fCntUp = 0; this->fCntUp = 0;
@ -333,17 +332,29 @@ void LoRaWANNode::resetSession() {
// reset all channels // reset all channels
memset(this->dynamicChannels, 0, sizeof(this->dynamicChannels)); memset(this->dynamicChannels, 0, sizeof(this->dynamicChannels));
// reset Rx2 channel to default value
this->channels[RADIOLIB_LORAWAN_RX2] = this->band->rx2;
this->sessionStatus = RADIOLIB_LORAWAN_SESSION_NONE;
}
void LoRaWANNode::createSession() {
// setup default channels
if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) {
for(int num = 0; num < 3 && this->band->txFreqs[num].freq > 0; num++) { for(int num = 0; num < 3; num++) {
if(this->band->txFreqs[num].freq) {
// copy the channels from the current channel plan // copy the channels from the current channel plan
this->dynamicChannels[RADIOLIB_LORAWAN_UPLINK][num] = this->band->txFreqs[num]; this->dynamicChannels[RADIOLIB_LORAWAN_UPLINK][num] = this->band->txFreqs[num];
this->dynamicChannels[RADIOLIB_LORAWAN_DOWNLINK][num] = this->band->txFreqs[num]; this->dynamicChannels[RADIOLIB_LORAWAN_DOWNLINK][num] = this->band->txFreqs[num];
} }
} }
}
this->enableDefaultChannels();
// setup the default channels // set default MAC state
this->addDefaultChannels();
// set data rate and Tx power
uint8_t cOcts[5]; // 5 = maximum downlink payload length uint8_t cOcts[5]; // 5 = maximum downlink payload length
uint8_t cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; uint8_t cid = RADIOLIB_LORAWAN_MAC_LINK_ADR;
uint8_t cLen = 1; // only apply Dr/Tx field uint8_t cLen = 1; // only apply Dr/Tx field
@ -376,7 +387,7 @@ void LoRaWANNode::resetSession() {
cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP; cid = RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP;
(void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK); (void)this->getMacLen(cid, &cLen, RADIOLIB_LORAWAN_DOWNLINK);
cOcts[0] = (RADIOLIB_LORAWAN_RX1_DR_OFFSET << 4); cOcts[0] = (RADIOLIB_LORAWAN_RX1_DR_OFFSET << 4);
cOcts[0] |= this->band->rx2.dr; cOcts[0] |= this->channels[RADIOLIB_LORAWAN_RX2].dr; // user may override the Rx2 datarate
LoRaWANNode::hton<uint32_t>(&cOcts[1], this->band->rx2.freq, 3); LoRaWANNode::hton<uint32_t>(&cOcts[1], this->band->rx2.freq, 3);
(void)execMacCommand(cid, cOcts, cLen); (void)execMacCommand(cid, cOcts, cLen);
@ -428,6 +439,9 @@ void LoRaWANNode::resetSession() {
cOcts[0] = (RADIOLIB_LORAWAN_REJOIN_MAX_TIME_N << 4); cOcts[0] = (RADIOLIB_LORAWAN_REJOIN_MAX_TIME_N << 4);
cOcts[0] |= RADIOLIB_LORAWAN_REJOIN_MAX_COUNT_N; cOcts[0] |= RADIOLIB_LORAWAN_REJOIN_MAX_COUNT_N;
(void)execMacCommand(cid, cOcts, cLen); (void)execMacCommand(cid, cOcts, cLen);
// set up a new session, ready for activation
this->sessionStatus = RADIOLIB_LORAWAN_SESSION_ACTIVATING;
} }
uint8_t* LoRaWANNode::getBufferSession() { uint8_t* LoRaWANNode::getBufferSession() {
@ -440,13 +454,17 @@ uint8_t* LoRaWANNode::getBufferSession() {
LoRaWANNode::hton<uint32_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FCNT_UP], this->fCntUp); LoRaWANNode::hton<uint32_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FCNT_UP], this->fCntUp);
LoRaWANNode::hton<uint8_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CLASS], this->lwClass); LoRaWANNode::hton<uint8_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CLASS], this->lwClass);
// store the unused channel flags
memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_AVAILABLE_CHANNELS], this->channelFlags, RADIOLIB_LORAWAN_MAX_NUM_SUBBANDS);
// store the current uplink MAC command queue // store the current uplink MAC command queue
memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE], this->fOptsUp, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN); memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE], this->fOptsUp, RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN);
memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_LEN], &this->fOptsUpLen, 1); memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_LEN], &this->fOptsUpLen, 1);
// store the channel masks and unused channel flags
memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR] + 1, this->channelMasks, sizeof(this->channelMasks));
memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_AVAILABLE_CHANNELS], this->channelFlags, sizeof(this->channelFlags));
// store the session status
LoRaWANNode::hton<uint8_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_STATUS], this->sessionStatus);
// generate the signature of the Session buffer, and store it in the last two bytes of the Session buffer // generate the signature of the Session buffer, and store it in the last two bytes of the Session buffer
uint16_t signature = LoRaWANNode::checkSum16(this->bufferSession, RADIOLIB_LORAWAN_SESSION_BUF_SIZE - 2); uint16_t signature = LoRaWANNode::checkSum16(this->bufferSession, RADIOLIB_LORAWAN_SESSION_BUF_SIZE - 2);
LoRaWANNode::hton<uint16_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_SIGNATURE], signature); LoRaWANNode::hton<uint16_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_SIGNATURE], signature);
@ -475,42 +493,21 @@ int16_t LoRaWANNode::setBufferSession(const uint8_t* persistentBuffer) {
// copy the whole buffer over // copy the whole buffer over
memcpy(this->bufferSession, persistentBuffer, RADIOLIB_LORAWAN_SESSION_BUF_SIZE); memcpy(this->bufferSession, persistentBuffer, RADIOLIB_LORAWAN_SESSION_BUF_SIZE);
// always restore the channels, so as to adhere to channel hopping between JoinRequests // setup the default channels
memcpy(this->channelFlags, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_AVAILABLE_CHANNELS], RADIOLIB_LORAWAN_MAX_NUM_SUBBANDS); if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) {
for(int num = 0; num < 3; num++) {
// check if the session is active, if not, don't restore anything else if(this->band->txFreqs[num].freq) {
if((bool)this->bufferSession[RADIOLIB_LORAWAN_SESSION_ACTIVE] == false) { // copy the channels from the current channel plan
return(RADIOLIB_ERR_NETWORK_NOT_JOINED); this->dynamicChannels[RADIOLIB_LORAWAN_UPLINK][num] = this->band->txFreqs[num];
this->dynamicChannels[RADIOLIB_LORAWAN_DOWNLINK][num] = this->band->txFreqs[num];
} }
}
}
this->enableDefaultChannels();
//// this code can be used in case breaking chances must be caught:
// uint8_t nvm_table_version = this->bufferNonces[RADIOLIB_LORAWAN_NONCES_VERSION];
// if (RADIOLIB_LORAWAN_NONCES_VERSION_VAL > nvm_table_version) {
// // set default values for variables that are new or something
// }
// pull all authentication keys from persistent storage
this->devAddr = LoRaWANNode::ntoh<uint32_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DEV_ADDR]);
memcpy(this->appSKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_APP_SKEY], RADIOLIB_AES128_BLOCK_SIZE);
memcpy(this->nwkSEncKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY], RADIOLIB_AES128_BLOCK_SIZE);
memcpy(this->fNwkSIntKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY], RADIOLIB_AES128_BLOCK_SIZE);
memcpy(this->sNwkSIntKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY], RADIOLIB_AES128_BLOCK_SIZE);
// restore session parameters
this->rev = LoRaWANNode::ntoh<uint8_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION]);
this->lwClass = LoRaWANNode::ntoh<uint8_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CLASS]);
this->homeNetId = LoRaWANNode::ntoh<uint32_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_HOMENET_ID]);
this->aFCntDown = LoRaWANNode::ntoh<uint32_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN]);
this->nFCntDown = LoRaWANNode::ntoh<uint32_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN]);
this->confFCntUp = LoRaWANNode::ntoh<uint32_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP]);
this->confFCntDown = LoRaWANNode::ntoh<uint32_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN]);
this->adrFCnt = LoRaWANNode::ntoh<uint32_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_FCNT]);
this->fCntUp = LoRaWANNode::ntoh<uint32_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FCNT_UP]);
// restore the complete MAC state
uint8_t cOcts[14] = { 0 }; // see Wiki dev notes for this odd size uint8_t cOcts[14] = { 0 }; // see Wiki dev notes for this odd size
uint8_t cid; uint8_t cid;
uint8_t cLen = 0; uint8_t cLen;
// for dynamic bands, the additional channels must be restored per-channel // for dynamic bands, the additional channels must be restored per-channel
if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) {
@ -541,39 +538,64 @@ int16_t LoRaWANNode::setBufferSession(const uint8_t* persistentBuffer) {
} }
} }
// restore the MAC state - ADR needs special care, the rest is straight default // restore the datarate and channels
cid = RADIOLIB_LORAWAN_MAC_LINK_ADR; cid = RADIOLIB_LORAWAN_MAC_LINK_ADR;
cLen = 14; // special internal ADR command cLen = 14; // only apply Dr/Tx field
memcpy(cOcts, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR], cLen); memcpy(cOcts, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR], cLen);
(void)execMacCommand(cid, cOcts, cLen); (void)execMacCommand(cid, cOcts, cLen);
// always restore the channels, so as to adhere to channel hopping between JoinRequests
memcpy(this->channelFlags, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_AVAILABLE_CHANNELS], RADIOLIB_LORAWAN_MAX_NUM_SUBBANDS);
// restore the session status
this->sessionStatus = LoRaWANNode::ntoh<uint8_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_STATUS]);
// check if the session is active, if not, don't restore anything else
if(this->sessionStatus != RADIOLIB_LORAWAN_SESSION_ACTIVE) {
return(RADIOLIB_ERR_NETWORK_NOT_JOINED);
}
// restore the rest of the MAC state
const uint8_t cids[6] = { const uint8_t cids[6] = {
RADIOLIB_LORAWAN_MAC_DUTY_CYCLE, RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP, RADIOLIB_LORAWAN_MAC_DUTY_CYCLE, RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP,
RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP, RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP, RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP, RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP,
RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP, RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP, RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP
}; };
const uint16_t locs[6] = { const uint16_t locs[6] = {
RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE, RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP, RADIOLIB_LORAWAN_SESSION_DUTY_CYCLE, RADIOLIB_LORAWAN_SESSION_RX_PARAM_SETUP,
RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP, RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP, RADIOLIB_LORAWAN_SESSION_RX_TIMING_SETUP, RADIOLIB_LORAWAN_SESSION_TX_PARAM_SETUP,
RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP, RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP RADIOLIB_LORAWAN_SESSION_ADR_PARAM_SETUP, RADIOLIB_LORAWAN_SESSION_REJOIN_PARAM_SETUP
}; };
for(uint8_t i = 0; i < 6; i++) { for(uint8_t i = 0; i < 6; i++) {
(void)this->getMacLen(cids[i], &cLen, RADIOLIB_LORAWAN_DOWNLINK); (void)this->getMacLen(cids[i], &cLen, RADIOLIB_LORAWAN_DOWNLINK);
memcpy(cOcts, &this->bufferSession[locs[i]], cLen); memcpy(cOcts, &this->bufferSession[locs[i]], cLen);
(void)execMacCommand(cids[i], cOcts, cLen); (void)execMacCommand(cids[i], cOcts, cLen);
} }
// set the unused channels
memcpy(this->channelFlags, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_AVAILABLE_CHANNELS], RADIOLIB_LORAWAN_MAX_NUM_SUBBANDS);
// copy uplink MAC command queue back in place // copy uplink MAC command queue back in place
memcpy(this->fOptsUp, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE], RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN); memcpy(this->fOptsUp, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE], RADIOLIB_LORAWAN_FHDR_FOPTS_MAX_LEN);
memcpy(&this->fOptsUpLen, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_LEN], 1); memcpy(&this->fOptsUpLen, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_MAC_QUEUE_LEN], 1);
// restore authentication keys
this->devAddr = LoRaWANNode::ntoh<uint32_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DEV_ADDR]);
memcpy(this->appSKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_APP_SKEY], RADIOLIB_AES128_BLOCK_SIZE);
memcpy(this->nwkSEncKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY], RADIOLIB_AES128_BLOCK_SIZE);
memcpy(this->fNwkSIntKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY], RADIOLIB_AES128_BLOCK_SIZE);
memcpy(this->sNwkSIntKey, &this->bufferSession[RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY], RADIOLIB_AES128_BLOCK_SIZE);
// restore session parameters
this->rev = LoRaWANNode::ntoh<uint8_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION]);
this->lwClass = LoRaWANNode::ntoh<uint8_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CLASS]);
this->homeNetId = LoRaWANNode::ntoh<uint32_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_HOMENET_ID]);
this->aFCntDown = LoRaWANNode::ntoh<uint32_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_A_FCNT_DOWN]);
this->nFCntDown = LoRaWANNode::ntoh<uint32_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_N_FCNT_DOWN]);
this->confFCntUp = LoRaWANNode::ntoh<uint32_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_UP]);
this->confFCntDown = LoRaWANNode::ntoh<uint32_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_CONF_FCNT_DOWN]);
this->adrFCnt = LoRaWANNode::ntoh<uint32_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_ADR_FCNT]);
this->fCntUp = LoRaWANNode::ntoh<uint32_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_FCNT_UP]);
// as both the Nonces and session are restored, revert to active session // as both the Nonces and session are restored, revert to active session
this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; this->sessionStatus = RADIOLIB_LORAWAN_SESSION_PENDING;
return(state); return(state);
} }
@ -582,8 +604,9 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, const uint8_t*
if(!appKey) { if(!appKey) {
return(RADIOLIB_ERR_NULL_POINTER); return(RADIOLIB_ERR_NULL_POINTER);
} }
// clear all the device credentials in case there were any // clear all the device parameters in case there were any
this->clearNonces(); this->clearNonces();
this->clearSession();
this->joinEUI = joinEUI; this->joinEUI = joinEUI;
this->devEUI = devEUI; this->devEUI = devEUI;
@ -603,9 +626,6 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, const uint8_t*
this->lwMode = RADIOLIB_LORAWAN_MODE_OTAA; this->lwMode = RADIOLIB_LORAWAN_MODE_OTAA;
// set all MAC properties to default values
this->resetSession();
return(RADIOLIB_ERR_NONE); return(RADIOLIB_ERR_NONE);
} }
@ -613,8 +633,9 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, const uint8_t* fNwkSIntKey, const u
if(!nwkSEncKey || !appSKey) { if(!nwkSEncKey || !appSKey) {
return(RADIOLIB_ERR_NULL_POINTER); return(RADIOLIB_ERR_NULL_POINTER);
} }
// clear all the device credentials in case there were any // clear all the device parameters in case there were any
this->clearNonces(); this->clearNonces();
this->clearSession();
this->devAddr = addr; this->devAddr = addr;
memcpy(this->appSKey, appSKey, RADIOLIB_AES128_KEY_SIZE); memcpy(this->appSKey, appSKey, RADIOLIB_AES128_KEY_SIZE);
@ -637,13 +658,6 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, const uint8_t* fNwkSIntKey, const u
this->lwMode = RADIOLIB_LORAWAN_MODE_ABP; this->lwMode = RADIOLIB_LORAWAN_MODE_ABP;
// set all MAC properties to default values
this->resetSession();
if(this->rev == 1) {
LoRaWANNode::pushMacCommand(RADIOLIB_LORAWAN_MAC_RESET, &this->rev, this->fOptsUp, &this->fOptsUpLen, RADIOLIB_LORAWAN_UPLINK);
}
return(RADIOLIB_ERR_NONE); return(RADIOLIB_ERR_NONE);
} }
@ -836,9 +850,6 @@ int16_t LoRaWANNode::processJoinAccept(LoRaWANJoinEvent_t *joinEvent) {
LoRaWANNode::hton<uint32_t>(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_JOIN_NONCE], this->joinNonce, 3); LoRaWANNode::hton<uint32_t>(&this->bufferNonces[RADIOLIB_LORAWAN_NONCES_JOIN_NONCE], this->joinNonce, 3);
this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true;
this->bufferSession[RADIOLIB_LORAWAN_SESSION_ACTIVE] = (uint8_t)true;
// store DevAddr and all keys // store DevAddr and all keys
LoRaWANNode::hton<uint32_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DEV_ADDR], this->devAddr); LoRaWANNode::hton<uint32_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_DEV_ADDR], this->devAddr);
memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_APP_SKEY], this->appSKey, RADIOLIB_AES128_KEY_SIZE); memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_APP_SKEY], this->appSKey, RADIOLIB_AES128_KEY_SIZE);
@ -850,8 +861,6 @@ int16_t LoRaWANNode::processJoinAccept(LoRaWANJoinEvent_t *joinEvent) {
LoRaWANNode::hton<uint32_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_HOMENET_ID], this->homeNetId); LoRaWANNode::hton<uint32_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_HOMENET_ID], this->homeNetId);
LoRaWANNode::hton<uint8_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION], this->rev); LoRaWANNode::hton<uint8_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION], this->rev);
this->isActive = true;
// received JoinAccept, so update JoinNonce value in event // received JoinAccept, so update JoinNonce value in event
if(joinEvent) { if(joinEvent) {
joinEvent->joinNonce = this->joinNonce; joinEvent->joinNonce = this->joinNonce;
@ -861,17 +870,29 @@ int16_t LoRaWANNode::processJoinAccept(LoRaWANJoinEvent_t *joinEvent) {
} }
int16_t LoRaWANNode::activateOTAA(LoRaWANJoinEvent_t *joinEvent) { int16_t LoRaWANNode::activateOTAA(LoRaWANJoinEvent_t *joinEvent) {
// only allow OTAA mode
if(this->lwMode != RADIOLIB_LORAWAN_MODE_OTAA) {
return(RADIOLIB_ERR_INVALID_MODE);
}
// check if there is an active session // check if there is an active session
if(this->isActivated()) { if(this->isActivated()) {
// already activated, don't do anything // already activated, don't do anything
return(RADIOLIB_ERR_NONE); return(RADIOLIB_ERR_NONE);
} }
if(this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE]) {
// check if there is a restored session
if(this->sessionStatus == RADIOLIB_LORAWAN_SESSION_PENDING) {
// session restored but not yet activated - do so now // session restored but not yet activated - do so now
this->isActive = true; this->sessionStatus = RADIOLIB_LORAWAN_SESSION_ACTIVE;
return(RADIOLIB_LORAWAN_SESSION_RESTORED); return(RADIOLIB_LORAWAN_SESSION_RESTORED);
} }
// if there is no session, reset everything to defaults
if(this->sessionStatus == RADIOLIB_LORAWAN_SESSION_NONE) {
this->createSession();
}
// starting a new session, so make sure to update event fields already // starting a new session, so make sure to update event fields already
if(joinEvent) { if(joinEvent) {
joinEvent->newSession = true; joinEvent->newSession = true;
@ -928,24 +949,34 @@ int16_t LoRaWANNode::activateOTAA(LoRaWANJoinEvent_t *joinEvent) {
(void)this->calculateChannelFlags(); (void)this->calculateChannelFlags();
this->sessionStatus = RADIOLIB_LORAWAN_SESSION_ACTIVE;
return(RADIOLIB_LORAWAN_NEW_SESSION); return(RADIOLIB_LORAWAN_NEW_SESSION);
} }
int16_t LoRaWANNode::activateABP() { int16_t LoRaWANNode::activateABP() {
// only allow ABP mode
if(this->lwMode != RADIOLIB_LORAWAN_MODE_ABP) {
return(RADIOLIB_ERR_INVALID_MODE);
}
// check if there is an active session // check if there is an active session
if(this->isActivated()) { if(this->isActivated()) {
// already activated, don't do anything // already activated, don't do anything
return(RADIOLIB_ERR_NONE); return(RADIOLIB_ERR_NONE);
} }
if(this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE]) {
// check if there is a restored session
if(this->sessionStatus == RADIOLIB_LORAWAN_SESSION_PENDING) {
// session restored but not yet activated - do so now // session restored but not yet activated - do so now
this->isActive = true; this->sessionStatus = RADIOLIB_LORAWAN_SESSION_ACTIVE;
return(RADIOLIB_LORAWAN_SESSION_RESTORED); return(RADIOLIB_LORAWAN_SESSION_RESTORED);
} }
// new session all good, so set active-bit to true // if there is no session, reset everything to defaults
this->bufferNonces[RADIOLIB_LORAWAN_NONCES_ACTIVE] = (uint8_t)true; if(this->sessionStatus == RADIOLIB_LORAWAN_SESSION_NONE) {
this->bufferSession[RADIOLIB_LORAWAN_SESSION_ACTIVE] = (uint8_t)true; this->createSession();
}
// generate the signature of the Nonces buffer, and store it in the last two bytes of the Nonces buffer // generate the signature of the Nonces buffer, and store it in the last two bytes of the Nonces buffer
// also store this signature in the Session buffer to make sure these buffers match // also store this signature in the Session buffer to make sure these buffers match
@ -964,7 +995,11 @@ int16_t LoRaWANNode::activateABP() {
LoRaWANNode::hton<uint32_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_HOMENET_ID], this->homeNetId); LoRaWANNode::hton<uint32_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_HOMENET_ID], this->homeNetId);
LoRaWANNode::hton<uint8_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION], this->rev); LoRaWANNode::hton<uint8_t>(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_VERSION], this->rev);
this->isActive = true; if(this->rev == 1) {
LoRaWANNode::pushMacCommand(RADIOLIB_LORAWAN_MAC_RESET, &this->rev, this->fOptsUp, &this->fOptsUpLen, RADIOLIB_LORAWAN_UPLINK);
}
this->sessionStatus = RADIOLIB_LORAWAN_SESSION_ACTIVE;
return(RADIOLIB_LORAWAN_NEW_SESSION); return(RADIOLIB_LORAWAN_NEW_SESSION);
} }
@ -1016,7 +1051,7 @@ void LoRaWANNode::processCFList(const uint8_t* cfList) {
} }
bool LoRaWANNode::isActivated() { bool LoRaWANNode::isActivated() {
return(this->isActive); return(this->sessionStatus == RADIOLIB_LORAWAN_SESSION_ACTIVE);
} }
int16_t LoRaWANNode::setClass(uint8_t cls) { int16_t LoRaWANNode::setClass(uint8_t cls) {
@ -1192,7 +1227,7 @@ void LoRaWANNode::adrBackoff() {
} }
// last resort: enable all (default) channels // last resort: enable all (default) channels
this->addDefaultChannels(); this->enableDefaultChannels();
// re-enabling default channels may have enabled channels that do support // re-enabling default channels may have enabled channels that do support
// the next required datarate; if datarate can be decreased, try it // the next required datarate; if datarate can be decreased, try it
@ -2209,7 +2244,7 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin
// only apply channel mask if present (internal Dr/Tx commands do not set channel mask) // only apply channel mask if present (internal Dr/Tx commands do not set channel mask)
chMaskAck = true; chMaskAck = true;
if(lenIn > 1) { if(lenIn > 1) {
this->addDefaultChannels(true); this->enableDefaultChannels(true);
for(int i = 0; i < RADIOLIB_LORAWAN_MAX_NUM_FIXED_CHANNELS / 16; i++) { for(int i = 0; i < RADIOLIB_LORAWAN_MAX_NUM_FIXED_CHANNELS / 16; i++) {
uint16_t m8 = (uint16_t)optIn[1 + 2*i] | ((uint16_t)optIn[2 + 2*i] << 8); uint16_t m8 = (uint16_t)optIn[1 + 2*i] | ((uint16_t)optIn[2 + 2*i] << 8);
uint16_t m16 = this->channelMasks[i]; uint16_t m16 = this->channelMasks[i];
@ -2412,12 +2447,15 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin
uint8_t macDrMax = (optIn[4] & 0xF0) >> 4; uint8_t macDrMax = (optIn[4] & 0xF0) >> 4;
uint8_t macDrMin = optIn[4] & 0x0F; uint8_t macDrMin = optIn[4] & 0x0F;
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("NewChannelReq: index = %d, freq = %7.3f MHz, DR %d-%d",
macChIndex, macFreq / 10000.0, macDrMin, macDrMax);
uint8_t drAck = 0; uint8_t drAck = 0;
uint8_t freqAck = 0; uint8_t freqAck = 0;
// the default channels shall not be modified, so check if this is a default channel // the default channels shall not be modified, so check if this is a default channel
// if the channel index is set, this channel is defined, so return a NACK // if the channel index is set, this channel is defined, so return a NACK
if(macChIndex < 3 && this->band->txFreqs[macChIndex].idx != RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE) { if(macChIndex < 3 && this->band->txFreqs[macChIndex].freq > 0) {
optOut[0] = 0; optOut[0] = 0;
return(true); return(true);
} }
@ -2457,39 +2495,19 @@ bool LoRaWANNode::execMacCommand(uint8_t cid, uint8_t* optIn, uint8_t lenIn, uin
// downlink channel is identical to uplink channel // downlink channel is identical to uplink channel
this->dynamicChannels[RADIOLIB_LORAWAN_DOWNLINK][macChIndex] = this->dynamicChannels[RADIOLIB_LORAWAN_UPLINK][macChIndex]; this->dynamicChannels[RADIOLIB_LORAWAN_DOWNLINK][macChIndex] = this->dynamicChannels[RADIOLIB_LORAWAN_UPLINK][macChIndex];
// add the new channel (unless this happens during session restore) // add the new channel
if(this->isActivated()) {
this->channelMasks[0] |= (0x0001 << macChIndex); this->channelMasks[0] |= (0x0001 << macChIndex);
this->channelFlags[0] |= (0x0001 << macChIndex); this->channelFlags[0] |= (0x0001 << macChIndex);
}
} else { } else {
this->dynamicChannels[RADIOLIB_LORAWAN_UPLINK][macChIndex] = RADIOLIB_LORAWAN_CHANNEL_NONE; this->dynamicChannels[RADIOLIB_LORAWAN_UPLINK][macChIndex] = RADIOLIB_LORAWAN_CHANNEL_NONE;
this->dynamicChannels[RADIOLIB_LORAWAN_DOWNLINK][macChIndex] = RADIOLIB_LORAWAN_CHANNEL_NONE; this->dynamicChannels[RADIOLIB_LORAWAN_DOWNLINK][macChIndex] = RADIOLIB_LORAWAN_CHANNEL_NONE;
// remove this channel (unless this happens during session restore) // remove this channel
if(this->isActivated()) {
this->channelMasks[0] &= ~(0x0001 << macChIndex); this->channelMasks[0] &= ~(0x0001 << macChIndex);
this->channelFlags[0] &= ~(0x0001 << macChIndex); this->channelFlags[0] &= ~(0x0001 << macChIndex);
} }
}
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("UL: %3d %7.3f (%d - %d) | DL: %3d %7.3f (%d - %d)",
this->dynamicChannels[RADIOLIB_LORAWAN_UPLINK][macChIndex].idx,
this->dynamicChannels[RADIOLIB_LORAWAN_UPLINK][macChIndex].freq / 10000.0,
this->dynamicChannels[RADIOLIB_LORAWAN_UPLINK][macChIndex].drMin,
this->dynamicChannels[RADIOLIB_LORAWAN_UPLINK][macChIndex].drMax,
this->dynamicChannels[RADIOLIB_LORAWAN_DOWNLINK][macChIndex].idx,
this->dynamicChannels[RADIOLIB_LORAWAN_DOWNLINK][macChIndex].freq / 10000.0,
this->dynamicChannels[RADIOLIB_LORAWAN_DOWNLINK][macChIndex].drMin,
this->dynamicChannels[RADIOLIB_LORAWAN_DOWNLINK][macChIndex].drMax
);
memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS] + macChIndex * lenIn, optIn, lenIn); memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_UL_CHANNELS] + macChIndex * lenIn, optIn, lenIn);
// update the channel masks in the session buffer as we modified a channel
if(this->isActivated()) {
memcpy(&this->bufferSession[RADIOLIB_LORAWAN_SESSION_LINK_ADR] + 1, this->channelMasks, sizeof(this->channelMasks));
}
return(true); return(true);
} break; } break;
@ -3036,6 +3054,11 @@ int16_t LoRaWANNode::setRx2Dr(uint8_t dr) {
return(RADIOLIB_ERR_INVALID_DATA_RATE); return(RADIOLIB_ERR_INVALID_DATA_RATE);
} }
// check if datarate is within the allowed range for Rx2
if(dr < this->band->rx2.drMin || dr > this->band->rx2.drMax) {
return(RADIOLIB_ERR_INVALID_DATA_RATE);
}
// find and check if the datarate is available for this radio module // find and check if the datarate is available for this radio module
DataRate_t dataRate; DataRate_t dataRate;
int16_t state = findDataRate(dr, &dataRate); int16_t state = findDataRate(dr, &dataRate);
@ -3271,11 +3294,10 @@ bool LoRaWANNode::cadChannelClear() {
return(true); return(true);
} }
void LoRaWANNode::addDefaultChannels(bool addDynamic) { void LoRaWANNode::enableDefaultChannels(bool addDynamic) {
if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) { if(this->band->bandType == RADIOLIB_LORAWAN_BAND_DYNAMIC) {
// there are at most three default channels for dynamic bands
// these can never be modified, so we only need to re-enable them
int num = 0; int num = 0;
// there are at most three default channels for dynamic bands
for(; num < 3; num++) { for(; num < 3; num++) {
if(this->band->txFreqs[num].freq) { if(this->band->txFreqs[num].freq) {
this->channelMasks[0] |= (0x0001 << num); this->channelMasks[0] |= (0x0001 << num);

Wyświetl plik

@ -79,7 +79,6 @@
#define RADIOLIB_LORAWAN_BAND_DYNAMIC (0) #define RADIOLIB_LORAWAN_BAND_DYNAMIC (0)
#define RADIOLIB_LORAWAN_BAND_FIXED (1) #define RADIOLIB_LORAWAN_BAND_FIXED (1)
#define RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES (15) #define RADIOLIB_LORAWAN_CHANNEL_NUM_DATARATES (15)
#define RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE (0xFF >> 0)
// recommended default settings // recommended default settings
#define RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS (1000) #define RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS (1000)
@ -218,9 +217,6 @@
#define RADIOLIB_LORAWAN_FPORT_TS009 (224) #define RADIOLIB_LORAWAN_FPORT_TS009 (224)
#define RADIOLIB_LORAWAN_FPORT_TS011 (226) #define RADIOLIB_LORAWAN_FPORT_TS011 (226)
// the length of internal MAC command queue - hopefully this is enough for most use cases
#define RADIOLIB_LORAWAN_MAC_COMMAND_QUEUE_SIZE (9)
// the maximum number of simultaneously available channels // the maximum number of simultaneously available channels
#define RADIOLIB_LORAWAN_MAX_NUM_DYNAMIC_CHANNELS (16) #define RADIOLIB_LORAWAN_MAX_NUM_DYNAMIC_CHANNELS (16)
#define RADIOLIB_LORAWAN_MAX_NUM_SUBBANDS (12) #define RADIOLIB_LORAWAN_MAX_NUM_SUBBANDS (12)
@ -233,6 +229,12 @@
#define RADIOLIB_LORAWAN_MAX_DOWNLINK_SIZE (250) #define RADIOLIB_LORAWAN_MAX_DOWNLINK_SIZE (250)
// session states
#define RADIOLIB_LORAWAN_SESSION_NONE (0x00)
#define RADIOLIB_LORAWAN_SESSION_ACTIVATING (0x01)
#define RADIOLIB_LORAWAN_SESSION_PENDING (0x02)
#define RADIOLIB_LORAWAN_SESSION_ACTIVE (0x03)
// threshold at which sleeping via user callback enabled, in ms // threshold at which sleeping via user callback enabled, in ms
#define RADIOLIB_LORAWAN_DELAY_SLEEP_THRESHOLD (50) #define RADIOLIB_LORAWAN_DELAY_SLEEP_THRESHOLD (50)
@ -328,15 +330,14 @@ enum LoRaWANSchemeBase_t {
RADIOLIB_LORAWAN_NONCES_CHECKSUM = RADIOLIB_LORAWAN_NONCES_PLAN + sizeof(uint8_t), // 2 bytes RADIOLIB_LORAWAN_NONCES_CHECKSUM = RADIOLIB_LORAWAN_NONCES_PLAN + sizeof(uint8_t), // 2 bytes
RADIOLIB_LORAWAN_NONCES_DEV_NONCE = RADIOLIB_LORAWAN_NONCES_CHECKSUM + sizeof(uint16_t), // 2 bytes RADIOLIB_LORAWAN_NONCES_DEV_NONCE = RADIOLIB_LORAWAN_NONCES_CHECKSUM + sizeof(uint16_t), // 2 bytes
RADIOLIB_LORAWAN_NONCES_JOIN_NONCE = RADIOLIB_LORAWAN_NONCES_DEV_NONCE + sizeof(uint16_t), // 3 bytes RADIOLIB_LORAWAN_NONCES_JOIN_NONCE = RADIOLIB_LORAWAN_NONCES_DEV_NONCE + sizeof(uint16_t), // 3 bytes
RADIOLIB_LORAWAN_NONCES_ACTIVE = RADIOLIB_LORAWAN_NONCES_JOIN_NONCE + 3, // 1 byte RADIOLIB_LORAWAN_NONCES_SIGNATURE = RADIOLIB_LORAWAN_NONCES_JOIN_NONCE + 3, // 2 bytes
RADIOLIB_LORAWAN_NONCES_SIGNATURE = RADIOLIB_LORAWAN_NONCES_ACTIVE + sizeof(uint8_t), // 2 bytes
RADIOLIB_LORAWAN_NONCES_BUF_SIZE = RADIOLIB_LORAWAN_NONCES_SIGNATURE + sizeof(uint16_t) // Nonces buffer size RADIOLIB_LORAWAN_NONCES_BUF_SIZE = RADIOLIB_LORAWAN_NONCES_SIGNATURE + sizeof(uint16_t) // Nonces buffer size
}; };
enum LoRaWANSchemeSession_t { enum LoRaWANSchemeSession_t {
RADIOLIB_LORAWAN_SESSION_START = 0x00, RADIOLIB_LORAWAN_SESSION_START = 0x00,
RADIOLIB_LORAWAN_SESSION_ACTIVE = RADIOLIB_LORAWAN_SESSION_START, // 1 byte RADIOLIB_LORAWAN_SESSION_STATUS = RADIOLIB_LORAWAN_SESSION_START, // 1 byte
RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY = RADIOLIB_LORAWAN_SESSION_ACTIVE + 1, // 16 bytes RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY = RADIOLIB_LORAWAN_SESSION_STATUS + 1, // 16 bytes
RADIOLIB_LORAWAN_SESSION_APP_SKEY = RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY + RADIOLIB_AES128_KEY_SIZE, // 16 bytes RADIOLIB_LORAWAN_SESSION_APP_SKEY = RADIOLIB_LORAWAN_SESSION_NWK_SENC_KEY + RADIOLIB_AES128_KEY_SIZE, // 16 bytes
RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY = RADIOLIB_LORAWAN_SESSION_APP_SKEY + RADIOLIB_AES128_KEY_SIZE, // 16 bytes RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY = RADIOLIB_LORAWAN_SESSION_APP_SKEY + RADIOLIB_AES128_KEY_SIZE, // 16 bytes
RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY = RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY + RADIOLIB_AES128_KEY_SIZE, // 16 bytes RADIOLIB_LORAWAN_SESSION_SNWK_SINT_KEY = RADIOLIB_LORAWAN_SESSION_FNWK_SINT_KEY + RADIOLIB_AES128_KEY_SIZE, // 16 bytes
@ -392,8 +393,8 @@ struct LoRaWANChannel_t {
}; };
// alias for unused channel // alias for unused channel
#define RADIOLIB_LORAWAN_CHANNEL_NONE { .idx = RADIOLIB_LORAWAN_CHANNEL_INDEX_NONE, .freq = 0, \ #define RADIOLIB_LORAWAN_CHANNEL_NONE { .idx = 0, .freq = 0, .drMin = 0, .drMax = 0, \
.drMin = 0, .drMax = 0, .dr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED } .dr = RADIOLIB_LORAWAN_DATA_RATE_UNUSED }
/*! /*!
\struct LoRaWANChannelSpan_t \struct LoRaWANChannelSpan_t
@ -610,9 +611,9 @@ class LoRaWANNode {
int16_t setBufferNonces(const uint8_t* persistentBuffer); int16_t setBufferNonces(const uint8_t* persistentBuffer);
/*! /*!
\brief Clear an active session and start a new one. This requires the device to rejoin the network. \brief Clear an active session. This requires the device to rejoin the network.
*/ */
void resetSession(); void clearSession();
/*! /*!
\brief Returns the pointer to the internal buffer that holds the LW session parameters \brief Returns the pointer to the internal buffer that holds the LW session parameters
@ -994,7 +995,7 @@ class LoRaWANNode {
uint16_t lwMode = RADIOLIB_LORAWAN_MODE_NONE; uint16_t lwMode = RADIOLIB_LORAWAN_MODE_NONE;
uint8_t lwClass = RADIOLIB_LORAWAN_CLASS_A; uint8_t lwClass = RADIOLIB_LORAWAN_CLASS_A;
bool isActive = false; uint8_t sessionStatus = RADIOLIB_LORAWAN_SESSION_NONE;
uint64_t joinEUI = 0; uint64_t joinEUI = 0;
uint64_t devEUI = 0; uint64_t devEUI = 0;
@ -1114,6 +1115,9 @@ class LoRaWANNode {
// this will reset the device credentials, so the device starts completely new // this will reset the device credentials, so the device starts completely new
void clearNonces(); void clearNonces();
// setup an empty session with default parameters
void createSession();
// setup Join-Request payload // setup Join-Request payload
void composeJoinRequest(uint8_t* joinRequestMsg); void composeJoinRequest(uint8_t* joinRequestMsg);
@ -1204,8 +1208,8 @@ class LoRaWANNode {
// perform a single CAD operation for the under SF/CH combination. Returns either busy or otherwise. // perform a single CAD operation for the under SF/CH combination. Returns either busy or otherwise.
bool cadChannelClear(); bool cadChannelClear();
// add all default channels on top of the current channels // enable all default channels on top of the current channels
void addDefaultChannels(bool addDynamic = false); void enableDefaultChannels(bool addDynamic = false);
// calculate which channels are available given the current datarate // calculate which channels are available given the current datarate
// returns true if there is any such channel, false otherwise // returns true if there is any such channel, false otherwise