Implement session persistence & more 1.1 protocol

This commit is contained in:
StevenCellist 2023-09-19 12:23:48 +02:00
parent 690a050ebb
commit 42c883e606
4 changed files with 159 additions and 16 deletions

View file

@ -16,6 +16,15 @@
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID (6) #define RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID (6)
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID (7) #define RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID (7)
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_JOIN_NONCE_ID (8)
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_HOME_NET_ID (9)
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_DL_SETTINGS_ID (10)
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX_DELAY_ID (11)
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_CF_LIST_ID (12)
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_NFCNT_DOWN_ID (13)
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_AFCNT_DOWN_ID (14)
#define RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_ID (15)
static const uint32_t RadioLibPersistentParamTable[] = { static const uint32_t RadioLibPersistentParamTable[] = {
0x00, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID 0x00, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_NONCE_ID
0x04, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID 0x04, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_DEV_ADDR_ID
@ -25,7 +34,16 @@ static const uint32_t RadioLibPersistentParamTable[] = {
0x20, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID 0x20, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID
0x30, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID 0x30, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID
0x40, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID 0x40, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID
0x50, // end
0x50, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_JOIN_NONCE_ID
0x54, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_HOME_NET_ID
0x58, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_DL_SETTINGS_ID
0x5C, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX_DELAY_ID
0x60, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_CF_LIST
0x70, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_NFCNT_DOWN_ID
0x74, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_AFCNT_DOWN_ID
0x78, // RADIOLIB_PERSISTENT_PARAM_LORAWAN_CONF_FCNT_ID
0x7C, // end
}; };
/*! /*!

View file

@ -533,6 +533,11 @@
*/ */
#define RADIOLIB_ERR_COMMAND_QUEUE_EMPTY (-1110) #define RADIOLIB_ERR_COMMAND_QUEUE_EMPTY (-1110)
/*!
\brief Unable to join network because JoinNonce is not higher than saved value.
*/
#define RADIOLIB_ERR_JOIN_NONCE_INVALID (-1111)
/*! /*!
\} \}
*/ */

View file

@ -44,7 +44,7 @@ void LoRaWANNode::wipe() {
mod->hal->wipePersistentStorage(); mod->hal->wipePersistentStorage();
} }
int16_t LoRaWANNode::begin() { int16_t LoRaWANNode::begin(bool otaa) {
int16_t state = this->setPhyProperties(); int16_t state = this->setPhyProperties();
RADIOLIB_ASSERT(state); RADIOLIB_ASSERT(state);
@ -61,6 +61,86 @@ int16_t LoRaWANNode::begin() {
mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE);
mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE);
mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE);
RADIOLIB_DEBUG_PRINTLN("appSKey:");
RADIOLIB_DEBUG_HEXDUMP(this->appSKey, RADIOLIB_AES128_BLOCK_SIZE);
// in case of ABP, we are done already
if (!otaa) {
return(RADIOLIB_ERR_NONE);
}
uint32_t dlSettings = mod->hal->getPersistentParameter<uint32_t>(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DL_SETTINGS_ID);
this->rev = (dlSettings & RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_1) >> 7;
uint8_t rx1DrOffset = (dlSettings & 0x70) >> 4;
uint8_t rx2DataRate = dlSettings & 0x0F;
RADIOLIB_DEBUG_PRINTLN("LoRaWAN revision: %d", this->rev);
// TODO process the RX2 data rate
(void)rx2DataRate;
// TODO process the data rate offset
(void)rx1DrOffset;
// parse Rx1 delay (and subsequently Rx2)
this->rxDelays[0] = mod->hal->getPersistentParameter<uint32_t>(RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX_DELAY_ID);
if(this->rxDelays[0] == 0) {
this->rxDelays[0] = RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS;
}
this->rxDelays[1] = this->rxDelays[0] + 1000;
// process CFlist if any bit is non-zero
uint8_t cfList[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN] = { 0 };
uint8_t allZero[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN] = { 0 };
mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_CF_LIST_ID), cfList, RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN);
RADIOLIB_DEBUG_PRINTLN("cfList:");
RADIOLIB_DEBUG_HEXDUMP(cfList, RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN);
if(memcmp(cfList, allZero, RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN)) {
if(this->band->cfListType == RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES) {
// list of frequencies
for(uint8_t i = 0; i < 5; i++) {
uint32_t freq = LoRaWANNode::ntoh<uint32_t>(&cfList[3*i], 3);
availableChannelsFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i] = (float)freq/10000.0;
availableChannelsFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_DOWNLINK][i] = availableChannelsFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i];
RADIOLIB_DEBUG_PRINTLN("Channel UL/DL %d frequency = %f MHz", i, availableChannelsFreq[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK][i]);
}
} else {
// frequency mask, we need to find out which frequencies are actually being used
uint8_t channelId = 0;
uint8_t chSpan = 0;
uint8_t chNum = 0;
for(uint8_t i = 0; i < 5; i++) {
uint16_t mask = LoRaWANNode::ntoh<uint16_t>(&cfList[2*i]);
RADIOLIB_DEBUG_PRINTLN("mask[%d] = 0x%04x", i, mask);
for(uint8_t j = 0; j < 16; j++) {
if(chNum >= this->band->defaultChannels[chSpan].numChannels) {
chNum -= this->band->defaultChannels[chSpan].numChannels;
chSpan++;
if(chSpan >= this->band->numChannelSpans) {
RADIOLIB_DEBUG_PRINTLN("channel bitmask overrun!");
return(RADIOLIB_ERR_UNKNOWN);
}
}
if(mask & (1UL << j)) {
RADIOLIB_DEBUG_PRINTLN("chNum = %d, chSpan = %d", chNum, chSpan);
uint8_t dir = this->band->defaultChannels[chSpan].direction;
float freq = this->band->defaultChannels[chSpan].freqStart + chNum*this->band->defaultChannels[chSpan].freqStep;
availableChannelsFreq[dir][channelId] = freq;
RADIOLIB_DEBUG_PRINTLN("Channel %cL %d frequency = %f MHz", dir ? 'U': 'D', channelId, availableChannelsFreq[dir][channelId]);
channelId++;
}
chNum++;
}
}
}
}
state = this->setupChannels();
RADIOLIB_ASSERT(state);
return(RADIOLIB_ERR_NONE); return(RADIOLIB_ERR_NONE);
} }
@ -177,7 +257,9 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe
// check LoRaWAN revision (the MIC verification depends on this) // check LoRaWAN revision (the MIC verification depends on this)
uint8_t dlSettings = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_DL_SETTINGS_POS]; uint8_t dlSettings = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_DL_SETTINGS_POS];
if(dlSettings & RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_1) { this->rev = (dlSettings & RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_1) >> 7;
RADIOLIB_DEBUG_PRINTLN("LoRaWAN revision: 1.%d", this->rev);
if(this->rev == 1) {
// 1.1 version, first we need to derive the join accept integrity key // 1.1 version, first we need to derive the join accept integrity key
uint8_t keyDerivationBuff[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; uint8_t keyDerivationBuff[RADIOLIB_AES128_BLOCK_SIZE] = { 0 };
keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_JS_INT_KEY; keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_JS_INT_KEY;
@ -203,11 +285,28 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe
} }
} }
uint8_t rx1DrOffset = (dlSettings & 0x70) >> 4;
uint8_t rx2DataRate = dlSettings & 0x0F;
// parse the contents // TODO process the RX2 data rate
(void)rx2DataRate;
// TODO process the data rate offset
(void)rx1DrOffset;
// get & compare JoinNonce: should be higher than value saved in non-volatile storage
uint32_t joinNonce = LoRaWANNode::ntoh<uint32_t>(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS], 3); uint32_t joinNonce = LoRaWANNode::ntoh<uint32_t>(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS], 3);
uint32_t joinNonceOld = mod->hal->getPersistentParameter<uint32_t>(RADIOLIB_PERSISTENT_PARAM_LORAWAN_JOIN_NONCE_ID);
RADIOLIB_DEBUG_PRINTLN("JoinNonceOld: %d, JoinNonce: %d", joinNonceOld, joinNonce);
if(joinNonce <= joinNonceOld) {
return(RADIOLIB_ERR_JOIN_NONCE_INVALID);
}
// parse other contents
uint32_t homeNetId = LoRaWANNode::ntoh<uint32_t>(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], 3); uint32_t homeNetId = LoRaWANNode::ntoh<uint32_t>(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], 3);
this->devAddr = LoRaWANNode::ntoh<uint32_t>(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS]); this->devAddr = LoRaWANNode::ntoh<uint32_t>(&joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS]);
// parse Rx1 delay (and subsequently Rx2)
this->rxDelays[0] = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_RX_DELAY_POS]*1000; this->rxDelays[0] = joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_RX_DELAY_POS]*1000;
if(this->rxDelays[0] == 0) { if(this->rxDelays[0] == 0) {
this->rxDelays[0] = RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS; this->rxDelays[0] = RADIOLIB_LORAWAN_RECEIVE_DELAY_1_MS;
@ -215,7 +314,9 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe
this->rxDelays[1] = this->rxDelays[0] + 1000; this->rxDelays[1] = this->rxDelays[0] + 1000;
// process CFlist if present // process CFlist if present
uint8_t cfList[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN] = { 0 };
if(lenRx == RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN) { if(lenRx == RADIOLIB_LORAWAN_JOIN_ACCEPT_MAX_LEN) {
memcpy(&cfList[0], &joinAcceptMsg[RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_POS], RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN);
if(this->band->cfListType == RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES) { if(this->band->cfListType == RADIOLIB_LORAWAN_CFLIST_TYPE_FREQUENCIES) {
// list of frequencies // list of frequencies
for(uint8_t i = 0; i < 5; i++) { for(uint8_t i = 0; i < 5; i++) {
@ -258,7 +359,6 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe
} }
} }
} }
// prepare buffer for key derivation // prepare buffer for key derivation
@ -266,7 +366,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe
LoRaWANNode::hton<uint32_t>(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS], joinNonce, 3); LoRaWANNode::hton<uint32_t>(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_JOIN_NONCE_POS], joinNonce, 3);
// check protocol version (1.0 vs 1.1) // check protocol version (1.0 vs 1.1)
if(dlSettings & RADIOLIB_LORAWAN_JOIN_ACCEPT_R_1_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], devNonce); LoRaWANNode::hton<uint16_t>(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_NONCE_POS], devNonce);
@ -288,7 +388,6 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe
RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->nwkSEncKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->nwkSEncKey);
// enqueue the RekeyInd MAC command to be sent in the next uplink // enqueue the RekeyInd MAC command to be sent in the next uplink
this->rev = 1;
LoRaWANMacCommand_t cmd = { LoRaWANMacCommand_t cmd = {
.cid = RADIOLIB_LORAWAN_MAC_CMD_REKEY, .cid = RADIOLIB_LORAWAN_MAC_CMD_REKEY,
.len = sizeof(uint8_t), .len = sizeof(uint8_t),
@ -300,7 +399,6 @@ 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
this->rev = 0;
LoRaWANNode::hton<uint32_t>(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], homeNetId, 3); LoRaWANNode::hton<uint32_t>(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], homeNetId, 3);
LoRaWANNode::hton<uint16_t>(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS], devNonce); LoRaWANNode::hton<uint16_t>(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS], devNonce);
keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY; keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY;
@ -325,8 +423,20 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe
mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE); mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE);
mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE); mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE);
// save uplink parameters
mod->hal->setPersistentParameter<uint32_t>(RADIOLIB_PERSISTENT_PARAM_LORAWAN_JOIN_NONCE_ID, joinNonce);
mod->hal->setPersistentParameter<uint32_t>(RADIOLIB_PERSISTENT_PARAM_LORAWAN_HOME_NET_ID, homeNetId);
mod->hal->setPersistentParameter<uint32_t>(RADIOLIB_PERSISTENT_PARAM_LORAWAN_RX_DELAY_ID, this->rxDelays[0]);
mod->hal->setPersistentParameter<uint32_t>(RADIOLIB_PERSISTENT_PARAM_LORAWAN_DL_SETTINGS_ID, (uint32_t)dlSettings);
// save cfList (all 0 if none is present)
RADIOLIB_DEBUG_PRINTLN("cfList:");
RADIOLIB_DEBUG_HEXDUMP(cfList, RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN);
mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_PERSISTENT_PARAM_LORAWAN_CF_LIST_ID), cfList, RADIOLIB_LORAWAN_JOIN_ACCEPT_CFLIST_LEN);
// all complete, reset device counters and set the magic number // all complete, reset device counters and set the magic number
mod->hal->setPersistentParameter<uint32_t>(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID, 0); mod->hal->setPersistentParameter<uint32_t>(RADIOLIB_PERSISTENT_PARAM_LORAWAN_FCNT_UP_ID, 0);
mod->hal->setPersistentParameter<uint32_t>(RADIOLIB_PERSISTENT_PARAM_LORAWAN_NFCNT_DOWN_ID, 0);
mod->hal->setPersistentParameter<uint32_t>(RADIOLIB_PERSISTENT_PARAM_LORAWAN_AFCNT_DOWN_ID, 0);
mod->hal->setPersistentParameter<uint32_t>(RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID, RADIOLIB_LORAWAN_MAGIC); mod->hal->setPersistentParameter<uint32_t>(RADIOLIB_PERSISTENT_PARAM_LORAWAN_MAGIC_ID, RADIOLIB_LORAWAN_MAGIC);
return(RADIOLIB_ERR_NONE); return(RADIOLIB_ERR_NONE);
} }
@ -435,6 +545,7 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) {
} }
// set the port // set the port
// TODO if FOptsLen > 0, then port must be either not present or > 0 (4.3.1.6)
uplinkMsg[RADIOLIB_LORAWAN_FHDR_FPORT_POS(foptsLen)] = port; uplinkMsg[RADIOLIB_LORAWAN_FHDR_FPORT_POS(foptsLen)] = port;
// select encryption key based on the target port // select encryption key based on the target port
@ -759,9 +870,18 @@ int16_t LoRaWANNode::downlink(uint8_t* data, size_t* len) {
#if !defined(RADIOLIB_STATIC_ONLY) #if !defined(RADIOLIB_STATIC_ONLY)
delete[] downlinkMsg; delete[] downlinkMsg;
#endif #endif
// increase nFcntDown by 1 (MAC downlink only)
uint32_t nFcntDown = mod->hal->getPersistentParameter<uint32_t>(RADIOLIB_PERSISTENT_PARAM_LORAWAN_NFCNT_DOWN_ID);
mod->hal->setPersistentParameter<uint32_t>(RADIOLIB_PERSISTENT_PARAM_LORAWAN_NFCNT_DOWN_ID, nFcntDown + 1);
return(RADIOLIB_ERR_NONE); return(RADIOLIB_ERR_NONE);
} }
// increase aFcntDown by 1 (application downlink with payload)
uint32_t aFcntDown = mod->hal->getPersistentParameter<uint32_t>(RADIOLIB_PERSISTENT_PARAM_LORAWAN_AFCNT_DOWN_ID);
mod->hal->setPersistentParameter<uint32_t>(RADIOLIB_PERSISTENT_PARAM_LORAWAN_AFCNT_DOWN_ID, aFcntDown + 1);
// there is payload, and so there should be a port too // there is payload, and so there should be a port too
// TODO pass the port? // TODO pass the port?
*len = payLen - 1; *len = payLen - 1;

View file

@ -309,7 +309,7 @@ class LoRaWANNode {
\brief Join network by loading information from persistent storage. \brief Join network by loading information from persistent storage.
\returns \ref status_codes \returns \ref status_codes
*/ */
int16_t begin(); int16_t begin(bool otaa = true);
/*! /*!
\brief Join network by performing over-the-air activation. By this procedure, \brief Join network by performing over-the-air activation. By this procedure,