From 07bfead143cf617b76e19d40a291dffb5c7e3685 Mon Sep 17 00:00:00 2001 From: Luiz Date: Sun, 19 Aug 2018 10:53:52 -0300 Subject: [PATCH 1/3] Add function to invert IQ signal register (#179) Add function to change register (REG_INVERTIQ) to support communication node and gateway The register does not exist in datasheet but use on but used in Semtech code. Reference : https://github.com/intel-iot-devkit/upm/blob/master/src/sx1276/sx1276.cxx * Add LoRa Simple Gateway/Node Exemple Example how to use InvertIQ function to create a simple Gateway/Node logic. --- API.md | 10 ++ .../LoRaSimpleGateway/LoRaSimpleGateway.ino | 113 ++++++++++++++++++ examples/LoRaSimpleNode/LoRaSimpleNode.ino | 113 ++++++++++++++++++ keywords.txt | 2 + src/LoRa.cpp | 14 +++ src/LoRa.h | 3 + 6 files changed, 255 insertions(+) create mode 100644 examples/LoRaSimpleGateway/LoRaSimpleGateway.ino create mode 100644 examples/LoRaSimpleNode/LoRaSimpleNode.ino diff --git a/API.md b/API.md index 01c1526..4b7d46e 100644 --- a/API.md +++ b/API.md @@ -329,6 +329,16 @@ LoRa.enableCrc(); LoRa.disableCrc(); ``` +### Invert IQ Signals + +Enable or disable Invert the LoRa I and Q signals, by default a invertIQ is not used. + +```arduino +LoRa.enableInvertIQ(); + +LoRa.disableInvertIQ(); +``` + ## Other functions ### Random diff --git a/examples/LoRaSimpleGateway/LoRaSimpleGateway.ino b/examples/LoRaSimpleGateway/LoRaSimpleGateway.ino new file mode 100644 index 0000000..745bf1f --- /dev/null +++ b/examples/LoRaSimpleGateway/LoRaSimpleGateway.ino @@ -0,0 +1,113 @@ +/* + LoRa Simple Gateway/Node Exemple + + This code uses InvertIQ function to create a simple Gateway/Node logic. + + Gateway - Sends messages with enableInvertIQ() + - Receives messages with disableInvertIQ() + + Node - Sends messages with disableInvertIQ() + - Receives messages with enableInvertIQ() + + With this arrangement a Gateway never receive messages from another Gateway + and a Node never receive message from another Node. + Only Gateway to Node and vice versa. + + This code receives messages and sends a message every second. + + InvertIQ function basically invert the LoRa I and Q signals. + + See the Semtech datasheet, http://www.semtech.com/images/datasheet/sx1276.pdf + for more on InvertIQ register 0x33. + + created 05 August 2018 + by Luiz H. Cassettari +*/ + +#include // include libraries +#include + +const long frequency = 915E6; // LoRa Frequency + +const int csPin = 10; // LoRa radio chip select +const int resetPin = 9; // LoRa radio reset +const int irqPin = 2; // change for your board; must be a hardware interrupt pin + +void setup() { + Serial.begin(9600); // initialize serial + while (!Serial); + + LoRa.setPins(csPin, resetPin, irqPin); + + if (!LoRa.begin(frequency)) { + Serial.println("LoRa init failed. Check your connections."); + while (true); // if failed, do nothing + } + + Serial.println("LoRa init succeeded."); + Serial.println(); + Serial.println("LoRa Simple Gateway"); + Serial.println("Only receive messages from nodes"); + Serial.println("Tx: invertIQ enable"); + Serial.println("Rx: invertIQ disable"); + Serial.println(); + + LoRa.onReceive(onReceive); + LoRa_rxMode(); +} + +void loop() { + if (runEvery(5000)) { // repeat every 5000 millis + + String message = "HeLoRa World! "; + message += "I'm a Gateway! "; + message += millis(); + + LoRa_sendMessage(message); // send a message + + Serial.println("Send Message!"); + } +} + +void LoRa_rxMode(){ + LoRa.disableInvertIQ(); // normal mode + LoRa.receive(); // set receive mode +} + +void LoRa_txMode(){ + LoRa.idle(); // set standby mode + LoRa.enableInvertIQ(); // active invert I and Q signals +} + +void LoRa_sendMessage(String message) { + LoRa_txMode(); // set tx mode + LoRa.beginPacket(); // start packet + LoRa.print(message); // add payload + LoRa.endPacket(); // finish packet and send it + LoRa_rxMode(); // set rx mode +} + +void onReceive(int packetSize) { + String message = ""; + + while (LoRa.available()) { + message += (char)LoRa.read(); + } + + Serial.print("Gateway Receive: "); + Serial.println(message); + +} + +boolean runEvery(unsigned long interval) +{ + static unsigned long previousMillis = 0; + unsigned long currentMillis = millis(); + if (currentMillis - previousMillis >= interval) + { + previousMillis = currentMillis; + return true; + } + return false; +} + diff --git a/examples/LoRaSimpleNode/LoRaSimpleNode.ino b/examples/LoRaSimpleNode/LoRaSimpleNode.ino new file mode 100644 index 0000000..a6cb0c0 --- /dev/null +++ b/examples/LoRaSimpleNode/LoRaSimpleNode.ino @@ -0,0 +1,113 @@ +/* + LoRa Simple Gateway/Node Exemple + + This code uses InvertIQ function to create a simple Gateway/Node logic. + + Gateway - Sends messages with enableInvertIQ() + - Receives messages with disableInvertIQ() + + Node - Sends messages with disableInvertIQ() + - Receives messages with enableInvertIQ() + + With this arrangement a Gateway never receive messages from another Gateway + and a Node never receive message from another Node. + Only Gateway to Node and vice versa. + + This code receives messages and sends a message every second. + + InvertIQ function basically invert the LoRa I and Q signals. + + See the Semtech datasheet, http://www.semtech.com/images/datasheet/sx1276.pdf + for more on InvertIQ register 0x33. + + created 05 August 2018 + by Luiz H. Cassettari +*/ + +#include // include libraries +#include + +const long frequency = 915E6; // LoRa Frequency + +const int csPin = 10; // LoRa radio chip select +const int resetPin = 9; // LoRa radio reset +const int irqPin = 2; // change for your board; must be a hardware interrupt pin + +void setup() { + Serial.begin(9600); // initialize serial + while (!Serial); + + LoRa.setPins(csPin, resetPin, irqPin); + + if (!LoRa.begin(frequency)) { + Serial.println("LoRa init failed. Check your connections."); + while (true); // if failed, do nothing + } + + Serial.println("LoRa init succeeded."); + Serial.println(); + Serial.println("LoRa Simple Node"); + Serial.println("Only receive messages from gateways"); + Serial.println("Tx: invertIQ disable"); + Serial.println("Rx: invertIQ enable"); + Serial.println(); + + LoRa.onReceive(onReceive); + LoRa_rxMode(); +} + +void loop() { + if (runEvery(1000)) { // repeat every 1000 millis + + String message = "HeLoRa World! "; + message += "I'm a Node! "; + message += millis(); + + LoRa_sendMessage(message); // send a message + + Serial.println("Send Message!"); + } +} + +void LoRa_rxMode(){ + LoRa.enableInvertIQ(); // active invert I and Q signals + LoRa.receive(); // set receive mode +} + +void LoRa_txMode(){ + LoRa.idle(); // set standby mode + LoRa.disableInvertIQ(); // normal mode +} + +void LoRa_sendMessage(String message) { + LoRa_txMode(); // set tx mode + LoRa.beginPacket(); // start packet + LoRa.print(message); // add payload + LoRa.endPacket(); // finish packet and send it + LoRa_rxMode(); // set rx mode +} + +void onReceive(int packetSize) { + String message = ""; + + while (LoRa.available()) { + message += (char)LoRa.read(); + } + + Serial.print("Node Receive: "); + Serial.println(message); + +} + +boolean runEvery(unsigned long interval) +{ + static unsigned long previousMillis = 0; + unsigned long currentMillis = millis(); + if (currentMillis - previousMillis >= interval) + { + previousMillis = currentMillis; + return true; + } + return false; +} + diff --git a/keywords.txt b/keywords.txt index 759bb0a..854ed8c 100644 --- a/keywords.txt +++ b/keywords.txt @@ -44,6 +44,8 @@ setPreambleLength KEYWORD2 setSyncWord KEYWORD2 enableCrc KEYWORD2 disableCrc KEYWORD2 +enableInvertIQ KEYWORD2 +disableInvertIQ KEYWORD2 random KEYWORD2 setPins KEYWORD2 diff --git a/src/LoRa.cpp b/src/LoRa.cpp index 7f829ca..065c5e3 100644 --- a/src/LoRa.cpp +++ b/src/LoRa.cpp @@ -31,8 +31,10 @@ #define REG_FREQ_ERROR_LSB 0x2a #define REG_RSSI_WIDEBAND 0x2c #define REG_DETECTION_OPTIMIZE 0x31 +#define REG_INVERTIQ 0x33 #define REG_DETECTION_THRESHOLD 0x37 #define REG_SYNC_WORD 0x39 +#define REG_INVERTIQ2 0x3b #define REG_DIO_MAPPING_1 0x40 #define REG_VERSION 0x42 #define REG_PA_DAC 0x4d @@ -531,6 +533,18 @@ void LoRaClass::disableCrc() writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) & 0xfb); } +void LoRaClass::enableInvertIQ() +{ + writeRegister(REG_INVERTIQ, 0x66); + writeRegister(REG_INVERTIQ2, 0x19); +} + +void LoRaClass::disableInvertIQ() +{ + writeRegister(REG_INVERTIQ, 0x27); + writeRegister(REG_INVERTIQ2, 0x1d); +} + void LoRaClass::setOCP(uint8_t mA) { uint8_t ocpTrim = 27; diff --git a/src/LoRa.h b/src/LoRa.h index a5cc2de..a58007d 100644 --- a/src/LoRa.h +++ b/src/LoRa.h @@ -66,6 +66,9 @@ class LoRaClass : public Stream { void setSyncWord(int sw); void enableCrc(); void disableCrc(); + void enableInvertIQ(); + void disableInvertIQ(); + void setOCP(uint8_t mA); // Over Current Protection control // deprecated From 9d2a8c9c824af07f1e59dd42c6af453e56eef0b4 Mon Sep 17 00:00:00 2001 From: Samuel Lang Date: Sun, 19 Aug 2018 16:34:32 +0200 Subject: [PATCH 2/3] non blocking functions added (#62) --- .travis.yml | 1 + API.md | 7 ++-- .../LoRaSenderNonBlocking.ino | 35 ++++++++++++++++++ src/LoRa.cpp | 36 +++++++++++++++---- src/LoRa.h | 3 +- 5 files changed, 72 insertions(+), 10 deletions(-) create mode 100644 examples/LoRaSenderNonBlocking/LoRaSenderNonBlocking.ino diff --git a/.travis.yml b/.travis.yml index 8a9cb12..ae7a782 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,5 +33,6 @@ script: buildExampleSketch LoRaReceiverCallback; fi - buildExampleSketch LoRaSender + - buildExampleSketch LoRaSenderNonBlocking - buildExampleSketch LoRaSetSpread - buildExampleSketch LoRaSetSyncWord diff --git a/API.md b/API.md index 4b7d46e..ded3b9c 100644 --- a/API.md +++ b/API.md @@ -82,7 +82,7 @@ LoRa.beginPacket(implicitHeader); * `implicitHeader` - (optional) `true` enables implicit header mode, `false` enables explicit header mode (default) -Returns `1` on success, `0` on failure. +Returns `1` if radio is ready to transmit, `0` if busy or on failure. ### Writing @@ -109,8 +109,11 @@ Returns the number of bytes written. End the sequence of sending a packet. ```arduino -LoRa.endPacket() +LoRa.endPacket(); + +LoRa.endPacket(async); ``` + * `async` - (optional) `true` enables non-blocking mode, `false` waits for transmission to be completed (default) Returns `1` on success, `0` on failure. diff --git a/examples/LoRaSenderNonBlocking/LoRaSenderNonBlocking.ino b/examples/LoRaSenderNonBlocking/LoRaSenderNonBlocking.ino new file mode 100644 index 0000000..0f39077 --- /dev/null +++ b/examples/LoRaSenderNonBlocking/LoRaSenderNonBlocking.ino @@ -0,0 +1,35 @@ +#include +#include + +int counter = 0; + +void setup() { + Serial.begin(9600); + while (!Serial); + + Serial.println("LoRa Sender non-blocking"); + + if (!LoRa.begin(915E6)) { + Serial.println("Starting LoRa failed!"); + while (1); + } +} + +void loop() { + // wait until the radio is ready to send a packet + while (LoRa.beginPacket() == 0) { + Serial.print("waiting for radio ... "); + delay(100); + } + + Serial.print("Sending packet non-blocking: "); + Serial.println(counter); + + // send in async / non-blocking mode + LoRa.beginPacket(); + LoRa.print("hello "); + LoRa.print(counter); + LoRa.endPacket(true); // true = async / non-blocking mode + + counter++; +} diff --git a/src/LoRa.cpp b/src/LoRa.cpp index 065c5e3..94841b2 100644 --- a/src/LoRa.cpp +++ b/src/LoRa.cpp @@ -149,6 +149,10 @@ void LoRaClass::end() int LoRaClass::beginPacket(int implicitHeader) { + if (isTransmitting()) { + return 0; + } + // put in standby mode idle(); @@ -165,22 +169,40 @@ int LoRaClass::beginPacket(int implicitHeader) return 1; } -int LoRaClass::endPacket() +int LoRaClass::endPacket(bool async) { // put in TX mode writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX); - // wait for TX done - while ((readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0) { - yield(); + if (async) { + // grace time is required for the radio + delayMicroseconds(150); + } else { + // wait for TX done + while ((readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0) { + yield(); + } + // clear IRQ's + writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK); } - // clear IRQ's - writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK); - return 1; } +bool LoRaClass::isTransmitting() +{ + if ((readRegister(REG_OP_MODE) & MODE_TX) == MODE_TX) { + return true; + } + + if (readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) { + // clear IRQ's + writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK); + } + + return false; +} + int LoRaClass::parsePacket(int size) { int packetLength = 0; diff --git a/src/LoRa.h b/src/LoRa.h index a58007d..c5d239e 100644 --- a/src/LoRa.h +++ b/src/LoRa.h @@ -32,7 +32,7 @@ class LoRaClass : public Stream { void end(); int beginPacket(int implicitHeader = false); - int endPacket(); + int endPacket(bool async = false); int parsePacket(int size = 0); int packetRssi(); @@ -88,6 +88,7 @@ class LoRaClass : public Stream { void implicitHeaderMode(); void handleDio0Rise(); + bool isTransmitting(); int getSpreadingFactor(); long getSignalBandwidth(); From baf0d73849e226343633d96a78da2ce2a6cf184d Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Sun, 19 Aug 2018 10:38:43 -0400 Subject: [PATCH 3/3] Update README.md Add more info. about the MKR WAN 1300 firmware. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f527971..c89956a 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ An [Arduino](https://arduino.cc/) library for sending and receiving data using [ * [HopeRF](http://www.hoperf.com/rf_transceiver/lora/) [RFM95W](http://www.hoperf.com/rf_transceiver/lora/RFM95W.html), [RFM96W](http://www.hoperf.com/rf_transceiver/lora/RFM96W.html), and [RFM98W](http://www.hoperf.com/rf_transceiver/lora/RFM98W.html) * [Modtronix](http://modtronix.com/) [inAir4](http://modtronix.com/inair4.html), [inAir9](http://modtronix.com/inair9.html), and [inAir9B](http://modtronix.com/inair9b.html) * [Arduino MKR WAN 1300](https://store.arduino.cc/usa/mkr-wan-1300) - * **NOTE:** Requires firmware v1.1.6 or later on the on-board Murata module + * **NOTE:** Requires firmware v1.1.6 or later on the on-board Murata module. Please use the [MKRWANFWUpdate_standalone example](https://github.com/arduino-libraries/MKRWAN/blob/master/examples/MKRWANFWUpdate_standalone/MKRWANFWUpdate_standalone.ino) from latest [MKRWAN library](https://github.com/arduino-libraries/MKRWAN) release to update the firmware. * **WARNING**: [LoRa.onReceive(...)](https://github.com/sandeepmistry/arduino-LoRa/blob/master/API.md#register-callback) and [LoRa.recieve()](https://github.com/sandeepmistry/arduino-LoRa/blob/master/API.md#receive-mode) is not compatible with this board! ### Semtech SX1276/77/78/79 wiring