From b75904cce1abb48bf91ab2d27445c42cb28f474c Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sat, 1 Jun 2019 20:46:34 +0200
Subject: [PATCH 001/106] Removed old comment

---
 src/Module.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/Module.cpp b/src/Module.cpp
index 9dd22fea..5c238519 100644
--- a/src/Module.cpp
+++ b/src/Module.cpp
@@ -200,7 +200,6 @@ void Module::SPIwriteRegister(uint8_t reg, uint8_t data) {
 
 void Module::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes) {
   // start SPI transaction
-  //_spi->beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
   _spi->beginTransaction(_spiSettings);
 
   // pull CS low

From fe54a308198e646c3c1781659fe88944f39126e6 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sat, 1 Jun 2019 20:46:55 +0200
Subject: [PATCH 002/106] [SX126x] Added missing length check

---
 src/modules/SX126x.cpp | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/modules/SX126x.cpp b/src/modules/SX126x.cpp
index f3d1e744..2118f00d 100644
--- a/src/modules/SX126x.cpp
+++ b/src/modules/SX126x.cpp
@@ -343,6 +343,11 @@ int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
   // suppress unused variable warning
   (void)addr;
 
+  // check packet length
+  if(len >= 256) {
+    return(ERR_PACKET_TOO_LONG);
+  }
+
   // set packet Length
   int16_t state = ERR_NONE;
   uint8_t modem = getPacketType();

From 140de0dd57d562fcb5560911d0e743f2aa1b4063 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sat, 1 Jun 2019 20:47:28 +0200
Subject: [PATCH 003/106] [RTTY] Changed parameter types

---
 src/protocols/RTTY.cpp | 4 ++--
 src/protocols/RTTY.h   | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/protocols/RTTY.cpp b/src/protocols/RTTY.cpp
index 7409e4ae..9427c87a 100644
--- a/src/protocols/RTTY.cpp
+++ b/src/protocols/RTTY.cpp
@@ -102,7 +102,7 @@ RTTYClient::RTTYClient(PhysicalLayer* phy) {
   _phy = phy;
 }
 
-int16_t RTTYClient::begin(float base, uint16_t shift, uint16_t rate, uint8_t encoding, uint8_t stopBits) {
+int16_t RTTYClient::begin(float base, uint32_t shift, uint16_t rate, uint8_t encoding, uint8_t stopBits) {
   // save configuration
   _encoding = encoding;
   _stopBits = stopBits;
@@ -125,7 +125,7 @@ int16_t RTTYClient::begin(float base, uint16_t shift, uint16_t rate, uint8_t enc
   _bitDuration = (uint32_t)1000000/rate;
 
   // calculate module carrier frequency resolution
-  uint16_t step = round((_phy->getCrystalFreq() * 1000000) / (uint32_t(1) << _phy->getDivExponent()));
+  uint32_t step = round((_phy->getCrystalFreq() * 1000000) / (uint32_t(1) << _phy->getDivExponent()));
 
   // check minimum shift value
   if(shift < step / 2) {
diff --git a/src/protocols/RTTY.h b/src/protocols/RTTY.h
index fd3f16e9..6a62cfb0 100644
--- a/src/protocols/RTTY.h
+++ b/src/protocols/RTTY.h
@@ -101,7 +101,7 @@ class RTTYClient {
 
       \returns \ref status_codes
     */
-    int16_t begin(float base, uint16_t shift, uint16_t rate, uint8_t encoding = ASCII, uint8_t stopBits = 1);
+    int16_t begin(float base, uint32_t shift, uint16_t rate, uint8_t encoding = ASCII, uint8_t stopBits = 1);
 
     /*!
       \brief Send out idle condition (RF tone at mark frequency).
@@ -142,7 +142,7 @@ class RTTYClient {
 
     uint8_t _encoding;
     uint32_t _base;
-    uint16_t _shift;
+    uint32_t _shift;
     uint16_t _bitDuration;
     uint8_t _dataBits;
     uint8_t _stopBits;

From 98259c0e3fd3c74504d364665d3a1647ec21cebe Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sat, 1 Jun 2019 20:47:45 +0200
Subject: [PATCH 004/106] [PHY] Fixed incorrect parameter name

---
 src/protocols/PhysicalLayer.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/protocols/PhysicalLayer.h b/src/protocols/PhysicalLayer.h
index 162c4d33..6aa8a0fa 100644
--- a/src/protocols/PhysicalLayer.h
+++ b/src/protocols/PhysicalLayer.h
@@ -168,7 +168,7 @@ class PhysicalLayer {
 
       \returns \ref status_codes
     */
-    virtual int16_t transmitDirect(uint32_t FRF = 0) = 0;
+    virtual int16_t transmitDirect(uint32_t frf = 0) = 0;
 
     /*!
       \brief Enables direct reception mode on pins DIO1 (clock) and DIO2 (data). Must be implemented in module class.

From 6ea5c623168930a5299db99efa2d15b0135e46ce Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sat, 1 Jun 2019 20:48:12 +0200
Subject: [PATCH 005/106] [Morse] Removed unnecessary Serial output

---
 src/protocols/Morse.cpp | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/src/protocols/Morse.cpp b/src/protocols/Morse.cpp
index d7587bdb..9738ff37 100644
--- a/src/protocols/Morse.cpp
+++ b/src/protocols/Morse.cpp
@@ -115,13 +115,10 @@ size_t MorseClient::write(uint8_t b) {
       break;
     }
   }
-  Serial.print((char)b);
-  Serial.print('\t');
   // check if the requested code was found in the array
   if(found) {
     // iterate over Morse code representation and output appropriate tones
     for(uint8_t i = 0; i < strlen(MorseTable[pos].m); i++) {
-      Serial.print(MorseTable[pos].m[i]);
       switch(MorseTable[pos].m[i]) {
         case '.':
           _phy->transmitDirect(_base);
@@ -140,7 +137,6 @@ size_t MorseClient::write(uint8_t b) {
       _phy->standby();
       delay(_dotLength);
     }
-    Serial.println();
 
     // letter space
     delay(_dotLength * 3);

From 1ebf818d88c79c67581d80b32feeef02eedaf220 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sat, 1 Jun 2019 20:50:43 +0200
Subject: [PATCH 006/106] [nRF24] Implemented basic functions

---
 .../nRF24/nRF24_Receive/nRF24_Receive.ino     |  82 +++
 .../nRF24/nRF24_Transmit/nRF24_Transmit.ino   |  81 +++
 keywords.txt                                  |   9 +-
 src/RadioLib.h                                |   1 +
 src/TypeDef.h                                 |   7 +-
 src/modules/nRF24.cpp                         | 566 ++++++++++++++++++
 src/modules/nRF24.h                           | 414 +++++++++++++
 7 files changed, 1157 insertions(+), 3 deletions(-)
 create mode 100644 examples/nRF24/nRF24_Receive/nRF24_Receive.ino
 create mode 100644 examples/nRF24/nRF24_Transmit/nRF24_Transmit.ino
 create mode 100644 src/modules/nRF24.cpp
 create mode 100644 src/modules/nRF24.h

diff --git a/examples/nRF24/nRF24_Receive/nRF24_Receive.ino b/examples/nRF24/nRF24_Receive/nRF24_Receive.ino
new file mode 100644
index 00000000..1ea09fb9
--- /dev/null
+++ b/examples/nRF24/nRF24_Receive/nRF24_Receive.ino
@@ -0,0 +1,82 @@
+/*
+   RadioLib nRF24 Receive Example
+
+   This example listens for FSK transmissions using nRF24 2.4 GHz radio module.
+   To successfully receive data, the following settings have to be the same
+   on both transmitter and receiver:
+    - carrier frequency
+    - data rate
+    - transmit pipe on transmitter must match receive pipe
+      on receiver
+*/
+
+// include the library
+#include <RadioLib.h>
+
+// nRF24 is in slot A on the shield
+nRF24 nrf = RadioShield.ModuleA;
+
+void setup() {
+  Serial.begin(9600);
+
+  // initialize nRF24
+  Serial.print(F("[nRF24] Initializing ... "));
+  // carrier frequency:           2400 MHz
+  // data rate:                   1000 kbps
+  // output power:                -12 dBm
+  // address width:               5 bytes
+  int state = nrf.begin();
+  if(state == ERR_NONE) {
+    Serial.println(F("success!"));
+  } else {
+    Serial.print(F("failed, code "));
+    Serial.println(state);
+    while(true);
+  }
+
+  // set receive pipe 0 address
+  // NOTE: address width in bytes MUST be equal to the 
+  //       width set in begin() or setAddressWidth()
+  //       methods (5 by default)
+  Serial.print(F("[nRF24] Setting address for receive pipe 0 ... "));
+  byte addr[] = {0x01, 0x23, 0x45, 0x67, 0x89};
+  state = nrf.setReceivePipe(0, addr);
+  if(state == ERR_NONE) {
+    Serial.println(F("success!"));
+  } else {
+    Serial.print(F("failed, code "));
+    Serial.println(state);
+    while(true);
+  }
+}
+
+void loop() {
+  Serial.print(F("[nRF24] Waiting for incoming transmission ... "));
+
+  // you can receive data as an Arduino String
+  // NOTE: receive() is a blocking method!
+  //       See example ReceiveInterrupt for details
+  //       on non-blocking reception method.
+  String str;
+  int state = nrf.receive(str);
+
+  // you can also receive data as byte array
+  /*
+    byte byteArr[8];
+    int state = nrf.receive(byteArr, 8);
+  */
+
+  if (state == ERR_NONE) {
+    // packet was successfully received
+    Serial.println(F("success!"));
+
+    // print the data of the packet
+    Serial.print(F("[nRF24] Data:\t\t"));
+    Serial.println(str);
+
+  } else if (state == ERR_RX_TIMEOUT) {
+    // timeout occurred while waiting for a packet
+    Serial.println(F("timeout!"));
+
+  }
+}
diff --git a/examples/nRF24/nRF24_Transmit/nRF24_Transmit.ino b/examples/nRF24/nRF24_Transmit/nRF24_Transmit.ino
new file mode 100644
index 00000000..304ab6b1
--- /dev/null
+++ b/examples/nRF24/nRF24_Transmit/nRF24_Transmit.ino
@@ -0,0 +1,81 @@
+/*
+   RadioLib nRF24 Transmit Example
+
+   This example transmits packets using nRF24 2.4 GHz radio module.
+   Each packet contains up to 32 bytes of data, in the form of:
+    - Arduino String
+    - null-terminated char array (C-string)
+    - arbitrary binary data (byte array)
+
+   Packet delivery is automatically acknowledged by the receiver.
+*/
+
+// include the library
+#include <RadioLib.h>
+
+// nRF24 is in slot A on the shield
+nRF24 nrf = RadioShield.ModuleA;
+
+void setup() {
+  Serial.begin(9600);
+
+  // initialize nRF24
+  Serial.print(F("[nRF24] Initializing ... "));
+  // carrier frequency:           2400 MHz
+  // data rate:                   1000 kbps
+  // output power:                -12 dBm
+  // address width:               5 bytes
+  int state = nrf.begin();
+  if(state == ERR_NONE) {
+    Serial.println(F("success!"));
+  } else {
+    Serial.print(F("failed, code "));
+    Serial.println(state);
+    while(true);
+  }
+
+  // set transmit address
+  // NOTE: address width in bytes MUST be equal to the
+  //       width set in begin() or setAddressWidth()
+  //       methods (5 by default)
+  byte addr[] = {0x01, 0x23, 0x45, 0x67, 0x89};
+  Serial.print(F("[nRF24] Setting transmit pipe ... "));
+  state = nrf.setTransmitPipe(addr);
+  if(state == ERR_NONE) {
+    Serial.println(F("success!"));
+  } else {
+    Serial.print(F("failed, code "));
+    Serial.println(state);
+    while(true);
+  }
+}
+
+void loop() {
+  Serial.print(F("[nRF24] Transmitting packet ... "));
+
+  // you can transmit C-string or Arduino string up to
+  // 32 characters long
+  int state = nrf.transmit("Hello World!");
+
+  if (state == ERR_NONE) {
+    // the packet was successfully transmitted
+    Serial.println(F("success!"));
+
+  } else if (state == ERR_PACKET_TOO_LONG) {
+    // the supplied packet was longer than 32 bytes
+    Serial.println(F("too long!"));
+
+  } else if (state == ERR_ACK_NOT_RECEIVED) {
+    // acknowledge from destination module
+    // was not received within 15 retries
+    Serial.println(F("ACK not received!"));
+
+  } else if (state == ERR_TX_TIMEOUT) {
+    // timed out while transmitting
+    Serial.println(F("timeout!"));
+
+  }
+
+  // wait for a second before transmitting again
+  delay(1000);
+}
diff --git a/keywords.txt b/keywords.txt
index aa731e66..7621a797 100644
--- a/keywords.txt
+++ b/keywords.txt
@@ -38,6 +38,7 @@ MQTTClient	KEYWORD1
 HTTPClient	KEYWORD1
 RTTYClient	KEYWORD1
 MorseClient	KEYWORD1
+PagerClient	KEYWORD1
 
 #######################################
 # Methods and Functions (KEYWORD2)
@@ -98,7 +99,7 @@ setAmbientTemperature	KEYWORD2
 # CC1101-specific
 getLQI	KEYWORD2
 setGdo0Action	KEYWORD2
-setGdo1Action KEYWORD2
+setGdo1Action	KEYWORD2
 
 # SX126x-specific
 setDio2Action	KEYWORD2
@@ -115,9 +116,11 @@ getPacketSource	KEYWORD2
 getPacketData	KEYWORD2
 
 # nRF24
-setTransmitAddress	KEYWORD2
+setAddressWidth	KEYWORD2
+setTransmitPipe	KEYWORD2
 setReceivePipe	KEYWORD2
 disablePipe	KEYWORD2
+getStatus	KEYWORD2
 
 # HTTP
 get	KEYWORD2
@@ -210,12 +213,14 @@ ERR_FRAME_NO_RESPONSE	LITERAL1
 ASCII	LITERAL1
 ASCII_EXTENDED	LITERAL1
 ITA2	LITERAL1
+BCD	LITERAL1
 ERR_INVALID_RTTY_SHIFT	LITERAL1
 ERR_UNSUPPORTED_ENCODING	LITERAL1
 
 ERR_INVALID_DATA_RATE	LITERAL1
 ERR_INVALID_ADDRESS_WIDTH	LITERAL1
 ERR_INVALID_PIPE_NUMBER	LITERAL1
+ERR_ACK_NOT_RECEIVED	LITERAL1
 
 ERR_INVALID_NUM_BROAD_ADDRS	LITERAL1
 
diff --git a/src/RadioLib.h b/src/RadioLib.h
index 58b56fff..00f6f510 100644
--- a/src/RadioLib.h
+++ b/src/RadioLib.h
@@ -42,6 +42,7 @@
 #include "modules/ESP8266.h"
 #include "modules/HC05.h"
 #include "modules/JDY08.h"
+#include "modules/nRF24.h"
 #include "modules/RF69.h"
 #include "modules/RFM95.h"
 #include "modules/RFM96.h"
diff --git a/src/TypeDef.h b/src/TypeDef.h
index 4e567cfd..b007f408 100644
--- a/src/TypeDef.h
+++ b/src/TypeDef.h
@@ -395,7 +395,7 @@
 */
 #define ERR_UNSUPPORTED_ENCODING              -402
 
-// nRF24 status codes
+// nRF24-specific status codes
 
 /*!
   \brief Supplied data rate is invalid.
@@ -412,6 +412,11 @@
 */
 #define ERR_INVALID_PIPE_NUMBER               -503
 
+/*!
+  \brief ACK packet from destination module was not received within 15 retries.
+*/
+#define ERR_ACK_NOT_RECEIVED                  -504
+
 // CC1101-specific status codes
 
 /*!
diff --git a/src/modules/nRF24.cpp b/src/modules/nRF24.cpp
new file mode 100644
index 00000000..59e13a04
--- /dev/null
+++ b/src/modules/nRF24.cpp
@@ -0,0 +1,566 @@
+#include "nRF24.h"
+
+nRF24::nRF24(Module* mod) : PhysicalLayer(NRF24_CRYSTAL_FREQ, NRF24_DIV_EXPONENT) {
+  _mod = mod;
+}
+
+int16_t nRF24::begin(int16_t freq, int16_t dataRate, int8_t power, uint8_t addrWidth) {
+  // set module properties
+  _mod->SPIreadCommand = NRF24_CMD_READ;
+  _mod->SPIwriteCommand = NRF24_CMD_WRITE;
+  _mod->init(USE_SPI, INT_BOTH);
+
+  // override pin mode on INT0 (connected to nRF24 CE pin)
+  pinMode(_mod->getInt0(), OUTPUT);
+  digitalWrite(_mod->getInt0(), LOW);
+
+  // wait for minimum power-on reset duration
+  delay(100);
+
+  // check SPI connection
+  int16_t val = _mod->SPIgetRegValue(NRF24_REG_SETUP_AW);
+  if(!((val >= 1) && (val <= 3))) {
+    DEBUG_PRINTLN(F("No nRF24 found!"));
+    _mod->term();
+    return(ERR_CHIP_NOT_FOUND);
+  }
+
+  // configure settings inaccessible by public API
+  int16_t state = config();
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
+  // set mode to standby
+  state = standby();
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
+  // set frequency
+  state = setFrequency(freq);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
+  // set data rate
+  state = setDataRate(dataRate);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
+  // set output power
+  state = setOutputPower(power);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
+  // set address width
+  state = setAddressWidth(addrWidth);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
+  return(state);
+}
+
+int16_t nRF24::sleep() {
+  return(_mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_POWER_DOWN, 1, 1));
+}
+
+int16_t nRF24::standby() {
+  // make sure carrier output is disabled
+  _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_CONT_WAVE_OFF, 7, 7);
+  _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_PLL_LOCK_OFF, 4, 4);
+  digitalWrite(_mod->getInt0(), LOW);
+
+  // use standby-1 mode
+  return(_mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_POWER_UP, 1, 1));
+}
+
+int16_t nRF24::transmit(uint8_t* data, size_t len, uint8_t addr) {
+  // start transmission
+  int16_t state = startTransmit(data, len, addr);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
+  // wait until transmission is finished
+  uint32_t start = micros();
+  while(digitalRead(_mod->getInt1())) {
+    // check maximum number of retransmits
+    if(getStatus(NRF24_MAX_RT)) {
+      standby();
+      clearIRQ();
+      return(ERR_ACK_NOT_RECEIVED);
+    }
+
+    // check timeout: 15 retries * 4ms (max Tx time as per datasheet)
+    if(micros() - start >= 60000) {
+      standby();
+      clearIRQ();
+      return(ERR_TX_TIMEOUT);
+    }
+  }
+
+  // clear interrupts
+  clearIRQ();
+
+  return(state);
+}
+
+int16_t nRF24::receive(uint8_t* data, size_t len) {
+  // start reception
+  int16_t state = startReceive();
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
+  // wait for Rx_DataReady or timeout
+  uint32_t start = micros();
+  while(digitalRead(_mod->getInt1())) {
+    // check timeout: 15 retries * 4ms (max Tx time as per datasheet)
+    if(micros() - start >= 60000) {
+      standby();
+      clearIRQ();
+      return(ERR_RX_TIMEOUT);
+    }
+  }
+
+  // read the received data
+  return(readData(data, len));
+}
+
+int16_t nRF24::transmitDirect(uint32_t frf) {
+  // set raw frequency value
+  if(frf != 0) {
+    uint8_t freqRaw = frf - 2400;
+    _mod->SPIwriteRegister(NRF24_REG_RF_CH, freqRaw & 0b01111111);
+  }
+
+  // output carrier
+  int16_t state = _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_PTX, 0, 0);
+  state |= _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_CONT_WAVE_ON, 7, 7);
+  state |= _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_PLL_LOCK_ON, 4, 4);
+  digitalWrite(_mod->getInt0(), HIGH);
+  return(state);
+}
+
+int16_t nRF24::receiveDirect() {
+  // nRF24 is unable to directly output demodulated data
+  // this method is implemented only for PhysicalLayer compatibility
+  return(ERR_NONE);
+}
+
+void nRF24::setIrqAction(void (*func)(void)) {
+  attachInterrupt(digitalPinToInterrupt(_mod->getInt1()), func, FALLING);
+}
+
+int16_t nRF24::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
+  // suppress unused variable warning
+  (void)addr;
+
+  // check packet length
+  if(len > 32) {
+    return(ERR_PACKET_TOO_LONG);
+  }
+
+  // set mode to standby
+  int16_t state = standby();
+  if(state != ERR_NONE) {
+     return(state);
+  }
+
+  // enable primary Tx mode
+  state = _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_PTX, 0, 0);
+
+  // clear interrupts
+  clearIRQ();
+
+  // enable Tx_DataSent interrupt
+  state |= _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_MASK_TX_DS_IRQ_ON, 5, 5);
+  if(state != ERR_NONE) {
+     return(state);
+  }
+
+  // flush Tx FIFO
+  SPItransfer(NRF24_CMD_FLUSH_TX);
+
+  // fill Tx FIFO
+  uint8_t buff[32];
+  memset(buff, 0x00, 32);
+  memcpy(buff, data, len);
+  SPIwriteTxPayload(data, len);
+
+  // CE high to start transmitting
+  digitalWrite(_mod->getInt0(), HIGH);
+  delayMicroseconds(10);
+  digitalWrite(_mod->getInt0(), LOW);
+
+  return(state);
+}
+
+int16_t nRF24::startReceive() {
+  // set mode to standby
+  int16_t state = standby();
+  if(state != ERR_NONE) {
+     return(state);
+  }
+
+  // enable primary Rx mode
+  state = _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_PRX, 0, 0);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
+  // enable Rx_DataReady interrupt
+  clearIRQ();
+  state |= _mod->SPIsetRegValue(NRF24_REG_CONFIG,  NRF24_MASK_RX_DR_IRQ_ON, 6, 6);
+  if(state != ERR_NONE) {
+     return(state);
+  }
+
+  // flush Rx FIFO
+  SPItransfer(NRF24_CMD_FLUSH_RX);
+
+  // CE high to start receiving
+  digitalWrite(_mod->getInt0(), HIGH);
+
+  // wait to enter Rx state
+  delayMicroseconds(130);
+
+  return(state);
+}
+
+int16_t nRF24::readData(uint8_t* data, size_t len) {
+  // set mode to standby
+  int16_t state = standby();
+  if(state != ERR_NONE) {
+     return(state);
+  }
+
+  // read payload length
+  uint8_t buff[1];
+  SPItransfer(NRF24_CMD_READ_RX_PAYLOAD_WIDTH, false, NULL, buff, 1);
+
+  size_t length = buff[0];
+
+  // read packet data
+  if(len == 0) {
+    // argument 'len' equal to zero indicates String call, which means dynamically allocated data array
+    // dispose of the original and create a new one
+    delete[] data;
+    data = new uint8_t[length + 1];
+  }
+  SPIreadRxPayload(data, length);
+
+  // add terminating null
+  data[length] = 0;
+
+  // clear interrupt
+  clearIRQ();
+
+  return(ERR_NONE);
+}
+
+int16_t nRF24::setFrequency(int16_t freq) {
+  // check allowed range
+  if(!((freq >= 2400) && (freq <= 2525))) {
+    return(ERR_INVALID_FREQUENCY);
+  }
+
+  // set mode to standby
+  int16_t state = standby();
+  if(state != ERR_NONE) {
+     return(state);
+  }
+
+  // set frequency
+  uint8_t freqRaw = freq - 2400;
+  state = _mod->SPIsetRegValue(NRF24_REG_RF_CH, freqRaw, 6, 0);
+  return(state);
+}
+
+int16_t nRF24::setDataRate(int16_t dataRate) {
+  // set mode to standby
+  int16_t state = standby();
+  if(state != ERR_NONE) {
+     return(state);
+  }
+
+  // set data rate
+  if(dataRate == 250) {
+    state = _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_DR_250_KBPS, 5, 5);
+    state |= _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_DR_250_KBPS, 3, 3);
+  } else if(dataRate == 1000) {
+    state = _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_DR_1_MBPS, 5, 5);
+    state |= _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_DR_1_MBPS, 3, 3);
+  } else if(dataRate == 2000) {
+    state = _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_DR_2_MBPS, 5, 5);
+    state |= _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, NRF24_DR_2_MBPS, 3, 3);
+  } else {
+    return(ERR_INVALID_DATA_RATE);
+  }
+
+  return(state);
+}
+
+int16_t nRF24::setOutputPower(int8_t power) {
+  // set mode to standby
+  int16_t state = standby();
+  if(state != ERR_NONE) {
+     return(state);
+  }
+
+  // check allowed values
+  uint8_t powerRaw = 0;
+  switch(power) {
+    case -18:
+      powerRaw = NRF24_RF_PWR_18_DBM;
+      break;
+    case -12:
+      powerRaw = NRF24_RF_PWR_12_DBM;
+      break;
+    case -6:
+      powerRaw = NRF24_RF_PWR_6_DBM;
+      break;
+    case 0:
+      powerRaw = NRF24_RF_PWR_0_DBM;
+      break;
+    default:
+      return(ERR_INVALID_OUTPUT_POWER);
+  }
+
+  // write new register value
+  state = _mod->SPIsetRegValue(NRF24_REG_RF_SETUP, powerRaw, 2, 1);
+  return(state);
+}
+
+int16_t nRF24::setAddressWidth(uint8_t addrWidth) {
+  // set mode to standby
+  int16_t state = standby();
+  if(state != ERR_NONE) {
+     return(state);
+  }
+
+  // set address width
+  switch(addrWidth) {
+    case 3:
+      state = _mod->SPIsetRegValue(NRF24_REG_SETUP_AW, NRF24_ADDRESS_3_BYTES, 1, 0);
+      break;
+    case 4:
+      state = _mod->SPIsetRegValue(NRF24_REG_SETUP_AW, NRF24_ADDRESS_4_BYTES, 1, 0);
+      break;
+    case 5:
+      state = _mod->SPIsetRegValue(NRF24_REG_SETUP_AW, NRF24_ADDRESS_5_BYTES, 1, 0);
+      break;
+    default:
+      return(ERR_INVALID_ADDRESS_WIDTH);
+  }
+
+  // save address width
+  _addrWidth = addrWidth;
+
+  return(state);
+}
+
+int16_t nRF24::setTransmitPipe(uint8_t* addr) {
+  // set mode to standby
+  int16_t state = standby();
+  if(state != ERR_NONE) {
+     return(state);
+  }
+
+  // set transmit address
+  _mod->SPIwriteRegisterBurst(NRF24_REG_TX_ADDR, addr, _addrWidth);
+
+  // set Rx pipe 0 address (for ACK)
+  _mod->SPIwriteRegisterBurst(NRF24_REG_RX_ADDR_P0, addr, _addrWidth);
+
+  return(state);
+}
+
+int16_t nRF24::setReceivePipe(uint8_t pipeNum, uint8_t* addr) {
+  // set mode to standby
+  int16_t state = standby();
+  if(state != ERR_NONE) {
+     return(state);
+  }
+
+  // write full pipe 0 - 1 address and enable the pipe
+  switch(pipeNum) {
+    case 0:
+      _mod->SPIwriteRegisterBurst(NRF24_REG_RX_ADDR_P0, addr, _addrWidth);
+      state |= _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P0_ON, 0, 0);
+    case 1:
+      _mod->SPIwriteRegisterBurst(NRF24_REG_RX_ADDR_P1, addr, _addrWidth);
+      state |= _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P1_ON, 1, 1);
+      break;
+    default:
+      return(ERR_INVALID_PIPE_NUMBER);
+  }
+
+  return(state);
+}
+
+int16_t nRF24::setReceivePipe(uint8_t pipeNum, uint8_t addrByte) {
+  // set mode to standby
+  int16_t state = standby();
+  if(state != ERR_NONE) {
+     return(state);
+  }
+
+  // write unique pipe 2 - 5 address and enable the pipe
+  switch(pipeNum) {
+    case 2:
+      state = _mod->SPIsetRegValue(NRF24_REG_RX_ADDR_P2, addrByte);
+      state |= _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P2_ON, 2, 2);
+      break;
+    case 3:
+      state = _mod->SPIsetRegValue(NRF24_REG_RX_ADDR_P3, addrByte);
+      state |= _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P3_ON, 3, 3);
+      break;
+    case 4:
+      state = _mod->SPIsetRegValue(NRF24_REG_RX_ADDR_P4, addrByte);
+      state |= _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P4_ON, 4, 4);
+      break;
+    case 5:
+      state = _mod->SPIsetRegValue(NRF24_REG_RX_ADDR_P5, addrByte);
+      state |= _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P5_ON, 5, 5);
+      break;
+    default:
+      return(ERR_INVALID_PIPE_NUMBER);
+  }
+
+  return(state);
+}
+
+int16_t nRF24::disablePipe(uint8_t pipeNum) {
+  // set mode to standby
+  int16_t state = standby();
+  if(state != ERR_NONE) {
+     return(state);
+  }
+
+  switch(pipeNum) {
+    case 0:
+      state = _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P0_OFF, 0, 0);
+      break;
+    case 1:
+      state = _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P1_OFF, 1, 1);
+      break;
+    case 2:
+      state = _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P2_OFF, 2, 2);
+      break;
+    case 3:
+      state = _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P3_OFF, 3, 3);
+      break;
+    case 4:
+      state = _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P4_OFF, 4, 4);
+      break;
+    case 5:
+      state = _mod->SPIsetRegValue(NRF24_REG_EN_RXADDR, NRF24_P5_OFF, 5, 5);
+      break;
+    default:
+      return(ERR_INVALID_PIPE_NUMBER);
+  }
+
+  return(state);
+}
+
+int16_t nRF24::getStatus(uint8_t mask) {
+  return(_mod->SPIgetRegValue(NRF24_REG_STATUS) & mask);
+}
+
+int16_t nRF24::setFrequencyDeviation(float freqDev) {
+  // nRF24 is unable to set frequency deviation
+  // this method is implemented only for PhysicalLayer compatibility
+  (void)freqDev;
+  return(ERR_NONE);
+}
+
+void nRF24::clearIRQ() {
+  // clear status bits
+  _mod->SPIsetRegValue(NRF24_REG_STATUS, NRF24_RX_DR | NRF24_TX_DS | NRF24_MAX_RT, 6, 4);
+
+  // disable interrupts
+  _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_MASK_RX_DR_IRQ_OFF | NRF24_MASK_TX_DS_IRQ_OFF | NRF24_MASK_MAX_RT_IRQ_OFF, 6, 4);
+}
+
+int16_t nRF24::config() {
+  // enable 16-bit CRC
+  int16_t state = _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_CRC_ON | NRF24_CRC_16, 3, 2);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
+  // set 15 retries and delay 1500 (5*250) us
+  _mod->SPIsetRegValue(NRF24_REG_SETUP_RETR, (5 << 4) | 5);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
+  // set features: dynamic payload on, payload with ACK packets off, dynamic ACK off
+  state = _mod->SPIsetRegValue(NRF24_REG_FEATURE, NRF24_DPL_ON | NRF24_ACK_PAY_OFF | NRF24_DYN_ACK_OFF, 2, 0);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
+  // enable dynamic payloads
+  state = _mod->SPIsetRegValue(NRF24_REG_DYNPD, NRF24_DPL_ALL_ON, 5, 0);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
+  // reset IRQ
+  clearIRQ();
+
+  // clear status
+  _mod->SPIsetRegValue(NRF24_REG_STATUS, NRF24_RX_DR | NRF24_TX_DS | NRF24_MAX_RT, 6, 4);
+
+  // flush FIFOs
+  SPItransfer(NRF24_CMD_FLUSH_TX);
+  SPItransfer(NRF24_CMD_FLUSH_RX);
+
+  // power up
+  _mod->SPIsetRegValue(NRF24_REG_CONFIG, NRF24_POWER_UP, 1, 1);
+  delay(5);
+
+  return(state);
+}
+
+void nRF24::SPIreadRxPayload(uint8_t* data, uint8_t numBytes) {
+  SPItransfer(NRF24_CMD_READ_RX_PAYLOAD, false, NULL, data, numBytes);
+}
+
+void nRF24::SPIwriteTxPayload(uint8_t* data, uint8_t numBytes) {
+  SPItransfer(NRF24_CMD_WRITE_TX_PAYLOAD, true, data, NULL, numBytes);
+}
+
+void nRF24::SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes) {
+  // get pointer to used SPI interface and the settings
+  SPIClass* spi = _mod->getSpi();
+  SPISettings spiSettings = _mod->getSpiSettings();
+
+  // start transfer
+  digitalWrite(_mod->getCs(), LOW);
+  spi->beginTransaction(spiSettings);
+
+  // send command
+  spi->transfer(cmd);
+
+  // send data
+  if(write) {
+    for(uint8_t i = 0; i < numBytes; i++) {
+      spi->transfer(dataOut[i]);
+    }
+  } else {
+    for(uint8_t i = 0; i < numBytes; i++) {
+      dataIn[i] = spi->transfer(0x00);
+    }
+  }
+
+  // stop transfer
+  spi->endTransaction();
+  digitalWrite(_mod->getCs(), HIGH);
+}
diff --git a/src/modules/nRF24.h b/src/modules/nRF24.h
new file mode 100644
index 00000000..dfbded20
--- /dev/null
+++ b/src/modules/nRF24.h
@@ -0,0 +1,414 @@
+#ifndef _RADIOLIB_NRF24_H
+#define _RADIOLIB_NRF24_H
+
+#include "Module.h"
+#include "TypeDef.h"
+
+#include "../protocols/PhysicalLayer.h"
+
+// nRF24 physical layer properties (dummy only)
+#define NRF24_CRYSTAL_FREQ                            1.0
+#define NRF24_DIV_EXPONENT                            0
+
+// nRF24 SPI commands
+#define NRF24_CMD_READ                                0b00000000
+#define NRF24_CMD_WRITE                               0b00100000
+#define NRF24_CMD_READ_RX_PAYLOAD                     0b01100001
+#define NRF24_CMD_WRITE_TX_PAYLOAD                    0b10100000
+#define NRF24_CMD_FLUSH_TX                            0b11100001
+#define NRF24_CMD_FLUSH_RX                            0b11100010
+#define NRF24_CMD_REUSE_TX_PAXLOAD                    0b11100011
+#define NRF24_CMD_READ_RX_PAYLOAD_WIDTH               0b01100000
+#define NRF24_CMD_WRITE_ACK_PAYLOAD                   0b10101000
+#define NRF24_CMD_WRITE_TX_PAYLOAD_NOACK              0b10110000
+#define NRF24_CMD_NOP                                 0b11111111
+
+// nRF24 register map
+#define NRF24_REG_CONFIG                              0x00
+#define NRF24_REG_EN_AA                               0x01
+#define NRF24_REG_EN_RXADDR                           0x02
+#define NRF24_REG_SETUP_AW                            0x03
+#define NRF24_REG_SETUP_RETR                          0x04
+#define NRF24_REG_RF_CH                               0x05
+#define NRF24_REG_RF_SETUP                            0x06
+#define NRF24_REG_STATUS                              0x07
+#define NRF24_REG_OBSERVE_TX                          0x08
+#define NRF24_REG_RPD                                 0x09
+#define NRF24_REG_RX_ADDR_P0                          0x0A
+#define NRF24_REG_RX_ADDR_P1                          0x0B
+#define NRF24_REG_RX_ADDR_P2                          0x0C
+#define NRF24_REG_RX_ADDR_P3                          0x0D
+#define NRF24_REG_RX_ADDR_P4                          0x0E
+#define NRF24_REG_RX_ADDR_P5                          0x0F
+#define NRF24_REG_TX_ADDR                             0x10
+#define NRF24_REG_RX_PW_P0                            0x11
+#define NRF24_REG_RX_PW_P1                            0x12
+#define NRF24_REG_RX_PW_P2                            0x13
+#define NRF24_REG_RX_PW_P3                            0x14
+#define NRF24_REG_RX_PW_P4                            0x15
+#define NRF24_REG_RX_PW_P5                            0x16
+#define NRF24_REG_FIFO_STATUS                         0x17
+#define NRF24_REG_DYNPD                               0x1C
+#define NRF24_REG_FEATURE                             0x1D
+
+// NRF24_REG_CONFIG                                                   MSB   LSB   DESCRIPTION
+#define NRF24_MASK_RX_DR_IRQ_OFF                      0b01000000  //  6     6     RX_DR will not be reflected on IRQ pin
+#define NRF24_MASK_RX_DR_IRQ_ON                       0b00000000  //  6     6     RX_DR will be reflected on IRQ pin as active low (default)
+#define NRF24_MASK_TX_DS_IRQ_OFF                      0b00100000  //  5     5     TX_DS will not be reflected on IRQ pin
+#define NRF24_MASK_TX_DS_IRQ_ON                       0b00000000  //  5     5     TX_DS will be reflected on IRQ pin as active low (default)
+#define NRF24_MASK_MAX_RT_IRQ_OFF                     0b00010000  //  4     4     MAX_RT will not be reflected on IRQ pin
+#define NRF24_MASK_MAX_RT_IRQ_ON                      0b00000000  //  4     4     MAX_RT will be reflected on IRQ pin as active low (default)
+#define NRF24_CRC_OFF                                 0b00000000  //  3     3     CRC calculation: disabled
+#define NRF24_CRC_ON                                  0b00001000  //  3     3                      enabled (default)
+#define NRF24_CRC_8                                   0b00000000  //  2     2     CRC scheme: CRC8 (default)
+#define NRF24_CRC_16                                  0b00000100  //  2     2                 CRC16
+#define NRF24_POWER_UP                                0b00000010  //  1     1     power up
+#define NRF24_POWER_DOWN                              0b00000000  //  1     1     power down
+#define NRF24_PTX                                     0b00000000  //  0     0     enable primary Tx
+#define NRF24_PRX                                     0b00000001  //  0     0     enable primary Rx
+
+// NRF24_REG_EN_AA
+#define NRF24_AA_P5_OFF                               0b00000000  //  5     5     auto-ACK on pipe 5: disabled
+#define NRF24_AA_P5_ON                                0b00100000  //  5     5                         enabled (default)
+#define NRF24_AA_P4_OFF                               0b00000000  //  4     4     auto-ACK on pipe 4: disabled
+#define NRF24_AA_P4_ON                                0b00010000  //  4     4                         enabled (default)
+#define NRF24_AA_P3_OFF                               0b00000000  //  3     3     auto-ACK on pipe 3: disabled
+#define NRF24_AA_P3_ON                                0b00001000  //  3     3                         enabled (default)
+#define NRF24_AA_P2_OFF                               0b00000000  //  2     2     auto-ACK on pipe 2: disabled
+#define NRF24_AA_P2_ON                                0b00000100  //  2     2                         enabled (default)
+#define NRF24_AA_P1_OFF                               0b00000000  //  1     1     auto-ACK on pipe 1: disabled
+#define NRF24_AA_P1_ON                                0b00000010  //  1     1                         enabled (default)
+#define NRF24_AA_P0_OFF                               0b00000000  //  0     0     auto-ACK on pipe 0: disabled
+#define NRF24_AA_P0_ON                                0b00000001  //  0     0                         enabled (default)
+
+// NRF24_REG_EN_RXADDR
+#define NRF24_P5_OFF                                  0b00000000  //  5     5     receive pipe 5: disabled (default)
+#define NRF24_P5_ON                                   0b00100000  //  5     5                     enabled
+#define NRF24_P4_OFF                                  0b00000000  //  4     4     receive pipe 4: disabled (default)
+#define NRF24_P4_ON                                   0b00010000  //  4     4                     enabled
+#define NRF24_P3_OFF                                  0b00000000  //  3     3     receive pipe 3: disabled (default)
+#define NRF24_P3_ON                                   0b00001000  //  3     3                     enabled
+#define NRF24_P2_OFF                                  0b00000000  //  2     2     receive pipe 2: disabled (default)
+#define NRF24_P2_ON                                   0b00000100  //  2     2                     enabled
+#define NRF24_P1_OFF                                  0b00000000  //  1     1     receive pipe 1: disabled
+#define NRF24_P1_ON                                   0b00000010  //  1     1                     enabled (default)
+#define NRF24_P0_OFF                                  0b00000000  //  0     0     receive pipe 0: disabled
+#define NRF24_P0_ON                                   0b00000001  //  0     0                     enabled (default)
+
+// NRF24_REG_SETUP_AW
+#define NRF24_ADDRESS_3_BYTES                         0b00000001  //  1     0     address width: 3 bytes
+#define NRF24_ADDRESS_4_BYTES                         0b00000010  //  1     0                    4 bytes
+#define NRF24_ADDRESS_5_BYTES                         0b00000011  //  1     0                    5 bytes (default)
+
+// NRF24_REG_SETUP_RETR
+#define NRF24_ARD                                     0b00000000  //  7     4     auto retransmit delay: t[us] = (NRF24_ARD + 1) * 250 us
+#define NRF24_ARC_OFF                                 0b00000000  //  3     0     auto retransmit count: auto retransmit disabled
+#define NRF24_ARC                                     0b00000011  //  3     0                            up to 3 retransmits on AA fail (default)
+
+// NRF24_REG_RF_CH
+#define NRF24_RF_CH                                   0b00000010  //  6     0     RF channel: f_CH[MHz] = 2400 MHz + NRF24_RF_CH
+
+// NRF24_REG_RF_SETUP
+#define NRF24_CONT_WAVE_OFF                           0b00000000  //  7     7     continuous carrier transmit: disabled (default)
+#define NRF24_CONT_WAVE_ON                            0b10000000  //  7     7                                  enabled
+#define NRF24_DR_250_KBPS                             0b00100000  //  5     5     data rate: 250 kbps
+#define NRF24_DR_1_MBPS                               0b00000000  //  3     3                1 Mbps (default)
+#define NRF24_DR_2_MBPS                               0b00001000  //  3     3                2 Mbps
+#define NRF24_PLL_LOCK_ON                             0b00010000  //  4     4     force PLL lock: enabled
+#define NRF24_PLL_LOCK_OFF                            0b00000000  //  4     4                     disabled (default)
+#define NRF24_RF_PWR_18_DBM                           0b00000000  //  2     1     output power: -18 dBm
+#define NRF24_RF_PWR_12_DBM                           0b00000010  //  2     1                   -12 dBm
+#define NRF24_RF_PWR_6_DBM                            0b00000100  //  2     1                   -6 dBm
+#define NRF24_RF_PWR_0_DBM                            0b00000110  //  2     1                   0 dBm (default)
+
+// NRF24_REG_STATUS
+#define NRF24_RX_DR                                   0b01000000  //  6     6     Rx data ready
+#define NRF24_TX_DS                                   0b00100000  //  5     5     Tx data sent
+#define NRF24_MAX_RT                                  0b00010000  //  4     4     maximum number of rentransmits reached (must be cleared to continue)
+#define NRF24_RX_FIFO_EMPTY                           0b00001110  //  3     1     Rx FIFO is empty
+#define NRF24_RX_P_NO                                 0b00000000  //  3     1     number of data pipe that received data
+#define NRF24_TX_FIFO_FULL                            0b00000001  //  0     0     Tx FIFO is full
+
+// NRF24_REG_OBSERVE_TX
+#define NRF24_PLOS_CNT                                0b00000000  //  7     4     number of lost packets
+#define NRF24_ARC_CNT                                 0b00000000  //  3     0     number of retransmitted packets
+
+// NRF24_REG_RPD
+#define NRF24_RP_BELOW_64_DBM                         0b00000000  //  0     0     received power in the current channel: less than -64 dBm
+#define NRF24_RP_ABOVE_64_DBM                         0b00000001  //  0     0                                            more than -64 dBm
+
+// NRF24_REG_FIFO_STATUS
+#define NRF24_TX_REUSE                                0b01000000  //  6     6     reusing last transmitted payload
+#define NRF24_TX_FIFO_FULL_FLAG                       0b00100000  //  5     5     Tx FIFO is full
+#define NRF24_TX_FIFO_EMPTY_FLAG                      0b00010000  //  4     4     Tx FIFO is empty
+#define NRF24_RX_FIFO_FULL_FLAG                       0b00000010  //  1     1     Rx FIFO is full
+#define NRF24_RX_FIFO_EMPTY_FLAG                      0b00000001  //  0     0     Rx FIFO is empty
+
+// NRF24_REG_DYNPD
+#define NRF24_DPL_P5_OFF                              0b00000000  //  5     5     dynamic payload length on pipe 5: disabled (default)
+#define NRF24_DPL_P5_ON                               0b00100000  //  5     5                                       enabled
+#define NRF24_DPL_P4_OFF                              0b00000000  //  4     4     dynamic payload length on pipe 4: disabled (default)
+#define NRF24_DPL_P4_ON                               0b00010000  //  4     4                                       enabled
+#define NRF24_DPL_P3_OFF                              0b00000000  //  3     3     dynamic payload length on pipe 3: disabled (default)
+#define NRF24_DPL_P3_ON                               0b00001000  //  3     3                                       enabled
+#define NRF24_DPL_P2_OFF                              0b00000000  //  2     2     dynamic payload length on pipe 2: disabled (default)
+#define NRF24_DPL_P2_ON                               0b00000100  //  2     2                                       enabled
+#define NRF24_DPL_P1_OFF                              0b00000000  //  1     1     dynamic payload length on pipe 1: disabled (default)
+#define NRF24_DPL_P1_ON                               0b00000010  //  1     1                                       enabled
+#define NRF24_DPL_P0_OFF                              0b00000000  //  0     0     dynamic payload length on pipe 0: disabled (default)
+#define NRF24_DPL_P0_ON                               0b00000001  //  0     0                                       enabled
+#define NRF24_DPL_ALL_OFF                             0b00000000  //  5     0     disable all dynamic payloads
+#define NRF24_DPL_ALL_ON                              0b00111111  //  5     0     enable all dynamic payloads
+
+// NRF24_REG_FEATURE
+#define NRF24_DPL_OFF                                 0b00000000  //  2     2     dynamic payload length: disabled (default)
+#define NRF24_DPL_ON                                  0b00000100  //  2     2                             enabled
+#define NRF24_ACK_PAY_OFF                             0b00000000  //  1     1     payload with ACK packets: disabled (default)
+#define NRF24_ACK_PAY_ON                              0b00000010  //  1     1                               enabled
+#define NRF24_DYN_ACK_OFF                             0b00000000  //  0     0     payloads without ACK: disabled (default)
+#define NRF24_DYN_ACK_ON                              0b00000001  //  0     0                           enabled
+
+/*!
+  \class nRF24
+
+  \brief Control class for %nRF24 module.
+*/
+class nRF24: public PhysicalLayer {
+  public:
+    // introduce PhysicalLayer overloads
+    using PhysicalLayer::transmit;
+    using PhysicalLayer::receive;
+    using PhysicalLayer::startTransmit;
+    using PhysicalLayer::readData;
+
+    /*!
+      \brief Default constructor.
+
+      \param mod Instance of Module that will be used to communicate with the radio.
+    */
+    nRF24(Module* module);
+
+    // basic methods
+
+    /*!
+      \brief Initialization method.
+
+      \param freq Carrier frequency in MHz. Defaults to 2400 MHz.
+
+      \param dataRate Data rate to be used in kbps. Defaults to 1000 kbps.
+
+      \param power Output power in dBm. Defaults to -12 dBm.
+
+      \param addrWidth Address width in bytes. Defaults to 5 bytes.
+
+      \returns \ref status_codes
+    */
+    int16_t begin(int16_t freq = 2400, int16_t dataRate = 1000, int8_t power = -12, uint8_t addrWidth = 5);
+
+    /*!
+      \brief Sets the module to sleep mode.
+
+      \returns \ref status_codes
+    */
+    int16_t sleep();
+
+    /*!
+      \brief Sets the module to standby mode.
+
+      \returns \ref status_codes
+    */
+    int16_t standby();
+
+    /*!
+      \brief Blocking binary transmit method.
+      Overloads for string-based transmissions are implemented in PhysicalLayer.
+
+      \param data Binary data to be sent.
+
+      \param len Number of bytes to send.
+
+      \param addr Dummy address parameter, to ensure PhysicalLayer compatibility.
+
+      \returns \ref status_codes
+    */
+    int16_t transmit(uint8_t* data, size_t len, uint8_t addr);
+
+    /*!
+      \brief Blocking binary receive method.
+      Overloads for string-based transmissions are implemented in PhysicalLayer.
+
+      \param data Binary data to be sent.
+
+      \param len Number of bytes to send.
+
+      \returns \ref status_codes
+    */
+    int16_t receive(uint8_t* data, size_t len);
+
+    /*!
+      \brief Starts direct mode transmission.
+
+      \param frf Raw RF frequency value. Defaults to 0, required for quick frequency shifts in RTTY.
+
+      \returns \ref status_codes
+    */
+    int16_t transmitDirect(uint32_t frf = 0);
+
+    /*!
+      \brief Dummy direct mode reception method, to ensure PhysicalLayer compatibility.
+
+      \returns \ref status_codes
+    */
+    int16_t receiveDirect();
+
+    // interrupt methods
+
+    /*!
+      \brief Sets interrupt service routine to call when IRQ activates.
+
+      \param func ISR to call.
+    */
+    void setIrqAction(void (*func)(void));
+
+    /*!
+      \brief Interrupt-driven binary transmit method. IRQ will be activated when full packet is transmitted.
+      Overloads for string-based transmissions are implemented in PhysicalLayer.
+
+      \param data Binary data to be sent.
+
+      \param len Number of bytes to send.
+
+      \param addr Dummy address parameter, to ensure PhysicalLayer compatibility.
+
+      \returns \ref status_codes
+    */
+    int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr);
+
+    /*!
+      \brief Interrupt-driven receive method. IRQ will be activated when full packet is received.
+
+      \returns \ref status_codes
+    */
+    int16_t startReceive();
+
+    /*!
+      \brief Reads data received after calling startReceive method.
+
+      \param data Pointer to array to save the received binary data.
+
+      \param len Number of bytes that will be received. Must be known in advance for binary transmissions.
+
+      \returns \ref status_codes
+    */
+    int16_t readData(uint8_t* data, size_t len);
+
+    // configuration methods
+
+    /*!
+      \brief Sets carrier frequency. Allowed values range from 2400 MHz to 2525 MHz.
+
+      \param freq Carrier frequency to be set in MHz.
+
+      \returns \ref status_codes
+    */
+    int16_t setFrequency(int16_t freq);
+
+    /*!
+      \brief Sets data rate. Allowed values are 2000, 1000 or 250 kbps.
+
+      \param dataRate Data rate to be set in kbps.
+
+      \returns \ref status_codes
+    */
+    int16_t setDataRate(int16_t dataRate);
+
+    /*!
+      \brief Sets output power. Allowed values are -18, -12, -6 or 0 dBm.
+
+      \param power Output power to be set in dBm.
+
+      \returns \ref status_codes
+    */
+    int16_t setOutputPower(int8_t power);
+
+    /*!
+      \brief Sets address width of transmit and receive pipes in bytes. Allowed values are 3, 4 or 5 bytes.
+
+      \param addrWidth Address width to be set in bytes.
+
+      \returns \ref status_codes
+    */
+    int16_t setAddressWidth(uint8_t addrWidth);
+
+    /*!
+      \brief Sets address of transmit pipe. The address width must be the same as the same as the configured in setAddressWidth.
+
+      \param addr Address to which the next packet shall be transmitted.
+
+      \returns \ref status_codes
+    */
+    int16_t setTransmitPipe(uint8_t* addr);
+
+    /*!
+      \brief Sets address of receive pipes 0 or 1. The address width must be the same as the same as the configured in setAddressWidth.
+
+      \param pipeNum Number of pipe to which the address shall be set. Either 0 or 1, other pipes are handled using overloaded method.
+
+      \param addr Address from which %nRF24 shall receive new packets on the specified pipe.
+
+      \returns \ref status_codes
+    */
+    int16_t setReceivePipe(uint8_t pipeNum, uint8_t* addr);
+
+    /*!
+      \brief Sets address of receive pipes 2 - 5. The first 2 - 4 address bytes for these pipes are the same as for address pipe 1, only the last byte can be set.
+
+      \param pipeNum Number of pipe to which the address shall be set. Allowed values range from 2 to 5.
+
+      \param addrByte LSB of address from which %nRF24 shall receive new packets on the specified pipe.
+
+      \returns \ref status_codes
+    */
+    int16_t setReceivePipe(uint8_t pipeNum, uint8_t addrByte);
+
+    /*!
+      \brief Disables specified receive pipe.
+
+      \param pipeNum Receive pipe to be disabled.
+
+      \returns \ref status_codes
+    */
+    int16_t disablePipe(uint8_t pipeNum);
+
+    /*!
+      \brief Gets nRF24 status register.
+
+      \param mask Bit mask to be used on the returned register value.
+
+      \returns Status register value or \ref status_codes
+    */
+    int16_t getStatus(uint8_t mask = 0xFF);
+
+    /*!
+      \brief Dummy configuration method, to ensure PhysicalLayer compatibility.
+
+      \param freqDev Dummy frequency deviation parameter, no configuration will be changed.
+
+      \returns \ref status_codes
+    */
+    int16_t setFrequencyDeviation(float freqDev);
+
+  private:
+    Module* _mod;
+
+    uint8_t _addrWidth;
+
+    int16_t config();
+    void clearIRQ();
+
+    void SPIreadRxPayload(uint8_t* data, uint8_t numBytes);
+    void SPIwriteTxPayload(uint8_t* data, uint8_t numBytes);
+    void SPItransfer(uint8_t cmd, bool write = false, uint8_t* dataOut = NULL, uint8_t* dataIn = NULL, uint8_t numBytes = 0);
+};
+
+#endif

From 528b20fdf3efbf7900f854c1aa4f64d412bf1a60 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sat, 1 Jun 2019 20:50:58 +0200
Subject: [PATCH 007/106] [RTTY] Added note about nRF24 usage

---
 examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino b/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino
index 5a7b4914..e1e9572e 100644
--- a/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino
+++ b/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino
@@ -50,13 +50,14 @@ void setup() {
   //         RF69 - 61 Hz
   //         CC1101 - 397 Hz
   //         SX126x - 1 Hz
+  //         nRF24 - 1000000 Hz
   Serial.print(F("[RTTY] Initializing ... "));
   // low ("space") frequency:     434.0 MHz
   // frequency shift:             183 Hz
   // baud rate:                   45 baud
   // encoding:                    ASCII (7-bit)
   // stop bits:                   1
-  state = rtty.begin(434, 183, 45);
+  state = rtty.begin(434.0, 183, 45);
   if(state == ERR_NONE) {
     Serial.println(F("success!"));
   } else {

From fa46be439c1ca0bcf693c71f35e9df245c1cdd6e Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sat, 1 Jun 2019 20:51:04 +0200
Subject: [PATCH 008/106] [Morse] Added note about nRF24 usage

---
 examples/Morse/Morse_Transmit/Morse_Transmit.ino | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/examples/Morse/Morse_Transmit/Morse_Transmit.ino b/examples/Morse/Morse_Transmit/Morse_Transmit.ino
index 3ad9431d..58490a92 100644
--- a/examples/Morse/Morse_Transmit/Morse_Transmit.ino
+++ b/examples/Morse/Morse_Transmit/Morse_Transmit.ino
@@ -4,12 +4,13 @@
    This example sends Morse code message using
    SX1278's FSK modem.
 
-   Other modules that can be used for Morse:
+   Other modules that can be used for Morse Code:
     - SX127x/RFM9x
     - RF69
     - SX1231
     - CC1101
     - SX126x
+    - nRF24
 */
 
 // include the library

From 0bfc570391d139fe6488f44457bb7991eb349212 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Grome=C5=A1?= <jgromes@users.noreply.github.com>
Date: Sat, 1 Jun 2019 20:56:24 +0200
Subject: [PATCH 009/106] Update README.md

---
 README.md | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/README.md b/README.md
index d68e2a2f..5eb137d7 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,7 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github
 * __ES8266__ WiFi module
 * __HC05__ Bluetooth module
 * __JDY08__ BLE module
+* __nRF24L01__ 2.4 GHz module
 * __RF69__ FSK/OOK radio module
 * __RFM9x__ series LoRa modules (RFM95, RM96, RFM97, RFM98)
 * __SX127x__ series LoRa modules (SX1272, SX1273, SX1276, SX1277, SX1278, SX1279)
@@ -27,12 +28,11 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github
 ### Supported protocols:
 * __MQTT__ for modules: ESP8266
 * __HTTP__ for modules: ESP8266
-* __RTTY__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231 and CC1101
-* __Morse Code__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231 and CC1101
+* __RTTY__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101 and nRF24L01
+* __Morse Code__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101 and nRF24L01
 
 ### In development:
 * __SIM800C__ GSM module
-* __nRF24L01__ 2.4 GHz module
 * __LoRaWAN__ protocol for SX127x, RFM9x and SX126x modules
 * ___and more!___
 

From f004966e57a8a842741d80431c7f8ba28a30fcfb Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sat, 1 Jun 2019 20:57:03 +0200
Subject: [PATCH 010/106] Advanced version to 1.1.0

---
 library.properties | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library.properties b/library.properties
index 0ea6c738..c362f3b2 100644
--- a/library.properties
+++ b/library.properties
@@ -1,5 +1,5 @@
 name=RadioLib
-version=1.0.0
+version=1.1.0
 author=Jan Gromes <gromes.jan@gmail.com>
 maintainer=Jan Gromes <gromes.jan@gmail.com>
 sentence=Universal wireless communication library for Arduino

From 7d141fbbc2254090af43d833436d6ef8370a93c4 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 2 Jun 2019 13:38:46 +0200
Subject: [PATCH 011/106] [Morse] Moved Morse code table to flash

---
 src/protocols/Morse.cpp | 125 +++++++++++++++++++++-------------------
 1 file changed, 66 insertions(+), 59 deletions(-)

diff --git a/src/protocols/Morse.cpp b/src/protocols/Morse.cpp
index 9738ff37..e874c722 100644
--- a/src/protocols/Morse.cpp
+++ b/src/protocols/Morse.cpp
@@ -6,66 +6,66 @@
 */
 struct Morse_t {
   char c;                                             // ASCII character
-  const char* m;                                      // Morse code representation
+  char m[7];                                          // Morse code representation
 };
 /*!
   \endcond
 */
 
 // array of all Morse code characters
-static const Morse_t MorseTable[MORSE_LENGTH] = {
-  {.c = 'A', .m = ".-"},
-  {.c = 'B', .m = "-..."},
-  {.c = 'C', .m = "-.-."},
-  {.c = 'D', .m = "-.."},
-  {.c = 'E', .m = "."},
-  {.c = 'F', .m = "..-."},
-  {.c = 'G', .m = "--."},
-  {.c = 'H', .m = "...."},
-  {.c = 'I', .m = ".."},
-  {.c = 'J', .m = ".---"},
-  {.c = 'K', .m = "-.-"},
-  {.c = 'L', .m = ".-.."},
-  {.c = 'M', .m = "--"},
-  {.c = 'N', .m = "-."},
-  {.c = 'O', .m = "---"},
-  {.c = 'P', .m = ".--."},
-  {.c = 'Q', .m = "--.-"},
-  {.c = 'R', .m = ".-."},
-  {.c = 'S', .m = "..."},
-  {.c = 'T', .m = "-"},
-  {.c = 'U', .m = "..-"},
-  {.c = 'V', .m = "...-"},
-  {.c = 'W', .m = ".--"},
-  {.c = 'X', .m = "-..-"},
-  {.c = 'Y', .m = "-.--"},
-  {.c = 'Z', .m = "--.."},
-  {.c = '1', .m = ".----"},
-  {.c = '2', .m = "..---"},
-  {.c = '3', .m = "...--"},
-  {.c = '4', .m = "....-"},
-  {.c = '5', .m = "....."},
-  {.c = '6', .m = "-...."},
-  {.c = '7', .m = "--..."},
-  {.c = '8', .m = "---.."},
-  {.c = '9', .m = "----."},
-  {.c = '0', .m = "-----"},
-  {.c = '.', .m = ".-.-.-"},
-  {.c = ',', .m = "--..--"},
-  {.c = ':', .m = "---..."},
-  {.c = '?', .m = "..--.."},
-  {.c = '\'', .m = ".----."},
-  {.c = '-', .m = "-....-"},
-  {.c = '/', .m = "-..-."},
-  {.c = '(', .m = "-.--."},
-  {.c = ')', .m = "-.--.-"},
-  {.c = '\"', .m = ".-..-."},
-  {.c = '=', .m = "-...-"},
-  {.c = '+', .m = ".-.-."},
-  {.c = '@', .m = ".--.-."},
-  {.c = ' ', .m = "_"},                               // space is used to separate words
-  {.c = 0x01, .m = "-.-.-"},                          // ASCII SOH (start of heading) is used as alias for start signal
-  {.c = 0x02, .m = ".-.-."}                           // ASCII EOT (end of transmission) is used as alias for stop signal
+const Morse_t MorseTable[MORSE_LENGTH] PROGMEM = {
+  {'A', ".-"},
+  {'B',"-..."},
+  {'C', "-.-."},
+  {'D',"-.."},
+  {'E',"."},
+  {'F',"..-."},
+  {'G',"--."},
+  {'H',"...."},
+  {'I',".."},
+  {'J',".---"},
+  {'K',"-.-"},
+  {'L',".-.."},
+  {'M',"--"},
+  {'N',"-."},
+  {'O',"---"},
+  {'P',".--."},
+  {'Q',"--.-"},
+  {'R',".-."},
+  {'S',"..."},
+  {'T',"-"},
+  {'U',"..-"},
+  {'V',"...-"},
+  {'W',".--"},
+  {'X',"-..-"},
+  {'Y',"-.--"},
+  {'Z',"--.."},
+  {'1',".----"},
+  {'2',"..---"},
+  {'3',"...--"},
+  {'4',"....-"},
+  {'5',"....."},
+  {'6',"-...."},
+  {'7',"--..."},
+  {'8',"---.."},
+  {'9',"----."},
+  {'0',"-----"},
+  {'.',".-.-.-"},
+  {',',"--..--"},
+  {':',"---..."},
+  {'?',"..--.."},
+  {'\'',".----."},
+  {'-',"-....-"},
+  {'/',"-..-."},
+  {'(',"-.--."},
+  {')',"-.--.-"},
+  {'\"',".-..-."},
+  {'=',"-...-"},
+  {'+',".-.-."},
+  {'@',".--.-."},
+  {' ',"_"},                               // space is used to separate words
+  {0x01,"-.-.-"},                          // ASCII SOH (start of heading) is used as alias for start signal
+  {0x02,".-.-."}                           // ASCII EOT (end of transmission) is used as alias for stop signal
 };
 
 MorseClient::MorseClient(PhysicalLayer* phy) {
@@ -107,19 +107,25 @@ size_t MorseClient::write(uint8_t* buff, size_t len) {
 
 size_t MorseClient::write(uint8_t b) {
   // find the correct Morse code in array
-  uint8_t pos;
+  Morse_t mc;
   bool found = false;
-  for(pos = 0; pos < MORSE_LENGTH; pos++) {
-    if(MorseTable[pos].c == toupper(b)) {
+  for(uint8_t pos = 0; pos < MORSE_LENGTH; pos++) {
+    memcpy_P(&mc, &MorseTable[pos], sizeof(Morse_t));
+    if(mc.c == toupper(b)) {
       found = true;
       break;
     }
   }
+
   // check if the requested code was found in the array
   if(found) {
+    DEBUG_PRINT(mc.c);
+    DEBUG_PRINT('\t');
+    DEBUG_PRINTLN(mc.m);
+
     // iterate over Morse code representation and output appropriate tones
-    for(uint8_t i = 0; i < strlen(MorseTable[pos].m); i++) {
-      switch(MorseTable[pos].m[i]) {
+    for(uint8_t i = 0; i < strlen(mc.m); i++) {
+      switch(mc.m[i]) {
         case '.':
           _phy->transmitDirect(_base);
           delay(_dotLength);
@@ -139,6 +145,7 @@ size_t MorseClient::write(uint8_t b) {
     }
 
     // letter space
+    DEBUG_PRINTLN();
     delay(_dotLength * 3);
 
     return(1);

From b3f228e207585d443ae9039a46bc4b00139ad7c5 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 2 Jun 2019 13:39:10 +0200
Subject: [PATCH 012/106] [RTTY] Moved ITA2 code table to flash

---
 src/protocols/RTTY.cpp | 4 ++--
 src/protocols/RTTY.h   | 8 ++++----
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/protocols/RTTY.cpp b/src/protocols/RTTY.cpp
index 9427c87a..0cc22dc7 100644
--- a/src/protocols/RTTY.cpp
+++ b/src/protocols/RTTY.cpp
@@ -84,11 +84,11 @@ uint16_t ITA2String::getBits(char c) {
   // search ITA2 table
   uint16_t code = 0x0000;
   for(uint8_t i = 0; i < ITA2_LENGTH; i++) {
-    if(ITA2Table[i][0] == c) {
+    if(pgm_read_byte(ITA2Table[i][0]) == c) {
       // character is in letter shift
       code = (ITA2_LTRS << 5) | i;
       break;
-    } else if(ITA2Table[i][1] == c) {
+    } else if(pgm_read_byte(ITA2Table[i][1]) == c) {
       // character is in figures shift
       code = (ITA2_FIGS << 5) | i;
       break;
diff --git a/src/protocols/RTTY.h b/src/protocols/RTTY.h
index 6a62cfb0..6a4e9332 100644
--- a/src/protocols/RTTY.h
+++ b/src/protocols/RTTY.h
@@ -11,10 +11,10 @@
 // ITA2 character table: - position in array corresponds to 5-bit ITA2 code
 //                       - characters to the left are in letters shift, characters to the right in figures shift
 //                       - characters marked 0x7F do not have ASCII equivalent
-static const char ITA2Table[ITA2_LENGTH][2] = {{'\0', '\0'}, {'E', '3'}, {'\n', '\n'}, {'A', '-'}, {' ', ' '}, {'S', '\''}, {'I', '8'}, {'U', '7'},
-                                               {'\r', '\r'}, {'D', 0x05}, {'R', '4'}, {'J', '\a'}, {'N', ','}, {'F', '!'}, {'C', ':'}, {'K', '('},
-                                               {'T', '5'}, {'Z', '+'}, {'L', ')'}, {'W', '2'}, {'H', 0x7F}, {'Y', '6'}, {'P', '0'}, {'Q', '1'},
-                                               {'O', '9'}, {'B', '?'}, {'G', '&'}, {0x7F, 0x7F}, {'M', '.'}, {'X', '/'}, {'V', ';'}, {0x7F, 0x7F}};
+static const char ITA2Table[ITA2_LENGTH][2] PROGMEM = {{'\0', '\0'}, {'E', '3'}, {'\n', '\n'}, {'A', '-'}, {' ', ' '}, {'S', '\''}, {'I', '8'}, {'U', '7'},
+                                                       {'\r', '\r'}, {'D', 0x05}, {'R', '4'}, {'J', '\a'}, {'N', ','}, {'F', '!'}, {'C', ':'}, {'K', '('},
+                                                       {'T', '5'}, {'Z', '+'}, {'L', ')'}, {'W', '2'}, {'H', 0x7F}, {'Y', '6'}, {'P', '0'}, {'Q', '1'},
+                                                       {'O', '9'}, {'B', '?'}, {'G', '&'}, {0x7F, 0x7F}, {'M', '.'}, {'X', '/'}, {'V', ';'}, {0x7F, 0x7F}};
 
 /*!
   \class ITA2String

From 554f894adf5dc27fc2c0b2bc9a6a899de9592686 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 2 Jun 2019 14:09:10 +0200
Subject: [PATCH 013/106] [CC1101] Updated examples

---
 .../CC1101/CC1101_Receive/CC1101_Receive.ino  | 28 ++++++++++++++---
 .../CC1101_Receive_Address.ino                | 19 ++++++++++--
 .../CC1101_Receive_Interrupt.ino              | 31 +++++++++++++++++--
 .../CC1101_Settings/CC1101_Settings.ino       | 19 +++++++-----
 .../CC1101_Transmit/CC1101_Transmit.ino       | 23 ++++++++++++--
 .../CC1101_Transmit_Address.ino               | 19 ++++++++++--
 .../CC1101_Transmit_Interrupt.ino             | 31 +++++++++++++------
 7 files changed, 140 insertions(+), 30 deletions(-)

diff --git a/examples/CC1101/CC1101_Receive/CC1101_Receive.ino b/examples/CC1101/CC1101_Receive/CC1101_Receive.ino
index 80962365..8c851088 100644
--- a/examples/CC1101/CC1101_Receive/CC1101_Receive.ino
+++ b/examples/CC1101/CC1101_Receive/CC1101_Receive.ino
@@ -1,15 +1,30 @@
 /*
    RadioLib CC1101 Receive Example
 
-   This example receives packets using CC1101 FSK radio
-   module.
+   This example receives packets using CC1101 FSK radio module.
+   To successfully receive data, the following settings have to be the same
+   on both transmitter and receiver:
+    - carrier frequency
+    - bit rate
+    - frequency deviation
+    - sync word
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// CC1101 is in slot A on the shield
-CC1101 cc = RadioShield.ModuleA;
+// CC1101 has the following connections:
+// NSS pin:   10
+// GDO0 pin:  2
+// GDO2 pin:  3
+CC1101 cc = new Module(10, 2, 3);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//CC1101 cc = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
@@ -67,5 +82,10 @@ void loop() {
     // packet was received, but is malformed
     Serial.println(F("CRC error!"));
 
+  } else {
+    // some other error occurred
+    Serial.print(F("failed, code "));
+    Serial.println(state);
+
   }
 }
diff --git a/examples/CC1101/CC1101_Receive_Address/CC1101_Receive_Address.ino b/examples/CC1101/CC1101_Receive_Address/CC1101_Receive_Address.ino
index 066b6908..1f1aa5bf 100644
--- a/examples/CC1101/CC1101_Receive_Address/CC1101_Receive_Address.ino
+++ b/examples/CC1101/CC1101_Receive_Address/CC1101_Receive_Address.ino
@@ -6,13 +6,23 @@
    destination node. After setting node address, this node
    will automatically filter out any packets that do not
    contain either node address or broadcast addresses.
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// CC1101 is in slot A on the shield
-CC1101 cc = RadioShield.ModuleA;
+// CC1101 has the following connections:
+// NSS pin:   10
+// GDO0 pin:  2
+// GDO2 pin:  3
+CC1101 cc = new Module(10, 2, 3);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//CC1101 cc = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
@@ -102,5 +112,10 @@ void loop() {
     // packet was received, but is malformed
     Serial.println(F("CRC error!"));
 
+  } else {
+    // some other error occurred
+    Serial.print(F("failed, code "));
+    Serial.println(state);
+
   }
 }
diff --git a/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino b/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino
index f5573df4..9fcae3fe 100644
--- a/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino
+++ b/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino
@@ -4,13 +4,30 @@
    This example listens for FSK transmissions and tries to
    receive them. Once a packet is received, an interrupt is
    triggered.
+
+   To successfully receive data, the following settings have to be the same
+   on both transmitter and receiver:
+    - carrier frequency
+    - bit rate
+    - frequency deviation
+    - sync word
+
+    For full API reference, see the GitHub Pages
+    https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// CC1101 module is in slot A on the shield
-CC1101 cc = RadioShield.ModuleA;
+// CC1101 has the following connections:
+// NSS pin:   10
+// GDO0 pin:  2
+// GDO2 pin:  3
+CC1101 cc = new Module(10, 2, 3);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//CC1101 cc = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
@@ -113,6 +130,16 @@ void loop() {
       // of the last received packet, lower is better
       Serial.print(F("[CC1101] LQI:\t\t"));
       Serial.println(cc.getLQI());
+
+    } else if (state == ERR_CRC_MISMATCH) {
+      // packet was received, but is malformed
+      Serial.println(F("CRC error!"));
+
+    } else {
+      // some other error occurred
+      Serial.print(F("failed, code "));
+      Serial.println(state);
+
     }
 
     // we're ready to receive more packets,
diff --git a/examples/CC1101/CC1101_Settings/CC1101_Settings.ino b/examples/CC1101/CC1101_Settings/CC1101_Settings.ino
index e8789d1a..6140a851 100644
--- a/examples/CC1101/CC1101_Settings/CC1101_Settings.ino
+++ b/examples/CC1101/CC1101_Settings/CC1101_Settings.ino
@@ -10,20 +10,23 @@
     - allowed frequency deviation
     - output power during transmission
     - sync word
+
+    For full API reference, see the GitHub Pages
+    https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// CC1101 module is in slot A on the shield
-CC1101 cc1 = RadioShield.ModuleA;
+// CC1101 has the following connections:
+// NSS pin:   10
+// GDO0 pin:  2
+// GDO2 pin:  3
+CC1101 cc1 = new Module(10, 2, 3);
 
-// if you're not using RadioShield, you can specify
-// the connection yourself
-// NSS pin:   6
-// DIO0 pin:  4
-// DIO1 pin:  5
-CC1101 cc2 = new Module(6, 4, 5);
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+CC1101 cc2 = RadioShield.ModuleB;
 
 void setup() {
   Serial.begin(9600);
diff --git a/examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino b/examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino
index 28786d7b..f9272993 100644
--- a/examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino
+++ b/examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino
@@ -2,13 +2,27 @@
    RadioLib CC1101 Transmit Example
 
    This example transmits packets using CC1101 FSK radio module.
+   Each packet contains up to 64 bytes of data, in the form of:
+    - Arduino String
+    - null-terminated char array (C-string)
+    - arbitrary binary data (byte array)
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// CC1101 is in slot A on the shield
-CC1101 cc = RadioShield.ModuleA;
+// CC1101 has the following connections:
+// NSS pin:   10
+// GDO0 pin:  2
+// GDO2 pin:  3
+CC1101 cc = new Module(10, 2, 3);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//CC1101 cc = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
@@ -50,6 +64,11 @@ void loop() {
     // the supplied packet was longer than 255 bytes
     Serial.println(F(" too long!"));
 
+  } else {
+    // some other error occurred
+    Serial.print(F("failed, code "));
+    Serial.println(state);
+
   }
 
   // wait for a second before transmitting again
diff --git a/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino b/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino
index 7a0235fd..b9e8a966 100644
--- a/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino
+++ b/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino
@@ -6,13 +6,23 @@
    destination node. After setting node address, this node
    will automatically filter out any packets that do not
    contain either node address or broadcast addresses.
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// CC1101 is in slot A on the shield
-CC1101 cc = RadioShield.ModuleA;
+// CC1101 has the following connections:
+// NSS pin:   10
+// GDO0 pin:  2
+// GDO2 pin:  3
+CC1101 cc = new Module(10, 2, 3);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//CC1101 cc = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
@@ -86,6 +96,11 @@ void loop() {
     // the supplied packet was longer than 255 bytes
     Serial.println(F(" too long!"));
 
+  } else {
+    // some other error occurred
+    Serial.print(F("failed, code "));
+    Serial.println(state);
+
   }
 
   // wait for a second before transmitting again
diff --git a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino
index cb0914f3..9a909d72 100644
--- a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino
+++ b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino
@@ -1,19 +1,29 @@
 /*
    RadioLib CC1101 Transmit with Interrupts Example
 
-   This example transmits FSK packets with one second delays
-   between them. Each packet contains up to 64 bytes
-   of data, in the form of:
+   This example transmits packets using CC1101 FSK radio module.
+   Once a packet is transmitted, an interrupt is triggered.
+   Each packet contains up to 64 bytes of data, in the form of:
     - Arduino String
     - null-terminated char array (C-string)
     - arbitrary binary data (byte array)
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// CC1101 module is in slot A on the shield
-CC1101 cc = RadioShield.ModuleA;
+// CC1101 has the following connections:
+// NSS pin:   10
+// GDO0 pin:  2
+// GDO2 pin:  3
+CC1101 cc = new Module(10, 2, 3);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//CC1101 cc = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
@@ -34,7 +44,7 @@ void setup() {
     while (true);
   }
 
-  // set the function that will be called 
+  // set the function that will be called
   // when packet transmission is finished
   cc.setGdo0Action(setFlag);
 
@@ -51,10 +61,11 @@ void setup() {
                       0x78, 0xAB, 0xCD, 0xEF};
     state = cc.transmit(byteArr, 8);
   */
-  
+
   if (state != ERR_NONE) {
     Serial.print(F("failed, code "));
     Serial.println(state);
+    while (true);
   }
 }
 
@@ -69,7 +80,7 @@ void setFlag(void) {
 void loop() {
   // check if the previous transmission finished
   if(transmittedFlag) {
-    Serial.println(F("[CC1101] Packet transmission finished!"));
+    Serial.println(F("packet transmission finished!"));
 
     // wait one second before next transmission
     delay(1000);
@@ -80,14 +91,14 @@ void loop() {
     // you can transmit C-string or Arduino string up to
     // 64 characters long
     int state = cc.startTransmit("Hello World!");
-  
+
     // you can also transmit byte array up to 256 bytes long
     /*
       byte byteArr[] = {0x01, 0x23, 0x45, 0x56,
                         0x78, 0xAB, 0xCD, 0xEF};
       int state = cc.transmit(byteArr, 8);
     */
-    
+
     if (state != ERR_NONE) {
       Serial.print(F("failed, code "));
       Serial.println(state);

From 0adf34fea24dee77170a9ad3128787406767af12 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 2 Jun 2019 15:02:12 +0200
Subject: [PATCH 014/106] [HC05] Updated examples

---
 examples/HC05/HC05_Basic/HC05_Basic.ino | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/examples/HC05/HC05_Basic/HC05_Basic.ino b/examples/HC05/HC05_Basic/HC05_Basic.ino
index f9e7e526..dc7790be 100644
--- a/examples/HC05/HC05_Basic/HC05_Basic.ino
+++ b/examples/HC05/HC05_Basic/HC05_Basic.ino
@@ -3,14 +3,23 @@
 
    This example sends data using HC05 Bluetooth module.
    HC05 works exactly like a Serial line, data are sent to the paired device.
-   The default pairing code for HC05 is 1234.
+   The default pairing code for HC05 is 1234 or 1111.
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// HC05 module is in slot A on the shield
-HC05 bluetooth = RadioShield.ModuleA;
+// HC05 has the following connections:
+// TX pin: 9
+// RX pin: 8
+HC05 bluetooth = new Module(9, 8);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//HC05 bluetooth = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);

From 66cd4e45ec8873d81253901bbba68f32d2355591 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 2 Jun 2019 15:02:19 +0200
Subject: [PATCH 015/106] [HTTP] Updated examples

---
 examples/HTTP/HTTP_Get/HTTP_Get.ino   | 13 +++++++++++--
 examples/HTTP/HTTP_Post/HTTP_Post.ino | 22 +++++++++++++++-------
 2 files changed, 26 insertions(+), 9 deletions(-)

diff --git a/examples/HTTP/HTTP_Get/HTTP_Get.ino b/examples/HTTP/HTTP_Get/HTTP_Get.ino
index f36cc226..8a253d45 100644
--- a/examples/HTTP/HTTP_Get/HTTP_Get.ino
+++ b/examples/HTTP/HTTP_Get/HTTP_Get.ino
@@ -8,13 +8,22 @@
 
    IMPORTANT: Before uploading this example, make sure that the ESP8266 module is running
    AT firmware (can be found in the /extras folder of the library)!
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// ESP8266 module is in slot A on the shield
-ESP8266 wifi = RadioShield.ModuleA;
+// ESP8266 has the following connections:
+// TX pin: 9
+// RX pin: 8
+ESP8266 wifi = new Module(9, 8);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//ESP8266 wifi = RadioShield.ModuleA;
 
 // create HTTP client instance using the wifi module
 // the default port used for HTTP is 80
diff --git a/examples/HTTP/HTTP_Post/HTTP_Post.ino b/examples/HTTP/HTTP_Post/HTTP_Post.ino
index cda01ae4..9df864c7 100644
--- a/examples/HTTP/HTTP_Post/HTTP_Post.ino
+++ b/examples/HTTP/HTTP_Post/HTTP_Post.ino
@@ -1,20 +1,29 @@
 /*
    RadioLib HTTP POST Example
-   
+
    This example sends HTTP POST request using ESP8266 WiFi module.
-   
+
    Please note that the response will be saved including header. HTTP header size
    can easily exceed Arduino resources and cause the program to behave erratically.
-   
+
    IMPORTANT: Before uploading this example, make sure that the ESP8266 module is running
    AT firmware (can be found in the /extras folder of the library)!
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
  */
 
 // include the library
 #include <RadioLib.h>
 
-// ESP8266 module is in slot A on the shield
-ESP8266 wifi = RadioShield.ModuleA;
+// ESP8266 has the following connections:
+// TX pin: 9
+// RX pin: 8
+ESP8266 wifi = new Module(9, 8);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//ESP8266 wifi = RadioShield.ModuleA;
 
 // create HTTP client instance using the wifi module
 // the default port used for HTTP is 80
@@ -22,7 +31,7 @@ HTTPClient http(&wifi, 80);
 
 void setup() {
   Serial.begin(9600);
-  
+
   // initialize ESP8266
   Serial.print(F("[ESP8266] Initializing ... "));
   // baudrate:  9600 baud
@@ -75,4 +84,3 @@ void loop() {
   // wait for a second before sending new request
   delay(1000);
 }
-

From 4b9de4c290503670338713c09f532c8a56616eef Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 2 Jun 2019 15:02:26 +0200
Subject: [PATCH 016/106] [JDY08] Updated examples

---
 examples/JDY08/JDY08_Basic/JDY08_Basic.ino | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/examples/JDY08/JDY08_Basic/JDY08_Basic.ino b/examples/JDY08/JDY08_Basic/JDY08_Basic.ino
index c8777772..f78b6c80 100644
--- a/examples/JDY08/JDY08_Basic/JDY08_Basic.ino
+++ b/examples/JDY08/JDY08_Basic/JDY08_Basic.ino
@@ -2,13 +2,23 @@
    RadioLib JDY08 Example
 
    This example sends data using JDY08 Bluetooth module.
+   JDY08 works exactly like a Serial line, data are sent to the paired device.
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// JDY08 module is in slot A on the shield
-JDY08 ble = RadioShield.ModuleA;
+// JDY08 has the following connections:
+// TX pin: 9
+// RX pin: 8
+JDY08 ble = new Module(9, 8);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//JDY08 ble = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);

From 659f1ab91c4a1df26750d670c87029749e64047b Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 2 Jun 2019 15:02:37 +0200
Subject: [PATCH 017/106] [MQTT] Updated examples

---
 examples/MQTT/MQTT_Publish/MQTT_Publish.ino     | 14 +++++++++++---
 examples/MQTT/MQTT_Subscribe/MQTT_Subscribe.ino | 13 +++++++++++--
 2 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/examples/MQTT/MQTT_Publish/MQTT_Publish.ino b/examples/MQTT/MQTT_Publish/MQTT_Publish.ino
index e5e85051..1dc25099 100644
--- a/examples/MQTT/MQTT_Publish/MQTT_Publish.ino
+++ b/examples/MQTT/MQTT_Publish/MQTT_Publish.ino
@@ -8,13 +8,22 @@
 
    IMPORTANT: Before uploading this example, make sure that the ESP8266 module is running
    AT firmware (can be found in the /extras folder of the library)!
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// ESP8266 module is in slot A on the shield
-ESP8266 wifi = RadioShield.ModuleA;
+// ESP8266 has the following connections:
+// TX pin: 9
+// RX pin: 8
+ESP8266 wifi = new Module(9, 8);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//ESP8266 wifi = RadioShield.ModuleA;
 
 // create MQTT client instance using the wifi module
 // the default port used for MQTT is 1883
@@ -80,4 +89,3 @@ void loop() {
   // wait for a second before publishing again
   delay(1000);
 }
-
diff --git a/examples/MQTT/MQTT_Subscribe/MQTT_Subscribe.ino b/examples/MQTT/MQTT_Subscribe/MQTT_Subscribe.ino
index 85ae9861..c06bc758 100644
--- a/examples/MQTT/MQTT_Subscribe/MQTT_Subscribe.ino
+++ b/examples/MQTT/MQTT_Subscribe/MQTT_Subscribe.ino
@@ -8,13 +8,22 @@
 
    IMPORTANT: Before uploading this example, make sure that the ESP8266 module is running
    AT firmware (can be found in the /extras folder of the library)!
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// ESP8266 module is in slot A on the shield
-ESP8266 wifi = RadioShield.ModuleA;
+// ESP8266 has the following connections:
+// TX pin: 9
+// RX pin: 8
+ESP8266 wifi = new Module(9, 8);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//ESP8266 wifi = RadioShield.ModuleA;
 
 // create MQTT client instance using the wifi module
 // the default port used for MQTT is 1883

From 8fbfb68749d912dff196d8b4d4757bf501feda3a Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 2 Jun 2019 15:02:45 +0200
Subject: [PATCH 018/106] [Morse] Updated examples

---
 examples/Morse/Morse_Transmit/Morse_Transmit.ino | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/examples/Morse/Morse_Transmit/Morse_Transmit.ino b/examples/Morse/Morse_Transmit/Morse_Transmit.ino
index 58490a92..9e158777 100644
--- a/examples/Morse/Morse_Transmit/Morse_Transmit.ino
+++ b/examples/Morse/Morse_Transmit/Morse_Transmit.ino
@@ -16,8 +16,15 @@
 // include the library
 #include <RadioLib.h>
 
-// SX1278 module is in slot A on the shield
-SX1278 fsk = RadioShield.ModuleA;
+// SX1278 has the following connections:
+// NSS pin:   10
+// DIO0 pin:  2
+// DIO1 pin:  3
+SX1278 fsk = new Module(10, 2, 3);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//SX1278 fsk = RadioShield.ModuleA;
 
 // create Morse client instance using the FSK module
 MorseClient morse(&fsk);

From a49f1da0937e4728d75a69314676053fa3edcf73 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 2 Jun 2019 15:02:56 +0200
Subject: [PATCH 019/106] [RF69] Updated examples

---
 examples/RF69/RF69_Receive/RF69_Receive.ino   | 25 +++++++++++++++++--
 .../RF69_Receive_AES/RF69_Receive_AES.ino     | 22 +++++++++++++---
 .../RF69_Receive_Address.ino                  | 19 ++++++++++++--
 .../RF69_Receive_Interrupt.ino                | 24 ++++++++++++++++--
 examples/RF69/RF69_Settings/RF69_Settings.ino | 19 ++++++++------
 examples/RF69/RF69_Transmit/RF69_Transmit.ino | 23 +++++++++++++++--
 .../RF69_Transmit_AES/RF69_Transmit_AES.ino   | 24 ++++++++++++++----
 .../RF69_Transmit_Address.ino                 | 23 ++++++++++++++---
 .../RF69_Transmit_Interrupt.ino               | 24 ++++++++++++------
 9 files changed, 167 insertions(+), 36 deletions(-)

diff --git a/examples/RF69/RF69_Receive/RF69_Receive.ino b/examples/RF69/RF69_Receive/RF69_Receive.ino
index 15bbef16..fb8b69bd 100644
--- a/examples/RF69/RF69_Receive/RF69_Receive.ino
+++ b/examples/RF69/RF69_Receive/RF69_Receive.ino
@@ -2,13 +2,29 @@
    RadioLib RF69 Receive Example
 
    This example receives packets using RF69 FSK radio module.
+   To successfully receive data, the following settings have to be the same
+   on both transmitter and receiver:
+    - carrier frequency
+    - bit rate
+    - frequency deviation
+    - sync word
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// RF69 module is in slot A on the shield
-RF69 rf = RadioShield.ModuleA;
+// RF69 has the following connections:
+// NSS pin:   10
+// DIO0 pin:  2
+// DIO1 pin:  3
+RF69 rf = new Module(10, 2, 3);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//RF69 rf = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
@@ -60,5 +76,10 @@ void loop() {
     // packet was received, but is malformed
     Serial.println(F("CRC error!"));
 
+  } else {
+    // some other error occurred
+    Serial.print(F("failed, code "));
+    Serial.println(state);
+
   }
 }
diff --git a/examples/RF69/RF69_Receive_AES/RF69_Receive_AES.ino b/examples/RF69/RF69_Receive_AES/RF69_Receive_AES.ino
index 1664304d..cc5e074a 100644
--- a/examples/RF69/RF69_Receive_AES/RF69_Receive_AES.ino
+++ b/examples/RF69/RF69_Receive_AES/RF69_Receive_AES.ino
@@ -4,13 +4,23 @@
    This example receives packets using RF69 FSK radio module.
    Packets are decrypted using hardware AES.
    NOTE: When using address filtering, the address byte is NOT encrypted!
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// RF69 module is in slot A on the shield
-RF69 rf = RadioShield.ModuleA;
+// RF69 has the following connections:
+// NSS pin:   10
+// DIO0 pin:  2
+// DIO1 pin:  3
+RF69 rf = new Module(10, 2, 3);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//RF69 rf = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
@@ -35,8 +45,7 @@ void setup() {
   // set AES key that will be used to decrypt the packet
   // NOTE: the key must be exactly 16 bytes long!
   uint8_t key[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-                   0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
-                  };
+                   0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
   rf.setAESKey(key);
 
   // enable AES encryption
@@ -77,5 +86,10 @@ void loop() {
     // packet was received, but is malformed
     Serial.println(F("CRC error!"));
 
+  } else {
+    // some other error occurred
+    Serial.print(F("failed, code "));
+    Serial.println(state);
+
   }
 }
diff --git a/examples/RF69/RF69_Receive_Address/RF69_Receive_Address.ino b/examples/RF69/RF69_Receive_Address/RF69_Receive_Address.ino
index 61530cc0..c0444357 100644
--- a/examples/RF69/RF69_Receive_Address/RF69_Receive_Address.ino
+++ b/examples/RF69/RF69_Receive_Address/RF69_Receive_Address.ino
@@ -6,13 +6,23 @@
    After setting node (or broadcast) address, this node will
    automatically filter out any packets that do not contain
    either node address or broadcast address.
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// RF69 module is in slot A on the shield
-RF69 rf = RadioShield.ModuleA;
+// RF69 has the following connections:
+// NSS pin:   10
+// DIO0 pin:  2
+// DIO1 pin:  3
+RF69 rf = new Module(10, 2, 3);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//RF69 rf = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
@@ -105,5 +115,10 @@ void loop() {
     // packet was received, but is malformed
     Serial.println(F("CRC error!"));
 
+  } else {
+    // some other error occurred
+    Serial.print(F("failed, code "));
+    Serial.println(state);
+
   }
 }
diff --git a/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino b/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino
index 8d38952d..336f41a1 100644
--- a/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino
+++ b/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino
@@ -4,13 +4,23 @@
    This example listens for FSK transmissions and tries to
    receive them. Once a packet is received, an interrupt is
    triggered.
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// RF69 module is in slot A on the shield
-RF69 rf = RadioShield.ModuleA;
+// RF69 has the following connections:
+// NSS pin:   10
+// DIO0 pin:  2
+// DIO1 pin:  3
+RF69 rf = new Module(10, 2, 3);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//RF69 rf = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
@@ -103,6 +113,16 @@ void loop() {
       // print data of the packet
       Serial.print(F("[RF69] Data:\t\t\t"));
       Serial.println(str);
+
+    } else if (state == ERR_CRC_MISMATCH) {
+      // packet was received, but is malformed
+      Serial.println(F("CRC error!"));
+
+    } else {
+      // some other error occurred
+      Serial.print(F("failed, code "));
+      Serial.println(state);
+
     }
 
     // we're ready to receive more packets,
diff --git a/examples/RF69/RF69_Settings/RF69_Settings.ino b/examples/RF69/RF69_Settings/RF69_Settings.ino
index ed86e505..1f223745 100644
--- a/examples/RF69/RF69_Settings/RF69_Settings.ino
+++ b/examples/RF69/RF69_Settings/RF69_Settings.ino
@@ -10,20 +10,23 @@
     - allowed frequency deviation
     - output power during transmission
     - sync word
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// RF69 module is in slot A on the shield
-RF69 rf1 = RadioShield.ModuleA;
+// RF69 has the following connections:
+// NSS pin:   10
+// DIO0 pin:  2
+// DIO1 pin:  3
+RF69 rf1 = new Module(10, 2, 3);
 
-// if you're not using RadioShield, you can specify
-// the connection yourself
-// NSS pin:   6
-// DIO0 pin:  4
-// DIO1 pin:  5
-RF69 rf2 = new Module(6, 4, 5);
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+RF69 rf2 = RadioShield.ModuleB;
 
 void setup() {
   Serial.begin(9600);
diff --git a/examples/RF69/RF69_Transmit/RF69_Transmit.ino b/examples/RF69/RF69_Transmit/RF69_Transmit.ino
index e8b92c40..dca4f975 100644
--- a/examples/RF69/RF69_Transmit/RF69_Transmit.ino
+++ b/examples/RF69/RF69_Transmit/RF69_Transmit.ino
@@ -2,13 +2,27 @@
    RadioLib RF69 Transmit Example
 
    This example transmits packets using RF69 FSK radio module.
+   Each packet contains up to 64 bytes of data, in the form of:
+    - Arduino String
+    - null-terminated char array (C-string)
+    - arbitrary binary data (byte array)
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// RF69 module is in slot A on the shield
-RF69 rf = RadioShield.ModuleA;
+// RF69 has the following connections:
+// NSS pin:   10
+// DIO0 pin:  2
+// DIO1 pin:  3
+RF69 rf = new Module(10, 2, 3);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//RF69 rf = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
@@ -51,6 +65,11 @@ void loop() {
     // the supplied packet was longer than 64 bytes
     Serial.println(F(" too long!"));
 
+  } else {
+    // some other error occurred
+    Serial.print(F("failed, code "));
+    Serial.println(state);
+
   }
 
   // wait for a second before transmitting again
diff --git a/examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino b/examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino
index a8b93576..b0b127ff 100644
--- a/examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino
+++ b/examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino
@@ -4,13 +4,23 @@
    This example transmits packets using RF69 FSK radio module.
    Packets are encrypted using hardware AES.
    NOTE: When using address filtering, the address byte is NOT encrypted!
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// RF69 module is in slot A on the shield
-RF69 rf = RadioShield.ModuleA;
+// RF69 has the following connections:
+// NSS pin:   10
+// DIO0 pin:  2
+// DIO1 pin:  3
+RF69 rf = new Module(10, 2, 3);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//RF69 rf = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
@@ -35,8 +45,7 @@ void setup() {
   // set AES key to encrypt the packet
   // NOTE: the key must be exactly 16 bytes long!
   uint8_t key[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-                   0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
-                  };
+                   0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
   rf.setAESKey(key);
 
   // enable AES encryption
@@ -65,9 +74,14 @@ void loop() {
     Serial.println(F(" success!"));
 
   } else if (state == ERR_PACKET_TOO_LONG) {
-    // the supplied packet was longer than 256 bytes
+    // the supplied packet was longer than 64 bytes
     Serial.println(F(" too long!"));
 
+  } else {
+    // some other error occurred
+    Serial.print(F("failed, code "));
+    Serial.println(state);
+
   }
 
   // wait for a second before transmitting again
diff --git a/examples/RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino b/examples/RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino
index 77e2a38c..03b61a70 100644
--- a/examples/RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino
+++ b/examples/RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino
@@ -6,13 +6,23 @@
    After setting node (or broadcast) address, this node will
    automatically filter out any packets that do not contain
    either node address or broadcast address.
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// RF69 module is in slot A on the shield
-RF69 rf = RadioShield.ModuleA;
+// RF69 has the following connections:
+// NSS pin:   10
+// DIO0 pin:  2
+// DIO1 pin:  3
+RF69 rf = new Module(10, 2, 3);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//RF69 rf = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
@@ -35,7 +45,7 @@ void setup() {
   }
 
   // set node address
-  // NOTE: calling this method will autmatically enable
+  // NOTE: calling this method will automatically enable
   // address filtering (node address only)
   Serial.print(F("[RF69] Setting node address ... "));
   state = rf.setNodeAddress(0x01);
@@ -104,9 +114,14 @@ void loop() {
     Serial.println(F(" success!"));
 
   } else if (state == ERR_PACKET_TOO_LONG) {
-    // the supplied packet was longer than 256 bytes
+    // the supplied packet was longer than 64 bytes
     Serial.println(F(" too long!"));
 
+  } else {
+    // some other error occurred
+    Serial.print(F("failed, code "));
+    Serial.println(state);
+
   }
 
   // wait for a second before transmitting again
diff --git a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino
index 294164bf..1f4481ec 100644
--- a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino
+++ b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino
@@ -7,13 +7,23 @@
     - Arduino String
     - null-terminated char array (C-string)
     - arbitrary binary data (byte array)
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// RF69 module is in slot A on the shield
-RF69 rf = RadioShield.ModuleA;
+// RF69 has the following connections:
+// NSS pin:   10
+// DIO0 pin:  2
+// DIO1 pin:  3
+RF69 rf = new Module(10, 2, 3);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//RF69 rf = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
@@ -35,7 +45,7 @@ void setup() {
     while (true);
   }
 
-  // set the function that will be called 
+  // set the function that will be called
   // when packet transmission is finished
   rf.setDio0Action(setFlag);
 
@@ -52,7 +62,7 @@ void setup() {
                       0x78, 0xAB, 0xCD, 0xEF};
     state = rf.transmit(byteArr, 8);
   */
-  
+
   if (state != ERR_NONE) {
     Serial.print(F("failed, code "));
     Serial.println(state);
@@ -70,7 +80,7 @@ void setFlag(void) {
 void loop() {
   // check if the previous transmission finished
   if(transmittedFlag) {
-    Serial.println(F("[RF69] Packet transmission finished!"));
+    Serial.println(F("packet transmission finished!"));
 
     // wait one second before next transmission
     delay(1000);
@@ -81,14 +91,14 @@ void loop() {
     // you can transmit C-string or Arduino string up to
     // 64 characters long
     int state = rf.startTransmit("Hello World!");
-  
+
     // you can also transmit byte array up to 256 bytes long
     /*
       byte byteArr[] = {0x01, 0x23, 0x45, 0x56,
                         0x78, 0xAB, 0xCD, 0xEF};
       int state = rf.transmit(byteArr, 8);
     */
-    
+
     if (state != ERR_NONE) {
       Serial.print(F("failed, code "));
       Serial.println(state);

From ff6e87a0dd03943134652ad742248f8d853af4a2 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 2 Jun 2019 15:03:02 +0200
Subject: [PATCH 020/106] [RTTY] Updated examples

---
 examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino b/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino
index e1e9572e..3b7b799c 100644
--- a/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino
+++ b/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino
@@ -10,13 +10,24 @@
     - SX1231
     - CC1101
     - SX126x
+    - nRF24
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// SX1278 module is in slot A on the shield
-SX1278 fsk = RadioShield.ModuleA;
+// SX1278 has the following connections:
+// NSS pin:   10
+// DIO0 pin:  2
+// DIO1 pin:  3
+SX1278 fsk = new Module(10, 2, 3);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//SX1278 fsk = RadioShield.ModuleA;
 
 // create RTTY client instance using the FSK module
 RTTYClient rtty(&fsk);

From 076b111e6cc80764effb4d0e357062fe31df4398 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 2 Jun 2019 15:03:10 +0200
Subject: [PATCH 021/106] [SX1231] Updated examples

---
 .../SX1231/SX1231_Receive/SX1231_Receive.ino  | 19 +++++++++++++++++--
 .../SX1231_Transmit/SX1231_Transmit.ino       | 14 ++++++++++++--
 2 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/examples/SX1231/SX1231_Receive/SX1231_Receive.ino b/examples/SX1231/SX1231_Receive/SX1231_Receive.ino
index 42af27e8..8de99947 100644
--- a/examples/SX1231/SX1231_Receive/SX1231_Receive.ino
+++ b/examples/SX1231/SX1231_Receive/SX1231_Receive.ino
@@ -6,13 +6,23 @@
    NOTE: SX1231 offers the same features as RF69 and has the same
          interface. Please see RF69 examples for examples on AES,
          address filtering, interrupts and settings.
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// SX1231 module is in slot A on the shield
-SX1231 rf = RadioShield.ModuleA;
+// SX1231 has the following connections:
+// NSS pin:   10
+// DIO0 pin:  2
+// DIO1 pin:  3
+SX1231 rf = new Module(10, 2, 3);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//SX1231 rf = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
@@ -64,5 +74,10 @@ void loop() {
     // packet was received, but is malformed
     Serial.println(F("CRC error!"));
 
+  } else {
+    // some other error occurred
+    Serial.print(F("failed, code "));
+    Serial.println(state);
+
   }
 }
diff --git a/examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino b/examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino
index 6fbc5f06..b3376f2d 100644
--- a/examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino
+++ b/examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino
@@ -6,13 +6,23 @@
    NOTE: SX1231 offers the same features as RF69 and has the same
          interface. Please see RF69 examples for examples on AES,
          address filtering, interrupts and settings.
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// SX1231 module is in slot A on the shield
-SX1231 rf = RadioShield.ModuleA;
+// SX1231 has the following connections:
+// NSS pin:   10
+// DIO0 pin:  2
+// DIO1 pin:  3
+SX1231 rf = new Module(10, 2, 3);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//SX1231 rf = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);

From 98f60dd092e9b09afc5d3a719511e703bf3ec0f5 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 2 Jun 2019 15:03:21 +0200
Subject: [PATCH 022/106] [SX126x] Updated examples

---
 .../SX126x_Channel_Activity_Detection.ino     | 23 +++++---
 .../SX126x_FSK_Modem/SX126x_FSK_Modem.ino     | 25 ++++++---
 .../SX126x/SX126x_Receive/SX126x_Receive.ino  | 20 ++++++-
 .../SX126x_Receive_Interrupt.ino              | 20 ++++++-
 .../SX126x_Settings/SX126x_Settings.ino       | 53 ++++++++++---------
 .../SX126x_Transmit/SX126x_Transmit.ino       | 20 ++++++-
 .../SX126x_Transmit_Interrupt.ino             | 11 +++-
 7 files changed, 126 insertions(+), 46 deletions(-)

diff --git a/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino b/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino
index b1f2611b..0750f181 100644
--- a/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino
+++ b/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino
@@ -1,20 +1,31 @@
 /*
    RadioLib SX126x Channel Activity Detection Example
 
-   This example scans the current LoRa channel and detects 
-   valid LoRa preambles. Preamble is the first part of 
-   LoRa transmission, so this can be used to check 
-   if the LoRa channel is free, or if you should start 
+   This example scans the current LoRa channel and detects
+   valid LoRa preambles. Preamble is the first part of
+   LoRa transmission, so this can be used to check
+   if the LoRa channel is free, or if you should start
    receiving a message.
 
    Other modules from SX126x family can also be used.
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// SX1262 module is in slot A on the shield
-SX1262 lora = RadioShield.ModuleA;
+// SX1262 has the following connections:
+// NSS pin:   10
+// DIO1 pin:  2
+// DIO2 pin:  3
+// BUSY pin:  9
+SX1262 lora = new Module(10, 2, 3, 9);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//SX1262 lora = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
diff --git a/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino b/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino
index f961f5a6..61b6a1e8 100644
--- a/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino
+++ b/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino
@@ -2,19 +2,30 @@
    RadioLib SX126x FSK Modem Example
 
    This example shows how to use FSK modem in SX126x chips.
-   
+
    NOTE: The sketch below is just a guide on how to use
          FSK modem, so this code should not be run directly!
          Instead, modify the other examples to use FSK
          modem and use the appropriate configuration
          methods.
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// SX1262 module is in slot A on the shield
-SX1262 fsk = RadioShield.ModuleA;
+// SX1262 has the following connections:
+// NSS pin:   10
+// DIO1 pin:  2
+// DIO2 pin:  3
+// BUSY pin:  9
+SX1262 fsk = new Module(10, 2, 3, 9);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//SX1262 fsk = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
@@ -45,7 +56,7 @@ void setup() {
   // lora.begin()       start LoRa mode (and disable FSK)
   // lora.beginFSK()    start FSK mode (and disable LoRa)
 
-  // the following settings can also 
+  // the following settings can also
   // be modified at run-time
   state = fsk.setFrequency(433.5);
   state = fsk.setBitRate(100.0);
@@ -54,7 +65,7 @@ void setup() {
   state = fsk.setOutputPower(10.0);
   state = fsk.setCurrentLimit(100.0);
   state = fsk.setDataShaping(1.0);
-  uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67, 
+  uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67,
                         0x89, 0xAB, 0xCD, 0xEF};
   state = fsk.setSyncWord(syncWord, 8);
   if (state != ERR_NONE) {
@@ -75,7 +86,7 @@ void setup() {
 void loop() {
   // FSK modem can use the same transmit/receive methods
   // as the LoRa modem, even their interrupt-driven versions
-  
+
   // transmit FSK packet
   int state = fsk.transmit("Hello World!");
   /*
@@ -116,7 +127,7 @@ void loop() {
   // it can be enabled by setting node address, broadcast
   // address, or both
   //
-  // to transmit packet to a particular address, 
+  // to transmit packet to a particular address,
   // use the following methods:
   //
   // fsk.transmit("Hello World!", address);
diff --git a/examples/SX126x/SX126x_Receive/SX126x_Receive.ino b/examples/SX126x/SX126x_Receive/SX126x_Receive.ino
index 8cbec6cc..1e582158 100644
--- a/examples/SX126x/SX126x_Receive/SX126x_Receive.ino
+++ b/examples/SX126x/SX126x_Receive/SX126x_Receive.ino
@@ -12,13 +12,24 @@
     - preamble length
 
    Other modules from SX126x family can also be used.
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// SX1262 module is in slot A on the shield
-SX1262 lora = RadioShield.ModuleA;
+// SX1262 has the following connections:
+// NSS pin:   10
+// DIO1 pin:  2
+// DIO2 pin:  3
+// BUSY pin:  9
+SX1262 lora = new Module(10, 2, 3, 9);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//SX1262 lora = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
@@ -88,5 +99,10 @@ void loop() {
     // packet was received, but is malformed
     Serial.println(F("CRC error!"));
 
+  } else {
+    // some other error occurred
+    Serial.print(F("failed, code "));
+    Serial.println(state);
+
   }
 }
diff --git a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino
index 107b2d38..3de2873e 100644
--- a/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino
+++ b/examples/SX126x/SX126x_Receive_Interrupt/SX126x_Receive_Interrupt.ino
@@ -13,13 +13,24 @@
     - sync word
 
    Other modules from SX126x/RFM9x family can also be used.
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// SX1262 module is in slot A on the shield
-SX1262 lora = RadioShield.ModuleA;
+// SX1262 has the following connections:
+// NSS pin:   10
+// DIO1 pin:  2
+// DIO2 pin:  3
+// BUSY pin:  9
+SX1262 lora = new Module(10, 2, 3, 9);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//SX1262 lora = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
@@ -131,6 +142,11 @@ void loop() {
       // packet was received, but is malformed
       Serial.println(F("CRC error!"));
 
+    } else {
+      // some other error occurred
+      Serial.print(F("failed, code "));
+      Serial.println(state);
+
     }
 
     // we're ready to receive more packets,
diff --git a/examples/SX126x/SX126x_Settings/SX126x_Settings.ino b/examples/SX126x/SX126x_Settings/SX126x_Settings.ino
index d6daf6d7..52553045 100644
--- a/examples/SX126x/SX126x_Settings/SX126x_Settings.ino
+++ b/examples/SX126x/SX126x_Settings/SX126x_Settings.ino
@@ -14,28 +14,31 @@
     - preamble length
     - TCXO voltage
 
-    Other modules from SX126x family can also be used.
+   Other modules from SX126x family can also be used.
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// SX1268 module is in slot A on the shield
-SX1268 loraSX1268 = RadioShield.ModuleA;
+// SX1262 has the following connections:
+// NSS pin:   10
+// DIO1 pin:  2
+// DIO2 pin:  3
+// BUSY pin:  9
+SX1262 loraSX1262 = new Module(10, 2, 3, 9);
 
-// if you're not using RadioShield, you can specify
-// the connection yourself
-// NSS pin:   6
-// DIO1 pin:  4
-// DIO2 pin:  5
-// BUSY pin:  7
-SX1262 loraSX1262 = new Module(6, 4, 5, 7);
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+SX1268 loraSX1268 = RadioShield.ModuleB;
 
 void setup() {
   Serial.begin(9600);
 
   // initialize SX1268 with default settings
-  Serial.print(F("[SX1268] Initializing ... "));
+  Serial.print(F("[SX1262] Initializing ... "));
   // carrier frequency:           434.0 MHz
   // bandwidth:                   125.0 kHz
   // spreading factor:            9
@@ -45,7 +48,7 @@ void setup() {
   // current limit:               60 mA
   // preamble length:             8 symbols
   // CRC:                         enabled
-  int state = loraSX1268.begin();
+  int state = loraSX1262.begin();
   if (state == ERR_NONE) {
     Serial.println(F("success!"));
   } else {
@@ -58,7 +61,7 @@ void setup() {
   // non-default settings
   // this LoRa link will have high data rate,
   // but lower range
-  Serial.print(F("[SX1262] Initializing ... "));
+  Serial.print(F("[SX1268] Initializing ... "));
   // carrier frequency:           915.0 MHz
   // bandwidth:                   500.0 kHz
   // spreading factor:            6
@@ -68,7 +71,7 @@ void setup() {
   // current limit:               50 mA
   // preamble length:             20 symbols
   // CRC:                         enabled
-  state = loraSX1262.begin(915.0, 500.0, 6, 5, 0x3444, 50, 20);
+  state = loraSX1268.begin(915.0, 500.0, 6, 5, 0x3444, 50, 20);
   if (state == ERR_NONE) {
     Serial.println(F("success!"));
   } else {
@@ -81,64 +84,64 @@ void setup() {
   // and check if the configuration was changed successfully
 
   // set carrier frequency to 433.5 MHz
-  if (loraSX1268.setFrequency(433.5) == ERR_INVALID_FREQUENCY) {
+  if (loraSX1262.setFrequency(433.5) == ERR_INVALID_FREQUENCY) {
     Serial.println(F("Selected frequency is invalid for this module!"));
     while (true);
   }
 
   // set bandwidth to 250 kHz
-  if (loraSX1268.setBandwidth(250.0) == ERR_INVALID_BANDWIDTH) {
+  if (loraSX1262.setBandwidth(250.0) == ERR_INVALID_BANDWIDTH) {
     Serial.println(F("Selected bandwidth is invalid for this module!"));
     while (true);
   }
 
   // set spreading factor to 10
-  if (loraSX1268.setSpreadingFactor(10) == ERR_INVALID_SPREADING_FACTOR) {
+  if (loraSX1262.setSpreadingFactor(10) == ERR_INVALID_SPREADING_FACTOR) {
     Serial.println(F("Selected spreading factor is invalid for this module!"));
     while (true);
   }
 
   // set coding rate to 6
-  if (loraSX1268.setCodingRate(6) == ERR_INVALID_CODING_RATE) {
+  if (loraSX1262.setCodingRate(6) == ERR_INVALID_CODING_RATE) {
     Serial.println(F("Selected coding rate is invalid for this module!"));
     while (true);
   }
 
   // set LoRa sync word to 0x1234
-  if (loraSX1268.setSyncWord(0x1234) != ERR_NONE) {
+  if (loraSX1262.setSyncWord(0x1234) != ERR_NONE) {
     Serial.println(F("Unable to set sync word!"));
     while (true);
   }
 
   // set output power to 10 dBm (accepted range is -17 - 22 dBm)
-  if (loraSX1268.setOutputPower(10) == ERR_INVALID_OUTPUT_POWER) {
+  if (loraSX1262.setOutputPower(10) == ERR_INVALID_OUTPUT_POWER) {
     Serial.println(F("Selected output power is invalid for this module!"));
     while (true);
   }
 
   // set over current protection limit to 80 mA (accepted range is 45 - 240 mA)
   // NOTE: set value to 0 to disable overcurrent protection
-  if (loraSX1268.setCurrentLimit(80) == ERR_INVALID_CURRENT_LIMIT) {
+  if (loraSX1262.setCurrentLimit(80) == ERR_INVALID_CURRENT_LIMIT) {
     Serial.println(F("Selected current limit is invalid for this module!"));
     while (true);
   }
 
   // set LoRa preamble length to 15 symbols (accepted range is 0 - 65535)
-  if (loraSX1268.setPreambleLength(15) == ERR_INVALID_PREAMBLE_LENGTH) {
+  if (loraSX1262.setPreambleLength(15) == ERR_INVALID_PREAMBLE_LENGTH) {
     Serial.println(F("Selected preamble length is invalid for this module!"));
     while (true);
   }
 
   // disable CRC
-  if (loraSX1268.setCRC(false) == ERR_INVALID_CRC_CONFIGURATION) {
+  if (loraSX1262.setCRC(false) == ERR_INVALID_CRC_CONFIGURATION) {
     Serial.println(F("Selected CRC is invalid for this module!"));
     while (true);
   }
 
-  // Some SX126x have TCXO (temperature compensated crystal
+  // Some SX126x modules have TCXO (temperature compensated crystal
   // oscillator). To configure TCXO reference voltage,
   // the following method can be used.
-  if (loraSX1268.setTCXO(2.4) == ERR_INVALID_TCXO_VOLTAGE) {
+  if (loraSX1262.setTCXO(2.4) == ERR_INVALID_TCXO_VOLTAGE) {
     Serial.println(F("Selected TCXO voltage is invalid for this module!"));
     while (true);
   }
diff --git a/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino b/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino
index 2b49efff..94333c17 100644
--- a/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino
+++ b/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino
@@ -8,13 +8,24 @@
     - arbitrary binary data (byte array)
 
    Other modules from SX126x family can also be used.
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// SX1262 module is in slot A on the shield
-SX1262 lora = RadioShield.ModuleA;
+// SX1262 has the following connections:
+// NSS pin:   10
+// DIO1 pin:  2
+// DIO2 pin:  3
+// BUSY pin:  9
+SX1262 lora = new Module(10, 2, 3, 9);
+
+ // or using RadioShield
+ // https://github.com/jgromes/RadioShield
+ //SX1262 lora = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
@@ -94,6 +105,11 @@ void loop() {
     // timeout occured while transmitting packet
     Serial.println(F(" timeout!"));
 
+  } else {
+    // some other error occurred
+    Serial.print(F("failed, code "));
+    Serial.println(state);
+
   }
 
   // wait for a second before transmitting again
diff --git a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino
index 1c4e0508..04151894 100644
--- a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino
+++ b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino
@@ -9,13 +9,20 @@
     - arbitrary binary data (byte array)
 
    Other modules from SX126x family can also be used.
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// SX1262 module is in slot A on the shield
-SX1262 lora = RadioShield.ModuleA;
+// SX1262 has the following connections:
+// NSS pin:   10
+// DIO1 pin:  2
+// DIO2 pin:  3
+// BUSY pin:  9
+SX1262 lora = new Module(10, 2, 3, 9);
 
 void setup() {
   Serial.begin(9600);

From 63ee5f0a07a6543f6f03da6da846b2ea10ec4832 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 2 Jun 2019 15:03:33 +0200
Subject: [PATCH 023/106] [SX127x] Updated examples

---
 .../SX127x_Channel_Activity_Detection.ino     | 14 +++++++++++--
 .../SX127x_FSK_Modem/SX127x_FSK_Modem.ino     | 14 +++++++++++--
 .../SX127x/SX127x_Receive/SX127x_Receive.ino  | 19 ++++++++++++++++--
 .../SX127x_Receive_Interrupt.ino              | 19 ++++++++++++++++--
 .../SX127x_Settings/SX127x_Settings.ino       | 20 +++++++++++--------
 .../SX127x_Transmit/SX127x_Transmit.ino       | 19 ++++++++++++++++--
 .../SX127x_Transmit_Interrupt.ino             | 16 ++++++++++++---
 7 files changed, 100 insertions(+), 21 deletions(-)

diff --git a/examples/SX127x/SX127x_Channel_Activity_Detection/SX127x_Channel_Activity_Detection.ino b/examples/SX127x/SX127x_Channel_Activity_Detection/SX127x_Channel_Activity_Detection.ino
index 5bb9cf80..cf54ed75 100644
--- a/examples/SX127x/SX127x_Channel_Activity_Detection/SX127x_Channel_Activity_Detection.ino
+++ b/examples/SX127x/SX127x_Channel_Activity_Detection/SX127x_Channel_Activity_Detection.ino
@@ -8,13 +8,23 @@
    receiving a message.
 
    Other modules from SX127x/RFM9x family can also be used.
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// SX1278 module is in slot A on the shield
-SX1278 lora = RadioShield.ModuleA;
+// SX1278 has the following connections:
+// NSS pin:   10
+// DIO0 pin:  2
+// DIO1 pin:  3
+SX1278 lora = new Module(10, 2, 3);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//SX1278 lora = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
diff --git a/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino b/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino
index b2568aee..1c8cd1da 100644
--- a/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino
+++ b/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino
@@ -8,13 +8,23 @@
          Instead, modify the other examples to use FSK
          modem and use the appropriate configuration
          methods.
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// SX1278 module is in slot A on the shield
-SX1278 fsk = RadioShield.ModuleA;
+// SX1278 has the following connections:
+// NSS pin:   10
+// DIO0 pin:  2
+// DIO1 pin:  3
+SX1278 fsk = new Module(10, 2, 3);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//SX1278 fsk = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
diff --git a/examples/SX127x/SX127x_Receive/SX127x_Receive.ino b/examples/SX127x/SX127x_Receive/SX127x_Receive.ino
index 5bb86650..18e4ab48 100644
--- a/examples/SX127x/SX127x_Receive/SX127x_Receive.ino
+++ b/examples/SX127x/SX127x_Receive/SX127x_Receive.ino
@@ -12,13 +12,23 @@
     - preamble length
 
    Other modules from SX127x/RFM9x family can also be used.
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// SX1278 module is in slot A on the shield
-SX1278 lora = RadioShield.ModuleA;
+// SX1278 has the following connections:
+// NSS pin:   10
+// DIO0 pin:  2
+// DIO1 pin:  3
+SX1278 lora = new Module(10, 2, 3);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//SX1278 lora = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
@@ -94,5 +104,10 @@ void loop() {
     // packet was received, but is malformed
     Serial.println(F("CRC error!"));
 
+  } else {
+    // some other error occurred
+    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 6cea5147..c1cce7c4 100644
--- a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino
+++ b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino
@@ -13,13 +13,23 @@
     - sync word
 
    Other modules from SX127x/RFM9x family can also be used.
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// SX1278 module is in slot A on the shield
-SX1278 lora = RadioShield.ModuleA;
+// SX1278 has the following connections:
+// NSS pin:   10
+// DIO0 pin:  2
+// DIO1 pin:  3
+SX1278 lora = new Module(10, 2, 3);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//SX1278 lora = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
@@ -136,6 +146,11 @@ void loop() {
       // packet was received, but is malformed
       Serial.println(F("CRC error!"));
 
+    } else {
+      // some other error occurred
+      Serial.print(F("failed, code "));
+      Serial.println(state);
+
     }
 
     // we're ready to receive more packets,
diff --git a/examples/SX127x/SX127x_Settings/SX127x_Settings.ino b/examples/SX127x/SX127x_Settings/SX127x_Settings.ino
index 3c48799a..e64256fc 100644
--- a/examples/SX127x/SX127x_Settings/SX127x_Settings.ino
+++ b/examples/SX127x/SX127x_Settings/SX127x_Settings.ino
@@ -12,20 +12,24 @@
     - output power during transmission
 
     Other modules from SX127x/RFM9x family can also be used.
+
+    For full API reference, see the GitHub Pages
+    https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// SX1278 module is in slot A on the shield
-SX1278 loraSX1278 = RadioShield.ModuleA;
+// SX1278 has the following connections:
+// NSS pin:   10
+// DIO1 pin:  2
+// DIO2 pin:  3
+// BUSY pin:  9
+SX1262 loraSX1278 = new Module(10, 2, 3, 9);
 
-// if you're not using RadioShield, you can specify
-// the connection yourself
-// NSS pin:   6
-// DIO1 pin:  4
-// DIO2 pin:  5
-SX1272 loraSX1272 = new Module(6, 4, 5);
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+SX1268 loraSX1272 = RadioShield.ModuleB;
 
 void setup() {
   Serial.begin(9600);
diff --git a/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino b/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino
index 9e9d2457..2573a41d 100644
--- a/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino
+++ b/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino
@@ -8,13 +8,23 @@
     - arbitrary binary data (byte array)
 
    Other modules from SX127x/RFM9x family can also be used.
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// SX1278 module is in slot A on the shield
-SX1278 lora = RadioShield.ModuleA;
+// SX1278 has the following connections:
+// NSS pin:   10
+// DIO0 pin:  2
+// DIO1 pin:  3
+SX1278 lora = new Module(10, 2, 3);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//SX1278 lora = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
@@ -73,6 +83,11 @@ void loop() {
     // timeout occured while transmitting packet
     Serial.println(F(" timeout!"));
 
+  } else {
+    // some other error occurred
+    Serial.print(F("failed, code "));
+    Serial.println(state);
+
   }
 
   // wait for a second before transmitting again
diff --git a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino
index 0d60aea7..a0cc1f56 100644
--- a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino
+++ b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino
@@ -9,13 +9,23 @@
     - arbitrary binary data (byte array)
 
    Other modules from SX127x/RFM9x family can also be used.
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// SX1278 module is in slot A on the shield
-SX1278 lora = RadioShield.ModuleA;
+// SX1278 has the following connections:
+// NSS pin:   10
+// DIO0 pin:  2
+// DIO1 pin:  3
+SX1278 lora = new Module(10, 2, 3);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//SX1278 lora = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
@@ -75,7 +85,7 @@ void setFlag(void) {
 void loop() {
   // check if the previous transmission finished
   if(transmittedFlag) {
-    Serial.println(F("[SX1278] Packet transmission finished!"));
+    Serial.println(F("packet transmission finished!"));
 
     // wait one second before next transmission
     delay(1000);

From 6e7c28181e734d19e4333448ba21d092ce48c9fd Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 2 Jun 2019 15:03:40 +0200
Subject: [PATCH 024/106] [XBee] Updated examples

---
 examples/XBee/XBee_Receive/XBee_Receive.ino        | 14 ++++++++++++--
 examples/XBee/XBee_Transmit/XBee_Transmit.ino      | 14 ++++++++++++--
 .../XBee/XBee_Transparent/XBee_Transparent.ino     | 14 ++++++++++++--
 3 files changed, 36 insertions(+), 6 deletions(-)

diff --git a/examples/XBee/XBee_Receive/XBee_Receive.ino b/examples/XBee/XBee_Receive/XBee_Receive.ino
index b4e2a700..41921283 100644
--- a/examples/XBee/XBee_Receive/XBee_Receive.ino
+++ b/examples/XBee/XBee_Receive/XBee_Receive.ino
@@ -6,13 +6,23 @@
 
    IMPORTANT: Before uploading this example, make sure that the XBee module
    is running API ROUTER/ENDPOINT firmware!
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// XBee module is in slot A on the shield
-XBee bee = RadioShield.ModuleA;
+// XBee has the following connections:
+// TX pin:    9
+// RX pin:    8
+// RESET pin: 3
+XBee bee = new Module(9, 8);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//XBee bee = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
diff --git a/examples/XBee/XBee_Transmit/XBee_Transmit.ino b/examples/XBee/XBee_Transmit/XBee_Transmit.ino
index 8d7c9fc6..1123015d 100644
--- a/examples/XBee/XBee_Transmit/XBee_Transmit.ino
+++ b/examples/XBee/XBee_Transmit/XBee_Transmit.ino
@@ -6,13 +6,23 @@
 
    IMPORTANT: Before uploading this example, make sure that the XBee module
    is running API COORDINATOR firmware!
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// XBee module is in slot A on the shield
-XBee bee = RadioShield.ModuleA;
+// XBee has the following connections:
+// TX pin:    9
+// RX pin:    8
+// RESET pin: 3
+XBee bee = new Module(9, 8);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//XBee bee = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
diff --git a/examples/XBee/XBee_Transparent/XBee_Transparent.ino b/examples/XBee/XBee_Transparent/XBee_Transparent.ino
index 0eff8881..d8bef65c 100644
--- a/examples/XBee/XBee_Transparent/XBee_Transparent.ino
+++ b/examples/XBee/XBee_Transparent/XBee_Transparent.ino
@@ -8,13 +8,23 @@
 
    IMPORTANT: Before uploading this example, make sure that the XBee modules
    are running AT COORDINATOR and AT ROUTER firmware!
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// XBee module is in slot A on the shield
-XBeeSerial bee = RadioShield.ModuleA;
+// XBee has the following connections:
+// TX pin:    9
+// RX pin:    8
+// RESET pin: 3
+XBee bee = new Module(9, 8);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//XBee bee = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);

From 036bc02bad39377037d4648f24fabf6c8144267d Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 2 Jun 2019 15:03:53 +0200
Subject: [PATCH 025/106] [nRF24] Updated examples

---
 .../nRF24/nRF24_Receive/nRF24_Receive.ino     | 21 ++++++++++++++++---
 .../nRF24/nRF24_Transmit/nRF24_Transmit.ino   | 19 +++++++++++++++--
 2 files changed, 35 insertions(+), 5 deletions(-)

diff --git a/examples/nRF24/nRF24_Receive/nRF24_Receive.ino b/examples/nRF24/nRF24_Receive/nRF24_Receive.ino
index 1ea09fb9..785ce037 100644
--- a/examples/nRF24/nRF24_Receive/nRF24_Receive.ino
+++ b/examples/nRF24/nRF24_Receive/nRF24_Receive.ino
@@ -8,13 +8,23 @@
     - data rate
     - transmit pipe on transmitter must match receive pipe
       on receiver
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// nRF24 is in slot A on the shield
-nRF24 nrf = RadioShield.ModuleA;
+// nRF24 has the following connections:
+// NSS pin:   10
+// CE pin:    2
+// IRQ pin:   3
+nRF24 nrf = new Module(10, 2, 3);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//nRF24 nrf = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
@@ -35,7 +45,7 @@ void setup() {
   }
 
   // set receive pipe 0 address
-  // NOTE: address width in bytes MUST be equal to the 
+  // NOTE: address width in bytes MUST be equal to the
   //       width set in begin() or setAddressWidth()
   //       methods (5 by default)
   Serial.print(F("[nRF24] Setting address for receive pipe 0 ... "));
@@ -78,5 +88,10 @@ void loop() {
     // timeout occurred while waiting for a packet
     Serial.println(F("timeout!"));
 
+  } else {
+    // some other error occurred
+    Serial.print(F("failed, code "));
+    Serial.println(state);
+
   }
 }
diff --git a/examples/nRF24/nRF24_Transmit/nRF24_Transmit.ino b/examples/nRF24/nRF24_Transmit/nRF24_Transmit.ino
index 304ab6b1..d6c19f05 100644
--- a/examples/nRF24/nRF24_Transmit/nRF24_Transmit.ino
+++ b/examples/nRF24/nRF24_Transmit/nRF24_Transmit.ino
@@ -8,13 +8,23 @@
     - arbitrary binary data (byte array)
 
    Packet delivery is automatically acknowledged by the receiver.
+
+   For full API reference, see the GitHub Pages
+   https://jgromes.github.io/RadioLib/
 */
 
 // include the library
 #include <RadioLib.h>
 
-// nRF24 is in slot A on the shield
-nRF24 nrf = RadioShield.ModuleA;
+// nRF24 has the following connections:
+// NSS pin:   10
+// CE pin:    2
+// IRQ pin:   3
+nRF24 nrf = new Module(10, 2, 3);
+
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//nRF24 nrf = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);
@@ -74,6 +84,11 @@ void loop() {
     // timed out while transmitting
     Serial.println(F("timeout!"));
 
+  } else {
+    // some other error occurred
+    Serial.print(F("failed, code "));
+    Serial.println(state);
+
   }
 
   // wait for a second before transmitting again

From b1196bf8d859ae4d46d0bded476770d6c080bf17 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 2 Jun 2019 15:11:55 +0200
Subject: [PATCH 026/106] [SX127x] Fixed incorrect module types

---
 examples/SX127x/SX127x_Settings/SX127x_Settings.ino | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/examples/SX127x/SX127x_Settings/SX127x_Settings.ino b/examples/SX127x/SX127x_Settings/SX127x_Settings.ino
index e64256fc..e3a834a6 100644
--- a/examples/SX127x/SX127x_Settings/SX127x_Settings.ino
+++ b/examples/SX127x/SX127x_Settings/SX127x_Settings.ino
@@ -25,11 +25,11 @@
 // DIO1 pin:  2
 // DIO2 pin:  3
 // BUSY pin:  9
-SX1262 loraSX1278 = new Module(10, 2, 3, 9);
+SX1278 loraSX1278 = new Module(10, 2, 3, 9);
 
 // or using RadioShield
 // https://github.com/jgromes/RadioShield
-SX1268 loraSX1272 = RadioShield.ModuleB;
+SX1272 loraSX1272 = RadioShield.ModuleB;
 
 void setup() {
   Serial.begin(9600);

From 0d1e196d1864497a1355857845f61ac9c5dc6887 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 2 Jun 2019 15:15:22 +0200
Subject: [PATCH 027/106] [SX126x] Fixed incorect indentation

---
 examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino b/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino
index 94333c17..bdd9d929 100644
--- a/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino
+++ b/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino
@@ -23,9 +23,9 @@
 // BUSY pin:  9
 SX1262 lora = new Module(10, 2, 3, 9);
 
- // or using RadioShield
- // https://github.com/jgromes/RadioShield
- //SX1262 lora = RadioShield.ModuleA;
+// or using RadioShield
+// https://github.com/jgromes/RadioShield
+//SX1262 lora = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);

From 8cc9b175ad1b5d97dc7303797fa2caf97e5a3913 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 2 Jun 2019 15:20:15 +0200
Subject: [PATCH 028/106] [XBee] Fixed incorrect module types

---
 examples/XBee/XBee_Transparent/XBee_Transparent.ino | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/examples/XBee/XBee_Transparent/XBee_Transparent.ino b/examples/XBee/XBee_Transparent/XBee_Transparent.ino
index d8bef65c..deb29061 100644
--- a/examples/XBee/XBee_Transparent/XBee_Transparent.ino
+++ b/examples/XBee/XBee_Transparent/XBee_Transparent.ino
@@ -20,11 +20,11 @@
 // TX pin:    9
 // RX pin:    8
 // RESET pin: 3
-XBee bee = new Module(9, 8);
+XBeeSerial bee = new Module(9, 8);
 
 // or using RadioShield
 // https://github.com/jgromes/RadioShield
-//XBee bee = RadioShield.ModuleA;
+//XBeeSerial bee = RadioShield.ModuleA;
 
 void setup() {
   Serial.begin(9600);

From ac30ca652f12b3baa8c2797c371eb50dd8ed54e0 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 2 Jun 2019 16:22:57 +0200
Subject: [PATCH 029/106] [SX127x] Sync with LoRaLib 8.0.6

---
 src/modules/SX1272.cpp |  40 +++++++------
 src/modules/SX1272.h   | 127 ++++++++++++++++++++---------------------
 src/modules/SX1278.cpp |  40 +++++++------
 src/modules/SX1278.h   | 127 ++++++++++++++++++++---------------------
 src/modules/SX127x.cpp |   3 +-
 5 files changed, 171 insertions(+), 166 deletions(-)

diff --git a/src/modules/SX1272.cpp b/src/modules/SX1272.cpp
index 4856b755..b6cbcddc 100644
--- a/src/modules/SX1272.cpp
+++ b/src/modules/SX1272.cpp
@@ -122,6 +122,17 @@ int16_t SX1272::setBandwidth(float bw) {
   int16_t state = SX1272::setBandwidthRaw(newBandwidth);
   if(state == ERR_NONE) {
     SX127x::_bw = bw;
+
+    // calculate symbol length and set low data rate optimization, if needed
+    float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw;
+    DEBUG_PRINT("Symbol length: ");
+    DEBUG_PRINT(symbolLength);
+    DEBUG_PRINTLN(" ms");
+    if(symbolLength >= 16.0) {
+      state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_ON, 0, 0);
+    } else {
+      state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0);
+    }
   }
   return(state);
 }
@@ -165,6 +176,17 @@ int16_t SX1272::setSpreadingFactor(uint8_t sf) {
   int16_t state = SX1272::setSpreadingFactorRaw(newSpreadingFactor);
   if(state == ERR_NONE) {
     SX127x::_sf = sf;
+
+    // calculate symbol length and set low data rate optimization, if needed
+    float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw;
+    DEBUG_PRINT("Symbol length: ");
+    DEBUG_PRINT(symbolLength);
+    DEBUG_PRINTLN(" ms");
+    if(symbolLength >= 16.0) {
+      state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_ON, 0, 0);
+    } else {
+      state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0);
+    }
   }
   return(state);
 }
@@ -392,24 +414,6 @@ int16_t SX1272::setCodingRateRaw(uint8_t newCodingRate) {
   return(state);
 }
 
-int16_t SX1272::config() {
-  // configure common registers
-  int16_t state = SX127x::config();
-  if(state != ERR_NONE) {
-    return(state);
-  }
-
-  // calculate symbol length and set low data rate optimization, if needed
-  uint16_t base = 1;
-  float symbolLength = (float)(base << _sf) / (float)_bw;
-  if(symbolLength >= 16.0) {
-    state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_ON, 0, 0);
-  } else {
-    state = _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_LOW_DATA_RATE_OPT_OFF, 0, 0);
-  }
-  return(state);
-}
-
 int16_t SX1272::configFSK() {
   // configure common registers
   int16_t state = SX127x::configFSK();
diff --git a/src/modules/SX1272.h b/src/modules/SX1272.h
index 38a39432..aec213c8 100644
--- a/src/modules/SX1272.h
+++ b/src/modules/SX1272.h
@@ -86,178 +86,177 @@
 /*!
   \class SX1272
 
-  \brief Derived class for %SX1272 modules. Also used as base class for SX1273. 
+  \brief Derived class for %SX1272 modules. Also used as base class for SX1273.
   Both modules use the same basic hardware and only differ in parameter ranges.
 */
 class SX1272: public SX127x {
   public:
-  
+
     // constructor
-    
+
     /*!
       \brief Default constructor. Called from Arduino sketch when creating new LoRa instance.
-      
+
       \param mod Instance of Module that will be used to communicate with the %LoRa chip.
     */
     SX1272(Module* mod);
-    
+
     // basic methods
-    
+
     /*!
       \brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module.
-      
+
       \param freq Carrier frequency in MHz. Allowed values range from 860.0 MHz to 1020.0 MHz.
-      
+
       \param bw %LoRa link bandwidth in kHz. Allowed values are 125, 250 and 500 kHz.
-      
+
       \param sf %LoRa link spreading factor. Allowed values range from 6 to 12.
-      
+
       \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8.
-      
+
       \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks.
-      
+
       \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm.
-      
-      \param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA. 
+
+      \param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
       Set to 0 to disable OCP (not recommended).
-      
-      \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. 
+
+      \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number.
       Allowed values range from 6 to 65535.
-      
+
       \param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain.
       Set to 0 to enable automatic gain control (recommended).
-      
+
       \returns \ref status_codes
     */
     int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 17, uint8_t currentLimit = 100, uint16_t preambleLength = 8, uint8_t gain = 0);
-    
+
     /*!
       \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module.
-      
+
       \param freq Carrier frequency in MHz. Allowed values range from 860.0 MHz to 1020.0 MHz.
-      
+
       \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 1.2 to 300.0 kbps.
-      
-      \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.6 to 200.0 kHz. 
+
+      \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.6 to 200.0 kHz.
       Note that the allowed range changes based on bit rate setting, so that the condition FreqDev + BitRate/2 <= 250 kHz is always met.
-      
+
       \param rxBw Receiver bandwidth in kHz. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, 20.8, 25, 31.3, 41.7, 50, 62.5, 83.3, 100, 125, 166.7, 200 and 250 kHz.
-      
+
       \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm.
-      
-      \param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA. 
+
+      \param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
       Set to 0 to disable OCP (not recommended).
-      
+
       \param enableOOK Use OOK modulation instead of FSK.
-      
+
       \returns \ref status_codes
     */
     int16_t beginFSK(float freq = 915.0, float br = 48.0, float rxBw = 125.0, float freqDev = 50.0, int8_t power = 13, uint8_t currentLimit = 100, bool enableOOK = false);
-    
+
     // configuration methods
-    
+
     /*!
       \brief Sets carrier frequency. Allowed values range from 860.0 MHz to 1020.0 MHz.
-      
+
       \param freq Carrier frequency to be set in MHz.
-      
+
       \returns \ref status_codes
     */
     int16_t setFrequency(float freq);
-    
+
     /*!
       \brief Sets %LoRa link bandwidth. Allowed values are 125, 250 and 500 kHz. Only available in %LoRa mode.
-      
+
       \param bw %LoRa link bandwidth to be set in kHz.
-      
+
       \returns \ref status_codes
     */
     int16_t setBandwidth(float bw);
-    
+
     /*!
       \brief Sets %LoRa link spreading factor. Allowed values range from 6 to 12. Only available in %LoRa mode.
-      
+
       \param sf %LoRa link spreading factor to be set.
-      
+
       \returns \ref status_codes
     */
     int16_t setSpreadingFactor(uint8_t sf);
-    
+
     /*!
       \brief Sets %LoRa link coding rate denominator. Allowed values range from 5 to 8. Only available in %LoRa mode.
-      
+
       \param cr %LoRa link coding rate denominator to be set.
-      
+
       \returns \ref status_codes
     */
     int16_t setCodingRate(uint8_t cr);
-    
+
     /*!
       \brief Sets transmission output power. Allowed values range from 2 to 17 dBm.
-      
+
       \param power Transmission output power in dBm.
-      
+
       \returns \ref status_codes
     */
     int16_t setOutputPower(int8_t power);
-    
+
     /*!
       \brief Sets gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain.
       Set to 0 to enable automatic gain control (recommended). Only available in %LoRa mode.
-      
+
       \param gain Gain of receiver LNA (low-noise amplifier) to be set.
-      
+
       \returns \ref status_codes
     */
     int16_t setGain(uint8_t gain);
-    
+
     /*!
-      \brief Sets Gaussian filter bandwidth-time product that will be used for data shaping. 
+      \brief Sets Gaussian filter bandwidth-time product that will be used for data shaping.
       Allowed values are 0.3, 0.5 or 1.0. Set to 0 to disable data shaping. Only available in FSK mode with FSK modulation.
-      
+
       \param sh Gaussian shaping bandwidth-time product that will be used for data shaping
-      
+
       \returns \ref status_codes
     */
     int16_t setDataShaping(float sh);
-    
+
     /*!
-      \brief Sets filter cutoff frequency that will be used for data shaping. 
+      \brief Sets filter cutoff frequency that will be used for data shaping.
       Allowed values are 1 for frequency equal to bit rate and 2 for frequency equal to 2x bit rate. Set to 0 to disable data shaping.
       Only available in FSK mode with OOK modulation.
-      
+
       \param sh Cutoff frequency that will be used for data shaping
-      
+
       \returns \ref status_codes
     */
     int16_t setDataShapingOOK(uint8_t sh);
-    
+
     /*!
       \brief Gets recorded signal strength indicator of the latest received packet.
-      
+
       \returns Last packet recorded signal strength indicator (RSSI).
     */
     int8_t getRSSI();
-    
+
     /*!
       \brief Enables/disables CRC check of received packets.
-      
+
       \param enableCRC Enable (true) or disable (false) CRC.
-      
+
       \returns \ref status_codes
     */
     int16_t setCRC(bool enableCRC);
-  
+
   protected:
     int16_t setBandwidthRaw(uint8_t newBandwidth);
     int16_t setSpreadingFactorRaw(uint8_t newSpreadingFactor);
     int16_t setCodingRateRaw(uint8_t newCodingRate);
     
-    int16_t config();
     int16_t configFSK();
 
   private:
-    
+
 };
 
 #endif
diff --git a/src/modules/SX1278.cpp b/src/modules/SX1278.cpp
index aa01d52d..36ccef39 100644
--- a/src/modules/SX1278.cpp
+++ b/src/modules/SX1278.cpp
@@ -192,6 +192,17 @@ int16_t SX1278::setBandwidth(float bw) {
   int16_t state = SX1278::setBandwidthRaw(newBandwidth);
   if(state == ERR_NONE) {
     SX127x::_bw = bw;
+
+    // calculate symbol length and set low data rate optimization, if needed
+    float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw;
+    DEBUG_PRINT("Symbol length: ");
+    DEBUG_PRINT(symbolLength);
+    DEBUG_PRINTLN(" ms");
+    if(symbolLength >= 16.0) {
+      state = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_ON, 3, 3);
+    } else {
+      state = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3);
+    }
   }
   return(state);
 }
@@ -235,6 +246,17 @@ int16_t SX1278::setSpreadingFactor(uint8_t sf) {
   int16_t state = SX1278::setSpreadingFactorRaw(newSpreadingFactor);
   if(state == ERR_NONE) {
     SX127x::_sf = sf;
+
+    // calculate symbol length and set low data rate optimization, if needed
+    float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw;
+    DEBUG_PRINT("Symbol length: ");
+    DEBUG_PRINT(symbolLength);
+    DEBUG_PRINTLN(" ms");
+    if(symbolLength >= 16.0) {
+      state = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_ON, 3, 3);
+    } else {
+      state = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3);
+    }
   }
   return(state);
 }
@@ -468,24 +490,6 @@ int16_t SX1278::setCodingRateRaw(uint8_t newCodingRate) {
   return(state);
 }
 
-int16_t SX1278::config() {
-  // configure common registers
-  int16_t state = SX127x::config();
-  if(state != ERR_NONE) {
-    return(state);
-  }
-
-  // calculate symbol length and set low data rate optimization, if needed
-  uint16_t base = 1;
-  float symbolLength = (float)(base << _sf) / (float)_bw;
-  if(symbolLength >= 16.0) {
-    state = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_ON, 0, 0);
-  } else {
-    state = _mod->SPIsetRegValue(SX1278_REG_MODEM_CONFIG_3, SX1278_LOW_DATA_RATE_OPT_OFF, 0, 0);
-  }
-  return(state);
-}
-
 int16_t SX1278::configFSK() {
   // configure common registers
   int16_t state = SX127x::configFSK();
diff --git a/src/modules/SX1278.h b/src/modules/SX1278.h
index 5273175b..0786b45f 100644
--- a/src/modules/SX1278.h
+++ b/src/modules/SX1278.h
@@ -100,173 +100,172 @@
 */
 class SX1278: public SX127x {
   public:
-  
+
     // constructor
-    
+
     /*!
       \brief Default constructor. Called from Arduino sketch when creating new LoRa instance.
-      
+
       \param mod Instance of Module that will be used to communicate with the %LoRa chip.
     */
     SX1278(Module* mod);
-    
+
     // basic methods
-    
+
     /*!
       \brief %LoRa modem initialization method. Must be called at least once from Arduino sketch to initialize the module.
-      
+
       \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 525.0 MHz.
-      
+
       \param bw %LoRa link bandwidth in kHz. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz.
-      
+
       \param sf %LoRa link spreading factor. Allowed values range from 6 to 12.
-      
+
       \param cr %LoRa link coding rate denominator. Allowed values range from 5 to 8.
-      
+
       \param syncWord %LoRa sync word. Can be used to distinguish different networks. Note that value 0x34 is reserved for LoRaWAN networks.
-      
+
       \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm.
-      
-      \param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA. 
+
+      \param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
       Set to 0 to disable OCP (not recommended).
-      
-      \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number. 
+
+      \param preambleLength Length of %LoRa transmission preamble in symbols. The actual preamble length is 4.25 symbols longer than the set number.
       Allowed values range from 6 to 65535.
-      
+
       \param gain Gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain.
       Set to 0 to enable automatic gain control (recommended).
-      
+
       \returns \ref status_codes
     */
     int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 17, uint8_t currentLimit = 100, uint16_t preambleLength = 8, uint8_t gain = 0);
-    
+
     /*!
       \brief FSK modem initialization method. Must be called at least once from Arduino sketch to initialize the module.
-      
+
       \param freq Carrier frequency in MHz. Allowed values range from 137.0 MHz to 525.0 MHz.
-      
+
       \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 1.2 to 300.0 kbps.
-      
-      \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.6 to 200.0 kHz. 
+
+      \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.6 to 200.0 kHz.
       Note that the allowed range changes based on bit rate setting, so that the condition FreqDev + BitRate/2 <= 250 kHz is always met.
-      
+
       \param rxBw Receiver bandwidth in kHz. Allowed values are 2.6, 3.1, 3.9, 5.2, 6.3, 7.8, 10.4, 12.5, 15.6, 20.8, 25, 31.3, 41.7, 50, 62.5, 83.3, 100, 125, 166.7, 200 and 250 kHz.
-      
+
       \param power Transmission output power in dBm. Allowed values range from 2 to 17 dBm.
-      
-      \param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA. 
+
+      \param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
       Set to 0 to disable OCP (not recommended).
-      
+
       \param enableOOK Use OOK modulation instead of FSK.
-      
+
       \returns \ref status_codes
     */
     int16_t beginFSK(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 125.0, int8_t power = 13, uint8_t currentLimit = 100, bool enableOOK = false);
-    
+
     // configuration methods
-    
+
     /*!
       \brief Sets carrier frequency. Allowed values range from 137.0 MHz to 525.0 MHz.
-      
+
       \param freq Carrier frequency to be set in MHz.
-      
+
       \returns \ref status_codes
     */
     int16_t setFrequency(float freq);
-    
+
     /*!
       \brief Sets %LoRa link bandwidth. Allowed values are 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125, 250 and 500 kHz. Only available in %LoRa mode.
-      
+
       \param bw %LoRa link bandwidth to be set in kHz.
-      
+
       \returns \ref status_codes
     */
     int16_t setBandwidth(float bw);
-    
+
     /*!
       \brief Sets %LoRa link spreading factor. Allowed values range from 6 to 12. Only available in %LoRa mode.
-      
+
       \param sf %LoRa link spreading factor to be set.
-      
+
       \returns \ref status_codes
     */
     int16_t setSpreadingFactor(uint8_t sf);
-    
+
     /*!
       \brief Sets %LoRa link coding rate denominator. Allowed values range from 5 to 8. Only available in %LoRa mode.
-      
+
       \param cr %LoRa link coding rate denominator to be set.
-      
+
       \returns \ref status_codes
     */
     int16_t setCodingRate(uint8_t cr);
-    
+
     /*!
       \brief Sets transmission output power. Allowed values range from 2 to 17 dBm.
-      
+
       \param power Transmission output power in dBm.
-      
+
       \returns \ref status_codes
     */
     int16_t setOutputPower(int8_t power);
-    
+
     /*!
       \brief Sets gain of receiver LNA (low-noise amplifier). Can be set to any integer in range 1 to 6 where 1 is the highest gain.
       Set to 0 to enable automatic gain control (recommended). Only available in %LoRa mode.
-      
+
       \param gain Gain of receiver LNA (low-noise amplifier) to be set.
-      
+
       \returns \ref status_codes
     */
     int16_t setGain(uint8_t gain);
-    
+
     /*!
-      \brief Sets Gaussian filter bandwidth-time product that will be used for data shaping. 
+      \brief Sets Gaussian filter bandwidth-time product that will be used for data shaping.
       Allowed values are 0.3, 0.5 or 1.0. Set to 0 to disable data shaping. Only available in FSK mode with FSK modulation.
-      
+
       \param sh Gaussian shaping bandwidth-time product that will be used for data shaping
-      
+
       \returns \ref status_codes
     */
     int16_t setDataShaping(float sh);
-    
+
     /*!
-      \brief Sets filter cutoff frequency that will be used for data shaping. 
+      \brief Sets filter cutoff frequency that will be used for data shaping.
       Allowed values are 1 for frequency equal to bit rate and 2 for frequency equal to 2x bit rate. Set to 0 to disable data shaping.
       Only available in FSK mode with OOK modulation.
-      
+
       \param sh Cutoff frequency that will be used for data shaping
-      
+
       \returns \ref status_codes
     */
     int16_t setDataShapingOOK(uint8_t sh);
-    
+
     /*!
       \brief Gets recorded signal strength indicator of the latest received packet.
-      
+
       \returns Last packet recorded signal strength indicator (RSSI).
     */
     int8_t getRSSI();
-    
+
     /*!
       \brief Enables/disables CRC check of received packets.
-      
+
       \param enableCRC Enable (true) or disable (false) CRC.
-      
+
       \returns \ref status_codes
     */
     int16_t setCRC(bool enableCRC);
-  
+
   protected:
     int16_t setBandwidthRaw(uint8_t newBandwidth);
     int16_t setSpreadingFactorRaw(uint8_t newSpreadingFactor);
     int16_t setCodingRateRaw(uint8_t newCodingRate);
     
-    int16_t config();
     int16_t configFSK();
-    
+
   private:
-  
+
 };
 
 #endif
diff --git a/src/modules/SX127x.cpp b/src/modules/SX127x.cpp
index 8ce06e47..ce5a84dc 100644
--- a/src/modules/SX127x.cpp
+++ b/src/modules/SX127x.cpp
@@ -121,8 +121,7 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) {
   int16_t modem = getActiveModem();
   if(modem == SX127X_LORA) {
     // calculate timeout (150 % of expected time-one-air)
-    uint16_t base = 1;
-    float symbolLength = (float)(base << _sf) / (float)_bw;
+    float symbolLength = (float)(uint32_t(1) <<_sf) / (float)_bw;
     float de = 0;
     if(symbolLength >= 16.0) {
       de = 1;

From ba5522981d4affd613ad3cda982f31ec6f7dd77a Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 2 Jun 2019 16:23:07 +0200
Subject: [PATCH 030/106] [SX126x] Added debug output

---
 src/modules/SX126x.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/modules/SX126x.cpp b/src/modules/SX126x.cpp
index 2118f00d..ca18bbc8 100644
--- a/src/modules/SX126x.cpp
+++ b/src/modules/SX126x.cpp
@@ -983,6 +983,9 @@ int16_t SX126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t
   // calculate symbol length and enable low data rate optimization, if needed
   if(ldro == 0xFF) {
     float symbolLength = (float)(uint32_t(1) << _sf) / (float)_bwKhz;
+    DEBUG_PRINT("Symbol length: ");
+    DEBUG_PRINT(symbolLength);
+    DEBUG_PRINTLN(" ms");
     if(symbolLength >= 16.0) {
       _ldro = SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON;
     } else {

From 025d6d71a7c4d8aa92c12da79ffc679789e50a05 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 2 Jun 2019 16:23:40 +0200
Subject: [PATCH 031/106] [SX126x] Fixed serial output format

---
 examples/SX127x/SX127x_Receive/SX127x_Receive.ino         | 8 ++++----
 .../SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino | 4 ++--
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/examples/SX127x/SX127x_Receive/SX127x_Receive.ino b/examples/SX127x/SX127x_Receive/SX127x_Receive.ino
index 18e4ab48..9aed5e3a 100644
--- a/examples/SX127x/SX127x_Receive/SX127x_Receive.ino
+++ b/examples/SX127x/SX127x_Receive/SX127x_Receive.ino
@@ -75,24 +75,24 @@ void loop() {
     Serial.println(F("success!"));
 
     // print the data of the packet
-    Serial.print(F("[SX1278] Data:\t\t"));
+    Serial.print(F("[SX1278] Data:\t\t\t"));
     Serial.println(str);
 
     // print the RSSI (Received Signal Strength Indicator)
     // of the last received packet
-    Serial.print(F("[SX1278] RSSI:\t\t"));
+    Serial.print(F("[SX1278] RSSI:\t\t\t"));
     Serial.print(lora.getRSSI());
     Serial.println(F(" dBm"));
 
     // print the SNR (Signal-to-Noise Ratio)
     // of the last received packet
-    Serial.print(F("[SX1278] SNR:\t\t"));
+    Serial.print(F("[SX1278] SNR:\t\t\t"));
     Serial.print(lora.getSNR());
     Serial.println(F(" dBm"));
 
     // print frequency error
     // of the last received packet
-    Serial.print(F("Frequency error:\t"));
+    Serial.print(F("[SX1278] Frequency error:\t"));
     Serial.print(lora.getFrequencyError());
     Serial.println(F(" Hz"));
 
diff --git a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino
index c1cce7c4..10c74b09 100644
--- a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino
+++ b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino
@@ -144,11 +144,11 @@ void loop() {
 
     } else if (state == ERR_CRC_MISMATCH) {
       // packet was received, but is malformed
-      Serial.println(F("CRC error!"));
+      Serial.println(F("[SX1278] CRC error!"));
 
     } else {
       // some other error occurred
-      Serial.print(F("failed, code "));
+      Serial.print(F("[SX1278] Failed, code "));
       Serial.println(state);
 
     }

From 5c2bd2bc320c10287f70f7bc4a66216fe82c0d83 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Mon, 3 Jun 2019 10:41:39 +0200
Subject: [PATCH 032/106] [SX126x] Added SX1268 implementation

---
 src/modules/SX1262.cpp |  29 +++++++++++-
 src/modules/SX1262.h   |   4 +-
 src/modules/SX1268.cpp | 104 +++++++++++++++++++++++++++++++++++++++++
 src/modules/SX1268.h   |  90 +++++++++++++++++++++++++++++++++--
 src/modules/SX126x.cpp |  47 +++++--------------
 src/modules/SX126x.h   |   6 +--
 6 files changed, 235 insertions(+), 45 deletions(-)
 create mode 100644 src/modules/SX1268.cpp

diff --git a/src/modules/SX1262.cpp b/src/modules/SX1262.cpp
index e46a3431..218751ab 100644
--- a/src/modules/SX1262.cpp
+++ b/src/modules/SX1262.cpp
@@ -58,12 +58,39 @@ int16_t SX1262::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t
   return(state);
 }
 
-int16_t SX1262::setFrequency(float freq) {
+int16_t SX1262::setFrequency(float freq, bool calibrate) {
   // check frequency range
   if((freq < 150.0) || (freq > 960.0)) {
     return(ERR_INVALID_FREQUENCY);
   }
 
+  int16_t state = ERR_NONE;
+
+  // calibrate image
+  if(calibrate) {
+    uint8_t data[2];
+    if(freq > 900.0) {
+      data[0] = SX126X_CAL_IMG_902_MHZ_1;
+      data[1] = SX126X_CAL_IMG_902_MHZ_2;
+    } else if(freq > 850.0) {
+      data[0] = SX126X_CAL_IMG_863_MHZ_1;
+      data[1] = SX126X_CAL_IMG_863_MHZ_2;
+    } else if(freq > 770.0) {
+      data[0] = SX126X_CAL_IMG_779_MHZ_1;
+      data[1] = SX126X_CAL_IMG_779_MHZ_2;
+    } else if(freq > 460.0) {
+      data[0] = SX126X_CAL_IMG_470_MHZ_1;
+      data[1] = SX126X_CAL_IMG_470_MHZ_2;
+    } else {
+      data[0] = SX126X_CAL_IMG_430_MHZ_1;
+      data[1] = SX126X_CAL_IMG_430_MHZ_2;
+    }
+    state = SX126x::calibrateImage(data);
+    if(state != ERR_NONE) {
+      return(state);
+    }
+  }
+
   // set frequency
   return(SX126x::setFrequencyRaw(freq));
 }
diff --git a/src/modules/SX1262.h b/src/modules/SX1262.h
index 88fa961f..88a49576 100644
--- a/src/modules/SX1262.h
+++ b/src/modules/SX1262.h
@@ -78,9 +78,11 @@ class SX1262: public SX126x {
 
       \param freq Carrier frequency to be set in MHz.
 
+      \param calibrate Run image calibration.
+
       \returns \ref status_codes
     */
-    int16_t setFrequency(float freq);
+    int16_t setFrequency(float freq, bool calibrate = true);
 
     /*!
       \brief Sets output power. Allowed values are in range from -17 to 22 dBm.
diff --git a/src/modules/SX1268.cpp b/src/modules/SX1268.cpp
new file mode 100644
index 00000000..95718f0c
--- /dev/null
+++ b/src/modules/SX1268.cpp
@@ -0,0 +1,104 @@
+#include "SX1268.h"
+
+SX1268::SX1268(Module* mod) : SX126x(mod) {
+
+}
+
+int16_t SX1268::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, int8_t power, float currentLimit, uint16_t preambleLength) {
+  // execute common part
+  int16_t state = SX126x::begin(bw, sf, cr, syncWord, preambleLength);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
+  // configure publicly accessible settings
+  state = setFrequency(freq);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
+  state = setOutputPower(power);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
+  // OCP must be configured after PA
+  state = SX126x::setCurrentLimit(currentLimit);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
+  return(state);
+}
+int16_t SX1268::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, float currentLimit, uint16_t preambleLength, float dataShaping) {
+  // execute common part
+  int16_t state = SX126x::beginFSK(br, freqDev, rxBw, preambleLength, dataShaping);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
+  // configure publicly accessible settings
+  state = setFrequency(freq);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
+  state = setOutputPower(power);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
+  // OCP must be configured after PA
+  state = SX126x::setCurrentLimit(currentLimit);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
+  return(state);
+}
+
+int16_t SX1268::setFrequency(float freq, bool calibrate) {
+  // check frequency range
+  if((freq < 410.0) || (freq > 810.0)) {
+    return(ERR_INVALID_FREQUENCY);
+  }
+
+  int16_t state = ERR_NONE;
+
+  // calibrate image
+  if(calibrate) {
+    uint8_t data[2];
+    if(freq > 770.0) {
+      data[0] = SX126X_CAL_IMG_779_MHZ_1;
+      data[1] = SX126X_CAL_IMG_779_MHZ_2;
+    } else if(freq > 460.0) {
+      data[0] = SX126X_CAL_IMG_470_MHZ_1;
+      data[1] = SX126X_CAL_IMG_470_MHZ_2;
+    } else {
+      data[0] = SX126X_CAL_IMG_430_MHZ_1;
+      data[1] = SX126X_CAL_IMG_430_MHZ_2;
+    }
+    state = SX126x::calibrateImage(data);
+    if(state != ERR_NONE) {
+      return(state);
+    }
+  }
+
+  // set frequency
+  return(SX126x::setFrequencyRaw(freq));
+}
+
+int16_t SX1268::setOutputPower(int8_t power) {
+  // check allowed power range
+  if(!((power >= -9) && (power <= 22))) {
+    return(ERR_INVALID_OUTPUT_POWER);
+  }
+
+  // enable high power PA
+  SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1268);
+
+  // set output power
+  // TODO power ramp time configuration
+  SX126x::setTxParams(power);
+  return(ERR_NONE);
+}
diff --git a/src/modules/SX1268.h b/src/modules/SX1268.h
index 8f00ecd5..9c05529d 100644
--- a/src/modules/SX1268.h
+++ b/src/modules/SX1268.h
@@ -4,13 +4,93 @@
 #include "TypeDef.h"
 #include "Module.h"
 #include "SX126x.h"
-#include "SX1262.h"
 
 //SX126X_CMD_SET_PA_CONFIG
-#define SX126X_PA_CONFIG_SX1261                       0x01
-#define SX126X_PA_CONFIG_SX1262                       0x00
+#define SX126X_PA_CONFIG_SX1268                       0x00
 
-// TODO: implement SX1268 class
-using SX1268 = SX1262;
+/*!
+  \class SX1268
+
+  \brief Derived class for %SX1268 modules.
+*/
+class SX1268: public SX126x {
+  public:
+    /*!
+      \brief Default constructor.
+
+      \param mod Instance of Module that will be used to communicate with the radio.
+    */
+    SX1268(Module* mod);
+
+    // basic methods
+
+    /*!
+      \brief Initialization method for LoRa modem.
+
+      \param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
+
+      \param bw LoRa bandwidth in kHz. Defaults to 125.0 kHz.
+
+      \param sf LoRa spreading factor. Defaults to 9.
+
+      \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7).
+
+      \param syncWord 2-byte LoRa sync word. Defaults to SX126X_SYNC_WORD_PRIVATE (0x1424).
+
+      \param power Output power in dBm. Defaults to 14 dBm.
+
+      \param currentLimit Current protection limit in mA. Defaults to 60.0 mA.
+
+      \param preambleLength LoRa preamble length in symbols.Defaults to 8 symbols.
+
+      \returns \ref status_codes
+    */
+    int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint16_t syncWord = SX126X_SYNC_WORD_PRIVATE, int8_t power = 14, float currentLimit = 60.0, uint16_t preambleLength = 8);
+
+    /*!
+      \brief Initialization method for FSK modem.
+
+      \param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
+
+      \param br FSK bit rate in kbps. Defaults to 48.0 kbps.
+
+      \param freqDev Frequency deviation from carrier frequency in kHz.  Defaults to 50.0 kHz.
+
+      \param rxBw Receiver bandwidth in kHz. Defaults to 156.2 kHz.
+
+      \param power Output power in dBm. Defaults to 14 dBm.
+
+      \param currentLimit Current protection limit in mA. Defaults to 60.0 mA.
+
+      \parma preambleLength FSK preamble length in bits. Defaults to 16 bits.
+
+      \param dataShaping Time-bandwidth product of the Gaussian filter to be used for shaping. Defaults to 0.5.
+
+      \returns \ref status_codes
+    */
+    int16_t beginFSK(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 156.2, int8_t power = 14, float currentLimit = 60.0, uint16_t preambleLength = 16, float dataShaping = 0.5);
+
+    // configuration methods
+
+    /*!
+      \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz.
+
+      \param freq Carrier frequency to be set in MHz.
+
+      \param calibrate Run image calibration.
+
+      \returns \ref status_codes
+    */
+    int16_t setFrequency(float freq, bool calibrate = true);
+
+    /*!
+      \brief Sets output power. Allowed values are in range from -17 to 22 dBm.
+
+      \param power Output power to be set in dBm.
+
+      \returns \ref status_codes
+    */
+    int16_t setOutputPower(int8_t power);
+};
 
 #endif
diff --git a/src/modules/SX126x.cpp b/src/modules/SX126x.cpp
index ca18bbc8..05274763 100644
--- a/src/modules/SX126x.cpp
+++ b/src/modules/SX126x.cpp
@@ -576,9 +576,9 @@ int16_t SX126x::setFrequencyDeviation(float freqDev) {
   uint32_t freqDevRaw = (uint32_t)(((freqDev * 1000.0) * (float)((uint32_t)(1) << 25)) / (SX126X_CRYSTAL_FREQ * 1000000.0));
 
   // check modulation parameters
-  if(2 * freqDevRaw + _br > _rxBwKhz * 1000.0) {
+  /*if(2 * freqDevRaw + _br > _rxBwKhz * 1000.0) {
     return(ERR_INVALID_MODULATION_PARAMETERS);
-  }
+  }*/
   _freqDev = freqDevRaw;
 
   // update modulation parameters
@@ -600,9 +600,9 @@ int16_t SX126x::setBitRate(float br) {
   uint32_t brRaw = (uint32_t)((SX126X_CRYSTAL_FREQ * 1000000.0 * 32.0) / (br * 1000.0));
 
   // check modulation parameters
-  if(2 * _freqDev + brRaw > _rxBwKhz * 1000.0) {
+  /*if(2 * _freqDev + brRaw > _rxBwKhz * 1000.0) {
     return(ERR_INVALID_MODULATION_PARAMETERS);
-  }
+  }*/
   _br = brRaw;
 
   // update modulation parameters
@@ -616,9 +616,9 @@ int16_t SX126x::setRxBandwidth(float rxBw) {
   }
 
   // check modulation parameters
-  if(2 * _freqDev + _br > rxBw * 1000.0) {
+  /*if(2 * _freqDev + _br > rxBw * 1000.0) {
     return(ERR_INVALID_MODULATION_PARAMETERS);
-  }
+  }*/
   _rxBwKhz = rxBw;
 
   // check alowed receiver bandwidth values
@@ -968,6 +968,10 @@ int16_t SX126x::setRfFrequency(uint32_t frf) {
   return(SPIwriteCommand(SX126X_CMD_SET_RF_FREQUENCY, data, 4));
 }
 
+int16_t SX126x::calibrateImage(uint8_t* data) {
+  return(SPIwriteCommand(SX126X_CMD_CALIBRATE_IMAGE, data, 2));
+}
+
 uint8_t SX126x::getPacketType() {
   uint8_t data = 0xFF;
   SPIreadCommand(SX126X_CMD_GET_PACKET_TYPE, &data, 1);
@@ -1047,34 +1051,7 @@ int16_t SX126x::clearDeviceErrors() {
   return(SPIwriteCommand(SX126X_CMD_CLEAR_DEVICE_ERRORS, data, 1));
 }
 
-int16_t SX126x::setFrequencyRaw(float freq, bool calibrate) {
-  int16_t state = ERR_NONE;
-
-  // calibrate image
-  if(calibrate) {
-    uint8_t data[2];
-    if(freq > 900.0) {
-      data[0] = SX126X_CAL_IMG_902_MHZ_1;
-      data[1] = SX126X_CAL_IMG_902_MHZ_2;
-    } else if(freq > 850.0) {
-      data[0] = SX126X_CAL_IMG_863_MHZ_1;
-      data[1] = SX126X_CAL_IMG_863_MHZ_2;
-    } else if(freq > 770.0) {
-      data[0] = SX126X_CAL_IMG_779_MHZ_1;
-      data[1] = SX126X_CAL_IMG_779_MHZ_2;
-    } else if(freq > 460.0) {
-      data[0] = SX126X_CAL_IMG_470_MHZ_1;
-      data[1] = SX126X_CAL_IMG_470_MHZ_2;
-    } else {
-      data[0] = SX126X_CAL_IMG_430_MHZ_1;
-      data[1] = SX126X_CAL_IMG_430_MHZ_2;
-    }
-    state = SPIwriteCommand(SX126X_CMD_CALIBRATE_IMAGE, data, 2);
-    if(state != ERR_NONE) {
-      return(state);
-    }
-  }
-
+int16_t SX126x::setFrequencyRaw(float freq) {
   // calculate raw value
   uint32_t frf = (freq * (uint32_t(1) << SX126X_DIV_EXPONENT)) / SX126X_CRYSTAL_FREQ;
   setRfFrequency(frf);
@@ -1184,7 +1161,7 @@ int16_t SX126x::SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t*
   DEBUG_PRINT('\t');
 
   // variable to save error during SPI transfer
-  uint8_t status;
+  uint8_t status = 0;
 
   // send/receive all bytes
   if(write) {
diff --git a/src/modules/SX126x.h b/src/modules/SX126x.h
index 9bcd6187..a9a84b4b 100644
--- a/src/modules/SX126x.h
+++ b/src/modules/SX126x.h
@@ -150,7 +150,6 @@
 
 //SX126X_CMD_SET_PA_CONFIG
 #define SX126X_PA_CONFIG_HP_MAX                       0x07
-#define SX126X_PA_CONFIG_SX1268                       0x01
 #define SX126X_PA_CONFIG_PA_LUT                       0x01
 
 //SX126X_CMD_SET_RX_TX_FALLBACK_MODE
@@ -366,7 +365,7 @@ class SX126x: public PhysicalLayer {
 
       \param rxBw Receiver bandwidth in kHz. Allowed values are 4.8, 5.8, 7.3, 9.7, 11.7, 14.6, 19.5, 23.4, 29.3, 39.0, 46.9, 58.6, 78.2, 93.8, 117.3, 156.2, 187.2, 234.3, 312.0, 373.6 and 467.0 kHz.
 
-      \parma preambleLength FSK preamble length in bits. Allowed values range from 0 to 65535.
+      \param preambleLength FSK preamble length in bits. Allowed values range from 0 to 65535.
 
       \param dataShaping Time-bandwidth product of the Gaussian filter to be used for shaping. Allowed values are 0.3, 0.5, 0.7 and 1.0. Set to 0 to disable shaping.
 
@@ -692,6 +691,7 @@ class SX126x: public PhysicalLayer {
     uint16_t getIrqStatus();
     int16_t clearIrqStatus(uint16_t clearIrqParams = SX126X_IRQ_ALL);
     int16_t setRfFrequency(uint32_t frf);
+    int16_t calibrateImage(uint8_t* data);
     uint8_t getPacketType();
     int16_t setTxParams(uint8_t power, uint8_t rampTime = SX126X_PA_RAMP_200U);
     int16_t setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro = 0xFF);
@@ -704,7 +704,7 @@ class SX126x: public PhysicalLayer {
     uint16_t getDeviceErrors();
     int16_t clearDeviceErrors();
 
-    int16_t setFrequencyRaw(float freq, bool calibrate = true);
+    int16_t setFrequencyRaw(float freq);
 
   private:
     Module* _mod;

From 8fc323a900a9885bb47beacbfa336a12a0a23524 Mon Sep 17 00:00:00 2001
From: Bernd Giesecke <bernd@giesecke.tk>
Date: Tue, 4 Jun 2019 13:13:00 +0800
Subject: [PATCH 033/106] Add function to set DIO2 of SX126x chips to be used
 as RF antenna switch (based on example design of Semtech and used in many
 modules). This breaks the CAD function as DIO2 cannot be used as IRQ output.

Signed-off-by: Bernd Giesecke <bernd@giesecke.tk>
---
 src/Module.cpp         |  4 ++++
 src/Module.h           | 16 +++++++++++++++-
 src/modules/SX126x.cpp | 28 ++++++++++++++++++++++++++++
 src/modules/SX126x.h   |  7 +++++++
 4 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/src/Module.cpp b/src/Module.cpp
index 5c238519..da2ac6f9 100644
--- a/src/Module.cpp
+++ b/src/Module.cpp
@@ -79,6 +79,10 @@ void Module::term() {
   _spi->end();
 }
 
+void Module::setDio2Func(bool enable) { 
+  _dio2RfSwitch = enable;
+}
+
 void Module::ATemptyBuffer() {
   while(ModuleSerial->available() > 0) {
     ModuleSerial->read();
diff --git a/src/Module.h b/src/Module.h
index c596276f..0ed6a3eb 100644
--- a/src/Module.h
+++ b/src/Module.h
@@ -277,6 +277,20 @@ class Module {
     */
     int getTx() const { return(_tx); }
 
+    /*!
+      \brief Access method to get DIO2 RF switch flag.
+
+      \returns true if DIO2 is set as RF switch.
+    */
+    int getDio2Func() const { return(_dio2RfSwitch); }
+
+    /*!
+      \brief Access method to set/reset DIO2 RF switch flag.
+
+      \returns true if DIO2 is set as RF switch.
+    */
+    void setDio2Func(bool enable);
+
     /*!
       \brief Access method to get the SPI interface.
 
@@ -297,7 +311,7 @@ class Module {
     int _rx;
     int _int0;
     int _int1;
-
+    bool _dio2RfSwitch = false;
     SPIClass* _spi;
     SPISettings _spiSettings;
 
diff --git a/src/modules/SX126x.cpp b/src/modules/SX126x.cpp
index 05274763..e43a774d 100644
--- a/src/modules/SX126x.cpp
+++ b/src/modules/SX126x.cpp
@@ -274,6 +274,11 @@ int16_t SX126x::scanChannel() {
     return(ERR_WRONG_MODEM);
   }
 
+  if (_mod->getDio2Func()) {
+    // If DIO2 is used as RF switch this function does not work
+    return(ERR_WRONG_MODEM);
+  }
+
   // set mode to standby
   int16_t state = standby();
   if(state != ERR_NONE) {
@@ -1058,6 +1063,29 @@ int16_t SX126x::setFrequencyRaw(float freq) {
   return(ERR_NONE);
 }
 
+int16_t SX126x::setDio2AsRfSwitch(bool enable) {
+  int dio2 = _mod->getInt1();
+  if (dio2 == -1)
+  {
+    // DIO2 is not defined, return error
+    _mod->setDio2Func(false);
+    return ERR_WRONG_MODEM;
+  }
+  uint8_t* data = new uint8_t[1];
+  if (enable) {
+  // set DIO2 as RF switch
+    data[0] = SX126X_DIO2_AS_RF_SWITCH;
+  } else {
+    data[0] = SX126X_DIO2_AS_IRQ;
+  }
+  int16_t state = SPIwriteCommand(SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, data, 1);
+
+  if (state == ERR_NONE) {
+    _mod->setDio2Func(enable);
+  }
+  return(state);
+}
+
 int16_t SX126x::config(uint8_t modem) {
   // set DIO2 as IRQ
   uint8_t* data = new uint8_t[1];
diff --git a/src/modules/SX126x.h b/src/modules/SX126x.h
index a9a84b4b..1f34c759 100644
--- a/src/modules/SX126x.h
+++ b/src/modules/SX126x.h
@@ -678,6 +678,13 @@ class SX126x: public PhysicalLayer {
     */
     float getSNR();
 
+    /*!
+      \brief Set DIO2 to function as RF switch (default in Semtech example designs).
+
+      \returns \ref status_codes 
+    */
+    int16_t setDio2AsRfSwitch(bool enable = false);
+
   protected:
     // SX1276x SPI command implementations
     int16_t setTx(uint32_t timeout = 0);

From 23b0b9b25adfff134dedee985e5e83c9a69cde7d Mon Sep 17 00:00:00 2001
From: Bernd Giesecke <bernd@giesecke.tk>
Date: Tue, 4 Jun 2019 14:28:33 +0800
Subject: [PATCH 034/106] Moved `setDio2AsRfSwitch()` from module to SX126x
 Added new error code Removed memory leak

Signed-off-by: Bernd Giesecke <bernd@giesecke.tk>
---
 src/Module.cpp         |  4 ----
 src/Module.h           | 15 ---------------
 src/TypeDef.h          |  5 +++++
 src/modules/SX126x.cpp | 16 +++++-----------
 src/modules/SX126x.h   |  4 +++-
 5 files changed, 13 insertions(+), 31 deletions(-)

diff --git a/src/Module.cpp b/src/Module.cpp
index da2ac6f9..5c238519 100644
--- a/src/Module.cpp
+++ b/src/Module.cpp
@@ -79,10 +79,6 @@ void Module::term() {
   _spi->end();
 }
 
-void Module::setDio2Func(bool enable) { 
-  _dio2RfSwitch = enable;
-}
-
 void Module::ATemptyBuffer() {
   while(ModuleSerial->available() > 0) {
     ModuleSerial->read();
diff --git a/src/Module.h b/src/Module.h
index 0ed6a3eb..03fb75d4 100644
--- a/src/Module.h
+++ b/src/Module.h
@@ -277,20 +277,6 @@ class Module {
     */
     int getTx() const { return(_tx); }
 
-    /*!
-      \brief Access method to get DIO2 RF switch flag.
-
-      \returns true if DIO2 is set as RF switch.
-    */
-    int getDio2Func() const { return(_dio2RfSwitch); }
-
-    /*!
-      \brief Access method to set/reset DIO2 RF switch flag.
-
-      \returns true if DIO2 is set as RF switch.
-    */
-    void setDio2Func(bool enable);
-
     /*!
       \brief Access method to get the SPI interface.
 
@@ -311,7 +297,6 @@ class Module {
     int _rx;
     int _int0;
     int _int1;
-    bool _dio2RfSwitch = false;
     SPIClass* _spi;
     SPISettings _spiSettings;
 
diff --git a/src/TypeDef.h b/src/TypeDef.h
index b007f408..efda5ef0 100644
--- a/src/TypeDef.h
+++ b/src/TypeDef.h
@@ -461,6 +461,11 @@
 */
 #define ERR_SPI_CMD_FAILED                    -707
 
+/*!
+  \brief SX126x scan channel not possible because DIO2 is used as RF antenna switch.
+*/
+#define ERR_DIO2_UNAVAIL_CAD_FAILED           -708
+
 /*!
   \}
 */
diff --git a/src/modules/SX126x.cpp b/src/modules/SX126x.cpp
index e43a774d..deb2dba8 100644
--- a/src/modules/SX126x.cpp
+++ b/src/modules/SX126x.cpp
@@ -274,9 +274,9 @@ int16_t SX126x::scanChannel() {
     return(ERR_WRONG_MODEM);
   }
 
-  if (_mod->getDio2Func()) {
+  if (_dio2RfSwitch) {
     // If DIO2 is used as RF switch this function does not work
-    return(ERR_WRONG_MODEM);
+    return(ERR_DIO2_UNAVAIL_CAD_FAILED);
   }
 
   // set mode to standby
@@ -1064,14 +1064,7 @@ int16_t SX126x::setFrequencyRaw(float freq) {
 }
 
 int16_t SX126x::setDio2AsRfSwitch(bool enable) {
-  int dio2 = _mod->getInt1();
-  if (dio2 == -1)
-  {
-    // DIO2 is not defined, return error
-    _mod->setDio2Func(false);
-    return ERR_WRONG_MODEM;
-  }
-  uint8_t* data = new uint8_t[1];
+  uint8_t data[1];
   if (enable) {
   // set DIO2 as RF switch
     data[0] = SX126X_DIO2_AS_RF_SWITCH;
@@ -1081,13 +1074,14 @@ int16_t SX126x::setDio2AsRfSwitch(bool enable) {
   int16_t state = SPIwriteCommand(SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, data, 1);
 
   if (state == ERR_NONE) {
-    _mod->setDio2Func(enable);
+    _dio2RfSwitch = true;
   }
   return(state);
 }
 
 int16_t SX126x::config(uint8_t modem) {
   // set DIO2 as IRQ
+  _dio2RfSwitch = false;
   uint8_t* data = new uint8_t[1];
   data[0] = SX126X_DIO2_AS_IRQ;
   int16_t state = SPIwriteCommand(SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, data, 1);
diff --git a/src/modules/SX126x.h b/src/modules/SX126x.h
index 1f34c759..0139e191 100644
--- a/src/modules/SX126x.h
+++ b/src/modules/SX126x.h
@@ -683,7 +683,7 @@ class SX126x: public PhysicalLayer {
 
       \returns \ref status_codes 
     */
-    int16_t setDio2AsRfSwitch(bool enable = false);
+    int16_t setDio2AsRfSwitch(bool enable = true);
 
   protected:
     // SX1276x SPI command implementations
@@ -727,6 +727,8 @@ class SX126x: public PhysicalLayer {
 
     float _dataRate;
 
+    bool _dio2RfSwitch = false;
+
     int16_t config(uint8_t modem);
 
     // common low-level SPI interface

From c9779648d5784eefc6b49c3a270ceb53bf13dd9c Mon Sep 17 00:00:00 2001
From: Bernd Giesecke <bernd@giesecke.tk>
Date: Tue, 4 Jun 2019 14:32:33 +0800
Subject: [PATCH 035/106] Put back accidentially removed empty line.

Signed-off-by: Bernd Giesecke <bernd@giesecke.tk>
---
 src/Module.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/Module.h b/src/Module.h
index 03fb75d4..c596276f 100644
--- a/src/Module.h
+++ b/src/Module.h
@@ -297,6 +297,7 @@ class Module {
     int _rx;
     int _int0;
     int _int1;
+
     SPIClass* _spi;
     SPISettings _spiSettings;
 

From 7ab491d221a73ae973de55ec2a444724b88470d4 Mon Sep 17 00:00:00 2001
From: Bernd Giesecke <bernd@giesecke.tk>
Date: Tue, 4 Jun 2019 14:44:37 +0800
Subject: [PATCH 036/106] Correct wrong declaration of
 ```ESP8266::getNumBytes(uint32_t timeout, size_t minBytes)```

Signed-off-by: Bernd Giesecke <bernd@giesecke.tk>
---
 src/modules/ESP8266.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/modules/ESP8266.cpp b/src/modules/ESP8266.cpp
index c6dcc55a..8586cf96 100644
--- a/src/modules/ESP8266.cpp
+++ b/src/modules/ESP8266.cpp
@@ -180,7 +180,7 @@ size_t ESP8266::receive(uint8_t* data, size_t len, uint32_t timeout) {
   return(i);
 }
 
-uint16_t ESP8266::getNumBytes(uint32_t timeout, size_t minBytes) {
+size_t ESP8266::getNumBytes(uint32_t timeout, size_t minBytes) {
   // wait for available data
   uint32_t start = millis();
   while(_mod->ModuleSerial->available() < (int16_t)minBytes) {

From 039cb0646017a630a2943e63897f192c6d927831 Mon Sep 17 00:00:00 2001
From: Bernd Giesecke <bernd@giesecke.tk>
Date: Tue, 4 Jun 2019 15:18:11 +0800
Subject: [PATCH 037/106] Added missing keyword

Signed-off-by: Bernd Giesecke <bernd@giesecke.tk>
---
 keywords.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/keywords.txt b/keywords.txt
index 7621a797..31d82ea1 100644
--- a/keywords.txt
+++ b/keywords.txt
@@ -104,6 +104,7 @@ setGdo1Action	KEYWORD2
 # SX126x-specific
 setDio2Action	KEYWORD2
 setTCXO	KEYWORD2
+setDio2AsRfSwitch	KEYWORD2
 
 # ESP8266
 join	KEYWORD2

From 8c0a7a2ea31d2f92b47cd5d7e2fe76578a1b814c Mon Sep 17 00:00:00 2001
From: Bernd Giesecke <bernd@giesecke.tk>
Date: Tue, 4 Jun 2019 15:35:24 +0800
Subject: [PATCH 038/106] Moved DIO2 setting into begin()/beginFSK()

Signed-off-by: Bernd Giesecke <bernd@giesecke.tk>
---
 src/modules/SX126x.cpp | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/src/modules/SX126x.cpp b/src/modules/SX126x.cpp
index deb2dba8..3a74fe4e 100644
--- a/src/modules/SX126x.cpp
+++ b/src/modules/SX126x.cpp
@@ -33,6 +33,11 @@ int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, uint1
   }
 
   // configure publicly accessible settings
+  state = setDio2AsRfSwitch(false);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
   state = setSpreadingFactor(sf);
   if(state != ERR_NONE) {
     return(state);
@@ -86,6 +91,11 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL
   }
 
   // configure publicly accessible settings
+  state = setDio2AsRfSwitch(false);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
   state = setBitRate(br);
   if(state != ERR_NONE) {
     return(state);
@@ -1080,18 +1090,10 @@ int16_t SX126x::setDio2AsRfSwitch(bool enable) {
 }
 
 int16_t SX126x::config(uint8_t modem) {
-  // set DIO2 as IRQ
-  _dio2RfSwitch = false;
-  uint8_t* data = new uint8_t[1];
-  data[0] = SX126X_DIO2_AS_IRQ;
-  int16_t state = SPIwriteCommand(SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, data, 1);
-  if(state != ERR_NONE) {
-    return(state);
-  }
-
   // set regulator mode
+  uint8_t* data = new uint8_t[1];
   data[0] = SX126X_REGULATOR_DC_DC;
-  state = SPIwriteCommand(SX126X_CMD_SET_REGULATOR_MODE, data, 1);
+  int16_t state = SPIwriteCommand(SX126X_CMD_SET_REGULATOR_MODE, data, 1);
   if(state != ERR_NONE) {
     return(state);
   }

From b8b20a3753276304508936c89e653a7471fe3504 Mon Sep 17 00:00:00 2001
From: Bernd Giesecke <bernd@giesecke.tk>
Date: Tue, 4 Jun 2019 15:38:42 +0800
Subject: [PATCH 039/106] Corrected bug.

Signed-off-by: Bernd Giesecke <bernd@giesecke.tk>
---
 src/modules/SX126x.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/modules/SX126x.cpp b/src/modules/SX126x.cpp
index 3a74fe4e..8291857c 100644
--- a/src/modules/SX126x.cpp
+++ b/src/modules/SX126x.cpp
@@ -1084,7 +1084,7 @@ int16_t SX126x::setDio2AsRfSwitch(bool enable) {
   int16_t state = SPIwriteCommand(SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, data, 1);
 
   if (state == ERR_NONE) {
-    _dio2RfSwitch = true;
+    _dio2RfSwitch = enable;
   }
   return(state);
 }

From c9b68163d51af68b6603b6a32e06c16b6aa5b6ef Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Tue, 4 Jun 2019 10:13:04 +0200
Subject: [PATCH 040/106] [SX126x] Added notes about DIO2 RF control

---
 .../SX126x_Channel_Activity_Detection.ino     |  9 ++++-
 .../SX126x_Settings/SX126x_Settings.ino       |  9 +++++
 keywords.txt                                  |  1 +
 src/TypeDef.h                                 |  2 +-
 src/modules/SX126x.cpp                        | 38 +++++++++----------
 5 files changed, 37 insertions(+), 22 deletions(-)

diff --git a/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino b/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino
index 0750f181..91c53b09 100644
--- a/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino
+++ b/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino
@@ -59,11 +59,16 @@ void loop() {
 
   if (state == LORA_DETECTED) {
     // LoRa preamble was detected
-    Serial.println(F(" detected!"));
+    Serial.println(F("detected!"));
 
   } else if (state == CHANNEL_FREE) {
     // no preamble was detected, channel is free
-    Serial.println(F(" channel is free!"));
+    Serial.println(F("channel is free!"));
+
+  } else if (state == ERR_CAD_UNAVAILABLE) {
+    // no preamble was detected, channel is free
+    Serial.println(F("unable to perform scan!"));
+    Serial.println(F("[SX1262] Disable DIO2 RF control to run CAD."));
 
   }
 
diff --git a/examples/SX126x/SX126x_Settings/SX126x_Settings.ino b/examples/SX126x/SX126x_Settings/SX126x_Settings.ino
index 52553045..7d9114b0 100644
--- a/examples/SX126x/SX126x_Settings/SX126x_Settings.ino
+++ b/examples/SX126x/SX126x_Settings/SX126x_Settings.ino
@@ -13,6 +13,7 @@
     - CRC
     - preamble length
     - TCXO voltage
+    - DIO2 RF switch control
 
    Other modules from SX126x family can also be used.
 
@@ -146,6 +147,14 @@ void setup() {
     while (true);
   }
 
+  // Some SX126x modules use DIO2 as RF switch. To enable
+  // this feature, the following method can be used.
+  // NOTE: As long as DIO2 is configured to control RF switch,
+  //       Channel Activity Detection is disabled!
+  if (loraSX1262.setDio2AsRfSwitch() != ERR_NONE) {
+    Serial.println(F("Failed to set DIO2 as RF switch!"));
+    while (true);
+  }
 
   Serial.println(F("All settings succesfully changed!"));
 }
diff --git a/keywords.txt b/keywords.txt
index 31d82ea1..d9a7b7f2 100644
--- a/keywords.txt
+++ b/keywords.txt
@@ -232,3 +232,4 @@ ERR_INVALID_MODULATION_PARAMETERS	LITERAL1
 ERR_SPI_CMD_TIMEOUT	LITERAL1
 ERR_SPI_CMD_INVALID	LITERAL1
 ERR_SPI_CMD_FAILED	LITERAL1
+ERR_CAD_UNAVAILABLE	LITERAL1
diff --git a/src/TypeDef.h b/src/TypeDef.h
index efda5ef0..6a91a4c9 100644
--- a/src/TypeDef.h
+++ b/src/TypeDef.h
@@ -464,7 +464,7 @@
 /*!
   \brief SX126x scan channel not possible because DIO2 is used as RF antenna switch.
 */
-#define ERR_DIO2_UNAVAIL_CAD_FAILED           -708
+#define ERR_CAD_UNAVAILABLE                  -708
 
 /*!
   \}
diff --git a/src/modules/SX126x.cpp b/src/modules/SX126x.cpp
index 8291857c..17369cab 100644
--- a/src/modules/SX126x.cpp
+++ b/src/modules/SX126x.cpp
@@ -33,11 +33,6 @@ int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, uint1
   }
 
   // configure publicly accessible settings
-  state = setDio2AsRfSwitch(false);
-  if(state != ERR_NONE) {
-    return(state);
-  }
-
   state = setSpreadingFactor(sf);
   if(state != ERR_NONE) {
     return(state);
@@ -59,6 +54,12 @@ int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, uint1
   }
 
   state = setPreambleLength(preambleLength);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
+  // set publicly accessible settings that are not a part of begin method
+  state = setDio2AsRfSwitch(false);
 
   return(state);
 }
@@ -91,11 +92,6 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL
   }
 
   // configure publicly accessible settings
-  state = setDio2AsRfSwitch(false);
-  if(state != ERR_NONE) {
-    return(state);
-  }
-
   state = setBitRate(br);
   if(state != ERR_NONE) {
     return(state);
@@ -121,9 +117,14 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL
     return(state);
   }
 
-  // set default sync word 0x2D01 - not a beginFSK attribute
+  // set publicly accessible settings that are not a part of begin method
   uint8_t sync[] = {0x2D, 0x01};
   state = setSyncWord(sync, 2);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
+  state = setDio2AsRfSwitch(false);
 
   return(state);
 }
@@ -286,7 +287,7 @@ int16_t SX126x::scanChannel() {
 
   if (_dio2RfSwitch) {
     // If DIO2 is used as RF switch this function does not work
-    return(ERR_DIO2_UNAVAIL_CAD_FAILED);
+    return(ERR_CAD_UNAVAILABLE);
   }
 
   // set mode to standby
@@ -1074,16 +1075,15 @@ int16_t SX126x::setFrequencyRaw(float freq) {
 }
 
 int16_t SX126x::setDio2AsRfSwitch(bool enable) {
-  uint8_t data[1];
-  if (enable) {
-  // set DIO2 as RF switch
-    data[0] = SX126X_DIO2_AS_RF_SWITCH;
+  uint8_t data = 0;
+  if(enable) {
+    data = SX126X_DIO2_AS_RF_SWITCH;
   } else {
-    data[0] = SX126X_DIO2_AS_IRQ;
+    data = SX126X_DIO2_AS_IRQ;
   }
-  int16_t state = SPIwriteCommand(SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, data, 1);
+  int16_t state = SPIwriteCommand(SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1);
 
-  if (state == ERR_NONE) {
+  if(state == ERR_NONE) {
     _dio2RfSwitch = enable;
   }
   return(state);

From eddf96bbb2c31734141f93401fe814b68eddc88b Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Fri, 7 Jun 2019 10:05:40 +0200
Subject: [PATCH 041/106] [SX126x] Changed CAD to only use DIO1 (#19)

---
 .../SX126x_Channel_Activity_Detection.ino     |  8 +--
 .../SX126x_Settings/SX126x_Settings.ino       |  2 +-
 keywords.txt                                  |  1 -
 src/TypeDef.h                                 |  5 --
 src/modules/SX126x.cpp                        | 56 +++++++++----------
 src/modules/SX126x.h                          | 16 +++---
 6 files changed, 37 insertions(+), 51 deletions(-)

diff --git a/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino b/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino
index 91c53b09..9b2fb275 100644
--- a/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino
+++ b/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino
@@ -65,10 +65,10 @@ void loop() {
     // no preamble was detected, channel is free
     Serial.println(F("channel is free!"));
 
-  } else if (state == ERR_CAD_UNAVAILABLE) {
-    // no preamble was detected, channel is free
-    Serial.println(F("unable to perform scan!"));
-    Serial.println(F("[SX1262] Disable DIO2 RF control to run CAD."));
+  } else {
+    // some other error occurred
+    Serial.print(F("failed, code "));
+    Serial.println(state);
 
   }
 
diff --git a/examples/SX126x/SX126x_Settings/SX126x_Settings.ino b/examples/SX126x/SX126x_Settings/SX126x_Settings.ino
index 7d9114b0..beb4b455 100644
--- a/examples/SX126x/SX126x_Settings/SX126x_Settings.ino
+++ b/examples/SX126x/SX126x_Settings/SX126x_Settings.ino
@@ -150,7 +150,7 @@ void setup() {
   // Some SX126x modules use DIO2 as RF switch. To enable
   // this feature, the following method can be used.
   // NOTE: As long as DIO2 is configured to control RF switch,
-  //       Channel Activity Detection is disabled!
+  //       it can't be used as interrupt pin!
   if (loraSX1262.setDio2AsRfSwitch() != ERR_NONE) {
     Serial.println(F("Failed to set DIO2 as RF switch!"));
     while (true);
diff --git a/keywords.txt b/keywords.txt
index d9a7b7f2..31d82ea1 100644
--- a/keywords.txt
+++ b/keywords.txt
@@ -232,4 +232,3 @@ ERR_INVALID_MODULATION_PARAMETERS	LITERAL1
 ERR_SPI_CMD_TIMEOUT	LITERAL1
 ERR_SPI_CMD_INVALID	LITERAL1
 ERR_SPI_CMD_FAILED	LITERAL1
-ERR_CAD_UNAVAILABLE	LITERAL1
diff --git a/src/TypeDef.h b/src/TypeDef.h
index 6a91a4c9..b007f408 100644
--- a/src/TypeDef.h
+++ b/src/TypeDef.h
@@ -461,11 +461,6 @@
 */
 #define ERR_SPI_CMD_FAILED                    -707
 
-/*!
-  \brief SX126x scan channel not possible because DIO2 is used as RF antenna switch.
-*/
-#define ERR_CAD_UNAVAILABLE                  -708
-
 /*!
   \}
 */
diff --git a/src/modules/SX126x.cpp b/src/modules/SX126x.cpp
index 17369cab..7332b340 100644
--- a/src/modules/SX126x.cpp
+++ b/src/modules/SX126x.cpp
@@ -285,11 +285,6 @@ int16_t SX126x::scanChannel() {
     return(ERR_WRONG_MODEM);
   }
 
-  if (_dio2RfSwitch) {
-    // If DIO2 is used as RF switch this function does not work
-    return(ERR_CAD_UNAVAILABLE);
-  }
-
   // set mode to standby
   int16_t state = standby();
   if(state != ERR_NONE) {
@@ -297,7 +292,7 @@ int16_t SX126x::scanChannel() {
   }
 
   // set DIO pin mapping
-  state = setDioIrqParams(SX126X_IRQ_CAD_DETECTED | SX126X_IRQ_CAD_DONE, SX126X_IRQ_CAD_DONE, SX126X_IRQ_CAD_DETECTED);
+  state = setDioIrqParams(SX126X_IRQ_CAD_DETECTED | SX126X_IRQ_CAD_DONE, SX126X_IRQ_CAD_DETECTED | SX126X_IRQ_CAD_DONE);
   if(state != ERR_NONE) {
     return(state);
   }
@@ -315,17 +310,21 @@ int16_t SX126x::scanChannel() {
   }
 
   // wait for channel activity detected or timeout
-  while(!digitalRead(_mod->getInt0())) {
-    if(digitalRead(_mod->getInt1())) {
-      clearIrqStatus();
-      return(LORA_DETECTED);
-    }
+  while(!digitalRead(_mod->getInt0()));
+
+  // check CAD result
+  uint16_t cadResult = getIrqStatus();
+  if(cadResult & SX126X_IRQ_CAD_DETECTED) {
+    // detected some LoRa activity
+    clearIrqStatus();
+    return(LORA_DETECTED);
+  } else if(cadResult & SX126X_IRQ_CAD_DONE) {
+    // channel is free
+    clearIrqStatus();
+    return(CHANNEL_FREE);
   }
 
-  // clear interrupt flags
-  clearIrqStatus();
-
-  return(CHANNEL_FREE);
+  return(ERR_UNKNOWN);
 }
 
 int16_t SX126x::sleep() {
@@ -911,6 +910,16 @@ int16_t SX126x::setTCXO(float voltage, uint32_t timeout) {
   return(ERR_NONE);
 }
 
+int16_t SX126x::setDio2AsRfSwitch(bool enable) {
+  uint8_t data = 0;
+  if(enable) {
+    data = SX126X_DIO2_AS_RF_SWITCH;
+  } else {
+    data = SX126X_DIO2_AS_IRQ;
+  }
+  return(SPIwriteCommand(SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1));
+}
+
 int16_t SX126x::setTx(uint32_t timeout) {
   uint8_t data[3] = {(uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF)};
   return(SPIwriteCommand(SX126X_CMD_SET_TX, data, 3));
@@ -971,7 +980,7 @@ int16_t SX126x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t di
 uint16_t SX126x::getIrqStatus() {
   uint8_t data[2];
   SPIreadCommand(SX126X_CMD_GET_IRQ_STATUS, data, 2);
-  return(((uint16_t)(data[1]) << 8) | data[0]);
+  return(((uint16_t)(data[0]) << 8) | data[1]);
 }
 
 int16_t SX126x::clearIrqStatus(uint16_t clearIrqParams) {
@@ -1074,21 +1083,6 @@ int16_t SX126x::setFrequencyRaw(float freq) {
   return(ERR_NONE);
 }
 
-int16_t SX126x::setDio2AsRfSwitch(bool enable) {
-  uint8_t data = 0;
-  if(enable) {
-    data = SX126X_DIO2_AS_RF_SWITCH;
-  } else {
-    data = SX126X_DIO2_AS_IRQ;
-  }
-  int16_t state = SPIwriteCommand(SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1);
-
-  if(state == ERR_NONE) {
-    _dio2RfSwitch = enable;
-  }
-  return(state);
-}
-
 int16_t SX126x::config(uint8_t modem) {
   // set regulator mode
   uint8_t* data = new uint8_t[1];
diff --git a/src/modules/SX126x.h b/src/modules/SX126x.h
index 0139e191..e2d995bc 100644
--- a/src/modules/SX126x.h
+++ b/src/modules/SX126x.h
@@ -657,6 +657,13 @@ class SX126x: public PhysicalLayer {
     */
     int16_t setTCXO(float voltage, uint32_t timeout = 5000);
 
+    /*!
+      \brief Set DIO2 to function as RF switch (default in Semtech example designs).
+
+      \returns \ref status_codes
+    */
+    int16_t setDio2AsRfSwitch(bool enable = true);
+
     /*!
       \brief Gets effective data rate for the last transmitted packet. The value is calculated only for payload bytes.
 
@@ -678,13 +685,6 @@ class SX126x: public PhysicalLayer {
     */
     float getSNR();
 
-    /*!
-      \brief Set DIO2 to function as RF switch (default in Semtech example designs).
-
-      \returns \ref status_codes 
-    */
-    int16_t setDio2AsRfSwitch(bool enable = true);
-
   protected:
     // SX1276x SPI command implementations
     int16_t setTx(uint32_t timeout = 0);
@@ -727,8 +727,6 @@ class SX126x: public PhysicalLayer {
 
     float _dataRate;
 
-    bool _dio2RfSwitch = false;
-
     int16_t config(uint8_t modem);
 
     // common low-level SPI interface

From cca121c85ef562128811d88ab96ac6fd8281244b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Grome=C5=A1?= <jgromes@users.noreply.github.com>
Date: Sat, 8 Jun 2019 08:44:51 +0200
Subject: [PATCH 042/106] [SX126x] Updated example

---
 .../SX126x_Channel_Activity_Detection.ino                | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino b/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino
index 9b2fb275..ae15238a 100644
--- a/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino
+++ b/examples/SX126x/SX126x_Channel_Activity_Detection/SX126x_Channel_Activity_Detection.ino
@@ -1,11 +1,10 @@
 /*
    RadioLib SX126x Channel Activity Detection Example
 
-   This example scans the current LoRa channel and detects
-   valid LoRa preambles. Preamble is the first part of
-   LoRa transmission, so this can be used to check
-   if the LoRa channel is free, or if you should start
-   receiving a message.
+   This example uses SX1262 to scan the current LoRa 
+   channel and detect ongoing LoRa transmissions.
+   Unlike SX127x CAD, SX126x can detect any part 
+   of LoRa transmission, not just the preamble.
 
    Other modules from SX126x family can also be used.
 

From c72ad019f42ef79a9d67bfbc1f050b0d6eb961fa Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 16 Jun 2019 14:33:26 +0200
Subject: [PATCH 043/106] [SX127x] Sync with LoRaLib 8.1.0

---
 keywords.txt                    |   2 +-
 src/TypeDef.h                   |   4 +-
 src/modules/SX1272.cpp          |  11 ++-
 src/modules/SX1272.h            |   6 +-
 src/modules/SX1278.cpp          |  11 ++-
 src/modules/SX1278.h            |   6 +-
 src/modules/SX127x.cpp          | 168 +++++++++++++++++++++-----------
 src/modules/SX127x.h            |  24 ++++-
 src/protocols/PhysicalLayer.cpp |  73 +++++++++++---
 src/protocols/PhysicalLayer.h   |  32 ++++--
 10 files changed, 236 insertions(+), 101 deletions(-)

diff --git a/keywords.txt b/keywords.txt
index 31d82ea1..7a47ab48 100644
--- a/keywords.txt
+++ b/keywords.txt
@@ -162,7 +162,7 @@ ERR_NONE	LITERAL1
 ERR_UNKNOWN	LITERAL1
 
 ERR_CHIP_NOT_FOUND	LITERAL1
-ERR_EEPROM_NOT_INITIALIZED	LITERAL1
+ERR_MEMORY_ALLOCATION_FAILED	LITERAL1
 ERR_PACKET_TOO_LONG	LITERAL1
 ERR_TX_TIMEOUT	LITERAL1
 ERR_RX_TIMEOUT	LITERAL1
diff --git a/src/TypeDef.h b/src/TypeDef.h
index b007f408..73c81802 100644
--- a/src/TypeDef.h
+++ b/src/TypeDef.h
@@ -150,9 +150,9 @@
 #define ERR_CHIP_NOT_FOUND                    -2
 
 /*!
-  \brief Deprecated.
+  \brief Failed to allocate memory for temporary buffer. This can be cause by not enough RAM or by passing invalid pointer.
 */
-#define ERR_EEPROM_NOT_INITIALIZED            -3
+#define ERR_MEMORY_ALLOCATION_FAILED          -3
 
 /*!
   \brief Packet supplied to transmission method was longer than limit.
diff --git a/src/modules/SX1272.cpp b/src/modules/SX1272.cpp
index b6cbcddc..f592cff9 100644
--- a/src/modules/SX1272.cpp
+++ b/src/modules/SX1272.cpp
@@ -58,9 +58,9 @@ int16_t SX1272::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync
   return(state);
 }
 
-int16_t SX1272::beginFSK(float freq, float br, float rxBw, float freqDev, int8_t power, uint8_t currentLimit, bool enableOOK) {
+int16_t SX1272::beginFSK(float freq, float br, float rxBw, float freqDev, int8_t power, uint8_t currentLimit, uint16_t preambleLength, bool enableOOK) {
   // execute common part
-  int16_t state = SX127x::beginFSK(SX1272_CHIP_VERSION, br, rxBw, freqDev, currentLimit, enableOOK);
+  int16_t state = SX127x::beginFSK(SX1272_CHIP_VERSION, br, rxBw, freqDev, currentLimit, preambleLength, enableOOK);
   if(state != ERR_NONE) {
     return(state);
   }
@@ -294,13 +294,14 @@ int16_t SX1272::setDataShaping(float sh) {
   int16_t state = SX127x::standby();
 
   // set data shaping
+  sh *= 10.0;
   if(abs(sh - 0.0) <= 0.001) {
     state |= _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_NO_SHAPING, 4, 3);
-  } else if(abs(sh - 0.3) <= 0.001) {
+  } else if(abs(sh - 3.0) <= 0.001) {
     state |= _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_FSK_GAUSSIAN_0_3, 4, 3);
-  } else if(abs(sh - 0.5) <= 0.001) {
+  } else if(abs(sh - 5.0) <= 0.001) {
     state |= _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_FSK_GAUSSIAN_0_5, 4, 3);
-  } else if(abs(sh - 1.0) <= 0.001) {
+  } else if(abs(sh - 10.0) <= 0.001) {
     state |= _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_FSK_GAUSSIAN_1_0, 4, 3);
   } else {
     return(ERR_INVALID_DATA_SHAPING);
diff --git a/src/modules/SX1272.h b/src/modules/SX1272.h
index aec213c8..95f4068f 100644
--- a/src/modules/SX1272.h
+++ b/src/modules/SX1272.h
@@ -148,11 +148,13 @@ class SX1272: public SX127x {
       \param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
       Set to 0 to disable OCP (not recommended).
 
+      \param preambleLength Length of FSK preamble in bits.
+
       \param enableOOK Use OOK modulation instead of FSK.
 
       \returns \ref status_codes
     */
-    int16_t beginFSK(float freq = 915.0, float br = 48.0, float rxBw = 125.0, float freqDev = 50.0, int8_t power = 13, uint8_t currentLimit = 100, bool enableOOK = false);
+    int16_t beginFSK(float freq = 915.0, float br = 48.0, float rxBw = 125.0, float freqDev = 50.0, int8_t power = 13, uint8_t currentLimit = 100, uint16_t preambleLength = 16, bool enableOOK = false);
 
     // configuration methods
 
@@ -252,7 +254,7 @@ class SX1272: public SX127x {
     int16_t setBandwidthRaw(uint8_t newBandwidth);
     int16_t setSpreadingFactorRaw(uint8_t newSpreadingFactor);
     int16_t setCodingRateRaw(uint8_t newCodingRate);
-    
+
     int16_t configFSK();
 
   private:
diff --git a/src/modules/SX1278.cpp b/src/modules/SX1278.cpp
index 36ccef39..7f6ad28a 100644
--- a/src/modules/SX1278.cpp
+++ b/src/modules/SX1278.cpp
@@ -51,9 +51,9 @@ int16_t SX1278::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync
   return(state);
 }
 
-int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t currentLimit, bool enableOOK) {
+int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t currentLimit, uint16_t preambleLength, bool enableOOK) {
   // execute common part
-  int16_t state = SX127x::beginFSK(SX1278_CHIP_VERSION, br, freqDev, rxBw, currentLimit, enableOOK);
+  int16_t state = SX127x::beginFSK(SX1278_CHIP_VERSION, br, freqDev, rxBw, currentLimit, preambleLength, enableOOK);
   if(state != ERR_NONE) {
     return(state);
   }
@@ -364,13 +364,14 @@ int16_t SX1278::setDataShaping(float sh) {
   int16_t state = SX127x::standby();
 
   // set data shaping
+  sh *= 10.0;
   if(abs(sh - 0.0) <= 0.001) {
     state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_NO_SHAPING, 6, 5);
-  } else if(abs(sh - 0.3) <= 0.001) {
+  } else if(abs(sh - 3.0) <= 0.001) {
     state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_FSK_GAUSSIAN_0_3, 6, 5);
-  } else if(abs(sh - 0.5) <= 0.001) {
+  } else if(abs(sh - 5.0) <= 0.001) {
     state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_FSK_GAUSSIAN_0_5, 6, 5);
-  } else if(abs(sh - 1.0) <= 0.001) {
+  } else if(abs(sh - 10.0) <= 0.001) {
     state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_FSK_GAUSSIAN_1_0, 6, 5);
   } else {
     return(ERR_INVALID_DATA_SHAPING);
diff --git a/src/modules/SX1278.h b/src/modules/SX1278.h
index 0786b45f..937b0c58 100644
--- a/src/modules/SX1278.h
+++ b/src/modules/SX1278.h
@@ -157,11 +157,13 @@ class SX1278: public SX127x {
       \param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA.
       Set to 0 to disable OCP (not recommended).
 
+      \param preambleLength Length of FSK preamble in bits.
+
       \param enableOOK Use OOK modulation instead of FSK.
 
       \returns \ref status_codes
     */
-    int16_t beginFSK(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 125.0, int8_t power = 13, uint8_t currentLimit = 100, bool enableOOK = false);
+    int16_t beginFSK(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 125.0, int8_t power = 13, uint8_t currentLimit = 100,  uint16_t preambleLength = 16, bool enableOOK = false);
 
     // configuration methods
 
@@ -261,7 +263,7 @@ class SX1278: public SX127x {
     int16_t setBandwidthRaw(uint8_t newBandwidth);
     int16_t setSpreadingFactorRaw(uint8_t newSpreadingFactor);
     int16_t setCodingRateRaw(uint8_t newCodingRate);
-    
+
     int16_t configFSK();
 
   private:
diff --git a/src/modules/SX127x.cpp b/src/modules/SX127x.cpp
index ce5a84dc..e9af0db6 100644
--- a/src/modules/SX127x.cpp
+++ b/src/modules/SX127x.cpp
@@ -1,7 +1,8 @@
 #include "SX127x.h"
 
-SX127x::SX127x(Module* mod) : PhysicalLayer(SX127X_CRYSTAL_FREQ, SX127X_DIV_EXPONENT) {
+SX127x::SX127x(Module* mod) : PhysicalLayer(SX127X_CRYSTAL_FREQ, SX127X_DIV_EXPONENT, SX127X_MAX_PACKET_LENGTH) {
   _mod = mod;
+  _packetLengthQueried = false;
 }
 
 int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint8_t currentLimit, uint16_t preambleLength) {
@@ -48,7 +49,7 @@ int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint8_t currentLimi
   return(state);
 }
 
-int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxBw, uint8_t currentLimit, bool enableOOK) {
+int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxBw, uint8_t currentLimit, uint16_t preambleLength, bool enableOOK) {
   // set module properties
   _mod->init(USE_SPI, INT_BOTH);
 
@@ -95,6 +96,12 @@ int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxB
     return(state);
   }
 
+  // set preamble length
+  state = SX127x::setPreambleLength(preambleLength);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
   // default sync word value 0x2D01 is the same as the default in LowPowerLab RFM69 library
   uint8_t syncWord[] = {0x2D, 0x01};
   state = setSyncWord(syncWord, 2);
@@ -130,7 +137,7 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) {
     float crc = (float)(_mod->SPIgetRegValue(SX127X_REG_MODEM_CONFIG_2, 2, 2) >> 2);
     float n_pre = (float)((_mod->SPIgetRegValue(SX127X_REG_PREAMBLE_MSB) << 8) | _mod->SPIgetRegValue(SX127X_REG_PREAMBLE_LSB));
     float n_pay = 8.0 + max(ceil((8.0 * (float)len - 4.0 * (float)_sf + 28.0 + 16.0 * crc - 20.0 * ih)/(4.0 * (float)_sf - 8.0 * de)) * (float)_cr, 0.0);
-    uint32_t timeout = ceil(symbolLength * (n_pre + n_pay + 4.25) * 1.5);
+    uint32_t timeout = ceil(symbolLength * (n_pre + n_pay + 4.25) * 1500.0);
 
     // start transmission
     state = startTransmit(data, len, addr);
@@ -139,17 +146,17 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) {
     }
 
     // wait for packet transmission or timeout
-    uint32_t start = millis();
+    uint32_t start = micros();
     while(!digitalRead(_mod->getInt0())) {
-      if(millis() - start > timeout) {
+      if(micros() - start > timeout) {
         clearIRQFlags();
         return(ERR_TX_TIMEOUT);
       }
     }
-    uint32_t elapsed = millis() - start;
+    uint32_t elapsed = micros() - start;
 
     // update data rate
-    _dataRate = (len*8.0)/((float)elapsed/1000.0);
+    _dataRate = (len*8.0)/((float)elapsed/1000000.0);
 
     // clear interrupt flags
     clearIRQFlags();
@@ -157,8 +164,8 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) {
     return(ERR_NONE);
 
   } else if(modem == SX127X_FSK_OOK) {
-    // calculate timeout (150 % of expected time-on-air)
-    uint32_t timeout = (uint32_t)((((float)(len * 8)) / (_br * 1000.0)) * 1500.0);
+    // calculate timeout (5ms + 150 % of expected time-on-air)
+    uint32_t timeout = 5000 + (uint32_t)((((float)(len * 8)) / (_br * 1000.0)) * 1500000.0);
 
     // start transmission
     state = startTransmit(data, len, addr);
@@ -167,9 +174,9 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) {
     }
 
     // wait for transmission end or timeout
-    uint32_t start = millis();
+    uint32_t start = micros();
     while(!digitalRead(_mod->getInt0())) {
-      if(millis() - start > timeout) {
+      if(micros() - start > timeout) {
         clearIRQFlags();
         standby();
         return(ERR_TX_TIMEOUT);
@@ -195,7 +202,7 @@ int16_t SX127x::receive(uint8_t* data, size_t len) {
   int16_t modem = getActiveModem();
   if(modem == SX127X_LORA) {
     // set mode to receive
-    state = startReceive(SX127X_RXSINGLE);
+    state = startReceive(len, SX127X_RXSINGLE);
     if(state != ERR_NONE) {
       return(state);
     }
@@ -208,19 +215,12 @@ int16_t SX127x::receive(uint8_t* data, size_t len) {
       }
     }
 
-    // read the received data
-    return(readData(data, len));
-
   } else if(modem == SX127X_FSK_OOK) {
     // calculate timeout (500 % of expected time-one-air)
-    size_t maxLen = len;
-    if(len == 0) {
-      maxLen = 0xFF;
-    }
-    uint32_t timeout = (uint32_t)((((float)(maxLen * 8)) / (_br * 1000.0)) * 5000.0);
+    uint32_t timeout = (uint32_t)((((float)(len * 8)) / (_br * 1000.0)) * 5000.0);
 
     // set mode to receive
-    state = startReceive(SX127X_RX);
+    state = startReceive(len, SX127X_RX);
     if(state != ERR_NONE) {
       return(state);
     }
@@ -233,12 +233,12 @@ int16_t SX127x::receive(uint8_t* data, size_t len) {
         return(ERR_RX_TIMEOUT);
       }
     }
-
-    // read the received data
-    return(readData(data, len));
   }
 
-  return(ERR_UNKNOWN);
+  // read the received data
+  state = readData(data, len);
+
+  return(state);
 }
 
 int16_t SX127x::scanChannel() {
@@ -351,7 +351,7 @@ int16_t SX127x::packetMode() {
   return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_2, SX127X_DATA_MODE_PACKET, 6, 6));
 }
 
-int16_t SX127x::startReceive(uint8_t mode) {
+int16_t SX127x::startReceive(uint8_t len, uint8_t mode) {
   // set mode to standby
   int16_t state = setMode(SX127X_STANDBY);
 
@@ -360,6 +360,11 @@ int16_t SX127x::startReceive(uint8_t mode) {
     // set DIO pin mapping
     state |= _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_RX_DONE | SX127X_DIO1_RX_TIMEOUT, 7, 4);
 
+    // set expected packet length for SF6
+    if(_sf == 6) {
+      state |= _mod->SPIsetRegValue(SX127X_REG_PAYLOAD_LENGTH, len);
+    }
+
     // clear interrupt flags
     clearIRQFlags();
 
@@ -469,7 +474,13 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
 int16_t SX127x::readData(uint8_t* data, size_t len) {
   int16_t modem = getActiveModem();
   size_t length = len;
+
   if(modem == SX127X_LORA) {
+    // len set to maximum indicates unknown packet length, read the number of actually received bytes
+    if(len == SX127X_MAX_PACKET_LENGTH) {
+      length = getPacketLength();
+    }
+
     // check integrity CRC
     if(_mod->SPIgetRegValue(SX127X_REG_IRQ_FLAGS, 5, 5) == SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR) {
       // clear interrupt flags
@@ -478,14 +489,9 @@ int16_t SX127x::readData(uint8_t* data, size_t len) {
       return(ERR_CRC_MISMATCH);
     }
 
-    // get packet length
-    if(_sf != 6) {
-      length = _mod->SPIgetRegValue(SX127X_REG_RX_NB_BYTES);
-    }
-
   } else if(modem == SX127X_FSK_OOK) {
-    // get packet length
-    length = _mod->SPIreadRegister(SX127X_REG_FIFO);
+    // read packet length (always required in FSK)
+    length = getPacketLength();
 
     // check address filtering
     uint8_t filter = _mod->SPIgetRegValue(SX127X_REG_PACKET_CONFIG_1, 2, 1);
@@ -495,16 +501,16 @@ int16_t SX127x::readData(uint8_t* data, size_t len) {
   }
 
   // read packet data
-  if(len == 0) {
-    // argument len equal to zero indicates String call, which means dynamically allocated data array
-    // dispose of the original and create a new one
-    delete[] data;
-    data = new uint8_t[length + 1];
-  }
   _mod->SPIreadRegisterBurst(SX127X_REG_FIFO, length, data);
 
-  // add terminating null
-  data[length] = 0;
+  // dump bytes that weren't requested
+  size_t packetLength = getPacketLength();
+  if(packetLength > length) {
+    clearFIFO(packetLength - length);
+  }
+
+  // clear internal flag so getPacketLength can return the new packet length
+  _packetLengthQueried = false;
 
   // clear interrupt flags
   clearIRQFlags();
@@ -550,23 +556,33 @@ int16_t SX127x::setCurrentLimit(uint8_t currentLimit) {
 }
 
 int16_t SX127x::setPreambleLength(uint16_t preambleLength) {
-  // check active modem
-  if(getActiveModem() != SX127X_LORA) {
-    return(ERR_WRONG_MODEM);
-  }
-
-  // check allowed range
-  if(preambleLength < 6) {
-    return(ERR_INVALID_PREAMBLE_LENGTH);
-  }
-
   // set mode to standby
   int16_t state = setMode(SX127X_STANDBY);
+  if(state != ERR_NONE) {
+    return(state);
+  }
 
-  // set preamble length
-  state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_MSB, (preambleLength & 0xFF00) >> 8);
-  state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_LSB, preambleLength & 0x00FF);
-  return(state);
+  // check active modem
+  uint8_t modem = getActiveModem();
+  if(modem == SX127X_LORA) {
+    // check allowed range
+    if(preambleLength < 6) {
+      return(ERR_INVALID_PREAMBLE_LENGTH);
+    }
+
+    // set preamble length
+    state = _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_MSB, (preambleLength & 0xFF00) >> 8);
+    state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_LSB, preambleLength & 0x00FF);
+    return(state);
+
+  } else if(modem == SX127X_FSK_OOK) {
+    // set preamble length
+    state = _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_MSB_FSK, (preambleLength & 0xFF00) >> 8);
+    state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_LSB_FSK, preambleLength & 0x00FF);
+    return(state);
+  }
+
+  return(ERR_UNKNOWN);
 }
 
 float SX127x::getFrequencyError(bool autoCorrect) {
@@ -740,7 +756,6 @@ int16_t SX127x::setRxBandwidth(float rxBw) {
       }
     }
   }
-
   return(ERR_UNKNOWN);
 }
 
@@ -862,6 +877,30 @@ int16_t SX127x::setFrequencyRaw(float newFreq) {
   return(state);
 }
 
+size_t SX127x::getPacketLength(bool update) {
+  int16_t modem = getActiveModem();
+
+  if(modem == SX127X_LORA) {
+    if(_sf != 6) {
+      // get packet length for SF7 - SF12
+      return(_mod->SPIreadRegister(SX127X_REG_RX_NB_BYTES));
+
+    } else {
+      // return the maximum value for SF6
+      return(SX127X_MAX_PACKET_LENGTH);
+    }
+
+  } else if(modem == SX127X_FSK_OOK) {
+    // get packet length
+    if(!_packetLengthQueried && update) {
+      _packetLength = _mod->SPIreadRegister(SX127X_REG_FIFO);
+      _packetLengthQueried = true;
+    }
+  }
+
+  return(_packetLength);
+}
+
 int16_t SX127x::config() {
   // turn off frequency hopping
   int16_t state = _mod->SPIsetRegValue(SX127X_REG_HOP_PERIOD, SX127X_HOP_PERIOD_OFF);
@@ -879,12 +918,18 @@ int16_t SX127x::configFSK() {
   _mod->SPIwriteRegister(SX127X_REG_IRQ_FLAGS_2, SX127X_FLAG_FIFO_OVERRUN);
 
   // set packet configuration
-  state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_PACKET_VARIABLE | SX127X_DC_FREE_NONE | SX127X_CRC_ON | SX127X_CRC_AUTOCLEAR_ON, 7, 3);
+  state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_PACKET_VARIABLE | SX127X_DC_FREE_WHITENING | SX127X_CRC_ON | SX127X_CRC_AUTOCLEAR_ON | SX127X_ADDRESS_FILTERING_OFF | SX127X_CRC_WHITENING_TYPE_CCITT, 7, 0);
   state |= _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_2, SX127X_DATA_MODE_PACKET | SX127X_IO_HOME_OFF, 6, 5);
   if(state != ERR_NONE) {
     return(state);
   }
 
+  // set preamble polarity
+  state =_mod->SPIsetRegValue(SX127X_REG_SYNC_CONFIG, SX127X_PREAMBLE_POLARITY_55, 5, 5);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
   // set FIFO threshold
   state = _mod->SPIsetRegValue(SX127X_REG_FIFO_THRESH, SX127X_TX_START_FIFO_NOT_EMPTY, 7, 7);
   state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_THRESH, SX127X_FIFO_THRESH, 5, 0);
@@ -901,7 +946,7 @@ int16_t SX127x::configFSK() {
   }
 
   // enable preamble detector and set preamble length
-  state = _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_DETECT, SX127X_PREAMBLE_DETECTOR_ON | SX127X_PREAMBLE_DETECTOR_1_BYTE | SX127X_PREAMBLE_DETECTOR_TOL);
+  state = _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_DETECT, SX127X_PREAMBLE_DETECTOR_ON | SX127X_PREAMBLE_DETECTOR_2_BYTE | SX127X_PREAMBLE_DETECTOR_TOL);
   state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_MSB_FSK, SX127X_PREAMBLE_SIZE_MSB);
   state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_LSB_FSK, SX127X_PREAMBLE_SIZE_LSB);
   if(state != ERR_NONE) {
@@ -969,6 +1014,13 @@ void SX127x::clearIRQFlags() {
   }
 }
 
+void SX127x::clearFIFO(size_t count) {
+  while(count) {
+    _mod->SPIreadRegister(SX127X_REG_FIFO);
+    count--;
+  }
+}
+
 #ifdef RADIOLIB_DEBUG
 void SX127x::regDump() {
   Serial.println();
diff --git a/src/modules/SX127x.h b/src/modules/SX127x.h
index 063d5b0f..5236e595 100644
--- a/src/modules/SX127x.h
+++ b/src/modules/SX127x.h
@@ -9,6 +9,7 @@
 // SX127x physical layer properties
 #define SX127X_CRYSTAL_FREQ                           32.0
 #define SX127X_DIV_EXPONENT                           19
+#define SX127X_MAX_PACKET_LENGTH                      256
 
 // SX127x series common LoRa registers
 #define SX127X_REG_FIFO                               0x00
@@ -574,11 +575,13 @@ class SX127x: public PhysicalLayer {
 
       \param currentLimit Trim value for OCP (over current protection) in mA.
 
+      \param preambleLength Length of FSK preamble in bits.
+
       \param enableOOK Flag to specify OOK mode. This modulation is similar to FSK.
 
       \returns \ref status_codes
     */
-    int16_t beginFSK(uint8_t chipVersion, float br, float freqDev, float rxBw, uint8_t currentLimit, bool enableOOK);
+    int16_t beginFSK(uint8_t chipVersion, float br, float freqDev, float rxBw, uint8_t currentLimit, uint16_t preambleLength, bool enableOOK);
 
     /*!
       \brief Binary transmit method. Will transmit arbitrary binary data up to 255 bytes long using %LoRa or up to 63 bytes using FSK modem.
@@ -686,14 +689,16 @@ class SX127x: public PhysicalLayer {
     /*!
       \brief Interrupt-driven receive method. DIO0 will be activated when full valid packet is received.
 
+      \param len Expected length of packet to be received. Required for LoRa spreading factor 6.
+
       \param mode Receive mode to be used. Defaults to RxContinuous.
 
       \returns \ref status_codes
     */
-    int16_t startReceive(uint8_t mode = SX127X_RXCONTINUOUS);
+    int16_t startReceive(uint8_t len = 0, uint8_t mode = SX127X_RXCONTINUOUS);
 
     /*!
-      \brief Reads data that was received after calling startReceive method.
+      \brief Reads data that was received after calling startReceive method. This method reads len characters.
 
       \param data Pointer to array to save the received binary data.
 
@@ -828,6 +833,15 @@ class SX127x: public PhysicalLayer {
     */
     int16_t setOOK(bool enableOOK);
 
+     /*!
+      \brief Query modem for the packet length of received payload.
+
+      \param update Update received packet length. Will return cached value when set to false.
+
+      \returns Length of last received packet in bytes.
+    */
+    size_t getPacketLength(bool update = true);
+
     #ifdef RADIOLIB_DEBUG
       void regDump();
     #endif
@@ -849,13 +863,17 @@ class SX127x: public PhysicalLayer {
     int16_t getActiveModem();
     int16_t directMode();
 
+
   private:
     float _dataRate;
+    size_t _packetLength;
+    bool _packetLengthQueried; // FSK packet length is the first byte in FIFO, length can only be queried once
 
     bool findChip(uint8_t ver);
     int16_t setMode(uint8_t mode);
     int16_t setActiveModem(uint8_t modem);
     void clearIRQFlags();
+    void clearFIFO(size_t count); // used mostly to clear remaining bytes in FIFO after a packet read
 };
 
 #endif
diff --git a/src/protocols/PhysicalLayer.cpp b/src/protocols/PhysicalLayer.cpp
index 0fe2f268..23fb798c 100644
--- a/src/protocols/PhysicalLayer.cpp
+++ b/src/protocols/PhysicalLayer.cpp
@@ -1,8 +1,9 @@
 #include "PhysicalLayer.h"
 
-PhysicalLayer::PhysicalLayer(float crysFreq, uint8_t divExp) {
+PhysicalLayer::PhysicalLayer(float crysFreq, uint8_t divExp, size_t maxPacketLength) {
   _crystalFreq = crysFreq;
   _divExponent = divExp;
+  _maxPacketLength = maxPacketLength;
 }
 
 int16_t PhysicalLayer::transmit(__FlashStringHelper* fstr, uint8_t addr) {
@@ -49,30 +50,76 @@ int16_t PhysicalLayer::startTransmit(const char* str, uint8_t addr) {
 }
 
 int16_t PhysicalLayer::readData(String& str, size_t len) {
-  // create temporary array to store received data
-  char* data = new char[len + 1];
-  int16_t state = readData((uint8_t*)data, len);
+  int16_t state = ERR_NONE;
 
-  // if packet was received successfully, copy data into String
-  if(state == ERR_NONE) {
-    str = String(data);
+  // read the number of actually received bytes
+  size_t length = getPacketLength();
+
+  if((len < length) && (len != 0)) {
+    // user requested less bytes than were received, this is allowed (but frowned upon)
+    // requests for more data than were received will only return the number of actually received bytes (unlike PhysicalLayer::receive())
+    length = len;
   }
 
+  // build a temporary buffer
+  uint8_t* data = new uint8_t[length + 1];
+  if(!data) {
+    return(ERR_MEMORY_ALLOCATION_FAILED);
+  }
+
+  // read the received data
+  state = readData(data, length);
+
+  if(state == ERR_NONE) {
+    // add null terminator
+    data[length] = 0;
+
+    // initialize Arduino String class
+    str = String((char*)data);
+  }
+
+  // deallocate temporary buffer
   delete[] data;
+
   return(state);
 }
 
 int16_t PhysicalLayer::receive(String& str, size_t len) {
-  // create temporary array to store received data
-  char* data = new char[len + 1];
-  int16_t state = receive((uint8_t*)data, len);
+  int16_t state = ERR_NONE;
 
-  // if packet was received successfully, copy data into String
-  if(state == ERR_NONE) {
-    str = String(data);
+  // user can override the length of data to read
+  size_t length = len;
+
+  if(len == 0) {
+    // unknown packet length, set to maximum
+    length = _maxPacketLength;
   }
 
+  // build a temporary buffer
+  uint8_t* data = new uint8_t[length + 1];
+  if(!data) {
+    return(ERR_MEMORY_ALLOCATION_FAILED);
+  }
+
+  // attempt packet reception
+  state = receive(data, length);
+
+  if(state == ERR_NONE) {
+    // read the number of actually received bytes (for unknown packets)
+    if(len == 0) {
+      length = getPacketLength(false);
+    }
+
+    // add null terminator
+    data[length] = 0;
+
+    // initialize Arduino String class
+    str = String((char*)data);
+  }
+
+  // deallocate temporary buffer
   delete[] data;
+
   return(state);
 }
 
diff --git a/src/protocols/PhysicalLayer.h b/src/protocols/PhysicalLayer.h
index 6aa8a0fa..51c01b98 100644
--- a/src/protocols/PhysicalLayer.h
+++ b/src/protocols/PhysicalLayer.h
@@ -21,8 +21,10 @@ class PhysicalLayer {
       \param crysFreq Frequency of crystal oscillator inside the module in MHz.
 
       \param divExp Exponent of module frequency divider.
+
+      \param maxPacketLength Maximum length of packet that can be received by the module-
     */
-    PhysicalLayer(float crysFreq, uint8_t divExp);
+    PhysicalLayer(float crysFreq, uint8_t divExp, size_t maxPacketLength);
 
     // basic methods
 
@@ -77,12 +79,19 @@ class PhysicalLayer {
 
       \param str Address of Arduino String to save the received data.
 
-      \param len Expected number of characters in the message.
+      \param len Expected number of characters in the message. Leave as 0 if expecting a unknown size packet
 
       \returns \ref status_codes
     */
     int16_t receive(String& str, size_t len = 0);
 
+    /*!
+      \brief Sets module to standby.
+      
+      \returns \ref status_codes
+    */
+    virtual int16_t standby() = 0;
+
     /*!
       \brief Binary receive method. Must be implemented in module class.
 
@@ -94,13 +103,6 @@ class PhysicalLayer {
     */
     virtual int16_t receive(uint8_t* data, size_t len) = 0;
 
-    /*!
-      \brief Sets module to standby.
-
-      \returns \ref status_codes
-    */
-    virtual int16_t standby() = 0;
-
     /*!
       \brief Interrupt-driven Arduino String transmit method. Unlike the standard transmit method, this one is non-blocking.
       Interrupt pin will be activated when transmission finishes.
@@ -168,7 +170,7 @@ class PhysicalLayer {
 
       \returns \ref status_codes
     */
-    virtual int16_t transmitDirect(uint32_t frf = 0) = 0;
+    virtual int16_t transmitDirect(uint32_t FRF = 0) = 0;
 
     /*!
       \brief Enables direct reception mode on pins DIO1 (clock) and DIO2 (data). Must be implemented in module class.
@@ -204,9 +206,19 @@ class PhysicalLayer {
     */
     uint8_t getDivExponent();
 
+    /*!
+     \brief Query modem for the packet length of received payload.
+
+     \param update Update received packet length. Will return cached value when set to false.
+
+     \returns Length of last received packet in bytes.
+   */
+   virtual size_t getPacketLength(bool update = true) = 0;
+
   private:
     float _crystalFreq;
     uint8_t _divExponent;
+    size_t _maxPacketLength;
 };
 
 #endif

From fa9da6b967c872bc2ed3a03a41f869aa07cf2894 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 16 Jun 2019 14:33:46 +0200
Subject: [PATCH 044/106] [CC1101] Implemented getPacketLength

---
 .../CC1101_Transmit/CC1101_Transmit.ino       |  6 ++--
 src/modules/CC1101.cpp                        | 28 +++++++++++++------
 src/modules/CC1101.h                          | 13 +++++++++
 3 files changed, 35 insertions(+), 12 deletions(-)

diff --git a/examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino b/examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino
index f9272993..87bde6e1 100644
--- a/examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino
+++ b/examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino
@@ -58,11 +58,11 @@ void loop() {
 
   if (state == ERR_NONE) {
     // the packet was successfully transmitted
-    Serial.println(F(" success!"));
+    Serial.println(F("success!"));
 
   } else if (state == ERR_PACKET_TOO_LONG) {
-    // the supplied packet was longer than 255 bytes
-    Serial.println(F(" too long!"));
+    // the supplied packet was longer than 64 bytes
+    Serial.println(F("too long!"));
 
   } else {
     // some other error occurred
diff --git a/src/modules/CC1101.cpp b/src/modules/CC1101.cpp
index 3e87c7c0..3bf6d4f9 100644
--- a/src/modules/CC1101.cpp
+++ b/src/modules/CC1101.cpp
@@ -1,7 +1,8 @@
 #include "CC1101.h"
 
-CC1101::CC1101(Module* module) : PhysicalLayer(CC1101_CRYSTAL_FREQ, CC1101_DIV_EXPONENT) {
+CC1101::CC1101(Module* module) : PhysicalLayer(CC1101_CRYSTAL_FREQ, CC1101_DIV_EXPONENT, CC1101_MAX_PACKET_LENGTH) {
   _mod = module;
+  _packetLengthQueried = false;
 }
 
 int16_t CC1101::begin(float freq, float br, float rxBw, float freqDev, int8_t power) {
@@ -175,7 +176,7 @@ void CC1101::setGdo2Action(void (*func)(void), uint8_t dir) {
 
 int16_t CC1101::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
   // check packet length
-  if(len > 63) {
+  if(len > CC1101_MAX_PACKET_LENGTH) {
     return(ERR_PACKET_TOO_LONG);
   }
 
@@ -230,7 +231,10 @@ int16_t CC1101::startReceive() {
 
 int16_t CC1101::readData(uint8_t* data, size_t len) {
   // get packet length
-  size_t length = SPIreadRegister(CC1101_REG_RXBYTES) - 2;
+  size_t length = len;
+  if(len == CC1101_MAX_PACKET_LENGTH) {
+    length = getPacketLength();
+  }
 
   // check address filtering
   uint8_t filter = SPIgetRegValue(CC1101_REG_PKTCTRL1, 1, 0);
@@ -239,12 +243,6 @@ int16_t CC1101::readData(uint8_t* data, size_t len) {
   }
 
   // read packet data
-  if(len == 0) {
-    // argument len equal to zero indicates String call, which means dynamically allocated data array
-    // dispose of the original and create a new one
-    delete[] data;
-    data = new uint8_t[length + 1];
-  }
   SPIreadRegisterBurst(CC1101_REG_FIFO, length, data);
 
   // read RSSI byte
@@ -260,6 +258,9 @@ int16_t CC1101::readData(uint8_t* data, size_t len) {
   // flush Rx FIFO
   SPIsendCommand(CC1101_CMD_FLUSH_RX);
 
+  // clear internal flag so getPacketLength can return the new packet length
+  _packetLengthQueried = false;
+
   // set mode to standby
   standby();
 
@@ -474,6 +475,15 @@ uint8_t CC1101::getLQI() {
   return(_rawLQI);
 }
 
+size_t CC1101::getPacketLength(bool update) {
+  if(!_packetLengthQueried && update) {
+    _packetLength = _mod->SPIreadRegister(CC1101_REG_FIFO);
+    _packetLengthQueried = true;
+  }
+
+  return(_packetLength);
+}
+
 int16_t CC1101::config() {
   // enable automatic frequency synthesizer calibration
   int16_t state = SPIsetRegValue(CC1101_REG_MCSM0, CC1101_FS_AUTOCAL_IDLE_TO_RXTX, 5, 4);
diff --git a/src/modules/CC1101.h b/src/modules/CC1101.h
index f512fdf8..a2060819 100644
--- a/src/modules/CC1101.h
+++ b/src/modules/CC1101.h
@@ -9,6 +9,7 @@
 // CC1101 physical layer properties
 #define CC1101_CRYSTAL_FREQ                           26.0
 #define CC1101_DIV_EXPONENT                           16
+#define CC1101_MAX_PACKET_LENGTH                      63
 
 // CC1101 SPI commands
 #define CC1101_CMD_READ                               0b10000000
@@ -729,6 +730,15 @@ class CC1101: public PhysicalLayer {
     */
     uint8_t getLQI();
 
+     /*!
+      \brief Query modem for the packet length of received payload.
+
+      \param update Update received packet length. Will return cached value when set to false.
+
+      \returns Length of last received packet in bytes.
+    */
+    size_t getPacketLength(bool update = true);
+
   private:
     Module* _mod;
 
@@ -736,6 +746,9 @@ class CC1101: public PhysicalLayer {
     uint8_t _rawRSSI;
     uint8_t _rawLQI;
 
+    size_t _packetLength;
+    bool _packetLengthQueried;
+
     int16_t config();
     int16_t directMode();
     void getExpMant(float target, uint16_t mantOffset, uint8_t divExp, uint8_t expMax, uint8_t& exp, uint8_t& mant);

From 3ad5dfa44462bc08f0f2558341c2d38688d4507f Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 16 Jun 2019 14:33:59 +0200
Subject: [PATCH 045/106] [RF69] Implemented getPacketLength

---
 examples/RF69/RF69_Transmit/RF69_Transmit.ino |  4 +-
 src/modules/RF69.cpp                          | 64 +++++++++++--------
 src/modules/RF69.h                            | 17 ++++-
 3 files changed, 57 insertions(+), 28 deletions(-)

diff --git a/examples/RF69/RF69_Transmit/RF69_Transmit.ino b/examples/RF69/RF69_Transmit/RF69_Transmit.ino
index dca4f975..eb818b22 100644
--- a/examples/RF69/RF69_Transmit/RF69_Transmit.ino
+++ b/examples/RF69/RF69_Transmit/RF69_Transmit.ino
@@ -59,11 +59,11 @@ void loop() {
 
   if (state == ERR_NONE) {
     // the packet was successfully transmitted
-    Serial.println(F(" success!"));
+    Serial.println(F("success!"));
 
   } else if (state == ERR_PACKET_TOO_LONG) {
     // the supplied packet was longer than 64 bytes
-    Serial.println(F(" too long!"));
+    Serial.println(F("too long!"));
 
   } else {
     // some other error occurred
diff --git a/src/modules/RF69.cpp b/src/modules/RF69.cpp
index 91918416..951e6aba 100644
--- a/src/modules/RF69.cpp
+++ b/src/modules/RF69.cpp
@@ -1,8 +1,9 @@
 #include "RF69.h"
 
-RF69::RF69(Module* module) : PhysicalLayer(RF69_CRYSTAL_FREQ, RF69_DIV_EXPONENT)  {
+RF69::RF69(Module* module) : PhysicalLayer(RF69_CRYSTAL_FREQ, RF69_DIV_EXPONENT, RF69_MAX_PACKET_LENGTH)  {
   _mod = module;
   _tempOffset = 0;
+  _packetLengthQueried = false;
 }
 
 int16_t RF69::begin(float freq, float br, float rxBw, float freqDev, int8_t power) {
@@ -102,7 +103,7 @@ int16_t RF69::transmit(uint8_t* data, size_t len, uint8_t addr) {
 
 int16_t RF69::receive(uint8_t* data, size_t len) {
   // start reception
-  int16_t state = startReceive();
+  int16_t state = startReceive(true);
   if(state != ERR_NONE) {
     return(state);
   }
@@ -191,27 +192,31 @@ int16_t RF69::disableAES() {
   return(_mod->SPIsetRegValue(RF69_REG_PACKET_CONFIG_2, RF69_AES_OFF, 0, 0));
 }
 
-int16_t RF69::startReceive() {
+int16_t RF69::startReceive(bool timeout) {
   // set mode to standby
   int16_t state = setMode(RF69_STANDBY);
 
-  // set DIO pin mapping
-  state |= _mod->SPIsetRegValue(RF69_REG_DIO_MAPPING_1, RF69_DIO0_PACK_PAYLOAD_READY, 7, 6);
-
-  // clear interrupt flags
-  clearIRQFlags();
-
-  // disable RX timeouts
-  state |= _mod->SPIsetRegValue(RF69_REG_RX_TIMEOUT_1, RF69_TIMEOUT_RX_START_OFF);
-  state |= _mod->SPIsetRegValue(RF69_REG_RX_TIMEOUT_2, RF69_TIMEOUT_RSSI_THRESH_OFF);
+  // set RX timeouts and DIO pin mapping
+  if(timeout) {
+    state = _mod->SPIsetRegValue(RF69_REG_DIO_MAPPING_1, RF69_DIO0_PACK_PAYLOAD_READY | RF69_DIO1_PACK_TIMEOUT, 7, 4);
+    state |= _mod->SPIsetRegValue(RF69_REG_RX_TIMEOUT_1, RF69_TIMEOUT_RX_START);
+    state |= _mod->SPIsetRegValue(RF69_REG_RX_TIMEOUT_2, RF69_TIMEOUT_RSSI_THRESH);
+  } else {
+    state = _mod->SPIsetRegValue(RF69_REG_DIO_MAPPING_1, RF69_DIO0_PACK_PAYLOAD_READY, 7, 6);
+    state |= _mod->SPIsetRegValue(RF69_REG_RX_TIMEOUT_1, RF69_TIMEOUT_RX_START_OFF);
+    state |= _mod->SPIsetRegValue(RF69_REG_RX_TIMEOUT_2, RF69_TIMEOUT_RSSI_THRESH_OFF);
+  }
   if(state != ERR_NONE) {
     return(state);
   }
 
+  // clear interrupt flags
+  clearIRQFlags();
+
   // set mode to receive
-  state = setMode(RF69_RX);
-  state |= _mod->SPIsetRegValue(RF69_REG_TEST_PA1, RF69_PA1_NORMAL);
+  state = _mod->SPIsetRegValue(RF69_REG_TEST_PA1, RF69_PA1_NORMAL);
   state |= _mod->SPIsetRegValue(RF69_REG_TEST_PA2, RF69_PA2_NORMAL);
+  state |= setMode(RF69_RX);
 
   return(state);
 }
@@ -226,7 +231,7 @@ void RF69::setDio1Action(void (*func)(void)) {
 
 int16_t RF69::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
   // check packet length
-  if(len > 64) {
+  if(len > RF69_MAX_PACKET_LENGTH) {
     return(ERR_PACKET_TOO_LONG);
   }
 
@@ -264,7 +269,10 @@ int16_t RF69::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
 
 int16_t RF69::readData(uint8_t* data, size_t len) {
   // get packet length
-  size_t length = _mod->SPIreadRegister(RF69_REG_FIFO);
+  size_t length = len;
+  if(len == RF69_MAX_PACKET_LENGTH) {
+    length = getPacketLength();
+  }
 
   // check address filtering
   uint8_t filter = _mod->SPIgetRegValue(RF69_REG_PACKET_CONFIG_1, 2, 1);
@@ -273,12 +281,6 @@ int16_t RF69::readData(uint8_t* data, size_t len) {
   }
 
   // read packet data
-  if(len == 0) {
-    // argument len equal to zero indicates String call, which means dynamically allocated data array
-    // dispose of the original and create a new one
-    delete[] data;
-    data = new uint8_t[length + 1];
-  }
   _mod->SPIreadRegisterBurst(RF69_REG_FIFO, length, data);
 
   // add terminating null
@@ -287,6 +289,9 @@ int16_t RF69::readData(uint8_t* data, size_t len) {
   // update RSSI
   lastPacketRSSI = -1.0 * (_mod->SPIgetRegValue(RF69_REG_RSSI_VALUE)/2.0);
 
+  // clear internal flag so getPacketLength can return the new packet length
+  _packetLengthQueried = false;
+
   // clear interrupt flags
   clearIRQFlags();
 
@@ -443,9 +448,9 @@ int16_t RF69::setFrequencyDeviation(float freqDev) {
 
   // set frequency deviation from carrier frequency
   uint32_t base = 1;
-  uint32_t FDEV = (freqDev * (base << 19)) / 32000;
-  int16_t state = _mod->SPIsetRegValue(RF69_REG_FDEV_MSB, (FDEV & 0xFF00) >> 8, 5, 0);
-  state |= _mod->SPIsetRegValue(RF69_REG_FDEV_LSB, FDEV & 0x00FF, 7, 0);
+  uint32_t fdev = (freqDev * (base << 19)) / 32000;
+  int16_t state = _mod->SPIsetRegValue(RF69_REG_FDEV_MSB, (fdev & 0xFF00) >> 8, 5, 0);
+  state |= _mod->SPIsetRegValue(RF69_REG_FDEV_LSB, fdev & 0x00FF, 7, 0);
 
   return(state);
 }
@@ -556,6 +561,15 @@ int16_t RF69::getTemperature() {
   return(0 - (rawTemp + _tempOffset));
 }
 
+size_t RF69::getPacketLength(bool update) {
+  if(!_packetLengthQueried && update) {
+    _packetLength = _mod->SPIreadRegister(RF69_REG_FIFO);
+    _packetLengthQueried = true;
+  }
+
+  return(_packetLength);
+}
+
 int16_t RF69::config() {
   int16_t state = ERR_NONE;
 
diff --git a/src/modules/RF69.h b/src/modules/RF69.h
index 26a959a2..15fe18dc 100644
--- a/src/modules/RF69.h
+++ b/src/modules/RF69.h
@@ -9,6 +9,7 @@
 // RF69 physical layer properties
 #define RF69_CRYSTAL_FREQ                             32.0
 #define RF69_DIV_EXPONENT                             19
+#define RF69_MAX_PACKET_LENGTH                        64
 
 // RF69 register map
 #define RF69_REG_FIFO                                 0x00
@@ -580,9 +581,11 @@ class RF69: public PhysicalLayer {
     /*!
       \brief Interrupt-driven receive method. GDO0 will be activated when full packet is received.
 
+      \param timeout Enable module-driven timeout. Set to false for listen mode.
+
       \returns \ref status_codes
     */
-    int16_t startReceive();
+    int16_t startReceive(bool timeout = false);
 
     /*!
       \brief Reads data received after calling startReceive method.
@@ -694,6 +697,15 @@ class RF69: public PhysicalLayer {
     */
     int16_t getTemperature();
 
+     /*!
+      \brief Query modem for the packet length of received payload.
+
+      \param update Update received packet length. Will return cached value when set to false.
+
+      \returns Length of last received packet in bytes.
+    */
+    size_t getPacketLength(bool update = true);
+
   protected:
     Module* _mod;
 
@@ -701,6 +713,9 @@ class RF69: public PhysicalLayer {
     float _rxBw;
     int16_t _tempOffset;
 
+    size_t _packetLength;
+    bool _packetLengthQueried;
+
     int16_t config();
     int16_t directMode();
 

From 94301c9043e05176635748d659758c56f7b85ef9 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 16 Jun 2019 14:34:06 +0200
Subject: [PATCH 046/106] [nRF24] Implemented getPacketLength

---
 src/modules/nRF24.cpp | 27 ++++++++++++++-------------
 src/modules/nRF24.h   | 10 ++++++++++
 2 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/src/modules/nRF24.cpp b/src/modules/nRF24.cpp
index 59e13a04..f4df1cbe 100644
--- a/src/modules/nRF24.cpp
+++ b/src/modules/nRF24.cpp
@@ -1,6 +1,6 @@
 #include "nRF24.h"
 
-nRF24::nRF24(Module* mod) : PhysicalLayer(NRF24_CRYSTAL_FREQ, NRF24_DIV_EXPONENT) {
+nRF24::nRF24(Module* mod) : PhysicalLayer(NRF24_CRYSTAL_FREQ, NRF24_DIV_EXPONENT, NRF24_MAX_PACKET_LENGTH) {
   _mod = mod;
 }
 
@@ -161,7 +161,7 @@ int16_t nRF24::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
   (void)addr;
 
   // check packet length
-  if(len > 32) {
+  if(len > NRF24_MAX_PACKET_LENGTH) {
     return(ERR_PACKET_TOO_LONG);
   }
 
@@ -239,19 +239,13 @@ int16_t nRF24::readData(uint8_t* data, size_t len) {
      return(state);
   }
 
-  // read payload length
-  uint8_t buff[1];
-  SPItransfer(NRF24_CMD_READ_RX_PAYLOAD_WIDTH, false, NULL, buff, 1);
-
-  size_t length = buff[0];
+  // get packet length
+  size_t length = len;
+  if(len == NRF24_MAX_PACKET_LENGTH) {
+    length = getPacketLength();
+  }
 
   // read packet data
-  if(len == 0) {
-    // argument 'len' equal to zero indicates String call, which means dynamically allocated data array
-    // dispose of the original and create a new one
-    delete[] data;
-    data = new uint8_t[length + 1];
-  }
   SPIreadRxPayload(data, length);
 
   // add terminating null
@@ -479,6 +473,13 @@ int16_t nRF24::setFrequencyDeviation(float freqDev) {
   return(ERR_NONE);
 }
 
+size_t nRF24::getPacketLength(bool update) {
+  (void)update;
+  uint8_t length = 0;
+  SPItransfer(NRF24_CMD_READ_RX_PAYLOAD_WIDTH, false, NULL, &length, 1);
+  return((size_t)length);
+}
+
 void nRF24::clearIRQ() {
   // clear status bits
   _mod->SPIsetRegValue(NRF24_REG_STATUS, NRF24_RX_DR | NRF24_TX_DS | NRF24_MAX_RT, 6, 4);
diff --git a/src/modules/nRF24.h b/src/modules/nRF24.h
index dfbded20..6b577576 100644
--- a/src/modules/nRF24.h
+++ b/src/modules/nRF24.h
@@ -9,6 +9,7 @@
 // nRF24 physical layer properties (dummy only)
 #define NRF24_CRYSTAL_FREQ                            1.0
 #define NRF24_DIV_EXPONENT                            0
+#define NRF24_MAX_PACKET_LENGTH                       32
 
 // nRF24 SPI commands
 #define NRF24_CMD_READ                                0b00000000
@@ -398,6 +399,15 @@ class nRF24: public PhysicalLayer {
     */
     int16_t setFrequencyDeviation(float freqDev);
 
+     /*!
+      \brief Query modem for the packet length of received payload.
+
+      \param update Update received packet length. Will return cached value when set to false.
+
+      \returns Length of last received packet in bytes.
+    */
+    size_t getPacketLength(bool update = true);
+
   private:
     Module* _mod;
 

From 5527573692705e219691415660a11072b2246bb3 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 16 Jun 2019 14:34:19 +0200
Subject: [PATCH 047/106] [SX126x] Implemented getPacketLength

---
 .../SX126x_Transmit/SX126x_Transmit.ino       | 32 ++++++++++---------
 src/modules/SX126x.cpp                        | 29 +++++++----------
 src/modules/SX126x.h                          | 10 ++++++
 3 files changed, 39 insertions(+), 32 deletions(-)

diff --git a/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino b/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino
index bdd9d929..65d24eec 100644
--- a/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino
+++ b/examples/SX126x/SX126x_Transmit/SX126x_Transmit.ino
@@ -56,20 +56,22 @@ void setup() {
   //       control must be enabled by calling
   //       setTCXO() and specifying the reference
   //       voltage.
+  
   /*
-  Serial.print(F("[SX1262] Setting TCXO reference ... "));
-  // enable TCXO
-  // reference voltage:           1.6 V
-  // timeout:                     5000 us
-  state = lora.setTCXO(1.6);
-  if (state == ERR_NONE) {
-    Serial.println(F("success!"));
-  } else {
-    Serial.print(F("failed, code "));
-    Serial.println(state);
-    while (true);
-  }
+    Serial.print(F("[SX1262] Setting TCXO reference ... "));
+    // enable TCXO
+    // reference voltage:           1.6 V
+    // timeout:                     5000 us
+    state = lora.setTCXO(1.6);
+    if (state == ERR_NONE) {
+      Serial.println(F("success!"));
+    } else {
+      Serial.print(F("failed, code "));
+      Serial.println(state);
+      while (true);
+    }
   */
+  
 }
 
 void loop() {
@@ -90,7 +92,7 @@ void loop() {
 
   if (state == ERR_NONE) {
     // the packet was successfully transmitted
-    Serial.println(F(" success!"));
+    Serial.println(F("success!"));
 
     // print measured data rate
     Serial.print(F("[SX1262] Datarate:\t"));
@@ -99,11 +101,11 @@ void loop() {
 
   } else if (state == ERR_PACKET_TOO_LONG) {
     // the supplied packet was longer than 256 bytes
-    Serial.println(F(" too long!"));
+    Serial.println(F("too long!"));
 
   } else if (state == ERR_TX_TIMEOUT) {
     // timeout occured while transmitting packet
-    Serial.println(F(" timeout!"));
+    Serial.println(F("timeout!"));
 
   } else {
     // some other error occurred
diff --git a/src/modules/SX126x.cpp b/src/modules/SX126x.cpp
index 7332b340..b6efdc00 100644
--- a/src/modules/SX126x.cpp
+++ b/src/modules/SX126x.cpp
@@ -1,6 +1,6 @@
 #include "SX126x.h"
 
-SX126x::SX126x(Module* mod) : PhysicalLayer(SX126X_CRYSTAL_FREQ, SX126X_DIV_EXPONENT) {
+SX126x::SX126x(Module* mod) : PhysicalLayer(SX126X_CRYSTAL_FREQ, SX126X_DIV_EXPONENT, SX126X_MAX_PACKET_LENGTH) {
   _mod = mod;
 }
 
@@ -137,7 +137,7 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) {
   }
 
   // check packet length
-  if(len >= 256) {
+  if(len > SX126X_MAX_PACKET_LENGTH) {
     return(ERR_PACKET_TOO_LONG);
   }
 
@@ -359,7 +359,7 @@ int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
   (void)addr;
 
   // check packet length
-  if(len >= 256) {
+  if(len > SX126X_MAX_PACKET_LENGTH) {
     return(ERR_PACKET_TOO_LONG);
   }
 
@@ -447,22 +447,10 @@ int16_t SX126x::readData(uint8_t* data, size_t len) {
   }
 
   // get packet length
-  uint8_t rxBufStatus[2];
-  int16_t state = SPIreadCommand(SX126X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2);
-  if(state != ERR_NONE) {
-    return(state);
-  }
-
-  size_t length = rxBufStatus[0];
+  size_t length = getPacketLength();
 
   // read packet data
-  if(len == 0) {
-    // argument 'len' equal to zero indicates String call, which means dynamically allocated data array
-    // dispose of the original and create a new one
-    delete[] data;
-    data = new uint8_t[length + 1];
-  }
-  state = readBuffer(data, length);
+  int16_t state = readBuffer(data, length);
   if(state != ERR_NONE) {
     return(state);
   }
@@ -872,6 +860,13 @@ float SX126x::getSNR() {
   return(snrPkt/4.0);
 }
 
+size_t SX126x::getPacketLength(bool update) {
+  (void)update;
+  uint8_t rxBufStatus[2];
+  SPIreadCommand(SX126X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2);
+  return((size_t)rxBufStatus[0]);
+}
+
 int16_t SX126x::setTCXO(float voltage, uint32_t timeout) {
   // set mode to standby
   standby();
diff --git a/src/modules/SX126x.h b/src/modules/SX126x.h
index e2d995bc..696c728e 100644
--- a/src/modules/SX126x.h
+++ b/src/modules/SX126x.h
@@ -9,6 +9,7 @@
 // SX126X physical layer properties
 #define SX126X_CRYSTAL_FREQ                           32.0
 #define SX126X_DIV_EXPONENT                           25
+#define SX126X_MAX_PACKET_LENGTH                      255
 
 // SX126X SPI commands
 // operational modes commands
@@ -685,6 +686,15 @@ class SX126x: public PhysicalLayer {
     */
     float getSNR();
 
+     /*!
+      \brief Query modem for the packet length of received payload.
+
+      \param update Update received packet length. Will return cached value when set to false.
+
+      \returns Length of last received packet in bytes.
+    */
+    size_t getPacketLength(bool update = true);
+
   protected:
     // SX1276x SPI command implementations
     int16_t setTx(uint32_t timeout = 0);

From acd5297e067793fc8e78793fb73fd65a1716c265 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 16 Jun 2019 14:34:36 +0200
Subject: [PATCH 048/106] Advnaced version to 1.2.0

---
 library.properties | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library.properties b/library.properties
index c362f3b2..5c36bd45 100644
--- a/library.properties
+++ b/library.properties
@@ -1,5 +1,5 @@
 name=RadioLib
-version=1.1.0
+version=1.2.0
 author=Jan Gromes <gromes.jan@gmail.com>
 maintainer=Jan Gromes <gromes.jan@gmail.com>
 sentence=Universal wireless communication library for Arduino

From 49eb062fcfcc42bcedd601d910b2e0965ec9e5e9 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sat, 22 Jun 2019 16:36:44 +0200
Subject: [PATCH 049/106] Added more debug output

---
 src/Module.cpp | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/src/Module.cpp b/src/Module.cpp
index 5c238519..a623b61d 100644
--- a/src/Module.cpp
+++ b/src/Module.cpp
@@ -207,17 +207,30 @@ void Module::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* da
 
   // send SPI register address with access command
   _spi->transfer(reg | cmd);
+  DEBUG_PRINT(reg | cmd, HEX);
+  DEBUG_PRINT('\t');
+  DEBUG_PRINT(reg | cmd, BIN);
+  DEBUG_PRINT('\t');
 
   // send data or get response
   if(cmd == SPIwriteCommand) {
     for(size_t n = 0; n < numBytes; n++) {
       _spi->transfer(dataOut[n]);
+      DEBUG_PRINT(dataOut[n], HEX);
+      DEBUG_PRINT('\t');
+      DEBUG_PRINT(dataOut[n], BIN);
+      DEBUG_PRINT('\t');
     }
   } else if (cmd == SPIreadCommand) {
     for(size_t n = 0; n < numBytes; n++) {
       dataIn[n] = _spi->transfer(0x00);
+      DEBUG_PRINT(dataIn[n], HEX);
+      DEBUG_PRINT('\t');
+      DEBUG_PRINT(dataIn[n], BIN);
+      DEBUG_PRINT('\t');
     }
   }
+  DEBUG_PRINTLN();
 
   // release CS
   digitalWrite(_cs, HIGH);

From 2ca26d1a605f3c739fc6545775c368c9ecda7d10 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sat, 22 Jun 2019 16:36:58 +0200
Subject: [PATCH 050/106] Fixed format

---
 src/TypeDef.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/TypeDef.h b/src/TypeDef.h
index 73c81802..931426ac 100644
--- a/src/TypeDef.h
+++ b/src/TypeDef.h
@@ -139,7 +139,7 @@
   \brief There was an unexpected, unknown error. If you see this, something went incredibly wrong.
   Your Arduino may be possessed, contact your local exorcist to resolve this error.
 */
-#define ERR_UNKNOWN                            -1
+#define ERR_UNKNOWN                           -1
 
 // SX127x/RFM9x status codes
 

From e1c79af18b756179c12f1eb53a4476261e788cd8 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sat, 22 Jun 2019 16:37:57 +0200
Subject: [PATCH 051/106] [SX126x] Added OCP config reset

---
 src/modules/SX1262.cpp |  27 ++++----
 src/modules/SX1268.cpp |  27 ++++----
 src/modules/SX126x.cpp | 138 ++++++++++++++++++++++-------------------
 src/modules/SX126x.h   |  30 ++++-----
 4 files changed, 112 insertions(+), 110 deletions(-)

diff --git a/src/modules/SX1262.cpp b/src/modules/SX1262.cpp
index 218751ab..0bcce47d 100644
--- a/src/modules/SX1262.cpp
+++ b/src/modules/SX1262.cpp
@@ -6,7 +6,7 @@ SX1262::SX1262(Module* mod) : SX126x(mod) {
 
 int16_t SX1262::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, int8_t power, float currentLimit, uint16_t preambleLength) {
   // execute common part
-  int16_t state = SX126x::begin(bw, sf, cr, syncWord, preambleLength);
+  int16_t state = SX126x::begin(bw, sf, cr, syncWord, currentLimit, preambleLength);
   if(state != ERR_NONE) {
     return(state);
   }
@@ -22,18 +22,12 @@ int16_t SX1262::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint16_t syn
     return(state);
   }
 
-  // OCP must be configured after PA
-  state = SX126x::setCurrentLimit(currentLimit);
-  if(state != ERR_NONE) {
-    return(state);
-  }
-
   return(state);
 }
 
 int16_t SX1262::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, float currentLimit, uint16_t preambleLength, float dataShaping) {
   // execute common part
-  int16_t state = SX126x::beginFSK(br, freqDev, rxBw, preambleLength, dataShaping);
+  int16_t state = SX126x::beginFSK(br, freqDev, rxBw, currentLimit, preambleLength, dataShaping);
   if(state != ERR_NONE) {
     return(state);
   }
@@ -49,12 +43,6 @@ int16_t SX1262::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t
     return(state);
   }
 
-  // OCP must be configured after PA
-  state = SX126x::setCurrentLimit(currentLimit);
-  if(state != ERR_NONE) {
-    return(state);
-  }
-
   return(state);
 }
 
@@ -101,6 +89,13 @@ int16_t SX1262::setOutputPower(int8_t power) {
     return(ERR_INVALID_OUTPUT_POWER);
   }
 
+  // get current OCP configuration
+  uint8_t ocp = 0;
+  int16_t state = readRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
   // enable high power PA for output power higher than 14 dBm
   if(power > 13) {
     SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1262);
@@ -111,5 +106,7 @@ int16_t SX1262::setOutputPower(int8_t power) {
   // set output power
   // TODO power ramp time configuration
   SX126x::setTxParams(power);
-  return(ERR_NONE);
+
+  // restore OCP configuration
+  return(writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1));
 }
diff --git a/src/modules/SX1268.cpp b/src/modules/SX1268.cpp
index 95718f0c..c0b01a80 100644
--- a/src/modules/SX1268.cpp
+++ b/src/modules/SX1268.cpp
@@ -6,7 +6,7 @@ SX1268::SX1268(Module* mod) : SX126x(mod) {
 
 int16_t SX1268::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, int8_t power, float currentLimit, uint16_t preambleLength) {
   // execute common part
-  int16_t state = SX126x::begin(bw, sf, cr, syncWord, preambleLength);
+  int16_t state = SX126x::begin(bw, sf, cr, syncWord, currentLimit, preambleLength);
   if(state != ERR_NONE) {
     return(state);
   }
@@ -22,17 +22,11 @@ int16_t SX1268::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint16_t syn
     return(state);
   }
 
-  // OCP must be configured after PA
-  state = SX126x::setCurrentLimit(currentLimit);
-  if(state != ERR_NONE) {
-    return(state);
-  }
-
   return(state);
 }
 int16_t SX1268::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, float currentLimit, uint16_t preambleLength, float dataShaping) {
   // execute common part
-  int16_t state = SX126x::beginFSK(br, freqDev, rxBw, preambleLength, dataShaping);
+  int16_t state = SX126x::beginFSK(br, freqDev, rxBw, currentLimit, preambleLength, dataShaping);
   if(state != ERR_NONE) {
     return(state);
   }
@@ -48,12 +42,6 @@ int16_t SX1268::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t
     return(state);
   }
 
-  // OCP must be configured after PA
-  state = SX126x::setCurrentLimit(currentLimit);
-  if(state != ERR_NONE) {
-    return(state);
-  }
-
   return(state);
 }
 
@@ -94,11 +82,20 @@ int16_t SX1268::setOutputPower(int8_t power) {
     return(ERR_INVALID_OUTPUT_POWER);
   }
 
+  // get current OCP configuration
+  uint8_t ocp = 0;
+  int16_t state = readRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
   // enable high power PA
   SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1268);
 
   // set output power
   // TODO power ramp time configuration
   SX126x::setTxParams(power);
-  return(ERR_NONE);
+
+  // restore OCP configuration
+  return(writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1));
 }
diff --git a/src/modules/SX126x.cpp b/src/modules/SX126x.cpp
index b6efdc00..5a90af65 100644
--- a/src/modules/SX126x.cpp
+++ b/src/modules/SX126x.cpp
@@ -447,7 +447,10 @@ int16_t SX126x::readData(uint8_t* data, size_t len) {
   }
 
   // get packet length
-  size_t length = getPacketLength();
+  size_t length = len;
+  if(len == SX126X_MAX_PACKET_LENGTH) {
+    length = getPacketLength();
+  }
 
   // read packet data
   int16_t state = readBuffer(data, length);
@@ -774,67 +777,67 @@ int16_t SX126x::disableAddressFiltering() {
   return(setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp));
 }
 
-int16_t SX126x::setCRC(bool enableCRC) {
-  // check active modem
-  if(getPacketType() != SX126X_PACKET_TYPE_LORA) {
-    return(ERR_WRONG_MODEM);
-  }
-
-  // update packet parameters
-  if(enableCRC) {
-    _crcType = SX126X_LORA_CRC_ON;
-  } else {
-    _crcType = SX126X_LORA_CRC_OFF;
-  }
-  return(setPacketParams(_preambleLength, _crcType));
-}
-
 int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool inverted) {
   // check active modem
-  if(getPacketType() != SX126X_PACKET_TYPE_GFSK) {
-    return(ERR_WRONG_MODEM);
-  }
+  uint8_t modem = getPacketType();
+
+  if(modem == SX126X_PACKET_TYPE_GFSK) {
+    // update packet parameters
+    switch(len) {
+      case 0:
+        _crcTypeFSK = SX126X_GFSK_CRC_OFF;
+        break;
+      case 1:
+        if(inverted) {
+          _crcTypeFSK = SX126X_GFSK_CRC_1_BYTE_INV;
+        } else {
+          _crcTypeFSK = SX126X_GFSK_CRC_1_BYTE;
+        }
+        break;
+      case 2:
+        if(inverted) {
+          _crcTypeFSK = SX126X_GFSK_CRC_2_BYTE_INV;
+        } else {
+          _crcTypeFSK = SX126X_GFSK_CRC_2_BYTE;
+        }
+        break;
+      default:
+        return(ERR_INVALID_CRC_CONFIGURATION);
+    }
+
+    int16_t state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp);
+    if(state != ERR_NONE) {
+      return(state);
+    }
+
+    // write initial CRC value
+    uint8_t data[2] = {(uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF)};
+    state = writeRegister(SX126X_REG_CRC_INITIAL_MSB, data, 2);
+    if(state != ERR_NONE) {
+      return(state);
+    }
+
+    // write CRC polynomial value
+    data[0] = (uint8_t)((polynomial >> 8) & 0xFF);
+    data[1] = (uint8_t)(polynomial & 0xFF);
+    state = writeRegister(SX126X_REG_CRC_POLYNOMIAL_MSB, data, 2);
 
-  // update packet parameters
-  switch(len) {
-    case 0:
-      _crcTypeFSK = SX126X_GFSK_CRC_OFF;
-      break;
-    case 1:
-      if(inverted) {
-        _crcTypeFSK = SX126X_GFSK_CRC_1_BYTE_INV;
-      } else {
-        _crcTypeFSK = SX126X_GFSK_CRC_1_BYTE;
-      }
-      break;
-    case 2:
-      if(inverted) {
-        _crcTypeFSK = SX126X_GFSK_CRC_2_BYTE_INV;
-      } else {
-        _crcTypeFSK = SX126X_GFSK_CRC_2_BYTE;
-      }
-      break;
-    default:
-      return(ERR_INVALID_CRC_CONFIGURATION);
-  }
-  int16_t state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp);
-  if(state != ERR_NONE) {
     return(state);
+
+  } else if(modem == SX126X_PACKET_TYPE_LORA) {
+    // LoRa CRC doesn't allow to set CRC polynomial, inital value, or inversion
+
+    // update packet parameters
+    if(len) {
+      _crcType = SX126X_LORA_CRC_ON;
+    } else {
+      _crcType = SX126X_LORA_CRC_OFF;
+    }
+
+    return(setPacketParams(_preambleLength, _crcType));
   }
 
-  // write initial CRC value
-  uint8_t data[2] = {(uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF)};
-  state = writeRegister(SX126X_REG_CRC_INITIAL_MSB, data, 2);
-  if(state != ERR_NONE) {
-    return(state);
-  }
-
-  // write CRC polynomial value
-  data[0] = (uint8_t)((polynomial >> 8) & 0xFF);
-  data[1] = (uint8_t)(polynomial & 0xFF);
-  state = writeRegister(SX126X_REG_CRC_POLYNOMIAL_MSB, data, 2);
-
-  return(state);
+  return(ERR_UNKNOWN);
 }
 
 float SX126x::getDataRate() {
@@ -944,6 +947,11 @@ int16_t SX126x::writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) {
   return(state);
 }
 
+int16_t SX126x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) {
+  uint8_t cmd[] = {SX126X_CMD_READ_REGISTER, (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF)};
+  return(SX126x::SPItransfer(cmd, 3, false, NULL, data, numBytes, true));
+}
+
 int16_t SX126x::writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) {
   uint8_t* dat = new uint8_t[1 + numBytes];
   dat[0] = offset;
@@ -1148,14 +1156,16 @@ int16_t SX126x::config(uint8_t modem) {
 }
 
 int16_t SX126x::SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy) {
-  return(SX126x::SPItransfer(cmd, true, data, NULL, numBytes, waitForBusy));
+  uint8_t cmdBuffer[] = {cmd};
+  return(SX126x::SPItransfer(cmdBuffer, 1, true, data, NULL, numBytes, waitForBusy));
 }
 
 int16_t SX126x::SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy) {
-  return(SX126x::SPItransfer(cmd, false, NULL, data, numBytes, waitForBusy));
+  uint8_t cmdBuffer[] = {cmd};
+  return(SX126x::SPItransfer(cmdBuffer, 1, false, NULL, data, numBytes, waitForBusy));
 }
 
-int16_t SX126x::SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy) {
+int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy) {
   // get pointer to used SPI interface and the settings
   SPIClass* spi = _mod->getSpi();
   SPISettings spiSettings = _mod->getSpiSettings();
@@ -1168,10 +1178,12 @@ int16_t SX126x::SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t*
   digitalWrite(_mod->getCs(), LOW);
   spi->beginTransaction(spiSettings);
 
-  // send command byte
-  spi->transfer(cmd);
-  DEBUG_PRINT(cmd, HEX);
-  DEBUG_PRINT('\t');
+  // send command byte(s)
+  for(uint8_t n = 0; n < cmdLen; n++) {
+    spi->transfer(cmd[n]);
+    DEBUG_PRINT(cmd[n], HEX);
+    DEBUG_PRINT('\t');
+  }
 
   // variable to save error during SPI transfer
   uint8_t status = 0;
diff --git a/src/modules/SX126x.h b/src/modules/SX126x.h
index 696c728e..0662e508 100644
--- a/src/modules/SX126x.h
+++ b/src/modules/SX126x.h
@@ -351,11 +351,13 @@ class SX126x: public PhysicalLayer {
 
       \param syncWord 2-byte LoRa sync word.
 
+      \param currentLimit Current protection limit in mA.
+
       \param preambleLength LoRa preamble length in symbols. Allowed values range from 1 to 65535.
 
       \returns \ref status_codes
     */
-    int16_t begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, uint16_t preambleLength);
+    int16_t begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, float currentLimit, uint16_t preambleLength);
 
     /*!
       \brief Initialization method for FSK modem.
@@ -366,13 +368,15 @@ class SX126x: public PhysicalLayer {
 
       \param rxBw Receiver bandwidth in kHz. Allowed values are 4.8, 5.8, 7.3, 9.7, 11.7, 14.6, 19.5, 23.4, 29.3, 39.0, 46.9, 58.6, 78.2, 93.8, 117.3, 156.2, 187.2, 234.3, 312.0, 373.6 and 467.0 kHz.
 
+      \param currentLimit Current protection limit in mA.
+
       \param preambleLength FSK preamble length in bits. Allowed values range from 0 to 65535.
 
       \param dataShaping Time-bandwidth product of the Gaussian filter to be used for shaping. Allowed values are 0.3, 0.5, 0.7 and 1.0. Set to 0 to disable shaping.
 
       \returns \ref status_codes
     */
-    int16_t beginFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float dataShaping);
+    int16_t beginFSK(float br, float freqDev, float rxBw, float currentLimit, uint16_t preambleLength, float dataShaping);
 
     /*!
       \brief Blocking binary transmit method.
@@ -626,24 +630,15 @@ class SX126x: public PhysicalLayer {
     int16_t disableAddressFiltering();
 
     /*!
-      \brief Sets LoRa CRC.
+      \brief Sets CRC configuration.
 
-      \param enableCRC Enable or disable LoRa CRC.
+      \param len CRC length in bytes, Allowed values are 1 or 2, set to 0 to disable CRC.
 
-      \returns \ref status_codes
-    */
-    int16_t setCRC(bool enableCRC);
+      \param initial Initial CRC value. FSK only. Defaults to 0x1D0F (CCIT CRC).
 
-    /*!
-      \brief Sets FSK CRC configuration.
+      \param polynomial Polynomial for CRC calculation. FSK only. Defaults to 0x1021 (CCIT CRC).
 
-      \param len CRC length in bytes, Allowed values are 1 or 2, set to 0 to disable FSK CRC.
-
-      \param initial Initial CRC value. Defaults to 0x1D0F (CCIT CRC).
-
-      \param polynomial Polynomial for CRC calculation. Defaults to 0x1021 (CCIT CRC).
-
-      \param inverted Invert CRC bytes. Defaults to true (CCIT CRC)
+      \param inverted Invert CRC bytes. FSK only. Defaults to true (CCIT CRC).
 
       \returns \ref status_codes
     */
@@ -702,6 +697,7 @@ class SX126x: public PhysicalLayer {
     int16_t setCad();
     int16_t setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax = SX126X_PA_CONFIG_HP_MAX, uint8_t paLut = SX126X_PA_CONFIG_PA_LUT);
     int16_t writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes);
+    int16_t readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes);
     int16_t writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00);
     int16_t readBuffer(uint8_t* data, uint8_t numBytes);
     int16_t setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask = SX126X_IRQ_NONE, uint16_t dio3Mask = SX126X_IRQ_NONE);
@@ -742,7 +738,7 @@ class SX126x: public PhysicalLayer {
     // common low-level SPI interface
     int16_t SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
     int16_t SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
-    int16_t SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy);
+    int16_t SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy);
 };
 
 #endif

From bd21ddb7d85a9020b19f0a655e19057badd6d195 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sat, 22 Jun 2019 16:50:44 +0200
Subject: [PATCH 052/106] [SX126x] Fixed incorrect parameters

---
 src/modules/SX126x.cpp | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/src/modules/SX126x.cpp b/src/modules/SX126x.cpp
index 5a90af65..39dc1b44 100644
--- a/src/modules/SX126x.cpp
+++ b/src/modules/SX126x.cpp
@@ -4,7 +4,7 @@ SX126x::SX126x(Module* mod) : PhysicalLayer(SX126X_CRYSTAL_FREQ, SX126X_DIV_EXPO
   _mod = mod;
 }
 
-int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, uint16_t preambleLength) {
+int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, float currentLimit, uint16_t preambleLength) {
   // set module properties
   _mod->init(USE_SPI, INT_BOTH);
   pinMode(_mod->getRx(), INPUT);
@@ -53,6 +53,11 @@ int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, uint1
     return(state);
   }
 
+  state = setCurrentLimit(currentLimit);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
   state = setPreambleLength(preambleLength);
   if(state != ERR_NONE) {
     return(state);
@@ -64,7 +69,7 @@ int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, uint1
   return(state);
 }
 
-int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float dataShaping) {
+int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, float currentLimit, uint16_t preambleLength, float dataShaping) {
   // set module properties
   _mod->init(USE_SPI, INT_BOTH);
   pinMode(_mod->getRx(), INPUT);
@@ -107,6 +112,11 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL
     return(state);
   }
 
+  state = setCurrentLimit(currentLimit);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
   state = setDataShaping(dataShaping);
   if(state != ERR_NONE) {
     return(state);

From b0cd4b5125c74be5dce1254e70fa6dde673fb19e Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Tue, 2 Jul 2019 19:52:26 +0200
Subject: [PATCH 053/106] [SX126x] Removed redundant null terminator

---
 src/modules/SX126x.cpp | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/src/modules/SX126x.cpp b/src/modules/SX126x.cpp
index 39dc1b44..34348255 100644
--- a/src/modules/SX126x.cpp
+++ b/src/modules/SX126x.cpp
@@ -468,9 +468,6 @@ int16_t SX126x::readData(uint8_t* data, size_t len) {
     return(state);
   }
 
-  // add terminating null
-  data[length] = 0;
-
   // clear interrupt flags
   state = clearIrqStatus();
 

From ea1e6fea68460e2bcd066856a74d93119745bdb8 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Sun, 7 Jul 2019 19:48:55 +0200
Subject: [PATCH 054/106] [SX126x] Added BUSY timeout

---
 src/modules/SX126x.cpp | 18 +++++++++++++-----
 src/modules/SX126x.h   |  2 +-
 2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/src/modules/SX126x.cpp b/src/modules/SX126x.cpp
index 34348255..93327118 100644
--- a/src/modules/SX126x.cpp
+++ b/src/modules/SX126x.cpp
@@ -1172,14 +1172,18 @@ int16_t SX126x::SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, boo
   return(SX126x::SPItransfer(cmdBuffer, 1, false, NULL, data, numBytes, waitForBusy));
 }
 
-int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy) {
+int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy, uint32_t timeout) {
   // get pointer to used SPI interface and the settings
   SPIClass* spi = _mod->getSpi();
   SPISettings spiSettings = _mod->getSpiSettings();
 
   // ensure BUSY is low (state meachine ready)
-  // TODO timeout
-  while(digitalRead(_mod->getRx()));
+  uint32_t start = millis();
+  while(digitalRead(_mod->getRx())) {
+    if(millis() - start >= timeout) {
+      return(ERR_SPI_CMD_TIMEOUT);
+    }
+  }
 
   // start transfer
   digitalWrite(_mod->getCs(), LOW);
@@ -1242,10 +1246,14 @@ int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d
   digitalWrite(_mod->getCs(), HIGH);
 
   // wait for BUSY to go high and then low
-  // TODO timeout
   if(waitForBusy) {
     delayMicroseconds(1);
-    while(digitalRead(_mod->getRx()));
+    start = millis();
+    while(digitalRead(_mod->getRx())) {
+        if(millis() - start >= timeout) {
+          return(ERR_SPI_CMD_TIMEOUT);
+        }
+    }
   }
 
   // parse status
diff --git a/src/modules/SX126x.h b/src/modules/SX126x.h
index 0662e508..9f9253b4 100644
--- a/src/modules/SX126x.h
+++ b/src/modules/SX126x.h
@@ -738,7 +738,7 @@ class SX126x: public PhysicalLayer {
     // common low-level SPI interface
     int16_t SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
     int16_t SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
-    int16_t SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy);
+    int16_t SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy, uint32_t timeout = 5000);
 };
 
 #endif

From 3610e1c7c899c1b1dcac1c63a81efad286b3b6cd Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Thu, 11 Jul 2019 07:15:05 +0200
Subject: [PATCH 055/106] [SX127x] Sync with LoRaLib 8.1.1

---
 src/modules/SX127x.cpp | 63 +++++++++++++++++-------------------------
 1 file changed, 25 insertions(+), 38 deletions(-)

diff --git a/src/modules/SX127x.cpp b/src/modules/SX127x.cpp
index e9af0db6..59712207 100644
--- a/src/modules/SX127x.cpp
+++ b/src/modules/SX127x.cpp
@@ -126,6 +126,7 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) {
   int16_t state = setMode(SX127X_STANDBY);
 
   int16_t modem = getActiveModem();
+  uint32_t start;
   if(modem == SX127X_LORA) {
     // calculate timeout (150 % of expected time-one-air)
     float symbolLength = (float)(uint32_t(1) <<_sf) / (float)_bw;
@@ -146,26 +147,17 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) {
     }
 
     // wait for packet transmission or timeout
-    uint32_t start = micros();
+    start = micros();
     while(!digitalRead(_mod->getInt0())) {
       if(micros() - start > timeout) {
         clearIRQFlags();
         return(ERR_TX_TIMEOUT);
       }
     }
-    uint32_t elapsed = micros() - start;
-
-    // update data rate
-    _dataRate = (len*8.0)/((float)elapsed/1000000.0);
-
-    // clear interrupt flags
-    clearIRQFlags();
-
-    return(ERR_NONE);
 
   } else if(modem == SX127X_FSK_OOK) {
-    // calculate timeout (5ms + 150 % of expected time-on-air)
-    uint32_t timeout = 5000 + (uint32_t)((((float)(len * 8)) / (_br * 1000.0)) * 1500000.0);
+    // calculate timeout (5ms + 500 % of expected time-on-air)
+    uint32_t timeout = 5000000 + (uint32_t)((((float)(len * 8)) / (_br * 1000.0)) * 5000000.0);
 
     // start transmission
     state = startTransmit(data, len, addr);
@@ -174,7 +166,7 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) {
     }
 
     // wait for transmission end or timeout
-    uint32_t start = micros();
+    start = micros();
     while(!digitalRead(_mod->getInt0())) {
       if(micros() - start > timeout) {
         clearIRQFlags();
@@ -182,17 +174,17 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) {
         return(ERR_TX_TIMEOUT);
       }
     }
-
-    // clear interrupt flags
-    clearIRQFlags();
-
-    // set mode to standby to disable transmitter
-    state |= standby();
-
-    return(state);
   }
 
-  return(ERR_UNKNOWN);
+  // update data rate
+  uint32_t elapsed = micros() - start;
+  _dataRate = (len*8.0)/((float)elapsed/1000000.0);
+
+  // clear interrupt flags
+  clearIRQFlags();
+
+  // set mode to standby to disable transmitter
+  return(standby());
 }
 
 int16_t SX127x::receive(uint8_t* data, size_t len) {
@@ -217,7 +209,7 @@ int16_t SX127x::receive(uint8_t* data, size_t len) {
 
   } else if(modem == SX127X_FSK_OOK) {
     // calculate timeout (500 % of expected time-one-air)
-    uint32_t timeout = (uint32_t)((((float)(len * 8)) / (_br * 1000.0)) * 5000.0);
+    uint32_t timeout = (uint32_t)((((float)(len * 8)) / (_br * 1000.0)) * 5000000.0);
 
     // set mode to receive
     state = startReceive(len, SX127X_RX);
@@ -226,9 +218,9 @@ int16_t SX127x::receive(uint8_t* data, size_t len) {
     }
 
     // wait for packet reception or timeout
-    uint32_t start = millis();
+    uint32_t start = micros();
     while(!digitalRead(_mod->getInt0())) {
-      if(millis() - start > timeout) {
+      if(micros() - start > timeout) {
         clearIRQFlags();
         return(ERR_RX_TIMEOUT);
       }
@@ -571,14 +563,14 @@ int16_t SX127x::setPreambleLength(uint16_t preambleLength) {
     }
 
     // set preamble length
-    state = _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_MSB, (preambleLength & 0xFF00) >> 8);
-    state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_LSB, preambleLength & 0x00FF);
+    state = _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_MSB, (uint8_t)((preambleLength >> 8) & 0xFF));
+    state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_LSB, (uint8_t)(preambleLength & 0xFF));
     return(state);
 
   } else if(modem == SX127X_FSK_OOK) {
     // set preamble length
-    state = _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_MSB_FSK, (preambleLength & 0xFF00) >> 8);
-    state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_LSB_FSK, preambleLength & 0x00FF);
+    state = _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_MSB_FSK, (uint8_t)((preambleLength >> 8) & 0xFF));
+    state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_LSB_FSK, (uint8_t)(preambleLength & 0xFF));
     return(state);
   }
 
@@ -590,7 +582,7 @@ float SX127x::getFrequencyError(bool autoCorrect) {
   if(modem == SX127X_LORA) {
     // get raw frequency error
     uint32_t raw = (uint32_t)_mod->SPIgetRegValue(SX127X_REG_FEI_MSB, 3, 0) << 16;
-    raw |= _mod->SPIgetRegValue(SX127X_REG_FEI_MID) << 8;
+    raw |= (uint16_t)_mod->SPIgetRegValue(SX127X_REG_FEI_MID) << 8;
     raw |= _mod->SPIgetRegValue(SX127X_REG_FEI_LSB);
 
     uint32_t base = (uint32_t)2 << 23;
@@ -616,7 +608,7 @@ float SX127x::getFrequencyError(bool autoCorrect) {
 
   } else if(modem == SX127X_FSK_OOK) {
     // get raw frequency error
-    uint16_t raw = _mod->SPIgetRegValue(SX127X_REG_FEI_MSB_FSK) << 8;
+    uint16_t raw = (uint16_t)_mod->SPIgetRegValue(SX127X_REG_FEI_MSB_FSK) << 8;
     raw |= _mod->SPIgetRegValue(SX127X_REG_FEI_LSB_FSK);
 
     uint32_t base = 1;
@@ -650,11 +642,6 @@ float SX127x::getSNR() {
 }
 
 float SX127x::getDataRate() {
-  // check active modem
-  if(getActiveModem() != SX127X_LORA) {
-    return(0);
-  }
-
   return(_dataRate);
 }
 
@@ -766,7 +753,7 @@ int16_t SX127x::setSyncWord(uint8_t* syncWord, size_t len) {
   }
 
   // check constraints
-  if(len > 8) {
+  if((len > 8) || (len < 1)) {
     return(ERR_INVALID_SYNC_WORD);
   }
 
@@ -779,7 +766,7 @@ int16_t SX127x::setSyncWord(uint8_t* syncWord, size_t len) {
 
   // enable sync word recognition
   int16_t state = _mod->SPIsetRegValue(SX127X_REG_SYNC_CONFIG, SX127X_SYNC_ON, 4, 4);
-  state |= _mod->SPIsetRegValue(SX127X_REG_SYNC_CONFIG, len, 2, 0);
+  state |= _mod->SPIsetRegValue(SX127X_REG_SYNC_CONFIG, len - 1, 2, 0);
   if(state != ERR_NONE) {
     return(state);
   }

From 1f4ec7134c83bcdd78a5a2d2151afe201888cc80 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Thu, 11 Jul 2019 07:22:03 +0200
Subject: [PATCH 056/106] Advanced version to 1.2.1

---
 library.properties | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library.properties b/library.properties
index 5c36bd45..c807428d 100644
--- a/library.properties
+++ b/library.properties
@@ -1,5 +1,5 @@
 name=RadioLib
-version=1.2.0
+version=1.2.1
 author=Jan Gromes <gromes.jan@gmail.com>
 maintainer=Jan Gromes <gromes.jan@gmail.com>
 sentence=Universal wireless communication library for Arduino

From d6d12fc0989575d311f64a9fe790450423131e4b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Grome=C5=A1?= <jgromes@users.noreply.github.com>
Date: Fri, 12 Jul 2019 11:42:00 +0200
Subject: [PATCH 057/106] Update CONTRIBUTING.md

---
 CONTRIBUTING.md | 53 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a593561a..e073ea03 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -3,6 +3,10 @@
 First of all, thank you very much for taking the time to contribute! All feedback and ideas are greatly appreciated.
 To keep this library organized, please follow these rules.
 
+## Issues
+
+The following rules guide submission of new issues. These rules are in place mainly so that the issue author can get help as quickly as possible.
+
 1. **Questions are welcome, spam is not.**  
 Any issues without description will be considered spam and as such will be **CLOSED** and **LOCKED** immediately!
 2. **This repository has issue templates.**  
@@ -11,3 +15,52 @@ To report bugs or suggest new features, use the provided issue templates. Use th
 Issues with generic titles (e.g. "not working", "lora", etc.) will be **CLOSED** until the title is fixed, since the title is supposed to categorize the issue. The same applies for issues with very little information and extensive grammatical or formatting errors that make it difficult to find out what is the actual issue.
 4. **Issues deserve some attention too.**  
 Issues that are left for 2 weeks without response by the original author when asked for further information will be closed due to inactivity. This is to keep track of important issues, the author is encouraged to reopen the issue at a later date.
+
+## Code style guidelines
+
+I like pretty code! Or at least, I like *consistent* code style. When creating pull requests, please follow these style guidelines, they're in place to keep high code readability.
+
+1. **Bracket style**  
+This library uses the following style of bracket indentation (1TBS, or "javascript" style):
+```c++
+if (foo) {
+  bar();
+} else {
+  baz();
+}
+```
+
+2. **Tabs**  
+Use 2 space characters for tabs.
+
+3. **Single-line comments**  
+Comments can be very useful - and they can become the bane of readability. Every single-line comment should start at new line, have one space between comment delimiter `//` and the start of the comment itself. The comment should also start with a lower-case letter.
+```c++
+// this function does something
+foo("bar");
+
+// here it does something else
+foo(12345);
+```
+
+4. **Split code into blocks**  
+It is very easy to write code that machine can read. It is much harder to write one that humans can read. That's why it's a great idea to split code into blocks - even if the block is just a single line!
+```c++
+// build a temporary buffer (first block)
+uint8_t* data = new uint8_t[len + 1];
+if(!data) {
+  return(ERR_MEMORY_ALLOCATION_FAILED);
+}
+
+// read the received data (second block)
+state = readData(data, len);
+
+// add null terminator (third block)
+data[len] = 0;
+```
+
+5. **Doxygen**  
+If you're adding a new method, make sure to add appropriate Doxygen comments, so that the documentation is always complete.
+
+6. **Keywords**  
+This is an Arduino library, so it needs to comply with the Arduino library specification. To add a new keyword to the Arduino IDE syntax highlighting, add it to the keywords.txt file. **Use true tabs in keywords.txt! No spaces there!"

From 14e81052174588f06fb66892af8e8c95a75f126a Mon Sep 17 00:00:00 2001
From: Dmitriy <svetotled@gmail.com>
Date: Wed, 17 Jul 2019 21:12:29 +0300
Subject: [PATCH 058/106] ESP8266, not ES8266

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 5eb137d7..a8f36fc2 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github
 
 ### Supported modules:
 * __CC1101__ FSK radio module
-* __ES8266__ WiFi module
+* __ESP8266__ WiFi module
 * __HC05__ Bluetooth module
 * __JDY08__ BLE module
 * __nRF24L01__ 2.4 GHz module

From 6e0354f2e36e6a8ed03c4cdfcd069a34ec564e41 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Thu, 18 Jul 2019 18:05:40 +0200
Subject: [PATCH 059/106] Travis script update

---
 .travis.yml | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index a0fd7a94..77c202ac 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,7 @@
 env:
   global:
     # keep Arduino IDE version at 1.8.1 until https://github.com/per1234/arduino-ci-script/issues/1 is resolved
-    - ARDUINO_IDE_VERSION="1.8.1"
+    - ARDUINO_IDE_VERSION="1.8.9"
   matrix:
     - BOARD="arduino:avr:uno"
     - BOARD="arduino:avr:leonardo"
@@ -9,10 +9,17 @@ env:
 
 before_install:
   # install Arduino IDE
-  - wget http://downloads.arduino.cc/arduino-$ARDUINO_IDE_VERSION-linux64.tar.xz
+  - wget https://downloads.arduino.cc/arduino-$ARDUINO_IDE_VERSION-linux64.tar.xz
   - tar xf arduino-$ARDUINO_IDE_VERSION-linux64.tar.xz
   - mv arduino-$ARDUINO_IDE_VERSION $HOME/arduino-ide
   - export PATH=$PATH:$HOME/arduino-ide
+  # firewall Arduino IDE noise (https://github.com/per1234/arduino-ci-script/issues/1#issuecomment-504158113)
+  - sudo iptables -P INPUT DROP
+  - sudo iptables -P FORWARD DROP
+  - sudo iptables -P OUTPUT ACCEPT
+  - sudo iptables -A INPUT -i lo -j ACCEPT
+  - sudo iptables -A OUTPUT -o lo -j ACCEPT
+  - sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
 
 # create directory to save the library and create symbolic link
 install:

From 5ea9bc89fde8c1580e04e33ee8387757d42364ff Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Thu, 18 Jul 2019 18:09:13 +0200
Subject: [PATCH 060/106] Removed redundant comment

---
 .travis.yml | 1 -
 1 file changed, 1 deletion(-)

diff --git a/.travis.yml b/.travis.yml
index 77c202ac..1915d096 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,5 @@
 env:
   global:
-    # keep Arduino IDE version at 1.8.1 until https://github.com/per1234/arduino-ci-script/issues/1 is resolved
     - ARDUINO_IDE_VERSION="1.8.9"
   matrix:
     - BOARD="arduino:avr:uno"

From c43ba03d7dbe2c98a964688749f1dae4fdbbf639 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Tue, 23 Jul 2019 20:22:35 +0200
Subject: [PATCH 061/106] [HTTP] Fixed memory leak

---
 src/protocols/HTTP.cpp | 47 +++++++++++++++++++++---------------------
 1 file changed, 24 insertions(+), 23 deletions(-)

diff --git a/src/protocols/HTTP.cpp b/src/protocols/HTTP.cpp
index 35a52f2a..11b41d57 100644
--- a/src/protocols/HTTP.cpp
+++ b/src/protocols/HTTP.cpp
@@ -22,7 +22,7 @@ int16_t HTTPClient::get(const char* url, String& response) {
     host = new char[hostEnd - hostStart];
     strncpy(host, hostStart + 1, hostEnd - hostStart - 1);
     host[hostEnd - hostStart - 1] = 0x00;
-    
+
     // find the endpoint string
     endpoint = new char[url + strlen(url) - hostEnd + 1];
     strcpy(endpoint, hostEnd);
@@ -32,12 +32,12 @@ int16_t HTTPClient::get(const char* url, String& response) {
     host = new char[hostEnd - url + 1];
     strncpy(host, url, hostEnd - url);
     host[hostEnd - url] = 0x00;
-    
+
     // find the endpoint string
     endpoint = new char[url + strlen(url) - hostEnd + 1];
     strcpy(endpoint, hostEnd);
   }
-  
+
   // build the GET request
   char* request = new char[strlen(endpoint) + strlen(host) + 25];
   strcpy(request, "GET ");
@@ -45,9 +45,9 @@ int16_t HTTPClient::get(const char* url, String& response) {
   strcat(request, " HTTP/1.1\r\nHost: ");
   strcat(request, host);
   strcat(request, "\r\n\r\n");
-  
+
   delete[] endpoint;
-  
+
   // create TCP connection
   int16_t state = _tl->openTransportConnection(host, "TCP", _port);
   delete[] host;
@@ -55,22 +55,22 @@ int16_t HTTPClient::get(const char* url, String& response) {
     delete[] request;
     return(state);
   }
-  
+
   // send the GET request
   state = _tl->send(request);
   delete[] request;
   if(state != ERR_NONE) {
     return(state);
   }
-  
+
   //delay(1000);
-  
+
   // get the response length
   size_t numBytes = _tl->getNumBytes();
   if(numBytes == 0) {
     return(ERR_RESPONSE_MALFORMED_AT);
   }
-  
+
   // read the response
   char* raw = new char[numBytes];
   size_t rawLength = _tl->receive((uint8_t*)raw, numBytes);
@@ -78,14 +78,14 @@ int16_t HTTPClient::get(const char* url, String& response) {
     delete[] raw;
     return(ERR_RESPONSE_MALFORMED);
   }
-  
+
   // close the tl connection
   state = _tl->closeTransportConnection();
   if(state != ERR_NONE) {
     delete[] raw;
     return(state);
   }
-  
+
   // get the response body
   char* responseStart = strstr(raw, "\r\n");
   if(responseStart == NULL) {
@@ -97,7 +97,7 @@ int16_t HTTPClient::get(const char* url, String& response) {
   responseStr[raw + rawLength - responseStart - 2] = 0x00;
   response = String(responseStr);
   delete[] responseStr;
-  
+
   // return the HTTP status code
   char* statusStart = strchr(raw, ' ');
   delete[] raw;
@@ -123,7 +123,7 @@ int16_t HTTPClient::post(const char* url, const char* content, String& response,
     host = new char[hostEnd - hostStart];
     strncpy(host, hostStart + 1, hostEnd - hostStart - 1);
     host[hostEnd - hostStart - 1] = 0x00;
-    
+
     // find the endpoint string
     endpoint = new char[url + strlen(url) - hostEnd + 1];
     strcpy(endpoint, hostEnd);
@@ -133,12 +133,12 @@ int16_t HTTPClient::post(const char* url, const char* content, String& response,
     host = new char[hostEnd - url + 1];
     strncpy(host, url, hostEnd - url);
     host[hostEnd - url] = 0x00;
-    
+
     // find the endpoint string
     endpoint = new char[url + strlen(url) - hostEnd + 1];
     strcpy(endpoint, hostEnd);
   }
-  
+
   // build the POST request
   char contentLengthStr[8];
   itoa(strlen(content), contentLengthStr, 10);
@@ -154,29 +154,30 @@ int16_t HTTPClient::post(const char* url, const char* content, String& response,
   strcat(request, "\r\n\r\n");
   strcat(request, content);
   strcat(request, "\r\n\r\n");
-  
+
   delete[] endpoint;
-  
+
   // create TCP connection
   int16_t state = _tl->openTransportConnection(host, "TCP", _port);
   delete[] host;
   if(state != ERR_NONE) {
+    delete[] request;
     return(state);
   }
-  
+
   // send the POST request
   state = _tl->send(request);
   delete[] request;
   if(state != ERR_NONE) {
     return(state);
   }
-  
+
   // get the response length
   size_t numBytes = _tl->getNumBytes();
   if(numBytes == 0) {
     return(ERR_RESPONSE_MALFORMED_AT);
   }
-  
+
   // read the response
   char* raw = new char[numBytes];
   size_t rawLength = _tl->receive((uint8_t*)raw, numBytes);
@@ -184,14 +185,14 @@ int16_t HTTPClient::post(const char* url, const char* content, String& response,
     delete[] raw;
     return(ERR_RESPONSE_MALFORMED);
   }
-  
+
   // close the tl connection
   state = _tl->closeTransportConnection();
   if(state != ERR_NONE) {
     delete[] raw;
     return(state);
   }
-  
+
   // get the response body
   char* responseStart = strstr(raw, "\r\n");
   if(responseStart == NULL) {
@@ -203,7 +204,7 @@ int16_t HTTPClient::post(const char* url, const char* content, String& response,
   responseStr[raw + rawLength - responseStart - 2] = 0x00;
   response = String(responseStr);
   delete[] responseStr;
-  
+
   // return the HTTP status code
   char* statusStart = strchr(raw, ' ');
   delete[] raw;

From 629ac5585aedb0993acfee66e7ba58dac312eb27 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Fri, 26 Jul 2019 09:43:24 +0200
Subject: [PATCH 062/106] [SX126x] Added method to get expected time-on-air

---
 keywords.txt           |  1 +
 src/modules/SX126x.cpp | 39 +++++++++++++++++++++++----------------
 src/modules/SX126x.h   |  9 +++++++++
 3 files changed, 33 insertions(+), 16 deletions(-)

diff --git a/keywords.txt b/keywords.txt
index 7a47ab48..1e47e76e 100644
--- a/keywords.txt
+++ b/keywords.txt
@@ -105,6 +105,7 @@ setGdo1Action	KEYWORD2
 setDio2Action	KEYWORD2
 setTCXO	KEYWORD2
 setDio2AsRfSwitch	KEYWORD2
+getTimeOnAir	KEYWORD2
 
 # ESP8266
 join	KEYWORD2
diff --git a/src/modules/SX126x.cpp b/src/modules/SX126x.cpp
index 93327118..94b9c581 100644
--- a/src/modules/SX126x.cpp
+++ b/src/modules/SX126x.cpp
@@ -157,25 +157,11 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) {
   uint8_t modem = getPacketType();
   if(modem == SX126X_PACKET_TYPE_LORA) {
     // calculate timeout (150% of expected time-on-air)
-    float symbolLength = (float)((uint32_t)(1) << _sf) / (float)_bwKhz;
-    float sfCoeff1 = 4.25;
-    float sfCoeff2 = 8.0;
-    if(_sf == 5 || _sf == 6) {
-      sfCoeff1 = 6.25;
-      sfCoeff2 = 0.0;
-    }
-    uint8_t sfDivisor = 4*_sf;
-    if(symbolLength >= 16.0) {
-      sfDivisor = 4*(_sf - 2);
-    }
-    float nSymbol = _preambleLength + sfCoeff1 + 8 + ceil(max(8.0 * len + (_crcType * 16.0) - 4.0 * _sf + sfCoeff2 + 20.0, 0.0) / sfDivisor) * (_cr + 4);
-    timeout = (uint32_t)(symbolLength * nSymbol * 1500.0);
+    timeout = (float)getTimeOnAir(len) * 1.5;
 
   } else if(modem == SX126X_PACKET_TYPE_GFSK) {
-
     // calculate timeout (500% of expected time-on-air)
-    float brBps = ((float)(SX126X_CRYSTAL_FREQ) * 1000000.0 * 32.0) / (float)_br;
-    timeout = (uint32_t)(((len * 8.0) / brBps) * 1000000.0 * 5.0);
+    timeout = (float)getTimeOnAir(len) * 5.0;
 
   } else {
     return(ERR_UNKNOWN);
@@ -877,6 +863,27 @@ size_t SX126x::getPacketLength(bool update) {
   return((size_t)rxBufStatus[0]);
 }
 
+uint32_t SX126x::getTimeOnAir(size_t len) {
+  if(getPacketType() == SX126X_PACKET_TYPE_LORA) {
+    float symbolLength = (float)((uint32_t)(1) << _sf) / (float)_bwKhz;
+    float sfCoeff1 = 4.25;
+    float sfCoeff2 = 8.0;
+    if(_sf == 5 || _sf == 6) {
+      sfCoeff1 = 6.25;
+      sfCoeff2 = 0.0;
+    }
+    uint8_t sfDivisor = 4*_sf;
+    if(symbolLength >= 16.0) {
+      sfDivisor = 4*(_sf - 2);
+    }
+    float nSymbol = _preambleLength + sfCoeff1 + 8 + ceil(max(8.0 * len + (_crcType * 16.0) - 4.0 * _sf + sfCoeff2 + 20.0, 0.0) / sfDivisor) * (_cr + 4);
+    return((uint32_t)(symbolLength * nSymbol * 1000.0));
+  } else {
+    float brBps = ((float)(SX126X_CRYSTAL_FREQ) * 1000000.0 * 32.0) / (float)_br;
+    return((uint32_t)(((len * 8.0) / brBps) * 1000000.0));
+  }
+}
+
 int16_t SX126x::setTCXO(float voltage, uint32_t timeout) {
   // set mode to standby
   standby();
diff --git a/src/modules/SX126x.h b/src/modules/SX126x.h
index 9f9253b4..134325bd 100644
--- a/src/modules/SX126x.h
+++ b/src/modules/SX126x.h
@@ -690,6 +690,15 @@ class SX126x: public PhysicalLayer {
     */
     size_t getPacketLength(bool update = true);
 
+    /*!
+     \brief Get expected time-on-air for a given size of payload
+
+     \param len Payload length in bytes.
+
+     \returns Expected time-on-air in microseconds.
+   */
+   uint32_t getTimeOnAir(size_t len);
+
   protected:
     // SX1276x SPI command implementations
     int16_t setTx(uint32_t timeout = 0);

From 11dc4be0ec7aa91149d6f1ffbcbea8b8e9f3ee6d Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Fri, 26 Jul 2019 20:06:12 +0200
Subject: [PATCH 063/106] [RTTY] Fixed ITA2 encoding

---
 src/protocols/RTTY.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/protocols/RTTY.cpp b/src/protocols/RTTY.cpp
index 0cc22dc7..e0f6d90b 100644
--- a/src/protocols/RTTY.cpp
+++ b/src/protocols/RTTY.cpp
@@ -84,11 +84,11 @@ uint16_t ITA2String::getBits(char c) {
   // search ITA2 table
   uint16_t code = 0x0000;
   for(uint8_t i = 0; i < ITA2_LENGTH; i++) {
-    if(pgm_read_byte(ITA2Table[i][0]) == c) {
+    if(pgm_read_byte(&ITA2Table[i][0]) == c) {
       // character is in letter shift
       code = (ITA2_LTRS << 5) | i;
       break;
-    } else if(pgm_read_byte(ITA2Table[i][1]) == c) {
+    } else if(pgm_read_byte(&ITA2Table[i][1]) == c) {
       // character is in figures shift
       code = (ITA2_FIGS << 5) | i;
       break;

From e8e19c478763f4bcf6adc25a5dd3158b5aae98e6 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Fri, 26 Jul 2019 20:06:42 +0200
Subject: [PATCH 064/106] Advanced version to 1.2.2

---
 library.properties | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library.properties b/library.properties
index c807428d..d8241731 100644
--- a/library.properties
+++ b/library.properties
@@ -1,5 +1,5 @@
 name=RadioLib
-version=1.2.1
+version=1.2.2
 author=Jan Gromes <gromes.jan@gmail.com>
 maintainer=Jan Gromes <gromes.jan@gmail.com>
 sentence=Universal wireless communication library for Arduino

From 20f3b429e9f735a9938b7cc1ea3c56b13cffc4a7 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Mon, 29 Jul 2019 07:55:44 +0200
Subject: [PATCH 065/106] [SX127x] Fixed uninitialized variable warning

---
 src/modules/SX127x.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/modules/SX127x.cpp b/src/modules/SX127x.cpp
index 59712207..31d63ec1 100644
--- a/src/modules/SX127x.cpp
+++ b/src/modules/SX127x.cpp
@@ -126,7 +126,7 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) {
   int16_t state = setMode(SX127X_STANDBY);
 
   int16_t modem = getActiveModem();
-  uint32_t start;
+  uint32_t start = 0;
   if(modem == SX127X_LORA) {
     // calculate timeout (150 % of expected time-one-air)
     float symbolLength = (float)(uint32_t(1) <<_sf) / (float)_bw;

From 9a300da9632e55572b0590a5ef64932ec7a2aa4a Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Mon, 29 Jul 2019 13:05:57 +0200
Subject: [PATCH 066/106] [RTTY] Added note about non-LoRa module usage

---
 examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino b/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino
index 3b7b799c..540f656a 100644
--- a/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino
+++ b/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino
@@ -45,6 +45,11 @@ void setup() {
   // current limit:               100 mA
   // sync word:                   0x2D  0x01
   int state = fsk.beginFSK();
+
+  // when using one of the non-LoRa modules for RTTY
+  // (RF69, CC1101, etc.), use the basic begin() method
+  // int state = fsk.begin();
+
   if(state == ERR_NONE) {
     Serial.println(F("success!"));
   } else {

From 3f0dc1100890d32365cf9be7141f8055e1be36eb Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Mon, 29 Jul 2019 13:06:08 +0200
Subject: [PATCH 067/106] [Morse] Added note about non-LoRa module usage

---
 examples/Morse/Morse_Transmit/Morse_Transmit.ino | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/examples/Morse/Morse_Transmit/Morse_Transmit.ino b/examples/Morse/Morse_Transmit/Morse_Transmit.ino
index 9e158777..611ffd93 100644
--- a/examples/Morse/Morse_Transmit/Morse_Transmit.ino
+++ b/examples/Morse/Morse_Transmit/Morse_Transmit.ino
@@ -42,6 +42,11 @@ void setup() {
   // current limit:               100 mA
   // sync word:                   0x2D  0x01
   int state = fsk.beginFSK();
+
+  // when using one of the non-LoRa modules for Morse code
+  // (RF69, CC1101, etc.), use the basic begin() method
+  // int state = fsk.begin();
+
   if(state == ERR_NONE) {
     Serial.println(F("success!"));
   } else {

From e751d31aa9246ac4bc05a3b4d1bc79196660fa08 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Wed, 31 Jul 2019 07:25:04 +0200
Subject: [PATCH 068/106] Added compatibility with ESP8266 platform

---
 .travis.yml             |  8 +++++++
 src/RadioLib.h          |  2 ++
 src/TypeDef.h           | 22 +++++++++---------
 src/modules/ESP8266.cpp | 50 +++++++++++++++++++++--------------------
 src/modules/ESP8266.h   |  2 +-
 5 files changed, 48 insertions(+), 36 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 1915d096..9b406320 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,6 +5,7 @@ env:
     - BOARD="arduino:avr:uno"
     - BOARD="arduino:avr:leonardo"
     - BOARD="arduino:avr:mega:cpu=atmega2560"
+    - BOARD="esp8266:esp8266:generic:xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K"
 
 before_install:
   # install Arduino IDE
@@ -12,6 +13,7 @@ before_install:
   - tar xf arduino-$ARDUINO_IDE_VERSION-linux64.tar.xz
   - mv arduino-$ARDUINO_IDE_VERSION $HOME/arduino-ide
   - export PATH=$PATH:$HOME/arduino-ide
+
   # firewall Arduino IDE noise (https://github.com/per1234/arduino-ci-script/issues/1#issuecomment-504158113)
   - sudo iptables -P INPUT DROP
   - sudo iptables -P FORWARD DROP
@@ -20,6 +22,12 @@ before_install:
   - sudo iptables -A OUTPUT -o lo -j ACCEPT
   - sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
 
+  # install 3rd party boards
+  - arduino --pref "boardsmanager.additional.urls=http://arduino.esp8266.com/stable/package_esp8266com_index.json,https://dl.espressif.com/dl/package_esp32_index.json" --save-prefs 2>&1
+  - if [[ "$BOARD" =~ "esp8266:esp8266:" ]]; then
+      arduino --install-boards esp8266:esp8266;
+    fi
+
 # create directory to save the library and create symbolic link
 install:
   - mkdir -p $HOME/Arduino/libraries
diff --git a/src/RadioLib.h b/src/RadioLib.h
index 00f6f510..29859501 100644
--- a/src/RadioLib.h
+++ b/src/RadioLib.h
@@ -39,7 +39,9 @@
 #include "Module.h"
 
 #include "modules/CC1101.h"
+#ifndef ESP8266
 #include "modules/ESP8266.h"
+#endif
 #include "modules/HC05.h"
 #include "modules/JDY08.h"
 #include "modules/nRF24.h"
diff --git a/src/TypeDef.h b/src/TypeDef.h
index 931426ac..5359cb82 100644
--- a/src/TypeDef.h
+++ b/src/TypeDef.h
@@ -4,7 +4,7 @@
 #if ARDUINO >= 100
   #include "Arduino.h"
 #else
-  #include "WProgram.h"
+  #error "Unsupported Arduino version (< 1.0.0)"
 #endif
 
 //#define RADIOLIB_DEBUG
@@ -71,52 +71,52 @@
 /*!
   \brief Use 1 bit stop.
 */
-#define UART_STOPBIT_1                        0x01
+#define RADIOLIB_UART_STOPBIT_1               0x01
 
 /*!
   \brief Use 1.5 bit stop.
 */
-#define UART_STOPBIT_1_5                      0x02
+#define RADIOLIB_UART_STOPBIT_1_5             0x02
 
 /*!
   \brief Use 2 bit stop.
 */
-#define UART_STOPBIT_2                        0x03
+#define RADIOLIB_UART_STOPBIT_2               0x03
 
 /*!
   \brief No parity.
 */
-#define UART_PARITY_NONE                      0x00
+#define RADIOLIB_UART_PARITY_NONE             0x00
 
 /*!
   \brief Odd parity.
 */
-#define UART_PARITY_ODD                       0x01
+#define RADIOLIB_UART_PARITY_ODD              0x01
 
 /*!
   \brief Even parity.
 */
-#define UART_PARITY_EVEN                      0x02
+#define RADIOLIB_UART_PARITY_EVEN             0x02
 
 /*!
   \brief No flow control.
 */
-#define UART_FLOW_NONE                        0x00
+#define RADIOLIB_UART_FLOW_NONE               0x00
 
 /*!
   \brief RTS only.
 */
-#define UART_FLOW_RTS                         0x01
+#define RADIOLIB_UART_FLOW_RTS                0x01
 
 /*!
   \brief CTS only.
 */
-#define UART_FLOW_CTS                         0x02
+#define RADIOLIB_UART_FLOW_CTS                0x02
 
 /*!
   \brief Both RTS and CTS.
 */
-#define UART_FLOW_BOTH                        0x03
+#define RADIOLIB_UART_FLOW_BOTH               0x03
 
 /*!
   \}
diff --git a/src/modules/ESP8266.cpp b/src/modules/ESP8266.cpp
index 8586cf96..38305579 100644
--- a/src/modules/ESP8266.cpp
+++ b/src/modules/ESP8266.cpp
@@ -1,3 +1,4 @@
+#ifndef ESP8266
 #include "ESP8266.h"
 
 ESP8266::ESP8266(Module* module) {
@@ -9,15 +10,15 @@ int16_t ESP8266::begin(long speed) {
   _mod->AtLineFeed = "\r\n";
   _mod->baudrate = speed;
   _mod->init(USE_UART, INT_NONE);
-  
+
   // empty UART buffer (garbage data)
   _mod->ATemptyBuffer();
-  
+
   // test AT setup
   if(!_mod->ATsendCommand("AT")) {
     return(ERR_AT_FAILED);
   }
-  
+
   return(ERR_NONE);
 }
 
@@ -26,10 +27,10 @@ int16_t ESP8266::reset() {
   if(!_mod->ATsendCommand("AT+RST")) {
     return(ERR_AT_FAILED);
   }
-  
+
   // wait for the module to start
   delay(2000);
-  
+
   // test AT setup
   uint32_t start = millis();
   while (millis() - start < 3000) {
@@ -39,7 +40,7 @@ int16_t ESP8266::reset() {
       return(ERR_NONE);
     }
   }
-  
+
   return(ERR_AT_FAILED);
 }
 
@@ -48,7 +49,7 @@ int16_t ESP8266::join(const char* ssid, const char* password) {
   if(!_mod->ATsendCommand("AT+CWMODE_CUR=3")) {
     return(ERR_AT_FAILED);
   }
-  
+
   // build AT command
   const char* atStr = "AT+CWJAP_CUR=\"";
   uint8_t cmdLen = strlen(atStr) + strlen(ssid) + strlen(password) + 4;
@@ -58,19 +59,19 @@ int16_t ESP8266::join(const char* ssid, const char* password) {
   strcat(cmd, "\",\"");
   strcat(cmd, password);
   strcat(cmd, "\"");
-  
+
   // send command
   bool res = _mod->ATsendCommand(cmd);
   delete[] cmd;
   if(!res) {
     return(ERR_AT_FAILED);
   }
-  
+
   // disable multiple connection mode
   if(!_mod->ATsendCommand("AT+CIPMUX=0")) {
     return(ERR_AT_FAILED);
   }
-  
+
   return(ERR_NONE);
 }
 
@@ -79,7 +80,7 @@ int16_t ESP8266::openTransportConnection(const char* host, const char* protocol,
   itoa(port, portStr, 10);
   char tcpKeepAliveStr[6];
   itoa(tcpKeepAlive, tcpKeepAliveStr, 10);
-  
+
   // build AT command
   const char* atStr = "AT+CIPSTART=\"";
   uint8_t cmdLen = strlen(atStr) + strlen(protocol) + strlen(host) + strlen(portStr) + 5;
@@ -97,14 +98,14 @@ int16_t ESP8266::openTransportConnection(const char* host, const char* protocol,
     strcat(cmd, ",");
     strcat(cmd, tcpKeepAliveStr);
   }
-  
+
   // send command
   bool res = _mod->ATsendCommand(cmd);
   delete[] cmd;
   if(!res) {
     return(ERR_AT_FAILED);
   }
-  
+
   return(ERR_NONE);
 }
 
@@ -124,19 +125,19 @@ int16_t ESP8266::send(const char* data) {
   char* cmd = new char[strlen(atStr) + strlen(lenStr)];
   strcpy(cmd, atStr);
   strcat(cmd, lenStr);
-  
+
   // send command
   bool res = _mod->ATsendCommand(cmd);
   delete[] cmd;
   if(!res) {
     return(ERR_AT_FAILED);
   }
-  
+
   // send data
   if(!_mod->ATsendCommand(data)) {
     return(ERR_AT_FAILED);
   }
-  
+
   return(ERR_NONE);
 }
 
@@ -148,26 +149,26 @@ int16_t ESP8266::send(uint8_t* data, uint32_t len) {
   char* cmd = new char[strlen(atStr) + strlen(lenStr)];
   strcpy(cmd, atStr);
   strcat(cmd, lenStr);
-  
+
   // send command
   bool res = _mod->ATsendCommand(cmd);
   delete[] cmd;
   if(!res) {
     return(ERR_AT_FAILED);
   }
-  
+
   // send data
   if(!_mod->ATsendData(data, len)) {
     return(ERR_AT_FAILED);
   }
-  
+
   return(ERR_NONE);
 }
 
 size_t ESP8266::receive(uint8_t* data, size_t len, uint32_t timeout) {
   size_t i = 0;
   uint32_t start = millis();
-  
+
   // wait until the required number of bytes is received or until timeout
   while((millis() - start < timeout) && (i < len)) {
     while(_mod->ModuleSerial->available() > 0) {
@@ -188,7 +189,7 @@ size_t ESP8266::getNumBytes(uint32_t timeout, size_t minBytes) {
       return(0);
     }
   }
-  
+
   // read response
   char rawStr[20];
   uint8_t i = 0;
@@ -205,17 +206,18 @@ size_t ESP8266::getNumBytes(uint32_t timeout, size_t minBytes) {
       break;
     }
   }
-  
+
   // get the number of bytes in response
   char* pch = strtok(rawStr, ",:");
   if(pch == NULL) {
     return(0);
   }
-  
+
   pch = strtok(NULL, ",:");
   if(pch == NULL) {
     return(0);
   }
-  
+
   return(atoi(pch));
 }
+#endif
diff --git a/src/modules/ESP8266.h b/src/modules/ESP8266.h
index c03a0d58..8d5d0a9e 100644
--- a/src/modules/ESP8266.h
+++ b/src/modules/ESP8266.h
@@ -1,4 +1,4 @@
-#ifndef _RADIOLIB_ESP8266_H
+#if !defined(_RADIOLIB_ESP8266_H) && !defined(ESP8266)
 #define _RADIOLIB_ESP8266_H
 
 #include "Module.h"

From adccaf88a677a6621b2da6cfc1ce56469584d465 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Grome=C5=A1?= <jgromes@users.noreply.github.com>
Date: Wed, 31 Jul 2019 07:27:40 +0200
Subject: [PATCH 069/106] Update README.md

---
 README.md | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index a8f36fc2..6eb72cd8 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,6 @@ Want to add a Bluetooth interface to your ZigBee network? Sure thing! Need to co
 
 RadioLib was originally created as a driver for [__RadioShield__](https://github.com/jgromes/RadioShield), but it can be used to control as many different wireless modules as you like - or at least as many as your Arduino can handle!
 
-
 ### Supported modules:
 * __CC1101__ FSK radio module
 * __ESP8266__ WiFi module
@@ -31,6 +30,10 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github
 * __RTTY__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101 and nRF24L01
 * __Morse Code__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101 and nRF24L01
 
+### Supported platforms:
+* __Arduino AVR boards__ - tested on Uno, Mega and Leonardo
+* __ESP8266 boards__ - NodeMCU, Wemos D1, etc.
+
 ### In development:
 * __SIM800C__ GSM module
 * __LoRaWAN__ protocol for SX127x, RFM9x and SX126x modules

From 8887bac07f680c15dc57d5f59d1235482875ca9e Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Wed, 31 Jul 2019 09:37:44 +0200
Subject: [PATCH 070/106] Added missing macro guards

---
 src/RadioLib.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/RadioLib.h b/src/RadioLib.h
index 29859501..b9951e52 100644
--- a/src/RadioLib.h
+++ b/src/RadioLib.h
@@ -67,9 +67,11 @@
 #include "protocols/RTTY.h"
 
 // transport layer protocols
+#ifndef ESP8266
 #include "protocols/TransportLayer.h"
 #include "protocols/HTTP.h"
 #include "protocols/MQTT.h"
+#endif
 
 // RadioShield pin definitions
 #define RADIOSHIELD_CS_A   10

From d8350c7e5abcbac68f68fe0d2cdec63b447dd08e Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Wed, 31 Jul 2019 09:38:04 +0200
Subject: [PATCH 071/106] Travis fix for ESP8266

---
 .travis.yml | 29 +++++++++++++++++++++++------
 1 file changed, 23 insertions(+), 6 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 9b406320..4f79c647 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -39,17 +39,34 @@ branches:
     - master
 
 script:
+  # set sketch skipping pattern for some boards
+  if [[ "$BOARD" =~ "esp8266:esp8266:" ]]; then
+    # on ESP8266, skip HTTP and MQTT examples
+    SKIP_PAT='(HTTP|MQTT).*ino'
+  else
+    # default skip pattern (matches everything)
+    SKIP_PAT='.*'
+  fi
+
   # build all example sketches
   - for example in $(find $PWD/examples -name '*.ino' | sort); do
-      echo -e "\n\033[1;33mBuilding ${example##*/} ... \033[0m";
-      arduino --verify --board $BOARD $example;
-      if [ $? -ne 0 ]; then
-        echo -e "\033[1;31m${example##*/} build FAILED\033[0m\n";
-        exit 1;
+      # check whether to skip this sketch
+      if [[ ${example} =~ $PAT2 ]]; then
+        # skip sketch
+        echo -e "\n\033[1;33mSkipped ${example##*/} (matched with $SKIP_PAT)\033[0m";
       else
-        echo -e "\033[1;32m${example##*/} build PASSED\033[0m\n";
+        # build sketch
+        echo -e "\n\033[1;33mBuilding ${example##*/} ... \033[0m";
+        arduino --verify --board $BOARD $example;
+        if [ $? -ne 0 ]; then
+          echo -e "\033[1;31m${example##*/} build FAILED\033[0m\n";
+          exit 1;
+        else
+          echo -e "\033[1;32m${example##*/} build PASSED\033[0m\n";
+        fi
       fi
     done
+
   # generate Doxygen documentation (only for Arduino UNO)
   - if [ $BOARD = "arduino:avr:uno" ]; then
       sudo apt-get update;

From 7caeb3ded0589121ee47a0df23322e557f0e8d1c Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Wed, 31 Jul 2019 09:56:25 +0200
Subject: [PATCH 072/106] Travis fix formatting

---
 .travis.yml | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 4f79c647..eceb1241 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -40,13 +40,13 @@ branches:
 
 script:
   # set sketch skipping pattern for some boards
-  if [[ "$BOARD" =~ "esp8266:esp8266:" ]]; then
-    # on ESP8266, skip HTTP and MQTT examples
-    SKIP_PAT='(HTTP|MQTT).*ino'
-  else
-    # default skip pattern (matches everything)
-    SKIP_PAT='.*'
-  fi
+  - if [[ "$BOARD" =~ "esp8266:esp8266:" ]]; then
+      # on ESP8266, skip HTTP and MQTT examples
+      SKIP_PAT='(HTTP|MQTT).*ino'
+    else
+      # default skip pattern (matches everything)
+      SKIP_PAT='.*'
+    fi
 
   # build all example sketches
   - for example in $(find $PWD/examples -name '*.ino' | sort); do

From 2dacf362ad5fc530a80a446d48aa20f92521fd19 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Wed, 31 Jul 2019 09:58:46 +0200
Subject: [PATCH 073/106] Travis fix

---
 .travis.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index eceb1241..0f1268bb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -42,10 +42,10 @@ script:
   # set sketch skipping pattern for some boards
   - if [[ "$BOARD" =~ "esp8266:esp8266:" ]]; then
       # on ESP8266, skip HTTP and MQTT examples
-      SKIP_PAT='(HTTP|MQTT).*ino'
+      SKIP_PAT='(HTTP|MQTT).*ino';
     else
       # default skip pattern (matches everything)
-      SKIP_PAT='.*'
+      SKIP_PAT='.*';
     fi
 
   # build all example sketches

From da0aad9b69c84335f394243a710c0ff34577d5e5 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Wed, 31 Jul 2019 10:02:45 +0200
Subject: [PATCH 074/106] Travis fix 2

---
 .travis.yml | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 0f1268bb..ed972cd0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -26,6 +26,9 @@ before_install:
   - arduino --pref "boardsmanager.additional.urls=http://arduino.esp8266.com/stable/package_esp8266com_index.json,https://dl.espressif.com/dl/package_esp32_index.json" --save-prefs 2>&1
   - if [[ "$BOARD" =~ "esp8266:esp8266:" ]]; then
       arduino --install-boards esp8266:esp8266;
+      export SKIP_PAT='(HTTP|MQTT).*ino';
+    else
+      SKIP_PAT='.*';
     fi
 
 # create directory to save the library and create symbolic link
@@ -39,15 +42,6 @@ branches:
     - master
 
 script:
-  # set sketch skipping pattern for some boards
-  - if [[ "$BOARD" =~ "esp8266:esp8266:" ]]; then
-      # on ESP8266, skip HTTP and MQTT examples
-      SKIP_PAT='(HTTP|MQTT).*ino';
-    else
-      # default skip pattern (matches everything)
-      SKIP_PAT='.*';
-    fi
-
   # build all example sketches
   - for example in $(find $PWD/examples -name '*.ino' | sort); do
       # check whether to skip this sketch

From 8577d43b2e33d1287d5af3246e5c6d62d9e2f1f6 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Wed, 31 Jul 2019 10:19:10 +0200
Subject: [PATCH 075/106] Travis fix 3

---
 .travis.yml | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index ed972cd0..0c4303ca 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -28,7 +28,7 @@ before_install:
       arduino --install-boards esp8266:esp8266;
       export SKIP_PAT='(HTTP|MQTT).*ino';
     else
-      SKIP_PAT='.*';
+      export SKIP_PAT='.*';
     fi
 
 # create directory to save the library and create symbolic link
@@ -43,7 +43,8 @@ branches:
 
 script:
   # build all example sketches
-  - for example in $(find $PWD/examples -name '*.ino' | sort); do
+  - |
+    for example in $(find $PWD/examples -name '*.ino' | sort); do
       # check whether to skip this sketch
       if [[ ${example} =~ $PAT2 ]]; then
         # skip sketch

From f974021803fec3022b70f5722c78b647944397b2 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Wed, 31 Jul 2019 10:22:14 +0200
Subject: [PATCH 076/106] Travix fix incorrect variable name

---
 .travis.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.travis.yml b/.travis.yml
index 0c4303ca..090532ad 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -46,7 +46,7 @@ script:
   - |
     for example in $(find $PWD/examples -name '*.ino' | sort); do
       # check whether to skip this sketch
-      if [[ ${example} =~ $PAT2 ]]; then
+      if [[ ${example} =~ $SKIP_PAT ]]; then
         # skip sketch
         echo -e "\n\033[1;33mSkipped ${example##*/} (matched with $SKIP_PAT)\033[0m";
       else

From cf5b098c0cc5d3e2eb1fa65ae92000c2c779b513 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Wed, 31 Jul 2019 10:28:02 +0200
Subject: [PATCH 077/106] Travix fix regex

---
 .travis.yml | 2 --
 1 file changed, 2 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 090532ad..f6683368 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -27,8 +27,6 @@ before_install:
   - if [[ "$BOARD" =~ "esp8266:esp8266:" ]]; then
       arduino --install-boards esp8266:esp8266;
       export SKIP_PAT='(HTTP|MQTT).*ino';
-    else
-      export SKIP_PAT='.*';
     fi
 
 # create directory to save the library and create symbolic link

From 4f2382ad8c6ae6ca31c62031edeada2099348f55 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Wed, 31 Jul 2019 10:39:05 +0200
Subject: [PATCH 078/106] Travis add variable check

---
 .travis.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.travis.yml b/.travis.yml
index f6683368..3e01acbc 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -44,7 +44,7 @@ script:
   - |
     for example in $(find $PWD/examples -name '*.ino' | sort); do
       # check whether to skip this sketch
-      if [[ ${example} =~ $SKIP_PAT ]]; then
+      if [ ! -z "$SKIP_PAT" ] && [[ ${example} =~ $SKIP_PAT ]]; then
         # skip sketch
         echo -e "\n\033[1;33mSkipped ${example##*/} (matched with $SKIP_PAT)\033[0m";
       else

From bbef47e71a66af94ebcc44f5cf98e4b376658dae Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Wed, 31 Jul 2019 11:16:25 +0200
Subject: [PATCH 079/106] Advacned version to 1.3.0

---
 library.properties | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library.properties b/library.properties
index d8241731..9b6922ac 100644
--- a/library.properties
+++ b/library.properties
@@ -1,5 +1,5 @@
 name=RadioLib
-version=1.2.2
+version=1.3.0
 author=Jan Gromes <gromes.jan@gmail.com>
 maintainer=Jan Gromes <gromes.jan@gmail.com>
 sentence=Universal wireless communication library for Arduino

From 1465e01fd4c36ff604c7fa39242e4952339c95b8 Mon Sep 17 00:00:00 2001
From: Bernd Giesecke <bernd@giesecke.tk>
Date: Sat, 7 Sep 2019 21:30:57 +0800
Subject: [PATCH 080/106] ESP32 & SAMD - use HardwareSerial instead of
 SoftwareSerial

ESP32 has no working SoftwareSerial. With a simple #ifdef ESP32 || SAMD a hardware serial will be used instead.
Minimum changes without influence on existing installations or usage.
---
 src/ISerial.cpp | 16 ++++++++++++++++
 src/Module.cpp  | 16 ++++++++++++++--
 src/Module.h    | 24 ++++++++++++++++++++++--
 3 files changed, 52 insertions(+), 4 deletions(-)

diff --git a/src/ISerial.cpp b/src/ISerial.cpp
index 0ae9ca47..6381fc9b 100644
--- a/src/ISerial.cpp
+++ b/src/ISerial.cpp
@@ -9,7 +9,11 @@ void ISerial::begin(long speed) {
 }
 
 bool ISerial::listen() {
+#if defined ( ESP32 )  || defined (SAMD_SERIES)
+  return true;
+#else
   return(_mod->ModuleSerial->listen());
+#endif
 }
 
 void ISerial::end() {
@@ -17,15 +21,27 @@ void ISerial::end() {
 }
 
 bool ISerial::isListening() {
+#if defined( ESP32 ) || defined ( SAMD_SERIES )
+  return true;
+#else
   return(_mod->ModuleSerial->isListening());
+#endif
 }
 
 bool ISerial::stopListening() {
+#if defined( ESP32 ) || defined ( SAMD_SERIES )
+  return true;
+#else
   return(_mod->ModuleSerial->stopListening());
+#endif
 }
 
 bool ISerial::overflow() {
+#if defined( ESP32 ) || defined ( SAMD_SERIES )
+  return false;
+#else
   return(_mod->ModuleSerial->overflow());
+#endif
 }
 
 int ISerial::peek() {
diff --git a/src/Module.cpp b/src/Module.cpp
index a623b61d..422ab66e 100644
--- a/src/Module.cpp
+++ b/src/Module.cpp
@@ -1,13 +1,17 @@
 #include "Module.h"
 
-Module::Module(int rx, int tx) {
+Module::Module(int rx, int tx, HardwareSerial* useSer) {
   _cs = -1;
   _rx = rx;
   _tx = tx;
   _int0 = -1;
   _int1 = -1;
 
+#if defined(ESP32) || defined(SAMD_SERIES)
+    ModuleSerial = useSer;
+#else
   ModuleSerial = new SoftwareSerial(_rx, _tx);
+#endif
 }
 
 Module::Module(int cs, int int0, int int1, SPIClass& spi, SPISettings spiSettings) {
@@ -20,7 +24,7 @@ Module::Module(int cs, int int0, int int1, SPIClass& spi, SPISettings spiSetting
   _spiSettings = spiSettings;
 }
 
-Module::Module(int cs, int int0, int int1, int rx, int tx, SPIClass& spi, SPISettings spiSettings) {
+Module::Module(int cs, int int0, int int1, int rx, int tx, SPIClass& spi, SPISettings spiSettings, HardwareSerial* useSer) {
   _cs = cs;
   _rx = rx;
   _tx = tx;
@@ -29,7 +33,11 @@ Module::Module(int cs, int int0, int int1, int rx, int tx, SPIClass& spi, SPISet
   _spi = &spi;
   _spiSettings = spiSettings;
 
+#if defined(ESP32) || defined(SAMD_SERIES)
+  ModuleSerial = useSer;
+#else
   ModuleSerial = new SoftwareSerial(_rx, _tx);
+#endif
 }
 
 Module::Module(int cs, int int0, int int1, int int2, SPIClass& spi, SPISettings spiSettings) {
@@ -51,7 +59,11 @@ void Module::init(uint8_t interface, uint8_t gpio) {
       _spi->begin();
       break;
     case USE_UART:
+#if defined(ESP32)
+      ModuleSerial->begin(baudrate, SERIAL_8N1, _rx, _tx);
+#else
       ModuleSerial->begin(baudrate);
+#endif
       break;
     case USE_I2C:
       break;
diff --git a/src/Module.h b/src/Module.h
index c596276f..263c01d9 100644
--- a/src/Module.h
+++ b/src/Module.h
@@ -3,7 +3,10 @@
 
 #include <SPI.h>
 //#include <Wire.h>
+#if defined(ESP32) || defined(SAMD_SERIES)
+#else
 #include <SoftwareSerial.h>
+#endif
 
 #include "TypeDef.h"
 
@@ -22,8 +25,14 @@ class Module {
       \param tx Arduino pin to be used as Tx pin for SoftwareSerial communication.
 
       \param rx Arduino pin to be used as Rx pin for SoftwareSerial communication.
+
+      \param serial HardwareSerial to be used on ESP32 and SAMD. Defaults to 1
     */
-    Module(int tx, int rx);
+#if defined(ESP32) || defined(SAMD_SERIES)
+    Module(int tx, int rx, HardwareSerial* useSer = &Serial1);
+#else
+    Module(int tx, int rx, HardwareSerial* useSer = nullptr);
+#endif
 
     /*!
       \brief SPI-based module constructor.
@@ -73,15 +82,26 @@ class Module {
       \param spi SPI interface to be used. Defaults to Arduino hardware SPI interface, can also use software SPI implementations.
 
       \param spiSettings SPI interface settings. Defaults to 2 MHz clock, MSB first, mode 0.
+
+      \param serial HardwareSerial to be used on ESP32 and SAMD. Defaults to 1
     */
-    Module(int cs, int int0, int int1, int rx, int tx, SPIClass& spi = SPI, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0));
+#if defined(ESP32) || defined(SAMD_SERIES)
+    Module(int cs, int int0, int int1, int rx, int tx, SPIClass& spi = SPI, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0), HardwareSerial* useSer = &Serial1);
+#else
+    Module(int cs, int int0, int int1, int rx, int tx, SPIClass& spi = SPI, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0), HardwareSerial* useSer = nullptr);
+#endif
+      
 
     // public member variables
 
     /*!
       \brief Internal SoftwareSerial instance.
     */
+#if defined(ESP32) || defined(SAMD_SERIES)
+    HardwareSerial* ModuleSerial;
+#else
     SoftwareSerial* ModuleSerial;
+#endif
 
     /*!
       \brief Baud rate of SoftwareSerial UART communication. Defaults to 9600 baud.

From b208956f5be58850f002b6297aa4ed5ad0b54133 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Mon, 9 Sep 2019 09:18:38 +0200
Subject: [PATCH 081/106] Travis added ESP32 platform

---
 .travis.yml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/.travis.yml b/.travis.yml
index 3e01acbc..79170b77 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,6 +6,7 @@ env:
     - BOARD="arduino:avr:leonardo"
     - BOARD="arduino:avr:mega:cpu=atmega2560"
     - BOARD="esp8266:esp8266:generic:xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K"
+    - BOARD="esp32:esp32:esp32"
 
 before_install:
   # install Arduino IDE
@@ -27,6 +28,8 @@ before_install:
   - if [[ "$BOARD" =~ "esp8266:esp8266:" ]]; then
       arduino --install-boards esp8266:esp8266;
       export SKIP_PAT='(HTTP|MQTT).*ino';
+    elif [[ "$BOARD" =~ "esp32:esp32:" ]]; then
+      arduino --install-boards esp32:esp32;
     fi
 
 # create directory to save the library and create symbolic link

From 5c15e252362e74ba82a04eb784428711aaeaf7b4 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Mon, 9 Sep 2019 09:18:49 +0200
Subject: [PATCH 082/106] Updated readme

---
 README.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/README.md b/README.md
index 6eb72cd8..49452cd5 100644
--- a/README.md
+++ b/README.md
@@ -33,6 +33,7 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github
 ### Supported platforms:
 * __Arduino AVR boards__ - tested on Uno, Mega and Leonardo
 * __ESP8266 boards__ - NodeMCU, Wemos D1, etc.
+* __ESP32 boards__ - tested on ESP-WROOM-32
 
 ### In development:
 * __SIM800C__ GSM module

From 14df1d8c523d724146eef1a1415144548d0c43fb Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Mon, 9 Sep 2019 10:03:57 +0200
Subject: [PATCH 083/106] [ESP8266] Fixed incorrect string length

---
 src/modules/ESP8266.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/modules/ESP8266.cpp b/src/modules/ESP8266.cpp
index 38305579..d34e0d57 100644
--- a/src/modules/ESP8266.cpp
+++ b/src/modules/ESP8266.cpp
@@ -53,7 +53,7 @@ int16_t ESP8266::join(const char* ssid, const char* password) {
   // build AT command
   const char* atStr = "AT+CWJAP_CUR=\"";
   uint8_t cmdLen = strlen(atStr) + strlen(ssid) + strlen(password) + 4;
-  char* cmd = new char[cmdLen];
+  char* cmd = new char[cmdLen + 1];
   strcpy(cmd, atStr);
   strcat(cmd, ssid);
   strcat(cmd, "\",\"");
@@ -87,7 +87,7 @@ int16_t ESP8266::openTransportConnection(const char* host, const char* protocol,
   if((strcmp(protocol, "TCP") == 0) && (tcpKeepAlive > 0)) {
 	  cmdLen += strlen(tcpKeepAliveStr) + 1;
   }
-  char* cmd = new char[cmdLen];
+  char* cmd = new char[cmdLen + 1];
   strcpy(cmd, atStr);
   strcat(cmd, protocol);
   strcat(cmd, "\",\"");
@@ -122,7 +122,7 @@ int16_t ESP8266::send(const char* data) {
   char lenStr[8];
   itoa(strlen(data), lenStr, 10);
   const char* atStr = "AT+CIPSEND=";
-  char* cmd = new char[strlen(atStr) + strlen(lenStr)];
+  char* cmd = new char[strlen(atStr) + strlen(lenStr) + 1];
   strcpy(cmd, atStr);
   strcat(cmd, lenStr);
 
@@ -146,7 +146,7 @@ int16_t ESP8266::send(uint8_t* data, uint32_t len) {
   char lenStr[8];
   itoa(len, lenStr, 10);
   const char atStr[] = "AT+CIPSEND=";
-  char* cmd = new char[strlen(atStr) + strlen(lenStr)];
+  char* cmd = new char[strlen(atStr) + strlen(lenStr) + 1];
   strcpy(cmd, atStr);
   strcat(cmd, lenStr);
 

From 4eef30a2a487e15c80b5c07b6b6b0eded634320b Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Mon, 9 Sep 2019 10:04:07 +0200
Subject: [PATCH 084/106] [HTTP] Fixed incorrect string length

---
 src/protocols/HTTP.cpp | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/src/protocols/HTTP.cpp b/src/protocols/HTTP.cpp
index 11b41d57..9200acb0 100644
--- a/src/protocols/HTTP.cpp
+++ b/src/protocols/HTTP.cpp
@@ -21,7 +21,7 @@ int16_t HTTPClient::get(const char* url, String& response) {
     char* hostEnd = strchr(hostStart + 1, '/');
     host = new char[hostEnd - hostStart];
     strncpy(host, hostStart + 1, hostEnd - hostStart - 1);
-    host[hostEnd - hostStart - 1] = 0x00;
+    host[hostEnd - hostStart - 1] = '\0';
 
     // find the endpoint string
     endpoint = new char[url + strlen(url) - hostEnd + 1];
@@ -31,7 +31,7 @@ int16_t HTTPClient::get(const char* url, String& response) {
     char* hostEnd = strchr(url, '/');
     host = new char[hostEnd - url + 1];
     strncpy(host, url, hostEnd - url);
-    host[hostEnd - url] = 0x00;
+    host[hostEnd - url] = '\0';
 
     // find the endpoint string
     endpoint = new char[url + strlen(url) - hostEnd + 1];
@@ -39,7 +39,7 @@ int16_t HTTPClient::get(const char* url, String& response) {
   }
 
   // build the GET request
-  char* request = new char[strlen(endpoint) + strlen(host) + 25];
+  char* request = new char[strlen(endpoint) + strlen(host) + 25 + 1];
   strcpy(request, "GET ");
   strcat(request, endpoint);
   strcat(request, " HTTP/1.1\r\nHost: ");
@@ -72,7 +72,7 @@ int16_t HTTPClient::get(const char* url, String& response) {
   }
 
   // read the response
-  char* raw = new char[numBytes];
+  char* raw = new char[numBytes + 1];
   size_t rawLength = _tl->receive((uint8_t*)raw, numBytes);
   if(rawLength == 0) {
     delete[] raw;
@@ -92,9 +92,9 @@ int16_t HTTPClient::get(const char* url, String& response) {
     delete[] raw;
     return(ERR_RESPONSE_MALFORMED);
   }
-  char* responseStr = new char[raw + rawLength - responseStart - 1];
+  char* responseStr = new char[raw + rawLength - responseStart - 1 + 1];
   strncpy(responseStr, responseStart + 2, raw + rawLength - responseStart - 1);
-  responseStr[raw + rawLength - responseStart - 2] = 0x00;
+  responseStr[raw + rawLength - responseStart - 2] = '\0';
   response = String(responseStr);
   delete[] responseStr;
 
@@ -122,7 +122,7 @@ int16_t HTTPClient::post(const char* url, const char* content, String& response,
     char* hostEnd = strchr(hostStart + 1, '/');
     host = new char[hostEnd - hostStart];
     strncpy(host, hostStart + 1, hostEnd - hostStart - 1);
-    host[hostEnd - hostStart - 1] = 0x00;
+    host[hostEnd - hostStart - 1] = '\0';
 
     // find the endpoint string
     endpoint = new char[url + strlen(url) - hostEnd + 1];
@@ -132,7 +132,7 @@ int16_t HTTPClient::post(const char* url, const char* content, String& response,
     char* hostEnd = strchr(url, '/');
     host = new char[hostEnd - url + 1];
     strncpy(host, url, hostEnd - url);
-    host[hostEnd - url] = 0x00;
+    host[hostEnd - url] = '\0';
 
     // find the endpoint string
     endpoint = new char[url + strlen(url) - hostEnd + 1];
@@ -142,7 +142,7 @@ int16_t HTTPClient::post(const char* url, const char* content, String& response,
   // build the POST request
   char contentLengthStr[8];
   itoa(strlen(content), contentLengthStr, 10);
-  char* request = new char[strlen(endpoint) + strlen(host) + strlen(contentType) + strlen(contentLengthStr) + strlen(content) + 64];
+  char* request = new char[strlen(endpoint) + strlen(host) + strlen(contentType) + strlen(contentLengthStr) + strlen(content) + 64 + 1];
   strcpy(request, "POST ");
   strcat(request, endpoint);
   strcat(request, " HTTP/1.1\r\nHost: ");

From 47d8ac8b0764effe570bb2b8a75704645662f664 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Mon, 9 Sep 2019 10:51:34 +0200
Subject: [PATCH 085/106] Advanced version to 1.4.0

---
 library.properties | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library.properties b/library.properties
index 9b6922ac..a1345bb1 100644
--- a/library.properties
+++ b/library.properties
@@ -1,5 +1,5 @@
 name=RadioLib
-version=1.3.0
+version=1.4.0
 author=Jan Gromes <gromes.jan@gmail.com>
 maintainer=Jan Gromes <gromes.jan@gmail.com>
 sentence=Universal wireless communication library for Arduino

From 972f874e9e66af5495a58f6493c68d2bec719f10 Mon Sep 17 00:00:00 2001
From: mmrein <55082189+mmrein@users.noreply.github.com>
Date: Tue, 10 Sep 2019 17:40:49 +0200
Subject: [PATCH 086/106] STM32 - use HardwareSerial instead of SoftwareSerial

Added support for STM32 boards, using HardwareSerial instead of SoftwareSerial the same way as in https://github.com/jgromes/RadioLib/pull/39
---
 src/ISerial.cpp |  9 ++++-----
 src/Module.cpp  |  4 ++--
 src/Module.h    | 10 +++++-----
 3 files changed, 11 insertions(+), 12 deletions(-)

diff --git a/src/ISerial.cpp b/src/ISerial.cpp
index 6381fc9b..7ff0be0a 100644
--- a/src/ISerial.cpp
+++ b/src/ISerial.cpp
@@ -9,7 +9,7 @@ void ISerial::begin(long speed) {
 }
 
 bool ISerial::listen() {
-#if defined ( ESP32 )  || defined (SAMD_SERIES)
+#if defined ( ESP32 )  || defined (SAMD_SERIES) || defined (ARDUINO_ARCH_STM32)
   return true;
 #else
   return(_mod->ModuleSerial->listen());
@@ -21,7 +21,7 @@ void ISerial::end() {
 }
 
 bool ISerial::isListening() {
-#if defined( ESP32 ) || defined ( SAMD_SERIES )
+#if defined( ESP32 ) || defined ( SAMD_SERIES ) || defined (ARDUINO_ARCH_STM32)
   return true;
 #else
   return(_mod->ModuleSerial->isListening());
@@ -29,7 +29,7 @@ bool ISerial::isListening() {
 }
 
 bool ISerial::stopListening() {
-#if defined( ESP32 ) || defined ( SAMD_SERIES )
+#if defined( ESP32 ) || defined ( SAMD_SERIES ) || defined (ARDUINO_ARCH_STM32)
   return true;
 #else
   return(_mod->ModuleSerial->stopListening());
@@ -37,7 +37,7 @@ bool ISerial::stopListening() {
 }
 
 bool ISerial::overflow() {
-#if defined( ESP32 ) || defined ( SAMD_SERIES )
+#if defined( ESP32 ) || defined ( SAMD_SERIES ) || defined (ARDUINO_ARCH_STM32)
   return false;
 #else
   return(_mod->ModuleSerial->overflow());
@@ -155,4 +155,3 @@ size_t ISerial::println(const Printable& x) {
 size_t ISerial::println(void) {
   return(_mod->ModuleSerial->println());
 }
-  
\ No newline at end of file
diff --git a/src/Module.cpp b/src/Module.cpp
index 422ab66e..8b87cf2c 100644
--- a/src/Module.cpp
+++ b/src/Module.cpp
@@ -7,7 +7,7 @@ Module::Module(int rx, int tx, HardwareSerial* useSer) {
   _int0 = -1;
   _int1 = -1;
 
-#if defined(ESP32) || defined(SAMD_SERIES)
+#if defined(ESP32) || defined(SAMD_SERIES) || defined (ARDUINO_ARCH_STM32)
     ModuleSerial = useSer;
 #else
   ModuleSerial = new SoftwareSerial(_rx, _tx);
@@ -33,7 +33,7 @@ Module::Module(int cs, int int0, int int1, int rx, int tx, SPIClass& spi, SPISet
   _spi = &spi;
   _spiSettings = spiSettings;
 
-#if defined(ESP32) || defined(SAMD_SERIES)
+#if defined(ESP32) || defined(SAMD_SERIES) || defined (ARDUINO_ARCH_STM32)
   ModuleSerial = useSer;
 #else
   ModuleSerial = new SoftwareSerial(_rx, _tx);
diff --git a/src/Module.h b/src/Module.h
index 263c01d9..c6684d39 100644
--- a/src/Module.h
+++ b/src/Module.h
@@ -3,7 +3,7 @@
 
 #include <SPI.h>
 //#include <Wire.h>
-#if defined(ESP32) || defined(SAMD_SERIES)
+#if defined(ESP32) || defined(SAMD_SERIES) || defined (ARDUINO_ARCH_STM32)
 #else
 #include <SoftwareSerial.h>
 #endif
@@ -28,7 +28,7 @@ class Module {
 
       \param serial HardwareSerial to be used on ESP32 and SAMD. Defaults to 1
     */
-#if defined(ESP32) || defined(SAMD_SERIES)
+#if defined(ESP32) || defined(SAMD_SERIES) || defined (ARDUINO_ARCH_STM32)
     Module(int tx, int rx, HardwareSerial* useSer = &Serial1);
 #else
     Module(int tx, int rx, HardwareSerial* useSer = nullptr);
@@ -85,19 +85,19 @@ class Module {
 
       \param serial HardwareSerial to be used on ESP32 and SAMD. Defaults to 1
     */
-#if defined(ESP32) || defined(SAMD_SERIES)
+#if defined(ESP32) || defined(SAMD_SERIES) || defined (ARDUINO_ARCH_STM32)
     Module(int cs, int int0, int int1, int rx, int tx, SPIClass& spi = SPI, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0), HardwareSerial* useSer = &Serial1);
 #else
     Module(int cs, int int0, int int1, int rx, int tx, SPIClass& spi = SPI, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0), HardwareSerial* useSer = nullptr);
 #endif
-      
+
 
     // public member variables
 
     /*!
       \brief Internal SoftwareSerial instance.
     */
-#if defined(ESP32) || defined(SAMD_SERIES)
+#if defined(ESP32) || defined(SAMD_SERIES) || defined (ARDUINO_ARCH_STM32)
     HardwareSerial* ModuleSerial;
 #else
     SoftwareSerial* ModuleSerial;

From f2625a04a9d611d3c6db399cafe9c47f811dadaa Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Tue, 10 Sep 2019 18:48:51 +0200
Subject: [PATCH 087/106] Travis added STM32 and SAMD platforms

---
 .travis.yml | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/.travis.yml b/.travis.yml
index 79170b77..209f129a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,11 +2,14 @@ env:
   global:
     - ARDUINO_IDE_VERSION="1.8.9"
   matrix:
+    # see https://github.com/arduino/Arduino/blob/master/build/shared/manpage.adoc#options
     - BOARD="arduino:avr:uno"
     - BOARD="arduino:avr:leonardo"
     - BOARD="arduino:avr:mega:cpu=atmega2560"
     - BOARD="esp8266:esp8266:generic:xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K"
     - BOARD="esp32:esp32:esp32"
+    - BOARD="stm32duino:STM32F1:genericSTM32F103C"
+    - BOARD="arduino:samd:arduino_zero_native"
 
 before_install:
   # install Arduino IDE
@@ -24,12 +27,16 @@ before_install:
   - sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
 
   # install 3rd party boards
-  - arduino --pref "boardsmanager.additional.urls=http://arduino.esp8266.com/stable/package_esp8266com_index.json,https://dl.espressif.com/dl/package_esp32_index.json" --save-prefs 2>&1
+  - arduino --pref "boardsmanager.additional.urls=http://arduino.esp8266.com/stable/package_esp8266com_index.json,https://dl.espressif.com/dl/package_esp32_index.json,http://dan.drown.org/stm32duino/package_STM32duino_index.json" --save-prefs 2>&1
   - if [[ "$BOARD" =~ "esp8266:esp8266:" ]]; then
       arduino --install-boards esp8266:esp8266;
       export SKIP_PAT='(HTTP|MQTT).*ino';
     elif [[ "$BOARD" =~ "esp32:esp32:" ]]; then
       arduino --install-boards esp32:esp32;
+    elif [[ "$BOARD" =~ "stm32duino:STM32F1:" ]]; then
+      arduino --install-boards stm32duino:STM32F1;
+    elif [[ "$BOARD" =~ "arduino:samd:" ]]; then
+      arduino --install-boards arduino:samd;
     fi
 
 # create directory to save the library and create symbolic link

From 5a2928987d12e7b48275b65903f42de6db8c3734 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Tue, 10 Sep 2019 19:07:10 +0200
Subject: [PATCH 088/106] Travis added missing STM32 variant

---
 .travis.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.travis.yml b/.travis.yml
index 209f129a..6017feda 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,7 +8,7 @@ env:
     - BOARD="arduino:avr:mega:cpu=atmega2560"
     - BOARD="esp8266:esp8266:generic:xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K"
     - BOARD="esp32:esp32:esp32"
-    - BOARD="stm32duino:STM32F1:genericSTM32F103C"
+    - BOARD="stm32duino:STM32F1:genericSTM32F103C:device_variant=STM32F103C8"
     - BOARD="arduino:samd:arduino_zero_native"
 
 before_install:

From 8335ddf2da4defe7988346261b952b6c61c49188 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Tue, 10 Sep 2019 19:41:12 +0200
Subject: [PATCH 089/106] Travis fixed incorrect STM32 index

---
 .travis.yml | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 6017feda..836ed8b7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,12 +3,13 @@ env:
     - ARDUINO_IDE_VERSION="1.8.9"
   matrix:
     # see https://github.com/arduino/Arduino/blob/master/build/shared/manpage.adoc#options
+    # and https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5-3rd-party-Hardware-specification#boardstxt
     - BOARD="arduino:avr:uno"
     - BOARD="arduino:avr:leonardo"
     - BOARD="arduino:avr:mega:cpu=atmega2560"
     - BOARD="esp8266:esp8266:generic:xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K"
     - BOARD="esp32:esp32:esp32"
-    - BOARD="stm32duino:STM32F1:genericSTM32F103C:device_variant=STM32F103C8"
+    - BOARD="STM32:stm32:GenF1:pnum=BLUEPILL_F103C6"
     - BOARD="arduino:samd:arduino_zero_native"
 
 before_install:
@@ -27,14 +28,14 @@ before_install:
   - sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
 
   # install 3rd party boards
-  - arduino --pref "boardsmanager.additional.urls=http://arduino.esp8266.com/stable/package_esp8266com_index.json,https://dl.espressif.com/dl/package_esp32_index.json,http://dan.drown.org/stm32duino/package_STM32duino_index.json" --save-prefs 2>&1
+  - arduino --pref "boardsmanager.additional.urls=http://arduino.esp8266.com/stable/package_esp8266com_index.json,https://dl.espressif.com/dl/package_esp32_index.json,https://github.com/stm32duino/BoardManagerFiles/raw/master/STM32/package_stm_index.json" --save-prefs 2>&1
   - if [[ "$BOARD" =~ "esp8266:esp8266:" ]]; then
       arduino --install-boards esp8266:esp8266;
       export SKIP_PAT='(HTTP|MQTT).*ino';
     elif [[ "$BOARD" =~ "esp32:esp32:" ]]; then
       arduino --install-boards esp32:esp32;
-    elif [[ "$BOARD" =~ "stm32duino:STM32F1:" ]]; then
-      arduino --install-boards stm32duino:STM32F1;
+    elif [[ "$BOARD" =~ "STM32:stm32:" ]]; then
+      arduino --install-boards STM32:stm32;
     elif [[ "$BOARD" =~ "arduino:samd:" ]]; then
       arduino --install-boards arduino:samd;
     fi

From 0b1905680da4e977ff62b30ba112aa5b554933ac Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Tue, 10 Sep 2019 20:20:18 +0200
Subject: [PATCH 090/106] Travis ordered boards based on job run time

---
 .travis.yml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 836ed8b7..69cb0753 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,13 +4,13 @@ env:
   matrix:
     # see https://github.com/arduino/Arduino/blob/master/build/shared/manpage.adoc#options
     # and https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5-3rd-party-Hardware-specification#boardstxt
+    - BOARD="esp32:esp32:esp32"
+    - BOARD="STM32:stm32:GenF1:pnum=BLUEPILL_F103C6"
+    - BOARD="esp8266:esp8266:generic:xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K"
+    - BOARD="arduino:samd:arduino_zero_native"
     - BOARD="arduino:avr:uno"
     - BOARD="arduino:avr:leonardo"
     - BOARD="arduino:avr:mega:cpu=atmega2560"
-    - BOARD="esp8266:esp8266:generic:xtal=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,eesz=512K"
-    - BOARD="esp32:esp32:esp32"
-    - BOARD="STM32:stm32:GenF1:pnum=BLUEPILL_F103C6"
-    - BOARD="arduino:samd:arduino_zero_native"
 
 before_install:
   # install Arduino IDE

From e5f56f05276bc240917868f0e840c0774605dca9 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Tue, 10 Sep 2019 20:23:29 +0200
Subject: [PATCH 091/106] Updated readme

---
 README.md | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/README.md b/README.md
index 49452cd5..8689d233 100644
--- a/README.md
+++ b/README.md
@@ -34,6 +34,8 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github
 * __Arduino AVR boards__ - tested on Uno, Mega and Leonardo
 * __ESP8266 boards__ - NodeMCU, Wemos D1, etc.
 * __ESP32 boards__ - tested on ESP-WROOM-32
+* __STM32 boards__ - tested on BluePill F103C6
+* __SAMD boards__ - Arduino Zero
 
 ### In development:
 * __SIM800C__ GSM module

From 4a78527d98369ed5206224d78f97d807c357cab5 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Tue, 10 Sep 2019 20:23:47 +0200
Subject: [PATCH 092/106] Advanced version to 1.5.0

---
 library.properties | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library.properties b/library.properties
index a1345bb1..93fca1fb 100644
--- a/library.properties
+++ b/library.properties
@@ -1,5 +1,5 @@
 name=RadioLib
-version=1.4.0
+version=1.5.0
 author=Jan Gromes <gromes.jan@gmail.com>
 maintainer=Jan Gromes <gromes.jan@gmail.com>
 sentence=Universal wireless communication library for Arduino

From a04a376afc8af85d0d5c8249fe405009a541367f Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Wed, 11 Sep 2019 12:29:02 +0200
Subject: [PATCH 093/106] [SX126x] Fixed waiting for BUSY pin in sleep mode
 (#42)

---
 src/modules/SX126x.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/modules/SX126x.cpp b/src/modules/SX126x.cpp
index 94b9c581..dd920d0f 100644
--- a/src/modules/SX126x.cpp
+++ b/src/modules/SX126x.cpp
@@ -325,7 +325,7 @@ int16_t SX126x::scanChannel() {
 
 int16_t SX126x::sleep() {
   uint8_t data[] = {SX126X_SLEEP_START_COLD | SX126X_SLEEP_RTC_OFF};
-  int16_t state = SPIwriteCommand(SX126X_CMD_SET_SLEEP, data, 1);
+  int16_t state = SPIwriteCommand(SX126X_CMD_SET_SLEEP, data, 1, false);
 
   // wait for SX126x to safely enter sleep mode
   delayMicroseconds(500);

From 1046db24e464b28d880f6d6c40fb9e10f73c671f Mon Sep 17 00:00:00 2001
From: mmrein <55082189+mmrein@users.noreply.github.com>
Date: Thu, 12 Sep 2019 10:16:36 +0200
Subject: [PATCH 094/106] Add setSyncBits for SX126x

Add setSyncBits for possibility to set the sync word length in bits
---
 src/modules/SX126x.cpp | 27 +++++++++++++++++++++++++++
 src/modules/SX126x.h   | 11 +++++++++++
 2 files changed, 38 insertions(+)

diff --git a/src/modules/SX126x.cpp b/src/modules/SX126x.cpp
index dd920d0f..e76b05e2 100644
--- a/src/modules/SX126x.cpp
+++ b/src/modules/SX126x.cpp
@@ -721,6 +721,33 @@ int16_t SX126x::setSyncWord(uint8_t* syncWord, uint8_t len) {
   return(state);
 }
 
+int16_t SX126x::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) { 
+  // check active modem
+  if(getPacketType() != SX126X_PACKET_TYPE_GFSK) {
+    return(ERR_WRONG_MODEM);
+  }
+
+  // check sync word Length
+  if(bitsLen > 0x40) {
+    return(ERR_INVALID_SYNC_WORD);
+  }
+
+  uint8_t bytesLen = bitsLen / 8;
+  if ((bitsLen % 8) != 0) bytesLen++;
+  
+  // write sync word
+  int16_t state = writeRegister(SX126X_REG_SYNC_WORD_0, syncWord, bytesLen);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+
+  // update packet parameters
+  _syncWordLength = bitsLen;
+  state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp);
+
+  return(state);
+}
+
 int16_t SX126x::setNodeAddress(uint8_t nodeAddr) {
   // check active modem
   if(getPacketType() != SX126X_PACKET_TYPE_GFSK) {
diff --git a/src/modules/SX126x.h b/src/modules/SX126x.h
index 134325bd..df43c497 100644
--- a/src/modules/SX126x.h
+++ b/src/modules/SX126x.h
@@ -604,6 +604,17 @@ class SX126x: public PhysicalLayer {
     */
     int16_t setSyncWord(uint8_t* syncWord, uint8_t len);
 
+    /*!
+      \brief Sets FSK sync word in the form of array of up to 8 bytes.
+
+      \param syncWord FSK sync word to be set.
+
+      \param len FSK sync word length in bits.
+
+      \returns \ref status_codes
+    */
+    int16_t setSyncBits(uint8_t *sync, uint8_t bitsLen);
+
     /*!
       \brief Sets node address. Calling this method will also enable address filtering for node address only.
 

From 86ca0290235fdbca48950b35780cbeecb7b3e6a2 Mon Sep 17 00:00:00 2001
From: mmrein <55082189+mmrein@users.noreply.github.com>
Date: Mon, 16 Sep 2019 19:25:35 +0200
Subject: [PATCH 095/106] Update SX126x.cpp

---
 src/modules/SX126x.cpp | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/modules/SX126x.cpp b/src/modules/SX126x.cpp
index e76b05e2..99996ea8 100644
--- a/src/modules/SX126x.cpp
+++ b/src/modules/SX126x.cpp
@@ -733,7 +733,9 @@ int16_t SX126x::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) {
   }
 
   uint8_t bytesLen = bitsLen / 8;
-  if ((bitsLen % 8) != 0) bytesLen++;
+  if ((bitsLen % 8) != 0) {
+    bytesLen++;
+  }
   
   // write sync word
   int16_t state = writeRegister(SX126X_REG_SYNC_WORD_0, syncWord, bytesLen);

From dbbb12610ce748b36802fb50d1aeff1a8575ae6f Mon Sep 17 00:00:00 2001
From: mmrein <55082189+mmrein@users.noreply.github.com>
Date: Mon, 16 Sep 2019 19:32:41 +0200
Subject: [PATCH 096/106] Add setSyncBits to # SX126x-specific

---
 keywords.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/keywords.txt b/keywords.txt
index 1e47e76e..d0846298 100644
--- a/keywords.txt
+++ b/keywords.txt
@@ -106,6 +106,7 @@ setDio2Action	KEYWORD2
 setTCXO	KEYWORD2
 setDio2AsRfSwitch	KEYWORD2
 getTimeOnAir	KEYWORD2
+setSyncBits KEYWORD2
 
 # ESP8266
 join	KEYWORD2

From c543a42124b15d43b1922acf3f8854bd5942617c Mon Sep 17 00:00:00 2001
From: mmrein <55082189+mmrein@users.noreply.github.com>
Date: Mon, 16 Sep 2019 19:51:39 +0200
Subject: [PATCH 097/106] Add examle use for setSyncBits method

---
 examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino b/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino
index 61b6a1e8..5a924b6d 100644
--- a/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino
+++ b/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino
@@ -73,6 +73,13 @@ void setup() {
     Serial.println(state);
     while (true);
   }
+   
+  // FSK modem on SX126x can handle the sync word setting in bits, not just
+  // whole bytes. The value used is LSB first.
+  // This makes same result as fsk.setSyncWord(syncWord, 8):
+  state = fsk.setSyncBits(syncWord, 64);
+  // This will use 0x012 as sync word (12 bits only):
+  state = fsk.setSyncBits(syncWord, 12);
 
   // FSK modem allows advanced CRC configuration
   // Default is CCIT CRC16 (2 bytes, initial 0x1D0F, polynomial 0x1021, inverted)

From 9bb8586beb61c38d206f0ab6737dd3a4fa1f58bb Mon Sep 17 00:00:00 2001
From: mmrein <55082189+mmrein@users.noreply.github.com>
Date: Mon, 16 Sep 2019 19:54:49 +0200
Subject: [PATCH 098/106] Updated note for setSyncBits example

---
 examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino b/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino
index 5a924b6d..18050269 100644
--- a/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino
+++ b/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino
@@ -75,7 +75,7 @@ void setup() {
   }
    
   // FSK modem on SX126x can handle the sync word setting in bits, not just
-  // whole bytes. The value used is LSB first.
+  // whole bytes. The value used is left-justified.
   // This makes same result as fsk.setSyncWord(syncWord, 8):
   state = fsk.setSyncBits(syncWord, 64);
   // This will use 0x012 as sync word (12 bits only):

From a810a31c5f8a9125a7e787ac731804a25c35687a Mon Sep 17 00:00:00 2001
From: mmrein <55082189+mmrein@users.noreply.github.com>
Date: Mon, 16 Sep 2019 20:10:59 +0200
Subject: [PATCH 099/106] setSyncBits: *sync changed to *syncWord, added note

setSyncBits: Update *sync to *syncWord, add note about bits of syncWord being used if less than 64 bits.
---
 src/modules/SX126x.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/modules/SX126x.h b/src/modules/SX126x.h
index df43c497..b56c879d 100644
--- a/src/modules/SX126x.h
+++ b/src/modules/SX126x.h
@@ -607,13 +607,13 @@ class SX126x: public PhysicalLayer {
     /*!
       \brief Sets FSK sync word in the form of array of up to 8 bytes.
 
-      \param syncWord FSK sync word to be set.
+      \param syncWord FSK sync word to be set. 
 
-      \param len FSK sync word length in bits.
+      \param len FSK sync word length in bits. If less than 64 bits the LSB's of syncWord will be ignored.
 
       \returns \ref status_codes
     */
-    int16_t setSyncBits(uint8_t *sync, uint8_t bitsLen);
+    int16_t setSyncBits(uint8_t *syncWord, uint8_t bitsLen);
 
     /*!
       \brief Sets node address. Calling this method will also enable address filtering for node address only.

From 586486b1d357fee07e3815f730fced1e4d850937 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Tue, 17 Sep 2019 08:35:12 +0200
Subject: [PATCH 100/106] Fixed keyword separator

---
 keywords.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/keywords.txt b/keywords.txt
index d0846298..9f0d6d10 100644
--- a/keywords.txt
+++ b/keywords.txt
@@ -106,7 +106,7 @@ setDio2Action	KEYWORD2
 setTCXO	KEYWORD2
 setDio2AsRfSwitch	KEYWORD2
 getTimeOnAir	KEYWORD2
-setSyncBits KEYWORD2
+setSyncBits	KEYWORD2
 
 # ESP8266
 join	KEYWORD2

From 2ce924605303af36b016536dca1f87bf812e6ee8 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Tue, 17 Sep 2019 08:37:31 +0200
Subject: [PATCH 101/106] [SX126x] Fixed doxygen param name

---
 src/modules/SX126x.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/modules/SX126x.h b/src/modules/SX126x.h
index b56c879d..072cf7ac 100644
--- a/src/modules/SX126x.h
+++ b/src/modules/SX126x.h
@@ -607,9 +607,9 @@ class SX126x: public PhysicalLayer {
     /*!
       \brief Sets FSK sync word in the form of array of up to 8 bytes.
 
-      \param syncWord FSK sync word to be set. 
+      \param syncWord FSK sync word to be set.
 
-      \param len FSK sync word length in bits. If less than 64 bits the LSB's of syncWord will be ignored.
+      \param bitsLen FSK sync word length in bits. If length is not divisible by 8, least significant bits of syncWord will be ignored.
 
       \returns \ref status_codes
     */

From 138e3128951ae4280188e327e0c736032268becc Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Tue, 17 Sep 2019 08:37:53 +0200
Subject: [PATCH 102/106] [CC1101] Fixed example

---
 .../CC1101_Transmit_Interrupt.ino             | 64 +++++++++++++------
 1 file changed, 45 insertions(+), 19 deletions(-)

diff --git a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino
index 9a909d72..14bf31eb 100644
--- a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino
+++ b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino
@@ -25,6 +25,9 @@ CC1101 cc = new Module(10, 2, 3);
 // https://github.com/jgromes/RadioShield
 //CC1101 cc = RadioShield.ModuleA;
 
+// save transmission state between loops
+int transmissionState = ERR_NONE;
+
 void setup() {
   Serial.begin(9600);
 
@@ -53,7 +56,7 @@ void setup() {
 
   // you can transmit C-string or Arduino string up to
   // 64 characters long
-  state = cc.startTransmit("Hello World!");
+  transmissionState = cc.startTransmit("Hello World!");
 
   // you can also transmit byte array up to 64 bytes long
   /*
@@ -61,36 +64,61 @@ void setup() {
                       0x78, 0xAB, 0xCD, 0xEF};
     state = cc.transmit(byteArr, 8);
   */
-
-  if (state != ERR_NONE) {
-    Serial.print(F("failed, code "));
-    Serial.println(state);
-    while (true);
-  }
 }
 
-// flag to indicate that a packet was received
+// flag to indicate that a packet was sent
 volatile bool transmittedFlag = false;
 
+// disable interrupt when it's not needed
+volatile bool enableInterrupt = true;
+
+// 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!
 void setFlag(void) {
-  // packet transmission is finished, set the flag
+  // check if the interrupt is enabled
+  if(!enableInterrupt) {
+    return;
+  }
+
+  // we sent a packet, set the flag
   transmittedFlag = true;
 }
 
 void loop() {
   // check if the previous transmission finished
   if(transmittedFlag) {
-    Serial.println(F("packet transmission finished!"));
+    // disable the interrupt service routine while
+    // processing the data
+    enableInterrupt = false;
 
-    // wait one second before next transmission
+    // reset flag
+    transmittedFlag = false;
+
+    if (transmissionState == ERR_NONE) {
+      // packet was successfully sent
+      Serial.println(F("transmission finished!"));
+
+      // NOTE: when using interrupt-driven transmit method,
+      //       it is not possible to automatically measure
+      //       transmission data rate using getDataRate()
+
+    } else {
+      Serial.print(F("failed, code "));
+      Serial.println(transmissionState);
+
+    }
+
+    // wait a second before transmitting again
     delay(1000);
 
-    // send another packet
+    // send another one
     Serial.print(F("[CC1101] Sending another packet ... "));
 
     // you can transmit C-string or Arduino string up to
-    // 64 characters long
-    int state = cc.startTransmit("Hello World!");
+    // 256 characters long
+    transmissionState = cc.startTransmit("Hello World!");
 
     // you can also transmit byte array up to 256 bytes long
     /*
@@ -99,10 +127,8 @@ void loop() {
       int state = cc.transmit(byteArr, 8);
     */
 
-    if (state != ERR_NONE) {
-      Serial.print(F("failed, code "));
-      Serial.println(state);
-    }
+    // we're ready to send more packets,
+    // enable interrupt service routine
+    enableInterrupt = true;
   }
-
 }

From f7fc293cd2b1d174b649e56a61048e3502032aa4 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Tue, 17 Sep 2019 08:38:01 +0200
Subject: [PATCH 103/106] [RF69] Fixed example

---
 .../RF69_Transmit_Interrupt.ino               | 63 +++++++++++++------
 1 file changed, 45 insertions(+), 18 deletions(-)

diff --git a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino
index 1f4481ec..684a9a9d 100644
--- a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino
+++ b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino
@@ -25,6 +25,9 @@ RF69 rf = new Module(10, 2, 3);
 // https://github.com/jgromes/RadioShield
 //RF69 rf = RadioShield.ModuleA;
 
+// save transmission state between loops
+int transmissionState = ERR_NONE;
+
 void setup() {
   Serial.begin(9600);
 
@@ -54,7 +57,7 @@ void setup() {
 
   // you can transmit C-string or Arduino string up to
   // 64 characters long
-  state = rf.startTransmit("Hello World!");
+  transmissionState = rf.startTransmit("Hello World!");
 
   // you can also transmit byte array up to 64 bytes long
   /*
@@ -62,35 +65,61 @@ void setup() {
                       0x78, 0xAB, 0xCD, 0xEF};
     state = rf.transmit(byteArr, 8);
   */
-
-  if (state != ERR_NONE) {
-    Serial.print(F("failed, code "));
-    Serial.println(state);
-  }
 }
 
-// flag to indicate that a packet was received
+// flag to indicate that a packet was sent
 volatile bool transmittedFlag = false;
 
+// disable interrupt when it's not needed
+volatile bool enableInterrupt = true;
+
+// 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!
 void setFlag(void) {
-  // packet transmission is finished, set the flag
+  // check if the interrupt is enabled
+  if(!enableInterrupt) {
+    return;
+  }
+
+  // we sent a packet, set the flag
   transmittedFlag = true;
 }
 
 void loop() {
   // check if the previous transmission finished
   if(transmittedFlag) {
-    Serial.println(F("packet transmission finished!"));
+    // disable the interrupt service routine while
+    // processing the data
+    enableInterrupt = false;
 
-    // wait one second before next transmission
+    // reset flag
+    transmittedFlag = false;
+
+    if (transmissionState == ERR_NONE) {
+      // packet was successfully sent
+      Serial.println(F("transmission finished!"));
+
+      // NOTE: when using interrupt-driven transmit method,
+      //       it is not possible to automatically measure
+      //       transmission data rate using getDataRate()
+
+    } else {
+      Serial.print(F("failed, code "));
+      Serial.println(transmissionState);
+
+    }
+
+    // wait a second before transmitting again
     delay(1000);
 
-    // send another packet
+    // send another one
     Serial.print(F("[RF69] Sending another packet ... "));
 
     // you can transmit C-string or Arduino string up to
-    // 64 characters long
-    int state = rf.startTransmit("Hello World!");
+    // 256 characters long
+    transmissionState = rf.startTransmit("Hello World!");
 
     // you can also transmit byte array up to 256 bytes long
     /*
@@ -99,10 +128,8 @@ void loop() {
       int state = rf.transmit(byteArr, 8);
     */
 
-    if (state != ERR_NONE) {
-      Serial.print(F("failed, code "));
-      Serial.println(state);
-    }
+    // we're ready to send more packets,
+    // enable interrupt service routine
+    enableInterrupt = true;
   }
-
 }

From 5f1f6383597936eab8659bde71753a11151ba73a Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Tue, 17 Sep 2019 08:38:07 +0200
Subject: [PATCH 104/106] [SX126x] Fixed example

---
 .../SX126x_Transmit_Interrupt.ino             | 67 +++++++++++++------
 1 file changed, 45 insertions(+), 22 deletions(-)

diff --git a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino
index 04151894..f295c2e5 100644
--- a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino
+++ b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino
@@ -24,6 +24,9 @@
 // BUSY pin:  9
 SX1262 lora = new Module(10, 2, 3, 9);
 
+// save transmission state between loops
+int transmissionState = ERR_NONE;
+
 void setup() {
   Serial.begin(9600);
 
@@ -56,7 +59,7 @@ void setup() {
 
   // you can transmit C-string or Arduino string up to
   // 256 characters long
-  state = lora.startTransmit("Hello World!");
+  transmissionState = lora.startTransmit("Hello World!");
 
   // you can also transmit byte array up to 256 bytes long
   /*
@@ -64,51 +67,71 @@ void setup() {
                       0x78, 0xAB, 0xCD, 0xEF};
     state = lora.transmit(byteArr, 8);
   */
-
-  if (state != ERR_NONE) {
-    Serial.print(F("failed, code "));
-    Serial.println(state);
-  }
 }
 
-// flag to indicate that a packet was received
+// flag to indicate that a packet was sent
 volatile bool transmittedFlag = false;
 
+// disable interrupt when it's not needed
+volatile bool enableInterrupt = true;
+
+// 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!
 void setFlag(void) {
-  // packet transmission is finished, set the flag
+  // check if the interrupt is enabled
+  if(!enableInterrupt) {
+    return;
+  }
+
+  // we sent a packet, set the flag
   transmittedFlag = true;
 }
 
 void loop() {
   // check if the previous transmission finished
   if(transmittedFlag) {
-    Serial.println(F("packet transmission finished!"));
+    // disable the interrupt service routine while
+    // processing the data
+    enableInterrupt = false;
 
-    // wait one second before next transmission
+    // reset flag
+    transmittedFlag = false;
+
+    if (transmissionState == ERR_NONE) {
+      // packet was successfully sent
+      Serial.println(F("transmission finished!"));
+
+      // NOTE: when using interrupt-driven transmit method,
+      //       it is not possible to automatically measure
+      //       transmission data rate using getDataRate()
+
+    } else {
+      Serial.print(F("failed, code "));
+      Serial.println(transmissionState);
+
+    }
+
+    // wait a second before transmitting again
     delay(1000);
 
-    // send another packet
+    // send another one
     Serial.print(F("[SX1262] Sending another packet ... "));
 
     // you can transmit C-string or Arduino string up to
     // 256 characters long
-    int state = lora.startTransmit("Hello World!");
+    transmissionState = lora.startTransmit("Hello World!");
 
     // you can also transmit byte array up to 256 bytes long
     /*
       byte byteArr[] = {0x01, 0x23, 0x45, 0x56,
                         0x78, 0xAB, 0xCD, 0xEF};
-      int state = lora.startTransmit(byteArr, 8);
+      int state = lora.transmit(byteArr, 8);
     */
 
-    // NOTE: when using interrupt-driven transmit method,
-    //       it is not possible to automatically measure
-    //       transmission data rate using getDataRate()
-
-    if (state != ERR_NONE) {
-      Serial.print(F("failed, code "));
-      Serial.println(state);
-    }
+    // we're ready to send more packets,
+    // enable interrupt service routine
+    enableInterrupt = true;
   }
-
 }

From 3623c9e0f5a4e68e269d13d1d9adffa9f500443d Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Tue, 17 Sep 2019 08:38:31 +0200
Subject: [PATCH 105/106] [SX127x] Sync with LoRaLib v8.1.2

---
 .../SX127x_Transmit_Interrupt.ino             | 65 +++++++++++++------
 1 file changed, 44 insertions(+), 21 deletions(-)

diff --git a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino
index a0cc1f56..08681c9e 100644
--- a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino
+++ b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino
@@ -27,6 +27,9 @@ SX1278 lora = new Module(10, 2, 3);
 // https://github.com/jgromes/RadioShield
 //SX1278 lora = RadioShield.ModuleA;
 
+// save transmission state between loops
+int transmissionState = ERR_NONE;
+
 void setup() {
   Serial.begin(9600);
 
@@ -59,7 +62,7 @@ void setup() {
 
   // you can transmit C-string or Arduino string up to
   // 256 characters long
-  state = lora.startTransmit("Hello World!");
+  transmissionState = lora.startTransmit("Hello World!");
 
   // you can also transmit byte array up to 256 bytes long
   /*
@@ -67,35 +70,61 @@ void setup() {
                       0x78, 0xAB, 0xCD, 0xEF};
     state = lora.transmit(byteArr, 8);
   */
-
-  if (state != ERR_NONE) {
-    Serial.print(F("failed, code "));
-    Serial.println(state);
-  }
 }
 
-// flag to indicate that a packet was received
+// flag to indicate that a packet was sent
 volatile bool transmittedFlag = false;
 
+// disable interrupt when it's not needed
+volatile bool enableInterrupt = true;
+
+// 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!
 void setFlag(void) {
-  // packet transmission is finished, set the flag
+  // check if the interrupt is enabled
+  if(!enableInterrupt) {
+    return;
+  }
+
+  // we sent a packet, set the flag
   transmittedFlag = true;
 }
 
 void loop() {
   // check if the previous transmission finished
   if(transmittedFlag) {
-    Serial.println(F("packet transmission finished!"));
+    // disable the interrupt service routine while
+    // processing the data
+    enableInterrupt = false;
 
-    // wait one second before next transmission
+    // reset flag
+    transmittedFlag = false;
+
+    if (transmissionState == ERR_NONE) {
+      // packet was successfully sent
+      Serial.println(F("transmission finished!"));
+
+      // NOTE: when using interrupt-driven transmit method,
+      //       it is not possible to automatically measure
+      //       transmission data rate using getDataRate()
+
+    } else {
+      Serial.print(F("failed, code "));
+      Serial.println(transmissionState);
+
+    }
+
+    // wait a second before transmitting again
     delay(1000);
 
-    // send another packet
+    // send another one
     Serial.print(F("[SX1278] Sending another packet ... "));
 
     // you can transmit C-string or Arduino string up to
     // 256 characters long
-    int state = lora.startTransmit("Hello World!");
+    transmissionState = lora.startTransmit("Hello World!");
 
     // you can also transmit byte array up to 256 bytes long
     /*
@@ -104,14 +133,8 @@ void loop() {
       int state = lora.transmit(byteArr, 8);
     */
 
-    // NOTE: when using interrupt-driven transmit method,
-    //       it is not possible to automatically measure
-    //       transmission data rate using getDataRate()
-
-    if (state != ERR_NONE) {
-      Serial.print(F("failed, code "));
-      Serial.println(state);
-    }
+    // we're ready to send more packets,
+    // enable interrupt service routine
+    enableInterrupt = true;
   }
-
 }

From 7593769db4038120b8c66fe4db4de9429592033e Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Tue, 17 Sep 2019 09:31:04 +0200
Subject: [PATCH 106/106] Advanced version to 1.6.1

---
 library.properties | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library.properties b/library.properties
index 93fca1fb..b349f77e 100644
--- a/library.properties
+++ b/library.properties
@@ -1,5 +1,5 @@
 name=RadioLib
-version=1.5.0
+version=1.6.1
 author=Jan Gromes <gromes.jan@gmail.com>
 maintainer=Jan Gromes <gromes.jan@gmail.com>
 sentence=Universal wireless communication library for Arduino