Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 4 commits into from
Oct 29, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 33 additions & 10 deletions src/modules/SX126x/SX126x.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1702,27 +1702,47 @@ 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,
// default CAD parameters are shown in Semtech AN1200.48, page 41.
uint8_t detPeakValues[6] = { 22, 22, 24, 25, 26, 30};
uint8_t symbolNumValues[6] = { RADIOLIB_SX126X_CAD_ON_2_SYMB,
jgromes marked this conversation as resolved.
Show resolved Hide resolved
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 };
RADIOLIB_SX126X_CAD_ON_2_SYMB,
RADIOLIB_SX126X_CAD_ON_2_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
uint8_t data[7];
data[0] = symbolNumValues[this->spreadingFactor - 5];
data[1] = detPeakValues[this->spreadingFactor - 5];
data[0] = symbolNumValues[this->spreadingFactor - 7];
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;
Expand All @@ -1736,6 +1756,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);
Expand Down Expand Up @@ -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);
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;
Expand Down
55 changes: 54 additions & 1 deletion src/protocols/LoRaWAN/LoRaWAN.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

// perform CSMA if enabled.
if (CSMA_ENABLE) {
performCSMA();
}

RADIOLIB_DEBUG_PRINTLN("uplinkMsg:");
RADIOLIB_DEBUG_HEXDUMP(uplinkMsg, uplinkMsgLen);

Expand Down Expand Up @@ -1762,4 +1767,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 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);
jgromes marked this conversation as resolved.
Show resolved Hide resolved

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
jgromes marked this conversation as resolved.
Show resolved Hide resolved
11 changes: 11 additions & 0 deletions src/protocols/LoRaWAN/LoRaWAN.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,11 @@
// the maximum number of simultaneously available channels
#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.

jgromes marked this conversation as resolved.
Show resolved Hide resolved
/*!
\struct LoRaWANChannelSpan_t
\brief Structure to save information about LoRaWAN channels.
Expand Down Expand Up @@ -502,6 +507,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