LCOV - code coverage report
Current view: top level - src/modules/LR11x0 - LR11x0.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 185 976 19.0 %
Date: 2026-06-03 18:53:41 Functions: 42 81 51.9 %

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

Generated by: LCOV version 1.14