kopia lustrzana https://github.com/jgromes/RadioLib
[LoRaWAN] Fully persistent channel management
rodzic
25df076b16
commit
e11e5f1286
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
Ładowanie…
Reference in New Issue