diff --git a/API.md b/API.md index db1cf1c..572eded 100644 --- a/API.md +++ b/API.md @@ -40,7 +40,7 @@ To save further pins one could connect the reset pin of the MCU with reset pin o #### Pin dio0 interrupt callbacks -The dio0 pin can be used for transmission finish callback and/or receiving callback, check `onTxDone` and `onReceive`. +The dio0 pin can be used for channel activity detection callback, transmission finish callback and/or receiving callback, check `onCadDone` , `onTxDone`, and `onReceive`. ### Set SPI interface @@ -250,6 +250,27 @@ Returns the next byte in the packet or `-1` if no bytes are available. **Note:** Other Arduino [`Stream` API's](https://www.arduino.cc/en/Reference/Stream) can also be used to read data from the packet +## Channel Activity Detection +**WARNING**: Channel activity detection callback uses the interrupt pin on the `dio0`, check `setPins` function! + +### Register callback + +Register a callback function for when channel activity detection has done. +```arduino +LoRa.onCadDone(onCadDone); + +void onCadDone(boolean signalDetected) { + // ... +} +``` + * `onCadDone` - function to call when channel activity detection has done. + * `signalDetected` - if `true`, the radio detects the presence of other LoRa signals. + +### Channel Activity detection mode +Puts the radio in channel activity detection mode. +```arduino +LoRa.channelActivityDetection(); +``` ## Other radio modes ### Idle mode diff --git a/examples/LoRaCADCallback/LoRaCADCallback.ino b/examples/LoRaCADCallback/LoRaCADCallback.ino new file mode 100644 index 0000000..b3bead2 --- /dev/null +++ b/examples/LoRaCADCallback/LoRaCADCallback.ino @@ -0,0 +1,58 @@ +#include +#include "LoRa.h" + +#ifdef ARDUINO_SAMD_MKRWAN1300 +#error "This example is not compatible with the Arduino MKR WAN 1300 board!" +#endif + +void setup() { + Serial.begin(9600); + while (!Serial); + + Serial.println("LoRa Receiver Callback"); + + if (!LoRa.begin(915E6)) { + Serial.println("Starting LoRa failed!"); + while (1); + } + + // register the channel activity dectection callback + LoRa.onCadDone(onCadDone); + // register the receive callback + LoRa.onReceive(onReceive); + // put the radio into CAD mode + LoRa.channelActivityDetection(); +} + +void loop() { + // do nothing +} + +void onCadDone(boolean signalDetected) { + // detect preamble + if (signalDetected) { + Serial.println("Signal detected"); + // put the radio into continuous receive mode + LoRa.receive(); + } else { + // try next activity dectection + LoRa.channelActivityDetection(); + } +} + +void onReceive(int packetSize) { + // received a packet + Serial.print("Received packet '"); + + // read packet + for (int i = 0; i < packetSize; i++) { + Serial.print((char)LoRa.read()); + } + + // print RSSI of packet + Serial.print("' with RSSI "); + Serial.println(LoRa.packetRssi()); + + // put the radio into CAD mode + LoRa.channelActivityDetection(); +} diff --git a/keywords.txt b/keywords.txt index 2e74cff..f4b7e4e 100644 --- a/keywords.txt +++ b/keywords.txt @@ -34,6 +34,8 @@ flush KEYWORD2 onReceive KEYWORD2 onTxDone KEYWORD2 +onCadDone KEYWORD2 +channelActivityDetection KEYWORD2 receive KEYWORD2 idle KEYWORD2 sleep KEYWORD2 diff --git a/src/LoRa.cpp b/src/LoRa.cpp index 44b4946..5cdb5cd 100644 --- a/src/LoRa.cpp +++ b/src/LoRa.cpp @@ -47,6 +47,7 @@ #define MODE_TX 0x03 #define MODE_RX_CONTINUOUS 0x05 #define MODE_RX_SINGLE 0x06 +#define MODE_CAD 0x07 // PA config #define PA_BOOST 0x80 @@ -55,6 +56,8 @@ #define IRQ_TX_DONE_MASK 0x08 #define IRQ_PAYLOAD_CRC_ERROR_MASK 0x20 #define IRQ_RX_DONE_MASK 0x40 +#define IRQ_CAD_DONE_MASK 0x04 +#define IRQ_CAD_DETECTED_MASK 0x01 #define RF_MID_BAND_THRESHOLD 525E6 #define RSSI_OFFSET_HF_PORT 157 @@ -76,6 +79,7 @@ LoRaClass::LoRaClass() : _packetIndex(0), _implicitHeaderMode(0), _onReceive(NULL), + _onCadDone(NULL), _onTxDone(NULL) { // overide Stream timeout value @@ -377,6 +381,24 @@ void LoRaClass::onReceive(void(*callback)(int)) } } +void LoRaClass::onCadDone(void(*callback)(boolean)) +{ + _onCadDone = callback; + + if (callback) { + pinMode(_dio0, INPUT); +#ifdef SPI_HAS_NOTUSINGINTERRUPT + SPI.usingInterrupt(digitalPinToInterrupt(_dio0)); +#endif + attachInterrupt(digitalPinToInterrupt(_dio0), LoRaClass::onDio0Rise, RISING); + } else { + detachInterrupt(digitalPinToInterrupt(_dio0)); +#ifdef SPI_HAS_NOTUSINGINTERRUPT + SPI.notUsingInterrupt(digitalPinToInterrupt(_dio0)); +#endif + } +} + void LoRaClass::onTxDone(void(*callback)()) { _onTxDone = callback; @@ -410,6 +432,12 @@ void LoRaClass::receive(int size) writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_CONTINUOUS); } + +void LoRaClass::channelActivityDetection(void) +{ + writeRegister(REG_DIO_MAPPING_1, 0x80);// DIO0 => CADDONE + writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_CAD); +} #endif void LoRaClass::idle() @@ -696,7 +724,11 @@ void LoRaClass::handleDio0Rise() // clear IRQ's writeRegister(REG_IRQ_FLAGS, irqFlags); - if ((irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0) { + if ((irqFlags & IRQ_CAD_DONE_MASK) != 0) { + if (_onCadDone) { + _onCadDone((irqFlags & IRQ_CAD_DETECTED_MASK) != 0); + } + } else if ((irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0) { if ((irqFlags & IRQ_RX_DONE_MASK) != 0) { // received a packet @@ -711,8 +743,7 @@ void LoRaClass::handleDio0Rise() if (_onReceive) { _onReceive(packetLength); } - } - else if ((irqFlags & IRQ_TX_DONE_MASK) != 0) { + } else if ((irqFlags & IRQ_TX_DONE_MASK) != 0) { if (_onTxDone) { _onTxDone(); } diff --git a/src/LoRa.h b/src/LoRa.h index b312db5..bad87da 100644 --- a/src/LoRa.h +++ b/src/LoRa.h @@ -59,9 +59,11 @@ public: #ifndef ARDUINO_SAMD_MKRWAN1300 void onReceive(void(*callback)(int)); + void onCadDone(void(*callback)(boolean)); void onTxDone(void(*callback)()); void receive(int size = 0); + void channelActivityDetection(void); #endif void idle(); void sleep(); @@ -122,6 +124,7 @@ private: int _packetIndex; int _implicitHeaderMode; void (*_onReceive)(int); + void (*_onCadDone)(boolean); void (*_onTxDone)(); };