LCOV - code coverage report
Current view: top level - src/modules/LR2021 - LR2021.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 144 640 22.5 %
Date: 2026-06-03 18:53:41 Functions: 32 52 61.5 %

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

Generated by: LCOV version 1.14