diff --git a/keywords.txt b/keywords.txt
index 93d4afbc..53bfc893 100644
--- a/keywords.txt
+++ b/keywords.txt
@@ -20,6 +20,7 @@ RFM96	KEYWORD1
 RFM97	KEYWORD1
 RFM98	KEYWORD1
 SX1231	KEYWORD1
+SX1262	KEYWORD1
 SX1272	KEYWORD1
 SX1273	KEYWORD1
 SX1276	KEYWORD1
diff --git a/src/RadioLib.h b/src/RadioLib.h
index 0b432443..0de12de2 100644
--- a/src/RadioLib.h
+++ b/src/RadioLib.h
@@ -13,6 +13,7 @@
 #include "modules/RFM96.h"
 #include "modules/RFM97.h"
 #include "modules/SX1231.h"
+#include "modules/SX1262.h"
 #include "modules/SX1272.h"
 #include "modules/SX1273.h"
 #include "modules/SX1276.h"
diff --git a/src/modules/SX1262.cpp b/src/modules/SX1262.cpp
new file mode 100644
index 00000000..0e8a6377
--- /dev/null
+++ b/src/modules/SX1262.cpp
@@ -0,0 +1,56 @@
+#include "SX1262.h"
+
+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, currentLimit, 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);
+  }
+  
+  return(state);
+}
+
+int16_t SX1262::setFrequency(float freq) {
+  // check frequency range
+  if((freq < 150.0) || (freq > 960.0)) {
+    return(ERR_INVALID_FREQUENCY);
+  }
+  
+  // set frequency
+  return(SX126x::setFrequencyRaw(freq));
+}
+
+int16_t SX1262::setOutputPower(int8_t power) {
+  // check allowed power range
+  if(!((power >= -17) && (power <= 22))) {
+    return(ERR_INVALID_OUTPUT_POWER);
+  }
+  
+  // enable high power PA for output power higher than 14 dBm
+  if(power > 14) {
+    SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1262);
+  } else {
+    SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1261);
+  }
+  
+  // set output power
+  // TODO power ramp time configuration
+  SX126x::setTxParams(power);
+  return(ERR_NONE);
+}
+    
diff --git a/src/modules/SX1262.h b/src/modules/SX1262.h
new file mode 100644
index 00000000..f740dc37
--- /dev/null
+++ b/src/modules/SX1262.h
@@ -0,0 +1,29 @@
+#ifndef _RADIOLIB_SX1262_H
+#define _RADIOLIB_SX1262_H
+
+#include "TypeDef.h"
+#include "Module.h"
+#include "SX126x.h"
+
+//SX126X_CMD_SET_PA_CONFIG
+#define SX126X_PA_CONFIG_SX1261                       0x01
+#define SX126X_PA_CONFIG_SX1262                       0x00
+
+class SX1262: public SX126x {
+  public:
+    // constructor
+    SX1262(Module* mod);
+    
+    // basic methods
+    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);
+    
+    // configuration methods
+    int16_t setFrequency(float freq);
+    int16_t setOutputPower(int8_t power);
+    
+  private:
+    
+    
+};
+
+#endif
diff --git a/src/modules/SX126x.cpp b/src/modules/SX126x.cpp
new file mode 100644
index 00000000..4de399b8
--- /dev/null
+++ b/src/modules/SX126x.cpp
@@ -0,0 +1,360 @@
+#include "SX126x.h"
+
+SX126x::SX126x(Module* mod) : PhysicalLayer(SX126X_CRYSTAL_FREQ, SX126X_DIV_EXPONENT) {
+  _mod = mod;
+  _bw = SX126X_LORA_BW_125_0;
+  _bwKhz = 125.0;
+  _sf = 9;
+  _cr = SX126X_LORA_CR_4_7;
+  _ldro = 0x00;
+}
+
+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);
+  
+  // set mode to standby
+  standby();
+  
+  // configure settings not accessible by API
+  config();
+  
+  // configure publicly accessible settings
+  int16_t state = setBandwidth(bw);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+  
+  state = setSpreadingFactor(sf);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+  
+  state = setCodingRate(cr);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+  
+  state = setSyncWord(syncWord);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+  
+  state = setCurrentLimit(currentLimit);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+  
+  state = setPreambleLength(preambleLength);
+  if(state != ERR_NONE) {
+    return(state);
+  }
+  
+  return(state);
+}
+
+int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) {
+
+}
+
+int16_t SX126x::receive(uint8_t* data, size_t len) {
+
+}
+
+int16_t SX126x::transmitDirect(uint32_t frf) {
+
+}
+
+int16_t SX126x::receiveDirect() {
+
+}
+
+int16_t SX126x::sleep() {
+  uint8_t data[] = {SX126X_SLEEP_START_COLD | SX126X_SLEEP_RTC_OFF};
+  SPIwriteCommand(SX126X_CMD_SET_SLEEP, data, 1);
+  
+  // wait for SX126x to safely enter sleep mode
+  delayMicroseconds(500);
+  
+  return(ERR_NONE);
+}
+
+int16_t SX126x::standby(uint8_t mode) {
+  uint8_t data[] = {mode};
+  SPIwriteCommand(SX126X_CMD_SET_STANDBY, data, 1);
+  return(ERR_NONE);
+}
+
+int16_t SX126x::setBandwidth(float bw) {
+  // check active modem
+  if(getPacketType() != SX126X_PACKET_TYPE_LORA) {
+    return(ERR_WRONG_MODEM);
+  }
+
+  // check alowed bandwidth values
+  if(abs(bw - 7.8) <= 0.001) {
+    _bw = SX126X_LORA_BW_7_8;
+  } else if(abs(bw - 10.4) <= 0.001) {
+    _bw = SX126X_LORA_BW_10_4;
+  } else if(abs(bw - 15.6) <= 0.001) {
+    _bw = SX126X_LORA_BW_15_6;
+  } else if(abs(bw - 20.8) <= 0.001) {
+    _bw = SX126X_LORA_BW_20_8;
+  } else if(abs(bw - 31.25) <= 0.001) {
+    _bw = SX126X_LORA_BW_31_25;
+  } else if(abs(bw - 41.7) <= 0.001) {
+    _bw = SX126X_LORA_BW_41_7;
+  } else if(abs(bw - 62.5) <= 0.001) {
+    _bw = SX126X_LORA_BW_62_5;
+  } else if(abs(bw - 125.0) <= 0.001) {
+    _bw = SX126X_LORA_BW_125_0;
+  } else if(abs(bw - 250.0) <= 0.001) {
+    _bw = SX126X_LORA_BW_250_0;
+  } else if(abs(bw - 500.0) <= 0.001) {
+    _bw = SX126X_LORA_BW_500_0;
+  } else {
+    return(ERR_INVALID_BANDWIDTH);
+  }
+  
+  // update modulation parameters
+  _bwKhz = bw;
+  setModulationParams(_bw, _sf, _cr);
+  return(ERR_NONE);
+}
+
+int16_t SX126x::setSpreadingFactor(uint8_t sf) {
+  // check active modem
+  if(getPacketType() != SX126X_PACKET_TYPE_LORA) {
+    return(ERR_WRONG_MODEM);
+  }
+  
+  // check allowed spreading factor values
+  if(!((sf >= 5) && (sf <= 12))) {
+    return(ERR_INVALID_SPREADING_FACTOR);
+  }
+  
+  // update modulation parameters
+  _sf = sf;
+  setModulationParams(_bw, _sf, _cr);
+  return(ERR_NONE);
+}
+
+int16_t SX126x::setCodingRate(uint8_t cr) {
+  // check active modem
+  if(getPacketType() != SX126X_PACKET_TYPE_LORA) {
+    return(ERR_WRONG_MODEM);
+  }
+  
+  // check allowed spreading factor values
+  if(!((cr >= 5) && (cr <= 8))) {
+    return(ERR_INVALID_CODING_RATE);
+  }
+  
+  // update modulation parameters
+  _cr = cr - 4;
+  setModulationParams(_bw, _sf, _cr);
+  return(ERR_NONE);
+}
+
+int16_t SX126x::setSyncWord(uint16_t syncWord) {
+  // check active modem
+  if(getPacketType() != SX126X_PACKET_TYPE_LORA) {
+    return(ERR_WRONG_MODEM);
+  }
+  
+  // update register
+  uint8_t data[2] = {(uint8_t)((syncWord >> 8) & 0xFF), (uint8_t)(syncWord & 0xFF)};
+  writeRegister(SX126X_REG_LORA_SYNC_WORD_MSB, data, 2);
+  return(ERR_NONE);
+}
+
+int16_t SX126x::setCurrentLimit(float currentLimit) {
+  // calculate raw value
+  uint8_t rawLimit = (uint8_t)(currentLimit / 2.5);
+  
+  // update register
+  writeRegister(SX126X_REG_OCP_CONFIGURATION, &rawLimit, 1);
+  return(ERR_NONE);
+}
+
+int16_t SX126x::setPreambleLength(uint16_t preambleLength) {
+  // update packet parameters
+  _preambleLength = preambleLength;
+  setPacketParams((uint8_t)((_preambleLength >> 8) & 0xFF), (uint8_t)(_preambleLength & 0xFF), _payloadLength, _crcType);
+  return(ERR_NONE);
+}
+
+float SX126x::getDataRate() {
+
+}
+
+int16_t SX126x::setFrequencyDeviation(float freqDev) {
+
+}
+
+void SX126x::setTx(uint32_t timeout) {
+  uint8_t data[3] = {(uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF)};
+  SPIwriteCommand(SX126X_CMD_SET_TX, data, 3);
+}
+
+void SX126x::setRx(uint32_t timeout) {
+  uint8_t data[3] = {(uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF)};
+  SPIwriteCommand(SX126X_CMD_SET_RX, data, 3);
+}
+
+void SX126x::setCad() {
+  SPIwriteCommand(SX126X_CMD_SET_CAD, NULL, 0);
+}
+
+void SX126x::setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax, uint8_t paLut) {
+  uint8_t data[4] = {paDutyCycle, deviceSel, hpMax, paLut};
+  SPIwriteCommand(SX126X_CMD_SET_TX_PARAMS, data, 4);
+}
+
+void SX126x::writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) {
+  uint8_t* dat = new uint8_t[2 + numBytes];
+  dat[0] = (uint8_t)((addr >> 8) & 0xFF);
+  dat[1] = (uint8_t)(addr & 0xFF);
+  memcpy(dat + 2, data, numBytes);
+  SPIwriteCommand(SX126X_CMD_WRITE_REGISTER, dat, 2 + numBytes);
+  delete[] dat;
+}
+
+void SX126x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) {
+  uint8_t data[8] = {(uint8_t)((irqMask >> 8) & 0xFF), (uint8_t)(irqMask & 0xFF),
+                     (uint8_t)((dio1Mask >> 8) & 0xFF), (uint8_t)(dio1Mask & 0xFF),
+                     (uint8_t)((dio2Mask >> 8) & 0xFF), (uint8_t)(dio2Mask & 0xFF),
+                     (uint8_t)((dio3Mask >> 8) & 0xFF), (uint8_t)(dio3Mask & 0xFF)};
+  SPIwriteCommand(SX126X_CMD_SET_DIO_IRQ_PARAMS, data, 8);
+}
+
+void SX126x::clearIrqStatus(uint16_t clearIrqParams) {
+  uint8_t data[2] = {(uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF)};
+  SPIwriteCommand(SX126X_CMD_CLEAR_IRQ_STATUS, data, 2);
+}
+
+void SX126x::setRfFrequency(uint32_t frf) {
+  uint8_t data[4] = {(uint8_t)((frf >> 24) & 0xFF), (uint8_t)((frf >> 16) & 0xFF), (uint8_t)((frf >> 8) & 0xFF), (uint8_t)(frf & 0xFF)};
+  SPIwriteCommand(SX126X_CMD_SET_RF_FREQUENCY, data, 4);
+}
+
+uint8_t SX126x::getPacketType() {
+  uint8_t data[1];
+  SPIreadCommand(SX126X_CMD_GET_PACKET_TYPE, data, 1);
+  return(data[0]);
+}
+
+void SX126x::setTxParams(uint8_t power, uint8_t rampTime) {
+  uint8_t data[2] = {power, rampTime};
+  SPIwriteCommand(SX126X_CMD_SET_TX_PARAMS, data, 2);
+}
+
+void SX126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro) {
+  // calculate symbol length and enable low data rate optimization, if needed
+  if(ldro == 0xFF) {
+    float symbolLength = (float)(uint32_t(1) << _sf) / (float)_bwKhz;
+    if(symbolLength >= 16.0) {
+      _ldro = SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON;
+    } else {
+      _ldro = SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF;
+    }
+  } else {
+    _ldro = ldro;
+  }
+  
+  uint8_t data[4] = {sf, bw, cr, _ldro};
+  SPIwriteCommand(SX126X_CMD_SET_MODULATION_PARAMS, data, 4);
+}
+
+void SX126x::setPacketParams(uint16_t preambleLength, uint8_t headerType, uint8_t payloadLength, uint8_t crcType, uint8_t invertIQ) {
+  uint8_t data[7] = {(uint8_t)((preambleLength >> 8) & 0xFF), (uint8_t)(preambleLength & 0xFF), headerType, payloadLength, crcType, invertIQ};
+  SPIwriteCommand(SX126X_CMD_SET_PACKET_PARAMS, data, 7);
+}
+
+uint8_t SX126x::getRssiInt() {
+  uint8_t data[1];
+  SPIreadCommand(SX126X_CMD_GET_RSSI_INST, data, 1);
+  return(data[0]);
+}
+
+int16_t SX126x::setFrequencyRaw(float freq) {
+  // calculate raw value
+  uint32_t frf = (freq * (uint32_t(1) << SX126X_DIV_EXPONENT)) / SX126X_CRYSTAL_FREQ;
+  setRfFrequency(frf);
+  return(ERR_NONE);
+}
+
+int16_t SX126x::config() {
+  // set LoRa mode
+  uint8_t* data = new uint8_t[1];
+  data[0] = SX126X_PACKET_TYPE_LORA;
+  SPIwriteCommand(SX126X_CMD_SET_PACKET_TYPE, data, 1);
+  
+  // set Rx/Tx fallback mode to STDBY_RC
+  data[0] = SX126X_RX_TX_FALLBACK_MODE_STDBY_RC;
+  SPIwriteCommand(SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1);
+  
+  // set CAD parameters
+  delete[] data;
+  data = new uint8_t[7];
+  data[0] = SX126X_CAD_ON_8_SYMB;
+  data[1] = _sf + 13;
+  data[2] = 10;
+  data[3] = SX126X_CAD_GOTO_STDBY;
+  data[4] = 0x00;
+  data[5] = 0x00;
+  data[6] = 0x00;
+  SPIwriteCommand(SX126X_CMD_SET_CAD_PARAMS, data, 7);
+  delete[] data;
+  
+  return(ERR_NONE);
+}
+
+void SX126x::SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy) {
+  SX126x::SPItransfer(cmd, true, data, NULL, numBytes, waitForBusy);
+}
+
+void SX126x::SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy) {
+  SX126x::SPItransfer(cmd, false, NULL, data, numBytes, waitForBusy);
+}
+
+void SX126x::SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy) {
+  // get pointer to used SPI interface
+  SPIClass* spi = _mod->getSpi();
+  
+  // ensure BUSY is low (state meachine ready)
+  // TODO timeout
+  while(digitalRead(_mod->getRx()));
+  
+  // start transfer
+  digitalWrite(_mod->getCs(), LOW);
+  spi->beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
+  
+  // send command byte
+  spi->transfer(cmd);
+  
+  // send/receive all bytes
+  if(write) {
+    for(uint8_t n = 0; n < numBytes; n++) {
+      spi->transfer(dataOut[n]);
+    }
+  } else {
+    // skip the first byte for read-type commands (status-only)
+    spi->transfer(SX126X_CMD_NOP);
+    for(uint8_t n = 0; n < numBytes; n++) {
+      dataIn[n] = spi->transfer(SX126X_CMD_NOP);
+    }
+  }
+  
+  // stop transfer
+  spi->endTransaction();
+  digitalWrite(_mod->getCs(), HIGH);
+  
+  // wait for BUSY to go high and then low
+  // TODO timeout
+  if(waitForBusy) {
+    delayMicroseconds(1);
+    while(digitalRead(_mod->getRx()));
+  }
+}
diff --git a/src/modules/SX126x.h b/src/modules/SX126x.h
new file mode 100644
index 00000000..d5ccac0e
--- /dev/null
+++ b/src/modules/SX126x.h
@@ -0,0 +1,375 @@
+#ifndef _RADIOLIB_SX126X_H
+#define _RADIOLIB_SX126X_H
+
+#include "TypeDef.h"
+#include "Module.h"
+
+#include "../protocols/PhysicalLayer.h"
+
+// SX126X physical layer properties
+#define SX126X_CRYSTAL_FREQ                           32.0
+#define SX126X_DIV_EXPONENT                           25
+
+// SX126X SPI commands
+// operational modes commands
+#define SX126X_CMD_NOP                                0x00
+#define SX126X_CMD_SET_SLEEP                          0x84
+#define SX126X_CMD_SET_STANDBY                        0x80
+#define SX126X_CMD_SET_FS                             0xC1
+#define SX126X_CMD_SET_TX                             0x83
+#define SX126X_CMD_SET_RX                             0x82
+#define SX126X_CMD_STOP_TIMER_ON_PREAMBLE             0x9F
+#define SX126X_CMD_SET_RX_DUTY_CYCLE                  0x94
+#define SX126X_CMD_SET_CAD                            0xC5
+#define SX126X_CMD_SET_TX_CONTINUOUS_WAVE             0xD1
+#define SX126X_CMD_SET_TX_INFINITE_PREAMBLE           0xD2
+#define SX126X_CMD_SET_REGULATOR_MODE                 0x96
+#define SX126X_CMD_CALIBRATE                          0x89
+#define SX126X_CMD_CALIBRATE_IMAGE                    0x98
+#define SX126X_CMD_SET_PA_CONFIG                      0x95
+#define SX126X_CMD_SET_RX_TX_FALLBACK_MODE            0x93
+
+// register and buffer access commands
+#define SX126X_CMD_WRITE_REGISTER                     0x0D
+#define SX126X_CMD_READ_REGISTER                      0x1D
+#define SX126X_CMD_WRITE_BUFFER                       0x0E
+#define SX126X_CMD_READ_BUFFER                        0x1E
+
+// DIO and IRQ control
+#define SX126X_CMD_SET_DIO_IRQ_PARAMS                 0x08
+#define SX126X_CMD_GET_IRQ_STATUS                     0x12
+#define SX126X_CMD_CLEAR_IRQ_STATUS                   0x02
+#define SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL         0x9D
+#define SX126X_CMD_SET_DIO3_AS_TCXO_CTRL              0x97
+
+// RF, modulation and packet commands
+#define SX126X_CMD_SET_RF_FREQUENCY                   0x86
+#define SX126X_CMD_SET_PACKET_TYPE                    0x8A
+#define SX126X_CMD_GET_PACKET_TYPE                    0x11
+#define SX126X_CMD_SET_TX_PARAMS                      0x8E
+#define SX126X_CMD_SET_MODULATION_PARAMS              0x8B
+#define SX126X_CMD_SET_PACKET_PARAMS                  0x8C
+#define SX126X_CMD_SET_CAD_PARAMS                     0x88
+#define SX126X_CMD_SET_BUFFER_BASE_ADDRESS            0x8F
+#define SX126X_CMD_SET_LORA_SYMB_NUM_TIMEOUT          0x0A
+
+// status commands
+#define SX126X_CMD_GET_STATUS                         0xC0
+#define SX126X_CMD_GET_RSSI_INST                      0x15
+#define SX126X_CMD_GET_RX_BUFFER_STATUS               0x13
+#define SX126X_CMD_GET_PACKET_STATUS                  0x14
+#define SX126X_CMD_GET_DEVICE_ERRORS                  0x17
+#define SX126X_CMD_CLEAR_DEVICE_ERRORS                0x07
+#define SX126X_CMD_GET_STATS                          0x10
+#define SX126X_CMD_RESET_STATS                        0x00
+
+
+// SX126X register map
+#define SX126X_REG_WHITENING_INITIAL_MSB              0x06B8
+#define SX126X_REG_WHITENING_INITIAL_LSB              0x06B9
+#define SX126X_REG_CRC_INITIAL_MSB                    0x06BC
+#define SX126X_REG_CRC_INITIAL_LSB                    0x06BD
+#define SX126X_REG_CRC_POLYNOMIAL_MSB                 0x06BE
+#define SX126X_REG_CRC_POLYNOMIAL_LSB                 0x06BF
+#define SX126X_REG_SYNC_WORD_0                        0x06C0
+#define SX126X_REG_SYNC_WORD_1                        0x06C1
+#define SX126X_REG_SYNC_WORD_2                        0x06C2
+#define SX126X_REG_SYNC_WORD_3                        0x06C3
+#define SX126X_REG_SYNC_WORD_4                        0x06C4
+#define SX126X_REG_SYNC_WORD_5                        0x06C5
+#define SX126X_REG_SYNC_WORD_6                        0x06C6
+#define SX126X_REG_SYNC_WORD_7                        0x06C7
+#define SX126X_REG_NODE_ADDRESS                       0x06CD
+#define SX126X_REG_BROADCAST_ADDRESS                  0x06CE
+#define SX126X_REG_LORA_SYNC_WORD_MSB                 0x0740
+#define SX126X_REG_LORA_SYNC_WORD_LSB                 0x0741
+#define SX126X_REG_RANDOM_NUMBER_0                    0x0819
+#define SX126X_REG_RANDOM_NUMBER_1                    0x081A
+#define SX126X_REG_RANDOM_NUMBER_2                    0x081B
+#define SX126X_REG_RANDOM_NUMBER_3                    0x081C
+#define SX126X_REG_RX_GAIN                            0x08AC
+#define SX126X_REG_OCP_CONFIGURATION                  0x08E7
+#define SX126X_REG_XTA_TRIM                           0x0911
+#define SX126X_REG_XTB_TRIM                           0x0912
+
+
+// SX126X SPI command variables
+//SX126X_CMD_SET_SLEEP
+#define SX126X_SLEEP_START_COLD                       0b00000000  //  2     2     sleep mode: cold start, configuration is lost (default)
+#define SX126X_SLEEP_START_WARM                       0b00000100  //  2     2                 warm start, configuration is retained
+#define SX126X_SLEEP_RTC_OFF                          0b00000000  //  0     0     wake on RTC timeout: disabled
+#define SX126X_SLEEP_RTC_ON                           0b00000001  //  0     0                          enabled
+
+//SX126X_CMD_SET_STANDBY
+#define SX126X_STANDBY_RC                             0x00        //  7     0     standby mode: 13 MHz RC oscillator
+#define SX126X_STANDBY_XOSC                           0x01        //  7     0                   32 MHz crystal oscillator
+
+//SX126X_CMD_SET_RX
+#define SX126X_RX_TIMEOUT_NONE                        0x000000    //  23    0     Rx timeout duration: no timeout (Rx single mode)
+#define SX126X_RX_TIMEOUT_INF                         0xFFFFFF    //  23    0                          infinite (Rx continuous mode)
+
+//SX126X_CMD_STOP_TIMER_ON_PREAMBLE
+#define SX126X_STOP_ON_PREAMBLE_OFF                   0x00        //  7     0     stop timer on: sync word or header (default)
+#define SX126X_STOP_ON_PREAMBLE_ON                    0x01        //  7     0                    preamble detection
+
+//SX126X_CMD_SET_REGULATOR_MODE
+#define SX126X_REGULATOR_LDO                          0x00        //  7     0     set regulator mode: LDO (default)
+#define SX126X_REGULATOR_DC_DC                        0x01        //  7     0                         DC-DC
+
+//SX126X_CMD_CALIBRATE
+#define SX126X_CALIBRATE_IMAGE_OFF                    0b00000000  //  6     6     image calibration: disabled
+#define SX126X_CALIBRATE_IMAGE_ON                     0b01000000  //  6     6                        enabled
+#define SX126X_CALIBRATE_ADC_BULK_P_OFF               0b00000000  //  5     5     ADC bulk P calibration: disabled
+#define SX126X_CALIBRATE_ADC_BULK_P_ON                0b00100000  //  5     5                             enabled
+#define SX126X_CALIBRATE_ADC_BULK_N_OFF               0b00000000  //  4     4     ADC bulk N calibration: disabled
+#define SX126X_CALIBRATE_ADC_BULK_N_ON                0b00010000  //  4     4                             enabled
+#define SX126X_CALIBRATE_ADC_PULSE_OFF                0b00000000  //  3     3     ADC pulse calibration: disabled
+#define SX126X_CALIBRATE_ADC_PULSE_ON                 0b00001000  //  3     3                            enabled
+#define SX126X_CALIBRATE_PLL_OFF                      0b00000000  //  2     2     PLL calibration: disabled
+#define SX126X_CALIBRATE_PLL_ON                       0b00000100  //  2     2                      enabled
+#define SX126X_CALIBRATE_RC13M_OFF                    0b00000000  //  1     1     13 MHz RC osc. calibration: disabled
+#define SX126X_CALIBRATE_RC13M_ON                     0b00000010  //  1     1                                 enabled
+#define SX126X_CALIBRATE_RC64K_OFF                    0b00000000  //  0     0     64 kHz RC osc. calibration: disabled
+#define SX126X_CALIBRATE_RC64K_ON                     0b00000001  //  0     0                                 enabled
+
+//SX126X_CMD_CALIBRATE_IMAGE
+#define SX126X_CAL_IMG_430_MHZ_1                      0x6B
+#define SX126X_CAL_IMG_430_MHZ_2                      0x6F
+#define SX126X_CAL_IMG_470_MHZ_1                      0x75
+#define SX126X_CAL_IMG_470_MHZ_2                      0x81
+#define SX126X_CAL_IMG_779_MHZ_1                      0xC1
+#define SX126X_CAL_IMG_779_MHZ_2                      0xC5
+#define SX126X_CAL_IMG_863_MHZ_1                      0xD7
+#define SX126X_CAL_IMG_863_MHZ_2                      0xDB
+#define SX126X_CAL_IMG_902_MHZ_1                      0xE1
+#define SX126X_CAL_IMG_902_MHZ_2                      0xE9
+
+//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
+#define SX126X_RX_TX_FALLBACK_MODE_FS                 0x40        //  7     0     after Rx/Tx go to: FS mode
+#define SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC         0x30        //  7     0                        standby with crystal oscillator
+#define SX126X_RX_TX_FALLBACK_MODE_STDBY_RC           0x20        //  7     0                        standby with RC oscillator (default)
+
+//SX126X_CMD_SET_DIO_IRQ_PARAMS
+#define SX126X_IRQ_TIMEOUT                          0b1000000000  //  9     9     Rx or Tx timeout
+#define SX126X_IRQ_CAD_DETECTED                     0b0100000000  //  8     8     channel activity detected
+#define SX126X_IRQ_CAD_DONE                         0b0010000000  //  7     7     channel activity detection finished
+#define SX126X_IRQ_CRC_ERR                          0b0001000000  //  6     6     wrong CRC received
+#define SX126X_IRQ_HEADER_ERR                       0b0000100000  //  5     5     LoRa header CRC error
+#define SX126X_IRQ_HEADER_VALID                     0b0000010000  //  4     4     valid LoRa header received
+#define SX126X_IRQ_SYNC_WORD_VALID                  0b0000001000  //  3     3     valid sync word detected
+#define SX126X_IRQ_PREAMBLE_DETECTED                0b0000000100  //  2     2     preamble detected
+#define SX126X_IRQ_RX_DONE                          0b0000000010  //  1     1     packet received
+#define SX126X_IRQ_TX_DONE                          0b0000000001  //  0     0     packet transmission completed
+
+//SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL
+#define SX126X_DIO2_AS_IRQ                            0x00        //  7     0     DIO2 configuration: IRQ
+#define SX126X_DIO2_AS_RF_SWITCH                      0x01        //  7     0                         RF switch control
+
+//SX126X_CMD_SET_DIO3_AS_TCXO_CTRL
+#define SX126X_DIO3_OUTPUT_1_6                        0x00        //  7     0     DIO3 voltage output for TCXO: 1.6 V
+#define SX126X_DIO3_OUTPUT_1_7                        0x01        //  7     0                                   1.7 V
+#define SX126X_DIO3_OUTPUT_1_8                        0x02        //  7     0                                   1.8 V
+#define SX126X_DIO3_OUTPUT_2_2                        0x03        //  7     0                                   2.2 V
+#define SX126X_DIO3_OUTPUT_2_4                        0x04        //  7     0                                   2.4 V
+#define SX126X_DIO3_OUTPUT_2_7                        0x05        //  7     0                                   2.7 V
+#define SX126X_DIO3_OUTPUT_3_0                        0x06        //  7     0                                   3.0 V
+#define SX126X_DIO3_OUTPUT_3_3                        0x07        //  7     0                                   3.3 V
+
+//SX126X_CMD_SET_PACKET_TYPE
+#define SX126X_PACKET_TYPE_GFSK                       0x00        //  7     0     packet type: GFSK
+#define SX126X_PACKET_TYPE_LORA                       0x01        //  7     0                  LoRa
+
+//SX126X_CMD_SET_TX_PARAMS
+#define SX126X_PA_RAMP_10U                            0x00        //  7     0     ramp time: 10 us
+#define SX126X_PA_RAMP_20U                            0x01        //  7     0                20 us
+#define SX126X_PA_RAMP_40U                            0x02        //  7     0                40 us
+#define SX126X_PA_RAMP_80U                            0x03        //  7     0                80 us
+#define SX126X_PA_RAMP_200U                           0x04        //  7     0                200 us
+#define SX126X_PA_RAMP_800U                           0x05        //  7     0                800 us
+#define SX126X_PA_RAMP_1700U                          0x06        //  7     0                1700 us
+#define SX126X_PA_RAMP_3400U                          0x07        //  7     0                3400 us
+
+//SX126X_CMD_SET_MODULATION_PARAMS
+#define SX126X_GFSK_FILTER_NONE                       0x00        //  7     0     GFSK filter: none
+#define SX126X_GFSK_FILTER_GAUSS_0_3                  0x08        //  7     0                  Gaussian, BT = 0.3
+#define SX126X_GFSK_FILTER_GAUSS_0_5                  0x09        //  7     0                  Gaussian, BT = 0.5
+#define SX126X_GFSK_FILTER_GAUSS_0_7                  0x0A        //  7     0                  Gaussian, BT = 0.7
+#define SX126X_GFSK_FILTER_GAUSS_1                    0x0B        //  7     0                  Gaussian, BT = 1
+#define SX126X_GFSK_RX_BW_4_8                         0x1F        //  7     0     GFSK Rx bandwidth: 4.8 kHz
+#define SX126X_GFSK_RX_BW_5_8                         0x17        //  7     0                        5.8 kHz
+#define SX126X_GFSK_RX_BW_7_3                         0x0F        //  7     0                        7.3 kHz
+#define SX126X_GFSK_RX_BW_9_7                         0x1E        //  7     0                        9.7 kHz
+#define SX126X_GFSK_RX_BW_11_7                        0x16        //  7     0                        11.7 kHz
+#define SX126X_GFSK_RX_BW_14_6                        0x0E        //  7     0                        14.6 kHz
+#define SX126X_GFSK_RX_BW_19_5                        0x1D        //  7     0                        19.5 kHz
+#define SX126X_GFSK_RX_BW_23_4                        0x15        //  7     0                        23.4 kHz
+#define SX126X_GFSK_RX_BW_29_3                        0x0D        //  7     0                        29.3 kHz
+#define SX126X_GFSK_RX_BW_39_0                        0x1C        //  7     0                        39.0 kHz
+#define SX126X_GFSK_RX_BW_46_9                        0x14        //  7     0                        46.9 kHz
+#define SX126X_GFSK_RX_BW_58_6                        0x0C        //  7     0                        58.6 kHz
+#define SX126X_GFSK_RX_BW_78_2                        0x1B        //  7     0                        78.2 kHz
+#define SX126X_GFSK_RX_BW_93_8                        0x13        //  7     0                        93.8 kHz
+#define SX126X_GFSK_RX_BW_117_3                       0x0B        //  7     0                        117.3 kHz
+#define SX126X_GFSK_RX_BW_156_2                       0x1A        //  7     0                        156.2 kHz
+#define SX126X_GFSK_RX_BW_187_2                       0x12        //  7     0                        187.2 kHz
+#define SX126X_GFSK_RX_BW_232_3                       0x0A        //  7     0                        232.3 kHz
+#define SX126X_GFSK_RX_BW_312_0                       0x19        //  7     0                        312.0 kHz
+#define SX126X_GFSK_RX_BW_373_6                       0x11        //  7     0                        373.6 kHz
+#define SX126X_GFSK_RX_BW_467_0                       0x09        //  7     0                        467.0 kHz
+#define SX126X_LORA_BW_7_8                            0x00        //  7     0     LoRa bandwidth: 7.8 kHz
+#define SX126X_LORA_BW_10_4                           0x08        //  7     0                     10.4 kHz
+#define SX126X_LORA_BW_15_6                           0x01        //  7     0                     15.6 kHz
+#define SX126X_LORA_BW_20_8                           0x09        //  7     0                     20.8 kHz
+#define SX126X_LORA_BW_31_25                          0x02        //  7     0                     31.25 kHz
+#define SX126X_LORA_BW_41_7                           0x0A        //  7     0                     41.7 kHz
+#define SX126X_LORA_BW_62_5                           0x03        //  7     0                     62.5 kHz
+#define SX126X_LORA_BW_125_0                          0x04        //  7     0                     125.0 kHz
+#define SX126X_LORA_BW_250_0                          0x05        //  7     0                     250.0 kHz
+#define SX126X_LORA_BW_500_0                          0x06        //  7     0                     500.0 kHz
+#define SX126X_LORA_CR_4_5                            0x01        //  7     0     LoRa coding rate: 4/5
+#define SX126X_LORA_CR_4_6                            0x02        //  7     0                       4/6
+#define SX126X_LORA_CR_4_7                            0x03        //  7     0                       4/7
+#define SX126X_LORA_CR_4_8                            0x04        //  7     0                       4/8
+#define SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF        0x00        //  7     0     LoRa low data rate optimization: disabled
+#define SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON         0x01        //  7     0                                      enabled
+
+//SX126X_CMD_SET_PACKET_PARAMS
+#define SX126X_GFSK_PREAMBLE_DETECT_OFF               0x00        //  7     0     GFSK minimum preamble length before reception starts: detector disabled
+#define SX126X_GFSK_PREAMBLE_DETECT_8                 0x04        //  7     0                                                           8 bits
+#define SX126X_GFSK_PREAMBLE_DETECT_16                0x05        //  7     0                                                           16 bits
+#define SX126X_GFSK_PREAMBLE_DETECT_24                0x06        //  7     0                                                           24 bits
+#define SX126X_GFSK_PREAMBLE_DETECT_32                0x07        //  7     0                                                           32 bits
+#define SX126X_GFSK_ADDRESS_FILT_OFF                  0x00        //  7     0     GFSK address filtering: disabled
+#define SX126X_GFSK_ADDRESS_FILT_NODE                 0x01        //  7     0                             node only
+#define SX126X_GFSK_ADDRESS_FILT_NODE_BROADCAST       0x02        //  7     0                             node and broadcast
+#define SX126X_GFSK_PACKET_FIXED                      0x00        //  7     0     GFSK packet type: fixed (payload length known in advance to both sides)
+#define SX126X_GFSK_PACKET_VARIABLE                   0x01        //  7     0                       variable (payload length added to packet)
+#define SX126X_GFSK_CRC_OFF                           0x01        //  7     0     GFSK packet CRC: disabled
+#define SX126X_GFSK_CRC_1_BYTE                        0x00        //  7     0                      1 byte
+#define SX126X_GFSK_CRC_2_BYTE                        0x02        //  7     0                      2 byte
+#define SX126X_GFSK_CRC_1_BYTE_INV                    0x04        //  7     0                      1 byte, inverted
+#define SX126X_GFSK_CRC_2_BYTE_INV                    0x06        //  7     0                      2 byte, inverted
+#define SX126X_GFSK_WHITENING_OFF                     0x00        //  7     0     GFSK data whitening: disabled
+#define SX126X_GFSK_WHITENING_ON                      0x01        //  7     0                          enabled
+#define SX126X_LORA_HEADER_EXPLICIT                   0x00        //  7     0     LoRa header mode: explicit
+#define SX126X_LORA_HEADER_IMPLICIT                   0x01        //  7     0                       implicit
+#define SX126X_LORA_CRC_OFF                           0x00        //  7     0     LoRa CRC mode: disabled
+#define SX126X_LORA_CRC_ON                            0x01        //  7     0                    enabled
+#define SX126X_LORA_IQ_STANDARD                       0x00        //  7     0     LoRa IQ setup: standard
+#define SX126X_LORA_IQ_INVERTED                       0x01        //  7     0                    inverted
+
+//SX126X_CMD_SET_CAD_PARAMS
+#define SX126X_CAD_ON_1_SYMB                          0x00        //  7     0     number of symbols used for CAD: 1
+#define SX126X_CAD_ON_2_SYMB                          0x01        //  7     0                                     2
+#define SX126X_CAD_ON_4_SYMB                          0x02        //  7     0                                     4
+#define SX126X_CAD_ON_8_SYMB                          0x03        //  7     0                                     8
+#define SX126X_CAD_ON_16_SYMB                         0x04        //  7     0                                     16
+#define SX126X_CAD_GOTO_STDBY                         0x00        //  7     0     after CAD is done, always go to STDBY_RC mode
+#define SX126X_CAD_GOTO_RX                            0x01        //  7     0     after CAD is done, go to Rx mode if activity is detected
+
+//SX126X_CMD_GET_STATUS
+#define SX126X_STATUS_MODE_STDBY_RC                   0b00100000  //  6     4     current chip mode: STDBY_RC
+#define SX126X_STATUS_MODE_STDBY_XOSC                 0b00110000  //  6     4                        STDBY_XOSC
+#define SX126X_STATUS_MODE_FS                         0b01000000  //  6     4                        FS
+#define SX126X_STATUS_MODE_RX                         0b01010000  //  6     4                        RX
+#define SX126X_STATUS_MODE_TX                         0b01100000  //  6     4                        TX
+#define SX126X_STATUS_DATA_AVAILABLE                  0b00000100  //  3     1     command status: packet received and data can be retrieved
+#define SX126X_STATUS_CMD_TIMEOUT                     0b00000110  //  3     1                     SPI command timed out
+#define SX126X_STATUS_CMD_INVALID                     0b00001000  //  3     1                     invalid SPI command
+#define SX126X_STATUS_CMD_FAILED                      0b00001010  //  3     1                     SPI command failed to execute
+#define SX126X_STATUS_TX_DONE                         0b00001100  //  3     1                     packet transmission done
+
+//SX126X_CMD_GET_PACKET_STATUS
+#define SX126X_GFSK_RX_STATUS_PREAMBLE_ERR            0b10000000  //  7     7     GFSK Rx status: preamble error
+#define SX126X_GFSK_RX_STATUS_SYNC_ERR                0b01000000  //  6     6                     sync word error
+#define SX126X_GFSK_RX_STATUS_ADRS_ERR                0b00100000  //  5     5                     address error
+#define SX126X_GFSK_RX_STATUS_CRC_ERR                 0b00010000  //  4     4                     CRC error
+#define SX126X_GFSK_RX_STATUS_LENGTH_ERR              0b00001000  //  3     3                     length error
+#define SX126X_GFSK_RX_STATUS_ABORT_ERR               0b00000100  //  2     2                     abort error
+#define SX126X_GFSK_RX_STATUS_PACKET_RECEIVED         0b00000010  //  2     2                     packet received
+#define SX126X_GFSK_RX_STATUS_PACKET_SENT             0b00000001  //  2     2                     packet sent
+
+//SX126X_CMD_GET_DEVICE_ERRORS
+#define SX126X_PA_RAMP_ERR                           0b100000000  //  8     8     device errors: PA ramping failed
+#define SX126X_PLL_LOCK_ERR                          0b001000000  //  6     6                    PLL failed to lock
+#define SX126X_XOSC_START_ERR                        0b000100000  //  5     5                    crystal oscillator failed to start
+#define SX126X_IMG_CALIB_ERR                         0b000010000  //  4     4                    image calibration failed
+#define SX126X_ADC_CALIB_ERR                         0b000001000  //  3     3                    ADC calibration failed
+#define SX126X_PLL_CALIB_ERR                         0b000000100  //  2     2                    PLL calibration failed
+#define SX126X_RC13M_CALIB_ERR                       0b000000010  //  1     1                    RC13M calibration failed
+#define SX126X_RC64K_CALIB_ERR                       0b000000001  //  0     0                    RC64K calibration failed
+
+
+// SX126X SPI register variables
+//SX126X_REG_LORA_SYNC_WORD_MSB + LSB
+#define SX126X_SYNC_WORD_PUBLIC                       0x3444
+#define SX126X_SYNC_WORD_PRIVATE                      0x1424
+
+
+class SX126x: public PhysicalLayer {
+  public:
+    // introduce PhysicalLayer overloads
+    using PhysicalLayer::transmit;
+    using PhysicalLayer::receive;
+  
+    // constructor
+    SX126x(Module* mod);
+    
+    // basic methods
+    int16_t begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, float currentLimit, uint16_t preambleLength);
+    int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0);
+    int16_t receive(uint8_t* data, size_t len);
+    int16_t transmitDirect(uint32_t frf = 0);
+    int16_t receiveDirect();
+    int16_t sleep();
+    int16_t standby(uint8_t mode = SX126X_STANDBY_RC);
+    
+    // configuration methods
+    int16_t setBandwidth(float bw);
+    int16_t setSpreadingFactor(uint8_t sf);
+    int16_t setCodingRate(uint8_t cr);
+    int16_t setSyncWord(uint16_t syncWord);
+    int16_t setCurrentLimit(float currentLimit);
+    int16_t setPreambleLength(uint16_t preambleLength);
+    float getDataRate();
+    int16_t setFrequencyDeviation(float freqDev);
+  
+  protected:
+    // SX1276x SPI command implementations
+    void setTx(uint32_t timeout);
+    void setRx(uint32_t timeout);
+    void setCad();
+    void setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax = SX126X_PA_CONFIG_HP_MAX, uint8_t paLut = SX126X_PA_CONFIG_PA_LUT);
+    void writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes);
+    void setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask = 0x0000);
+    void clearIrqStatus(uint16_t clearIrqParams = 0xFFFF);
+    void setRfFrequency(uint32_t frf);
+    uint8_t getPacketType();
+    void setTxParams(uint8_t power, uint8_t rampTime = SX126X_PA_RAMP_80U);
+    void setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro = 0xFF);
+    void setPacketParams(uint16_t preambleLength, uint8_t payloadLength, uint8_t crcType, uint8_t headerType = SX126X_LORA_HEADER_EXPLICIT, uint8_t invertIQ = SX126X_LORA_IQ_STANDARD);
+    uint8_t getRssiInt();
+    
+    int16_t setFrequencyRaw(float freq);
+  
+  private:
+    Module* _mod;
+    
+    uint8_t _bw, _sf, _cr, _ldro, _payloadLength, _crcType;
+    uint16_t _preambleLength;
+    float _bwKhz;
+    
+    int16_t config();
+    
+    // common low-level SPI interface
+    void SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
+    void SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
+    void SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy);
+};
+
+#endif