[LoRaWAN] fix include logic

This commit is contained in:
StevenCellist 2023-11-04 07:59:42 +01:00
parent 60f50e0a04
commit ccb28f3b7b
2 changed files with 85 additions and 81 deletions

View file

@ -1,5 +1,4 @@
#include "LoRaWAN.h" #include "LoRaWAN.h"
#include "LoRaWANBands.cpp"
#include <string.h> #include <string.h>
#if !defined(RADIOLIB_EXCLUDE_LORAWAN) #if !defined(RADIOLIB_EXCLUDE_LORAWAN)
@ -19,6 +18,16 @@ static void LoRaWANNodeOnDownlinkAction(void) {
downlinkAction = true; downlinkAction = true;
} }
uint8_t getDownlinkDataRate(uint8_t uplink, uint8_t offset, uint8_t base, uint8_t min, uint8_t max) {
int8_t dr = uplink - offset + base;
if(dr < min) {
dr = min;
} else if (dr > max) {
dr = max;
}
return(dr);
}
LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band) { LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band) {
this->phyLayer = phy; this->phyLayer = phy;
this->band = band; this->band = band;
@ -29,18 +38,18 @@ LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band) {
this->enableCSMA = false; this->enableCSMA = false;
} }
#if !defined(RADIOLIB_EEPROM_UNSUPPORTED)
void LoRaWANNode::wipe() {
Module* mod = this->phyLayer->getMod();
mod->hal->wipePersistentStorage();
}
void LoRaWANNode::setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA) { void LoRaWANNode::setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA) {
this->backoffMax = backoffMax; this->backoffMax = backoffMax;
this->difsSlots = difsSlots; this->difsSlots = difsSlots;
this->enableCSMA = enableCSMA; this->enableCSMA = enableCSMA;
} }
#if !defined(RADIOLIB_EEPROM_UNSUPPORTED)
void LoRaWANNode::wipe() {
Module* mod = this->phyLayer->getMod();
mod->hal->wipePersistentStorage();
}
int16_t LoRaWANNode::restore() { int16_t LoRaWANNode::restore() {
// check the magic value // check the magic value
Module* mod = this->phyLayer->getMod(); Module* mod = this->phyLayer->getMod();
@ -375,7 +384,6 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe
// 1.0 version, just derive the keys // 1.0 version, just derive the keys
LoRaWANNode::hton<uint32_t>(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], this->homeNetId, 3); LoRaWANNode::hton<uint32_t>(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_HOME_NET_ID_POS], this->homeNetId, 3);
LoRaWANNode::hton<uint16_t>(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS], this->devNonce); LoRaWANNode::hton<uint16_t>(&keyDerivationBuff[RADIOLIB_LORAWAN_JOIN_ACCEPT_DEV_ADDR_POS], this->devNonce);
keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY; keyDerivationBuff[0] = RADIOLIB_LORAWAN_JOIN_ACCEPT_APP_S_KEY;
RadioLibAES128Instance.init(nwkKey); RadioLibAES128Instance.init(nwkKey);
RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->appSKey); RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->appSKey);
@ -656,7 +664,6 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf
this->isMACPayload = false; this->isMACPayload = false;
} }
// check if there are some MAC commands to piggyback (only when piggybacking onto a application-frame) // check if there are some MAC commands to piggyback (only when piggybacking onto a application-frame)
uint8_t foptsLen = 0; uint8_t foptsLen = 0;
size_t foptsBufSize = 0; size_t foptsBufSize = 0;
@ -804,7 +811,6 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf
// encrypt the frame payload // encrypt the frame payload
processAES(data, len, encKey, &uplinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(foptsLen)], this->fcntUp, RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, 0x00, true); processAES(data, len, encKey, &uplinkMsg[RADIOLIB_LORAWAN_FRAME_PAYLOAD_POS(foptsLen)], this->fcntUp, RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK, 0x00, true);
// create blocks for MIC calculation // create blocks for MIC calculation
uint8_t block0[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; uint8_t block0[RADIOLIB_AES128_BLOCK_SIZE] = { 0 };
block0[RADIOLIB_LORAWAN_BLOCK_MAGIC_POS] = RADIOLIB_LORAWAN_MIC_BLOCK_MAGIC; block0[RADIOLIB_LORAWAN_BLOCK_MAGIC_POS] = RADIOLIB_LORAWAN_MIC_BLOCK_MAGIC;
@ -838,14 +844,14 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf
LoRaWANNode::hton<uint32_t>(&uplinkMsg[uplinkMsgLen - sizeof(uint32_t)], micF); LoRaWANNode::hton<uint32_t>(&uplinkMsg[uplinkMsgLen - sizeof(uint32_t)], micF);
} }
RADIOLIB_DEBUG_PRINTLN("uplinkMsg:");
RADIOLIB_DEBUG_HEXDUMP(uplinkMsg, uplinkMsgLen);
// perform CSMA if enabled. // perform CSMA if enabled.
if (enableCSMA) { if (enableCSMA) {
performCSMA(); performCSMA();
} }
RADIOLIB_DEBUG_PRINTLN("uplinkMsg:");
RADIOLIB_DEBUG_HEXDUMP(uplinkMsg, uplinkMsgLen);
// send it (without the MIC calculation blocks) // send it (without the MIC calculation blocks)
state = this->phyLayer->transmit(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS], uplinkMsgLen - RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS); state = this->phyLayer->transmit(&uplinkMsg[RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS], uplinkMsgLen - RADIOLIB_LORAWAN_FHDR_LEN_START_OFFS);
@ -2009,6 +2015,50 @@ size_t LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd) {
return(0); return(0);
} }
// The following function enables LMAC, a CSMA scheme for LoRa as specified
// in the LoRa Alliance Technical Recommendation #13.
// A user may enable CSMA to provide frames an additional layer of protection from interference.
// https://resources.lora-alliance.org/technical-recommendations/tr013-1-0-0-csma
void LoRaWANNode::performCSMA() {
// Compute initial random back-off.
// When BO is reduced to zero, the function returns and the frame is transmitted.
uint32_t BO = this->phyLayer->random(1, this->backoffMax + 1);
while (BO > 0) {
// DIFS: Check channel for DIFS_slots
bool channelFreeDuringDIFS = true;
for (uint8_t i = 0; i < this->difsSlots; i++) {
if (performCAD()) {
RADIOLIB_DEBUG_PRINTLN("OCCUPIED CHANNEL DURING DIFS");
channelFreeDuringDIFS = false;
// Channel is occupied during DIFS, hop to another.
this->selectChannels();
break;
}
}
// Start reducing BO counter if DIFS slot was free.
if (channelFreeDuringDIFS) {
// Continue decrementing BO with per each CAD reporting free channel.
while (BO > 0) {
if (performCAD()) {
RADIOLIB_DEBUG_PRINTLN("OCCUPIED CHANNEL DURING BO");
// Channel is busy during CAD, hop to another and return to DIFS state again.
this->selectChannels();
break; // Exit loop. Go back to DIFS state.
}
BO--; // Decrement BO by one if channel is free
}
}
}
}
bool LoRaWANNode::performCAD() {
int16_t state = this->phyLayer->scanChannel();
if ((state == RADIOLIB_PREAMBLE_DETECTED) || (state == RADIOLIB_LORA_DETECTED)) {
return true; // Channel is busy
}
return false; // Channel is free
}
void LoRaWANNode::processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fcnt, uint8_t dir, uint8_t ctrId, bool counter) { void LoRaWANNode::processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fcnt, uint8_t dir, uint8_t ctrId, bool counter) {
// figure out how many encryption blocks are there // figure out how many encryption blocks are there
size_t numBlocks = len/RADIOLIB_AES128_BLOCK_SIZE; size_t numBlocks = len/RADIOLIB_AES128_BLOCK_SIZE;
@ -2076,52 +2126,4 @@ void LoRaWANNode::hton(uint8_t* buff, T val, size_t size) {
} }
} }
// The following function enables LMAC, a CSMA scheme for LoRa as specified
// in the LoRa Alliance Technical Recommendation #13.
// A user may enable CSMA to provide frames an additional layer of protection from interference.
// https://resources.lora-alliance.org/technical-recommendations/tr013-1-0-0-csma
void LoRaWANNode::performCSMA() {
// Compute initial random back-off.
// When BO is reduced to zero, the function returns and the frame is transmitted.
uint32_t BO = this->phyLayer->random(1, this->backoffMax + 1);
while (BO > 0) {
// DIFS: Check channel for DIFS_slots
bool channelFreeDuringDIFS = true;
for (uint8_t i = 0; i < this->difsSlots; i++) {
if (performCAD()) {
RADIOLIB_DEBUG_PRINTLN("OCCUPIED CHANNEL DURING DIFS");
channelFreeDuringDIFS = false;
// Channel is occupied during DIFS, hop to another.
this->selectChannels();
break;
}
}
// Start reducing BO counter if DIFS slot was free.
if (channelFreeDuringDIFS) {
// Continue decrementing BO with per each CAD reporting free channel.
while (BO > 0) {
if (performCAD()) {
RADIOLIB_DEBUG_PRINTLN("OCCUPIED CHANNEL DURING BO");
// Channel is busy during CAD, hop to another and return to DIFS state again.
this->selectChannels();
break; // Exit loop. Go back to DIFS state.
}
BO--; // Decrement BO by one if channel is free
}
}
}
}
bool LoRaWANNode::performCAD() {
int16_t state = this->phyLayer->scanChannel();
if ((state == RADIOLIB_PREAMBLE_DETECTED) || (state == RADIOLIB_LORA_DETECTED)) {
return true; // Channel is busy
}
return false; // Channel is free
}
#endif #endif

View file

@ -338,9 +338,11 @@ class LoRaWANNode {
// RX2 channel properties - may be changed by MAC command // RX2 channel properties - may be changed by MAC command
LoRaWANChannel_t rx2; LoRaWANChannel_t rx2;
/*! \brief Num of Back Off(BO) slots to be decremented after DIFS phase. 0 to disable BO. /*!
\brief Num of Back Off(BO) slots to be decremented after DIFS phase. 0 to disable BO.
A random BO avoids collisions in the case where two or more nodes start the CSMA A random BO avoids collisions in the case where two or more nodes start the CSMA
process at the same time. */ process at the same time.
*/
uint8_t backoffMax; uint8_t backoffMax;
/*! \brief Num of CADs to estimate a clear CH. */ /*! \brief Num of CADs to estimate a clear CH. */
@ -370,14 +372,6 @@ class LoRaWANNode {
int16_t restore(); int16_t restore();
#endif #endif
/*!
\brief Configures CSMA for LoRaWAN as per TR-13, LoRa Alliance.
\param backoffMax Num of BO slots to be decremented after DIFS phase. 0 to disable BO.
\param difsSlots Num of CADs to estimate a clear CH.
\param enableCSMA enable/disable CSMA for LoRaWAN.
*/
void setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA = false);
/*! /*!
\brief Join network by performing over-the-air activation. By this procedure, \brief Join network by performing over-the-air activation. By this procedure,
the device will perform an exchange with the network server and set all necessary configuration. the device will perform an exchange with the network server and set all necessary configuration.
@ -500,6 +494,14 @@ class LoRaWANNode {
*/ */
int16_t selectSubband(uint8_t startChannel, uint8_t endChannel); int16_t selectSubband(uint8_t startChannel, uint8_t endChannel);
/*!
\brief Configures CSMA for LoRaWAN as per TR-13, LoRa Alliance.
\param backoffMax Num of BO slots to be decremented after DIFS phase. 0 to disable BO.
\param difsSlots Num of CADs to estimate a clear CH.
\param enableCSMA enable/disable CSMA for LoRaWAN.
*/
void setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA = false);
#if !defined(RADIOLIB_GODMODE) #if !defined(RADIOLIB_GODMODE)
private: private:
#endif #endif
@ -628,6 +630,12 @@ class LoRaWANNode {
// execute mac command, return the number of processed bytes for sequential processing // execute mac command, return the number of processed bytes for sequential processing
size_t execMacCommand(LoRaWANMacCommand_t* cmd); size_t execMacCommand(LoRaWANMacCommand_t* cmd);
// Performs CSMA as per LoRa Alliance Technical Reccomendation 13 (TR-013).
void performCSMA();
// perform a single CAD operation for the under SF/CH combination. Returns either busy or otherwise.
bool performCAD();
// function to encrypt and decrypt payloads // function to encrypt and decrypt payloads
void processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fcnt, uint8_t dir, uint8_t ctrId, bool counter); void processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fcnt, uint8_t dir, uint8_t ctrId, bool counter);
@ -638,12 +646,6 @@ class LoRaWANNode {
// host-to-network conversion method - takes data from host variable and and converts it to network packet endians // host-to-network conversion method - takes data from host variable and and converts it to network packet endians
template<typename T> template<typename T>
static void hton(uint8_t* buff, T val, size_t size = 0); static void hton(uint8_t* buff, T val, size_t size = 0);
// perform a single CAD operation for the under SF/CH combination. Returns either busy or otherwise.
bool performCAD();
// Performs CSMA as per LoRa Alliance Technical Reccomendation 13 (TR-013).
void performCSMA();
}; };
#endif #endif