acid-drop

- Hacking the planet from a LilyGo T-Deck using custom firmware
git clone git://git.acid.vegas/acid-drop.git
Log | Files | Refs | Archive | README | LICENSE

SX126x.cpp (56526B)

      1 #include "SX126x.h"
      2 #if !defined(RADIOLIB_EXCLUDE_SX126X)
      3 
      4 SX126x::SX126x(Module* mod) : PhysicalLayer(RADIOLIB_SX126X_FREQUENCY_STEP_SIZE, RADIOLIB_SX126X_MAX_PACKET_LENGTH) {
      5   _mod = mod;
      6 }
      7 
      8 Module* SX126x::getMod() {
      9   return(_mod);
     10 }
     11 
     12 int16_t SX126x::begin(uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) {
     13   // set module properties
     14   _mod->init();
     15   _mod->pinMode(_mod->getIrq(), INPUT);
     16   _mod->pinMode(_mod->getGpio(), INPUT);
     17   RADIOLIB_DEBUG_PRINTLN(F("M\tSX126x"));
     18 
     19   // BW in kHz and SF are required in order to calculate LDRO for setModulationParams
     20   // set the defaults, this will get overwritten later anyway
     21   _bwKhz = 500.0;
     22   _sf = 9;
     23 
     24   // initialize configuration variables (will be overwritten during public settings configuration)
     25   _bw = RADIOLIB_SX126X_LORA_BW_500_0;  // initialized to 500 kHz, since lower valeus will interfere with LLCC68
     26   _cr = RADIOLIB_SX126X_LORA_CR_4_7;
     27   _ldro = 0x00;
     28   _crcType = RADIOLIB_SX126X_LORA_CRC_ON;
     29   _preambleLength = preambleLength;
     30   _tcxoDelay = 0;
     31   _headerType = RADIOLIB_SX126X_LORA_HEADER_EXPLICIT;
     32   _implicitLen = 0xFF;
     33 
     34   // reset the module and verify startup
     35   int16_t state = reset();
     36   RADIOLIB_ASSERT(state);
     37 
     38   // set mode to standby
     39   state = standby();
     40   RADIOLIB_ASSERT(state);
     41 
     42   // configure settings not accessible by API
     43   state = config(RADIOLIB_SX126X_PACKET_TYPE_LORA);
     44   RADIOLIB_ASSERT(state);
     45 
     46   // set TCXO control, if requested
     47   if(tcxoVoltage > 0.0) {
     48     state = setTCXO(tcxoVoltage);
     49     RADIOLIB_ASSERT(state);
     50   }
     51 
     52   // configure publicly accessible settings
     53   state = setCodingRate(cr);
     54   RADIOLIB_ASSERT(state);
     55 
     56   state = setSyncWord(syncWord);
     57   RADIOLIB_ASSERT(state);
     58 
     59   state = setPreambleLength(preambleLength);
     60   RADIOLIB_ASSERT(state);
     61 
     62   // set publicly accessible settings that are not a part of begin method
     63   state = setCurrentLimit(60.0);
     64   RADIOLIB_ASSERT(state);
     65 
     66   state = setDio2AsRfSwitch(true);
     67   RADIOLIB_ASSERT(state);
     68 
     69   if (useRegulatorLDO) {
     70       state = setRegulatorLDO();
     71   } else {
     72       state = setRegulatorDCDC();
     73   }
     74 
     75   return(state);
     76 }
     77 
     78 int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO) {
     79   // set module properties
     80   _mod->init();
     81   _mod->pinMode(_mod->getIrq(), INPUT);
     82   _mod->pinMode(_mod->getGpio(), INPUT);
     83   RADIOLIB_DEBUG_PRINTLN(F("M\tSX126x"));
     84 
     85   // initialize configuration variables (will be overwritten during public settings configuration)
     86   _br = 21333;                                  // 48.0 kbps
     87   _freqDev = 52428;                             // 50.0 kHz
     88   _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_156_2;
     89   _rxBwKhz = 156.2;
     90   _pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5;
     91   _crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV;     // CCIT CRC configuration
     92   _preambleLengthFSK = preambleLength;
     93   _addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF;
     94 
     95   // reset the module and verify startup
     96   int16_t state = reset();
     97   RADIOLIB_ASSERT(state);
     98 
     99   // set mode to standby
    100   state = standby();
    101   RADIOLIB_ASSERT(state);
    102 
    103   // configure settings not accessible by API
    104   state = config(RADIOLIB_SX126X_PACKET_TYPE_GFSK);
    105   RADIOLIB_ASSERT(state);
    106 
    107   // set TCXO control, if requested
    108   if(tcxoVoltage > 0.0) {
    109     state = setTCXO(tcxoVoltage);
    110     RADIOLIB_ASSERT(state);
    111   }
    112 
    113   // configure publicly accessible settings
    114   state = setBitRate(br);
    115   RADIOLIB_ASSERT(state);
    116 
    117   state = setFrequencyDeviation(freqDev);
    118   RADIOLIB_ASSERT(state);
    119 
    120   state = setRxBandwidth(rxBw);
    121   RADIOLIB_ASSERT(state);
    122 
    123   state = setCurrentLimit(60.0);
    124   RADIOLIB_ASSERT(state);
    125 
    126   state = setPreambleLength(preambleLength);
    127   RADIOLIB_ASSERT(state);
    128 
    129   if(useRegulatorLDO) {
    130     state = setRegulatorLDO();
    131   } else {
    132     state = setRegulatorDCDC();
    133   }
    134   RADIOLIB_ASSERT(state);
    135 
    136   // set publicly accessible settings that are not a part of begin method
    137   uint8_t sync[] = {0x12, 0xAD};
    138   state = setSyncWord(sync, 2);
    139   RADIOLIB_ASSERT(state);
    140 
    141   state = setDataShaping(RADIOLIB_SHAPING_NONE);
    142   RADIOLIB_ASSERT(state);
    143 
    144   state = setEncoding(RADIOLIB_ENCODING_NRZ);
    145   RADIOLIB_ASSERT(state);
    146 
    147   state = variablePacketLengthMode(RADIOLIB_SX126X_MAX_PACKET_LENGTH);
    148   RADIOLIB_ASSERT(state);
    149 
    150   state = setCRC(2);
    151   RADIOLIB_ASSERT(state);
    152 
    153   state = setDio2AsRfSwitch(false);
    154   RADIOLIB_ASSERT(state);
    155 
    156   return(state);
    157 }
    158 
    159 int16_t SX126x::reset(bool verify) {
    160   // run the reset sequence
    161   _mod->pinMode(_mod->getRst(), OUTPUT);
    162   _mod->digitalWrite(_mod->getRst(), LOW);
    163   _mod->delay(1);
    164   _mod->digitalWrite(_mod->getRst(), HIGH);
    165 
    166   // return immediately when verification is disabled
    167   if(!verify) {
    168     return(RADIOLIB_ERR_NONE);
    169   }
    170 
    171   // set mode to standby - SX126x often refuses first few commands after reset
    172   uint32_t start = _mod->millis();
    173   while(true) {
    174     // try to set mode to standby
    175     int16_t state = standby();
    176     if(state == RADIOLIB_ERR_NONE) {
    177       // standby command successful
    178       return(RADIOLIB_ERR_NONE);
    179     }
    180 
    181     // standby command failed, check timeout and try again
    182     if(_mod->millis() - start >= 3000) {
    183       // timed out, possibly incorrect wiring
    184       return(state);
    185     }
    186 
    187     // wait a bit to not spam the module
    188     _mod->delay(10);
    189   }
    190 }
    191 
    192 int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) {
    193   // set mode to standby
    194   int16_t state = standby();
    195   RADIOLIB_ASSERT(state);
    196 
    197   // check packet length
    198   if(len > RADIOLIB_SX126X_MAX_PACKET_LENGTH) {
    199     return(RADIOLIB_ERR_PACKET_TOO_LONG);
    200   }
    201 
    202   uint32_t timeout = 0;
    203 
    204   // get currently active modem
    205   uint8_t modem = getPacketType();
    206   if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
    207     // calculate timeout (150% of expected time-on-air)
    208     timeout = (getTimeOnAir(len) * 3) / 2;
    209 
    210   } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
    211     // calculate timeout (500% of expected time-on-air)
    212     timeout = getTimeOnAir(len) * 5;
    213 
    214   } else {
    215     return(RADIOLIB_ERR_UNKNOWN);
    216   }
    217 
    218   RADIOLIB_DEBUG_PRINT(F("Timeout in "));
    219   RADIOLIB_DEBUG_PRINT(timeout);
    220   RADIOLIB_DEBUG_PRINTLN(F(" us"));
    221 
    222   // start transmission
    223   state = startTransmit(data, len, addr);
    224   RADIOLIB_ASSERT(state);
    225 
    226   // wait for packet transmission or timeout
    227   uint32_t start = _mod->micros();
    228   while(!_mod->digitalRead(_mod->getIrq())) {
    229     _mod->yield();
    230     if(_mod->micros() - start > timeout) {
    231       clearIrqStatus();
    232       standby();
    233       return(RADIOLIB_ERR_TX_TIMEOUT);
    234     }
    235   }
    236   uint32_t elapsed = _mod->micros() - start;
    237 
    238   // update data rate
    239   _dataRate = (len*8.0)/((float)elapsed/1000000.0);
    240 
    241   // clear interrupt flags
    242   state = clearIrqStatus();
    243   RADIOLIB_ASSERT(state);
    244 
    245   // set mode to standby to disable transmitter
    246   state = standby();
    247 
    248   return(state);
    249 }
    250 
    251 int16_t SX126x::receive(uint8_t* data, size_t len) {
    252   // set mode to standby
    253   int16_t state = standby();
    254   RADIOLIB_ASSERT(state);
    255 
    256   uint32_t timeout = 0;
    257 
    258   // get currently active modem
    259   uint8_t modem = getPacketType();
    260   if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
    261     // calculate timeout (100 LoRa symbols, the default for SX127x series)
    262     float symbolLength = (float)(uint32_t(1) << _sf) / (float)_bwKhz;
    263     timeout = (uint32_t)(symbolLength * 100.0 * 1000.0);
    264   } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
    265     // calculate timeout (500 % of expected time-one-air)
    266     size_t maxLen = len;
    267     if(len == 0) {
    268       maxLen = 0xFF;
    269     }
    270     float brBps = ((float)(RADIOLIB_SX126X_CRYSTAL_FREQ) * 1000000.0 * 32.0) / (float)_br;
    271     timeout = (uint32_t)(((maxLen * 8.0) / brBps) * 1000000.0 * 5.0);
    272 
    273   } else {
    274     return(RADIOLIB_ERR_UNKNOWN);
    275   }
    276 
    277   RADIOLIB_DEBUG_PRINT(F("Timeout in "));
    278   RADIOLIB_DEBUG_PRINT(timeout);
    279   RADIOLIB_DEBUG_PRINTLN(F(" us"));
    280 
    281   // start reception
    282   uint32_t timeoutValue = (uint32_t)((float)timeout / 15.625);
    283   state = startReceive(timeoutValue);
    284   RADIOLIB_ASSERT(state);
    285 
    286   // wait for packet reception or timeout
    287   uint32_t start = _mod->micros();
    288   while(!_mod->digitalRead(_mod->getIrq())) {
    289     _mod->yield();
    290     if(_mod->micros() - start > timeout) {
    291       fixImplicitTimeout();
    292       clearIrqStatus();
    293       standby();
    294       return(RADIOLIB_ERR_RX_TIMEOUT);
    295     }
    296   }
    297 
    298   // fix timeout in implicit LoRa mode
    299   if(((_headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA))) {
    300     state = fixImplicitTimeout();
    301     RADIOLIB_ASSERT(state);
    302   }
    303 
    304   // read the received data
    305   return(readData(data, len));
    306 }
    307 
    308 int16_t SX126x::transmitDirect(uint32_t frf) {
    309   // set RF switch (if present)
    310   _mod->setRfSwitchState(LOW, HIGH);
    311 
    312   // user requested to start transmitting immediately (required for RTTY)
    313   int16_t state = RADIOLIB_ERR_NONE;
    314   if(frf != 0) {
    315     state = setRfFrequency(frf);
    316   }
    317   RADIOLIB_ASSERT(state);
    318 
    319   // start transmitting
    320   uint8_t data[] = {RADIOLIB_SX126X_CMD_NOP};
    321   return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_TX_CONTINUOUS_WAVE, data, 1));
    322 }
    323 
    324 int16_t SX126x::receiveDirect() {
    325   // set RF switch (if present)
    326   _mod->setRfSwitchState(HIGH, LOW);
    327 
    328   // SX126x is unable to output received data directly
    329   return(RADIOLIB_ERR_UNKNOWN);
    330 }
    331 
    332 int16_t SX126x::scanChannel() {
    333   // set mode to CAD
    334   int state = startChannelScan();
    335   RADIOLIB_ASSERT(state);
    336 
    337   // wait for channel activity detected or timeout
    338   while(!_mod->digitalRead(_mod->getIrq())) {
    339     _mod->yield();
    340   }
    341 
    342   // check CAD result
    343   return(getChannelScanResult());
    344 }
    345 
    346 int16_t SX126x::sleep(bool retainConfig) {
    347   // set RF switch (if present)
    348   _mod->setRfSwitchState(LOW, LOW);
    349 
    350   uint8_t sleepMode = RADIOLIB_SX126X_SLEEP_START_WARM | RADIOLIB_SX126X_SLEEP_RTC_OFF;
    351   if(!retainConfig) {
    352     sleepMode = RADIOLIB_SX126X_SLEEP_START_COLD | RADIOLIB_SX126X_SLEEP_RTC_OFF;
    353   }
    354   int16_t state = SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_SLEEP, &sleepMode, 1, false);
    355 
    356   // wait for SX126x to safely enter sleep mode
    357   _mod->delay(1);
    358 
    359   return(state);
    360 }
    361 
    362 int16_t SX126x::standby() {
    363   return(SX126x::standby(RADIOLIB_SX126X_STANDBY_RC));
    364 }
    365 
    366 int16_t SX126x::standby(uint8_t mode) {
    367   // set RF switch (if present)
    368   _mod->setRfSwitchState(LOW, LOW);
    369 
    370   uint8_t data[] = {mode};
    371   return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_STANDBY, data, 1));
    372 }
    373 
    374 void SX126x::setDio1Action(void (*func)(void)) {
    375   _mod->attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()), func, RISING);
    376 }
    377 
    378 void SX126x::clearDio1Action() {
    379   _mod->detachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getIrq()));
    380 }
    381 
    382 int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
    383   // suppress unused variable warning
    384   (void)addr;
    385 
    386   // check packet length
    387   if(len > RADIOLIB_SX126X_MAX_PACKET_LENGTH) {
    388     return(RADIOLIB_ERR_PACKET_TOO_LONG);
    389   }
    390 
    391   // maximum packet length is decreased by 1 when address filtering is active
    392   if((_addrComp != RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF) && (len > RADIOLIB_SX126X_MAX_PACKET_LENGTH - 1)) {
    393     return(RADIOLIB_ERR_PACKET_TOO_LONG);
    394   }
    395 
    396   // set packet Length
    397   int16_t state = RADIOLIB_ERR_NONE;
    398   uint8_t modem = getPacketType();
    399   if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
    400     state = setPacketParams(_preambleLength, _crcType, len, _headerType);
    401   } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
    402     state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType, len);
    403   } else {
    404     return(RADIOLIB_ERR_UNKNOWN);
    405   }
    406   RADIOLIB_ASSERT(state);
    407 
    408   // set DIO mapping
    409   state = setDioIrqParams(RADIOLIB_SX126X_IRQ_TX_DONE | RADIOLIB_SX126X_IRQ_TIMEOUT, RADIOLIB_SX126X_IRQ_TX_DONE);
    410   RADIOLIB_ASSERT(state);
    411 
    412   // set buffer pointers
    413   state = setBufferBaseAddress();
    414   RADIOLIB_ASSERT(state);
    415 
    416   // write packet to buffer
    417   state = writeBuffer(data, len);
    418   RADIOLIB_ASSERT(state);
    419 
    420   // clear interrupt flags
    421   state = clearIrqStatus();
    422   RADIOLIB_ASSERT(state);
    423 
    424   // fix sensitivity
    425   state = fixSensitivity();
    426   RADIOLIB_ASSERT(state);
    427 
    428   // set RF switch (if present)
    429   _mod->setRfSwitchState(LOW, HIGH);
    430 
    431   // start transmission
    432   state = setTx(RADIOLIB_SX126X_TX_TIMEOUT_NONE);
    433   RADIOLIB_ASSERT(state);
    434 
    435   // wait for BUSY to go low (= PA ramp up done)
    436   while(_mod->digitalRead(_mod->getGpio())) {
    437     _mod->yield();
    438   }
    439 
    440   return(state);
    441 }
    442 
    443 int16_t SX126x::startReceive(uint32_t timeout) {
    444   int16_t state = startReceiveCommon(timeout);
    445   RADIOLIB_ASSERT(state);
    446 
    447   // set RF switch (if present)
    448   _mod->setRfSwitchState(HIGH, LOW);
    449 
    450   // set mode to receive
    451   state = setRx(timeout);
    452 
    453   return(state);
    454 }
    455 
    456 int16_t SX126x::startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod) {
    457   // datasheet claims time to go to sleep is ~500us, same to wake up, compensate for that with 1 ms + TCXO delay
    458   uint32_t transitionTime = _tcxoDelay + 1000;
    459   sleepPeriod -= transitionTime;
    460 
    461   // divide by 15.625
    462   uint32_t rxPeriodRaw = (rxPeriod * 8) / 125;
    463   uint32_t sleepPeriodRaw = (sleepPeriod * 8) / 125;
    464 
    465   // check 24 bit limit and zero value (likely not intended)
    466   if((rxPeriodRaw & 0xFF000000) || (rxPeriodRaw == 0)) {
    467     return(RADIOLIB_ERR_INVALID_RX_PERIOD);
    468   }
    469 
    470   // this check of the high byte also catches underflow when we subtracted transitionTime
    471   if((sleepPeriodRaw & 0xFF000000) || (sleepPeriodRaw == 0)) {
    472     return(RADIOLIB_ERR_INVALID_SLEEP_PERIOD);
    473   }
    474 
    475   int16_t state = startReceiveCommon();
    476   RADIOLIB_ASSERT(state);
    477 
    478   uint8_t data[6] = {(uint8_t)((rxPeriodRaw >> 16) & 0xFF), (uint8_t)((rxPeriodRaw >> 8) & 0xFF), (uint8_t)(rxPeriodRaw & 0xFF),
    479                      (uint8_t)((sleepPeriodRaw >> 16) & 0xFF), (uint8_t)((sleepPeriodRaw >> 8) & 0xFF), (uint8_t)(sleepPeriodRaw & 0xFF)};
    480   return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_RX_DUTY_CYCLE, data, 6));
    481 }
    482 
    483 int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_t minSymbols) {
    484   if(senderPreambleLength == 0) {
    485     senderPreambleLength = _preambleLength;
    486   }
    487 
    488   // worst case is that the sender starts transmitting when we're just less than minSymbols from going back to sleep.
    489   // in this case, we don't catch minSymbols before going to sleep,
    490   // so we must be awake for at least that long before the sender stops transmitting.
    491   uint16_t sleepSymbols = senderPreambleLength - 2 * minSymbols;
    492 
    493   // if we're not to sleep at all, just use the standard startReceive.
    494   if(2 * minSymbols > senderPreambleLength) {
    495     return(startReceive());
    496   }
    497 
    498   uint32_t symbolLength = ((uint32_t)(10 * 1000) << _sf) / (10 * _bwKhz);
    499   uint32_t sleepPeriod = symbolLength * sleepSymbols;
    500   RADIOLIB_DEBUG_PRINT(F("Auto sleep period: "));
    501   RADIOLIB_DEBUG_PRINTLN(sleepPeriod);
    502 
    503   // when the unit detects a preamble, it starts a timer that will timeout if it doesn't receive a header in time.
    504   // the duration is sleepPeriod + 2 * wakePeriod.
    505   // The sleepPeriod doesn't take into account shutdown and startup time for the unit (~1ms)
    506   // We need to ensure that the timeout is longer than senderPreambleLength.
    507   // So we must satisfy: wakePeriod > (preamblePeriod - (sleepPeriod - 1000)) / 2. (A)
    508   // we also need to ensure the unit is awake to see at least minSymbols. (B)
    509   uint32_t wakePeriod = max(
    510     (symbolLength * (senderPreambleLength + 1) - (sleepPeriod - 1000)) / 2, // (A)
    511     symbolLength * (minSymbols + 1)); //(B)
    512   RADIOLIB_DEBUG_PRINT(F("Auto wake period: "));
    513   RADIOLIB_DEBUG_PRINTLN(wakePeriod);
    514 
    515   // If our sleep period is shorter than our transition time, just use the standard startReceive
    516   if(sleepPeriod < _tcxoDelay + 1016) {
    517     return(startReceive());
    518   }
    519 
    520   return(startReceiveDutyCycle(wakePeriod, sleepPeriod));
    521 }
    522 
    523 int16_t SX126x::startReceiveCommon(uint32_t timeout) {
    524   // set DIO mapping
    525   uint16_t mask = RADIOLIB_SX126X_IRQ_RX_DONE;
    526   if(timeout != RADIOLIB_SX126X_RX_TIMEOUT_INF) {
    527     mask |= RADIOLIB_SX126X_IRQ_TIMEOUT;
    528   }
    529   int16_t state = setDioIrqParams(RADIOLIB_SX126X_IRQ_RX_DONE | RADIOLIB_SX126X_IRQ_TIMEOUT | RADIOLIB_SX126X_IRQ_CRC_ERR | RADIOLIB_SX126X_IRQ_HEADER_ERR, mask);
    530   RADIOLIB_ASSERT(state);
    531 
    532   // set buffer pointers
    533   state = setBufferBaseAddress();
    534   RADIOLIB_ASSERT(state);
    535 
    536   // clear interrupt flags
    537   state = clearIrqStatus();
    538 
    539   // restore original packet length
    540   uint8_t modem = getPacketType();
    541   if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
    542     state = setPacketParams(_preambleLength, _crcType, _implicitLen, _headerType);
    543   } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
    544     state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType);
    545   } else {
    546     return(RADIOLIB_ERR_UNKNOWN);
    547   }
    548 
    549   return(state);
    550 }
    551 
    552 int16_t SX126x::readData(uint8_t* data, size_t len) {
    553   // set mode to standby
    554   int16_t state = standby();
    555   RADIOLIB_ASSERT(state);
    556 
    557   // check integrity CRC
    558   uint16_t irq = getIrqStatus();
    559   int16_t crcState = RADIOLIB_ERR_NONE;
    560   if((irq & RADIOLIB_SX126X_IRQ_CRC_ERR) || (irq & RADIOLIB_SX126X_IRQ_HEADER_ERR)) {
    561     crcState = RADIOLIB_ERR_CRC_MISMATCH;
    562   }
    563 
    564   // get packet length
    565   size_t length = getPacketLength();
    566   if((len != 0) && (len < length)) {
    567     // user requested less data than we got, only return what was requested
    568     length = len;
    569   }
    570 
    571   // read packet data
    572   state = readBuffer(data, length);
    573   RADIOLIB_ASSERT(state);
    574 
    575   // clear interrupt flags
    576   state = clearIrqStatus();
    577 
    578   // check if CRC failed - this is done after reading data to give user the option to keep them
    579   RADIOLIB_ASSERT(crcState);
    580 
    581   return(state);
    582 }
    583 
    584 int16_t SX126x::startChannelScan() {
    585   // check active modem
    586   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
    587     return(RADIOLIB_ERR_WRONG_MODEM);
    588   }
    589 
    590   // set mode to standby
    591   int16_t state = standby();
    592   RADIOLIB_ASSERT(state);
    593 
    594   // set RF switch (if present)
    595   _mod->setRfSwitchState(HIGH, LOW);
    596 
    597   // set DIO pin mapping
    598   state = setDioIrqParams(RADIOLIB_SX126X_IRQ_CAD_DETECTED | RADIOLIB_SX126X_IRQ_CAD_DONE, RADIOLIB_SX126X_IRQ_CAD_DETECTED | RADIOLIB_SX126X_IRQ_CAD_DONE);
    599   RADIOLIB_ASSERT(state);
    600 
    601   // clear interrupt flags
    602   state = clearIrqStatus();
    603   RADIOLIB_ASSERT(state);
    604 
    605   // set mode to CAD
    606   state = setCad();
    607   return(state);
    608 }
    609 
    610 int16_t SX126x::getChannelScanResult() {
    611   // check active modem
    612   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
    613     return(RADIOLIB_ERR_WRONG_MODEM);
    614   }
    615 
    616   // check CAD result
    617   uint16_t cadResult = getIrqStatus();
    618   if(cadResult & RADIOLIB_SX126X_IRQ_CAD_DETECTED) {
    619     // detected some LoRa activity
    620     clearIrqStatus();
    621     return(RADIOLIB_LORA_DETECTED);
    622   } else if(cadResult & RADIOLIB_SX126X_IRQ_CAD_DONE) {
    623     // channel is free
    624     clearIrqStatus();
    625     return(RADIOLIB_CHANNEL_FREE);
    626   }
    627 
    628   return(RADIOLIB_ERR_UNKNOWN);
    629 }
    630 
    631 int16_t SX126x::setBandwidth(float bw) {
    632   // check active modem
    633   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
    634     return(RADIOLIB_ERR_WRONG_MODEM);
    635   }
    636 
    637   // ensure byte conversion doesn't overflow
    638   RADIOLIB_CHECK_RANGE(bw, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH);
    639 
    640   // check allowed bandwidth values
    641   uint8_t bw_div2 = bw / 2 + 0.01;
    642   switch (bw_div2)  {
    643     case 3: // 7.8:
    644       _bw = RADIOLIB_SX126X_LORA_BW_7_8;
    645       break;
    646     case 5: // 10.4:
    647       _bw = RADIOLIB_SX126X_LORA_BW_10_4;
    648       break;
    649     case 7: // 15.6:
    650       _bw = RADIOLIB_SX126X_LORA_BW_15_6;
    651       break;
    652     case 10: // 20.8:
    653       _bw = RADIOLIB_SX126X_LORA_BW_20_8;
    654       break;
    655     case 15: // 31.25:
    656       _bw = RADIOLIB_SX126X_LORA_BW_31_25;
    657       break;
    658     case 20: // 41.7:
    659       _bw = RADIOLIB_SX126X_LORA_BW_41_7;
    660       break;
    661     case 31: // 62.5:
    662       _bw = RADIOLIB_SX126X_LORA_BW_62_5;
    663       break;
    664     case 62: // 125.0:
    665       _bw = RADIOLIB_SX126X_LORA_BW_125_0;
    666       break;
    667     case 125: // 250.0
    668       _bw = RADIOLIB_SX126X_LORA_BW_250_0;
    669       break;
    670     case 250: // 500.0
    671       _bw = RADIOLIB_SX126X_LORA_BW_500_0;
    672       break;
    673     default:
    674       return(RADIOLIB_ERR_INVALID_BANDWIDTH);
    675   }
    676 
    677   // update modulation parameters
    678   _bwKhz = bw;
    679   return(setModulationParams(_sf, _bw, _cr, _ldro));
    680 }
    681 
    682 int16_t SX126x::setSpreadingFactor(uint8_t sf) {
    683   // check active modem
    684   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
    685     return(RADIOLIB_ERR_WRONG_MODEM);
    686   }
    687 
    688   RADIOLIB_CHECK_RANGE(sf, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
    689 
    690   // update modulation parameters
    691   _sf = sf;
    692   return(setModulationParams(_sf, _bw, _cr, _ldro));
    693 }
    694 
    695 int16_t SX126x::setCodingRate(uint8_t cr) {
    696   // check active modem
    697   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
    698     return(RADIOLIB_ERR_WRONG_MODEM);
    699   }
    700 
    701   RADIOLIB_CHECK_RANGE(cr, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
    702 
    703   // update modulation parameters
    704   _cr = cr - 4;
    705   return(setModulationParams(_sf, _bw, _cr, _ldro));
    706 }
    707 
    708 int16_t SX126x::setSyncWord(uint8_t syncWord, uint8_t controlBits) {
    709   // check active modem
    710   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
    711     return(RADIOLIB_ERR_WRONG_MODEM);
    712   }
    713 
    714   // update register
    715   uint8_t data[2] = {(uint8_t)((syncWord & 0xF0) | ((controlBits & 0xF0) >> 4)), (uint8_t)(((syncWord & 0x0F) << 4) | (controlBits & 0x0F))};
    716   return(writeRegister(RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB, data, 2));
    717 }
    718 
    719 int16_t SX126x::setCurrentLimit(float currentLimit) {
    720   // check allowed range
    721   if(!((currentLimit >= 0) && (currentLimit <= 140))) {
    722     return(RADIOLIB_ERR_INVALID_CURRENT_LIMIT);
    723   }
    724 
    725   // calculate raw value
    726   uint8_t rawLimit = (uint8_t)(currentLimit / 2.5);
    727 
    728   // update register
    729   return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &rawLimit, 1));
    730 }
    731 
    732 float SX126x::getCurrentLimit() {
    733   // get the raw value
    734   uint8_t ocp = 0;
    735   readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
    736 
    737   // return the actual value
    738   return((float)ocp * 2.5);
    739 }
    740 
    741 int16_t SX126x::setPreambleLength(uint16_t preambleLength) {
    742   uint8_t modem = getPacketType();
    743   if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
    744     _preambleLength = preambleLength;
    745     return(setPacketParams(_preambleLength, _crcType, _implicitLen, _headerType));
    746   } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
    747     _preambleLengthFSK = preambleLength;
    748     return(setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType));
    749   }
    750 
    751   return(RADIOLIB_ERR_UNKNOWN);
    752 }
    753 
    754 int16_t SX126x::setFrequencyDeviation(float freqDev) {
    755   // check active modem
    756   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
    757     return(RADIOLIB_ERR_WRONG_MODEM);
    758   }
    759 
    760   // set frequency deviation to lowest available setting (required for digimodes)
    761   float newFreqDev = freqDev;
    762   if(freqDev < 0.0) {
    763     newFreqDev = 0.6;
    764   }
    765 
    766   RADIOLIB_CHECK_RANGE(newFreqDev, 0.6, 200.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
    767 
    768   // calculate raw frequency deviation value
    769   uint32_t freqDevRaw = (uint32_t)(((newFreqDev * 1000.0) * (float)((uint32_t)(1) << 25)) / (RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0));
    770 
    771   // check modulation parameters
    772   /*if(2 * freqDevRaw + _br > _rxBwKhz * 1000.0) {
    773     return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS);
    774   }*/
    775   _freqDev = freqDevRaw;
    776 
    777   // update modulation parameters
    778   return(setModulationParamsFSK(_br, _pulseShape, _rxBw, _freqDev));
    779 }
    780 
    781 int16_t SX126x::setBitRate(float br) {
    782   // check active modem
    783   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
    784     return(RADIOLIB_ERR_WRONG_MODEM);
    785   }
    786 
    787   RADIOLIB_CHECK_RANGE(br, 0.6, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE);
    788 
    789   // calculate raw bit rate value
    790   uint32_t brRaw = (uint32_t)((RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0 * 32.0) / (br * 1000.0));
    791 
    792   // check modulation parameters
    793   /*if(2 * _freqDev + brRaw > _rxBwKhz * 1000.0) {
    794     return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS);
    795   }*/
    796   _br = brRaw;
    797 
    798   // update modulation parameters
    799   return(setModulationParamsFSK(_br, _pulseShape, _rxBw, _freqDev));
    800 }
    801 
    802 int16_t SX126x::setRxBandwidth(float rxBw) {
    803   // check active modem
    804   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
    805     return(RADIOLIB_ERR_WRONG_MODEM);
    806   }
    807 
    808   // check modulation parameters
    809   /*if(2 * _freqDev + _br > rxBw * 1000.0) {
    810     return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS);
    811   }*/
    812   _rxBwKhz = rxBw;
    813 
    814   // check allowed receiver bandwidth values
    815   if(fabs(rxBw - 4.8) <= 0.001) {
    816     _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_4_8;
    817   } else if(fabs(rxBw - 5.8) <= 0.001) {
    818     _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_5_8;
    819   } else if(fabs(rxBw - 7.3) <= 0.001) {
    820     _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_7_3;
    821   } else if(fabs(rxBw - 9.7) <= 0.001) {
    822     _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_9_7;
    823   } else if(fabs(rxBw - 11.7) <= 0.001) {
    824     _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_11_7;
    825   } else if(fabs(rxBw - 14.6) <= 0.001) {
    826     _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_14_6;
    827   } else if(fabs(rxBw - 19.5) <= 0.001) {
    828     _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_19_5;
    829   } else if(fabs(rxBw - 23.4) <= 0.001) {
    830     _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_23_4;
    831   } else if(fabs(rxBw - 29.3) <= 0.001) {
    832     _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_29_3;
    833   } else if(fabs(rxBw - 39.0) <= 0.001) {
    834     _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_39_0;
    835   } else if(fabs(rxBw - 46.9) <= 0.001) {
    836     _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_46_9;
    837   } else if(fabs(rxBw - 58.6) <= 0.001) {
    838     _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_58_6;
    839   } else if(fabs(rxBw - 78.2) <= 0.001) {
    840     _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_78_2;
    841   } else if(fabs(rxBw - 93.8) <= 0.001) {
    842     _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_93_8;
    843   } else if(fabs(rxBw - 117.3) <= 0.001) {
    844     _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_117_3;
    845   } else if(fabs(rxBw - 156.2) <= 0.001) {
    846     _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_156_2;
    847   } else if(fabs(rxBw - 187.2) <= 0.001) {
    848     _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_187_2;
    849   } else if(fabs(rxBw - 234.3) <= 0.001) {
    850     _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_234_3;
    851   } else if(fabs(rxBw - 312.0) <= 0.001) {
    852     _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_312_0;
    853   } else if(fabs(rxBw - 373.6) <= 0.001) {
    854     _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_373_6;
    855   } else if(fabs(rxBw - 467.0) <= 0.001) {
    856     _rxBw = RADIOLIB_SX126X_GFSK_RX_BW_467_0;
    857   } else {
    858     return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH);
    859   }
    860 
    861   // update modulation parameters
    862   return(setModulationParamsFSK(_br, _pulseShape, _rxBw, _freqDev));
    863 }
    864 
    865 int16_t SX126x::setDataShaping(uint8_t sh) {
    866   // check active modem
    867   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
    868     return(RADIOLIB_ERR_WRONG_MODEM);
    869   }
    870 
    871   // set data shaping
    872   switch(sh) {
    873     case RADIOLIB_SHAPING_NONE:
    874       _pulseShape = RADIOLIB_SX126X_GFSK_FILTER_NONE;
    875       break;
    876     case RADIOLIB_SHAPING_0_3:
    877       _pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_3;
    878       break;
    879     case RADIOLIB_SHAPING_0_5:
    880       _pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5;
    881       break;
    882     case RADIOLIB_SHAPING_0_7:
    883       _pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_7;
    884       break;
    885     case RADIOLIB_SHAPING_1_0:
    886       _pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_1;
    887       break;
    888     default:
    889       return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
    890   }
    891 
    892   // update modulation parameters
    893   return(setModulationParamsFSK(_br, _pulseShape, _rxBw, _freqDev));
    894 }
    895 
    896 int16_t SX126x::setSyncWord(uint8_t* syncWord, uint8_t len) {
    897   // check active modem
    898   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
    899     return(RADIOLIB_ERR_WRONG_MODEM);
    900   }
    901 
    902   // check sync word Length
    903   if(len > 8) {
    904     return(RADIOLIB_ERR_INVALID_SYNC_WORD);
    905   }
    906 
    907   // write sync word
    908   int16_t state = writeRegister(RADIOLIB_SX126X_REG_SYNC_WORD_0, syncWord, len);
    909   RADIOLIB_ASSERT(state);
    910 
    911   // update packet parameters
    912   _syncWordLength = len * 8;
    913   state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType);
    914 
    915   return(state);
    916 }
    917 
    918 int16_t SX126x::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) {
    919   // check active modem
    920   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
    921     return(RADIOLIB_ERR_WRONG_MODEM);
    922   }
    923 
    924   // check sync word Length
    925   if(bitsLen > 0x40) {
    926     return(RADIOLIB_ERR_INVALID_SYNC_WORD);
    927   }
    928 
    929   uint8_t bytesLen = bitsLen / 8;
    930   if ((bitsLen % 8) != 0) {
    931     bytesLen++;
    932   }
    933 
    934   // write sync word
    935   int16_t state = writeRegister(RADIOLIB_SX126X_REG_SYNC_WORD_0, syncWord, bytesLen);
    936   RADIOLIB_ASSERT(state);
    937 
    938   // update packet parameters
    939   _syncWordLength = bitsLen;
    940   state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType);
    941 
    942   return(state);
    943 }
    944 
    945 int16_t SX126x::setNodeAddress(uint8_t nodeAddr) {
    946   // check active modem
    947   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
    948     return(RADIOLIB_ERR_WRONG_MODEM);
    949   }
    950 
    951   // enable address filtering (node only)
    952   _addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE;
    953   int16_t state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType);
    954   RADIOLIB_ASSERT(state);
    955 
    956   // set node address
    957   state = writeRegister(RADIOLIB_SX126X_REG_NODE_ADDRESS, &nodeAddr, 1);
    958 
    959   return(state);
    960 }
    961 
    962 int16_t SX126x::setBroadcastAddress(uint8_t broadAddr) {
    963   // check active modem
    964   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
    965     return(RADIOLIB_ERR_WRONG_MODEM);
    966   }
    967 
    968   // enable address filtering (node and broadcast)
    969   _addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_NODE_BROADCAST;
    970   int16_t state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType);
    971   RADIOLIB_ASSERT(state);
    972 
    973   // set broadcast address
    974   state = writeRegister(RADIOLIB_SX126X_REG_BROADCAST_ADDRESS, &broadAddr, 1);
    975 
    976   return(state);
    977 }
    978 
    979 int16_t SX126x::disableAddressFiltering() {
    980   // check active modem
    981   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
    982     return(RADIOLIB_ERR_WRONG_MODEM);
    983   }
    984 
    985   // disable address filtering
    986   _addrComp = RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF;
    987   return(setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening));
    988 }
    989 
    990 int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool inverted) {
    991   // check active modem
    992   uint8_t modem = getPacketType();
    993 
    994   if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
    995     // update packet parameters
    996     switch(len) {
    997       case 0:
    998         _crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_OFF;
    999         break;
   1000       case 1:
   1001         if(inverted) {
   1002           _crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE_INV;
   1003         } else {
   1004           _crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE;
   1005         }
   1006         break;
   1007       case 2:
   1008         if(inverted) {
   1009           _crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV;
   1010         } else {
   1011           _crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE;
   1012         }
   1013         break;
   1014       default:
   1015         return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
   1016     }
   1017 
   1018     int16_t state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType);
   1019     RADIOLIB_ASSERT(state);
   1020 
   1021     // write initial CRC value
   1022     uint8_t data[2] = {(uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF)};
   1023     state = writeRegister(RADIOLIB_SX126X_REG_CRC_INITIAL_MSB, data, 2);
   1024     RADIOLIB_ASSERT(state);
   1025 
   1026     // write CRC polynomial value
   1027     data[0] = (uint8_t)((polynomial >> 8) & 0xFF);
   1028     data[1] = (uint8_t)(polynomial & 0xFF);
   1029     state = writeRegister(RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_MSB, data, 2);
   1030 
   1031     return(state);
   1032 
   1033   } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
   1034     // LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion
   1035 
   1036     // update packet parameters
   1037     if(len) {
   1038       _crcType = RADIOLIB_SX126X_LORA_CRC_ON;
   1039     } else {
   1040       _crcType = RADIOLIB_SX126X_LORA_CRC_OFF;
   1041     }
   1042 
   1043     return(setPacketParams(_preambleLength, _crcType, _implicitLen, _headerType));
   1044   }
   1045 
   1046   return(RADIOLIB_ERR_UNKNOWN);
   1047 }
   1048 
   1049 int16_t SX126x::setWhitening(bool enabled, uint16_t initial) {
   1050   // check active modem
   1051   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
   1052     return(RADIOLIB_ERR_WRONG_MODEM);
   1053   }
   1054 
   1055   int16_t state = RADIOLIB_ERR_NONE;
   1056   if(!enabled) {
   1057     // disable whitening
   1058     _whitening = RADIOLIB_SX126X_GFSK_WHITENING_OFF;
   1059 
   1060     state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType);
   1061     RADIOLIB_ASSERT(state);
   1062 
   1063   } else {
   1064     // enable whitening
   1065     _whitening = RADIOLIB_SX126X_GFSK_WHITENING_ON;
   1066 
   1067     // write initial whitening value
   1068     // as per note on pg. 65 of datasheet v1.2: "The user should not change the value of the 7 MSB's of this register"
   1069     uint8_t data[2];
   1070     // first read the actual value and mask 7 MSB which we can not change
   1071     // if different value is written in 7 MSB, the Rx won't even work (tested on HW)
   1072     state = readRegister(RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB, data, 1);
   1073     RADIOLIB_ASSERT(state);
   1074 
   1075     data[0] = (data[0] & 0xFE) | (uint8_t)((initial >> 8) & 0x01);
   1076     data[1] = (uint8_t)(initial & 0xFF);
   1077     state = writeRegister(RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB, data, 2);
   1078     RADIOLIB_ASSERT(state);
   1079 
   1080     state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType);
   1081     RADIOLIB_ASSERT(state);
   1082   }
   1083   return(state);
   1084 }
   1085 
   1086 float SX126x::getDataRate() const {
   1087   return(_dataRate);
   1088 }
   1089 
   1090 float SX126x::getRSSI() {
   1091   // get last packet RSSI from packet status
   1092   uint32_t packetStatus = getPacketStatus();
   1093   uint8_t rssiPkt = packetStatus & 0xFF;
   1094   return(-1.0 * rssiPkt/2.0);
   1095 }
   1096 
   1097 float SX126x::getSNR() {
   1098   // check active modem
   1099   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
   1100     return(RADIOLIB_ERR_WRONG_MODEM);
   1101   }
   1102 
   1103   // get last packet SNR from packet status
   1104   uint32_t packetStatus = getPacketStatus();
   1105   uint8_t snrPkt = (packetStatus >> 8) & 0xFF;
   1106   if(snrPkt < 128) {
   1107     return(snrPkt/4.0);
   1108   } else {
   1109     return((snrPkt - 256)/4.0);
   1110   }
   1111 }
   1112 
   1113 size_t SX126x::getPacketLength(bool update) {
   1114   (void)update;
   1115   uint8_t rxBufStatus[2] = {0, 0};
   1116   SPIreadCommand(RADIOLIB_SX126X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2);
   1117   return((size_t)rxBufStatus[0]);
   1118 }
   1119 
   1120 int16_t SX126x::fixedPacketLengthMode(uint8_t len) {
   1121   return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_FIXED, len));
   1122 }
   1123 
   1124 int16_t SX126x::variablePacketLengthMode(uint8_t maxLen) {
   1125   return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_VARIABLE, maxLen));
   1126 }
   1127 
   1128 uint32_t SX126x::getTimeOnAir(size_t len) {
   1129   // everything is in microseconds to allow integer arithmetic
   1130   // some constants have .25, these are multiplied by 4, and have _x4 postfix to indicate that fact
   1131   if(getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
   1132     uint32_t symbolLength_us = ((uint32_t)(1000 * 10) << _sf) / (_bwKhz * 10) ;
   1133     uint8_t sfCoeff1_x4 = 17; // (4.25 * 4)
   1134     uint8_t sfCoeff2 = 8;
   1135     if(_sf == 5 || _sf == 6) {
   1136       sfCoeff1_x4 = 25; // 6.25 * 4
   1137       sfCoeff2 = 0;
   1138     }
   1139     uint8_t sfDivisor = 4*_sf;
   1140     if(symbolLength_us >= 16000) {
   1141       sfDivisor = 4*(_sf - 2);
   1142     }
   1143     const int8_t bitsPerCrc = 16;
   1144     const int8_t N_symbol_header = _headerType == RADIOLIB_SX126X_LORA_HEADER_EXPLICIT ? 20 : 0;
   1145 
   1146     // numerator of equation in section 6.1.4 of SX1268 datasheet v1.1 (might not actually be bitcount, but it has len * 8)
   1147     int16_t bitCount = (int16_t) 8 * len + _crcType * bitsPerCrc - 4 * _sf  + sfCoeff2 + N_symbol_header;
   1148     if(bitCount < 0) {
   1149       bitCount = 0;
   1150     }
   1151     // add (sfDivisor) - 1 to the numerator to give integer CEIL(...)
   1152     uint16_t nPreCodedSymbols = (bitCount + (sfDivisor - 1)) / (sfDivisor);
   1153 
   1154     // preamble can be 65k, therefore nSymbol_x4 needs to be 32 bit
   1155     uint32_t nSymbol_x4 = (_preambleLength + 8) * 4 + sfCoeff1_x4 + nPreCodedSymbols * (_cr + 4) * 4;
   1156 
   1157     return((symbolLength_us * nSymbol_x4) / 4);
   1158   } else {
   1159     return((len * 8 * _br) / (RADIOLIB_SX126X_CRYSTAL_FREQ * 32));
   1160   }
   1161 }
   1162 
   1163 float SX126x::getRSSIInst() {
   1164   uint8_t data[3] = {0, 0, 0};  // RssiInst, Status, RFU
   1165   SPIreadCommand(RADIOLIB_SX126X_CMD_GET_RSSI_INST, data, 3);
   1166 
   1167   return (float)data[0] / (-2.0);
   1168 }
   1169 
   1170 int16_t SX126x::implicitHeader(size_t len) {
   1171   return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_IMPLICIT, len));
   1172 }
   1173 
   1174 int16_t SX126x::explicitHeader() {
   1175   return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_EXPLICIT));
   1176 }
   1177 
   1178 int16_t SX126x::setRegulatorLDO() {
   1179   return(setRegulatorMode(RADIOLIB_SX126X_REGULATOR_LDO));
   1180 }
   1181 
   1182 int16_t SX126x::setRegulatorDCDC() {
   1183   return(setRegulatorMode(RADIOLIB_SX126X_REGULATOR_DC_DC));
   1184 }
   1185 
   1186 int16_t SX126x::setEncoding(uint8_t encoding) {
   1187   return(setWhitening(encoding));
   1188 }
   1189 
   1190 void SX126x::setRfSwitchPins(RADIOLIB_PIN_TYPE rxEn, RADIOLIB_PIN_TYPE txEn) {
   1191   _mod->setRfSwitchPins(rxEn, txEn);
   1192 }
   1193 
   1194 int16_t SX126x::forceLDRO(bool enable) {
   1195   // check active modem
   1196   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
   1197     return(RADIOLIB_ERR_WRONG_MODEM);
   1198   }
   1199 
   1200   // update modulation parameters
   1201   _ldroAuto = false;
   1202   _ldro = (uint8_t)enable;
   1203   return(setModulationParams(_sf, _bw, _cr, _ldro));
   1204 }
   1205 
   1206 int16_t SX126x::autoLDRO() {
   1207   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
   1208     return(RADIOLIB_ERR_WRONG_MODEM);
   1209   }
   1210 
   1211   _ldroAuto = true;
   1212   return(RADIOLIB_ERR_NONE);
   1213 }
   1214 
   1215 uint8_t SX126x::randomByte() {
   1216   // set mode to Rx
   1217   setRx(RADIOLIB_SX126X_RX_TIMEOUT_INF);
   1218 
   1219   // wait a bit for the RSSI reading to stabilise
   1220   _mod->delay(10);
   1221 
   1222   // read RSSI value 8 times, always keep just the least significant bit
   1223   uint8_t randByte = 0x00;
   1224   for(uint8_t i = 0; i < 8; i++) {
   1225     uint8_t val = 0x00;
   1226     readRegister(RADIOLIB_SX126X_REG_RANDOM_NUMBER_0, &val, sizeof(uint8_t));
   1227     randByte |= ((val & 0x01) << i);
   1228   }
   1229 
   1230   // set mode to standby
   1231   standby();
   1232 
   1233   return(randByte);
   1234 }
   1235 
   1236 #if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE)
   1237 void SX126x::setDirectAction(void (*func)(void)) {
   1238   // SX126x is unable to perform direct mode reception
   1239   // this method is implemented only for PhysicalLayer compatibility
   1240   (void)func;
   1241 }
   1242 
   1243 void SX126x::readBit(RADIOLIB_PIN_TYPE pin) {
   1244   // SX126x is unable to perform direct mode reception
   1245   // this method is implemented only for PhysicalLayer compatibility
   1246   (void)pin;
   1247 }
   1248 #endif
   1249 
   1250 int16_t SX126x::setTCXO(float voltage, uint32_t delay) {
   1251   // set mode to standby
   1252   standby();
   1253 
   1254   // check RADIOLIB_SX126X_XOSC_START_ERR flag and clear it
   1255   if(getDeviceErrors() & RADIOLIB_SX126X_XOSC_START_ERR) {
   1256     clearDeviceErrors();
   1257   }
   1258 
   1259   // check 0 V disable
   1260   if(fabs(voltage - 0.0) <= 0.001) {
   1261     return(reset(true));
   1262   }
   1263 
   1264   // check alowed voltage values
   1265   uint8_t data[4];
   1266   if(fabs(voltage - 1.6) <= 0.001) {
   1267     data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_6;
   1268   } else if(fabs(voltage - 1.7) <= 0.001) {
   1269     data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_7;
   1270   } else if(fabs(voltage - 1.8) <= 0.001) {
   1271     data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_8;
   1272   } else if(fabs(voltage - 2.2) <= 0.001) {
   1273     data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_2;
   1274   } else if(fabs(voltage - 2.4) <= 0.001) {
   1275     data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_4;
   1276   } else if(fabs(voltage - 2.7) <= 0.001) {
   1277     data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_7;
   1278   } else if(fabs(voltage - 3.0) <= 0.001) {
   1279     data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_3_0;
   1280   } else if(fabs(voltage - 3.3) <= 0.001) {
   1281     data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_3_3;
   1282   } else {
   1283     return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE);
   1284   }
   1285 
   1286   // calculate delay
   1287   uint32_t delayValue = (float)delay / 15.625;
   1288   data[1] = (uint8_t)((delayValue >> 16) & 0xFF);
   1289   data[2] = (uint8_t)((delayValue >> 8) & 0xFF);
   1290   data[3] = (uint8_t)(delayValue & 0xFF);
   1291 
   1292   _tcxoDelay = delay;
   1293 
   1294   // enable TCXO control on DIO3
   1295   return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL, data, 4));
   1296 }
   1297 
   1298 int16_t SX126x::setDio2AsRfSwitch(bool enable) {
   1299   uint8_t data = 0;
   1300   if(enable) {
   1301     data = RADIOLIB_SX126X_DIO2_AS_RF_SWITCH;
   1302   } else {
   1303     data = RADIOLIB_SX126X_DIO2_AS_IRQ;
   1304   }
   1305   return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1));
   1306 }
   1307 
   1308 int16_t SX126x::setTx(uint32_t timeout) {
   1309   uint8_t data[] = { (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF)} ;
   1310   return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_TX, data, 3));
   1311 }
   1312 
   1313 int16_t SX126x::setRx(uint32_t timeout) {
   1314   uint8_t data[] = { (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF) };
   1315   return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_RX, data, 3));
   1316 }
   1317 
   1318 int16_t SX126x::setCad() {
   1319   return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_CAD, NULL, 0));
   1320 }
   1321 
   1322 int16_t SX126x::setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax, uint8_t paLut) {
   1323   uint8_t data[] = { paDutyCycle, hpMax, deviceSel, paLut };
   1324   return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_PA_CONFIG, data, 4));
   1325 }
   1326 
   1327 int16_t SX126x::writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) {
   1328   uint8_t cmd[] = { RADIOLIB_SX126X_CMD_WRITE_REGISTER, (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) };
   1329   return(SPIwriteCommand(cmd, 3, data, numBytes));
   1330 }
   1331 
   1332 int16_t SX126x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) {
   1333   uint8_t cmd[] = { RADIOLIB_SX126X_CMD_READ_REGISTER, (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) };
   1334   return(SX126x::SPItransfer(cmd, 3, false, NULL, data, numBytes, true));
   1335 }
   1336 
   1337 int16_t SX126x::writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) {
   1338   uint8_t cmd[] = { RADIOLIB_SX126X_CMD_WRITE_BUFFER, offset };
   1339   return(SPIwriteCommand(cmd, 2, data, numBytes));
   1340 }
   1341 
   1342 int16_t SX126x::readBuffer(uint8_t* data, uint8_t numBytes) {
   1343   uint8_t cmd[] = { RADIOLIB_SX126X_CMD_READ_BUFFER, RADIOLIB_SX126X_CMD_NOP };
   1344   return(SPIreadCommand(cmd, 2, data, numBytes));
   1345 }
   1346 
   1347 int16_t SX126x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) {
   1348   uint8_t data[8] = {(uint8_t)((irqMask >> 8) & 0xFF), (uint8_t)(irqMask & 0xFF),
   1349                      (uint8_t)((dio1Mask >> 8) & 0xFF), (uint8_t)(dio1Mask & 0xFF),
   1350                      (uint8_t)((dio2Mask >> 8) & 0xFF), (uint8_t)(dio2Mask & 0xFF),
   1351                      (uint8_t)((dio3Mask >> 8) & 0xFF), (uint8_t)(dio3Mask & 0xFF)};
   1352   return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_DIO_IRQ_PARAMS, data, 8));
   1353 }
   1354 
   1355 uint16_t SX126x::getIrqStatus() {
   1356   uint8_t data[] = { 0x00, 0x00 };
   1357   SPIreadCommand(RADIOLIB_SX126X_CMD_GET_IRQ_STATUS, data, 2);
   1358   return(((uint16_t)(data[0]) << 8) | data[1]);
   1359 }
   1360 
   1361 int16_t SX126x::clearIrqStatus(uint16_t clearIrqParams) {
   1362   uint8_t data[] = { (uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF) };
   1363   return(SPIwriteCommand(RADIOLIB_SX126X_CMD_CLEAR_IRQ_STATUS, data, 2));
   1364 }
   1365 
   1366 int16_t SX126x::setRfFrequency(uint32_t frf) {
   1367   uint8_t data[] = { (uint8_t)((frf >> 24) & 0xFF), (uint8_t)((frf >> 16) & 0xFF), (uint8_t)((frf >> 8) & 0xFF), (uint8_t)(frf & 0xFF) };
   1368   return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_RF_FREQUENCY, data, 4));
   1369 }
   1370 
   1371 int16_t SX126x::calibrateImage(uint8_t* data) {
   1372   return(SPIwriteCommand(RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE, data, 2));
   1373 }
   1374 
   1375 uint8_t SX126x::getPacketType() {
   1376   uint8_t data = 0xFF;
   1377   SPIreadCommand(RADIOLIB_SX126X_CMD_GET_PACKET_TYPE, &data, 1);
   1378   return(data);
   1379 }
   1380 
   1381 int16_t SX126x::setTxParams(uint8_t power, uint8_t rampTime) {
   1382   uint8_t data[] = { power, rampTime };
   1383   return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_TX_PARAMS, data, 2));
   1384 }
   1385 
   1386 int16_t SX126x::setPacketMode(uint8_t mode, uint8_t len) {
   1387   // check active modem
   1388   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
   1389     return(RADIOLIB_ERR_WRONG_MODEM);
   1390   }
   1391 
   1392   // set requested packet mode
   1393   int16_t state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, mode, len);
   1394   RADIOLIB_ASSERT(state);
   1395 
   1396   // update cached value
   1397   _packetType = mode;
   1398   return(state);
   1399 }
   1400 
   1401 int16_t SX126x::setHeaderType(uint8_t headerType, size_t len) {
   1402   // check active modem
   1403   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
   1404     return(RADIOLIB_ERR_WRONG_MODEM);
   1405   }
   1406 
   1407   // set requested packet mode
   1408   int16_t state = setPacketParams(_preambleLength, _crcType, len, headerType);
   1409   RADIOLIB_ASSERT(state);
   1410 
   1411   // update cached value
   1412   _headerType = headerType;
   1413   _implicitLen = len;
   1414 
   1415   return(state);
   1416 }
   1417 
   1418 int16_t SX126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro) {
   1419   // calculate symbol length and enable low data rate optimization, if auto-configuration is enabled
   1420   if(_ldroAuto) {
   1421     float symbolLength = (float)(uint32_t(1) << _sf) / (float)_bwKhz;
   1422     RADIOLIB_DEBUG_PRINT("Symbol length: ");
   1423     RADIOLIB_DEBUG_PRINT(symbolLength);
   1424     RADIOLIB_DEBUG_PRINTLN(" ms");
   1425     if(symbolLength >= 16.0) {
   1426       _ldro = RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON;
   1427     } else {
   1428       _ldro = RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF;
   1429     }
   1430   } else {
   1431     _ldro = ldro;
   1432   }
   1433   // 500/9/8  - 0x09 0x04 0x03 0x00 - SF9, BW125, 4/8
   1434   // 500/11/8 - 0x0B 0x04 0x03 0x00 - SF11 BW125, 4/7
   1435   uint8_t data[4] = {sf, bw, cr, _ldro};
   1436   return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 4));
   1437 }
   1438 
   1439 int16_t SX126x::setModulationParamsFSK(uint32_t br, uint8_t pulseShape, uint8_t rxBw, uint32_t freqDev) {
   1440   uint8_t data[8] = {(uint8_t)((br >> 16) & 0xFF), (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF),
   1441                      pulseShape, rxBw,
   1442                      (uint8_t)((freqDev >> 16) & 0xFF), (uint8_t)((freqDev >> 8) & 0xFF), (uint8_t)(freqDev & 0xFF)};
   1443   return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 8));
   1444 }
   1445 
   1446 int16_t SX126x::setPacketParams(uint16_t preambleLength, uint8_t crcType, uint8_t payloadLength, uint8_t headerType, uint8_t invertIQ) {
   1447   int16_t state = fixInvertedIQ(invertIQ);
   1448   RADIOLIB_ASSERT(state);
   1449   uint8_t data[6] = {(uint8_t)((preambleLength >> 8) & 0xFF), (uint8_t)(preambleLength & 0xFF), headerType, payloadLength, crcType, invertIQ};
   1450   return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, 6));
   1451 }
   1452 
   1453 int16_t SX126x::setPacketParamsFSK(uint16_t preambleLength, uint8_t crcType, uint8_t syncWordLength, uint8_t addrComp, uint8_t whitening, uint8_t packetType, uint8_t payloadLength, uint8_t preambleDetectorLength) {
   1454   uint8_t data[9] = {(uint8_t)((preambleLength >> 8) & 0xFF), (uint8_t)(preambleLength & 0xFF),
   1455                      preambleDetectorLength, syncWordLength, addrComp,
   1456                      packetType, payloadLength, crcType, whitening};
   1457   return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, 9));
   1458 }
   1459 
   1460 int16_t SX126x::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) {
   1461   uint8_t data[2] = {txBaseAddress, rxBaseAddress};
   1462   return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2));
   1463 }
   1464 
   1465 int16_t SX126x::setRegulatorMode(uint8_t mode) {
   1466   uint8_t data[1] = {mode};
   1467   return(SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_REGULATOR_MODE, data, 1));
   1468 }
   1469 
   1470 uint8_t SX126x::getStatus() {
   1471   uint8_t data = 0;
   1472   SPIreadCommand(RADIOLIB_SX126X_CMD_GET_STATUS, &data, 1);
   1473   return(data);
   1474 }
   1475 
   1476 uint32_t SX126x::getPacketStatus() {
   1477   uint8_t data[3] = {0, 0, 0};
   1478   SPIreadCommand(RADIOLIB_SX126X_CMD_GET_PACKET_STATUS, data, 3);
   1479   return((((uint32_t)data[0]) << 16) | (((uint32_t)data[1]) << 8) | (uint32_t)data[2]);
   1480 }
   1481 
   1482 uint16_t SX126x::getDeviceErrors() {
   1483   uint8_t data[2] = {0, 0};
   1484   SPIreadCommand(RADIOLIB_SX126X_CMD_GET_DEVICE_ERRORS, data, 2);
   1485   uint16_t opError = (((uint16_t)data[0] & 0xFF) << 8) & ((uint16_t)data[1]);
   1486   return(opError);
   1487 }
   1488 
   1489 int16_t SX126x::clearDeviceErrors() {
   1490   uint8_t data[2] = {RADIOLIB_SX126X_CMD_NOP, RADIOLIB_SX126X_CMD_NOP};
   1491   return(SPIwriteCommand(RADIOLIB_SX126X_CMD_CLEAR_DEVICE_ERRORS, data, 2));
   1492 }
   1493 
   1494 int16_t SX126x::setFrequencyRaw(float freq) {
   1495   // calculate raw value
   1496   uint32_t frf = (freq * (uint32_t(1) << RADIOLIB_SX126X_DIV_EXPONENT)) / RADIOLIB_SX126X_CRYSTAL_FREQ;
   1497   return(setRfFrequency(frf));
   1498 }
   1499 
   1500 int16_t SX126x::fixSensitivity() {
   1501   // fix receiver sensitivity for 500 kHz LoRa
   1502   // see SX1262/SX1268 datasheet, chapter 15 Known Limitations, section 15.1 for details
   1503 
   1504   // read current sensitivity configuration
   1505   uint8_t sensitivityConfig = 0;
   1506   int16_t state = readRegister(RADIOLIB_SX126X_REG_SENSITIVITY_CONFIG, &sensitivityConfig, 1);
   1507   RADIOLIB_ASSERT(state);
   1508 
   1509   // fix the value for LoRa with 500 kHz bandwidth
   1510   if((getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA) && (fabs(_bwKhz - 500.0) <= 0.001)) {
   1511     sensitivityConfig &= 0xFB;
   1512   } else {
   1513     sensitivityConfig |= 0x04;
   1514   }
   1515   return(writeRegister(RADIOLIB_SX126X_REG_SENSITIVITY_CONFIG, &sensitivityConfig, 1));
   1516 }
   1517 
   1518 int16_t SX126x::fixPaClamping() {
   1519   // fixes overly eager PA clamping
   1520   // see SX1262/SX1268 datasheet, chapter 15 Known Limitations, section 15.2 for details
   1521 
   1522   // read current clamping configuration
   1523   uint8_t clampConfig = 0;
   1524   int16_t state = readRegister(RADIOLIB_SX126X_REG_TX_CLAMP_CONFIG, &clampConfig, 1);
   1525   RADIOLIB_ASSERT(state);
   1526 
   1527   // update with the new value
   1528   clampConfig |= 0x1E;
   1529   return(writeRegister(RADIOLIB_SX126X_REG_TX_CLAMP_CONFIG, &clampConfig, 1));
   1530 }
   1531 
   1532 int16_t SX126x::fixImplicitTimeout() {
   1533   // fixes timeout in implicit header mode
   1534   // see SX1262/SX1268 datasheet, chapter 15 Known Limitations, section 15.3 for details
   1535 
   1536   //check if we're in implicit LoRa mode
   1537   if(!((_headerType == RADIOLIB_SX126X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX126X_PACKET_TYPE_LORA))) {
   1538     return(RADIOLIB_ERR_WRONG_MODEM);
   1539   }
   1540 
   1541   // stop RTC counter
   1542   uint8_t rtcStop = 0x00;
   1543   int16_t state = writeRegister(RADIOLIB_SX126X_REG_DIO3_OUT_VOLTAGE_CTRL, &rtcStop, 1);
   1544   RADIOLIB_ASSERT(state);
   1545 
   1546   // read currently active event
   1547   uint8_t rtcEvent = 0;
   1548   state = readRegister(RADIOLIB_SX126X_REG_EVENT_MASK, &rtcEvent, 1);
   1549   RADIOLIB_ASSERT(state);
   1550 
   1551   // clear events
   1552   rtcEvent |= 0x02;
   1553   return(writeRegister(RADIOLIB_SX126X_REG_EVENT_MASK, &rtcEvent, 1));
   1554 }
   1555 
   1556 int16_t SX126x::fixInvertedIQ(uint8_t iqConfig) {
   1557   // fixes IQ configuration for inverted IQ
   1558   // see SX1262/SX1268 datasheet, chapter 15 Known Limitations, section 15.4 for details
   1559 
   1560   // read current IQ configuration
   1561   uint8_t iqConfigCurrent = 0;
   1562   int16_t state = readRegister(RADIOLIB_SX126X_REG_IQ_CONFIG, &iqConfigCurrent, 1);
   1563   RADIOLIB_ASSERT(state);
   1564 
   1565   // set correct IQ configuration
   1566   if(iqConfig == RADIOLIB_SX126X_LORA_IQ_INVERTED) {
   1567     iqConfigCurrent &= 0xFB;
   1568   } else {
   1569     iqConfigCurrent |= 0x04;
   1570   }
   1571 
   1572   // update with the new value
   1573   return(writeRegister(RADIOLIB_SX126X_REG_IQ_CONFIG, &iqConfigCurrent, 1));
   1574 }
   1575 
   1576 int16_t SX126x::config(uint8_t modem) {
   1577   // reset buffer base address
   1578   int16_t state = setBufferBaseAddress();
   1579   RADIOLIB_ASSERT(state);
   1580 
   1581   // set modem
   1582   uint8_t data[7];
   1583   data[0] = modem;
   1584   state = SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_PACKET_TYPE, data, 1);
   1585   RADIOLIB_ASSERT(state);
   1586 
   1587   // set Rx/Tx fallback mode to STDBY_RC
   1588   data[0] = RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC;
   1589   state = SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1);
   1590   RADIOLIB_ASSERT(state);
   1591 
   1592   // set CAD parameters
   1593   data[0] = RADIOLIB_SX126X_CAD_ON_8_SYMB;
   1594   data[1] = _sf + 13;
   1595   data[2] = 10;
   1596   data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY;
   1597   data[4] = 0x00;
   1598   data[5] = 0x00;
   1599   data[6] = 0x00;
   1600   state = SPIwriteCommand(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7);
   1601   RADIOLIB_ASSERT(state);
   1602 
   1603   // clear IRQ
   1604   state = clearIrqStatus();
   1605   state |= setDioIrqParams(RADIOLIB_SX126X_IRQ_NONE, RADIOLIB_SX126X_IRQ_NONE);
   1606   RADIOLIB_ASSERT(state);
   1607 
   1608   // calibrate all blocks
   1609   data[0] = RADIOLIB_SX126X_CALIBRATE_ALL;
   1610   state = SPIwriteCommand(RADIOLIB_SX126X_CMD_CALIBRATE, data, 1);
   1611   RADIOLIB_ASSERT(state);
   1612 
   1613   // wait for calibration completion
   1614   _mod->delay(5);
   1615   while(_mod->digitalRead(_mod->getGpio())) {
   1616     _mod->yield();
   1617   }
   1618 
   1619   return(RADIOLIB_ERR_NONE);
   1620 }
   1621 
   1622 int16_t SX126x::SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy) {
   1623   return(SX126x::SPItransfer(cmd, cmdLen, true, data, NULL, numBytes, waitForBusy));
   1624 }
   1625 
   1626 int16_t SX126x::SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy) {
   1627   return(SX126x::SPItransfer(&cmd, 1, true, data, NULL, numBytes, waitForBusy));
   1628 }
   1629 
   1630 int16_t SX126x::SPIreadCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy) {
   1631   return(SX126x::SPItransfer(cmd, cmdLen, false, NULL, data, numBytes, waitForBusy));
   1632 }
   1633 
   1634 int16_t SX126x::SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy) {
   1635   return(SX126x::SPItransfer(&cmd, 1, false, NULL, data, numBytes, waitForBusy));
   1636 }
   1637 
   1638 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) {
   1639   #if defined(RADIOLIB_VERBOSE)
   1640     uint8_t debugBuff[256];
   1641   #endif
   1642 
   1643   // pull NSS low
   1644   _mod->digitalWrite(_mod->getCs(), LOW);
   1645 
   1646   // ensure BUSY is low (state machine ready)
   1647   uint32_t start = _mod->millis();
   1648   while(_mod->digitalRead(_mod->getGpio())) {
   1649     _mod->yield();
   1650     if(_mod->millis() - start >= timeout) {
   1651       _mod->digitalWrite(_mod->getCs(), HIGH);
   1652       return(RADIOLIB_ERR_SPI_CMD_TIMEOUT);
   1653     }
   1654   }
   1655 
   1656   // start transfer
   1657   _mod->SPIbeginTransaction();
   1658 
   1659   // send command byte(s)
   1660   for(uint8_t n = 0; n < cmdLen; n++) {
   1661     _mod->SPItransfer(cmd[n]);
   1662   }
   1663 
   1664   // variable to save error during SPI transfer
   1665   uint8_t status = 0;
   1666 
   1667   // send/receive all bytes
   1668   if(write) {
   1669     for(uint8_t n = 0; n < numBytes; n++) {
   1670       // send byte
   1671       uint8_t in = _mod->SPItransfer(dataOut[n]);
   1672       #if defined(RADIOLIB_VERBOSE)
   1673         debugBuff[n] = in;
   1674       #endif
   1675 
   1676       // check status
   1677       if(((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_TIMEOUT) ||
   1678          ((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_INVALID) ||
   1679          ((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_FAILED)) {
   1680         status = in & 0b00001110;
   1681         break;
   1682       } else if(in == 0x00 || in == 0xFF) {
   1683         status = RADIOLIB_SX126X_STATUS_SPI_FAILED;
   1684         break;
   1685       }
   1686     }
   1687 
   1688   } else {
   1689     // skip the first byte for read-type commands (status-only)
   1690     uint8_t in = _mod->SPItransfer(RADIOLIB_SX126X_CMD_NOP);
   1691     #if defined(RADIOLIB_VERBOSE)
   1692       debugBuff[0] = in;
   1693     #endif
   1694 
   1695     // check status
   1696     if(((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_TIMEOUT) ||
   1697        ((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_INVALID) ||
   1698        ((in & 0b00001110) == RADIOLIB_SX126X_STATUS_CMD_FAILED)) {
   1699       status = in & 0b00001110;
   1700     } else if(in == 0x00 || in == 0xFF) {
   1701       status = RADIOLIB_SX126X_STATUS_SPI_FAILED;
   1702     } else {
   1703       for(uint8_t n = 0; n < numBytes; n++) {
   1704         dataIn[n] = _mod->SPItransfer(RADIOLIB_SX126X_CMD_NOP);
   1705       }
   1706     }
   1707   }
   1708 
   1709   // stop transfer
   1710   _mod->SPIendTransaction();
   1711   _mod->digitalWrite(_mod->getCs(), HIGH);
   1712 
   1713   // wait for BUSY to go high and then low
   1714   if(waitForBusy) {
   1715     _mod->delayMicroseconds(1);
   1716     start = _mod->millis();
   1717     while(_mod->digitalRead(_mod->getGpio())) {
   1718       _mod->yield();
   1719       if(_mod->millis() - start >= timeout) {
   1720         status = RADIOLIB_SX126X_STATUS_CMD_TIMEOUT;
   1721         break;
   1722       }
   1723     }
   1724   }
   1725 
   1726   // print debug output
   1727   #if defined(RADIOLIB_VERBOSE)
   1728     // print command byte(s)
   1729     RADIOLIB_VERBOSE_PRINT("CMD\t");
   1730     for(uint8_t n = 0; n < cmdLen; n++) {
   1731       RADIOLIB_VERBOSE_PRINT(cmd[n], HEX);
   1732       RADIOLIB_VERBOSE_PRINT('\t');
   1733     }
   1734     RADIOLIB_VERBOSE_PRINTLN();
   1735 
   1736     // print data bytes
   1737     RADIOLIB_VERBOSE_PRINT("DAT");
   1738     if(write) {
   1739       RADIOLIB_VERBOSE_PRINT("W\t");
   1740       for(uint8_t n = 0; n < numBytes; n++) {
   1741         RADIOLIB_VERBOSE_PRINT(dataOut[n], HEX);
   1742         RADIOLIB_VERBOSE_PRINT('\t');
   1743         RADIOLIB_VERBOSE_PRINT(debugBuff[n], HEX);
   1744         RADIOLIB_VERBOSE_PRINT('\t');
   1745       }
   1746       RADIOLIB_VERBOSE_PRINTLN();
   1747     } else {
   1748       RADIOLIB_VERBOSE_PRINT("R\t");
   1749       // skip the first byte for read-type commands (status-only)
   1750       RADIOLIB_VERBOSE_PRINT(RADIOLIB_SX126X_CMD_NOP, HEX);
   1751       RADIOLIB_VERBOSE_PRINT('\t');
   1752       RADIOLIB_VERBOSE_PRINT(debugBuff[0], HEX);
   1753       RADIOLIB_VERBOSE_PRINT('\t')
   1754 
   1755       for(uint8_t n = 0; n < numBytes; n++) {
   1756         RADIOLIB_VERBOSE_PRINT(RADIOLIB_SX126X_CMD_NOP, HEX);
   1757         RADIOLIB_VERBOSE_PRINT('\t');
   1758         RADIOLIB_VERBOSE_PRINT(dataIn[n], HEX);
   1759         RADIOLIB_VERBOSE_PRINT('\t');
   1760       }
   1761       RADIOLIB_VERBOSE_PRINTLN();
   1762     }
   1763     RADIOLIB_VERBOSE_PRINTLN();
   1764   #else
   1765     // some faster platforms require a short delay here
   1766     // not sure why, but it seems that long enough SPI transaction
   1767     // (e.g. setPacketParams for GFSK) will fail without it
   1768     #if defined(RADIOLIB_SPI_SLOWDOWN)
   1769       _mod->delay(1);
   1770     #endif
   1771   #endif
   1772 
   1773   // parse status
   1774   switch(status) {
   1775     case RADIOLIB_SX126X_STATUS_CMD_TIMEOUT:
   1776       return(RADIOLIB_ERR_SPI_CMD_TIMEOUT);
   1777     case RADIOLIB_SX126X_STATUS_CMD_INVALID:
   1778       return(RADIOLIB_ERR_SPI_CMD_INVALID);
   1779     case RADIOLIB_SX126X_STATUS_CMD_FAILED:
   1780       return(RADIOLIB_ERR_SPI_CMD_FAILED);
   1781     case RADIOLIB_SX126X_STATUS_SPI_FAILED:
   1782       return(RADIOLIB_ERR_CHIP_NOT_FOUND);
   1783     default:
   1784       return(RADIOLIB_ERR_NONE);
   1785   }
   1786 }
   1787 
   1788 #endif