Skip to content

Commit

Permalink
[SX128x] Added interface for interrupt-driven CAD (#1085)
Browse files Browse the repository at this point in the history
  • Loading branch information
jgromes committed May 5, 2024
1 parent 86cdefe commit bcd8a05
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
RadioLib SX128x Channel Activity Detection Example
This example uses SX1280 to scan the current LoRa
channel and detect ongoing LoRa transmissions.
Other modules from SX128x family can also be used.
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/

// include the library
#include <RadioLib.h>

// SX1280 has the following connections:
// NSS pin: 10
// DIO1 pin: 2
// NRST pin: 3
// BUSY pin: 9
SX1280 radio = new Module(10, 2, 3, 9);

// or using RadioShield
// https://github.com/jgromes/RadioShield
//SX1280 radio = RadioShield.ModuleA;

void setup() {
Serial.begin(9600);

// initialize SX1280 with default settings
Serial.print(F("[SX1280] Initializing ... "));
int state = radio.begin();
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}

// set the function that will be called
// when LoRa packet or timeout is detected
radio.setDio1Action(setFlag);

// start scanning the channel
Serial.print(F("[SX1280] Starting scan for LoRa preamble ... "));
state = radio.startChannelScan();
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
}
}

// flag to indicate that a packet was detected or CAD timed out
volatile bool scanFlag = false;

// this function is called when a complete packet
// is received by the module
// IMPORTANT: this function MUST be 'void' type
// and MUST NOT have any arguments!
#if defined(ESP8266) || defined(ESP32)
ICACHE_RAM_ATTR
#endif
void setFlag(void) {
// something happened, set the flag
scanFlag = true;
}

void loop() {
// check if the flag is set
if(scanFlag) {
// reset flag
scanFlag = false;

// check CAD result
int state = radio.getChannelScanResult();

if (state == RADIOLIB_LORA_DETECTED) {
// LoRa packet was detected
Serial.println(F("[SX1280] Packet detected!"));

} else if (state == RADIOLIB_CHANNEL_FREE) {
// channel is free
Serial.println(F("[SX1280] Channel is free!"));

} else {
// some other error occurred
Serial.print(F("[SX1280] Failed, code "));
Serial.println(state);

}

// start scanning the channel again
Serial.print(F("[SX1280] Starting scan for LoRa preamble ... "));
state = radio.startChannelScan();
if (state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
}
}
}
81 changes: 48 additions & 33 deletions src/modules/SX128x/SX128x.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -411,28 +411,8 @@ int16_t SX128x::receiveDirect() {
}

int16_t SX128x::scanChannel() {
// check active modem
if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) {
return(RADIOLIB_ERR_WRONG_MODEM);
}

// set mode to standby
int16_t state = standby();
RADIOLIB_ASSERT(state);

// set DIO pin mapping
state = setDioIrqParams(RADIOLIB_SX128X_IRQ_CAD_DETECTED | RADIOLIB_SX128X_IRQ_CAD_DONE, RADIOLIB_SX128X_IRQ_CAD_DETECTED | RADIOLIB_SX128X_IRQ_CAD_DONE);
RADIOLIB_ASSERT(state);

// clear interrupt flags
state = clearIrqStatus();
RADIOLIB_ASSERT(state);

// set RF switch (if present)
this->mod->setRfSwitchState(Module::MODE_RX);

// set mode to CAD
state = setCad();
int16_t state = startChannelScan();
RADIOLIB_ASSERT(state);

// wait for channel activity detected or timeout
Expand All @@ -441,18 +421,7 @@ int16_t SX128x::scanChannel() {
}

// check CAD result
uint16_t cadResult = getIrqStatus();
if(cadResult & RADIOLIB_SX128X_IRQ_CAD_DETECTED) {
// detected some LoRa activity
clearIrqStatus();
return(RADIOLIB_LORA_DETECTED);
} else if(cadResult & RADIOLIB_SX128X_IRQ_CAD_DONE) {
// channel is free
clearIrqStatus();
return(RADIOLIB_CHANNEL_FREE);
}

return(RADIOLIB_ERR_UNKNOWN);
return(getChannelScanResult());
}

int16_t SX128x::sleep(bool retainConfig) {
Expand Down Expand Up @@ -664,6 +633,52 @@ int16_t SX128x::readData(uint8_t* data, size_t len) {
return(state);
}

int16_t SX128x::startChannelScan() {
// check active modem
if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) {
return(RADIOLIB_ERR_WRONG_MODEM);
}

// set mode to standby
int16_t state = standby();
RADIOLIB_ASSERT(state);

// set DIO pin mapping
state = setDioIrqParams(RADIOLIB_SX128X_IRQ_CAD_DETECTED | RADIOLIB_SX128X_IRQ_CAD_DONE, RADIOLIB_SX128X_IRQ_CAD_DETECTED | RADIOLIB_SX128X_IRQ_CAD_DONE);
RADIOLIB_ASSERT(state);

// clear interrupt flags
state = clearIrqStatus();
RADIOLIB_ASSERT(state);

// set RF switch (if present)
this->mod->setRfSwitchState(Module::MODE_RX);

// set mode to CAD
return(setCad());
}

int16_t SX128x::getChannelScanResult() {
// check active modem
if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) {
return(RADIOLIB_ERR_WRONG_MODEM);
}

// check CAD result
uint16_t cadResult = getIrqStatus();
int16_t state = RADIOLIB_ERR_UNKNOWN;
if(cadResult & RADIOLIB_SX128X_IRQ_CAD_DETECTED) {
// detected some LoRa activity
state = RADIOLIB_LORA_DETECTED;
} else if(cadResult & RADIOLIB_SX128X_IRQ_CAD_DONE) {
// channel is free
state = RADIOLIB_CHANNEL_FREE;
}

clearIrqStatus();
return(state);
}

int16_t SX128x::setFrequency(float freq) {
RADIOLIB_CHECK_RANGE(freq, 2400.0, 2500.0, RADIOLIB_ERR_INVALID_FREQUENCY);

Expand Down
13 changes: 13 additions & 0 deletions src/modules/SX128x/SX128x.h
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,19 @@ class SX128x: public PhysicalLayer {
\returns \ref status_codes
*/
int16_t readData(uint8_t* data, size_t len) override;

/*!
\brief Interrupt-driven channel activity detection method. DIO1 will be activated
when LoRa preamble is detected, or upon timeout. Defaults to CAD parameter values recommended by AN1200.48.
\returns \ref status_codes
*/
int16_t startChannelScan() override;

/*!
\brief Read the channel scan result
\returns \ref status_codes
*/
int16_t getChannelScanResult() override;

// configuration methods

Expand Down

0 comments on commit bcd8a05

Please sign in to comment.