From e75fd5b84a7df7f6ea77071205651b7aa6afad86 Mon Sep 17 00:00:00 2001 From: Minoru Tomobe Date: Sun, 2 Feb 2020 23:14:40 +0900 Subject: [PATCH] Add Channel Activity Detection function and examples. --- API.md | 23 +++++++- examples/LoRaCADCallback/LoRaCADCallback.ino | 58 ++++++++++++++++++++ keywords.txt | 2 + src/LoRa.cpp | 36 +++++++++++- src/LoRa.h | 3 + 5 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 examples/LoRaCADCallback/LoRaCADCallback.ino diff --git a/API.md b/API.md index 78f054d..f2f9d40 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 @@ -242,6 +242,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.CAD(); +``` ## Other radio modes ### Idle mode diff --git a/examples/LoRaCADCallback/LoRaCADCallback.ino b/examples/LoRaCADCallback/LoRaCADCallback.ino new file mode 100644 index 0000000..c8ee5bd --- /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.CAD(); +} + +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.CAD(); + } +} + +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.CAD(); +} diff --git a/keywords.txt b/keywords.txt index 63e0e9a..36a176c 100644 --- a/keywords.txt +++ b/keywords.txt @@ -32,6 +32,8 @@ flush KEYWORD2 onReceive KEYWORD2 onTxDone KEYWORD2 +onCadDone KEYWORD2 +CAD KEYWORD2 receive KEYWORD2 idle KEYWORD2 sleep KEYWORD2 diff --git a/src/LoRa.cpp b/src/LoRa.cpp index 6980f5a..651215b 100644 --- a/src/LoRa.cpp +++ b/src/LoRa.cpp @@ -46,6 +46,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 @@ -54,6 +55,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 MAX_PKT_LENGTH 255 @@ -71,6 +74,7 @@ LoRaClass::LoRaClass() : _packetIndex(0), _implicitHeaderMode(0), _onReceive(NULL), + _onCadDone(NULL), _onTxDone(NULL) { // overide Stream timeout value @@ -199,7 +203,7 @@ int LoRaClass::endPacket(bool async) bool LoRaClass::isTransmitting() { - if ((readRegister(REG_OP_MODE) & MODE_TX) == MODE_TX) { + if ((readRegister(REG_OP_MODE) & B111) == MODE_TX) { return true; } @@ -367,6 +371,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; @@ -400,6 +422,12 @@ void LoRaClass::receive(int size) writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_CONTINUOUS); } + +void LoRaClass::CAD(void) +{ + writeRegister(REG_DIO_MAPPING_1, 0x80);// DIO0 => CADDONE + writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_CAD); +} #endif void LoRaClass::idle() @@ -679,7 +707,11 @@ void LoRaClass::handleDio0Rise() // reset FIFO address writeRegister(REG_FIFO_ADDR_PTR, 0); } - else if ((irqFlags & IRQ_TX_DONE_MASK) != 0) { + else if ((irqFlags & IRQ_CAD_DONE_MASK) != 0) { + if (_onCadDone) { + _onCadDone((irqFlags & IRQ_CAD_DETECTED_MASK) != 0); + } + } else if ((irqFlags & IRQ_TX_DONE_MASK) != 0) { if (_onTxDone) { _onTxDone(); } diff --git a/src/LoRa.h b/src/LoRa.h index c1671c1..56128d8 100644 --- a/src/LoRa.h +++ b/src/LoRa.h @@ -57,9 +57,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 CAD(void); #endif void idle(); void sleep(); @@ -118,6 +120,7 @@ private: int _packetIndex; int _implicitHeaderMode; void (*_onReceive)(int); + void (*_onCadDone)(boolean); void (*_onTxDone)(); };