LCOV - code coverage report
Current view: top level - src/modules/LR11x0 - LR11x0.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 45 1164 3.9 %
Date: 2025-10-24 15:14:50 Functions: 2 92 2.2 %

          Line data    Source code
       1             : #include "LR11x0.h"
       2             : 
       3             : #include <math.h>
       4             : #include <string.h>
       5             : 
       6             : #if !RADIOLIB_EXCLUDE_LR11X0
       7             : 
       8          13 : LR11x0::LR11x0(Module* mod) : PhysicalLayer() {
       9          13 :   this->freqStep = RADIOLIB_LR11X0_FREQUENCY_STEP_SIZE;
      10          13 :   this->maxPacketLength = RADIOLIB_LR11X0_MAX_PACKET_LENGTH;
      11          13 :   this->mod = mod;
      12          13 :   this->XTAL = false;
      13          13 :   this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_LR11X0_IRQ_TX_DONE;
      14          13 :   this->irqMap[RADIOLIB_IRQ_RX_DONE] = RADIOLIB_LR11X0_IRQ_RX_DONE;
      15          13 :   this->irqMap[RADIOLIB_IRQ_PREAMBLE_DETECTED] = RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED;
      16          13 :   this->irqMap[RADIOLIB_IRQ_SYNC_WORD_VALID] = RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID;
      17          13 :   this->irqMap[RADIOLIB_IRQ_HEADER_VALID] = RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID;
      18          13 :   this->irqMap[RADIOLIB_IRQ_HEADER_ERR] = RADIOLIB_LR11X0_IRQ_HEADER_ERR;
      19          13 :   this->irqMap[RADIOLIB_IRQ_CRC_ERR] = RADIOLIB_LR11X0_IRQ_CRC_ERR;
      20          13 :   this->irqMap[RADIOLIB_IRQ_CAD_DONE] = RADIOLIB_LR11X0_IRQ_CAD_DONE;
      21          13 :   this->irqMap[RADIOLIB_IRQ_CAD_DETECTED] = RADIOLIB_LR11X0_IRQ_CAD_DETECTED;
      22          13 :   this->irqMap[RADIOLIB_IRQ_TIMEOUT] = RADIOLIB_LR11X0_IRQ_TIMEOUT;
      23          13 : }
      24             : 
      25           0 : int16_t LR11x0::begin(float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16_t preambleLength, float tcxoVoltage, bool high) {
      26             :   // set module properties and perform initial setup
      27           0 :   int16_t state = this->modSetup(tcxoVoltage, RADIOLIB_LR11X0_PACKET_TYPE_LORA);
      28           0 :   RADIOLIB_ASSERT(state);
      29             : 
      30             :   // configure publicly accessible settings
      31           0 :   state = setBandwidth(bw, high);
      32           0 :   RADIOLIB_ASSERT(state);
      33             : 
      34           0 :   state = setSpreadingFactor(sf);
      35           0 :   RADIOLIB_ASSERT(state);
      36             : 
      37           0 :   state = setCodingRate(cr);
      38           0 :   RADIOLIB_ASSERT(state);
      39             : 
      40           0 :   state = setSyncWord(syncWord);
      41           0 :   RADIOLIB_ASSERT(state);
      42             : 
      43           0 :   state = setPreambleLength(preambleLength);
      44           0 :   RADIOLIB_ASSERT(state);
      45             : 
      46             :   // set publicly accessible settings that are not a part of begin method
      47           0 :   state = setCRC(2);
      48           0 :   RADIOLIB_ASSERT(state);
      49             : 
      50           0 :   state = invertIQ(false);
      51           0 :   RADIOLIB_ASSERT(state);
      52             : 
      53           0 :   state = setRegulatorLDO();
      54           0 :   RADIOLIB_ASSERT(state);
      55             : 
      56           0 :   return(RADIOLIB_ERR_NONE);
      57             : }
      58             : 
      59           0 : int16_t LR11x0::beginGFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float tcxoVoltage) {
      60             :   // set module properties and perform initial setup
      61           0 :   int16_t state = this->modSetup(tcxoVoltage, RADIOLIB_LR11X0_PACKET_TYPE_GFSK);
      62           0 :   RADIOLIB_ASSERT(state);
      63             : 
      64             :   // configure publicly accessible settings
      65           0 :   state = setBitRate(br);
      66           0 :   RADIOLIB_ASSERT(state);
      67             : 
      68           0 :   state = setFrequencyDeviation(freqDev);
      69           0 :   RADIOLIB_ASSERT(state);
      70             : 
      71           0 :   state = setRxBandwidth(rxBw);
      72           0 :   RADIOLIB_ASSERT(state);
      73             : 
      74           0 :   state = setPreambleLength(preambleLength);
      75           0 :   RADIOLIB_ASSERT(state);
      76             : 
      77             :   // set publicly accessible settings that are not a part of begin method
      78           0 :   uint8_t sync[] = { 0x12, 0xAD };
      79           0 :   state = setSyncWord(sync, 2);
      80           0 :   RADIOLIB_ASSERT(state);
      81             : 
      82           0 :   state = setDataShaping(RADIOLIB_SHAPING_NONE);
      83           0 :   RADIOLIB_ASSERT(state);
      84             : 
      85           0 :   state = setEncoding(RADIOLIB_ENCODING_NRZ);
      86           0 :   RADIOLIB_ASSERT(state);
      87             : 
      88           0 :   state = variablePacketLengthMode(RADIOLIB_LR11X0_MAX_PACKET_LENGTH);
      89           0 :   RADIOLIB_ASSERT(state);
      90             : 
      91           0 :   state = setCRC(2);
      92           0 :   RADIOLIB_ASSERT(state);
      93             : 
      94           0 :   state = setRegulatorLDO();
      95           0 :   RADIOLIB_ASSERT(state);
      96             : 
      97           0 :   return(RADIOLIB_ERR_NONE);
      98             : }
      99             : 
     100           0 : int16_t LR11x0::beginLRFHSS(uint8_t bw, uint8_t cr, bool narrowGrid, float tcxoVoltage) {
     101             :   // set module properties and perform initial setup
     102           0 :   int16_t state = this->modSetup(tcxoVoltage, RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS);
     103           0 :   RADIOLIB_ASSERT(state);
     104             : 
     105             :   // set grid spacing
     106           0 :   this->lrFhssGrid = narrowGrid ? RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_FCC;
     107             : 
     108             :   // configure publicly accessible settings
     109           0 :   state = setLrFhssConfig(bw, cr);
     110           0 :   RADIOLIB_ASSERT(state);
     111             : 
     112           0 :   uint8_t syncWord[] = { 0x12, 0xAD, 0x10, 0x1B };
     113           0 :   state = setSyncWord(syncWord, 4);
     114           0 :   RADIOLIB_ASSERT(state);
     115             : 
     116           0 :   state = setRegulatorLDO();
     117           0 :   RADIOLIB_ASSERT(state);
     118             : 
     119             :   // set fixed configuration
     120           0 :   return(setModulationParamsLrFhss(RADIOLIB_LR11X0_LR_FHSS_BIT_RATE_RAW, RADIOLIB_LR11X0_LR_FHSS_SHAPING_GAUSSIAN_BT_1_0));
     121             : }
     122             : 
     123           0 : int16_t LR11x0::beginGNSS(uint8_t constellations, float tcxoVoltage) {
     124             :   // set module properties and perform initial setup - packet type does not matter
     125           0 :   int16_t state = this->modSetup(tcxoVoltage, RADIOLIB_LR11X0_PACKET_TYPE_LORA);
     126           0 :   RADIOLIB_ASSERT(state);
     127             : 
     128           0 :   state = this->clearErrors();
     129           0 :   RADIOLIB_ASSERT(state);
     130             : 
     131             :   // set GNSS flag to reserve DIO11 for LF clock
     132           0 :   this->gnss = true;
     133           0 :   state = this->configLfClock(RADIOLIB_LR11X0_LF_BUSY_RELEASE_DISABLED | RADIOLIB_LR11X0_LF_CLK_XOSC);
     134           0 :   RADIOLIB_ASSERT(state);
     135             : 
     136           0 :   uint16_t errs = 0;
     137           0 :   state = this->getErrors(&errs);
     138           0 :   RADIOLIB_ASSERT(state);
     139           0 :   if(errs & 0x40) {
     140             :     RADIOLIB_DEBUG_BASIC_PRINTLN("LF_XOSC_START_ERR");
     141           0 :     return(RADIOLIB_ERR_SPI_CMD_FAILED);
     142             :   }
     143             : 
     144           0 :   state = this->gnssSetConstellationToUse(constellations);
     145           0 :   RADIOLIB_ASSERT(state);
     146             : 
     147           0 :   state = setRegulatorLDO();
     148           0 :   RADIOLIB_ASSERT(state);
     149             : 
     150           0 :   return(RADIOLIB_ERR_NONE);
     151             : }
     152             : 
     153           0 : int16_t LR11x0::reset() {
     154             :   // run the reset sequence
     155           0 :   this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput);
     156           0 :   this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow);
     157           0 :   this->mod->hal->delay(10);
     158           0 :   this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh);
     159             : 
     160             :   // the typical transition duration should be 273 ms
     161           0 :   this->mod->hal->delay(300);
     162             :   
     163             :   // wait for BUSY to go low
     164           0 :   RadioLibTime_t start = this->mod->hal->millis();
     165           0 :   while(this->mod->hal->digitalRead(this->mod->getGpio())) {
     166           0 :     this->mod->hal->yield();
     167           0 :     if(this->mod->hal->millis() - start >= 3000) {
     168             :       RADIOLIB_DEBUG_BASIC_PRINTLN("BUSY pin timeout after reset!");
     169           0 :       return(RADIOLIB_ERR_SPI_CMD_TIMEOUT);
     170             :     }
     171             :   }
     172             : 
     173           0 :   return(RADIOLIB_ERR_NONE);
     174             : }
     175             : 
     176           0 : int16_t LR11x0::transmit(const uint8_t* data, size_t len, uint8_t addr) {
     177             :    // set mode to standby
     178           0 :   int16_t state = standby();
     179           0 :   RADIOLIB_ASSERT(state);
     180             : 
     181             :   // check packet length
     182           0 :   if (this->codingRate > RADIOLIB_LR11X0_LORA_CR_4_8_SHORT) {
     183             :     // Long Interleaver needs at least 8 bytes
     184           0 :     if(len < 8) {
     185           0 :       return(RADIOLIB_ERR_PACKET_TOO_SHORT);
     186             :     }
     187             : 
     188             :     // Long Interleaver supports up to 253 bytes if CRC is enabled
     189           0 :     if (this->crcTypeLoRa == RADIOLIB_LR11X0_LORA_CRC_ENABLED && (len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH - 2)) {
     190           0 :       return(RADIOLIB_ERR_PACKET_TOO_LONG);
     191             :     }  
     192             :   } 
     193           0 :   if(len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH) {
     194           0 :     return(RADIOLIB_ERR_PACKET_TOO_LONG);
     195             :   }
     196             : 
     197             :   // get currently active modem
     198           0 :   uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
     199           0 :   state = getPacketType(&modem);
     200           0 :   RADIOLIB_ASSERT(state);
     201           0 :   RadioLibTime_t timeout = getTimeOnAir(len);
     202           0 :   if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
     203             :     // calculate timeout (150% of expected time-on-air)
     204           0 :     timeout = (timeout * 3) / 2;
     205             : 
     206           0 :   } else if((modem == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) || (modem == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS)) {
     207             :     // calculate timeout (500% of expected time-on-air)
     208           0 :     timeout = timeout * 5;
     209             : 
     210             :   } else {
     211           0 :     return(RADIOLIB_ERR_UNKNOWN);
     212             :   }
     213             : 
     214             :   RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout);
     215             : 
     216             :   // start transmission
     217           0 :   state = startTransmit(data, len, addr);
     218           0 :   RADIOLIB_ASSERT(state);
     219             : 
     220             :   // wait for packet transmission or timeout
     221           0 :   RadioLibTime_t start = this->mod->hal->micros();
     222           0 :   while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
     223           0 :     this->mod->hal->yield();
     224           0 :     if(this->mod->hal->micros() - start > timeout) {
     225           0 :       finishTransmit();
     226           0 :       return(RADIOLIB_ERR_TX_TIMEOUT);
     227             :     }
     228             :   }
     229           0 :   RadioLibTime_t elapsed = this->mod->hal->micros() - start;
     230             : 
     231             :   // update data rate
     232           0 :   this->dataRateMeasured = (len*8.0f)/((float)elapsed/1000000.0f);
     233             : 
     234           0 :   return(finishTransmit());
     235             : }
     236             : 
     237           0 : int16_t LR11x0::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) {
     238             :   // set mode to standby
     239           0 :   int16_t state = standby();
     240           0 :   RADIOLIB_ASSERT(state);
     241             : 
     242             :   // calculate timeout based on the configured modem
     243           0 :   RadioLibTime_t timeoutInternal = timeout;
     244           0 :   if(!timeoutInternal) {
     245             :     // get currently active modem
     246           0 :     uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
     247           0 :     state = getPacketType(&modem);
     248           0 :     RADIOLIB_ASSERT(state);
     249           0 :     if((modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) || (modem == RADIOLIB_LR11X0_PACKET_TYPE_GFSK)) {
     250             :       // calculate timeout (500 % of expected time-one-air)
     251           0 :       size_t maxLen = len;
     252           0 :       if(len == 0) { maxLen = RADIOLIB_LR11X0_MAX_PACKET_LENGTH; }
     253           0 :       timeoutInternal = (getTimeOnAir(maxLen) * 5) / 1000;
     254             :     
     255           0 :     } else if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) {
     256             :       // this modem cannot receive
     257           0 :       return(RADIOLIB_ERR_WRONG_MODEM);
     258             : 
     259             :     } else {
     260           0 :       return(RADIOLIB_ERR_UNKNOWN);
     261             :     
     262             :     }
     263             :   }
     264             : 
     265             :   RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeoutInternal);
     266             : 
     267             :   // start reception
     268           0 :   uint32_t timeoutValue = (uint32_t)(((float)timeoutInternal * 1000.0f) / 30.52f);
     269           0 :   state = startReceive(timeoutValue);
     270           0 :   RADIOLIB_ASSERT(state);
     271             : 
     272             :   // wait for packet reception or timeout
     273           0 :   bool softTimeout = false;
     274           0 :   RadioLibTime_t start = this->mod->hal->millis();
     275           0 :   while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
     276           0 :     this->mod->hal->yield();
     277             :     // safety check, the timeout should be done by the radio
     278           0 :     if(this->mod->hal->millis() - start > timeoutInternal) {
     279           0 :       softTimeout = true;
     280           0 :       break;
     281             :     }
     282             :   }
     283             : 
     284             :   // if it was a timeout, this will return an error code
     285             :   // TODO taken from SX126x, does this really work?
     286           0 :   state = standby();
     287           0 :   if((state != RADIOLIB_ERR_NONE) && (state != RADIOLIB_ERR_SPI_CMD_TIMEOUT)) {
     288           0 :     return(state);
     289             :   }
     290             : 
     291             :   // check whether this was a timeout or not
     292           0 :   if(softTimeout || (getIrqFlags() & this->irqMap[RADIOLIB_IRQ_TIMEOUT])) {
     293           0 :     (void)finishReceive();
     294           0 :     return(RADIOLIB_ERR_RX_TIMEOUT);
     295             :   }
     296             : 
     297             :   // read the received data
     298           0 :   return(readData(data, len));
     299             : }
     300             : 
     301           0 : int16_t LR11x0::transmitDirect(uint32_t frf) {
     302             :   // set RF switch (if present)
     303           0 :   this->mod->setRfSwitchState(Module::MODE_TX);
     304             : 
     305             :   // user requested to start transmitting immediately (required for RTTY)
     306           0 :   int16_t state = RADIOLIB_ERR_NONE;
     307           0 :   if(frf != 0) {
     308           0 :     state = setRfFrequency(frf);
     309             :   }
     310           0 :   RADIOLIB_ASSERT(state);
     311             : 
     312             :   // start transmitting
     313           0 :   return(setTxCw());
     314             : }
     315             : 
     316           0 : int16_t LR11x0::receiveDirect() {
     317             :   // set RF switch (if present)
     318           0 :   this->mod->setRfSwitchState(Module::MODE_RX);
     319             : 
     320             :   // LR11x0 is unable to output received data directly
     321           0 :   return(RADIOLIB_ERR_UNKNOWN);
     322             : }
     323             : 
     324           0 : int16_t LR11x0::scanChannel() {
     325           0 :   ChannelScanConfig_t cfg = {
     326             :     .cad = {
     327             :       .symNum = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT,
     328             :       .detPeak = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT,
     329             :       .detMin = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT,
     330             :       .exitMode = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT,
     331             :       .timeout = 0,
     332             :       .irqFlags = RADIOLIB_IRQ_CAD_DEFAULT_FLAGS,
     333             :       .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK,
     334             :     },
     335             :   };
     336           0 :   return(this->scanChannel(cfg));
     337             : }
     338             : 
     339           0 : int16_t LR11x0::scanChannel(const ChannelScanConfig_t &config) {
     340             :   // set mode to CAD
     341           0 :   int state = startChannelScan(config);
     342           0 :   RADIOLIB_ASSERT(state);
     343             : 
     344             :   // wait for channel activity detected or timeout
     345           0 :   while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
     346           0 :     this->mod->hal->yield();
     347             :   }
     348             : 
     349             :   // check CAD result
     350           0 :   return(getChannelScanResult());
     351             : }
     352             : 
     353           0 : int16_t LR11x0::standby() {
     354           0 :   return(LR11x0::standby(RADIOLIB_LR11X0_STANDBY_RC));
     355             : }
     356             : 
     357           0 : int16_t LR11x0::standby(uint8_t mode, bool wakeup) {
     358             :   // set RF switch (if present)
     359           0 :   this->mod->setRfSwitchState(Module::MODE_IDLE);
     360             : 
     361           0 :   if(wakeup) {
     362             :     // send a NOP command - this pulls the NSS low to exit the sleep mode,
     363             :     // while preventing interference with possible other SPI transactions
     364           0 :     (void)this->mod->SPIwriteStream((uint16_t)RADIOLIB_LR11X0_CMD_NOP, NULL, 0, false, false);
     365             :   }
     366             : 
     367           0 :   uint8_t buff[] = { mode };
     368           0 :   return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_STANDBY, true, buff, 1));
     369             : }
     370             : 
     371           0 : int16_t LR11x0::sleep() {
     372           0 :   return(LR11x0::sleep(true, 0));
     373             : }
     374             : 
     375           0 : int16_t LR11x0::sleep(bool retainConfig, uint32_t sleepTime) {
     376             :   // set RF switch (if present)
     377           0 :   this->mod->setRfSwitchState(Module::MODE_IDLE);
     378             : 
     379             :   uint8_t buff[] = { 
     380           0 :     (uint8_t)retainConfig,
     381           0 :     (uint8_t)((sleepTime >> 24) & 0xFF), (uint8_t)((sleepTime >> 16) & 0xFF),
     382           0 :     (uint8_t)((sleepTime >> 16) & 0xFF), (uint8_t)(sleepTime & 0xFF),
     383           0 :   };
     384           0 :   if(sleepTime) {
     385           0 :     buff[0] |= RADIOLIB_LR11X0_SLEEP_WAKEUP_ENABLED;
     386             :   }
     387             : 
     388           0 :   int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_SLEEP, true, buff, sizeof(buff));
     389             : 
     390             :   // wait for the module to safely enter sleep mode
     391           0 :   this->mod->hal->delay(1);
     392             : 
     393           0 :   return(state);
     394             : }
     395             : 
     396           0 : void LR11x0::setIrqAction(void (*func)(void)) {
     397           0 :   this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptRising);
     398           0 : }
     399             : 
     400           0 : void LR11x0::clearIrqAction() {
     401           0 :   this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()));
     402           0 : }
     403             : 
     404           0 : void LR11x0::setPacketReceivedAction(void (*func)(void)) {
     405           0 :   this->setIrqAction(func);
     406           0 : }
     407             : 
     408           0 : void LR11x0::clearPacketReceivedAction() {
     409           0 :   this->clearIrqAction();
     410           0 : }
     411             : 
     412           0 : void LR11x0::setPacketSentAction(void (*func)(void)) {
     413           0 :   this->setIrqAction(func);
     414           0 : }
     415             : 
     416           0 : void LR11x0::clearPacketSentAction() {
     417           0 :   this->clearIrqAction();
     418           0 : }
     419             : 
     420           0 : int16_t LR11x0::finishTransmit() {
     421             :   // clear interrupt flags
     422           0 :   clearIrqState(RADIOLIB_LR11X0_IRQ_ALL);
     423             : 
     424             :   // set mode to standby to disable transmitter/RF switch
     425           0 :   return(standby());
     426             : }
     427             : 
     428           0 : int16_t LR11x0::startReceive() {
     429           0 :   return(this->startReceive(RADIOLIB_LR11X0_RX_TIMEOUT_INF, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0));
     430             : }
     431             : 
     432           0 : uint32_t LR11x0::getIrqStatus() {
     433             :   // there is no dedicated "get IRQ" command, the IRQ bits are sent after the status bytes
     434           0 :   uint8_t buff[6] = { 0 };
     435           0 :   this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_0;
     436           0 :   mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true);
     437           0 :   this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8;
     438           0 :   uint32_t irq = ((uint32_t)(buff[2]) << 24) | ((uint32_t)(buff[3]) << 16) | ((uint32_t)(buff[4]) << 8) | (uint32_t)buff[5];
     439           0 :   return(irq);
     440             : }
     441             : 
     442           0 : int16_t LR11x0::readData(uint8_t* data, size_t len) {
     443             :   // check active modem
     444           0 :   int16_t state = RADIOLIB_ERR_NONE;
     445           0 :   uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
     446           0 :   state = getPacketType(&modem);
     447           0 :   RADIOLIB_ASSERT(state);
     448           0 :   if((modem != RADIOLIB_LR11X0_PACKET_TYPE_LORA) && 
     449           0 :      (modem != RADIOLIB_LR11X0_PACKET_TYPE_GFSK)) {
     450           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     451             :   }
     452             : 
     453             :   // check integrity CRC
     454           0 :   uint32_t irq = getIrqStatus();
     455           0 :   int16_t crcState = RADIOLIB_ERR_NONE;
     456             :   // Report CRC mismatch when there's a payload CRC error, or a header error and no valid header (to avoid false alarm from previous packet)
     457           0 :   if((irq & RADIOLIB_LR11X0_IRQ_CRC_ERR) || ((irq & RADIOLIB_LR11X0_IRQ_HEADER_ERR) && !(irq & RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID))) {
     458           0 :     crcState = RADIOLIB_ERR_CRC_MISMATCH;
     459             :   }
     460             : 
     461             :   // get packet length
     462             :   // the offset is needed since LR11x0 seems to move the buffer base by 4 bytes on every packet
     463           0 :   uint8_t offset = 0;
     464           0 :   size_t length = getPacketLength(true, &offset);
     465           0 :   if((len != 0) && (len < length)) {
     466             :     // user requested less data than we got, only return what was requested
     467           0 :     length = len;
     468             :   }
     469             : 
     470             :   // read packet data
     471           0 :   state = readBuffer8(data, length, offset);
     472           0 :   RADIOLIB_ASSERT(state);
     473             : 
     474             :   // clear the Rx buffer
     475           0 :   state = clearRxBuffer();
     476           0 :   RADIOLIB_ASSERT(state);
     477             : 
     478             :   // clear interrupt flags
     479           0 :   state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL);
     480             : 
     481             :   // check if CRC failed - this is done after reading data to give user the option to keep them
     482           0 :   RADIOLIB_ASSERT(crcState);
     483             : 
     484           0 :   return(state);
     485             : }
     486             : 
     487           0 : int16_t LR11x0::finishReceive() {
     488             :   // set mode to standby to disable RF switch
     489           0 :   int16_t state = standby();
     490           0 :   RADIOLIB_ASSERT(state);
     491             : 
     492             :   // clear interrupt flags
     493           0 :   return(clearIrqState(RADIOLIB_LR11X0_IRQ_ALL));
     494             : }
     495             : 
     496           0 : int16_t LR11x0::startChannelScan() {
     497           0 :   ChannelScanConfig_t cfg = {
     498             :     .cad = {
     499             :       .symNum = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT,
     500             :       .detPeak = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT,
     501             :       .detMin = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT,
     502             :       .exitMode = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT,
     503             :       .timeout = 0,
     504             :       .irqFlags = RADIOLIB_IRQ_CAD_DEFAULT_FLAGS,
     505             :       .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK,
     506             :     },
     507             :   };
     508           0 :   return(this->startChannelScan(cfg));
     509             : }
     510             : 
     511           0 : int16_t LR11x0::startChannelScan(const ChannelScanConfig_t &config) {
     512             :   // check active modem
     513           0 :   int16_t state = RADIOLIB_ERR_NONE;
     514           0 :   uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
     515           0 :   state = getPacketType(&modem);
     516           0 :   RADIOLIB_ASSERT(state);
     517           0 :   if(modem != RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
     518           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     519             :   }
     520             : 
     521             :   // set mode to standby
     522           0 :   state = standby();
     523           0 :   RADIOLIB_ASSERT(state);
     524             : 
     525             :   // set RF switch (if present)
     526           0 :   this->mod->setRfSwitchState(Module::MODE_RX);
     527             : 
     528             :   // set DIO pin mapping
     529           0 :   uint16_t irqFlags = (config.cad.irqFlags == RADIOLIB_IRQ_NOT_SUPPORTED) ? RADIOLIB_LR11X0_IRQ_CAD_DETECTED | RADIOLIB_LR11X0_IRQ_CAD_DONE : config.cad.irqFlags;
     530           0 :   state = setDioIrqParams(getIrqMapped(irqFlags), getIrqMapped(irqFlags));
     531           0 :   RADIOLIB_ASSERT(state);
     532             : 
     533             :   // clear interrupt flags
     534           0 :   state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL);
     535           0 :   RADIOLIB_ASSERT(state);
     536             : 
     537             :   // set mode to CAD
     538           0 :   return(startCad(config.cad.symNum, config.cad.detPeak, config.cad.detMin, config.cad.exitMode, config.cad.timeout));
     539             : }
     540             : 
     541           0 : int16_t LR11x0::getChannelScanResult() {
     542             :   // check active modem
     543           0 :   int16_t state = RADIOLIB_ERR_NONE;
     544           0 :   uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
     545           0 :   state = getPacketType(&modem);
     546           0 :   RADIOLIB_ASSERT(state);
     547           0 :   if(modem != RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
     548           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     549             :   }
     550             : 
     551             :   // check CAD result
     552           0 :   uint32_t cadResult = getIrqStatus();
     553           0 :   if(cadResult & RADIOLIB_LR11X0_IRQ_CAD_DETECTED) {
     554             :     // detected some LoRa activity
     555           0 :     return(RADIOLIB_LORA_DETECTED);
     556           0 :   } else if(cadResult & RADIOLIB_LR11X0_IRQ_CAD_DONE) {
     557             :     // channel is free
     558           0 :     return(RADIOLIB_CHANNEL_FREE);
     559             :   }
     560             : 
     561           0 :   return(RADIOLIB_ERR_UNKNOWN);
     562             : }
     563             : 
     564           0 : int16_t LR11x0::setBandwidth(float bw, bool high) {
     565             :   // check active modem
     566           0 :   uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
     567           0 :   int16_t state = getPacketType(&type);
     568           0 :   RADIOLIB_ASSERT(state);
     569           0 :   if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
     570           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     571             :   }
     572             : 
     573             :   // ensure byte conversion doesn't overflow
     574           0 :   if (high) {
     575           0 :     RADIOLIB_CHECK_RANGE(bw, 203.125f, 815.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
     576             : 
     577           0 :     if(fabsf(bw - 203.125f) <= 0.001f) {
     578           0 :       this->bandwidth = RADIOLIB_LR11X0_LORA_BW_203_125;
     579           0 :     } else if(fabsf(bw - 406.25f) <= 0.001f) {
     580           0 :       this->bandwidth = RADIOLIB_LR11X0_LORA_BW_406_25;
     581           0 :     } else if(fabsf(bw - 812.5f) <= 0.001f) {
     582           0 :       this->bandwidth = RADIOLIB_LR11X0_LORA_BW_812_50;
     583             :     } else {
     584           0 :       return(RADIOLIB_ERR_INVALID_BANDWIDTH);
     585             :     }
     586             :   } else {
     587           0 :     RADIOLIB_CHECK_RANGE(bw, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
     588             :     
     589             :     // check allowed bandwidth values
     590           0 :     uint8_t bw_div2 = bw / 2 + 0.01f;
     591           0 :     switch (bw_div2)  {
     592           0 :       case 31: // 62.5:
     593           0 :         this->bandwidth = RADIOLIB_LR11X0_LORA_BW_62_5;
     594           0 :         break;
     595           0 :       case 62: // 125.0:
     596           0 :         this->bandwidth = RADIOLIB_LR11X0_LORA_BW_125_0;
     597           0 :         break;
     598           0 :       case 125: // 250.0
     599           0 :         this->bandwidth = RADIOLIB_LR11X0_LORA_BW_250_0;
     600           0 :         break;
     601           0 :       case 250: // 500.0
     602           0 :         this->bandwidth = RADIOLIB_LR11X0_LORA_BW_500_0;
     603           0 :         break;
     604           0 :       default:
     605           0 :         return(RADIOLIB_ERR_INVALID_BANDWIDTH);
     606             :     }
     607             :   }
     608             : 
     609             :   // update modulation parameters
     610           0 :   this->bandwidthKhz = bw;
     611           0 :   return(setModulationParamsLoRa(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
     612             : }
     613             : 
     614           0 : int16_t LR11x0::setSpreadingFactor(uint8_t sf, bool legacy) {
     615             :   // check active modem
     616           0 :   uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
     617           0 :   int16_t state = getPacketType(&type);
     618           0 :   RADIOLIB_ASSERT(state);
     619           0 :   if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
     620           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     621             :   }
     622             : 
     623           0 :   RADIOLIB_CHECK_RANGE(sf, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
     624             : 
     625             :   // TODO enable SF6 legacy mode
     626             :   if(legacy && (sf == 6)) {
     627             :     //this->mod->SPIsetRegValue(RADIOLIB_LR11X0_REG_SF6_SX127X_COMPAT, RADIOLIB_LR11X0_SF6_SX127X, 18, 18);
     628             :   }
     629             : 
     630             :   // update modulation parameters
     631           0 :   this->spreadingFactor = sf;
     632           0 :   return(setModulationParamsLoRa(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
     633             : }
     634             : 
     635           0 : int16_t LR11x0::setCodingRate(uint8_t cr, bool longInterleave) {
     636             :   // check active modem
     637           0 :   uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
     638           0 :   int16_t state = getPacketType(&type);
     639           0 :   RADIOLIB_ASSERT(state);
     640           0 :   if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
     641           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     642             :   }
     643             : 
     644           0 :   RADIOLIB_CHECK_RANGE(cr, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
     645             : 
     646           0 :   if(longInterleave) {
     647           0 :     switch(cr) {
     648           0 :       case 4:
     649           0 :         this->codingRate = 0;
     650           0 :         break;
     651           0 :       case 5:
     652             :       case 6:
     653           0 :         this->codingRate = cr;
     654           0 :         break;
     655           0 :       case 8: 
     656           0 :         this->codingRate = cr - 1;
     657           0 :         break;
     658           0 :       default:
     659           0 :         return(RADIOLIB_ERR_INVALID_CODING_RATE);
     660             :     }
     661             :   
     662             :   } else {
     663           0 :     this->codingRate = cr - 4;
     664             :   
     665             :   }
     666             : 
     667             :   // update modulation parameters
     668           0 :   return(setModulationParamsLoRa(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
     669             : }
     670             : 
     671           0 : int16_t LR11x0::setSyncWord(uint8_t syncWord) {
     672             :   // check active modem
     673           0 :   uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
     674           0 :   int16_t state = getPacketType(&type);
     675           0 :   RADIOLIB_ASSERT(state);
     676           0 :   if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
     677           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     678             :   }
     679             :   
     680           0 :   return(setLoRaSyncWord(syncWord));
     681             : }
     682             : 
     683           0 : int16_t LR11x0::setBitRate(float br) {
     684           0 :   RADIOLIB_CHECK_RANGE(br, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
     685             : 
     686             :   // check active modem
     687           0 :   uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
     688           0 :   int16_t state = getPacketType(&type);
     689           0 :   RADIOLIB_ASSERT(state);
     690           0 :   if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
     691           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     692             :   }
     693             : 
     694             :   // set bit rate value
     695             :   // TODO implement fractional bit rate configuration
     696           0 :   this->bitRate = br * 1000.0f;
     697           0 :   state = setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev);
     698           0 :   RADIOLIB_ASSERT(state);
     699             : 
     700             :   // apply workaround
     701           0 :   return(workaroundGFSK());
     702             : }
     703             : 
     704           0 : int16_t LR11x0::setFrequencyDeviation(float freqDev) {
     705             :   // check active modem
     706           0 :   uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
     707           0 :   int16_t state = getPacketType(&type);
     708           0 :   RADIOLIB_ASSERT(state);
     709           0 :   if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
     710           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     711             :   }
     712             : 
     713             :   // set frequency deviation to lowest available setting (required for digimodes)
     714           0 :   float newFreqDev = freqDev;
     715           0 :   if(freqDev < 0.0f) {
     716           0 :     newFreqDev = 0.6f;
     717             :   }
     718             : 
     719           0 :   RADIOLIB_CHECK_RANGE(newFreqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
     720           0 :   this->frequencyDev = newFreqDev * 1000.0f;
     721           0 :   state = setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev);
     722           0 :   RADIOLIB_ASSERT(state);
     723             : 
     724             :   // apply workaround
     725           0 :   return(workaroundGFSK());
     726             : }
     727             : 
     728           0 : int16_t LR11x0::setRxBandwidth(float rxBw) {
     729             :   // check active modem
     730           0 :   uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
     731           0 :   int16_t state = getPacketType(&type);
     732           0 :   RADIOLIB_ASSERT(state);
     733           0 :   if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
     734           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     735             :   }
     736             : 
     737             :   // check modulation parameters
     738             :   /*if(2 * this->frequencyDev + this->bitRate > rxBw * 1000.0) {
     739             :     return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS);
     740             :   }*/
     741             : 
     742             :   // check allowed receiver bandwidth values
     743           0 :   if(fabsf(rxBw - 4.8f) <= 0.001f) {
     744           0 :     this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_4_8;
     745           0 :   } else if(fabsf(rxBw - 5.8f) <= 0.001f) {
     746           0 :     this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_5_8;
     747           0 :   } else if(fabsf(rxBw - 7.3f) <= 0.001f) {
     748           0 :     this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_7_3;
     749           0 :   } else if(fabsf(rxBw - 9.7f) <= 0.001f) {
     750           0 :     this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_9_7;
     751           0 :   } else if(fabsf(rxBw - 11.7f) <= 0.001f) {
     752           0 :     this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_11_7;
     753           0 :   } else if(fabsf(rxBw - 14.6f) <= 0.001f) {
     754           0 :     this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_14_6;
     755           0 :   } else if(fabsf(rxBw - 19.5f) <= 0.001f) {
     756           0 :     this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_19_5;
     757           0 :   } else if(fabsf(rxBw - 23.4f) <= 0.001f) {
     758           0 :     this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_23_4;
     759           0 :   } else if(fabsf(rxBw - 29.3f) <= 0.001f) {
     760           0 :     this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_29_3;
     761           0 :   } else if(fabsf(rxBw - 39.0f) <= 0.001f) {
     762           0 :     this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_39_0;
     763           0 :   } else if(fabsf(rxBw - 46.9f) <= 0.001f) {
     764           0 :     this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_46_9;
     765           0 :   } else if(fabsf(rxBw - 58.6f) <= 0.001f) {
     766           0 :     this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_58_6;
     767           0 :   } else if(fabsf(rxBw - 78.2f) <= 0.001f) {
     768           0 :     this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_78_2;
     769           0 :   } else if(fabsf(rxBw - 93.8f) <= 0.001f) {
     770           0 :     this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_93_8;
     771           0 :   } else if(fabsf(rxBw - 117.3f) <= 0.001f) {
     772           0 :     this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_117_3;
     773           0 :   } else if(fabsf(rxBw - 156.2f) <= 0.001f) {
     774           0 :     this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_156_2;
     775           0 :   } else if(fabsf(rxBw - 187.2f) <= 0.001f) {
     776           0 :     this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_187_2;
     777           0 :   } else if(fabsf(rxBw - 234.3f) <= 0.001f) {
     778           0 :     this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_234_3;
     779           0 :   } else if(fabsf(rxBw - 312.0f) <= 0.001f) {
     780           0 :     this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_312_0;
     781           0 :   } else if(fabsf(rxBw - 373.6f) <= 0.001f) {
     782           0 :     this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_373_6;
     783           0 :   } else if(fabsf(rxBw - 467.0f) <= 0.001f) {
     784           0 :     this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_467_0;
     785             :   } else {
     786           0 :     return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH);
     787             :   }
     788             : 
     789             :   // update modulation parameters
     790           0 :   state = setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev);
     791           0 :   RADIOLIB_ASSERT(state);
     792             : 
     793             :   // apply workaround
     794           0 :   return(workaroundGFSK());
     795             : }
     796             : 
     797           0 : int16_t LR11x0::setSyncWord(uint8_t* syncWord, size_t len) {
     798           0 :   if((!syncWord) || (!len) || (len > RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN)) {
     799           0 :     return(RADIOLIB_ERR_INVALID_SYNC_WORD);
     800             :   }
     801             : 
     802             :   // check active modem
     803           0 :   uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
     804           0 :   int16_t state = getPacketType(&type);
     805           0 :   RADIOLIB_ASSERT(state);
     806           0 :   if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
     807             :     // update sync word length
     808           0 :     this->syncWordLength = len*8;
     809           0 :     state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
     810           0 :     RADIOLIB_ASSERT(state);
     811             : 
     812             :     // sync word is passed most-significant byte first
     813           0 :     uint8_t fullSyncWord[RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN] = { 0 };
     814           0 :     memcpy(fullSyncWord, syncWord, len);
     815           0 :     return(setGfskSyncWord(fullSyncWord));
     816             : 
     817           0 :   } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
     818             :     // with length set to 1 and LoRa modem active, assume it is the LoRa sync word
     819           0 :     if(len > 1) {
     820           0 :       return(RADIOLIB_ERR_INVALID_SYNC_WORD);
     821             :     }
     822           0 :     return(setSyncWord(syncWord[0]));
     823             : 
     824           0 :   } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) {
     825             :     // with length set to 4 and LR-FHSS modem active, assume it is the LR-FHSS sync word
     826           0 :     if(len != sizeof(uint32_t)) {
     827           0 :       return(RADIOLIB_ERR_INVALID_SYNC_WORD);
     828             :     }
     829           0 :     uint32_t sync = 0;
     830           0 :     memcpy(&sync, syncWord, sizeof(uint32_t));
     831           0 :     return(lrFhssSetSyncWord(sync));
     832             :   
     833             :   }
     834             : 
     835           0 :   return(RADIOLIB_ERR_WRONG_MODEM);
     836             : }
     837             : 
     838           0 : int16_t LR11x0::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) {
     839           0 :   if((!syncWord) || (!bitsLen) || (bitsLen > 8*RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN)) {
     840           0 :     return(RADIOLIB_ERR_INVALID_SYNC_WORD);
     841             :   }
     842             : 
     843             :   // check active modem
     844           0 :   uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
     845           0 :   int16_t state = getPacketType(&type);
     846           0 :   RADIOLIB_ASSERT(state);
     847           0 :   if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
     848           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     849             :   }
     850             : 
     851           0 :   uint8_t bytesLen = bitsLen / 8;
     852           0 :   if ((bitsLen % 8) != 0) {
     853           0 :     bytesLen++;
     854             :   }
     855             : 
     856           0 :   return(setSyncWord(syncWord, bytesLen));
     857             : }
     858             : 
     859           0 : int16_t LR11x0::setNodeAddress(uint8_t nodeAddr) {
     860             :   // check active modem
     861           0 :   uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
     862           0 :   int16_t state = getPacketType(&type);
     863           0 :   RADIOLIB_ASSERT(state);
     864           0 :   if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
     865           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     866             :   }
     867             : 
     868             :   // enable address filtering (node only)
     869           0 :   this->addrComp = RADIOLIB_LR11X0_GFSK_ADDR_FILTER_NODE;
     870           0 :   state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
     871           0 :   RADIOLIB_ASSERT(state);
     872             :   
     873             :   // set node address
     874           0 :   this->node = nodeAddr;
     875           0 :   return(setPacketAdrs(this->node, 0));
     876             : }
     877             : 
     878           0 : int16_t LR11x0::setBroadcastAddress(uint8_t broadAddr) {
     879             :   // check active modem
     880           0 :   uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
     881           0 :   int16_t state = getPacketType(&type);
     882           0 :   RADIOLIB_ASSERT(state);
     883           0 :   if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
     884           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     885             :   }
     886             : 
     887             :   // enable address filtering (node and broadcast)
     888           0 :   this->addrComp = RADIOLIB_LR11X0_GFSK_ADDR_FILTER_NODE_BROADCAST;
     889           0 :   state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
     890           0 :   RADIOLIB_ASSERT(state);
     891             :   
     892             :   // set node and broadcast address
     893           0 :   return(setPacketAdrs(this->node, broadAddr));
     894             : }
     895             : 
     896           0 : int16_t LR11x0::disableAddressFiltering() {
     897             :   // check active modem
     898           0 :   uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
     899           0 :   int16_t state = getPacketType(&type);
     900           0 :   RADIOLIB_ASSERT(state);
     901           0 :   if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
     902           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     903             :   }
     904             : 
     905             :   // disable address filterin
     906           0 :   this->addrComp = RADIOLIB_LR11X0_GFSK_ADDR_FILTER_DISABLED;
     907           0 :   return(setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
     908             : }
     909             : 
     910           0 : int16_t LR11x0::setDataShaping(uint8_t sh) {
     911             :   // check active modem
     912           0 :   uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
     913           0 :   int16_t state = getPacketType(&type);
     914           0 :   RADIOLIB_ASSERT(state);
     915           0 :   if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
     916           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     917             :   }
     918             : 
     919             :   // set data shaping
     920           0 :   switch(sh) {
     921           0 :     case RADIOLIB_SHAPING_NONE:
     922           0 :       this->pulseShape = RADIOLIB_LR11X0_GFSK_SHAPING_NONE;
     923           0 :       break;
     924           0 :     case RADIOLIB_SHAPING_0_3:
     925           0 :       this->pulseShape = RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_0_3;
     926           0 :       break;
     927           0 :     case RADIOLIB_SHAPING_0_5:
     928           0 :       this->pulseShape = RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_0_5;
     929           0 :       break;
     930           0 :     case RADIOLIB_SHAPING_0_7:
     931           0 :       this->pulseShape = RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_0_7;
     932           0 :       break;
     933           0 :     case RADIOLIB_SHAPING_1_0:
     934           0 :       this->pulseShape = RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_1_0;
     935           0 :       break;
     936           0 :     default:
     937           0 :       return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
     938             :   }
     939             : 
     940             :   // update modulation parameters
     941           0 :   return(setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
     942             : }
     943             : 
     944           0 : int16_t LR11x0::setEncoding(uint8_t encoding) {
     945           0 :   return(setWhitening(encoding));
     946             : }
     947             : 
     948           0 : int16_t LR11x0::fixedPacketLengthMode(uint8_t len) {
     949           0 :   return(setPacketMode(RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_FIXED, len));
     950             : }
     951             : 
     952           0 : int16_t LR11x0::variablePacketLengthMode(uint8_t maxLen) {
     953           0 :   return(setPacketMode(RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_VARIABLE, maxLen));
     954             : }
     955             : 
     956           0 : int16_t LR11x0::setWhitening(bool enabled, uint16_t initial) {
     957             :   // check active modem
     958           0 :   uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
     959           0 :   int16_t state = getPacketType(&type);
     960           0 :   RADIOLIB_ASSERT(state);
     961           0 :   if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
     962           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     963             :   }
     964             : 
     965           0 :   if(!enabled) {
     966             :     // disable whitening
     967           0 :     this->whitening = RADIOLIB_LR11X0_GFSK_WHITENING_DISABLED;
     968             : 
     969             :   } else {
     970             :     // enable whitening
     971           0 :     this->whitening = RADIOLIB_LR11X0_GFSK_WHITENING_ENABLED;
     972             : 
     973             :     // write initial whitening value
     974           0 :     state = setGfskWhitParams(initial);
     975           0 :     RADIOLIB_ASSERT(state);
     976             :   }
     977             : 
     978           0 :   return(setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
     979             : }
     980             : 
     981           0 : int16_t LR11x0::setDataRate(DataRate_t dr, ModemType_t modem) {
     982             :   // get the current modem
     983             :   ModemType_t currentModem;
     984           0 :   int16_t state = this->getModem(&currentModem);
     985           0 :   RADIOLIB_ASSERT(state);
     986             : 
     987             :   // switch over if the requested modem is different
     988           0 :   if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) {
     989           0 :     state = this->standby();
     990           0 :     RADIOLIB_ASSERT(state);
     991           0 :     state = this->setModem(modem);
     992           0 :     RADIOLIB_ASSERT(state);
     993             :   }
     994             :   
     995           0 :   if(modem == RADIOLIB_MODEM_NONE) {
     996           0 :     modem = currentModem;
     997             :   }
     998             : 
     999             :   // select interpretation based on modem
    1000           0 :   if(modem == RADIOLIB_MODEM_FSK) {
    1001             :     // set the bit rate
    1002           0 :     state = this->setBitRate(dr.fsk.bitRate);
    1003           0 :     RADIOLIB_ASSERT(state);
    1004             : 
    1005             :     // set the frequency deviation
    1006           0 :     state = this->setFrequencyDeviation(dr.fsk.freqDev);
    1007             : 
    1008           0 :   } else if(modem == RADIOLIB_MODEM_LORA) {
    1009             :     // set the spreading factor
    1010           0 :     state = this->setSpreadingFactor(dr.lora.spreadingFactor);
    1011           0 :     RADIOLIB_ASSERT(state);
    1012             : 
    1013             :     // set the bandwidth
    1014           0 :     state = this->setBandwidth(dr.lora.bandwidth);
    1015           0 :     RADIOLIB_ASSERT(state);
    1016             : 
    1017             :     // set the coding rate
    1018           0 :     state = this->setCodingRate(dr.lora.codingRate);
    1019             :   
    1020           0 :   } else if(modem == RADIOLIB_MODEM_LRFHSS) {
    1021             :     // set the basic config
    1022           0 :     state = this->setLrFhssConfig(dr.lrFhss.bw, dr.lrFhss.cr);
    1023           0 :     RADIOLIB_ASSERT(state);
    1024             : 
    1025             :     // set hopping grid
    1026           0 :     this->lrFhssGrid = dr.lrFhss.narrowGrid ? RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_FCC;
    1027             :   
    1028             :   }
    1029             : 
    1030           0 :   return(state);
    1031             : }
    1032             : 
    1033           0 : int16_t LR11x0::checkDataRate(DataRate_t dr, ModemType_t modem) {
    1034           0 :   int16_t state = RADIOLIB_ERR_UNKNOWN;
    1035             : 
    1036             :   // retrieve modem if not supplied
    1037           0 :   if(modem == RADIOLIB_MODEM_NONE) {
    1038           0 :     state = this->getModem(&modem);
    1039           0 :     RADIOLIB_ASSERT(state);
    1040             :   }
    1041             : 
    1042             :   // select interpretation based on modem
    1043           0 :   if(modem == RADIOLIB_MODEM_FSK) {
    1044           0 :     RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
    1045           0 :     RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
    1046           0 :     return(RADIOLIB_ERR_NONE);
    1047             : 
    1048           0 :   } else if(modem == RADIOLIB_MODEM_LORA) {
    1049           0 :     RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
    1050           0 :     RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
    1051           0 :     RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
    1052           0 :     return(RADIOLIB_ERR_NONE);
    1053             :   
    1054             :   }
    1055             : 
    1056           0 :   return(state);
    1057             : }
    1058             : 
    1059           0 : int16_t LR11x0::setPreambleLength(size_t preambleLength) {
    1060             :   // check active modem
    1061           0 :   uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
    1062           0 :   int16_t state = getPacketType(&type);
    1063           0 :   RADIOLIB_ASSERT(state);
    1064           0 :   if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
    1065           0 :     this->preambleLengthLoRa = preambleLength;
    1066           0 :     return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType,  this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled));
    1067           0 :   } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
    1068           0 :     this->preambleLengthGFSK = preambleLength;
    1069           0 :     this->preambleDetLength = preambleLength >= 32 ? RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_32_BITS :
    1070             :                               preambleLength >= 24 ? RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_24_BITS :
    1071             :                               preambleLength >= 16 ? RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_16_BITS :
    1072             :                               preambleLength >   0 ? RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_8_BITS :
    1073             :                               RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_DISABLED;
    1074           0 :     return(setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
    1075             :   }
    1076             : 
    1077           0 :   return(RADIOLIB_ERR_WRONG_MODEM);
    1078             : }
    1079             : 
    1080           0 : int16_t LR11x0::setTCXO(float voltage, uint32_t delay) {
    1081             :   // check if TCXO is enabled at all
    1082           0 :   if(this->XTAL) {
    1083           0 :     return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE);
    1084             :   }
    1085             : 
    1086             :   // set mode to standby
    1087           0 :   standby();
    1088             : 
    1089             :   // check RADIOLIB_LR11X0_ERROR_STAT_HF_XOSC_START_ERR flag and clear it
    1090           0 :   uint16_t errors = 0;
    1091           0 :   int16_t state = getErrors(&errors);
    1092           0 :   RADIOLIB_ASSERT(state);
    1093           0 :   if(errors & RADIOLIB_LR11X0_ERROR_STAT_HF_XOSC_START_ERR) {
    1094           0 :     clearErrors();
    1095             :   }
    1096             : 
    1097             :   // check 0 V disable
    1098           0 :   if(fabsf(voltage - 0.0f) <= 0.001f) {
    1099           0 :     setTcxoMode(0, 0);
    1100           0 :     return(reset());
    1101             :   }
    1102             : 
    1103             :   // check allowed voltage values
    1104           0 :   uint8_t tune = 0;
    1105           0 :   if(fabsf(voltage - 1.6f) <= 0.001f) {
    1106           0 :     tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_1_6;
    1107           0 :   } else if(fabsf(voltage - 1.7f) <= 0.001f) {
    1108           0 :     tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_1_7;
    1109           0 :   } else if(fabsf(voltage - 1.8f) <= 0.001f) {
    1110           0 :     tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_1_8;
    1111           0 :   } else if(fabsf(voltage - 2.2f) <= 0.001f) {
    1112           0 :     tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_2_2;
    1113           0 :   } else if(fabsf(voltage - 2.4f) <= 0.001f) {
    1114           0 :     tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_2_4;
    1115           0 :   } else if(fabsf(voltage - 2.7f) <= 0.001f) {
    1116           0 :     tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_2_7;
    1117           0 :   } else if(fabsf(voltage - 3.0f) <= 0.001f) {
    1118           0 :     tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_3_0;
    1119           0 :   } else if(fabsf(voltage - 3.3f) <= 0.001f) {
    1120           0 :     tune = RADIOLIB_LR11X0_TCXO_VOLTAGE_3_3;
    1121             :   } else {
    1122           0 :     return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE);
    1123             :   }
    1124             : 
    1125             :   // calculate delay value
    1126           0 :   uint32_t delayValue = (uint32_t)((float)delay / 30.52f);
    1127           0 :   if(delayValue == 0) {
    1128           0 :     delayValue = 1;
    1129             :   }
    1130             :  
    1131             :   // enable TCXO control
    1132           0 :   return(setTcxoMode(tune, delayValue));
    1133             : }
    1134             : 
    1135           0 : int16_t LR11x0::setCRC(uint8_t len, uint32_t initial, uint32_t polynomial, bool inverted) {
    1136             :   // check active modem
    1137           0 :   uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
    1138           0 :   int16_t state = getPacketType(&type);
    1139           0 :   RADIOLIB_ASSERT(state);
    1140           0 :   if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
    1141             :     // LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion
    1142           0 :     this->crcTypeLoRa = len > 0 ? RADIOLIB_LR11X0_LORA_CRC_ENABLED : RADIOLIB_LR11X0_LORA_CRC_DISABLED;
    1143           0 :     state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled);
    1144             :   
    1145           0 :   } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
    1146             :     // update packet parameters
    1147           0 :     switch(len) {
    1148           0 :       case 0:
    1149           0 :         this->crcTypeGFSK = RADIOLIB_LR11X0_GFSK_CRC_DISABLED;
    1150           0 :         break;
    1151           0 :       case 1:
    1152           0 :         if(inverted) {
    1153           0 :           this->crcTypeGFSK = RADIOLIB_LR11X0_GFSK_CRC_1_BYTE_INV;
    1154             :         } else {
    1155           0 :           this->crcTypeGFSK = RADIOLIB_LR11X0_GFSK_CRC_1_BYTE;
    1156             :         }
    1157           0 :         break;
    1158           0 :       case 2:
    1159           0 :         if(inverted) {
    1160           0 :           this->crcTypeGFSK = RADIOLIB_LR11X0_GFSK_CRC_2_BYTE_INV;
    1161             :         } else {
    1162           0 :           this->crcTypeGFSK = RADIOLIB_LR11X0_GFSK_CRC_2_BYTE;
    1163             :         }
    1164           0 :         break;
    1165           0 :       default:
    1166           0 :         return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
    1167             :     }
    1168             : 
    1169           0 :     state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
    1170           0 :     RADIOLIB_ASSERT(state);
    1171             : 
    1172           0 :     state = setGfskCrcParams(initial, polynomial);
    1173             :   
    1174             :   }
    1175             : 
    1176           0 :   return(state);
    1177             : }
    1178             : 
    1179           0 : int16_t LR11x0::invertIQ(bool enable) {
    1180             :   // check active modem
    1181           0 :   uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
    1182           0 :   int16_t state = getPacketType(&type);
    1183           0 :   RADIOLIB_ASSERT(state);
    1184           0 :   if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
    1185           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1186             :   }
    1187             : 
    1188           0 :   this->invertIQEnabled = enable;
    1189           0 :   return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled));
    1190             : }
    1191             : 
    1192           0 : float LR11x0::getRSSI() {
    1193           0 :   float val = 0;
    1194             : 
    1195             :   // check active modem
    1196           0 :   uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
    1197           0 :   (void)getPacketType(&type);
    1198           0 :   if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
    1199           0 :     (void)getPacketStatusLoRa(&val, NULL, NULL);
    1200             : 
    1201           0 :   } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
    1202           0 :     (void)getPacketStatusGFSK(NULL, &val, NULL, NULL);
    1203             :   
    1204             :   }
    1205             : 
    1206           0 :   return(val);
    1207             : }
    1208             : 
    1209           0 : float LR11x0::getSNR() {
    1210           0 :   float val = 0;
    1211             : 
    1212             :   // check active modem
    1213           0 :   uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
    1214           0 :   (void)getPacketType(&type);
    1215           0 :   if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
    1216           0 :     (void)getPacketStatusLoRa(NULL, &val, NULL);
    1217             :   }
    1218             : 
    1219           0 :   return(val);
    1220             : }
    1221             : 
    1222           0 : float LR11x0::getFrequencyError() {
    1223             :   // TODO implement this
    1224           0 :   return(0);
    1225             : }
    1226             : 
    1227           0 : size_t LR11x0::getPacketLength(bool update) {
    1228           0 :   return(this->getPacketLength(update, NULL));
    1229             : }
    1230             : 
    1231           0 : size_t LR11x0::getPacketLength(bool update, uint8_t* offset) {
    1232             :   (void)update;
    1233             : 
    1234             :   // in implicit mode, return the cached value
    1235           0 :   uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
    1236           0 :   (void)getPacketType(&type);
    1237           0 :   if((type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) && (this->headerType == RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT)) {
    1238           0 :     return(this->implicitLen);
    1239             :   }
    1240             : 
    1241           0 :   uint8_t len = 0;
    1242           0 :   (void)getRxBufferStatus(&len, offset);
    1243           0 :   return((size_t)len);
    1244             : }
    1245             : 
    1246          13 : RadioLibTime_t LR11x0::calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) {
    1247             :   // check active modem
    1248          13 :   if (modem == ModemType_t::RADIOLIB_MODEM_LORA) {  
    1249           6 :     uint32_t symbolLength_us = ((uint32_t)(1000 * 10) << dr.lora.spreadingFactor) / (dr.lora.bandwidth * 10) ;
    1250           6 :     uint8_t sfCoeff1_x4 = 17; // (4.25 * 4)
    1251           6 :     uint8_t sfCoeff2 = 8;
    1252           6 :     if(dr.lora.spreadingFactor == 5 || dr.lora.spreadingFactor == 6) {
    1253           0 :       sfCoeff1_x4 = 25; // 6.25 * 4
    1254           0 :       sfCoeff2 = 0;
    1255             :     }
    1256           6 :     uint8_t sfDivisor = 4*dr.lora.spreadingFactor;
    1257           6 :     if(pc.lora.ldrOptimize) {
    1258           3 :       sfDivisor = 4*(dr.lora.spreadingFactor - 2);
    1259             :     }
    1260           6 :     const int8_t bitsPerCrc = 16;
    1261           6 :     const int8_t N_symbol_header = pc.lora.implicitHeader ? 0 : 20;
    1262             : 
    1263             :     // numerator of equation in section 6.1.4 of SX1268 datasheet v1.1 (might not actually be bitcount, but it has len * 8)
    1264           6 :     int16_t bitCount = (int16_t) 8 * len + pc.lora.crcEnabled * bitsPerCrc - 4 * dr.lora.spreadingFactor  + sfCoeff2 + N_symbol_header;
    1265           6 :     if(bitCount < 0) {
    1266           0 :       bitCount = 0;
    1267             :     }
    1268             :     // add (sfDivisor) - 1 to the numerator to give integer CEIL(...)
    1269           6 :     uint16_t nPreCodedSymbols = (bitCount + (sfDivisor - 1)) / (sfDivisor);
    1270             : 
    1271             :     // preamble can be 65k, therefore nSymbol_x4 needs to be 32 bit
    1272           6 :     uint32_t nSymbol_x4 = (pc.lora.preambleLength + 8) * 4 + sfCoeff1_x4 + nPreCodedSymbols * dr.lora.codingRate * 4;
    1273             : 
    1274             :     // get time-on-air in us
    1275           6 :     return((symbolLength_us * nSymbol_x4) / 4);
    1276             : 
    1277           7 :   } else if(modem == ModemType_t::RADIOLIB_MODEM_FSK) {
    1278           4 :     return((((float)(pc.fsk.crcLength * 8) + pc.fsk.syncWordLength + pc.fsk.preambleLength + (uint32_t)len * 8) / (dr.fsk.bitRate / 1000.0f)));
    1279             : 
    1280           3 :   } else if(modem == ModemType_t::RADIOLIB_MODEM_LRFHSS) {
    1281             :     // calculate the number of bits based on coding rate
    1282             :     uint16_t N_bits;
    1283           3 :     switch(dr.lrFhss.cr) {
    1284           0 :       case RADIOLIB_LR11X0_LR_FHSS_CR_5_6:
    1285           0 :         N_bits = ((len * 6) + 4) / 5; // this is from the official LR11xx driver, but why the extra +4?
    1286           0 :         break;
    1287           0 :       case RADIOLIB_LR11X0_LR_FHSS_CR_2_3:
    1288           0 :         N_bits = (len * 3) / 2;
    1289           0 :         break;
    1290           0 :       case RADIOLIB_LR11X0_LR_FHSS_CR_1_2:
    1291           0 :         N_bits = len * 2;
    1292           0 :         break;
    1293           3 :       case RADIOLIB_LR11X0_LR_FHSS_CR_1_3:
    1294           3 :         N_bits = len * 3;
    1295           3 :         break;
    1296           0 :       default:
    1297           0 :         return(RADIOLIB_ERR_INVALID_CODING_RATE);
    1298             :     }
    1299             : 
    1300             :     // calculate number of bits when accounting for unaligned last block
    1301           3 :     uint16_t N_payBits = (N_bits / RADIOLIB_LR11X0_LR_FHSS_FRAG_BITS) * RADIOLIB_LR11X0_LR_FHSS_BLOCK_BITS;
    1302           3 :     uint16_t N_lastBlockBits = N_bits % RADIOLIB_LR11X0_LR_FHSS_FRAG_BITS;
    1303           3 :     if(N_lastBlockBits) {
    1304           3 :       N_payBits += N_lastBlockBits + 2;
    1305             :     }
    1306             : 
    1307             :     // add header bits
    1308           3 :     uint16_t N_totalBits = (RADIOLIB_LR11X0_LR_FHSS_HEADER_BITS * pc.lrFhss.hdrCount) + N_payBits;
    1309           3 :     return(((uint32_t)N_totalBits * 8 * 1000000UL) / RADIOLIB_LR11X0_LR_FHSS_BIT_RATE);
    1310             :   
    1311             :   } else {
    1312           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1313             :   }
    1314             : 
    1315             :   return(0);
    1316             : }
    1317             : 
    1318           0 : RadioLibTime_t LR11x0::getTimeOnAir(size_t len) {
    1319             :   ModemType_t modem;
    1320           0 :   int32_t state = this->getModem(&modem);
    1321           0 :   RADIOLIB_ASSERT(state);
    1322             : 
    1323           0 :   DataRate_t dr = {};
    1324           0 :   PacketConfig_t pc = {};
    1325           0 :   switch(modem) {
    1326           0 :     case ModemType_t::RADIOLIB_MODEM_LORA: {
    1327           0 :       uint8_t cr = this->codingRate;
    1328             :       // We assume same calculation for short and long interleaving, so map CR values 0-4 and 5-7 to the same values
    1329           0 :       if (cr < 5) {
    1330           0 :         cr = cr + 4;
    1331           0 :       } else if (cr == 7) {
    1332           0 :         cr = cr + 1;
    1333             :       }
    1334             : 
    1335           0 :       dr.lora.spreadingFactor = this->spreadingFactor;
    1336           0 :       dr.lora.bandwidth = this->bandwidthKhz;
    1337           0 :       dr.lora.codingRate = cr;
    1338             : 
    1339           0 :       pc.lora.preambleLength = this->preambleLengthLoRa;
    1340           0 :       pc.lora.implicitHeader = (this->headerType == RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT) ? true : false;
    1341           0 :       pc.lora.crcEnabled = (this->crcTypeLoRa == RADIOLIB_LR11X0_LORA_CRC_ENABLED) ? true : false;
    1342           0 :       pc.lora.ldrOptimize = (bool)this->ldrOptimize;
    1343           0 :       break;
    1344             :     }
    1345           0 :     case ModemType_t::RADIOLIB_MODEM_FSK: {
    1346           0 :       dr.fsk.bitRate = (float)this->bitRate / 1000.0f;
    1347           0 :       dr.fsk.freqDev = (float)this->frequencyDev;
    1348             : 
    1349           0 :       uint8_t crcLen = 0;
    1350           0 :       if(this->crcTypeGFSK == RADIOLIB_LR11X0_GFSK_CRC_1_BYTE || this->crcTypeGFSK == RADIOLIB_LR11X0_GFSK_CRC_1_BYTE_INV) {
    1351           0 :         crcLen = 1;
    1352           0 :       } else if(this->crcTypeGFSK == RADIOLIB_LR11X0_GFSK_CRC_2_BYTE || this->crcTypeGFSK == RADIOLIB_LR11X0_GFSK_CRC_2_BYTE_INV) {
    1353           0 :         crcLen = 2;
    1354             :       }
    1355             :       
    1356           0 :       pc.fsk.preambleLength = this->preambleLengthGFSK;
    1357           0 :       pc.fsk.syncWordLength = this->syncWordLength; 
    1358           0 :       pc.fsk.crcLength = crcLen;
    1359           0 :       break;
    1360             :     }
    1361           0 :     case ModemType_t::RADIOLIB_MODEM_LRFHSS: {
    1362           0 :       dr.lrFhss.bw = this->lrFhssBw;
    1363           0 :       dr.lrFhss.cr = this->lrFhssCr;
    1364           0 :       dr.lrFhss.narrowGrid = (this->lrFhssGrid == RADIOLIB_LR11X0_LR_FHSS_GRID_STEP_NON_FCC) ? true : false;
    1365             : 
    1366           0 :       pc.lrFhss.hdrCount = this->lrFhssHdrCount;
    1367           0 :       break;
    1368             :     }
    1369           0 :     default:
    1370           0 :       return(RADIOLIB_ERR_WRONG_MODEM);
    1371             :   }
    1372             : 
    1373           0 :   return(this->calculateTimeOnAir(modem, dr, pc, len));
    1374             : }
    1375             : 
    1376           0 : RadioLibTime_t LR11x0::calculateRxTimeout(RadioLibTime_t timeoutUs) {
    1377             :   // the timeout value is given in units of 30.52 microseconds
    1378             :   // the calling function should provide some extra width, as this number of units is truncated to integer
    1379           0 :   RadioLibTime_t timeout = timeoutUs / 30.52;
    1380           0 :   return(timeout);
    1381             : }
    1382             : 
    1383           0 : uint32_t LR11x0::getIrqFlags() {
    1384           0 :   return((uint32_t)this->getIrqStatus());
    1385             : }
    1386             : 
    1387           0 : int16_t LR11x0::setIrqFlags(uint32_t irq) {
    1388           0 :   return(this->setDioIrqParams(irq, irq));
    1389             : }
    1390             : 
    1391           0 : int16_t LR11x0::clearIrqFlags(uint32_t irq) {
    1392           0 :   return(this->clearIrqState(irq));
    1393             : }
    1394             : 
    1395           0 : uint8_t LR11x0::randomByte() {
    1396           0 :   uint32_t num = 0;
    1397           0 :   (void)getRandomNumber(&num);
    1398           0 :   return((uint8_t)num);
    1399             : }
    1400             : 
    1401           0 : int16_t LR11x0::implicitHeader(size_t len) {
    1402           0 :   return(this->setHeaderType(RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT, len));
    1403             : }
    1404             : 
    1405           0 : int16_t LR11x0::explicitHeader() {
    1406           0 :   return(this->setHeaderType(RADIOLIB_LR11X0_LORA_HEADER_EXPLICIT));
    1407             : }
    1408             : 
    1409           0 : float LR11x0::getDataRate() const {
    1410           0 :   return(this->dataRateMeasured);
    1411             : }
    1412             : 
    1413           0 : int16_t LR11x0::setRegulatorLDO() {
    1414           0 :   return(this->setRegMode(RADIOLIB_LR11X0_REG_MODE_LDO));
    1415             : }
    1416             : 
    1417           0 : int16_t LR11x0::setRegulatorDCDC() {
    1418           0 :   return(this->setRegMode(RADIOLIB_LR11X0_REG_MODE_DC_DC));
    1419             : }
    1420             : 
    1421           0 : int16_t LR11x0::setRxBoostedGainMode(bool en) {
    1422           0 :   uint8_t buff[1] = { (uint8_t)en };
    1423           0 :   return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RX_BOOSTED, true, buff, sizeof(buff)));
    1424             : }
    1425             : 
    1426           0 : void LR11x0::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) {
    1427             :   // find which pins are used
    1428           0 :   uint8_t enable = 0;
    1429           0 :   for(size_t i = 0; i < Module::RFSWITCH_MAX_PINS; i++) {
    1430             :     // check if this pin is unused
    1431           0 :     if(pins[i] == RADIOLIB_NC) {
    1432           0 :       continue;
    1433             :     }
    1434             : 
    1435             :     // only keep DIO pins, there may be some GPIOs in the switch tabke
    1436           0 :     if(pins[i] & RFSWITCH_PIN_FLAG) {
    1437           0 :       enable |= 1UL << RADIOLIB_LR11X0_DIOx_VAL(pins[i]);
    1438             :     }
    1439             :     
    1440             :   }
    1441             : 
    1442             :   // now get the configuration
    1443           0 :   uint8_t modes[7] = { 0 };
    1444           0 :   for(size_t i = 0; i < 7; i++) {
    1445             :     // check end of table
    1446           0 :     if(table[i].mode == LR11x0::MODE_END_OF_TABLE) {
    1447           0 :       break;
    1448             :     }
    1449             : 
    1450             :     // get the mode ID in case the modes are out-of-order
    1451           0 :     uint8_t index = table[i].mode - LR11x0::MODE_STBY;
    1452             : 
    1453             :     // iterate over the pins
    1454           0 :     for(size_t j = 0; j < Module::RFSWITCH_MAX_PINS; j++) {
    1455             :       // only process modes for the DIOx pins, skip GPIO pins
    1456           0 :       if(!(pins[j] & RFSWITCH_PIN_FLAG)) {
    1457           0 :         continue;
    1458             :       }
    1459           0 :       modes[index] |= (table[i].values[j] == this->mod->hal->GpioLevelHigh) ? (1UL << j) : 0;
    1460             :     }
    1461             :   }
    1462             : 
    1463             :   // set it
    1464           0 :   this->setDioAsRfSwitch(enable, modes[0], modes[1], modes[2], modes[3], modes[4], modes[5], modes[6]);
    1465           0 : }
    1466             : 
    1467           0 : int16_t LR11x0::forceLDRO(bool enable) {
    1468             :   // check packet type
    1469           0 :   uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
    1470           0 :   int16_t state = getPacketType(&type);
    1471           0 :   RADIOLIB_ASSERT(state);
    1472           0 :   if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
    1473           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1474             :   }
    1475             : 
    1476             :   // update modulation parameters
    1477           0 :   this->ldroAuto = false;
    1478           0 :   this->ldrOptimize = (uint8_t)enable;
    1479           0 :   return(setModulationParamsLoRa(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
    1480             : }
    1481             : 
    1482           0 : int16_t LR11x0::autoLDRO() {
    1483           0 :   uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
    1484           0 :   int16_t state = getPacketType(&type);
    1485           0 :   RADIOLIB_ASSERT(state);
    1486           0 :   if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
    1487           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1488             :   }
    1489             : 
    1490           0 :   this->ldroAuto = true;
    1491           0 :   return(RADIOLIB_ERR_NONE);
    1492             : }
    1493             : 
    1494           0 : int16_t LR11x0::setLrFhssConfig(uint8_t bw, uint8_t cr, uint8_t hdrCount, uint16_t hopSeed) {
    1495             :   // check active modem
    1496           0 :   uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
    1497           0 :   int16_t state = getPacketType(&type);
    1498           0 :   RADIOLIB_ASSERT(state);
    1499           0 :   if(type != RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) {
    1500           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1501             :   }
    1502             : 
    1503             :   // check and cache all parameters
    1504           0 :   RADIOLIB_CHECK_RANGE((int8_t)cr, (int8_t)RADIOLIB_LR11X0_LR_FHSS_CR_5_6, (int8_t)RADIOLIB_LR11X0_LR_FHSS_CR_1_3, RADIOLIB_ERR_INVALID_CODING_RATE);
    1505           0 :   this->lrFhssCr = cr;
    1506           0 :   RADIOLIB_CHECK_RANGE((int8_t)bw, (int8_t)RADIOLIB_LR11X0_LR_FHSS_BW_39_06, (int8_t)RADIOLIB_LR11X0_LR_FHSS_BW_1574_2, RADIOLIB_ERR_INVALID_BANDWIDTH);
    1507           0 :   this->lrFhssBw = bw;
    1508           0 :   RADIOLIB_CHECK_RANGE(hdrCount, 1, 4, RADIOLIB_ERR_INVALID_BIT_RANGE);
    1509           0 :   this->lrFhssHdrCount = hdrCount;
    1510           0 :   RADIOLIB_CHECK_RANGE((int16_t)hopSeed, (int16_t)0x000, (int16_t)0x1FF, RADIOLIB_ERR_INVALID_DATA_SHAPING);
    1511           0 :   this->lrFhssHopSeq = hopSeed;
    1512           0 :   return(RADIOLIB_ERR_NONE);
    1513             : }
    1514             : 
    1515           0 : int16_t LR11x0::getVersionInfo(LR11x0VersionInfo_t* info) {
    1516           0 :   RADIOLIB_ASSERT_PTR(info);
    1517             : 
    1518           0 :   int16_t state = this->getVersion(&info->hardware, &info->device, &info->fwMajor, &info->fwMinor);
    1519           0 :   RADIOLIB_ASSERT(state);
    1520             :   
    1521             :   // LR1121 does not have GNSS and WiFi scanning
    1522           0 :   if(this->chipType == RADIOLIB_LR11X0_DEVICE_LR1121) {
    1523           0 :     info->fwMajorWiFi = 0;
    1524           0 :     info->fwMinorWiFi = 0;
    1525           0 :     info->fwGNSS = 0;
    1526           0 :     info->almanacGNSS = 0;
    1527           0 :     return(RADIOLIB_ERR_NONE);
    1528             :   }
    1529             : 
    1530           0 :   state = this->wifiReadVersion(&info->fwMajorWiFi, &info->fwMinorWiFi);
    1531           0 :   RADIOLIB_ASSERT(state);
    1532           0 :   return(this->gnssReadVersion(&info->fwGNSS, &info->almanacGNSS));
    1533             : }
    1534             : 
    1535           0 : int16_t LR11x0::updateFirmware(const uint32_t* image, size_t size, bool nonvolatile) {
    1536           0 :   RADIOLIB_ASSERT_PTR(image);
    1537             : 
    1538             :   // put the device to bootloader mode
    1539           0 :   int16_t state = this->reboot(true);
    1540           0 :   RADIOLIB_ASSERT(state);
    1541           0 :   this->mod->hal->delay(500);
    1542             : 
    1543             :   // check we're in bootloader
    1544           0 :   uint8_t device = 0xFF;
    1545           0 :   state = this->getVersion(NULL, &device, NULL, NULL);
    1546           0 :   RADIOLIB_ASSERT(state);
    1547           0 :   if(device != RADIOLIB_LR11X0_DEVICE_BOOT) {
    1548             :     RADIOLIB_DEBUG_BASIC_PRINTLN("Failed to put device to bootloader mode, %02x != %02x", (unsigned int)device, (unsigned int)RADIOLIB_LR11X0_DEVICE_BOOT);
    1549           0 :     return(RADIOLIB_ERR_CHIP_NOT_FOUND);
    1550             :   }
    1551             : 
    1552             :   // erase the image
    1553           0 :   state = this->bootEraseFlash();
    1554           0 :   RADIOLIB_ASSERT(state);
    1555             : 
    1556             :   // wait for BUSY to go low
    1557           0 :   RadioLibTime_t start = this->mod->hal->millis();
    1558           0 :   while(this->mod->hal->digitalRead(this->mod->getGpio())) {
    1559           0 :     this->mod->hal->yield();
    1560           0 :     if(this->mod->hal->millis() - start >= 3000) {
    1561             :       RADIOLIB_DEBUG_BASIC_PRINTLN("BUSY pin timeout after erase!");
    1562           0 :       return(RADIOLIB_ERR_SPI_CMD_TIMEOUT);
    1563             :     }
    1564             :   }
    1565             : 
    1566             :   // upload the new image
    1567           0 :   const size_t maxLen = 64;
    1568           0 :   size_t rem = size % maxLen;
    1569           0 :   size_t numWrites = (rem == 0) ? (size / maxLen) : ((size / maxLen) + 1);
    1570             :   RADIOLIB_DEBUG_BASIC_PRINTLN("Writing image in %lu chunks, last chunk size is %lu words", (unsigned long)numWrites, (unsigned long)rem);
    1571           0 :   for(size_t i = 0; i < numWrites; i ++) {
    1572           0 :     uint32_t offset = i * maxLen;
    1573           0 :     uint32_t len = (i == (numWrites - 1)) ? rem : maxLen;
    1574             :     RADIOLIB_DEBUG_BASIC_PRINTLN("Writing chunk %d at offset %08lx (%u words)", (int)i, (unsigned long)offset, (unsigned int)len);
    1575           0 :     this->bootWriteFlashEncrypted(offset*sizeof(uint32_t), const_cast<uint32_t*>(&image[offset]), len, nonvolatile);
    1576             :   }
    1577             : 
    1578             :   // kick the device from bootloader
    1579           0 :   state = this->reset();
    1580           0 :   RADIOLIB_ASSERT(state);
    1581             : 
    1582             :   // verify we are no longer in bootloader
    1583           0 :   state = this->getVersion(NULL, &device, NULL, NULL);
    1584           0 :   RADIOLIB_ASSERT(state);
    1585           0 :   if(device == RADIOLIB_LR11X0_DEVICE_BOOT) {
    1586             :     RADIOLIB_DEBUG_BASIC_PRINTLN("Failed to kick device from bootloader mode, %02x == %02x", (unsigned int)device, (unsigned int)RADIOLIB_LR11X0_DEVICE_BOOT);
    1587           0 :     return(RADIOLIB_ERR_CHIP_NOT_FOUND);
    1588             :   }
    1589             : 
    1590           0 :   return(state);
    1591             : }
    1592             : 
    1593           0 : int16_t LR11x0::getModem(ModemType_t* modem) {
    1594           0 :   RADIOLIB_ASSERT_PTR(modem);
    1595             : 
    1596           0 :   uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
    1597           0 :   int16_t state = getPacketType(&type);
    1598           0 :   RADIOLIB_ASSERT(state);
    1599             : 
    1600           0 :   switch(type) {
    1601           0 :     case(RADIOLIB_LR11X0_PACKET_TYPE_LORA):
    1602           0 :       *modem = ModemType_t::RADIOLIB_MODEM_LORA;
    1603           0 :       return(RADIOLIB_ERR_NONE);
    1604           0 :     case(RADIOLIB_LR11X0_PACKET_TYPE_GFSK):
    1605           0 :       *modem = ModemType_t::RADIOLIB_MODEM_FSK;
    1606           0 :       return(RADIOLIB_ERR_NONE);
    1607           0 :     case(RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS):
    1608           0 :       *modem = ModemType_t::RADIOLIB_MODEM_LRFHSS;
    1609           0 :       return(RADIOLIB_ERR_NONE);
    1610             :   }
    1611             :   
    1612           0 :   return(RADIOLIB_ERR_WRONG_MODEM);
    1613             : }
    1614             : 
    1615           0 : int16_t LR11x0::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) {
    1616             :   int16_t state;
    1617             : 
    1618           0 :   switch(mode) {
    1619           0 :     case(RADIOLIB_RADIO_MODE_RX): {
    1620             :       // check active modem
    1621           0 :       uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
    1622           0 :       state = getPacketType(&modem);
    1623           0 :       RADIOLIB_ASSERT(state);
    1624           0 :       if((modem != RADIOLIB_LR11X0_PACKET_TYPE_LORA) && 
    1625           0 :         (modem != RADIOLIB_LR11X0_PACKET_TYPE_GFSK)) {
    1626           0 :         return(RADIOLIB_ERR_WRONG_MODEM);
    1627             :       }
    1628             : 
    1629             :       // set DIO mapping
    1630           0 :       if(cfg->receive.timeout != RADIOLIB_LR11X0_RX_TIMEOUT_INF) {
    1631           0 :         cfg->receive.irqMask |= (1UL << RADIOLIB_IRQ_TIMEOUT);
    1632             :       }
    1633           0 :       state = setDioIrqParams(getIrqMapped(cfg->receive.irqFlags & cfg->receive.irqMask));
    1634           0 :       RADIOLIB_ASSERT(state);
    1635             : 
    1636             :       // clear interrupt flags
    1637           0 :       state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL);
    1638           0 :       RADIOLIB_ASSERT(state);
    1639             : 
    1640             :       // set implicit mode and expected len if applicable
    1641           0 :       if((this->headerType == RADIOLIB_LR11X0_LORA_HEADER_IMPLICIT) && (modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA)) {
    1642           0 :         state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, this->invertIQEnabled);
    1643           0 :         RADIOLIB_ASSERT(state);
    1644             :       }
    1645             : 
    1646             :       // if max(uint32_t) is used, revert to RxContinuous
    1647           0 :       if(cfg->receive.timeout == 0xFFFFFFFF) {
    1648           0 :         cfg->receive.timeout = 0xFFFFFF;
    1649             :       }
    1650           0 :       this->rxTimeout = cfg->receive.timeout;
    1651           0 :     } break;
    1652             :   
    1653           0 :     case(RADIOLIB_RADIO_MODE_TX): {
    1654             :       // check packet length
    1655           0 :       if(cfg->transmit.len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH) {
    1656           0 :         return(RADIOLIB_ERR_PACKET_TOO_LONG);
    1657             :       }
    1658             : 
    1659             :       // maximum packet length is decreased by 1 when address filtering is active
    1660           0 :       if((this->addrComp != RADIOLIB_LR11X0_GFSK_ADDR_FILTER_DISABLED) && (cfg->transmit.len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH - 1)) {
    1661           0 :         return(RADIOLIB_ERR_PACKET_TOO_LONG);
    1662             :       }
    1663             : 
    1664             :       // set packet Length
    1665           0 :       state = RADIOLIB_ERR_NONE;
    1666           0 :       uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
    1667           0 :       state = getPacketType(&modem);
    1668           0 :       RADIOLIB_ASSERT(state);
    1669           0 :       if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
    1670           0 :         state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, cfg->transmit.len, this->crcTypeLoRa, this->invertIQEnabled);
    1671             :       
    1672           0 :       } else if(modem == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
    1673           0 :         state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, cfg->transmit.len, this->crcTypeGFSK, this->whitening);
    1674             :       
    1675           0 :       } else if(modem != RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) {
    1676           0 :         return(RADIOLIB_ERR_UNKNOWN);
    1677             :       
    1678             :       }
    1679           0 :       RADIOLIB_ASSERT(state);
    1680             : 
    1681             :       // set DIO mapping
    1682           0 :       state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_TX_DONE | RADIOLIB_LR11X0_IRQ_TIMEOUT);
    1683           0 :       RADIOLIB_ASSERT(state);
    1684             : 
    1685           0 :       if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) {
    1686             :         // in LR-FHSS mode, the packet is built by the device
    1687             :         // TODO add configurable device offset
    1688           0 :         state = lrFhssBuildFrame(this->lrFhssHdrCount, this->lrFhssCr, this->lrFhssGrid, true, this->lrFhssBw, this->lrFhssHopSeq, 0, cfg->transmit.data, cfg->transmit.len);
    1689           0 :         RADIOLIB_ASSERT(state);
    1690             : 
    1691             :       } else {
    1692             :         // write packet to buffer
    1693           0 :         state = writeBuffer8(cfg->transmit.data, cfg->transmit.len);
    1694           0 :         RADIOLIB_ASSERT(state);
    1695             : 
    1696             :       }
    1697             : 
    1698             :       // clear interrupt flags
    1699           0 :       state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL);
    1700           0 :       RADIOLIB_ASSERT(state);
    1701           0 :     } break;
    1702             :     
    1703           0 :     default:
    1704           0 :       return(RADIOLIB_ERR_UNSUPPORTED);
    1705             :   }
    1706             : 
    1707           0 :   this->stagedMode = mode;
    1708           0 :   return(state);
    1709             : }
    1710             : 
    1711           0 : int16_t LR11x0::launchMode() {
    1712             :   int16_t state;
    1713           0 :   switch(this->stagedMode) {
    1714           0 :     case(RADIOLIB_RADIO_MODE_RX): {
    1715           0 :       this->mod->setRfSwitchState(Module::MODE_RX);
    1716           0 :       state = setRx(this->rxTimeout);
    1717           0 :     } break;
    1718             :   
    1719           0 :     case(RADIOLIB_RADIO_MODE_TX): {
    1720           0 :       this->mod->setRfSwitchState(Module::MODE_TX);
    1721           0 :       state = setTx(RADIOLIB_LR11X0_TX_TIMEOUT_NONE);
    1722           0 :       RADIOLIB_ASSERT(state);
    1723             : 
    1724             :       // wait for BUSY to go low (= PA ramp up done)
    1725           0 :       while(this->mod->hal->digitalRead(this->mod->getGpio())) {
    1726           0 :         this->mod->hal->yield();
    1727             :       }
    1728           0 :     } break;
    1729             :     
    1730           0 :     default:
    1731           0 :       return(RADIOLIB_ERR_UNSUPPORTED);
    1732             :   }
    1733             : 
    1734           0 :   this->stagedMode = RADIOLIB_RADIO_MODE_NONE;
    1735           0 :   return(state);
    1736             : }
    1737             : 
    1738           0 : uint8_t LR11x0::roundRampTime(uint32_t rampTimeUs) {
    1739             :   uint8_t regVal;
    1740             : 
    1741             :   // Round up the ramp time to nearest discrete register value
    1742           0 :   if(rampTimeUs <= 16) {
    1743           0 :     regVal = RADIOLIB_LR11X0_PA_RAMP_16U;
    1744           0 :   } else if(rampTimeUs <= 32) {
    1745           0 :     regVal = RADIOLIB_LR11X0_PA_RAMP_32U;
    1746           0 :   } else if(rampTimeUs <= 48) {
    1747           0 :     regVal = RADIOLIB_LR11X0_PA_RAMP_48U;
    1748           0 :   } else if(rampTimeUs <= 64) {
    1749           0 :     regVal = RADIOLIB_LR11X0_PA_RAMP_64U;
    1750           0 :   } else if(rampTimeUs <= 80) {
    1751           0 :     regVal = RADIOLIB_LR11X0_PA_RAMP_80U;
    1752           0 :   } else if(rampTimeUs <= 96) {
    1753           0 :     regVal = RADIOLIB_LR11X0_PA_RAMP_96U;
    1754           0 :   } else if(rampTimeUs <= 112) {
    1755           0 :     regVal = RADIOLIB_LR11X0_PA_RAMP_112U;
    1756           0 :   } else if(rampTimeUs <= 128) {
    1757           0 :     regVal = RADIOLIB_LR11X0_PA_RAMP_128U;
    1758           0 :   } else if(rampTimeUs <= 144) {
    1759           0 :     regVal = RADIOLIB_LR11X0_PA_RAMP_144U;
    1760           0 :   } else if(rampTimeUs <= 160) {
    1761           0 :     regVal = RADIOLIB_LR11X0_PA_RAMP_160U;
    1762           0 :   } else if(rampTimeUs <= 176) {
    1763           0 :     regVal = RADIOLIB_LR11X0_PA_RAMP_176U;
    1764           0 :   } else if(rampTimeUs <= 192) {
    1765           0 :     regVal = RADIOLIB_LR11X0_PA_RAMP_192U;
    1766           0 :   } else if(rampTimeUs <= 208) {
    1767           0 :     regVal = RADIOLIB_LR11X0_PA_RAMP_208U;
    1768           0 :   } else if(rampTimeUs <= 240) {
    1769           0 :     regVal = RADIOLIB_LR11X0_PA_RAMP_240U;
    1770           0 :   } else if(rampTimeUs <= 272) {
    1771           0 :     regVal = RADIOLIB_LR11X0_PA_RAMP_272U;
    1772             :   } else {  // 304
    1773           0 :     regVal = RADIOLIB_LR11X0_PA_RAMP_304U;
    1774             :   }
    1775             : 
    1776           0 :   return regVal;
    1777             : }
    1778             : 
    1779           0 : int16_t LR11x0::workaroundGFSK() {
    1780             :   // first, check we are using GFSK modem
    1781           0 :   uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
    1782           0 :   int16_t state = getPacketType(&modem);
    1783           0 :   RADIOLIB_ASSERT(state);
    1784           0 :   if(modem != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
    1785             :     // not in GFSK, nothing to do here
    1786           0 :     return(RADIOLIB_ERR_NONE);
    1787             :   }
    1788             : 
    1789             :   // this seems to always be the first step (even when resetting)
    1790           0 :   state = this->writeRegMemMask32(RADIOLIB_LR11X0_REG_GFSK_FIX1, 0x30, 0x10);
    1791           0 :   RADIOLIB_ASSERT(state);
    1792             : 
    1793             :   // these are the default values that will be applied if nothing matches
    1794           0 :   uint32_t valFix2 = 0x01;
    1795           0 :   uint32_t valFix3 = 0x0A01;
    1796             : 
    1797             :   // next, decide what to change based on modulation properties
    1798           0 :   if((this->bitRate == 1200) && (this->frequencyDev == 5000) && (this->rxBandwidth == RADIOLIB_LR11X0_GFSK_RX_BW_19_5)) {
    1799             :     // workaround for 1.2 kbps
    1800           0 :     valFix2 = 0x04;
    1801             : 
    1802           0 :   } else if((this->bitRate == 600) && (this->frequencyDev == 800) && (this->rxBandwidth == RADIOLIB_LR11X0_GFSK_RX_BW_4_8))  {
    1803             :     // value to write depends on the frequency
    1804           0 :     valFix3 = (this->freqMHz >= 1000.0f) ? 0x1100 : 0x0600;
    1805             :   
    1806             :   }
    1807             : 
    1808             :   // update the registers
    1809           0 :   state = this->writeRegMemMask32(RADIOLIB_LR11X0_REG_GFSK_FIX2, 0x05, valFix2);
    1810           0 :   RADIOLIB_ASSERT(state);
    1811           0 :   return(this->writeRegMemMask32(RADIOLIB_LR11X0_REG_GFSK_FIX3, 0x01FF03, valFix3));
    1812             : }
    1813             : 
    1814           0 : int16_t LR11x0::modSetup(float tcxoVoltage, uint8_t modem) {
    1815           0 :   this->mod->init();
    1816           0 :   this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
    1817           0 :   this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput);
    1818           0 :   this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_32;
    1819           0 :   this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16;
    1820           0 :   this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8;
    1821           0 :   this->mod->spiConfig.statusPos = 0;
    1822           0 :   this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_LR11X0_CMD_READ_REG_MEM;
    1823           0 :   this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_LR11X0_CMD_WRITE_REG_MEM;
    1824           0 :   this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_LR11X0_CMD_NOP;
    1825           0 :   this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_LR11X0_CMD_GET_STATUS;
    1826           0 :   this->mod->spiConfig.stream = true;
    1827           0 :   this->mod->spiConfig.parseStatusCb = SPIparseStatus;
    1828           0 :   this->mod->spiConfig.checkStatusCb = SPIcheckStatus;
    1829           0 :   this->gnss = false;
    1830             : 
    1831             :   // try to find the LR11x0 chip - this will also reset the module at least once
    1832           0 :   if(!LR11x0::findChip(this->chipType)) {
    1833             :     RADIOLIB_DEBUG_BASIC_PRINTLN("No LR11x0 found!");
    1834           0 :     this->mod->term();
    1835           0 :     return(RADIOLIB_ERR_CHIP_NOT_FOUND);
    1836             :   }
    1837             :   RADIOLIB_DEBUG_BASIC_PRINTLN("M\tLR11x0");
    1838             : 
    1839             :   // set mode to standby
    1840           0 :   int16_t state = standby();
    1841           0 :   RADIOLIB_ASSERT(state);
    1842             : 
    1843             :   // set TCXO control, if requested
    1844           0 :   if(!this->XTAL && tcxoVoltage > 0.0f) {
    1845           0 :     state = setTCXO(tcxoVoltage);
    1846           0 :     RADIOLIB_ASSERT(state);
    1847             :   }
    1848             : 
    1849             :   // configure settings not accessible by API
    1850           0 :   return(config(modem));
    1851             : }
    1852             : 
    1853           0 : int16_t LR11x0::SPIparseStatus(uint8_t in) {
    1854           0 :   if((in & 0b00001110) == RADIOLIB_LR11X0_STAT_1_CMD_PERR) {
    1855           0 :     return(RADIOLIB_ERR_SPI_CMD_INVALID);
    1856           0 :   } else if((in & 0b00001110) == RADIOLIB_LR11X0_STAT_1_CMD_FAIL) {
    1857           0 :     return(RADIOLIB_ERR_SPI_CMD_FAILED);
    1858           0 :   } else if((in == 0x00) || (in == 0xFF)) {
    1859           0 :     return(RADIOLIB_ERR_CHIP_NOT_FOUND);
    1860             :   }
    1861           0 :   return(RADIOLIB_ERR_NONE);
    1862             : }
    1863             : 
    1864           0 : int16_t LR11x0::SPIcheckStatus(Module* mod) {
    1865             :   // the status check command doesn't return status in the same place as other read commands,
    1866             :   // but only as the first byte (as with any other command), hence LR11x0::SPIcommand can't be used
    1867             :   // it also seems to ignore the actual command, and just sending in bunch of NOPs will work 
    1868           0 :   uint8_t buff[6] = { 0 };
    1869           0 :   mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_0;
    1870           0 :   int16_t state = mod->SPItransferStream(NULL, 0, false, NULL, buff, sizeof(buff), true);
    1871           0 :   mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8;
    1872           0 :   RADIOLIB_ASSERT(state);
    1873           0 :   return(LR11x0::SPIparseStatus(buff[0]));
    1874             : }
    1875             : 
    1876           0 : int16_t LR11x0::SPIcommand(uint16_t cmd, bool write, uint8_t* data, size_t len, const uint8_t* out, size_t outLen) {
    1877           0 :   int16_t state = RADIOLIB_ERR_UNKNOWN;
    1878           0 :   if(!write) {
    1879             :     // the SPI interface of LR11x0 requires two separate transactions for reading
    1880             :     // send the 16-bit command
    1881           0 :     state = this->mod->SPIwriteStream(cmd, out, outLen, true, false);
    1882           0 :     RADIOLIB_ASSERT(state);
    1883             : 
    1884             :     // read the result without command
    1885           0 :     this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_0;
    1886           0 :     state = this->mod->SPIreadStream(RADIOLIB_LR11X0_CMD_NOP, data, len, true, false);
    1887           0 :     this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_16;
    1888             : 
    1889             :   } else {
    1890             :     // write is just a single transaction
    1891           0 :     state = this->mod->SPIwriteStream(cmd, data, len, true, true);
    1892             :   
    1893             :   }
    1894             :   
    1895           0 :   return(state);
    1896             : }
    1897             : 
    1898           0 : bool LR11x0::findChip(uint8_t ver) {
    1899           0 :   uint8_t i = 0;
    1900           0 :   bool flagFound = false;
    1901           0 :   while((i < 10) && !flagFound) {
    1902             :     // reset the module
    1903           0 :     reset();
    1904             : 
    1905             :     // read the version
    1906             :     LR11x0VersionInfo_t info;
    1907           0 :     int16_t state = getVersionInfo(&info);
    1908           0 :     RADIOLIB_ASSERT(state);
    1909             : 
    1910           0 :     if((info.device == ver) || (info.device == RADIOLIB_LR11X0_DEVICE_BOOT)) {
    1911             :       RADIOLIB_DEBUG_BASIC_PRINTLN("Found LR11x0: RADIOLIB_LR11X0_CMD_GET_VERSION = 0x%02x", info.device);
    1912             :       RADIOLIB_DEBUG_BASIC_PRINTLN("Base FW version: %d.%d", (int)info.fwMajor, (int)info.fwMinor);
    1913           0 :       if(this->chipType != RADIOLIB_LR11X0_DEVICE_LR1121) {
    1914             :         RADIOLIB_DEBUG_BASIC_PRINTLN("WiFi FW version: %d.%d", (int)info.fwMajorWiFi, (int)info.fwMinorWiFi);
    1915             :         RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS FW version: %d.%d", (int)info.fwGNSS, (int)info.almanacGNSS);
    1916             :       }
    1917           0 :       if(info.device == RADIOLIB_LR11X0_DEVICE_BOOT) {
    1918             :         RADIOLIB_DEBUG_BASIC_PRINTLN("Warning: device is in bootloader mode! Only FW update is possible now.");
    1919             :       }
    1920           0 :       flagFound = true;
    1921             :     } else {
    1922             :       RADIOLIB_DEBUG_BASIC_PRINTLN("LR11x0 not found! (%d of 10 tries) RADIOLIB_LR11X0_CMD_GET_VERSION = 0x%02x", i + 1, info.device);
    1923             :       RADIOLIB_DEBUG_BASIC_PRINTLN("Expected: 0x%02x", ver);
    1924           0 :       this->mod->hal->delay(10);
    1925           0 :       i++;
    1926             :     }
    1927             :   }
    1928             :   
    1929             : 
    1930           0 :   return(flagFound);
    1931             : }
    1932             : 
    1933           0 : int16_t LR11x0::config(uint8_t modem) {
    1934           0 :   int16_t state = RADIOLIB_ERR_UNKNOWN;
    1935             : 
    1936             :   // set Rx/Tx fallback mode to STDBY_RC
    1937           0 :   state = this->setRxTxFallbackMode(RADIOLIB_LR11X0_FALLBACK_MODE_STBY_RC);
    1938           0 :   RADIOLIB_ASSERT(state);
    1939             : 
    1940             :   // clear IRQ
    1941           0 :   state = this->clearIrqState(RADIOLIB_LR11X0_IRQ_ALL);
    1942           0 :   state |= this->setDioIrqParams(RADIOLIB_LR11X0_IRQ_NONE);
    1943           0 :   RADIOLIB_ASSERT(state);
    1944             : 
    1945             :   // calibrate all blocks
    1946           0 :   (void)this->calibrate(RADIOLIB_LR11X0_CALIBRATE_ALL);
    1947             : 
    1948             :   // wait for calibration completion
    1949           0 :   this->mod->hal->delay(5);
    1950           0 :   while(this->mod->hal->digitalRead(this->mod->getGpio())) {
    1951           0 :     this->mod->hal->yield();
    1952             :   }
    1953             :   
    1954             :   // if something failed, show the device errors
    1955             :   #if RADIOLIB_DEBUG_BASIC
    1956             :   if(state != RADIOLIB_ERR_NONE) {
    1957             :     // unless mode is forced to standby, device errors will be 0
    1958             :     standby();
    1959             :     uint16_t errors = 0;
    1960             :     getErrors(&errors);
    1961             :     RADIOLIB_DEBUG_BASIC_PRINTLN("Calibration failed, device errors: 0x%X", errors);
    1962             :   }
    1963             :   #endif
    1964             : 
    1965             :   // set modem
    1966           0 :   state = this->setPacketType(modem);
    1967           0 :   return(state);
    1968             : }
    1969             : 
    1970           0 : int16_t LR11x0::setPacketMode(uint8_t mode, uint8_t len) {
    1971             :   // check active modem
    1972           0 :   uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
    1973           0 :   int16_t state = getPacketType(&type);
    1974           0 :   RADIOLIB_ASSERT(state);
    1975           0 :   if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
    1976           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1977             :   }
    1978             : 
    1979             :   // set requested packet mode
    1980           0 :   state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, mode, len, this->crcTypeGFSK, this->whitening);
    1981           0 :   RADIOLIB_ASSERT(state);
    1982             : 
    1983             :   // update cached value
    1984           0 :   this->packetType = mode;
    1985           0 :   return(state);
    1986             : }
    1987             : 
    1988           0 : int16_t LR11x0::startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uint8_t exitMode, RadioLibTime_t timeout) {
    1989             :   // check active modem
    1990           0 :   uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
    1991           0 :   int16_t state = getPacketType(&type);
    1992           0 :   RADIOLIB_ASSERT(state);
    1993           0 :   if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
    1994           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1995             :   }
    1996             : 
    1997             :   // select CAD parameters
    1998             :   // TODO the magic numbers are based on Semtech examples, this is probably suboptimal
    1999           0 :   uint8_t num = symbolNum;
    2000           0 :   if(num == RADIOLIB_LR11X0_CAD_PARAM_DEFAULT) {
    2001           0 :     num = 2;
    2002             :   }
    2003             :   
    2004           0 :   const uint8_t detPeakValues[8] = { 48, 48, 50, 55, 55, 59, 61, 65 };
    2005           0 :   uint8_t peak = detPeak;
    2006           0 :   if(peak == RADIOLIB_LR11X0_CAD_PARAM_DEFAULT) {
    2007           0 :     peak = detPeakValues[this->spreadingFactor - 5];
    2008             :   }
    2009             : 
    2010           0 :   uint8_t min = detMin;
    2011           0 :   if(min == RADIOLIB_LR11X0_CAD_PARAM_DEFAULT) {
    2012           0 :     min = 10;
    2013             :   }
    2014             : 
    2015           0 :   uint8_t mode = exitMode; 
    2016           0 :   if(mode == RADIOLIB_LR11X0_CAD_PARAM_DEFAULT) {
    2017           0 :     mode = RADIOLIB_LR11X0_CAD_EXIT_MODE_STBY_RC;
    2018             :   }
    2019             : 
    2020           0 :   uint32_t timeout_raw = (float)timeout / 30.52f;
    2021             : 
    2022             :   // set CAD parameters
    2023             :   // TODO add configurable exit mode and timeout
    2024           0 :   state = setCadParams(num, peak, min, mode, timeout_raw);
    2025           0 :   RADIOLIB_ASSERT(state);
    2026             : 
    2027             :   // start CAD
    2028           0 :   return(setCad());
    2029             : }
    2030             : 
    2031           0 : int16_t LR11x0::setHeaderType(uint8_t hdrType, size_t len) {
    2032             :   // check active modem
    2033           0 :   uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
    2034           0 :   int16_t state = getPacketType(&type);
    2035           0 :   RADIOLIB_ASSERT(state);
    2036           0 :   if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
    2037           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
    2038             :   }
    2039             : 
    2040             :   // set requested packet mode
    2041           0 :   state = setPacketParamsLoRa(this->preambleLengthLoRa, hdrType, len, this->crcTypeLoRa, this->invertIQEnabled);
    2042           0 :   RADIOLIB_ASSERT(state);
    2043             : 
    2044             :   // update cached value
    2045           0 :   this->headerType = hdrType;
    2046           0 :   this->implicitLen = len;
    2047             : 
    2048           0 :   return(state);
    2049             : }
    2050             : 
    2051           0 : Module* LR11x0::getMod() {
    2052           0 :   return(this->mod);
    2053             : }
    2054             : 
    2055             : #endif

Generated by: LCOV version 1.14