LCOV - code coverage report
Current view: top level - src/modules/LR2021 - LR2021.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 162 684 23.7 %
Date: 2026-11-08 19:43:08 Functions: 36 53 67.9 %

          Line data    Source code
       1             : #include "LR2021.h"
       2             : 
       3             : #include <string.h>
       4             : #include <math.h>
       5             : 
       6             : #if !RADIOLIB_EXCLUDE_LR2021
       7             : 
       8           2 : LR2021::LR2021(Module* mod) : LRxxxx(mod) {
       9           2 :   this->freqStep = RADIOLIB_LR2021_FREQUENCY_STEP_SIZE;
      10           2 :   this->maxPacketLength = RADIOLIB_LR2021_MAX_PACKET_LENGTH;
      11           2 :   this->implicitLen = RADIOLIB_LR2021_MAX_PACKET_LENGTH;
      12           2 :   this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_LR2021_IRQ_TX_DONE;
      13           2 :   this->irqMap[RADIOLIB_IRQ_RX_DONE] = RADIOLIB_LR2021_IRQ_RX_DONE;
      14           2 :   this->irqMap[RADIOLIB_IRQ_PREAMBLE_DETECTED] = RADIOLIB_LR2021_IRQ_PREAMBLE_DETECTED;
      15           2 :   this->irqMap[RADIOLIB_IRQ_SYNC_WORD_VALID] = RADIOLIB_LR2021_IRQ_LORA_HEADER_VALID;
      16           2 :   this->irqMap[RADIOLIB_IRQ_HEADER_VALID] = RADIOLIB_LR2021_IRQ_LORA_HEADER_VALID;
      17           2 :   this->irqMap[RADIOLIB_IRQ_HEADER_ERR] = RADIOLIB_LR2021_IRQ_LORA_HDR_CRC_ERROR;
      18           2 :   this->irqMap[RADIOLIB_IRQ_CRC_ERR] = RADIOLIB_LR2021_IRQ_CRC_ERROR;
      19           2 :   this->irqMap[RADIOLIB_IRQ_CAD_DONE] = RADIOLIB_LR2021_IRQ_CAD_DONE;
      20           2 :   this->irqMap[RADIOLIB_IRQ_CAD_DETECTED] = RADIOLIB_LR2021_IRQ_CAD_DETECTED;
      21           2 :   this->irqMap[RADIOLIB_IRQ_TIMEOUT] = RADIOLIB_LR2021_IRQ_TIMEOUT;
      22           2 :   this->updatePowerLimits(false);
      23           2 : }
      24             : 
      25           0 : int16_t LR2021::begin(const ConfigLoRa_t& cfg) {
      26             :   // set module properties and perform initial setup
      27           0 :   int16_t state = this->modSetup(cfg.frequency, RADIOLIB_LR2021_PACKET_TYPE_LORA);
      28           0 :   RADIOLIB_ASSERT(state);
      29             : 
      30             :   // configure publicly accessible settings
      31           0 :   state = setBandwidth(cfg.bandwidth);
      32           0 :   RADIOLIB_ASSERT(state);
      33             : 
      34           0 :   state = setSpreadingFactor(cfg.spreadingFactor);
      35           0 :   RADIOLIB_ASSERT(state);
      36             : 
      37           0 :   state = setCodingRate(cfg.codingRate);
      38           0 :   RADIOLIB_ASSERT(state);
      39             : 
      40           0 :   state = setSyncWord(cfg.syncWord);
      41           0 :   RADIOLIB_ASSERT(state);
      42             : 
      43           0 :   state = setOutputPower(cfg.power);
      44           0 :   RADIOLIB_ASSERT(state);
      45             : 
      46           0 :   state = setPreambleLength(cfg.preambleLength);
      47           0 :   RADIOLIB_ASSERT(state);
      48             : 
      49             :   // set publicly accessible settings that are not a part of begin method
      50           0 :   state = setCRC(2);
      51           0 :   RADIOLIB_ASSERT(state);
      52             : 
      53           0 :   state = invertIQ(false);
      54           0 :   return(state);
      55             : }
      56             : 
      57           0 : int16_t LR2021::beginGFSK(const ConfigFSK_t& cfg) {
      58           0 :   this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_153_8;
      59           0 :   this->frequencyDev = cfg.frequencyDeviation;
      60             : 
      61             :   // set module properties and perform initial setup
      62           0 :   int16_t state = this->modSetup(cfg.frequency, RADIOLIB_LR2021_PACKET_TYPE_GFSK);
      63           0 :   RADIOLIB_ASSERT(state);
      64             : 
      65             :   // configure publicly accessible settings
      66           0 :   state = setBitRate(cfg.bitRate);
      67           0 :   RADIOLIB_ASSERT(state);
      68             : 
      69           0 :   state = setFrequencyDeviation(cfg.frequencyDeviation);
      70           0 :   RADIOLIB_ASSERT(state);
      71             : 
      72           0 :   state = setRxBandwidth(cfg.receiverBandwidth);
      73           0 :   RADIOLIB_ASSERT(state);
      74             : 
      75           0 :   state = setOutputPower(cfg.power);
      76           0 :   RADIOLIB_ASSERT(state);
      77             : 
      78           0 :   state = setPreambleLength(cfg.preambleLength);
      79           0 :   RADIOLIB_ASSERT(state);
      80             : 
      81             :   // set publicly accessible settings that are not a part of begin method
      82           0 :   uint8_t sync[] = { 0x12, 0xAD };
      83           0 :   state = setSyncWord(sync, 2);
      84           0 :   RADIOLIB_ASSERT(state);
      85             : 
      86           0 :   state = setDataShaping(RADIOLIB_SHAPING_NONE);
      87           0 :   RADIOLIB_ASSERT(state);
      88             : 
      89           0 :   state = setEncoding(RADIOLIB_ENCODING_NRZ);
      90           0 :   RADIOLIB_ASSERT(state);
      91             : 
      92           0 :   state = variablePacketLengthMode(RADIOLIB_LR2021_MAX_PACKET_LENGTH);
      93           0 :   RADIOLIB_ASSERT(state);
      94             : 
      95           0 :   state = setCRC(2);
      96           0 :   return(state);
      97             : }
      98             : 
      99           0 : int16_t LR2021::beginOOK(const ConfigOOK_t& cfg) {
     100           0 :   this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_153_8;
     101             : 
     102             :   // set module properties and perform initial setup
     103           0 :   int16_t state = this->modSetup(cfg.frequency, RADIOLIB_LR2021_PACKET_TYPE_OOK);
     104           0 :   RADIOLIB_ASSERT(state);
     105             : 
     106             :   // configure publicly accessible settings
     107           0 :   state = setBitRate(cfg.bitRate);
     108           0 :   RADIOLIB_ASSERT(state);
     109             : 
     110           0 :   state = setRxBandwidth(cfg.receiverBandwidth);
     111           0 :   RADIOLIB_ASSERT(state);
     112             : 
     113           0 :   state = setOutputPower(cfg.power);
     114           0 :   RADIOLIB_ASSERT(state);
     115             : 
     116           0 :   state = setPreambleLength(cfg.preambleLength);
     117           0 :   RADIOLIB_ASSERT(state);
     118             : 
     119             :   // set publicly accessible settings that are not a part of begin method
     120           0 :   uint8_t sync[] = { 0x12, 0xAD };
     121           0 :   state = setSyncWord(sync, 2);
     122           0 :   RADIOLIB_ASSERT(state);
     123             : 
     124           0 :   state = setDataShaping(RADIOLIB_SHAPING_NONE);
     125           0 :   RADIOLIB_ASSERT(state);
     126             : 
     127           0 :   state = setEncoding(RADIOLIB_ENCODING_NRZ);
     128           0 :   RADIOLIB_ASSERT(state);
     129             : 
     130           0 :   state = variablePacketLengthMode(RADIOLIB_LR2021_MAX_PACKET_LENGTH);
     131           0 :   RADIOLIB_ASSERT(state);
     132             : 
     133           0 :   state = setCRC(2);
     134           0 :   return(state);
     135             : }
     136             : 
     137           0 : int16_t LR2021::beginLRFHSS(const ConfigLRFHSS_t& cfg) {
     138             :   // set module properties and perform initial setup
     139           0 :   int16_t state = this->modSetup(cfg.frequency, RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS);
     140           0 :   RADIOLIB_ASSERT(state);
     141             : 
     142             :   // configure publicly accessible settings
     143           0 :   state = setLrFhssConfig(cfg.bandwidth, cfg.codingRate, cfg.narrowGrid);
     144           0 :   RADIOLIB_ASSERT(state);
     145             : 
     146           0 :   state = setOutputPower(cfg.power);
     147           0 :   RADIOLIB_ASSERT(state);
     148             : 
     149           0 :   uint8_t syncWord[] = { 0x12, 0xAD, 0x10, 0x1B };
     150           0 :   state = setSyncWord(syncWord, 4);
     151           0 :   return(state);
     152             : }
     153             : 
     154           0 : int16_t LR2021::beginFLRC(const ConfigFLRC_t& cfg) {
     155             :   // initialize FLRC modulation variables
     156           0 :   this->bitRateFlrc = cfg.bitRate;
     157           0 :   this->codingRateFlrc = RADIOLIB_LR2021_FLRC_CR_3_4;
     158           0 :   this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_0_5;
     159             : 
     160             :   // initialize FLRC packet variables
     161           0 :   this->preambleLengthGFSK = cfg.preambleLength;
     162           0 :   this->crcLenGFSK = 1;
     163             : 
     164             :   // set module properties and perform initial setup
     165           0 :   int16_t state = this->modSetup(cfg.frequency, RADIOLIB_LR2021_PACKET_TYPE_FLRC);
     166           0 :   RADIOLIB_ASSERT(state);
     167             : 
     168             :   // configure publicly accessible settings
     169           0 :   state = setBitRate(cfg.bitRate);
     170           0 :   RADIOLIB_ASSERT(state);
     171             : 
     172           0 :   state = setCodingRate(cfg.codingRate);
     173           0 :   RADIOLIB_ASSERT(state);
     174             : 
     175           0 :   state = setOutputPower(cfg.power);
     176           0 :   RADIOLIB_ASSERT(state);
     177             : 
     178           0 :   state = setPreambleLength(cfg.preambleLength);
     179           0 :   RADIOLIB_ASSERT(state);
     180             : 
     181           0 :   state = setDataShaping(cfg.dataShaping);
     182           0 :   RADIOLIB_ASSERT(state);
     183             : 
     184             :   // set publicly accessible settings that are not a part of begin method
     185           0 :   uint8_t sync[] = { 0x2D, 0x01, 0x4B, 0x1D};
     186           0 :   state = setSyncWord(sync, 4);
     187           0 :   RADIOLIB_ASSERT(state);
     188             : 
     189           0 :   state = variablePacketLengthMode(RADIOLIB_LR2021_MAX_PACKET_LENGTH);
     190           0 :   RADIOLIB_ASSERT(state);
     191             : 
     192           0 :   state = setCRC(2);
     193           0 :   return(state);
     194             : }
     195             : 
     196           2 : int16_t LR2021::transmit(const uint8_t* data, size_t len, uint8_t addr) {
     197             :    // set mode to standby
     198           2 :   int16_t state = standby();
     199           2 :   RADIOLIB_ASSERT(state);
     200             : 
     201             :   // check packet length
     202           0 :   if (this->codingRate > RADIOLIB_LR2021_LORA_CR_4_8) {
     203             :     // Long Interleaver needs at least 8 bytes
     204           0 :     if(len < 8) {
     205           0 :       return(RADIOLIB_ERR_PACKET_TOO_SHORT);
     206             :     }
     207             : 
     208             :     // Long Interleaver supports up to 253 bytes if CRC is enabled
     209           0 :     if (this->crcTypeLoRa == RADIOLIB_LRXXXX_LORA_CRC_ENABLED && (len > RADIOLIB_LR2021_MAX_PACKET_LENGTH - 2)) {
     210           0 :       return(RADIOLIB_ERR_PACKET_TOO_LONG);
     211             :     }  
     212             :   } 
     213           0 :   if(len > RADIOLIB_LR2021_MAX_PACKET_LENGTH) {
     214           0 :     return(RADIOLIB_ERR_PACKET_TOO_LONG);
     215             :   }
     216             : 
     217             :   // get currently active modem
     218           0 :   uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     219           0 :   state = getPacketType(&modem);
     220           0 :   RADIOLIB_ASSERT(state);
     221           0 :   RadioLibTime_t timeout = getTimeOnAir(len);
     222           0 :   if(modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) {
     223             :     // calculate timeout (150% of expected time-on-air)
     224           0 :     timeout = (timeout * 3) / 2;
     225             : 
     226           0 :   } else if((modem == RADIOLIB_LR2021_PACKET_TYPE_GFSK) || 
     227           0 :             (modem == RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS) ||
     228           0 :             (modem == RADIOLIB_LR2021_PACKET_TYPE_FLRC) ||
     229           0 :             (modem == RADIOLIB_LR2021_PACKET_TYPE_OOK)) {
     230             :     // calculate timeout (500% of expected time-on-air)
     231           0 :     timeout = timeout * 5;
     232             : 
     233             :   } else {
     234           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     235             :   }
     236             : 
     237             :   RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout);
     238             : 
     239             :   // start transmission
     240           0 :   state = startTransmit(data, len, addr);
     241           0 :   RADIOLIB_ASSERT(state);
     242             : 
     243             :   // wait for packet transmission or timeout
     244           0 :   RadioLibTime_t start = this->mod->hal->micros();
     245           0 :   while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
     246           0 :     this->mod->hal->yield();
     247           0 :     if(this->mod->hal->micros() - start > timeout) {
     248           0 :       finishTransmit();
     249           0 :       return(RADIOLIB_ERR_TX_TIMEOUT);
     250             :     }
     251             :   }
     252             : 
     253           0 :   return(finishTransmit());
     254             : }
     255             : 
     256           2 : int16_t LR2021::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) {
     257             :   // set mode to standby
     258           2 :   int16_t state = standby();
     259           2 :   RADIOLIB_ASSERT(state);
     260             : 
     261             :   // calculate timeout based on the configured modem
     262           0 :   RadioLibTime_t timeoutInternal = timeout;
     263           0 :   if(!timeoutInternal) {
     264             :     // get currently active modem
     265           0 :     uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     266           0 :     state = getPacketType(&modem);
     267           0 :     RADIOLIB_ASSERT(state);
     268           0 :     if((modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) ||
     269           0 :        (modem == RADIOLIB_LR2021_PACKET_TYPE_GFSK) ||
     270           0 :        (modem == RADIOLIB_LR2021_PACKET_TYPE_FLRC) ||
     271           0 :        (modem == RADIOLIB_LR2021_PACKET_TYPE_OOK)) {
     272             :       // calculate timeout (500 % of expected time-one-air)
     273           0 :       size_t maxLen = len;
     274           0 :       if(len == 0) { maxLen = RADIOLIB_LR2021_MAX_PACKET_LENGTH; }
     275           0 :       timeoutInternal = (getTimeOnAir(maxLen) * 5) / 1000;
     276             :     
     277           0 :     } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS) {
     278             :       // this modem cannot receive
     279           0 :       return(RADIOLIB_ERR_WRONG_MODEM);
     280             : 
     281             :     } else {
     282           0 :       return(RADIOLIB_ERR_UNKNOWN);
     283             :     
     284             :     }
     285             :   }
     286             : 
     287             :   RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeoutInternal);
     288             : 
     289             :   // start reception
     290           0 :   uint32_t timeoutValue = (uint32_t)((float)timeoutInternal * (1000.0f / 30.52f));
     291           0 :   state = startReceive(timeoutValue);
     292           0 :   RADIOLIB_ASSERT(state);
     293             : 
     294             :   // wait for packet reception or timeout
     295           0 :   bool softTimeout = false;
     296           0 :   RadioLibTime_t start = this->mod->hal->millis();
     297           0 :   while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
     298           0 :     this->mod->hal->yield();
     299             :     // safety check, the timeout should be done by the radio
     300           0 :     if(this->mod->hal->millis() - start > timeoutInternal) {
     301           0 :       softTimeout = true;
     302           0 :       break;
     303             :     }
     304             :   }
     305             : 
     306             :   // if it was a timeout, this will return an error code
     307             :   //! \TODO: [LR2021] taken from SX126x, does this really work?
     308           0 :   state = standby();
     309           0 :   if((state != RADIOLIB_ERR_NONE) && (state != RADIOLIB_ERR_SPI_CMD_TIMEOUT)) {
     310           0 :     return(state);
     311             :   }
     312             : 
     313             :   // check whether this was a timeout or not
     314           0 :   if(softTimeout || (getIrqFlags() & this->irqMap[RADIOLIB_IRQ_TIMEOUT])) {
     315           0 :     (void)finishReceive();
     316           0 :     return(RADIOLIB_ERR_RX_TIMEOUT);
     317             :   }
     318             : 
     319             :   // read the received data
     320           0 :   return(readData(data, len));
     321             : }
     322             : 
     323           2 : int16_t LR2021::transmitDirect(uint32_t frf) {
     324             :   // set RF switch (if present)
     325           2 :   this->mod->setRfSwitchState(Module::MODE_TX);
     326             : 
     327             :   // user requested to start transmitting immediately (required for RTTY)
     328           2 :   int16_t state = RADIOLIB_ERR_NONE;
     329           2 :   if(frf != 0) {
     330           0 :     state = setRfFrequency(frf);
     331             :   }
     332           2 :   RADIOLIB_ASSERT(state);
     333             : 
     334             :   // start transmitting
     335           2 :   return(setTxTestMode(RADIOLIB_LR2021_TX_TEST_MODE_CW));
     336             : }
     337             : 
     338           2 : int16_t LR2021::receiveDirect() {
     339             :   // set RF switch (if present)
     340           2 :   this->mod->setRfSwitchState(Module::MODE_RX);
     341             : 
     342             :   // LR2021 is unable to output received data directly
     343           2 :   return(RADIOLIB_ERR_UNKNOWN);
     344             : }
     345             : 
     346           2 : int16_t LR2021::scanChannel() {
     347           2 :   ChannelScanConfig_t cfg = {
     348             :     .cad = {
     349             :       .symNum = RADIOLIB_LR2021_CAD_PARAM_DEFAULT,
     350             :       .detPeak = RADIOLIB_LR2021_CAD_PARAM_DEFAULT,
     351             :       .detMin = RADIOLIB_LR2021_CAD_PARAM_DEFAULT,
     352             :       .exitMode = RADIOLIB_LR2021_CAD_PARAM_DEFAULT,
     353             :       .rxTimeout = 0,
     354             :       .rxSymbols = 0,
     355             :       .irqFlags = RADIOLIB_IRQ_CAD_DEFAULT_FLAGS,
     356             :       .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK,
     357             :     },
     358             :   };
     359           4 :   return(this->scanChannel(cfg));
     360             : }
     361             : 
     362           4 : int16_t LR2021::scanChannel(const ChannelScanConfig_t &cfg) {
     363             :   // set mode to CAD
     364           4 :   int state = startChannelScan(cfg);
     365           4 :   RADIOLIB_ASSERT(state);
     366             : 
     367             :   // wait for channel activity detected or timeout
     368           0 :   while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
     369           0 :     this->mod->hal->yield();
     370             :   }
     371             : 
     372             :   // check CAD result
     373           0 :   return(getChannelScanResult());
     374             : }
     375             : 
     376           8 : int16_t LR2021::standby() {
     377           8 :   return(LR2021::standby(this->standbyXOSC ? RADIOLIB_LR2021_STANDBY_XOSC : RADIOLIB_LR2021_STANDBY_RC));
     378             : }
     379             : 
     380          10 : int16_t LR2021::standby(uint8_t mode) {
     381          10 :   return(this->standby(mode, true));
     382             : }
     383             : 
     384          10 : int16_t LR2021::standby(uint8_t mode, bool wakeup) {
     385             :   // set RF switch (if present)
     386          10 :   this->mod->setRfSwitchState(Module::MODE_IDLE);
     387             : 
     388          10 :   if(wakeup) {
     389             :     // send a NOP command - this pulls the NSS low to exit the sleep mode,
     390             :     // while preventing interference with possible other SPI transactions
     391          10 :     (void)this->mod->SPIwriteStream((uint16_t)RADIOLIB_LR2021_CMD_NOP, NULL, 0, false, false);
     392             :   }
     393             :   
     394          10 :   uint8_t buff[] = { mode };
     395          20 :   return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_STANDBY, true, buff, sizeof(buff)));
     396             : }
     397             : 
     398           2 : int16_t LR2021::sleep() {
     399           2 :   return(this->sleep(true, 0));
     400             : }
     401             : 
     402           2 : int16_t LR2021::sleep(bool retainConfig, uint32_t sleepTime) {
     403             :   // set RF switch (if present)
     404           2 :   this->mod->setRfSwitchState(Module::MODE_IDLE);
     405             : 
     406             :   uint8_t buff[] = { (uint8_t)(retainConfig ? RADIOLIB_LR2021_SLEEP_RETENTION_ENABLED : RADIOLIB_LR2021_SLEEP_RETENTION_DISABLED),
     407           2 :     (uint8_t)((sleepTime >> 24) & 0xFF), (uint8_t)((sleepTime >> 16) & 0xFF),
     408           2 :     (uint8_t)((sleepTime >> 8) & 0xFF), (uint8_t)(sleepTime & 0xFF),
     409           2 :   };
     410             : 
     411             :   // in sleep, the busy line will remain high, so we have to use this method to disable waiting for it to go low
     412           2 :   int16_t state = this->mod->SPIwriteStream(RADIOLIB_LR2021_CMD_SET_SLEEP, buff, sizeof(buff), false, false);
     413             : 
     414             :   // wait for the module to safely enter sleep mode
     415           2 :   this->mod->hal->delay(1);
     416             : 
     417           2 :   return(state);
     418             : }
     419             : 
     420           2 : size_t LR2021::getPacketLength(bool update) {
     421             :   (void)update;
     422             : 
     423             :   // in implicit mode, return the cached value
     424           2 :   uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     425           2 :   (void)getPacketType(&type);
     426           2 :   if((type == RADIOLIB_LR2021_PACKET_TYPE_LORA) && (this->headerType == RADIOLIB_LRXXXX_LORA_HEADER_IMPLICIT)) {
     427           0 :     return(this->implicitLen);
     428             :   }
     429             : 
     430           2 :   uint16_t len = 0;
     431           2 :   (void)getRxPktLength(&len);
     432           2 :   return((size_t)len);
     433             : }
     434             : 
     435           2 : int16_t LR2021::startReceive() {
     436           2 :   return(this->startReceive(RADIOLIB_LR2021_RX_TIMEOUT_INF, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0));
     437             : }
     438             : 
     439           0 : int16_t LR2021::startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask) {
     440             :   // datasheet claims time to go to sleep is ~500us, same to wake up, compensate for that with 1 ms + TCXO delay
     441           0 :   uint32_t transitionTime = this->tcxoDelay + 1000;
     442           0 :   sleepPeriod -= transitionTime;
     443             : 
     444             :   // divide by 30.517 microseconds (RTC period, 1/32.768 kHz)
     445             :   // the datasheet claims the RTC frequency is 32 kHz; however, using that makes the timing inaccurate
     446             :   // so it looks like the actual value is the 32.768 kHz used on the previous LR11xx chips
     447           0 :   uint32_t rxPeriodRaw = (uint32_t)(((uint64_t)rxPeriod * 34360) >> 20);
     448           0 :   uint32_t sleepPeriodRaw = (uint32_t)(((uint64_t)sleepPeriod * 34360) >> 20);
     449             : 
     450             :   // check 24 bit limit and zero value (likely not intended)
     451           0 :   if((rxPeriodRaw & 0xFF000000) || (rxPeriodRaw == 0)) {
     452           0 :     return(RADIOLIB_ERR_INVALID_RX_PERIOD);
     453             :   }
     454             : 
     455             :   // this check of the high byte also catches underflow when we subtracted transitionTime
     456           0 :   if((sleepPeriodRaw & 0xFF000000) || (sleepPeriodRaw == 0)) {
     457           0 :     return(RADIOLIB_ERR_INVALID_SLEEP_PERIOD);
     458             :   }
     459             : 
     460             :   // set up Rx mode
     461           0 :   RadioModeConfig_t cfg = {
     462             :     .receive = {
     463             :       .timeout = RADIOLIB_LR2021_RX_TIMEOUT_INF,
     464             :       .syncSymbols = 0,
     465             :       .irqFlags = irqFlags,
     466             :       .irqMask = irqMask,
     467             :       .len = 0,
     468             :     }
     469           0 :   };
     470           0 :   int16_t state = this->stageMode(RADIOLIB_RADIO_MODE_RX, &cfg);
     471           0 :   RADIOLIB_ASSERT(state);
     472             : 
     473             :   // on LR2021, the second parameter is total period of the cycle, not the sleep duration
     474           0 :   return(this->setRxDutyCycle(rxPeriodRaw, rxPeriodRaw + sleepPeriodRaw, RADIOLIB_LR2021_RX_DUTY_CYCLE_MODE_RX));
     475             : }
     476             : 
     477           0 : int16_t LR2021::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_t minSymbols, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask) {
     478             :   // calculate the sleep and wake periods
     479           0 :   uint32_t wakePeriod = 0;
     480           0 :   uint32_t sleepPeriod = 0;
     481             :   DataRate_t dr = {
     482             :     .lora = {
     483           0 :       .spreadingFactor = this->spreadingFactor,
     484           0 :       .bandwidth = this->bandwidthHz,
     485           0 :       .codingRate = this->codingRate,
     486             :     }
     487           0 :   };
     488           0 :   int16_t state = calculateRxDutyCycle(senderPreambleLength, this->preambleLengthLoRa, minSymbols, &dr, &wakePeriod, &sleepPeriod);
     489           0 :   RADIOLIB_ASSERT(state);
     490             : 
     491             :   // If our sleep period is shorter than our transition time, just use the standard startReceive
     492           0 :   if(sleepPeriod < this->tcxoDelay + 1016) {
     493           0 :     return(startReceive(RADIOLIB_LR2021_RX_TIMEOUT_INF, irqFlags, irqMask));
     494             :   }
     495             : 
     496           0 :   return(startReceiveDutyCycle(wakePeriod, sleepPeriod, irqFlags, irqMask));
     497             : }
     498             : 
     499           2 : int16_t LR2021::readData(uint8_t* data, size_t len) {
     500             :   // check active modem
     501           2 :   int16_t state = RADIOLIB_ERR_NONE;
     502           2 :   uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     503           2 :   state = getPacketType(&modem);
     504           2 :   RADIOLIB_ASSERT(state);
     505           0 :   if((modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) && 
     506           0 :      (modem != RADIOLIB_LR2021_PACKET_TYPE_GFSK) && 
     507           0 :      (modem != RADIOLIB_LR2021_PACKET_TYPE_FLRC) && 
     508           0 :      (modem != RADIOLIB_LR2021_PACKET_TYPE_OOK)) {
     509           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     510             :   }
     511             : 
     512             :   // check integrity CRC
     513           0 :   uint32_t irq = getIrqStatus();
     514           0 :   int16_t crcState = RADIOLIB_ERR_NONE;
     515             :   // report CRC mismatch when there's a payload CRC error
     516           0 :   if(irq & RADIOLIB_LR2021_IRQ_CRC_ERROR) {
     517           0 :     crcState = RADIOLIB_ERR_CRC_MISMATCH;
     518             :   }
     519             : 
     520             :   // // for LoRa modem and explicit header mode, check also also header valid flag
     521             :   // if((modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) &&
     522             :   //    (this->headerType == RADIOLIB_LRXXXX_LORA_HEADER_EXPLICIT) && 
     523             :   //    (!(irq & RADIOLIB_LR2021_IRQ_LORA_HEADER_VALID))) {
     524             :   //   crcState = RADIOLIB_ERR_LORA_HEADER_DAMAGED;
     525             :   // }
     526             : 
     527             :   // get packet length
     528           0 :   size_t length = getPacketLength();
     529           0 :   if((len != 0) && (len < length)) {
     530             :     // user requested less data than we got, only return what was requested
     531           0 :     length = len;
     532             :   }
     533             : 
     534             :   // read packet data
     535           0 :   state = readRadioRxFifo(data, length);
     536           0 :   RADIOLIB_ASSERT(state);
     537             : 
     538             :   // clear the Rx buffer
     539           0 :   state = clearRxFifo();
     540           0 :   RADIOLIB_ASSERT(state);
     541             : 
     542             :   // clear interrupt flags
     543           0 :   state = clearIrqState(RADIOLIB_LR2021_IRQ_ALL);
     544             : 
     545             :   // check if CRC failed - this is done after reading data to give user the option to keep them
     546           0 :   RADIOLIB_ASSERT(crcState);
     547             : 
     548           0 :   return(state);
     549             : }
     550             : 
     551           2 : int16_t LR2021::finishReceive() {
     552             :   // set mode to standby to disable RF switch
     553           2 :   int16_t state = standby();
     554           2 :   RADIOLIB_ASSERT(state);
     555             : 
     556             :   // clear interrupt flags
     557           0 :   return(clearIrqState(RADIOLIB_LR2021_IRQ_ALL));
     558             : }
     559             : 
     560           2 : int16_t LR2021::startChannelScan() {
     561           2 :   ChannelScanConfig_t cfg = {
     562             :     .cad = {
     563             :       .symNum = RADIOLIB_LR2021_CAD_PARAM_DEFAULT,
     564             :       .detPeak = RADIOLIB_LR2021_CAD_PARAM_DEFAULT,
     565             :       .detMin = RADIOLIB_LR2021_CAD_PARAM_DEFAULT,
     566             :       .exitMode = RADIOLIB_LR2021_CAD_PARAM_DEFAULT,
     567             :       .rxTimeout = 0,
     568             :       .rxSymbols = 0,
     569             :       .irqFlags = RADIOLIB_IRQ_CAD_DEFAULT_FLAGS,
     570             :       .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK,
     571             :     },
     572             :   };
     573           4 :   return(this->startChannelScan(cfg));
     574             : }
     575             : 
     576           8 : int16_t LR2021::startChannelScan(const ChannelScanConfig_t &cfg) {
     577             :   // check active modem
     578           8 :   int16_t state = RADIOLIB_ERR_NONE;
     579           8 :   uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     580           8 :   state = getPacketType(&modem);
     581           8 :   RADIOLIB_ASSERT(state);
     582           0 :   if(modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
     583           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     584             :   }
     585             : 
     586             :   // set mode to standby
     587           0 :   state = standby();
     588           0 :   RADIOLIB_ASSERT(state);
     589             : 
     590             :   // set RF switch (if present)
     591           0 :   this->mod->setRfSwitchState(Module::MODE_RX);
     592             : 
     593             :   // set DIO pin mapping
     594           0 :   uint32_t irqFlags = (cfg.cad.irqFlags == RADIOLIB_IRQ_NOT_SUPPORTED) ? RADIOLIB_LR2021_IRQ_CAD_DETECTED | RADIOLIB_LR2021_IRQ_CAD_DONE : cfg.cad.irqFlags;
     595           0 :   state = setDioIrqConfig(this->irqDioNum, getIrqMapped(irqFlags));
     596           0 :   RADIOLIB_ASSERT(state);
     597             : 
     598             :   // clear interrupt flags
     599           0 :   state = clearIrqState(RADIOLIB_LR2021_IRQ_ALL);
     600           0 :   RADIOLIB_ASSERT(state);
     601             : 
     602             :   // set LoRa symbol timeout
     603           0 :   state = setLoRaSynchTimeout(cfg.cad.rxSymbols);
     604           0 :   RADIOLIB_ASSERT(state);
     605             :   
     606             :   // set mode to CAD
     607           0 :   return(startCad(cfg.cad.symNum, cfg.cad.detPeak, this->fastCad, cfg.cad.exitMode, cfg.cad.rxTimeout));
     608             : }
     609             : 
     610           2 : int16_t LR2021::getChannelScanResult() {
     611             :   // check active modem
     612           2 :   int16_t state = RADIOLIB_ERR_NONE;
     613           2 :   uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     614           2 :   state = getPacketType(&modem);
     615           2 :   RADIOLIB_ASSERT(state);
     616           0 :   if(modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
     617           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     618             :   }
     619             : 
     620             :   // check CAD result
     621           0 :   uint32_t cadResult = getIrqStatus();
     622           0 :   if(cadResult & RADIOLIB_LR2021_IRQ_CAD_DETECTED) {
     623             :     // detected some LoRa activity
     624           0 :     return(RADIOLIB_LORA_DETECTED);
     625           0 :   } else if(cadResult & RADIOLIB_LR2021_IRQ_CAD_DONE) {
     626             :     // channel is free
     627           0 :     return(RADIOLIB_CHANNEL_FREE);
     628             :   }
     629             : 
     630           0 :   return(RADIOLIB_ERR_UNKNOWN);
     631             : }
     632             : 
     633           2 : uint32_t LR2021::getIrqFlags() {
     634           2 :   return(getIrqStatus());
     635             : }
     636             : 
     637           2 : int16_t LR2021::setIrqFlags(uint32_t irq) {
     638           2 :   return(this->setDioIrqConfig(this->irqDioNum, irq));
     639             : }
     640             : 
     641           4 : int16_t LR2021::clearIrqFlags(uint32_t irq) {
     642           4 :   return(this->clearIrqState(irq));
     643             : }
     644             : 
     645           2 : int16_t LR2021::setModem(ModemType_t modem) {
     646           2 :   switch(modem) {
     647           0 :     case(ModemType_t::RADIOLIB_MODEM_LORA): {
     648           0 :       ConfigLoRa_t cfg;
     649           0 :       return(this->begin(cfg));
     650             :     } break;
     651           0 :     case(ModemType_t::RADIOLIB_MODEM_FSK): {
     652           0 :       ConfigFSK_t cfg;
     653           0 :       return(this->beginGFSK(cfg));
     654             :     } break;
     655           0 :     case(ModemType_t::RADIOLIB_MODEM_LRFHSS): {
     656           0 :       ConfigLRFHSS_t cfg;
     657           0 :       return(this->beginLRFHSS(cfg));
     658             :     } break;
     659           2 :     default:
     660           2 :       return(RADIOLIB_ERR_WRONG_MODEM);
     661             :   }
     662             :   return(RADIOLIB_ERR_WRONG_MODEM);
     663             : }
     664             : 
     665           0 : Module* LR2021::getMod() {
     666           0 :   return(this->mod);
     667             : }
     668             : 
     669           0 : int16_t LR2021::modSetup(uint32_t freq, uint8_t modem) {
     670           0 :   int16_t state = this->mod->init();
     671           0 :   RADIOLIB_ASSERT(state);
     672           0 :   this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
     673           0 :   this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput);
     674           0 :   this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_LR2021_CMD_READ_REG_MEM_32;
     675           0 :   this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_LR2021_CMD_WRITE_REG_MEM_32;
     676           0 :   this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_LR2021_CMD_NOP;
     677           0 :   this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_LR2021_CMD_GET_STATUS;
     678           0 :   this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_24;
     679           0 :   this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_16;
     680             : 
     681             :   // try to find the chip - this will also reset the module at least once
     682           0 :   if(!this->findChip()) {
     683             :     RADIOLIB_DEBUG_BASIC_PRINTLN("No %s found!", this->chipName());
     684           0 :     state = this->mod->term();
     685           0 :     RADIOLIB_ASSERT(state);
     686           0 :     return(RADIOLIB_ERR_CHIP_NOT_FOUND);
     687             :   }
     688             :   RADIOLIB_DEBUG_BASIC_PRINTLN("M\t%s", this->chipName());
     689             : 
     690             :   // set mode to standby
     691             :   // force the device to use RC oscillator, as XOSC may not be ready yet
     692           0 :   state = standby(RADIOLIB_LR2021_STANDBY_RC);
     693           0 :   RADIOLIB_ASSERT(state);
     694             : 
     695             :   // set TCXO control, if requested
     696           0 :   if(this->tcxoVoltage != RadioLibTCXOVoltage_t::VoltageNone) {
     697           0 :     state = setTCXO(this->tcxoVoltage);
     698           0 :     RADIOLIB_ASSERT(state);
     699             :   }
     700             : 
     701             :   // configure settings not accessible by API
     702           0 :   state = config(modem);
     703           0 :   RADIOLIB_ASSERT(state);
     704             : 
     705             :   // restore RF switch configuration, if it exists
     706             :   uint32_t pins[Module::RFSWITCH_MAX_PINS];
     707           0 :   const Module::RfSwitchMode_t* table = nullptr;
     708           0 :   this->mod->getRfSwitchTable(pins, &table);
     709           0 :   if(table != nullptr) {
     710           0 :     this->setRfSwitchTable(pins, table);
     711             :   }
     712             : 
     713           0 :   state = setFrequency(freq);
     714           0 :   return(state);
     715             : }
     716             : 
     717           0 : const char* LR2021::chipName(void) const {
     718           0 :   switch(this->chipType) {
     719           0 :     case(RADIOLIB_LR2021_DEVICE_LR2022):
     720           0 :       return("LR2022");
     721           0 :     case(RADIOLIB_LR2021_DEVICE_LR2012):
     722           0 :       return("LR2012");
     723           0 :     default:
     724           0 :       return("LR2021");
     725             :   }
     726             : }
     727             : 
     728           2 : bool LR2021::subGhzOnly(void) const {
     729             :   // the LR2012 has no high-frequency front end at all - no HF PA, no HF LNA, no HF mixer
     730           2 :   return(this->chipType == RADIOLIB_LR2021_DEVICE_LR2012);
     731             : }
     732             : 
     733           0 : bool LR2021::findChip(void) {
     734             :   // the LR2021 reports 1.24, the LR2022 and LR2012 both report 2.0
     735           0 :   const uint16_t expVersion = (this->chipType == RADIOLIB_LR2021_DEVICE_LR2021) ? RADIOLIB_LR2021_FW_LR2021 : RADIOLIB_LR2021_FW_LR20X2;
     736           0 :   const uint8_t expMajor = (uint8_t)(expVersion >> 8);
     737           0 :   const uint8_t expMinor = (uint8_t)(expVersion & 0xFF);
     738             : 
     739           0 :   uint8_t i = 0;
     740           0 :   bool flagFound = false;
     741           0 :   uint8_t fwMajor = 0, fwMinor = 0;
     742           0 :   while((i < 10) && !flagFound) {
     743             :     // reset the module
     744           0 :     reset();
     745             : 
     746             :     // read the version
     747           0 :     int16_t state = getVersion(&fwMajor, &fwMinor);
     748           0 :     RADIOLIB_ASSERT(state);
     749             : 
     750           0 :     if((fwMajor == expMajor) && (fwMinor == expMinor)) {
     751             :       RADIOLIB_DEBUG_BASIC_PRINTLN("Found %s", this->chipName());
     752             :       RADIOLIB_DEBUG_BASIC_PRINTLN("Base FW version: %d.%d", (int)fwMajor, (int)fwMinor);
     753           0 :       flagFound = true;
     754             :     } else {
     755             :       RADIOLIB_DEBUG_BASIC_PRINTLN("%s not found! (%d of 10 tries) FW version: = %d.%d", this->chipName(), (int)i, (int)fwMajor, (int)fwMinor);
     756             :       RADIOLIB_DEBUG_BASIC_PRINTLN("Expected: %d.%d", (int)expMajor, (int)expMinor);
     757           0 :       this->mod->hal->delay(10);
     758           0 :       i++;
     759             :     }
     760             :   }
     761             : 
     762           0 :   return(flagFound);
     763             : }
     764             : 
     765           0 : int16_t LR2021::config(uint8_t modem) {
     766             :   // set Rx/Tx fallback mode
     767           0 :   int16_t state = this->setRxTxFallbackMode(this->standbyXOSC ? RADIOLIB_LR2021_FALLBACK_MODE_STBY_XOSC : RADIOLIB_LR2021_FALLBACK_MODE_STBY_RC);
     768           0 :   RADIOLIB_ASSERT(state);
     769             : 
     770             :   // clear IRQ
     771           0 :   state = this->clearIrqState(RADIOLIB_LR2021_IRQ_ALL);
     772           0 :   RADIOLIB_ASSERT(state);
     773             : 
     774             :   // validate DIO pin number
     775           0 :   if((this->irqDioNum < 5) || (this->irqDioNum > 11)) {
     776           0 :     return(RADIOLIB_ERR_INVALID_DIO_PIN);
     777             :   }
     778             : 
     779             :   // set the DIO to IRQ
     780             :   // DIO5 can only be pull up
     781           0 :   uint8_t pull = this->irqDioNum == 5 ? RADIOLIB_LR2021_DIO_SLEEP_PULL_UP : RADIOLIB_LR2021_DIO_SLEEP_PULL_DOWN;
     782           0 :   state = this->setDioFunction(this->irqDioNum, RADIOLIB_LR2021_DIO_FUNCTION_IRQ, pull);
     783           0 :   RADIOLIB_ASSERT(state);
     784             : 
     785             :   // calibrate all blocks
     786           0 :   state = this->calibrate(RADIOLIB_LR2021_CALIBRATE_ALL);
     787             : 
     788             :   // wait for calibration completion
     789           0 :   this->mod->hal->delay(5);
     790           0 :   while(this->mod->hal->digitalRead(this->mod->getGpio())) {
     791           0 :     this->mod->hal->yield();
     792             :   }
     793             :   
     794             :   // if something failed, show the device errors
     795             :   #if RADIOLIB_DEBUG_BASIC
     796             :   if(state != RADIOLIB_ERR_NONE) {
     797             :     uint16_t errors = 0;
     798             :     getErrors(&errors);
     799             :     RADIOLIB_DEBUG_BASIC_PRINTLN("Calibration failed, device errors: 0x%X", errors);
     800             :   }
     801             :   #endif
     802           0 :   RADIOLIB_ASSERT(state);
     803             : 
     804             :   // set modem
     805           0 :   state = this->setPacketType(modem);
     806           0 :   return(state);
     807             : }
     808             : 
     809           0 : int16_t LR2021::startCad(uint8_t symbolNum, uint8_t detPeak, bool fast, uint8_t exitMode, RadioLibTime_t timeout) {
     810             :   // check active modem
     811           0 :   uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     812           0 :   int16_t state = getPacketType(&type);
     813           0 :   RADIOLIB_ASSERT(state);
     814           0 :   if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
     815           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     816             :   }
     817             : 
     818             :   // select CAD parameters
     819           0 :   uint8_t num = symbolNum;
     820           0 :   if(num == RADIOLIB_LR2021_CAD_PARAM_DEFAULT) {
     821           0 :     num = 2;
     822             :   }
     823             :   
     824             :   // reference values ​​from the datasheet for 2 symbols
     825             :   //! \TODO: [LR2021] allow CAD peak detection autoconfiguration
     826           0 :   const uint8_t detPeakValues[8] = { 56, 56, 56, 58, 58, 60, 64, 68 };
     827           0 :   uint8_t peak = detPeak;
     828           0 :   if(peak == RADIOLIB_LR2021_CAD_PARAM_DEFAULT) {
     829           0 :     peak = detPeakValues[this->spreadingFactor - 5];
     830             :   }
     831             : 
     832             :   // in Fast CAD mode enable acceleration
     833           0 :   uint8_t pnrDelta = fast ? RADIOLIB_LR2021_LORA_CAD_PNR_DELTA_FAST : RADIOLIB_LR2021_LORA_CAD_PNR_DELTA_STANDARD;
     834             : 
     835           0 :   uint8_t mode = exitMode; 
     836           0 :   if(mode == RADIOLIB_LR2021_CAD_PARAM_DEFAULT) {
     837           0 :     mode = RADIOLIB_LR2021_LORA_CAD_EXIT_MODE_FALLBACK;
     838             :   }
     839             : 
     840           0 :   uint32_t timeout_raw = (uint32_t)((float)timeout * (1.0f / 30.52f));
     841             : 
     842             :   // set LoRa CAD parameters
     843             :   // preamble only mode is intentionally disabled, as it is unreliable according to the datasheet
     844           0 :   state = setLoRaCadParams(num, false, pnrDelta, mode, timeout_raw, peak);
     845           0 :   RADIOLIB_ASSERT(state);
     846             : 
     847             :   // start LoraCAD
     848           0 :   return(setLoRaCad());
     849             : }
     850             : 
     851           2 : void LR2021::updatePowerLimits(bool highFreq) {
     852           2 :   if(highFreq) {
     853           0 :     this->powerMin = RADIOLIB_LR2021_HF_POUT_MIN;
     854           0 :     this->powerMax = RADIOLIB_LR2021_HF_POUT_MAX;
     855             :   } else {
     856           2 :     this->powerMin = RADIOLIB_LR2021_LF_POUT_MIN;
     857           2 :     this->powerMax = RADIOLIB_LR2021_LF_POUT_MAX;
     858             :   }
     859           2 :   this->paSteps = this->powerMax - this->powerMin + 1;
     860           2 : }
     861             : 
     862           2 : RadioLibTime_t LR2021::getTimeOnAir(size_t len) {
     863           2 :   uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     864           2 :   int16_t state = getPacketType(&type);
     865           2 :   RADIOLIB_ASSERT(state);
     866             : 
     867           0 :   switch(type) {
     868             :     // basic modems are supported by the LRxxxx base class
     869           0 :     case(RADIOLIB_LR2021_PACKET_TYPE_LORA):
     870           0 :       return(LRxxxx::getToA(len, ModemType_t::RADIOLIB_MODEM_LORA));
     871           0 :     case(RADIOLIB_LR2021_PACKET_TYPE_GFSK):
     872           0 :       return(LRxxxx::getToA(len, ModemType_t::RADIOLIB_MODEM_FSK));
     873           0 :     case(RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS):
     874           0 :       return(LRxxxx::getToA(len, ModemType_t::RADIOLIB_MODEM_LRFHSS));
     875           0 :     case(RADIOLIB_LR2021_PACKET_TYPE_FLRC): {
     876             :       //! \todo [LR2021] Add FLRC to the modems supported in ModemType_t
     877             : 
     878             :       // calculate the bits of the uncoded part of the packet
     879           0 :       size_t n_uncoded_bits = (this->preambleLengthGFSK + 1)*4 + 21 + this->syncWordLength*8;
     880           0 :       if(this->packetType != RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) { n_uncoded_bits+= 16; }
     881             : 
     882             :       // calculate bits in the coded part
     883           0 :       size_t n_coded_bits = len*8;
     884           0 :       if(this->crcLenGFSK != 0) { n_coded_bits += (this->crcLenGFSK + 1)*8; }
     885           0 :       if(this->codingRateFlrc <= RADIOLIB_LR2021_FLRC_CR_3_4) { n_coded_bits += 6; }
     886           0 :       float n_coded_bits_flt = n_coded_bits;
     887           0 :       switch(this->codingRateFlrc) {
     888           0 :         case(RADIOLIB_LR2021_FLRC_CR_1_2):
     889           0 :           n_coded_bits += 6;
     890           0 :           n_coded_bits_flt = (float)n_coded_bits*2.0f;
     891           0 :           break;
     892           0 :         case(RADIOLIB_LR2021_FLRC_CR_3_4):
     893           0 :           n_coded_bits += 6;
     894           0 :           n_coded_bits_flt = (float)n_coded_bits*(4.0f/3.0f);
     895           0 :           break;
     896           0 :         case(RADIOLIB_LR2021_FLRC_CR_2_3):
     897           0 :           n_coded_bits_flt = (float)n_coded_bits*(3.0f/2.0f);
     898           0 :           break;
     899             :       }
     900           0 :       n_coded_bits = n_coded_bits_flt + 0.5f;
     901             : 
     902             :       // now calculate the real time on air
     903           0 :       return((float)(n_uncoded_bits + n_coded_bits) / (float)(this->bitRate));
     904             :     } 
     905             :   }
     906             : 
     907             :   RADIOLIB_DEBUG_BASIC_PRINTLN("Called getTimeOnAir() for invalid modem (%02x)!", type);
     908           0 :   return(0);
     909             : }
     910             : 
     911           6 : int16_t LR2021::getModem(ModemType_t* modem) {
     912           6 :   RADIOLIB_ASSERT_PTR(modem);
     913             : 
     914           6 :   uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     915           6 :   int16_t state = getPacketType(&type);
     916           6 :   RADIOLIB_ASSERT(state);
     917             : 
     918           0 :   switch(type) {
     919           0 :     case(RADIOLIB_LR2021_PACKET_TYPE_LORA):
     920           0 :       *modem = ModemType_t::RADIOLIB_MODEM_LORA;
     921           0 :       return(RADIOLIB_ERR_NONE);
     922           0 :     case(RADIOLIB_LR2021_PACKET_TYPE_GFSK):
     923           0 :       *modem = ModemType_t::RADIOLIB_MODEM_FSK;
     924           0 :       return(RADIOLIB_ERR_NONE);
     925           0 :     case(RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS):
     926           0 :       *modem = ModemType_t::RADIOLIB_MODEM_LRFHSS;
     927           0 :       return(RADIOLIB_ERR_NONE);
     928             :   }
     929             :   
     930           0 :   return(RADIOLIB_ERR_WRONG_MODEM);
     931             : }
     932             : 
     933           2 : int16_t LR2021::getMode(RadioModeType_t* mode) {
     934           2 :   RADIOLIB_ASSERT_PTR(mode);
     935             : 
     936           2 :   uint8_t stat2 = 0;
     937           2 :   int16_t state = getStatus(NULL, &stat2, NULL);
     938           2 :   RADIOLIB_ASSERT(state);
     939             : 
     940           0 :   switch(stat2 & 0b00000111) {
     941           0 :     case(RADIOLIB_LR2021_STAT_2_MODE_SLEEP):
     942           0 :       *mode = RADIOLIB_RADIO_MODE_SLEEP;
     943           0 :       break;
     944           0 :     case(RADIOLIB_LR2021_STAT_2_MODE_STBY_RC):
     945             :     case(RADIOLIB_LR2021_STAT_2_MODE_STBY_XOSC):
     946           0 :       *mode = RADIOLIB_RADIO_MODE_STANDBY;
     947           0 :       break;
     948           0 :     case(RADIOLIB_LR2021_STAT_2_MODE_RX):
     949           0 :       *mode = RADIOLIB_RADIO_MODE_RX;
     950           0 :       break;
     951           0 :     case(RADIOLIB_LR2021_STAT_2_MODE_TX):
     952           0 :       *mode = RADIOLIB_RADIO_MODE_TX;
     953           0 :       break;
     954           0 :     default:
     955             :       // frequency synthesis, or a value this part does not assign
     956           0 :       *mode = RADIOLIB_RADIO_MODE_NONE;
     957           0 :       break;
     958             :   }
     959             : 
     960           0 :   return(RADIOLIB_ERR_NONE);
     961             : }
     962             : 
     963           8 : int16_t LR2021::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) {
     964             :   int16_t state;
     965             : 
     966           8 :   switch(mode) {
     967           6 :     case(RADIOLIB_RADIO_MODE_RX): {
     968             :       // check active modem
     969           6 :       uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     970           6 :       state = getPacketType(&modem);
     971           6 :       RADIOLIB_ASSERT(state);
     972           0 :       if((modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) && 
     973           0 :         (modem != RADIOLIB_LR2021_PACKET_TYPE_GFSK) && 
     974           0 :         (modem != RADIOLIB_LR2021_PACKET_TYPE_FLRC) && 
     975           0 :         (modem != RADIOLIB_LR2021_PACKET_TYPE_OOK)) {
     976           0 :         return(RADIOLIB_ERR_WRONG_MODEM);
     977             :       }
     978             : 
     979             :       // in implicit LoRa header mode, use the provided length if it is nonzero
     980             :       // otherwise we trust the user has previously set the payload length manually
     981           0 :       if((this->headerType == RADIOLIB_LRXXXX_LORA_HEADER_IMPLICIT) && 
     982           0 :         (modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) && 
     983           0 :         (cfg->receive.len != 0)) {
     984           0 :         this->implicitLen = cfg->receive.len;
     985             :       }
     986             :       
     987             :       // set the correct Rx path
     988           0 :       state = setRxPath(this->highFreq ? RADIOLIB_LR2021_RX_PATH_HF : RADIOLIB_LR2021_RX_PATH_LF, this->highFreq ? this->gainModeHf : this->gainModeLf);
     989           0 :       RADIOLIB_ASSERT(state);
     990             : 
     991             :       // set DIO mapping
     992           0 :       if(cfg->receive.timeout != RADIOLIB_LR2021_RX_TIMEOUT_INF) {
     993           0 :         cfg->receive.irqMask |= (1UL << RADIOLIB_IRQ_TIMEOUT);
     994             :       }
     995           0 :       state = setDioIrqConfig(this->irqDioNum, getIrqMapped(cfg->receive.irqFlags & cfg->receive.irqMask));
     996           0 :       RADIOLIB_ASSERT(state);
     997             : 
     998             :       // clear interrupt flags
     999           0 :       state = clearIrqState(RADIOLIB_LR2021_IRQ_ALL);
    1000           0 :       RADIOLIB_ASSERT(state);
    1001             : 
    1002             :       // restore maximum allowed received packet length (may have been changed by previous Tx)
    1003           0 :       if(modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) {
    1004           0 :         state = setLoRaPacketParams(this->preambleLengthLoRa, this->headerType,
    1005           0 :           (this->headerType == RADIOLIB_LRXXXX_LORA_HEADER_IMPLICIT) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH,
    1006           0 :           this->crcTypeLoRa, this->invertIQEnabled);
    1007           0 :         RADIOLIB_ASSERT(state);
    1008             : 
    1009           0 :         state = setLoRaSynchTimeout(cfg->receive.syncSymbols);
    1010             : 
    1011           0 :       } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
    1012           0 :         state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType,
    1013           0 :           (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, 
    1014           0 :           this->crcTypeGFSK, this->whitening);
    1015             : 
    1016           0 :       } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_OOK) {
    1017           0 :         state = setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType,
    1018           0 :           (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH,
    1019           0 :           this->crcTypeGFSK, this->whitening);
    1020             : 
    1021           0 :       } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
    1022           0 :         state = setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK,
    1023           0 :           (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH);
    1024             :       
    1025             :       } else {
    1026           0 :         return(RADIOLIB_ERR_WRONG_MODEM);
    1027             :       }
    1028             :       
    1029           0 :       RADIOLIB_ASSERT(state);
    1030             : 
    1031             :       // if max(uint32_t) is used, revert to RxContinuous
    1032           0 :       if(cfg->receive.timeout == 0xFFFFFFFF) {
    1033           0 :         cfg->receive.timeout = 0xFFFFFF;
    1034             :       }
    1035           0 :       this->rxTimeout = cfg->receive.timeout;
    1036           0 :     } break;
    1037             :   
    1038           2 :     case(RADIOLIB_RADIO_MODE_TX): {
    1039             :       // check packet length
    1040           2 :       if(cfg->transmit.len > RADIOLIB_LR2021_MAX_PACKET_LENGTH) {
    1041           2 :         return(RADIOLIB_ERR_PACKET_TOO_LONG);
    1042             :       }
    1043             : 
    1044             :       // maximum packet length is decreased by 1 when address filtering is active
    1045             :       //! \todo [LR2021] implement GFSK address filtering
    1046             : 
    1047             :       // set packet Length
    1048           2 :       uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
    1049           2 :       state = getPacketType(&modem);
    1050           2 :       RADIOLIB_ASSERT(state);
    1051           0 :       if(modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) {
    1052           0 :         state = setLoRaPacketParams(this->preambleLengthLoRa, this->headerType, cfg->transmit.len, this->crcTypeLoRa, this->invertIQEnabled);
    1053             :       
    1054           0 :       } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
    1055           0 :         state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, cfg->transmit.len, this->crcTypeGFSK, this->whitening);
    1056             : 
    1057           0 :       } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_OOK) {
    1058           0 :         state = setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, cfg->transmit.len, this->crcTypeGFSK, this->whitening);
    1059             : 
    1060           0 :       } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
    1061           0 :         state = setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, cfg->transmit.len);
    1062             :       
    1063           0 :       } else if(modem != RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS) {
    1064           0 :         return(RADIOLIB_ERR_WRONG_MODEM);
    1065             :       }
    1066             : 
    1067           0 :       RADIOLIB_ASSERT(state);
    1068             : 
    1069             :       // set DIO mapping
    1070           0 :       state = setDioIrqConfig(this->irqDioNum, RADIOLIB_LR2021_IRQ_TX_DONE | RADIOLIB_LR2021_IRQ_TIMEOUT);
    1071           0 :       RADIOLIB_ASSERT(state);
    1072             : 
    1073           0 :       if(modem == RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS) {
    1074             :         // an LR-FHSS frame is built from the payload in this step, so it cannot be written ahead
    1075           0 :         if(cfg->transmit.data == NULL) {
    1076           0 :           return(RADIOLIB_ERR_UNSUPPORTED);
    1077             :         }
    1078             : 
    1079             :         // in LR-FHSS mode, the packet is built by the device
    1080             :         //! \todo [LR2021] add configurable LR-FHSS device offset
    1081           0 :         state = LRxxxx::lrFhssBuildFrame(RADIOLIB_LR2021_CMD_LR_FHSS_BUILD_FRAME, this->lrFhssHdrCount, this->lrFhssCr, this->lrFhssGrid, true, this->lrFhssBw, this->lrFhssHopSeq, 0, cfg->transmit.data, cfg->transmit.len);
    1082           0 :         RADIOLIB_ASSERT(state);
    1083             : 
    1084           0 :       } else if(cfg->transmit.data != NULL) {
    1085             :         // write packet to buffer - unless the caller already did that with writeTxBuffer,
    1086             :         // which it signals by leaving the payload pointer empty
    1087           0 :         state = writeRadioTxFifo(cfg->transmit.data, cfg->transmit.len);
    1088           0 :         RADIOLIB_ASSERT(state);
    1089             : 
    1090             :       }
    1091             : 
    1092             :       // clear interrupt flags
    1093           0 :       state = clearIrqState(RADIOLIB_LR2021_IRQ_ALL);
    1094           0 :       RADIOLIB_ASSERT(state);
    1095           0 :     } break;
    1096             :     
    1097           0 :     default:
    1098           0 :       return(RADIOLIB_ERR_UNSUPPORTED);
    1099             :   }
    1100             : 
    1101           0 :   this->stagedMode = mode;
    1102           0 :   return(state);
    1103             : }
    1104             : 
    1105           2 : int16_t LR2021::writeTxBuffer(const uint8_t* data, size_t len) {
    1106           2 :   if(data == NULL) {
    1107           0 :     return(RADIOLIB_ERR_NULL_POINTER);
    1108             :   }
    1109           2 :   if(len > RADIOLIB_LR2021_MAX_PACKET_LENGTH) {
    1110           0 :     return(RADIOLIB_ERR_PACKET_TOO_LONG);
    1111             :   }
    1112             : 
    1113             :   // the transmit FIFO appends, so anything left in it has to go first
    1114           2 :   int16_t state = clearTxFifo();
    1115           2 :   RADIOLIB_ASSERT(state);
    1116             : 
    1117           0 :   return(writeRadioTxFifo(data, len));
    1118             : }
    1119             : 
    1120           2 : int16_t LR2021::clearTxBuffer() {
    1121           2 :   return(clearTxFifo());
    1122             : }
    1123             : 
    1124           2 : int16_t LR2021::launchMode() {
    1125             :   int16_t state;
    1126           2 :   switch(this->stagedMode) {
    1127           2 :     case(RADIOLIB_RADIO_MODE_RX): {
    1128           2 :       this->mod->setRfSwitchState(Module::MODE_RX);
    1129           2 :       state = setRx(this->rxTimeout);
    1130           2 :     } break;
    1131             :   
    1132           0 :     case(RADIOLIB_RADIO_MODE_TX): {
    1133           0 :       this->mod->setRfSwitchState(Module::MODE_TX);
    1134           0 :       state = setTx(RADIOLIB_LR2021_TX_TIMEOUT_NONE);
    1135           0 :       RADIOLIB_ASSERT(state);
    1136             : 
    1137             :       // wait for BUSY to go low (= PA ramp up done)
    1138           0 :       while(this->mod->hal->digitalRead(this->mod->getGpio())) {
    1139           0 :         this->mod->hal->yield();
    1140             :       }
    1141           0 :     } break;
    1142             :     
    1143           0 :     default:
    1144           0 :       return(RADIOLIB_ERR_UNSUPPORTED);
    1145             :   }
    1146             : 
    1147           2 :   this->stagedMode = RADIOLIB_RADIO_MODE_NONE;
    1148           2 :   return(state);
    1149             : }
    1150             : 
    1151           0 : float LR2021::getVoltage(uint8_t bits) {
    1152           0 :   if((bits < 8) || (bits > 13)) {
    1153           0 :     return(0);
    1154             :   }
    1155             : 
    1156             :   uint16_t val;
    1157           0 :   if(getVbat(bits, &val) != RADIOLIB_ERR_NONE) {
    1158           0 :     return(0);
    1159             :   }
    1160             :   
    1161           0 :   return((float)val * (1.0f / 1000.0f));
    1162             : }
    1163             : 
    1164           0 : float LR2021::getTemperature(uint8_t source, uint8_t bits) {
    1165           0 :   if((bits < 8) || (bits > 13)) {
    1166           0 :     return(0);
    1167             :   }
    1168             : 
    1169             :   float val;
    1170           0 :   if(getTemp(source, bits, &val) != RADIOLIB_ERR_NONE) {
    1171           0 :     return(0);
    1172             :   }
    1173             : 
    1174           0 :   return(val);
    1175             : }
    1176             : 
    1177           2 : float LR2021::getRSSI() {
    1178           2 :   return(this->getRSSI(true));
    1179             : }
    1180             : 
    1181           2 : float LR2021::getRSSI(bool packet, bool skipReceive) {
    1182           2 :   float rssi = 0;
    1183             :   int16_t state;
    1184           2 :   if(!packet) { 
    1185             :     // get instantaneous RSSI value
    1186           0 :     if(!skipReceive) { (void)startReceive(); }
    1187           0 :     state = this->getRssiInst(&rssi);
    1188           0 :     if(!skipReceive) { (void)standby(); }
    1189           0 :     if(state != RADIOLIB_ERR_NONE) { return(0); }
    1190           0 :     return(rssi);
    1191             :   }
    1192             : 
    1193             :   // check modem type
    1194           2 :   uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
    1195           2 :   state = this->getPacketType(&modem);
    1196           2 :   if(state != RADIOLIB_ERR_NONE) { return(0); }
    1197           0 :   if(modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) {
    1198           0 :     state = this->getLoRaPacketStatus(NULL, NULL, NULL, NULL, &rssi, NULL);
    1199           0 :   } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
    1200           0 :     state = this->getGfskPacketStatus(NULL, &rssi, NULL, NULL, NULL, NULL);
    1201           0 :   } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_OOK) {
    1202           0 :     state = this->getOokPacketStatus(NULL, NULL, &rssi, NULL, NULL, NULL);
    1203           0 :   } else if (modem == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
    1204           0 :     state = this->getFlrcPacketStatus(NULL, &rssi, NULL, NULL, NULL);
    1205             :   } else {
    1206           0 :     return(0);
    1207             :   }
    1208             : 
    1209           0 :   if(state != RADIOLIB_ERR_NONE) { return(0); }
    1210           0 :   return(rssi);
    1211             : }
    1212             : 
    1213           2 : float LR2021::getSNR() {
    1214             :   float snr;
    1215           2 :   uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
    1216           2 :   int16_t state = this->getPacketType(&modem);
    1217           2 :   if(state != RADIOLIB_ERR_NONE) { return(0); }
    1218           0 :   if(modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) { return(0); }
    1219           0 :   state = this->getLoRaPacketStatus(NULL, NULL, NULL, &snr, NULL, NULL);
    1220           0 :   if(state != RADIOLIB_ERR_NONE) { return(0); }
    1221           0 :   return(snr);
    1222             : }
    1223             : 
    1224           0 : int32_t LR2021::getFrequencyError() {
    1225             :   int32_t freqErr;
    1226           0 :   uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
    1227           0 :   int16_t state = this->getPacketType(&modem);
    1228           0 :   if(state != RADIOLIB_ERR_NONE) { return(0); }
    1229           0 :   if(modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) {
    1230           0 :     state = this->getLoRaPacketStatus(NULL, NULL, NULL, NULL, NULL, NULL, NULL, &freqErr);
    1231           0 :   } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
    1232           0 :     state = this->getFlrcPacketStatus(NULL, NULL, NULL, NULL, &freqErr);
    1233             :   } else {
    1234           0 :     state = RADIOLIB_ERR_WRONG_MODEM;
    1235             :   }
    1236           0 :   if(state != RADIOLIB_ERR_NONE) { return(0); }
    1237           0 :   return(freqErr);
    1238             : }
    1239             : 
    1240           2 : uint8_t LR2021::randomByte() {
    1241           2 :   uint32_t num = 0;
    1242           2 :   (void)getRandomNumber(&num);
    1243           2 :   return((uint8_t)num);
    1244             : }
    1245             : 
    1246           0 : int16_t LR2021::getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC){
    1247             :   // check if in explicit header mode, as LR11x0, SX126x, SX127x and SX128x do
    1248           0 :   if(this->headerType == RADIOLIB_LRXXXX_LORA_HEADER_IMPLICIT) {
    1249           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1250             :   }
    1251             : 
    1252           0 :   return(this->getLoRaPacketStatus(cr, hasCRC, NULL, NULL, NULL, NULL));
    1253             : }
    1254             : 
    1255             : #endif

Generated by: LCOV version 1.14