From 4567044deb964beadd225b420f651df417a20026 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 28 Dec 2021 13:47:06 +0100 Subject: [PATCH 01/16] Added support for Raspberry PI (#432) --- README.md | 1 + src/BuildOpt.h | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/README.md b/README.md index 5e67821d..ab9cfdb7 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x * __Raspberry Pi__ * [__RP2040__](https://github.com/arduino/ArduinoCore-mbed) - Raspberry Pi Pico and Arduino Nano RP2040 Connect + * [__Raspberry Pi__](https://github.com/me-no-dev/RasPiArduino) - Arduino framework for RaspberryPI * __Heltec__ * [__CubeCell__](https://github.com/HelTecAutomation/CubeCell-Arduino) - ASR650X series (CubeCell-Board, CubeCell-Capsule, CubeCell-Module etc.) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index cc40c7a3..37f3a426 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -734,6 +734,60 @@ #undef yield #endif +#elif defined(RASPI) + // RaspiDuino framework (https://github.com/me-no-dev/RasPiArduino) + #define RADIOLIB_PLATFORM "RasPiArduino" + #define RADIOLIB_PIN_TYPE uint8_t + #define RADIOLIB_PIN_MODE uint8_t + #define RADIOLIB_PIN_STATUS uint8_t + #define RADIOLIB_INTERRUPT_STATUS RADIOLIB_PIN_STATUS + #define RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(p) digitalPinToInterrupt(p) + #define RADIOLIB_NC (0xFF) + #define RADIOLIB_DEFAULT_SPI SPI + #define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0) + #define RADIOLIB_NONVOLATILE PROGMEM + #define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr) + #define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type; + + // Arduino API callbacks + #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8_t pin, uint8_t mode) + #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint8_t pin, uint8_t value) + #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, uint8_t pin) + #define RADIOLIB_CB_ARGS_TONE (void, tone, uint8_t _pin, unsigned int frequency, unsigned long duration) + #define RADIOLIB_CB_ARGS_NO_TONE (void, noTone, uint8_t _pin) + #define RADIOLIB_CB_ARGS_ATTACH_INTERRUPT (void, attachInterrupt, uint8_t interruptNum, void (*userFunc)(void), int mode) + #define RADIOLIB_CB_ARGS_DETACH_INTERRUPT (void, detachInterrupt, uint8_t interruptNum) + #define RADIOLIB_CB_ARGS_YIELD (void, yield, void) + #define RADIOLIB_CB_ARGS_DELAY (void, delay, uint32_t ms) + #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) + #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) + #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) + #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) + #define RADIOLIB_CB_ARGS_SPI_END_TRANSACTION (void, SPIendTransaction, void) + #define RADIOLIB_CB_ARGS_SPI_END (void, SPIend, void) + + // let's start off easy - no tone on this platform, that can happen + #define RADIOLIB_TONE_UNSUPPORTED + + // hmm, no yield either - weird on something like Raspberry PI, but sure, we can handle it + #define RADIOLIB_YIELD_UNSUPPORTED + + // aight, getting to the juicy stuff - PGM_P seems missing, that's the first time + #define PGM_P const char * + + // ... and for the grand finale, we have millis() and micros() DEFINED AS MACROS! + #if defined(millis) + #undef millis + inline unsigned long millis() { return((unsigned long)(STCV / 1000)); }; + #endif + + #if defined(micros) + #undef micros + inline unsigned long micros() { return((unsigned long)(STCV)); }; + #endif + #else // other Arduino platforms not covered by the above list - this may or may not work #define RADIOLIB_PLATFORM "Unknown Arduino" From d53ddf1ca418243b3f02832497f553762f50b0e5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 29 Dec 2021 08:48:40 +0100 Subject: [PATCH 02/16] [CC1101] Added ESP8266/ESP32 IRAM attribute --- .../CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino | 3 +++ .../CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino | 3 +++ 2 files changed, 6 insertions(+) diff --git a/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino b/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino index e52630a5..65ae79a2 100644 --- a/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino +++ b/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino @@ -82,6 +82,9 @@ volatile bool enableInterrupt = true; // 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) { // check if the interrupt is enabled if(!enableInterrupt) { diff --git a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino index 29719ade..1d993a77 100644 --- a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino +++ b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino @@ -75,6 +75,9 @@ volatile bool enableInterrupt = true; // is transmitted 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) { // check if the interrupt is enabled if(!enableInterrupt) { From a7705236b12e2a74cd1667c83823ce1131ef2555 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 29 Dec 2021 08:48:49 +0100 Subject: [PATCH 03/16] [RF69] Added ESP8266/ESP32 IRAM attribute --- .../RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino | 3 +++ .../RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino | 3 +++ 2 files changed, 6 insertions(+) diff --git a/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino b/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino index 12d5de5d..da520351 100644 --- a/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino +++ b/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino @@ -74,6 +74,9 @@ volatile bool enableInterrupt = true; // 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) { // check if the interrupt is enabled if(!enableInterrupt) { diff --git a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino index eb54a541..6ae3fa1c 100644 --- a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino +++ b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino @@ -91,6 +91,9 @@ volatile bool enableInterrupt = true; // is transmitted 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) { // check if the interrupt is enabled if(!enableInterrupt) { From bb2cf12c8d8556342d73efe41fe359a47e6695af Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 29 Dec 2021 08:48:59 +0100 Subject: [PATCH 04/16] [SX126x] Added ESP8266/ESP32 IRAM attribute --- .../SX126x_Channel_Activity_Detection_Interrupt.ino | 3 +++ .../SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino | 3 +++ .../SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino | 3 +++ 3 files changed, 9 insertions(+) diff --git a/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino b/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino index ed658daa..f7763773 100644 --- a/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino +++ b/examples/SX126x/SX126x_Channel_Activity_Detection_Interrupt/SX126x_Channel_Activity_Detection_Interrupt.ino @@ -71,6 +71,9 @@ volatile bool enableInterrupt = true; // 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) { // check if the interrupt is enabled if(!enableInterrupt) { diff --git a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino index d50f2849..4132617c 100644 --- a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino +++ b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino @@ -88,6 +88,9 @@ volatile bool enableInterrupt = true; // 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) { // check if the interrupt is enabled if(!enableInterrupt) { diff --git a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino index 19e76817..69fd17c7 100644 --- a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino +++ b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino @@ -80,6 +80,9 @@ volatile bool enableInterrupt = true; // is transmitted 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) { // check if the interrupt is enabled if(!enableInterrupt) { From 5cb5836ed82f98caf2203a18536fd9b8edb7ecb7 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 29 Dec 2021 08:49:14 +0100 Subject: [PATCH 05/16] [SX127x] Added ESP8266/ESP32 IRAM attribute --- .../SX127x_Channel_Activity_Detection_Interrupt.ino | 11 +++++++---- .../SX127x_Receive_Interrupt.ino | 3 +++ .../SX127x_Transmit_Interrupt.ino | 3 +++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino b/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino index 30f945e4..55372452 100644 --- a/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino +++ b/examples/SX127x/SX127x_Channel_Activity_Detection_Interrupt/SX127x_Channel_Activity_Detection_Interrupt.ino @@ -79,6 +79,9 @@ volatile bool enableInterrupt = true; // is detected within timeout period // IMPORTANT: this function MUST be 'void' type // and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif void setFlagTimeout(void) { // check if the interrupt is enabled if(!enableInterrupt) { @@ -115,14 +118,14 @@ void loop() { // LoRa preamble was detected Serial.print(F("[SX1278] Preamble detected!")); - + } - + // check if we need to restart channel activity detection if(detectedFlag || timeoutFlag) { // start scanning the channel Serial.print(F("[SX1278] Starting scan for LoRa preamble ... ")); - + // start scanning current channel int state = radio.startChannelScan(); if (state == RADIOLIB_ERR_NONE) { @@ -131,6 +134,6 @@ void loop() { Serial.print(F("failed, code ")); Serial.println(state); } - + } } diff --git a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino index 9db3eaf3..e3228970 100644 --- a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino +++ b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino @@ -85,6 +85,9 @@ volatile bool enableInterrupt = true; // 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) { // check if the interrupt is enabled if(!enableInterrupt) { diff --git a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino index b218a0a7..f0fe3e8b 100644 --- a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino +++ b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino @@ -77,6 +77,9 @@ volatile bool enableInterrupt = true; // is transmitted 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) { // check if the interrupt is enabled if(!enableInterrupt) { From fa4a4de87980ee5fb26fb4ad4403f98f85494aef Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 29 Dec 2021 08:49:22 +0100 Subject: [PATCH 06/16] [SX128x] Added ESP8266/ESP32 IRAM attribute --- .../SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino | 3 +++ .../SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino | 3 +++ 2 files changed, 6 insertions(+) diff --git a/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino b/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino index 9bc9eaaa..274121df 100644 --- a/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino +++ b/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino @@ -85,6 +85,9 @@ volatile bool enableInterrupt = true; // 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) { // check if the interrupt is enabled if(!enableInterrupt) { diff --git a/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino b/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino index b23fb0c1..55d44faa 100644 --- a/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino +++ b/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino @@ -77,6 +77,9 @@ volatile bool enableInterrupt = true; // is transmitted 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) { // check if the interrupt is enabled if(!enableInterrupt) { From 9f40d9a17a4c8a71038ec6674593afabe497bc0b Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 29 Dec 2021 08:49:30 +0100 Subject: [PATCH 07/16] [nRF24] Added ESP8266/ESP32 IRAM attribute --- .../nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino | 3 +++ .../nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino | 3 +++ 2 files changed, 6 insertions(+) diff --git a/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino b/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino index cafa2964..9e73394a 100644 --- a/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino +++ b/examples/nRF24/nRF24_Receive_Interrupt/nRF24_Receive_Interrupt.ino @@ -94,6 +94,9 @@ volatile bool enableInterrupt = true; // 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) { // check if the interrupt is enabled if(!enableInterrupt) { diff --git a/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino b/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino index 9b6720c5..14d0c072 100644 --- a/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino +++ b/examples/nRF24/nRF24_Transmit_Interrupt/nRF24_Transmit_Interrupt.ino @@ -90,6 +90,9 @@ volatile bool enableInterrupt = true; // is transmitted 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) { // check if the interrupt is enabled if(!enableInterrupt) { From a2eb2d7aa5d673ad6af77ef841a737ffd2b950f4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 29 Dec 2021 08:49:44 +0100 Subject: [PATCH 08/16] [Si443x] Added ESP8266/ESP32 IRAM attribute (#434) --- .../Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino | 3 +++ .../Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino | 3 +++ 2 files changed, 6 insertions(+) diff --git a/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino b/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino index 16c1af41..061ee094 100644 --- a/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino +++ b/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino @@ -76,6 +76,9 @@ volatile bool enableInterrupt = true; // 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) { // check if the interrupt is enabled if(!enableInterrupt) { diff --git a/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino b/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino index 4703233a..7f6877c6 100644 --- a/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino +++ b/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino @@ -75,6 +75,9 @@ volatile bool enableInterrupt = true; // is transmitted 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) { // check if the interrupt is enabled if(!enableInterrupt) { From 3cc299d17be4ea6a3ea2a6e33f57ccf72839bc33 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Thu, 13 Jan 2022 12:25:02 -0700 Subject: [PATCH 09/16] Add FHSS support --- .../SX127x_Receive_FHSS.ino | 122 +++++++++++++++++ .../SX127x_Transmit_FHSS.ino | 124 ++++++++++++++++++ keywords.txt | 4 + src/modules/SX127x/SX1276.cpp | 22 ++++ src/modules/SX127x/SX1276.h | 28 ++++ src/modules/SX127x/SX127x.cpp | 17 ++- 6 files changed, 313 insertions(+), 4 deletions(-) create mode 100644 examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino create mode 100644 examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino diff --git a/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino b/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino new file mode 100644 index 00000000..d45bec3b --- /dev/null +++ b/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino @@ -0,0 +1,122 @@ +/* + RadioLib SX127x Transmit with Frequency Hopping Example + + This example transmits packets using SX1278 LoRa radio module. + Each packet contains up to 256 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + Other modules from SX127x/RFM9x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ + + The SX1276 / 7 / 8 / 9 supports FHSS or Frequency Hopping Spread Spectrum. + Once a hopping period is set and a transmission is started the radio + will begin triggering interrupts every hop period where the radio frequency + is changed to the next channel. This allows a simple mechanism to abide by + the FCC 400ms max dwell time rule. + https://www.govinfo.gov/content/pkg/CFR-2019-title47-vol1/pdf/CFR-2019-title47-vol1-sec15-247.pdf +*/ + +#include //Click here to get the library: http://librarymanager/All#RadioLib + +//Pins for RFM97 100mW Shield to SparkFun ESP32 Thing Plus C +int pin_cs = 15; +int pin_dio0 = 26; +int pin_dio1 = 25; +int pin_rst = 32; +SX1276 radio = new Module(pin_cs, pin_dio0, pin_rst, pin_dio1); + +int counter = 0; + +volatile bool rxComplete = false; +volatile bool fhssChange = false; + +//The channel frequencies can be generated randomly or hard coded +float channels[] = {908.0, 906.0, 907.0, 905.0, 903.0, 910.0, 909.0}; +int numberOfChannels = sizeof(channels) / sizeof(float); + +int hopsCompleted = 0; + +void setup() +{ + Serial.begin(115200); + + //Begin radio on home channel + Serial.print(F("[SX127x] Initializing ... ")); + int state = radio.begin(channels[0]); + if (state != RADIOLIB_ERR_NONE) + { + Serial.print(F("Failed with code: ")); + Serial.println(state); + } + else + Serial.println(F("Success!")); + + // Set hop period to enable FHSS + // We set an artifically short period to show lots of hops + // HoppingPeriod = Tsym * FreqHoppingPeriod + // Given defaults of spreadfactor = 9, bandwidth = 125, it follows Tsym = 4.10ms + // HoppingPeriod = 4.10 * 9 = 36.9ms. Can be as high as 400ms to be within regulatory limits + radio.setFHSSHoppingPeriod(9); + + Serial.print(F("Hopping period: ")); + Serial.println(radio.getFHSSHoppingPeriod()); + + radio.setDio0Action(dio0ISR); //Called when transmission is finished + radio.setDio1Action(dio1ISR); //Called after a transmission has started, so we can move to next freq + + radio.startReceive(); + + Serial.println(F("Waiting for new packet")); +} + +void loop() +{ + if (rxComplete == true) + { + uint8_t incomingBuffer[255]; + radio.readData(incomingBuffer, 255); + uint8_t receivedBytes = radio.getPacketLength(); + Serial.write(incomingBuffer, receivedBytes); + Serial.println(); + + Serial.print(F("Hops completed: ")); + Serial.println(hopsCompleted); + hopsCompleted = 0; + + radio.startReceive(); + + rxComplete = false; + } + + if (fhssChange == true) + { + radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); + //Serial.print(F("Radio on channel: ")); + //Serial.println(radio.getFHSSChannel()); + + hopsCompleted++; + radio.clearFHSSInt(); + fhssChange = false; + } +} + +//ISR when DIO0 goes low +//Called when transmission is complete or when RX is received +void dio0ISR(void) +{ + rxComplete = true; +} + +//ISR when DIO1 goes low +//Called when FhssChangeChannel interrupt occurs (at the beginning of each transmission) +void dio1ISR(void) +{ + fhssChange = true; +} diff --git a/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino b/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino new file mode 100644 index 00000000..504852e0 --- /dev/null +++ b/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino @@ -0,0 +1,124 @@ +/* + RadioLib SX127x Transmit with Frequency Hopping Example + + This example transmits packets using SX1278 LoRa radio module. + Each packet contains up to 256 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + Other modules from SX127x/RFM9x family can also be used. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---lora-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ + + The SX1276 / 7 / 8 / 9 supports FHSS or Frequency Hopping Spread Spectrum. + Once a hopping period is set and a transmission is started the radio + will begin triggering interrupts every hop period where the radio frequency + is changed to the next channel. This allows a simple mechanism to abide by + the FCC 400ms max dwell time rule. + https://www.govinfo.gov/content/pkg/CFR-2019-title47-vol1/pdf/CFR-2019-title47-vol1-sec15-247.pdf +*/ + +#include //Click here to get the library: http://librarymanager/All#RadioLib + +//Pins for SparkFun 1W EBYTE Breakout to Uno +int pin_cs = 7; +int pin_dio0 = 3; +int pin_dio1 = 2; +int pin_rst = A2; +SX1276 radio = new Module(pin_cs, pin_dio0, pin_rst, pin_dio1); + +volatile bool xmitComplete = false; +volatile bool fhssChange = false; + +//The channel frequencies can be generated randomly or hard coded +float channels[] = {908.0, 906.0, 907.0, 905.0, 903.0, 910.0, 909.0}; +int numberOfChannels = sizeof(channels) / sizeof(float); + +int hopsCompleted = 0; +int counter = 0; + +void setup() +{ + Serial.begin(115200); + + //Begin radio on home channel + Serial.print(F("[SX127x] Initializing ... ")); + int state = radio.begin(channels[0]); + if (state != RADIOLIB_ERR_NONE) + { + Serial.print(F("Failed with code: ")); + Serial.println(state); + } + else + Serial.println(F("Success!")); + + // Set hop period to enable FHSS + // We set an artifically short period to show lots of hops + // HoppingPeriod = Tsym * FreqHoppingPeriod + // Given defaults of spreadfactor = 9, bandwidth = 125, it follows Tsym = 4.10ms + // HoppingPeriod = 4.10 * 9 = 36.9ms. Can be as high as 400ms to be within regulatory limits + radio.setFHSSHoppingPeriod(9); + + Serial.print(F("Hopping period: ")); + Serial.println(radio.getFHSSHoppingPeriod()); + + radio.setDio0Action(dio0ISR); //Called when transmission is finished + radio.setDio1Action(dio1ISR); //Called after a transmission has started, so we can move to next freq + + Serial.print(F("Transmitting packet...")); + + char output[256]; + sprintf(output, "Let's create a really long packet to trigger lots of hop interrupts. A packet can be up to 256 bytes long. This packet is 222 bytes so using sf = 9, bw = 125, timeOnAir is 1488ms. 1488ms / (9*4.10ms) = 40 hops. Counter: %d", counter++); + + radio.startTransmit(output, strlen(output) - 1); +} + +void loop() +{ + if (xmitComplete == true) + { + xmitComplete = false; + Serial.println(F("Transmit complete")); + Serial.print(F("Radio after xmit is on channel: ")); + Serial.println(radio.getFHSSChannel()); + //The FHSS channel is automatically reset to 0 upon end of transmission + + radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); //Return to home channel before next transaction + + Serial.print(F("Hops completed: ")); + Serial.println(hopsCompleted); + hopsCompleted = 0; + + radio.startReceive(); + } + + if (fhssChange == true) + { + radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); + //Serial.print(F("Radio on channel: ")); + //Serial.println(radio.getFHSSChannel()); + + hopsCompleted++; + fhssChange = false; + radio.clearFHSSInt(); + } +} + +//ISR when DIO0 goes low +//Called when transmission is complete or when RX is received +void dio0ISR(void) +{ + xmitComplete = true; +} + +//ISR when DIO1 goes low +//Called when FhssChangeChannel interrupt occurs (at regular HoppingPeriods) +void dio1ISR(void) +{ + fhssChange = true; +} diff --git a/keywords.txt b/keywords.txt index 9167c2a6..31db163d 100644 --- a/keywords.txt +++ b/keywords.txt @@ -142,6 +142,10 @@ setDirectAction KEYWORD2 readBit KEYWORD2 enableBitSync KEYWORD2 disableBitSync KEYWORD2 +setFHSSHoppingPeriod KEYWORD2 +getFHSSHoppingPeriod KEYWORD2 +getFHSSChannel KEYWORD2 +clearFHSSInt KEYWORD2 # RF69-specific setAESKey KEYWORD2 diff --git a/src/modules/SX127x/SX1276.cpp b/src/modules/SX127x/SX1276.cpp index c4c32f9c..fa1b46b8 100644 --- a/src/modules/SX127x/SX1276.cpp +++ b/src/modules/SX127x/SX1276.cpp @@ -70,4 +70,26 @@ int16_t SX1276::setFrequency(float freq) { return(state); } +int16_t SX1276::setFHSSHoppingPeriod(uint8_t freqHoppingPeriod) { + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, freqHoppingPeriod)); +} + +uint8_t SX1276::getFHSSHoppingPeriod(void) { + return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD)); +} + +uint8_t SX1276::getFHSSChannel(void) { + return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 5, 0)); +} + +void SX1276::clearFHSSInt(void) { + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_LORA) { + _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, getIRQFlags() | RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL); + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + return; //These are not the interrupts you are looking for + } +} + + #endif diff --git a/src/modules/SX127x/SX1276.h b/src/modules/SX127x/SX1276.h index cdc4cac5..15006ce3 100644 --- a/src/modules/SX127x/SX1276.h +++ b/src/modules/SX127x/SX1276.h @@ -84,6 +84,34 @@ class SX1276: public SX1278 { */ int16_t setFrequency(float freq); + /*! + \brief Sets the hopping period and enables FHSS + + \param freqHoppingPeriod Integer multiple of symbol periods between hops + + \returns \ref status_codes + */ + int16_t setFHSSHoppingPeriod(uint8_t freqHoppingPeriod); + + /*! + \brief Gets FHSS hopping period + + \returns 8 bit period + */ + uint8_t getFHSSHoppingPeriod(void); + + /*! + \brief Gets the FHSS channel in use + + \returns 6 bit channel number + */ + uint8_t getFHSSChannel(void); + + /*! + \brief Clear the FHSS interrupt + */ + void clearFHSSInt(void); + #if !defined(RADIOLIB_GODMODE) private: #endif diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 24323447..9b099bbc 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -375,7 +375,10 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { int16_t modem = getActiveModem(); if(modem == RADIOLIB_SX127X_LORA) { // set DIO pin mapping - state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_RX_DONE | RADIOLIB_SX127X_DIO1_RX_TIMEOUT, 7, 4); + if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_RX_DONE | RADIOLIB_SX127X_DIO1_FHSS_CHANGE_CHANNEL, 7, 4); + else + state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_RX_DONE | RADIOLIB_SX127X_DIO1_RX_TIMEOUT, 7, 4); // set expected packet length for SF6 if(_sf == 6) { @@ -448,7 +451,10 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { } // set DIO mapping - _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_TX_DONE, 7, 6); + if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) + _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_TX_DONE | RADIOLIB_SX127X_DIO1_FHSS_CHANGE_CHANNEL, 7, 4); + else + _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_TX_DONE, 7, 6); // apply fixes to errata RADIOLIB_ERRATA_SX127X(false); @@ -987,8 +993,11 @@ int16_t SX127x::setOOK(bool enableOOK) { } int16_t SX127x::setFrequencyRaw(float newFreq) { - // set mode to standby - int16_t state = setMode(RADIOLIB_SX127X_STANDBY); + int16_t state = RADIOLIB_ERR_NONE; + + // set mode to standby if not FHSS + if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) == RADIOLIB_SX127X_HOP_PERIOD_OFF) + state = setMode(RADIOLIB_SX127X_STANDBY); // calculate register values uint32_t FRF = (newFreq * (uint32_t(1) << RADIOLIB_SX127X_DIV_EXPONENT)) / RADIOLIB_SX127X_CRYSTAL_FREQ; From 20e1ab23dfff7b9214079d053f1150fce7283cef Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Mon, 17 Jan 2022 11:35:19 -0700 Subject: [PATCH 10/16] Add helper functions for SX1277, SX1278, SX1279 --- src/modules/SX127x/SX1277.cpp | 20 ++++++++++++++++++++ src/modules/SX127x/SX1277.h | 28 ++++++++++++++++++++++++++++ src/modules/SX127x/SX1278.cpp | 21 +++++++++++++++++++++ src/modules/SX127x/SX1278.h | 28 ++++++++++++++++++++++++++++ src/modules/SX127x/SX1279.cpp | 21 +++++++++++++++++++++ src/modules/SX127x/SX1279.h | 28 ++++++++++++++++++++++++++++ src/modules/SX127x/SX127x.cpp | 15 ++++++++++----- 7 files changed, 156 insertions(+), 5 deletions(-) diff --git a/src/modules/SX127x/SX1277.cpp b/src/modules/SX127x/SX1277.cpp index 59250e45..2bc2790a 100644 --- a/src/modules/SX127x/SX1277.cpp +++ b/src/modules/SX127x/SX1277.cpp @@ -100,4 +100,24 @@ int16_t SX1277::setSpreadingFactor(uint8_t sf) { return(state); } +int16_t SX1277::setFHSSHoppingPeriod(uint8_t freqHoppingPeriod) { + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, freqHoppingPeriod)); +} + +uint8_t SX1277::getFHSSHoppingPeriod(void) { + return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD)); +} + +uint8_t SX1277::getFHSSChannel(void) { + return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 5, 0)); +} + +void SX1277::clearFHSSInt(void) { + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_LORA) { + _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, getIRQFlags() | RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL); + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + return; //These are not the interrupts you are looking for + } +} #endif diff --git a/src/modules/SX127x/SX1277.h b/src/modules/SX127x/SX1277.h index b9f7a5cf..fed18de5 100644 --- a/src/modules/SX127x/SX1277.h +++ b/src/modules/SX127x/SX1277.h @@ -93,6 +93,34 @@ class SX1277: public SX1278 { */ int16_t setSpreadingFactor(uint8_t sf); + /*! + \brief Sets the hopping period and enables FHSS + + \param freqHoppingPeriod Integer multiple of symbol periods between hops + + \returns \ref status_codes + */ + int16_t setFHSSHoppingPeriod(uint8_t freqHoppingPeriod); + + /*! + \brief Gets FHSS hopping period + + \returns 8 bit period + */ + uint8_t getFHSSHoppingPeriod(void); + + /*! + \brief Gets the FHSS channel in use + + \returns 6 bit channel number + */ + uint8_t getFHSSChannel(void); + + /*! + \brief Clear the FHSS interrupt + */ + void clearFHSSInt(void); + #if !defined(RADIOLIB_GODMODE) private: #endif diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 317c38ee..71ba02e1 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -623,4 +623,25 @@ void SX1278::errataFix(bool rx) { _mod->SPIsetRegValue(0x30, fixedRegs[2]); } +int16_t SX1278::setFHSSHoppingPeriod(uint8_t freqHoppingPeriod) { + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, freqHoppingPeriod)); +} + +uint8_t SX1278::getFHSSHoppingPeriod(void) { + return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD)); +} + +uint8_t SX1278::getFHSSChannel(void) { + return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 5, 0)); +} + +void SX1278::clearFHSSInt(void) { + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_LORA) { + _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, getIRQFlags() | RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL); + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + return; //These are not the interrupts you are looking for + } +} + #endif diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index 150b97c3..533a0da9 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -302,6 +302,34 @@ class SX1278: public SX127x { */ int16_t explicitHeader(); + /*! + \brief Sets the hopping period and enables FHSS + + \param freqHoppingPeriod Integer multiple of symbol periods between hops + + \returns \ref status_codes + */ + int16_t setFHSSHoppingPeriod(uint8_t freqHoppingPeriod); + + /*! + \brief Gets FHSS hopping period + + \returns 8 bit period + */ + uint8_t getFHSSHoppingPeriod(void); + + /*! + \brief Gets the FHSS channel in use + + \returns 6 bit channel number + */ + uint8_t getFHSSChannel(void); + + /*! + \brief Clear the FHSS interrupt + */ + void clearFHSSInt(void); + #if !defined(RADIOLIB_GODMODE) protected: #endif diff --git a/src/modules/SX127x/SX1279.cpp b/src/modules/SX127x/SX1279.cpp index 1eac9dc9..286d0f47 100644 --- a/src/modules/SX127x/SX1279.cpp +++ b/src/modules/SX127x/SX1279.cpp @@ -70,4 +70,25 @@ int16_t SX1279::setFrequency(float freq) { return(state); } +int16_t SX1279::setFHSSHoppingPeriod(uint8_t freqHoppingPeriod) { + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, freqHoppingPeriod)); +} + +uint8_t SX1279::getFHSSHoppingPeriod(void) { + return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD)); +} + +uint8_t SX1279::getFHSSChannel(void) { + return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 5, 0)); +} + +void SX1279::clearFHSSInt(void) { + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_LORA) { + _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, getIRQFlags() | RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL); + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + return; //These are not the interrupts you are looking for + } +} + #endif diff --git a/src/modules/SX127x/SX1279.h b/src/modules/SX127x/SX1279.h index c9ff8ab0..5328213b 100644 --- a/src/modules/SX127x/SX1279.h +++ b/src/modules/SX127x/SX1279.h @@ -84,6 +84,34 @@ class SX1279: public SX1278 { */ int16_t setFrequency(float freq); + /*! + \brief Sets the hopping period and enables FHSS + + \param freqHoppingPeriod Integer multiple of symbol periods between hops + + \returns \ref status_codes + */ + int16_t setFHSSHoppingPeriod(uint8_t freqHoppingPeriod); + + /*! + \brief Gets FHSS hopping period + + \returns 8 bit period + */ + uint8_t getFHSSHoppingPeriod(void); + + /*! + \brief Gets the FHSS channel in use + + \returns 6 bit channel number + */ + uint8_t getFHSSChannel(void); + + /*! + \brief Clear the FHSS interrupt + */ + void clearFHSSInt(void); + #if !defined(RADIOLIB_GODMODE) private: #endif diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 9b099bbc..15736a0a 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -375,10 +375,12 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { int16_t modem = getActiveModem(); if(modem == RADIOLIB_SX127X_LORA) { // set DIO pin mapping - if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) + if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) { state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_RX_DONE | RADIOLIB_SX127X_DIO1_FHSS_CHANGE_CHANNEL, 7, 4); - else + } + else { state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_RX_DONE | RADIOLIB_SX127X_DIO1_RX_TIMEOUT, 7, 4); + } // set expected packet length for SF6 if(_sf == 6) { @@ -451,10 +453,12 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { } // set DIO mapping - if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) + if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) { _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_TX_DONE | RADIOLIB_SX127X_DIO1_FHSS_CHANGE_CHANNEL, 7, 4); - else + } + else { _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_TX_DONE, 7, 6); + } // apply fixes to errata RADIOLIB_ERRATA_SX127X(false); @@ -996,8 +1000,9 @@ int16_t SX127x::setFrequencyRaw(float newFreq) { int16_t state = RADIOLIB_ERR_NONE; // set mode to standby if not FHSS - if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) == RADIOLIB_SX127X_HOP_PERIOD_OFF) + if(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) == RADIOLIB_SX127X_HOP_PERIOD_OFF) { state = setMode(RADIOLIB_SX127X_STANDBY); + } // calculate register values uint32_t FRF = (newFreq * (uint32_t(1) << RADIOLIB_SX127X_DIV_EXPONENT)) / RADIOLIB_SX127X_CRYSTAL_FREQ; From c4fec32965abd7e81ce4e6b7f6fbf1abfcfddefd Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Mon, 17 Jan 2022 11:43:13 -0700 Subject: [PATCH 11/16] Change coding style to match library style guide. --- .../SX127x_Receive_FHSS.ino | 86 ++++++++----------- .../SX127x_Transmit_FHSS.ino | 83 ++++++++---------- 2 files changed, 73 insertions(+), 96 deletions(-) diff --git a/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino b/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino index d45bec3b..7ee31b83 100644 --- a/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino +++ b/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino @@ -18,68 +18,61 @@ The SX1276 / 7 / 8 / 9 supports FHSS or Frequency Hopping Spread Spectrum. Once a hopping period is set and a transmission is started the radio will begin triggering interrupts every hop period where the radio frequency - is changed to the next channel. This allows a simple mechanism to abide by - the FCC 400ms max dwell time rule. - https://www.govinfo.gov/content/pkg/CFR-2019-title47-vol1/pdf/CFR-2019-title47-vol1-sec15-247.pdf + is changed to the next channel. */ #include //Click here to get the library: http://librarymanager/All#RadioLib -//Pins for RFM97 100mW Shield to SparkFun ESP32 Thing Plus C -int pin_cs = 15; -int pin_dio0 = 26; -int pin_dio1 = 25; -int pin_rst = 32; +// SX1276 has the following connections: +const int pin_cs = 10; +const int pin_dio0 = 2; +const int pin_dio1 = 9; +const int pin_rst = 3; SX1276 radio = new Module(pin_cs, pin_dio0, pin_rst, pin_dio1); -int counter = 0; - volatile bool rxComplete = false; volatile bool fhssChange = false; -//The channel frequencies can be generated randomly or hard coded +// the channel frequencies can be generated randomly or hard coded float channels[] = {908.0, 906.0, 907.0, 905.0, 903.0, 910.0, 909.0}; int numberOfChannels = sizeof(channels) / sizeof(float); int hopsCompleted = 0; -void setup() -{ - Serial.begin(115200); +void setup() { + Serial.begin(9600); - //Begin radio on home channel + // begin radio on home channel Serial.print(F("[SX127x] Initializing ... ")); int state = radio.begin(channels[0]); - if (state != RADIOLIB_ERR_NONE) - { + if (state != RADIOLIB_ERR_NONE) { Serial.print(F("Failed with code: ")); Serial.println(state); } else Serial.println(F("Success!")); - // Set hop period to enable FHSS - // We set an artifically short period to show lots of hops - // HoppingPeriod = Tsym * FreqHoppingPeriod - // Given defaults of spreadfactor = 9, bandwidth = 125, it follows Tsym = 4.10ms - // HoppingPeriod = 4.10 * 9 = 36.9ms. Can be as high as 400ms to be within regulatory limits - radio.setFHSSHoppingPeriod(9); + // set hop period to enable FHSS + state = radio.setFHSSHoppingPeriod(9); + if (state != RADIOLIB_ERR_NONE) { + Serial.print(F("Error setting hopping period: ")); + Serial.println(state); + } + radio.setDio0Action(dio0ISR); // called when transmission is finished + radio.setDio1Action(dio1ISR); // called after a transmission has started, so we can move to next freq - Serial.print(F("Hopping period: ")); - Serial.println(radio.getFHSSHoppingPeriod()); - - radio.setDio0Action(dio0ISR); //Called when transmission is finished - radio.setDio1Action(dio1ISR); //Called after a transmission has started, so we can move to next freq - - radio.startReceive(); - - Serial.println(F("Waiting for new packet")); + // start listening for LoRa packets + Serial.print(F("[SX1278] Starting to listen ... ")); + state = radio.startReceive(); + if (state != RADIOLIB_ERR_NONE) { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } } -void loop() -{ - if (rxComplete == true) - { +void loop() { + if (rxComplete == true) { uint8_t incomingBuffer[255]; radio.readData(incomingBuffer, 255); uint8_t receivedBytes = radio.getPacketLength(); @@ -95,11 +88,8 @@ void loop() rxComplete = false; } - if (fhssChange == true) - { + if (fhssChange == true) { radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); - //Serial.print(F("Radio on channel: ")); - //Serial.println(radio.getFHSSChannel()); hopsCompleted++; radio.clearFHSSInt(); @@ -107,16 +97,14 @@ void loop() } } -//ISR when DIO0 goes low -//Called when transmission is complete or when RX is received -void dio0ISR(void) -{ +// ISR when DIO0 goes low +// called when transmission is complete or when RX is received +void dio0ISR(void) { rxComplete = true; } -//ISR when DIO1 goes low -//Called when FhssChangeChannel interrupt occurs (at the beginning of each transmission) -void dio1ISR(void) -{ +// ISR when DIO1 goes low +// called when FhssChangeChannel interrupt occurs (at the beginning of each transmission) +void dio1ISR(void) { fhssChange = true; -} +} \ No newline at end of file diff --git a/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino b/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino index 504852e0..f1ecbaf8 100644 --- a/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino +++ b/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino @@ -18,77 +18,71 @@ The SX1276 / 7 / 8 / 9 supports FHSS or Frequency Hopping Spread Spectrum. Once a hopping period is set and a transmission is started the radio will begin triggering interrupts every hop period where the radio frequency - is changed to the next channel. This allows a simple mechanism to abide by - the FCC 400ms max dwell time rule. - https://www.govinfo.gov/content/pkg/CFR-2019-title47-vol1/pdf/CFR-2019-title47-vol1-sec15-247.pdf + is changed to the next channel. */ #include //Click here to get the library: http://librarymanager/All#RadioLib -//Pins for SparkFun 1W EBYTE Breakout to Uno -int pin_cs = 7; -int pin_dio0 = 3; -int pin_dio1 = 2; -int pin_rst = A2; +// SX1276 has the following connections: +const int pin_cs = 10; +const int pin_dio0 = 2; +const int pin_dio1 = 9; +const int pin_rst = 3; SX1276 radio = new Module(pin_cs, pin_dio0, pin_rst, pin_dio1); volatile bool xmitComplete = false; volatile bool fhssChange = false; -//The channel frequencies can be generated randomly or hard coded +// the channel frequencies can be generated randomly or hard coded float channels[] = {908.0, 906.0, 907.0, 905.0, 903.0, 910.0, 909.0}; int numberOfChannels = sizeof(channels) / sizeof(float); int hopsCompleted = 0; int counter = 0; -void setup() -{ - Serial.begin(115200); +void setup() { + Serial.begin(9600); - //Begin radio on home channel + // begin radio on home channel Serial.print(F("[SX127x] Initializing ... ")); int state = radio.begin(channels[0]); - if (state != RADIOLIB_ERR_NONE) - { + if (state != RADIOLIB_ERR_NONE) { Serial.print(F("Failed with code: ")); Serial.println(state); } else Serial.println(F("Success!")); - // Set hop period to enable FHSS - // We set an artifically short period to show lots of hops - // HoppingPeriod = Tsym * FreqHoppingPeriod - // Given defaults of spreadfactor = 9, bandwidth = 125, it follows Tsym = 4.10ms - // HoppingPeriod = 4.10 * 9 = 36.9ms. Can be as high as 400ms to be within regulatory limits - radio.setFHSSHoppingPeriod(9); + // set hop period to enable FHSS + state = radio.setFHSSHoppingPeriod(9); + if(state != RADIOLIB_ERR_NONE) { + Serial.print(F("Error setting hopping period: ")); + Serial.println(state); + } - Serial.print(F("Hopping period: ")); - Serial.println(radio.getFHSSHoppingPeriod()); - - radio.setDio0Action(dio0ISR); //Called when transmission is finished - radio.setDio1Action(dio1ISR); //Called after a transmission has started, so we can move to next freq + radio.setDio0Action(dio0ISR); // called when transmission is finished + radio.setDio1Action(dio1ISR); // called after a transmission has started, so we can move to next freq Serial.print(F("Transmitting packet...")); - char output[256]; - sprintf(output, "Let's create a really long packet to trigger lots of hop interrupts. A packet can be up to 256 bytes long. This packet is 222 bytes so using sf = 9, bw = 125, timeOnAir is 1488ms. 1488ms / (9*4.10ms) = 40 hops. Counter: %d", counter++); + String longOutput = "Let's create a really long packet to trigger lots of hop interrupts. A packet can be up to 256 bytes long. This packet is 222 bytes so using sf = 9, bw = 125, timeOnAir is 1488ms. 1488ms / (9*4.10ms) = 40 hops. Counter: "; - radio.startTransmit(output, strlen(output) - 1); + state = radio.startTransmit(longOutput + counter); + if (state != RADIOLIB_ERR_NONE) { + Serial.print(F("Error transmitting with code: ")); + Serial.println(state); + } } -void loop() -{ - if (xmitComplete == true) - { +void loop() { + if (xmitComplete == true) { xmitComplete = false; Serial.println(F("Transmit complete")); Serial.print(F("Radio after xmit is on channel: ")); Serial.println(radio.getFHSSChannel()); - //The FHSS channel is automatically reset to 0 upon end of transmission + // the FHSS channel is automatically reset to 0 upon end of transmission - radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); //Return to home channel before next transaction + radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); // Return to home channel before next transaction Serial.print(F("Hops completed: ")); Serial.println(hopsCompleted); @@ -97,11 +91,8 @@ void loop() radio.startReceive(); } - if (fhssChange == true) - { + if (fhssChange == true) { radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); - //Serial.print(F("Radio on channel: ")); - //Serial.println(radio.getFHSSChannel()); hopsCompleted++; fhssChange = false; @@ -109,16 +100,14 @@ void loop() } } -//ISR when DIO0 goes low -//Called when transmission is complete or when RX is received -void dio0ISR(void) -{ +// ISR when DIO0 goes low +// called when transmission is complete or when RX is received +void dio0ISR(void) { xmitComplete = true; } -//ISR when DIO1 goes low -//Called when FhssChangeChannel interrupt occurs (at regular HoppingPeriods) -void dio1ISR(void) -{ +// ISR when DIO1 goes low +// called when FhssChangeChannel interrupt occurs (at regular HoppingPeriods) +void dio1ISR(void) { fhssChange = true; } From 06ef449b68fb698914d4becaff2fa18b099bb489 Mon Sep 17 00:00:00 2001 From: Nathan Seidle Date: Mon, 17 Jan 2022 11:47:49 -0700 Subject: [PATCH 12/16] Move helper functions from SX1276/7/8/9 to global SX127x. --- src/modules/SX127x/SX1276.cpp | 22 ---------------------- src/modules/SX127x/SX1276.h | 28 ---------------------------- src/modules/SX127x/SX1277.cpp | 20 -------------------- src/modules/SX127x/SX1277.h | 28 ---------------------------- src/modules/SX127x/SX1278.cpp | 21 --------------------- src/modules/SX127x/SX1278.h | 28 ---------------------------- src/modules/SX127x/SX1279.cpp | 21 --------------------- src/modules/SX127x/SX1279.h | 28 ---------------------------- src/modules/SX127x/SX127x.cpp | 21 +++++++++++++++++++++ src/modules/SX127x/SX127x.h | 28 ++++++++++++++++++++++++++++ 10 files changed, 49 insertions(+), 196 deletions(-) diff --git a/src/modules/SX127x/SX1276.cpp b/src/modules/SX127x/SX1276.cpp index fa1b46b8..c4c32f9c 100644 --- a/src/modules/SX127x/SX1276.cpp +++ b/src/modules/SX127x/SX1276.cpp @@ -70,26 +70,4 @@ int16_t SX1276::setFrequency(float freq) { return(state); } -int16_t SX1276::setFHSSHoppingPeriod(uint8_t freqHoppingPeriod) { - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, freqHoppingPeriod)); -} - -uint8_t SX1276::getFHSSHoppingPeriod(void) { - return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD)); -} - -uint8_t SX1276::getFHSSChannel(void) { - return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 5, 0)); -} - -void SX1276::clearFHSSInt(void) { - int16_t modem = getActiveModem(); - if(modem == RADIOLIB_SX127X_LORA) { - _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, getIRQFlags() | RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL); - } else if(modem == RADIOLIB_SX127X_FSK_OOK) { - return; //These are not the interrupts you are looking for - } -} - - #endif diff --git a/src/modules/SX127x/SX1276.h b/src/modules/SX127x/SX1276.h index 15006ce3..cdc4cac5 100644 --- a/src/modules/SX127x/SX1276.h +++ b/src/modules/SX127x/SX1276.h @@ -84,34 +84,6 @@ class SX1276: public SX1278 { */ int16_t setFrequency(float freq); - /*! - \brief Sets the hopping period and enables FHSS - - \param freqHoppingPeriod Integer multiple of symbol periods between hops - - \returns \ref status_codes - */ - int16_t setFHSSHoppingPeriod(uint8_t freqHoppingPeriod); - - /*! - \brief Gets FHSS hopping period - - \returns 8 bit period - */ - uint8_t getFHSSHoppingPeriod(void); - - /*! - \brief Gets the FHSS channel in use - - \returns 6 bit channel number - */ - uint8_t getFHSSChannel(void); - - /*! - \brief Clear the FHSS interrupt - */ - void clearFHSSInt(void); - #if !defined(RADIOLIB_GODMODE) private: #endif diff --git a/src/modules/SX127x/SX1277.cpp b/src/modules/SX127x/SX1277.cpp index 2bc2790a..59250e45 100644 --- a/src/modules/SX127x/SX1277.cpp +++ b/src/modules/SX127x/SX1277.cpp @@ -100,24 +100,4 @@ int16_t SX1277::setSpreadingFactor(uint8_t sf) { return(state); } -int16_t SX1277::setFHSSHoppingPeriod(uint8_t freqHoppingPeriod) { - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, freqHoppingPeriod)); -} - -uint8_t SX1277::getFHSSHoppingPeriod(void) { - return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD)); -} - -uint8_t SX1277::getFHSSChannel(void) { - return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 5, 0)); -} - -void SX1277::clearFHSSInt(void) { - int16_t modem = getActiveModem(); - if(modem == RADIOLIB_SX127X_LORA) { - _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, getIRQFlags() | RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL); - } else if(modem == RADIOLIB_SX127X_FSK_OOK) { - return; //These are not the interrupts you are looking for - } -} #endif diff --git a/src/modules/SX127x/SX1277.h b/src/modules/SX127x/SX1277.h index fed18de5..b9f7a5cf 100644 --- a/src/modules/SX127x/SX1277.h +++ b/src/modules/SX127x/SX1277.h @@ -93,34 +93,6 @@ class SX1277: public SX1278 { */ int16_t setSpreadingFactor(uint8_t sf); - /*! - \brief Sets the hopping period and enables FHSS - - \param freqHoppingPeriod Integer multiple of symbol periods between hops - - \returns \ref status_codes - */ - int16_t setFHSSHoppingPeriod(uint8_t freqHoppingPeriod); - - /*! - \brief Gets FHSS hopping period - - \returns 8 bit period - */ - uint8_t getFHSSHoppingPeriod(void); - - /*! - \brief Gets the FHSS channel in use - - \returns 6 bit channel number - */ - uint8_t getFHSSChannel(void); - - /*! - \brief Clear the FHSS interrupt - */ - void clearFHSSInt(void); - #if !defined(RADIOLIB_GODMODE) private: #endif diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 71ba02e1..317c38ee 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -623,25 +623,4 @@ void SX1278::errataFix(bool rx) { _mod->SPIsetRegValue(0x30, fixedRegs[2]); } -int16_t SX1278::setFHSSHoppingPeriod(uint8_t freqHoppingPeriod) { - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, freqHoppingPeriod)); -} - -uint8_t SX1278::getFHSSHoppingPeriod(void) { - return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD)); -} - -uint8_t SX1278::getFHSSChannel(void) { - return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 5, 0)); -} - -void SX1278::clearFHSSInt(void) { - int16_t modem = getActiveModem(); - if(modem == RADIOLIB_SX127X_LORA) { - _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, getIRQFlags() | RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL); - } else if(modem == RADIOLIB_SX127X_FSK_OOK) { - return; //These are not the interrupts you are looking for - } -} - #endif diff --git a/src/modules/SX127x/SX1278.h b/src/modules/SX127x/SX1278.h index 533a0da9..150b97c3 100644 --- a/src/modules/SX127x/SX1278.h +++ b/src/modules/SX127x/SX1278.h @@ -302,34 +302,6 @@ class SX1278: public SX127x { */ int16_t explicitHeader(); - /*! - \brief Sets the hopping period and enables FHSS - - \param freqHoppingPeriod Integer multiple of symbol periods between hops - - \returns \ref status_codes - */ - int16_t setFHSSHoppingPeriod(uint8_t freqHoppingPeriod); - - /*! - \brief Gets FHSS hopping period - - \returns 8 bit period - */ - uint8_t getFHSSHoppingPeriod(void); - - /*! - \brief Gets the FHSS channel in use - - \returns 6 bit channel number - */ - uint8_t getFHSSChannel(void); - - /*! - \brief Clear the FHSS interrupt - */ - void clearFHSSInt(void); - #if !defined(RADIOLIB_GODMODE) protected: #endif diff --git a/src/modules/SX127x/SX1279.cpp b/src/modules/SX127x/SX1279.cpp index 286d0f47..1eac9dc9 100644 --- a/src/modules/SX127x/SX1279.cpp +++ b/src/modules/SX127x/SX1279.cpp @@ -70,25 +70,4 @@ int16_t SX1279::setFrequency(float freq) { return(state); } -int16_t SX1279::setFHSSHoppingPeriod(uint8_t freqHoppingPeriod) { - return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, freqHoppingPeriod)); -} - -uint8_t SX1279::getFHSSHoppingPeriod(void) { - return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD)); -} - -uint8_t SX1279::getFHSSChannel(void) { - return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 5, 0)); -} - -void SX1279::clearFHSSInt(void) { - int16_t modem = getActiveModem(); - if(modem == RADIOLIB_SX127X_LORA) { - _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, getIRQFlags() | RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL); - } else if(modem == RADIOLIB_SX127X_FSK_OOK) { - return; //These are not the interrupts you are looking for - } -} - #endif diff --git a/src/modules/SX127x/SX1279.h b/src/modules/SX127x/SX1279.h index 5328213b..c9ff8ab0 100644 --- a/src/modules/SX127x/SX1279.h +++ b/src/modules/SX127x/SX1279.h @@ -84,34 +84,6 @@ class SX1279: public SX1278 { */ int16_t setFrequency(float freq); - /*! - \brief Sets the hopping period and enables FHSS - - \param freqHoppingPeriod Integer multiple of symbol periods between hops - - \returns \ref status_codes - */ - int16_t setFHSSHoppingPeriod(uint8_t freqHoppingPeriod); - - /*! - \brief Gets FHSS hopping period - - \returns 8 bit period - */ - uint8_t getFHSSHoppingPeriod(void); - - /*! - \brief Gets the FHSS channel in use - - \returns 6 bit channel number - */ - uint8_t getFHSSChannel(void); - - /*! - \brief Clear the FHSS interrupt - */ - void clearFHSSInt(void); - #if !defined(RADIOLIB_GODMODE) private: #endif diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 15736a0a..1db50c20 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -1367,4 +1367,25 @@ void SX127x::readBit(RADIOLIB_PIN_TYPE pin) { updateDirectBuffer((uint8_t)digitalRead(pin)); } +int16_t SX127x::setFHSSHoppingPeriod(uint8_t freqHoppingPeriod) { + return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, freqHoppingPeriod)); +} + +uint8_t SX127x::getFHSSHoppingPeriod(void) { + return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD)); +} + +uint8_t SX127x::getFHSSChannel(void) { + return(_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 5, 0)); +} + +void SX127x::clearFHSSInt(void) { + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_LORA) { + _mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, getIRQFlags() | RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL); + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + return; //These are not the interrupts you are looking for + } +} + #endif diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index 66ab01c8..b0671bac 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -1073,6 +1073,34 @@ class SX127x: public PhysicalLayer { */ void readBit(RADIOLIB_PIN_TYPE pin); + /*! + \brief Sets the hopping period and enables FHSS + + \param freqHoppingPeriod Integer multiple of symbol periods between hops + + \returns \ref status_codes + */ + int16_t setFHSSHoppingPeriod(uint8_t freqHoppingPeriod); + + /*! + \brief Gets FHSS hopping period + + \returns 8 bit period + */ + uint8_t getFHSSHoppingPeriod(void); + + /*! + \brief Gets the FHSS channel in use + + \returns 6 bit channel number + */ + uint8_t getFHSSChannel(void); + + /*! + \brief Clear the FHSS interrupt + */ + void clearFHSSInt(void); + #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) protected: #endif From 636719854642d841351105fa77f2f58caba1fb9c Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Jan 2022 10:21:28 +0100 Subject: [PATCH 13/16] [SX127x] Fixed shaping disable (#452) --- src/modules/SX127x/SX1278.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 317c38ee..685fe175 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -314,6 +314,11 @@ int16_t SX1278::setDataShaping(uint8_t sh) { // check modulation if(SX127x::_ook) { + // we're in OOK mode, the only thing we can do is disable + if(sh == RADIOLIB_SHAPING_NONE) { + return(setDataShapingOOK(0)); + } + return(RADIOLIB_ERR_INVALID_MODULATION); } From 73e3da212a79ba0c6498083890201f4b7c7bf33f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Jan 2022 12:05:30 +0100 Subject: [PATCH 14/16] [SX127x] Updated FHSS example formatting --- .../SX127x_Receive_FHSS.ino | 162 +++++++++++----- .../SX127x_Transmit_FHSS.ino | 179 ++++++++++++------ 2 files changed, 239 insertions(+), 102 deletions(-) diff --git a/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino b/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino index 7ee31b83..3aeca4a8 100644 --- a/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino +++ b/examples/SX127x/SX127x_Receive_FHSS/SX127x_Receive_FHSS.ino @@ -15,56 +15,98 @@ For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ - The SX1276 / 7 / 8 / 9 supports FHSS or Frequency Hopping Spread Spectrum. - Once a hopping period is set and a transmission is started the radio + SX127x supports FHSS or Frequency Hopping Spread Spectrum. + Once a hopping period is set and a transmission is started, the radio will begin triggering interrupts every hop period where the radio frequency is changed to the next channel. */ -#include //Click here to get the library: http://librarymanager/All#RadioLib +#include -// SX1276 has the following connections: -const int pin_cs = 10; -const int pin_dio0 = 2; -const int pin_dio1 = 9; -const int pin_rst = 3; -SX1276 radio = new Module(pin_cs, pin_dio0, pin_rst, pin_dio1); +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); -volatile bool rxComplete = false; -volatile bool fhssChange = false; +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// flag to indicate frequency must be changed +volatile bool fhssChangeFlag = false; // the channel frequencies can be generated randomly or hard coded -float channels[] = {908.0, 906.0, 907.0, 905.0, 903.0, 910.0, 909.0}; +// NOTE: The frequency list MUST be the same on both sides! +float channels[] = { 433.0, 433.4, 433.2, 433.6, 434.0, 433.8 }; int numberOfChannels = sizeof(channels) / sizeof(float); +// counter to keep track of how many frequency hops were performed int hopsCompleted = 0; +// 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 setRxFlag(void) { + receivedFlag = true; +} + +// this function is called when FhssChangeChannel interrupt occurs +// (at the beginning of each transmission) +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFHSSFlag(void) { + fhssChangeFlag = true; +} + void setup() { Serial.begin(9600); // begin radio on home channel - Serial.print(F("[SX127x] Initializing ... ")); + Serial.print(F("[SX1278] Initializing ... ")); int state = radio.begin(channels[0]); - if (state != RADIOLIB_ERR_NONE) { - Serial.print(F("Failed with code: ")); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); Serial.println(state); + while (true); } - else - Serial.println(F("Success!")); - // set hop period to enable FHSS + // set hop period in symbols + // this will also enable FHSS state = radio.setFHSSHoppingPeriod(9); - if (state != RADIOLIB_ERR_NONE) { - Serial.print(F("Error setting hopping period: ")); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); Serial.println(state); + while (true); } - radio.setDio0Action(dio0ISR); // called when transmission is finished - radio.setDio1Action(dio1ISR); // called after a transmission has started, so we can move to next freq + + // set the function to call when reception is finished + radio.setDio0Action(setRxFlag); + + // set the function to call when we need to hcange frequency + radio.setDio1Action(setFHSSFlag); // start listening for LoRa packets Serial.print(F("[SX1278] Starting to listen ... ")); state = radio.startReceive(); - if (state != RADIOLIB_ERR_NONE) { + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { Serial.print(F("failed, code ")); Serial.println(state); while (true); @@ -72,39 +114,67 @@ void setup() { } void loop() { - if (rxComplete == true) { - uint8_t incomingBuffer[255]; - radio.readData(incomingBuffer, 255); - uint8_t receivedBytes = radio.getPacketLength(); - Serial.write(incomingBuffer, receivedBytes); - Serial.println(); + // check if the reception flag is set + if (receivedFlag == true) { + // you can read received data as an Arduino String + String str; + int state = radio.readData(str); - Serial.print(F("Hops completed: ")); + // you can also read received data as byte array + /* + byte byteArr[8]; + int state = radio.readData(byteArr, 8); + */ + + if (state == RADIOLIB_ERR_NONE) { + // packet was successfully received + Serial.println(F("[SX1278] Received packet!")); + + // print data of the packet + Serial.print(F("[SX1278] Data:\t\t")); + Serial.println(str); + + } else if (state == RADIOLIB_ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("[SX1278] CRC error!")); + + } else { + // some other error occurred + Serial.print(F("[SX1278] Failed, code ")); + Serial.println(state); + + } + + // print the number of hops it took + Serial.print(F("[SX1278] Hops completed: ")); Serial.println(hopsCompleted); + + // reset the counter hopsCompleted = 0; + // put the module back to listen mode radio.startReceive(); - rxComplete = false; + // we're ready to receive more packets, clear the flag + receivedFlag = false; } - if (fhssChange == true) { - radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); + // check if we need to do another frequency hop + if (fhssChangeFlag == true) { + // we do, change it now + int state = radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); + if (state != RADIOLIB_ERR_NONE) { + Serial.print(F("[SX1278] Failed to change frequency, code ")); + Serial.println(state); + } + // increment the counter hopsCompleted++; + + // clear the FHSS interrupt radio.clearFHSSInt(); - fhssChange = false; + + // we're ready to do another hop, clear the flag + fhssChangeFlag = false; } } - -// ISR when DIO0 goes low -// called when transmission is complete or when RX is received -void dio0ISR(void) { - rxComplete = true; -} - -// ISR when DIO1 goes low -// called when FhssChangeChannel interrupt occurs (at the beginning of each transmission) -void dio1ISR(void) { - fhssChange = true; -} \ No newline at end of file diff --git a/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino b/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino index f1ecbaf8..b6182af5 100644 --- a/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino +++ b/examples/SX127x/SX127x_Transmit_FHSS/SX127x_Transmit_FHSS.ino @@ -15,99 +15,166 @@ For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ - The SX1276 / 7 / 8 / 9 supports FHSS or Frequency Hopping Spread Spectrum. - Once a hopping period is set and a transmission is started the radio + SX127x supports FHSS or Frequency Hopping Spread Spectrum. + Once a hopping period is set and a transmission is started, the radio will begin triggering interrupts every hop period where the radio frequency is changed to the next channel. */ -#include //Click here to get the library: http://librarymanager/All#RadioLib +#include -// SX1276 has the following connections: -const int pin_cs = 10; -const int pin_dio0 = 2; -const int pin_dio1 = 9; -const int pin_rst = 3; -SX1276 radio = new Module(pin_cs, pin_dio0, pin_rst, pin_dio1); +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); -volatile bool xmitComplete = false; -volatile bool fhssChange = false; +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// flag to indicate that a packet was received +volatile bool transmittedFlag = false; + +// flag to indicate frequency must be changed +volatile bool fhssChangeFlag = false; // the channel frequencies can be generated randomly or hard coded -float channels[] = {908.0, 906.0, 907.0, 905.0, 903.0, 910.0, 909.0}; +// NOTE: The frequency list MUST be the same on both sides! +float channels[] = { 433.0, 433.4, 433.2, 433.6, 434.0, 433.8 }; int numberOfChannels = sizeof(channels) / sizeof(float); +// counter to keep track of how many frequency hops were performed int hopsCompleted = 0; -int counter = 0; + +// counter that increments with each sent packet +int packetCounter = 0; + +// save transmission state between loops +int transmissionState = RADIOLIB_ERR_NONE; + +// this is the packet that will be sent +String longPacket = "Let's create a really long packet to trigger \ +lots of hop interrupts. A packet can be up to 256 bytes long. \ +This packet is 222 bytes so using sf = 9, bw = 125, timeOnAir is \ +1488ms. 1488ms / (9*4.10ms) = 40 hops. Counter: "; + +// this function is called when a complete packet +// is transmitted 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 setTxFlag(void) { + transmittedFlag = true; +} + +// this function is called when FhssChangeChannel interrupt occurs +// (at the beginning of each transmission) +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +#if defined(ESP8266) || defined(ESP32) + ICACHE_RAM_ATTR +#endif +void setFHSSFlag(void) { + fhssChangeFlag = true; +} void setup() { Serial.begin(9600); // begin radio on home channel - Serial.print(F("[SX127x] Initializing ... ")); + Serial.print(F("[SX1278] Initializing ... ")); int state = radio.begin(channels[0]); - if (state != RADIOLIB_ERR_NONE) { - Serial.print(F("Failed with code: ")); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); Serial.println(state); + while (true); } - else - Serial.println(F("Success!")); - // set hop period to enable FHSS + // set hop period in symbols + // this will also enable FHSS state = radio.setFHSSHoppingPeriod(9); - if(state != RADIOLIB_ERR_NONE) { - Serial.print(F("Error setting hopping period: ")); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); Serial.println(state); + while (true); } - radio.setDio0Action(dio0ISR); // called when transmission is finished - radio.setDio1Action(dio1ISR); // called after a transmission has started, so we can move to next freq + // set the function to call when transmission is finished + radio.setDio0Action(setTxFlag); - Serial.print(F("Transmitting packet...")); + // set the function to call when we need to hcange frequency + radio.setDio1Action(setFHSSFlag); - String longOutput = "Let's create a really long packet to trigger lots of hop interrupts. A packet can be up to 256 bytes long. This packet is 222 bytes so using sf = 9, bw = 125, timeOnAir is 1488ms. 1488ms / (9*4.10ms) = 40 hops. Counter: "; - - state = radio.startTransmit(longOutput + counter); - if (state != RADIOLIB_ERR_NONE) { - Serial.print(F("Error transmitting with code: ")); - Serial.println(state); - } + // start transmitting the first packet + Serial.print(F("[SX1278] Sending first packet ... ")); + transmissionState = radio.startTransmit(longPacket + packetCounter); } void loop() { - if (xmitComplete == true) { - xmitComplete = false; - Serial.println(F("Transmit complete")); - Serial.print(F("Radio after xmit is on channel: ")); + // check if the transmission flag is set + if (transmittedFlag == true) { + // reset flag + transmittedFlag = false; + + if (transmissionState == RADIOLIB_ERR_NONE) { + // packet was successfully sent + Serial.println(F("transmission finished!")); + + } else { + Serial.print(F("failed, code ")); + Serial.println(transmissionState); + + } + + // The channel is automatically reset to 0 upon completion + Serial.print(F("[SX1278] Radio is on channel: ")); Serial.println(radio.getFHSSChannel()); - // the FHSS channel is automatically reset to 0 upon end of transmission - radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); // Return to home channel before next transaction - - Serial.print(F("Hops completed: ")); + // print the number of hops it took + Serial.print(F("[SX1278] Hops completed: ")); Serial.println(hopsCompleted); + + // reset the counter hopsCompleted = 0; - radio.startReceive(); - } - - if (fhssChange == true) { + // return to home channel before the next transaction radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); + // wait a second before transmitting again + delay(1000); + + // increment the packet counter + packetCounter++; + + // send another packet + Serial.print(F("[SX1278] Sending another packet ... ")); + transmissionState = radio.startTransmit(longPacket + packetCounter); + } + + // check if we need to do another frequency hop + if (fhssChangeFlag == true) { + // we do, change it now + int state = radio.setFrequency(channels[radio.getFHSSChannel() % numberOfChannels]); + if (state != RADIOLIB_ERR_NONE) { + Serial.print(F("[SX1278] Failed to change frequency, code ")); + Serial.println(state); + } + + // increment the counter hopsCompleted++; - fhssChange = false; + + // clear the FHSS interrupt radio.clearFHSSInt(); + + // we're ready to do another hop, clear the flag + fhssChangeFlag = false; } } - -// ISR when DIO0 goes low -// called when transmission is complete or when RX is received -void dio0ISR(void) { - xmitComplete = true; -} - -// ISR when DIO1 goes low -// called when FhssChangeChannel interrupt occurs (at regular HoppingPeriods) -void dio1ISR(void) { - fhssChange = true; -} From 0de8ef6bce29c5e4fbbe34226d5b827a77888f05 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Jan 2022 12:05:50 +0100 Subject: [PATCH 15/16] [SX127x] Fixed typo --- .../SX127x/SX127x_PingPong/SX127x_PingPong.ino | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino b/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino index cd505a06..e403c902 100644 --- a/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino +++ b/examples/SX127x/SX127x_PingPong/SX127x_PingPong.ino @@ -48,7 +48,7 @@ void setFlag(void) { return; } - // we sent aor received packet, set the flag + // we sent or received packet, set the flag operationDone = true; } @@ -105,17 +105,17 @@ void loop() { if (transmissionState == RADIOLIB_ERR_NONE) { // packet was successfully sent Serial.println(F("transmission finished!")); - + } else { Serial.print(F("failed, code ")); Serial.println(transmissionState); - + } // listen for response radio.startReceive(); transmitFlag = false; - + } else { // the previous operation was reception // print data and send another packet @@ -125,21 +125,21 @@ void loop() { if (state == RADIOLIB_ERR_NONE) { // packet was successfully received Serial.println(F("[SX1278] Received packet!")); - + // print data of the packet Serial.print(F("[SX1278] Data:\t\t")); Serial.println(str); - + // print RSSI (Received Signal Strength Indicator) Serial.print(F("[SX1278] RSSI:\t\t")); Serial.print(radio.getRSSI()); Serial.println(F(" dBm")); - + // print SNR (Signal-to-Noise Ratio) Serial.print(F("[SX1278] SNR:\t\t")); Serial.print(radio.getSNR()); Serial.println(F(" dB")); - + } // wait a second before transmitting again @@ -154,6 +154,6 @@ void loop() { // we're ready to process more packets, // enable interrupt service routine enableInterrupt = true; - + } } From 19109bc7d84e462b1309b7e05332a8f112b4dcb4 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 23 Jan 2022 17:05:58 +0100 Subject: [PATCH 16/16] [Si443x] Added fixed packet length mode --- src/modules/Si443x/Si443x.cpp | 34 ++++++++++++++++++++++++++++++++-- src/modules/Si443x/Si443x.h | 20 ++++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index 1e4221e9..90bba72e 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -61,6 +61,8 @@ int16_t Si443x::begin(float br, float freqDev, float rxBw, uint8_t preambleLen) state = setEncoding(0); RADIOLIB_ASSERT(state); + state = variablePacketLengthMode(); + return(state); } @@ -233,8 +235,9 @@ int16_t Si443x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { clearIRQFlags(); // set packet length - /// \todo variable packet length - _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_TRANSMIT_PACKET_LENGTH, len); + if (_packetLengthConfig == RADIOLIB_SI443X_FIXED_PACKET_LENGTH_OFF) { + _mod->SPIwriteRegister(RADIOLIB_SI443X_REG_TRANSMIT_PACKET_LENGTH, len); + } /// \todo use header as address field? (void)addr; @@ -591,6 +594,14 @@ void Si443x::readBit(RADIOLIB_PIN_TYPE pin) { updateDirectBuffer((uint8_t)digitalRead(pin)); } +int16_t Si443x::fixedPacketLengthMode(uint8_t len) { + return(Si443x::setPacketMode(RADIOLIB_SI443X_FIXED_PACKET_LENGTH_ON, len)); +} + +int16_t Si443x::variablePacketLengthMode(uint8_t maxLen) { + return(Si443x::setPacketMode(RADIOLIB_SI443X_FIXED_PACKET_LENGTH_OFF, maxLen)); +} + int16_t Si443x::setFrequencyRaw(float newFreq) { // set mode to standby int16_t state = standby(); @@ -619,6 +630,25 @@ int16_t Si443x::setFrequencyRaw(float newFreq) { return(state); } +int16_t Si443x::setPacketMode(uint8_t mode, uint8_t len) { + // check packet length + if (len > RADIOLIB_SI443X_MAX_PACKET_LENGTH) { + return(RADIOLIB_ERR_PACKET_TOO_LONG); + } + + // set to fixed packet length + int16_t state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_HEADER_CONTROL_2, mode, 3, 3); + RADIOLIB_ASSERT(state); + + // set length to register + state = _mod->SPIsetRegValue(RADIOLIB_SI443X_REG_TRANSMIT_PACKET_LENGTH, len); + RADIOLIB_ASSERT(state); + + // update cached value + _packetLengthConfig = mode; + return(state); +} + bool Si443x::findChip() { uint8_t i = 0; bool flagFound = false; diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h index 9a5c0df1..40feceef 100644 --- a/src/modules/Si443x/Si443x.h +++ b/src/modules/Si443x/Si443x.h @@ -816,6 +816,24 @@ class Si443x: public PhysicalLayer { */ void readBit(RADIOLIB_PIN_TYPE pin); + /*! + \brief Set modem in fixed packet length mode. + + \param len Packet length. + + \returns \ref status_codes + */ + int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_SI443X_MAX_PACKET_LENGTH); + + /*! + \brief Set modem in variable packet length mode. + + \param len Maximum packet length. + + \returns \ref status_codes + */ + int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_SI443X_MAX_PACKET_LENGTH); + #if !defined(RADIOLIB_GODMODE) && !defined(RADIOLIB_LOW_LEVEL) protected: #endif @@ -831,8 +849,10 @@ class Si443x: public PhysicalLayer { size_t _packetLength = 0; bool _packetLengthQueried = false; + uint8_t _packetLengthConfig = RADIOLIB_SI443X_FIXED_PACKET_LENGTH_ON; int16_t setFrequencyRaw(float newFreq); + int16_t setPacketMode(uint8_t mode, uint8_t len); #if !defined(RADIOLIB_GODMODE) private: