added functionality for LoRa Alliance TR-13 Enabling CSMA for LoRaWAN

This commit is contained in:
Amalinda 2023-10-28 11:36:32 +08:00
parent 556f37f608
commit da57f1cdef
3 changed files with 98 additions and 11 deletions

View file

@ -1702,27 +1702,47 @@ int16_t SX126x::setRx(uint32_t timeout) {
return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX, data, 3, true, false)); 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) { 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 // default CAD parameters are shown in Semtech AN1200.48, page 41.
uint8_t detPeakValues[8] = { 22, 22, 22, 22, 23, 24, 25, 28}; uint8_t detPeakValues[6] = { 22, 22, 24, 25, 26, 30};
uint8_t symbolNumValues[8] = { RADIOLIB_SX126X_CAD_ON_2_SYMB, uint8_t symbolNumValues[6] = { 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_2_SYMB,
RADIOLIB_SX126X_CAD_ON_2_SYMB, RADIOLIB_SX126X_CAD_ON_2_SYMB,
RADIOLIB_SX126X_CAD_ON_4_SYMB, RADIOLIB_SX126X_CAD_ON_2_SYMB,
RADIOLIB_SX126X_CAD_ON_4_SYMB, RADIOLIB_SX126X_CAD_ON_2_SYMB };
RADIOLIB_SX126X_CAD_ON_4_SYMB,
RADIOLIB_SX126X_CAD_ON_4_SYMB }; // 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 // build the packet
uint8_t data[7]; uint8_t data[7];
data[0] = symbolNumValues[this->spreadingFactor - 5]; data[0] = symbolNumValues[this->spreadingFactor - 7];
data[1] = detPeakValues[this->spreadingFactor - 5]; data[1] = detPeakValues[this->spreadingFactor - 7];
data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN; data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN;
data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY; data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY;
data[4] = 0x00; data[4] = 0x00;
data[5] = 0x00; data[5] = 0x00;
data[6] = 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 // set user-provided values
if(symbolNum != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) { if(symbolNum != RADIOLIB_SX126X_CAD_PARAM_DEFAULT) {
data[0] = symbolNum; data[0] = symbolNum;
@ -1736,6 +1756,9 @@ int16_t SX126x::setCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin) {
data[2] = detMin; data[2] = detMin;
} }
*/
// configure parameters // configure parameters
int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7); int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7);
RADIOLIB_ASSERT(state); RADIOLIB_ASSERT(state);
@ -2030,7 +2053,7 @@ int16_t SX126x::config(uint8_t modem) {
state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1); state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1);
RADIOLIB_ASSERT(state); 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[0] = RADIOLIB_SX126X_CAD_ON_8_SYMB;
data[1] = this->spreadingFactor + 13; data[1] = this->spreadingFactor + 13;
data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN; data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN;

View file

@ -637,6 +637,11 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port) {
LoRaWANNode::hton<uint32_t>(&uplinkMsg[uplinkMsgLen - sizeof(uint32_t)], micF); LoRaWANNode::hton<uint32_t>(&uplinkMsg[uplinkMsgLen - sizeof(uint32_t)], micF);
} }
// perform CSMA if enabled.
if (CSMA_ENABLE) {
performCSMA();
}
RADIOLIB_DEBUG_PRINTLN("uplinkMsg:"); RADIOLIB_DEBUG_PRINTLN("uplinkMsg:");
RADIOLIB_DEBUG_HEXDUMP(uplinkMsg, uplinkMsgLen); RADIOLIB_DEBUG_HEXDUMP(uplinkMsg, uplinkMsgLen);
@ -1762,4 +1767,52 @@ 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 Reccomendation #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 = random(1, BO_MAX + 1);
while (BO > 0) {
// DIFS: Check channel for DIFS_slots
bool channelFreeDuringDIFS = true;
for (uint8_t i = 0; i < DIFS_SLOTS; 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 #endif

View file

@ -176,6 +176,11 @@
// the maximum number of simultaneously available channels // the maximum number of simultaneously available channels
#define RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS (8) #define RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS (8)
// CSMA definitions
#define DIFS_SLOTS (2) // Number of CADs to estimate a clear channel.
#define BO_MAX (6) // Number of maximum CADs to back-off. Set to 0 to disable.
#define CSMA_ENABLE (true) // Enables/disables CSMA functionality.
/*! /*!
\struct LoRaWANChannelSpan_t \struct LoRaWANChannelSpan_t
\brief Structure to save information about LoRaWAN channels. \brief Structure to save information about LoRaWAN channels.
@ -502,6 +507,12 @@ 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