From 7a768c8ed65bed919624e95f74725b30a6001984 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Fri, 22 Mar 2019 19:01:56 +0100
Subject: [PATCH] [SX127x] Sync with LoRaLib v8.0.1

---
 .../SX127x_FSK_Modem/SX127x_FSK_Modem.ino     | 14 ++++
 .../SX127x/SX127x_Receive/SX127x_Receive.ino  |  3 +
 .../SX127x_Transmit/SX127x_Transmit.ino       |  3 +
 keywords.txt                                  |  4 +
 src/Module.cpp                                | 73 +++++++++++--------
 src/Module.h                                  |  9 ++-
 src/TypeDef.h                                 |  1 +
 src/modules/SX1272.cpp                        | 67 +++++++++++++++--
 src/modules/SX1272.h                          | 28 ++++++-
 src/modules/SX1278.cpp                        | 68 ++++++++++++++---
 src/modules/SX1278.h                          | 28 ++++++-
 src/modules/SX127x.cpp                        | 73 +++++++++++++------
 src/modules/SX127x.h                          | 14 +++-
 13 files changed, 307 insertions(+), 78 deletions(-)

diff --git a/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino b/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino
index d5e23bf7..c129c6e1 100644
--- a/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino
+++ b/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino
@@ -29,6 +29,7 @@ void setup() {
   // current limit:               100 mA
   // data shaping:                Gaussian, BT = 0.3
   // sync word:                   0x2D  0x01
+  // OOK modulation:              false
   int state = fsk.beginFSK();
   if (state == ERR_NONE) {
     Serial.println(F("success!"));
@@ -61,6 +62,19 @@ void setup() {
     while (true);
   }
 
+  // FSK modulation can be changed to OOK
+  // NOTE: When using OOK, the maximum bit rate is only 32.768 kbps!
+  //       Also, data shaping changes from Gaussian filter to
+  //       simple filter with cutoff frequency. Make sure to call
+  //       setDataShapingOOK() to set the correct shaping!
+  state = fsk.setOOK(true);
+  state = fsk.setDataShapingOOK(1);
+  if (state != ERR_NONE) {
+    Serial.print(F("Unable to change modulation, code "));
+    Serial.println(state);
+    while (true);
+  }
+
   #warning "This sketch is just an API guide! Read the note at line 6."
 }
 
diff --git a/examples/SX127x/SX127x_Receive/SX127x_Receive.ino b/examples/SX127x/SX127x_Receive/SX127x_Receive.ino
index d70d1caa..b1f44767 100644
--- a/examples/SX127x/SX127x_Receive/SX127x_Receive.ino
+++ b/examples/SX127x/SX127x_Receive/SX127x_Receive.ino
@@ -48,6 +48,9 @@ void loop() {
   Serial.print(F("[SX1278] 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 = lora.receive(str);
 
diff --git a/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino b/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino
index 008e9156..9ac2a098 100644
--- a/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino
+++ b/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino
@@ -45,6 +45,9 @@ void loop() {
 
   // you can transmit C-string or Arduino string up to
   // 256 characters long
+  // NOTE: transmit() is a blocking method!
+  //       See example SX127x_Transmit_Interrupt for details
+  //       on non-blocking transmission method.
   int state = lora.transmit("Hello World!");
 
   // you can also transmit byte array up to 256 bytes long
diff --git a/keywords.txt b/keywords.txt
index fd020ec1..93d4afbc 100644
--- a/keywords.txt
+++ b/keywords.txt
@@ -79,6 +79,9 @@ setNodeAddress	KEYWORD2
 setBroadcastAddress	KEYWORD2
 disableAddressFiltering	KEYWORD2
 setDataShaping	KEYWORD2
+setOOK	KEYWORD2
+setDataShapingOOK	KEYWORD2
+setCRC	KEYWORD2
 
 # RF69-specific
 setAESKey	KEYWORD2
@@ -162,6 +165,7 @@ ERR_INVALID_BIT_RATE_BW_RATIO	LITERAL1
 ERR_INVALID_RX_BANDWIDTH	LITERAL1
 ERR_INVALID_SYNC_WORD	LITERAL1
 ERR_INVALID_DATA_SHAPING	LITERAL1
+ERR_INVALID_MODULATION	LITERAL1
 
 ERR_AT_FAILED	LITERAL1
 ERR_URL_MALFORMED	LITERAL1
diff --git a/src/Module.cpp b/src/Module.cpp
index 59f9a8c9..95653fca 100644
--- a/src/Module.cpp
+++ b/src/Module.cpp
@@ -10,20 +10,22 @@ Module::Module(int rx, int tx) {
   ModuleSerial = new SoftwareSerial(_rx, _tx);
 }
 
-Module::Module(int cs, int int0, int int1) {
+Module::Module(int cs, int int0, int int1, SPIClass& spi) {
   _cs = cs;
   _rx = -1;
   _tx = -1;
   _int0 = int0;
   _int1 = int1;
+  _spi = &spi;
 }
 
-Module::Module(int cs, int rx, int tx, int int0, int int1) {
+Module::Module(int cs, int rx, int tx, int int0, int int1, SPIClass& spi) {
   _cs = cs;
   _rx = rx;
   _tx = tx;
   _int0 = int0;
   _int1 = int1;
+  _spi = &spi;
   
   ModuleSerial = new SoftwareSerial(_rx, _tx);
 }
@@ -33,7 +35,7 @@ void Module::init(uint8_t interface, uint8_t gpio) {
     case USE_SPI:
       pinMode(_cs, OUTPUT);
       digitalWrite(_cs, HIGH);
-      SPI.begin();
+      _spi->begin();
       break;
     case USE_UART:
       ModuleSerial->begin(baudrate);
@@ -58,6 +60,11 @@ void Module::init(uint8_t interface, uint8_t gpio) {
   }
 }
 
+void Module::term() {
+  // stop SPI
+  _spi->end();
+}
+
 void Module::ATemptyBuffer() {
   while(ModuleSerial->available() > 0) {
     ModuleSerial->read();
@@ -160,39 +167,47 @@ int16_t Module::SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t
 }
 
 void Module::SPIreadRegisterBurst(uint8_t reg, uint8_t numBytes, uint8_t* inBytes) {
-  digitalWrite(_cs, LOW);
-  SPI.transfer(reg | SPIreadCommand);
-  for(uint8_t i = 0; i < numBytes; i++) {
-    inBytes[i] = SPI.transfer(reg);
-  }
-  digitalWrite(_cs, HIGH);
+  SPItransfer(SPIreadCommand, reg, NULL, inBytes, numBytes);
 }
 
 uint8_t Module::SPIreadRegister(uint8_t reg) {
-  uint8_t inByte;
-  digitalWrite(_cs, LOW);
-  SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
-  SPI.transfer(reg | SPIreadCommand);
-  SPI.endTransaction();
-  inByte = SPI.transfer(0x00);
-  digitalWrite(_cs, HIGH);
-  return(inByte);
+  uint8_t resp;
+  SPItransfer(SPIreadCommand, reg, NULL, &resp, 1);
+  return(resp);
 }
 
 void Module::SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, uint8_t numBytes) {
-  digitalWrite(_cs, LOW);
-  SPI.transfer(reg | SPIwriteCommand);
-  for(uint8_t i = 0; i < numBytes; i++) {
-    SPI.transfer(data[i]);
-  }
-  digitalWrite(_cs, HIGH);
+  SPItransfer(SPIwriteCommand, reg, data, NULL, numBytes);
 }
 
 void Module::SPIwriteRegister(uint8_t reg, uint8_t data) {
-  digitalWrite(_cs, LOW);
-  SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
-  SPI.transfer(reg | SPIwriteCommand);
-  SPI.transfer(data);
-  SPI.endTransaction();
-  digitalWrite(_cs, HIGH);
+  SPItransfer(SPIwriteCommand, reg, &data, NULL, 1);
+}
+
+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));
+  
+  // pull CS low
+  digitalWrite(_cs, LOW);
+  
+  // send SPI register address with access command
+  _spi->transfer(reg | cmd);
+  
+  // send data or get response
+  if(cmd == SPIwriteCommand) {
+    for(size_t n = 0; n < numBytes; n++) {
+      _spi->transfer(dataOut[n]);
+    }
+  } else if (cmd == SPIreadCommand) {
+    for(size_t n = 0; n < numBytes; n++) {
+      dataIn[n] = _spi->transfer(0x00);
+    }
+  }
+  
+  // release CS
+  digitalWrite(_cs, HIGH);
+  
+  // end SPI transaction
+  _spi->endTransaction();
 }
diff --git a/src/Module.h b/src/Module.h
index aae40eac..7ee55b0c 100644
--- a/src/Module.h
+++ b/src/Module.h
@@ -10,8 +10,8 @@
 class Module {
   public:
     Module(int tx, int rx);
-    Module(int cs, int int0, int int1);
-    Module(int cs, int rx, int tx, int int0, int int1);
+    Module(int cs, int int0, int int1, SPIClass& spi = SPI);
+    Module(int cs, int rx, int tx, int int0, int int1, SPIClass& spi = SPI);
     
     SoftwareSerial* ModuleSerial;
     
@@ -22,6 +22,7 @@ class Module {
     uint8_t SPIwriteCommand = 0b10000000;
     
     void init(uint8_t interface, uint8_t gpio);
+    void term();
     
     void ATemptyBuffer();
     bool ATgetResponse();
@@ -37,6 +38,8 @@ class Module {
     void SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, uint8_t numBytes);
     void SPIwriteRegister(uint8_t reg, uint8_t data);
     
+    void SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes);
+    
     int getCs() const { return(_cs); }
     int getInt0() const { return(_int0); }
     int getInt1() const { return(_int1); }
@@ -48,6 +51,8 @@ class Module {
     int _int0;
     int _int1;
     
+    SPIClass* _spi;
+    
     uint32_t _ATtimeout = 15000;
 };
 
diff --git a/src/TypeDef.h b/src/TypeDef.h
index 01ae29d9..30a077c1 100644
--- a/src/TypeDef.h
+++ b/src/TypeDef.h
@@ -70,6 +70,7 @@
 #define ERR_INVALID_RX_BANDWIDTH              -104
 #define ERR_INVALID_SYNC_WORD                 -105
 #define ERR_INVALID_DATA_SHAPING              -106
+#define ERR_INVALID_MODULATION                -107
 
 // ESP8266 status codes
 #define ERR_AT_FAILED                         -201
diff --git a/src/modules/SX1272.cpp b/src/modules/SX1272.cpp
index 04288d08..57cc72f9 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, float sh) {
+int16_t SX1272::beginFSK(float freq, float br, float rxBw, float freqDev, int8_t power, uint8_t currentLimit, bool enableOOK) {
   // execute common part
-  int16_t state = SX127x::beginFSK(SX1272_CHIP_VERSION, br, rxBw, freqDev, currentLimit);
+  int16_t state = SX127x::beginFSK(SX1272_CHIP_VERSION, br, rxBw, freqDev, currentLimit, enableOOK);
   if(state != ERR_NONE) {
     return(state);
   }
@@ -82,11 +82,6 @@ int16_t SX1272::beginFSK(float freq, float br, float rxBw, float freqDev, int8_t
     return(state);
   }
   
-  state = setDataShaping(sh);
-  if(state != ERR_NONE) {
-    return(state);
-  }
-  
   return(state);
 }
 
@@ -268,6 +263,11 @@ int16_t SX1272::setDataShaping(float sh) {
     return(ERR_WRONG_MODEM);
   }
   
+  // check modulation
+  if(!SX127x::_ook) {
+    return(ERR_INVALID_MODULATION);
+  }
+  
   // set mode to standby
   int16_t state = SX127x::standby();
   
@@ -286,6 +286,39 @@ int16_t SX1272::setDataShaping(float sh) {
   return(state);
 }
 
+int16_t SX1272::setDataShapingOOK(uint8_t sh) {
+  // check active modem
+  if(getActiveModem() != SX127X_FSK_OOK) {
+    return(ERR_WRONG_MODEM);
+  }
+  
+  // check modulation
+  if(!SX127x::_ook) {
+    return(ERR_INVALID_MODULATION);
+  }
+  
+  // set mode to standby
+  int16_t state = SX127x::standby();
+  
+  // set data shaping
+  switch(sh) {
+    case 0:
+      state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1272_NO_SHAPING, 4, 3);
+      break;
+    case 1:
+      state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1272_OOK_FILTER_BR, 4, 3);
+      break;
+    case 2:
+      state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1272_OOK_FILTER_2BR, 4, 3);
+      break;
+    default:
+      state = ERR_INVALID_DATA_SHAPING;
+      break;
+  }
+  
+  return(state);
+}
+
 int8_t SX1272::getRSSI() {
   // check active modem
   if(getActiveModem() != SX127X_LORA) {
@@ -304,6 +337,24 @@ int8_t SX1272::getRSSI() {
   return(lastPacketRSSI);
 }
 
+int16_t SX1272::setCRC(bool enableCRC) {
+  if(getActiveModem() == SX127X_LORA) {
+    // set LoRa CRC
+    if(enableCRC) {
+      return(_mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX1272_RX_CRC_MODE_ON, 2, 2));
+    } else {
+      return(_mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX1272_RX_CRC_MODE_OFF, 2, 2));
+    }
+  } else {
+    // set FSK CRC
+    if(enableCRC) {
+      return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_ON, 4, 4));
+    } else {
+      return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_OFF, 4, 4));
+    }
+  }
+}
+
 int16_t SX1272::setBandwidthRaw(uint8_t newBandwidth) {
   // set mode to standby
   int16_t state = SX127x::standby();
@@ -319,7 +370,7 @@ int16_t SX1272::setSpreadingFactorRaw(uint8_t newSpreadingFactor) {
   
   // write registers
   if(newSpreadingFactor == SX127X_SF_6) {
-    state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_HEADER_IMPL_MODE | SX1272_RX_CRC_MODE_OFF, 2, 1);
+    state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_HEADER_IMPL_MODE | SX1272_RX_CRC_MODE_ON, 2, 1);
     state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX127X_SF_6 | SX127X_TX_MODE_SINGLE, 7, 3);
     state |= _mod->SPIsetRegValue(SX127X_REG_DETECT_OPTIMIZE, SX127X_DETECT_OPTIMIZE_SF_6, 2, 0);
     state |= _mod->SPIsetRegValue(SX127X_REG_DETECTION_THRESHOLD, SX127X_DETECTION_THRESHOLD_SF_6);
diff --git a/src/modules/SX1272.h b/src/modules/SX1272.h
index c2a8707e..38a39432 100644
--- a/src/modules/SX1272.h
+++ b/src/modules/SX1272.h
@@ -148,11 +148,11 @@ 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 sh Gaussian shaping 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.
+      \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, float sh = 0.3);
+    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
     
@@ -212,8 +212,8 @@ class SX1272: public SX127x {
     int16_t setGain(uint8_t gain);
     
     /*!
-      \brief Sets gaussian shaping 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.
+      \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
       
@@ -221,12 +221,32 @@ class SX1272: public SX127x {
     */
     int16_t setDataShaping(float sh);
     
+    /*!
+      \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);
diff --git a/src/modules/SX1278.cpp b/src/modules/SX1278.cpp
index 91d9ef7a..effb54fc 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, float sh) {
+int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t currentLimit, bool enableOOK) {
   // execute common part
-  int16_t state = SX127x::beginFSK(SX1278_CHIP_VERSION, br, freqDev, rxBw, currentLimit);
+  int16_t state = SX127x::beginFSK(SX1278_CHIP_VERSION, br, freqDev, rxBw, currentLimit, enableOOK);
   if(state != ERR_NONE) {
     return(state);
   }
@@ -75,11 +75,6 @@ int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t
     return(state);
   }
   
-  state = setDataShaping(sh);
-  if(state != ERR_NONE) {
-    return(state);
-  }
-  
   return(state);
 }
 
@@ -338,6 +333,11 @@ int16_t SX1278::setDataShaping(float sh) {
     return(ERR_WRONG_MODEM);
   }
   
+  // check modulation
+  if(SX127x::_ook) {
+    return(ERR_INVALID_MODULATION);
+  }
+  
   // set mode to standby
   int16_t state = SX127x::standby();
   
@@ -356,6 +356,38 @@ int16_t SX1278::setDataShaping(float sh) {
   return(state);
 }
 
+int16_t SX1278::setDataShapingOOK(uint8_t sh) {
+  // check active modem
+  if(getActiveModem() != SX127X_FSK_OOK) {
+    return(ERR_WRONG_MODEM);
+  }
+  
+  // check modulation
+  if(!SX127x::_ook) {
+    return(ERR_INVALID_MODULATION);
+  }
+  
+  // set mode to standby
+  int16_t state = SX127x::standby();
+  
+  // set data shaping
+  switch(sh) {
+    case 0:
+      state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_NO_SHAPING, 6, 5);
+      break;
+    case 1:
+      state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_OOK_FILTER_BR, 6, 5);
+      break;
+    case 2:
+      state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_OOK_FILTER_2BR, 6, 5);
+      break;
+    default:
+      return(ERR_INVALID_DATA_SHAPING);
+  }
+  
+  return(state);
+}
+
 int8_t SX1278::getRSSI() {
   // check active modem
   if(getActiveModem() != SX127X_LORA) {
@@ -381,6 +413,24 @@ int8_t SX1278::getRSSI() {
   return(lastPacketRSSI);
 }
 
+int16_t SX1278::setCRC(bool enableCRC) {
+  if(getActiveModem() == SX127X_LORA) {
+    // set LoRa CRC
+    if(enableCRC) {
+      return(_mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX1278_RX_CRC_MODE_ON, 2, 2));
+    } else {
+      return(_mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX1278_RX_CRC_MODE_OFF, 2, 2));
+    }
+  } else {
+    // set FSK CRC
+    if(enableCRC) {
+      return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_ON, 4, 4));
+    } else {
+      return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_OFF, 4, 4));
+    }
+  }
+}
+
 int16_t SX1278::setBandwidthRaw(uint8_t newBandwidth) {
   // set mode to standby
   int16_t state = SX127x::standby();
@@ -397,12 +447,12 @@ int16_t SX1278::setSpreadingFactorRaw(uint8_t newSpreadingFactor) {
   // write registers
   if(newSpreadingFactor == SX127X_SF_6) {
     state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1278_HEADER_IMPL_MODE, 0, 0);
-    state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX127X_SF_6 | SX127X_TX_MODE_SINGLE | SX1278_RX_CRC_MODE_OFF, 7, 2);
+    state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX127X_SF_6 | SX127X_TX_MODE_SINGLE | SX1278_RX_CRC_MODE_ON, 7, 2);
     state |= _mod->SPIsetRegValue(SX127X_REG_DETECT_OPTIMIZE, SX127X_DETECT_OPTIMIZE_SF_6, 2, 0);
     state |= _mod->SPIsetRegValue(SX127X_REG_DETECTION_THRESHOLD, SX127X_DETECTION_THRESHOLD_SF_6);
   } else {
     state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1278_HEADER_EXPL_MODE, 0, 0);
-    state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | SX127X_TX_MODE_SINGLE | SX1278_RX_CRC_MODE_OFF, 7, 2);
+    state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | SX127X_TX_MODE_SINGLE | SX1278_RX_CRC_MODE_ON, 7, 2);
     state |= _mod->SPIsetRegValue(SX127X_REG_DETECT_OPTIMIZE, SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0);
     state |= _mod->SPIsetRegValue(SX127X_REG_DETECTION_THRESHOLD, SX127X_DETECTION_THRESHOLD_SF_7_12);
   }
diff --git a/src/modules/SX1278.h b/src/modules/SX1278.h
index 6349989b..5273175b 100644
--- a/src/modules/SX1278.h
+++ b/src/modules/SX1278.h
@@ -157,11 +157,11 @@ 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 sh Gaussian shaping 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.
+      \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, float sh = 0.3);
+    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
     
@@ -221,8 +221,8 @@ class SX1278: public SX127x {
     int16_t setGain(uint8_t gain);
     
     /*!
-      \brief Sets gaussian shaping 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.
+      \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
       
@@ -230,12 +230,32 @@ class SX1278: public SX127x {
     */
     int16_t setDataShaping(float sh);
     
+    /*!
+      \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);
diff --git a/src/modules/SX127x.cpp b/src/modules/SX127x.cpp
index 5b3d9745..a00d23a9 100644
--- a/src/modules/SX127x.cpp
+++ b/src/modules/SX127x.cpp
@@ -10,11 +10,11 @@ int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint8_t currentLimi
   
   // try to find the SX127x chip
   if(!SX127x::findChip(chipVersion)) {
-    DEBUG_PRINTLN(F("No SX127x found!"));
-    SPI.end();
+    DEBUG_PRINTLN("No SX127x found!");
+    _mod->term();
     return(ERR_CHIP_NOT_FOUND);
   } else {
-    DEBUG_PRINTLN(F("Found SX127x!"));
+    DEBUG_PRINTLN("Found SX127x!");
   }
   
   // check active modem
@@ -48,17 +48,17 @@ 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) {
+int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxBw, uint8_t currentLimit, bool enableOOK) {
   // set module properties
   _mod->init(USE_SPI, INT_BOTH);
   
   // try to find the SX127x chip
   if(!SX127x::findChip(chipVersion)) {
-    DEBUG_PRINTLN(F("No SX127x found!"));
-    SPI.end();
+    DEBUG_PRINTLN("No SX127x found!");
+    _mod->term();
     return(ERR_CHIP_NOT_FOUND);
   } else {
-    DEBUG_PRINTLN(F("Found SX127x!"));
+    DEBUG_PRINTLN("Found SX127x!");
   }
   
   // check currently active modem
@@ -104,6 +104,12 @@ int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxB
   
   // disable address filtering
   state = disableAddressFiltering();
+  if(state != ERR_NONE) {
+    return(state);
+  }
+  
+  // enable/disable OOK
+  state = setOOK(enableOOK);
   
   return(state);
 }
@@ -208,6 +214,7 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) {
     while(!digitalRead(_mod->getInt0())) {
       if(millis() - start > timeout) {
         clearIRQFlags();
+        standby();
         return(ERR_TX_TIMEOUT);
       }
     }
@@ -215,7 +222,10 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) {
     // clear interrupt flags
     clearIRQFlags();
     
-    return(ERR_NONE);
+    // set mode to standby to disable transmitter
+    state |= standby();
+    
+    return(state);
   }
   
   return(ERR_UNKNOWN);
@@ -785,8 +795,14 @@ int16_t SX127x::setBitRate(float br) {
   }
 
   // check allowed bitrate
-  if((br < 1.2) || (br > 300.0)) {
-    return(ERR_INVALID_BIT_RATE);
+  if(_ook) {
+    if((br < 1.2) || (br > 32.768)) {
+      return(ERR_INVALID_BIT_RATE);
+    }
+  } else {
+    if((br < 1.2) || (br > 300.0)) {
+      return(ERR_INVALID_BIT_RATE);
+    }
   }
   
   // set mode to STANDBY
@@ -794,12 +810,13 @@ int16_t SX127x::setBitRate(float br) {
   if(state != ERR_NONE) {
     return(state);
   }
-  
+
   // set bit rate
-  uint16_t bitRate = 32000 / br;
+  uint16_t bitRate = (SX127X_CRYSTAL_FREQ * 1000.0) / br;
   state = _mod->SPIsetRegValue(SX127X_REG_BITRATE_MSB, (bitRate & 0xFF00) >> 8, 7, 0);
   state |= _mod->SPIsetRegValue(SX127X_REG_BITRATE_LSB, bitRate & 0x00FF, 7, 0);
-  // TODO: fractional part of bit rate setting
+
+  // TODO: fractional part of bit rate setting (not in OOK)
   if(state == ERR_NONE) {
     SX127x::_br = br;
   }
@@ -899,7 +916,7 @@ int16_t SX127x::setSyncWord(uint8_t* syncWord, size_t len) {
   }
   
   // set sync word
-  _mod->SPIwriteRegisterBurst(SX127X_SYNC_VALUE_1, syncWord, len);
+  _mod->SPIwriteRegisterBurst(SX127X_REG_SYNC_VALUE_1, syncWord, len);
   return(ERR_NONE);
 }
 
@@ -957,6 +974,26 @@ int16_t SX127x::disableAddressFiltering() {
   return(_mod->SPIsetRegValue(SX127X_REG_BROADCAST_ADRS, 0x00));
 }
 
+int16_t SX127x::setOOK(bool enableOOK) {
+  // check active modem
+  if(getActiveModem() != SX127X_FSK_OOK) {
+    return(ERR_WRONG_MODEM);
+  }
+  
+  // set OOK and if successful, save the new setting
+  int16_t state = ERR_NONE;
+  if(enableOOK) { 
+    state = _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX127X_MODULATION_OOK, 6, 5, 5);
+  } else {
+    state = _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX127X_MODULATION_FSK, 6, 5, 5);
+  }
+  if(state == ERR_NONE) {
+    _ook = enableOOK;
+  }
+  
+  return(state);
+}
+
 int16_t SX127x::setFrequencyRaw(float newFreq) {
   // set mode to standby
   int16_t state = setMode(SX127X_STANDBY);
@@ -978,14 +1015,8 @@ int16_t SX127x::config() {
 }
 
 int16_t SX127x::configFSK() {
-  // set FSK modulation
-  int16_t state = _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX127X_MODULATION_FSK, 6, 5, 5);
-  if(state != ERR_NONE) {
-    return(state);
-  }
-  
   // set RSSI threshold
-  state = _mod->SPIsetRegValue(SX127X_REG_RSSI_THRESH, SX127X_RSSI_THRESHOLD);
+  int16_t state = _mod->SPIsetRegValue(SX127X_REG_RSSI_THRESH, SX127X_RSSI_THRESHOLD);
   if(state != ERR_NONE) {
     return(state);
   }
diff --git a/src/modules/SX127x.h b/src/modules/SX127x.h
index 6d9a9e10..70ba2085 100644
--- a/src/modules/SX127x.h
+++ b/src/modules/SX127x.h
@@ -572,9 +572,11 @@ class SX127x: public PhysicalLayer {
       
       \param currentLimit Trim value for OCP (over current protection) in mA.
       
+      \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);
+    int16_t beginFSK(uint8_t chipVersion, float br, float freqDev, float rxBw, uint8_t currentLimit, 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.
@@ -848,6 +850,15 @@ class SX127x: public PhysicalLayer {
     */
     int16_t disableAddressFiltering();
     
+    /*!
+      \brief Enables/disables OOK modulation instead of FSK.
+      
+      \param enableOOK Enable (true) or disable (false) OOK.
+      
+      \returns \ref status_codes
+    */
+    int16_t setOOK(bool enableOOK);
+    
     #ifdef RADIOLIB_DEBUG
       void regDump();
     #endif
@@ -861,6 +872,7 @@ class SX127x: public PhysicalLayer {
     uint8_t _cr;
     float _br;
     float _rxBw;
+    bool _ook;
     
     int16_t tx(char* data, uint8_t length);
     int16_t rxSingle(char* data, uint8_t* length);