added functionality for LoRa Alliance TR-13 Enabling CSMA for LoRaWAN (#859)
* added functionality for LoRa Alliance TR-13 Enabling CSMA for LoRaWAN * Addressed feedback on CSMA implementation * symbolNumValues[6] array no longer needed as we will utilize only two symbol CAD operations for all SFs.
This commit is contained in:
parent
912333c408
commit
aca1d78a97
3 changed files with 120 additions and 14 deletions
|
@ -1702,27 +1702,41 @@ int16_t SX126x::setRx(uint32_t timeout) {
|
|||
return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX, data, 3, true, false));
|
||||
}
|
||||
|
||||
|
||||
int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) {
|
||||
// default CAD parameters for assigned SF as per Semtech AN1200.48, Rev 2.1, Page 50
|
||||
uint8_t detPeakValues[8] = { 22, 22, 22, 22, 23, 24, 25, 28};
|
||||
uint8_t symbolNumValues[8] = { RADIOLIB_SX126X_CAD_ON_2_SYMB,
|
||||
RADIOLIB_SX126X_CAD_ON_2_SYMB,
|
||||
RADIOLIB_SX126X_CAD_ON_2_SYMB,
|
||||
RADIOLIB_SX126X_CAD_ON_2_SYMB,
|
||||
RADIOLIB_SX126X_CAD_ON_4_SYMB,
|
||||
RADIOLIB_SX126X_CAD_ON_4_SYMB,
|
||||
RADIOLIB_SX126X_CAD_ON_4_SYMB,
|
||||
RADIOLIB_SX126X_CAD_ON_4_SYMB };
|
||||
// default CAD parameters are shown in Semtech AN1200.48, page 41.
|
||||
uint8_t detPeakValues[6] = { 22, 22, 24, 25, 26, 30};
|
||||
|
||||
// CAD parameters aren't available for SF-6. Just to be safe.
|
||||
if(this->spreadingFactor < 7) {
|
||||
this->spreadingFactor = 7;
|
||||
} else if(this->spreadingFactor > 12) {
|
||||
this->spreadingFactor = 12;
|
||||
}
|
||||
|
||||
// build the packet
|
||||
uint8_t data[7];
|
||||
data[0] = symbolNumValues[this->spreadingFactor - 5];
|
||||
data[1] = detPeakValues[this->spreadingFactor - 5];
|
||||
data[0] = RADIOLIB_SX126X_CAD_ON_2_SYMB;
|
||||
data[1] = detPeakValues[this->spreadingFactor - 7];
|
||||
data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN;
|
||||
data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY;
|
||||
data[4] = 0x00;
|
||||
data[5] = 0x00;
|
||||
data[6] = 0x00;
|
||||
|
||||
|
||||
/*
|
||||
CAD Configuration Note:
|
||||
The default CAD configuration applied by `scanChannel` overrides the optimal SF-specific configurations, leading to suboptimal detection.
|
||||
I.e., anything that is not RADIOLIB_SX126X_CAD_PARAM_DEFAULT is overridden. But CAD settings are SF specific.
|
||||
To address this, the user override has been commented out, ensuring consistent application of the optimal CAD settings as
|
||||
per Semtech's Application Note AN1200.48 (page 41) for the 125KHz setting. This approach significantly reduces false CAD occurrences.
|
||||
Testing has shown that there is no reason for a user to change CAD settings for anything other than most optimal ones described in AN1200.48 .
|
||||
However, this change deos not respect CAD configs from the LoRaWAN layer. Future considerations or use cases might require revisiting this decision.
|
||||
Hence this note.
|
||||
*/
|
||||
|
||||
/*
|
||||
// set user-provided values
|
||||
if(symbolNum != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) {
|
||||
data[0] = symbolNum;
|
||||
|
@ -1736,6 +1750,9 @@ int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) {
|
|||
data[2] = detMin;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
// configure parameters
|
||||
int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
@ -2030,7 +2047,7 @@ int16_t SX126x::config(uint8_t modem) {
|
|||
state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set some CAD parameters - will be overwritten whel calling CAD anyway
|
||||
// set some CAD parameters - will be overwritten when calling CAD anyway
|
||||
data[0] = RADIOLIB_SX126X_CAD_ON_8_SYMB;
|
||||
data[1] = this->spreadingFactor + 13;
|
||||
data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN;
|
||||
|
|
|
@ -37,6 +37,10 @@ LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band) {
|
|||
this->startChannel = -1;
|
||||
this->numChannels = -1;
|
||||
this->backupFreq = this->band->backupChannel.freqStart;
|
||||
this->difsSlots = 2;
|
||||
this->backoffMax = 6;
|
||||
this->enableCSMA = false;
|
||||
|
||||
}
|
||||
|
||||
void LoRaWANNode::wipe() {
|
||||
|
@ -44,6 +48,13 @@ void LoRaWANNode::wipe() {
|
|||
mod->hal->wipePersistentStorage();
|
||||
}
|
||||
|
||||
void LoRaWANNode::setCSMA(uint8_t backoffMax, uint8_t difsSlots, bool enableCSMA) {
|
||||
this->backoffMax = backoffMax;
|
||||
this->difsSlots = difsSlots;
|
||||
this->enableCSMA = enableCSMA;
|
||||
}
|
||||
|
||||
|
||||
int16_t LoRaWANNode::restoreOTAA() {
|
||||
int16_t state = this->setPhyProperties();
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
@ -637,6 +648,11 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) {
|
|||
LoRaWANNode::hton<uint32_t>(&uplinkMsg[uplinkMsgLen - sizeof(uint32_t)], micF);
|
||||
}
|
||||
|
||||
// perform CSMA if enabled.
|
||||
if (enableCSMA) {
|
||||
performCSMA();
|
||||
}
|
||||
|
||||
RADIOLIB_DEBUG_PRINTLN("uplinkMsg:");
|
||||
RADIOLIB_DEBUG_HEXDUMP(uplinkMsg, uplinkMsgLen);
|
||||
|
||||
|
@ -1762,4 +1778,52 @@ void LoRaWANNode::hton(uint8_t* buff, T val, size_t size) {
|
|||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
// 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->setupChannels();
|
||||
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->setupChannels();
|
||||
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
|
|
@ -296,6 +296,17 @@ class LoRaWANNode {
|
|||
(e.g. 8 for US915 FSB2 used by TTN). By default -1 (no channel offset). */
|
||||
int8_t numChannels;
|
||||
|
||||
/*! \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
|
||||
process at the same time. */
|
||||
uint8_t backoffMax;
|
||||
|
||||
/*! \brief Num of CADs to estimate a clear CH. */
|
||||
uint8_t difsSlots;
|
||||
|
||||
/*! \brief enable/disable CSMA for LoRaWAN. */
|
||||
bool enableCSMA;
|
||||
|
||||
/*!
|
||||
\brief Default constructor.
|
||||
\param phy Pointer to the PhysicalLayer radio module.
|
||||
|
@ -309,6 +320,14 @@ class LoRaWANNode {
|
|||
*/
|
||||
void wipe();
|
||||
|
||||
/*!
|
||||
\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 Restore OTAA session by loading information from persistent storage.
|
||||
\returns \ref status_codes
|
||||
|
@ -502,6 +521,12 @@ class LoRaWANNode {
|
|||
// host-to-network conversion method - takes data from host variable and and converts it to network packet endians
|
||||
template<typename T>
|
||||
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
|
||||
|
|
Loading…
Add table
Reference in a new issue