LCOV - code coverage report
Current view: top level - src/modules/LR2021 - LR2021_config.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 56 612 9.2 %
Date: 2026-04-20 19:58:46 Functions: 14 38 36.8 %

          Line data    Source code
       1             : #include "LR2021.h"
       2             : 
       3             : #include "../LR11x0/LR_common.h"
       4             : #include "LR2021_registers.h"
       5             : 
       6             : #include <math.h>
       7             : #include <string.h>
       8             : 
       9             : #if !RADIOLIB_EXCLUDE_LR2021
      10             : 
      11             : // maximum number of allowed frontend calibration attempts
      12             : #define RADIOLIB_LR2021_MAX_CAL_ATTEMPTS    (10)
      13             : 
      14           1 : int16_t LR2021::setFrequency(float freq) {
      15           1 :   return(this->setFrequency(freq, false));
      16             : }
      17             : 
      18           1 : int16_t LR2021::setFrequency(float freq, bool skipCalibration) {
      19             :   #if RADIOLIB_CHECK_PARAMS
      20           1 :   if(!(((freq >= 150.0f) && (freq <= 1090.0f)) ||
      21           1 :     ((freq >= 1900.0f) && (freq <= 2200.0f)) ||
      22           1 :     ((freq >= 2400.0f) && (freq <= 2500.0f)))) {
      23           1 :       return(RADIOLIB_ERR_INVALID_FREQUENCY);
      24             :   }
      25             :   #endif
      26             : 
      27             :   // check if we need to recalibrate image
      28             :   int16_t state;
      29           0 :   if(!skipCalibration && (fabsf(freq - this->freqMHz) >= RADIOLIB_LR2021_CAL_IMG_FREQ_TRIG_MHZ)) {
      30             :     // calibration can fail if there is a strong interfering source
      31             :     // run it several times until it passes
      32           0 :     int i = 0;
      33           0 :     for(; i < RADIOLIB_LR2021_MAX_CAL_ATTEMPTS; i++) {
      34             :       // get the nearest multiple of 4 MHz
      35           0 :       uint16_t frequencies[3] = { (uint16_t)((freq / 4.0f) + 0.5f), 0, 0 };
      36           0 :       frequencies[0] |= (freq > RADIOLIB_LR2021_LF_CUTOFF_FREQ) ? RADIOLIB_LR2021_CALIBRATE_FE_HF_PATH : RADIOLIB_LR2021_CALIBRATE_FE_LF_PATH;
      37           0 :       state = calibrateFrontEnd(const_cast<const uint16_t*>(frequencies));
      38             : 
      39             :       // if something failed, check the device errors
      40           0 :       if(state != RADIOLIB_ERR_NONE) {
      41           0 :         uint16_t errors = 0;
      42           0 :         getErrors(&errors);
      43             :         RADIOLIB_DEBUG_BASIC_PRINTLN("Frontend calibration #%d failed, device errors: 0x%X", i, errors);
      44             : 
      45             :         // if this is caused by something else than RSSI saturation, repeating will not help
      46           0 :         if((errors & RADIOLIB_LR2021_SRC_SATURATION_CALIB_ERR) == 0) {
      47           0 :           return(state);
      48             :         }
      49             : 
      50             :         // wait a little while before the next attempt
      51           0 :         this->mod->hal->delay(5);
      52             :       
      53             :       } else {
      54             :         // calibration passed
      55           0 :         break;
      56             :       }
      57             : 
      58             :     }
      59             : 
      60           0 :     if(i == RADIOLIB_LR2021_MAX_CAL_ATTEMPTS) {
      61           0 :       return(RADIOLIB_ERR_FRONTEND_CALIBRATION_FAILED);
      62             :     }
      63             : 
      64             :   }
      65             : 
      66             :   // set frequency
      67           0 :   state = setRfFrequency((uint32_t)(freq*1000000.0f));
      68           0 :   RADIOLIB_ASSERT(state);
      69           0 :   this->freqMHz = freq;
      70           0 :   this->highFreq = (freq > RADIOLIB_LR2021_LF_CUTOFF_FREQ);
      71           0 :   return(state);
      72             : }
      73             : 
      74           1 : int16_t LR2021::setOutputPower(int8_t power) {
      75           1 :   return(this->setOutputPower(power, 48));
      76             : }
      77             : 
      78           1 : int16_t LR2021::setOutputPower(int8_t power, uint32_t rampTimeUs) {
      79             :   // check if power value is configurable
      80           1 :   int16_t state = this->checkOutputPower(power, NULL);
      81           1 :   RADIOLIB_ASSERT(state);
      82             :   
      83             :   //! \TODO: [LR2021] how and when to configure OCP?
      84             :   //! \TODO: [LR2021] Determine the optimal PA configuration
      85             :   // update PA config
      86           1 :   state = setPaConfig(this->highFreq, 
      87             :     RADIOLIB_LR2021_PA_LF_MODE_FSM, 
      88             :     RADIOLIB_LR2021_PA_LF_DUTY_CYCLE_UNUSED, 
      89             :     RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, 
      90             :     RADIOLIB_LR2021_PA_HF_DUTY_CYCLE_UNUSED);
      91           1 :   RADIOLIB_ASSERT(state);
      92             : 
      93             :   // set output power
      94           0 :   state = setTxParams(power, roundRampTime(rampTimeUs));
      95           0 :   return(state);
      96             : }
      97             : 
      98           2 : int16_t LR2021::checkOutputPower(int8_t power, int8_t* clipped) {
      99           2 :   if(this->highFreq) {
     100           0 :     if(clipped) {
     101           0 :       *clipped = RADIOLIB_MAX(-19, RADIOLIB_MIN(12, power));
     102             :     }
     103           0 :     RADIOLIB_CHECK_RANGE(power, -19, 12, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
     104             : 
     105             :   } else {
     106           2 :     if(clipped) {
     107           0 :       *clipped = RADIOLIB_MAX(-9, RADIOLIB_MIN(22, power));
     108             :     }
     109           2 :     RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
     110             : 
     111             :   }
     112             :   
     113           2 :   return(RADIOLIB_ERR_NONE);
     114             : }
     115             : 
     116           0 : void LR2021::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) {
     117             :   // find which pins are used
     118             :   // on LR2021, modes are configured per DIO (exact opposite of LR11x0)
     119           0 :   uint8_t dioConfigs[7] = { 0 };
     120           0 :   for(size_t i = 0; i < Module::RFSWITCH_MAX_PINS; i++) {
     121             :     // check if this pin is unused
     122           0 :     if(pins[i] == RADIOLIB_NC) { continue; }
     123             : 
     124             :     // only keep DIO pins, there may be some GPIOs in the switch tabke
     125           0 :     if((pins[i] & RFSWITCH_PIN_FLAG) == 0) { continue; }
     126             :     
     127             :     // find modes in which this pin is used
     128           0 :     uint32_t dioNum = RADIOLIB_LRXXXX_DIOx_VAL(pins[i]);
     129           0 :     size_t j = 0;
     130           0 :     while(table[j].mode != LR2021::MODE_END_OF_TABLE) {
     131           0 :       dioConfigs[dioNum] |= (table[j].values[i] == this->mod->hal->GpioLevelHigh) ? (1UL << (table[j].mode - 1)) : 0;
     132           0 :       j++;
     133             :     }
     134             : 
     135             :     // For DIO = 5, only DIO_SLEEP_PULL_UP is accepted. Otherwise the SetDioFunction returns FAIL.
     136           0 :     uint8_t pull = dioNum == 0 ? RADIOLIB_LR2021_DIO_SLEEP_PULL_UP : RADIOLIB_LR2021_DIO_SLEEP_PULL_AUTO;
     137             :     // enable RF control for this pin and set the modes in which it is active
     138           0 :     (void)this->setDioFunction(dioNum + 5, RADIOLIB_LR2021_DIO_FUNCTION_RF_SWITCH, pull);
     139           0 :     (void)this->setDioRfSwitchConfig(dioNum + 5, dioConfigs[i]);
     140             :   }
     141           0 : }
     142             : 
     143           0 : int16_t LR2021::setBandwidth(float bw) {
     144             :   // check active modem
     145           0 :   uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     146           0 :   int16_t state = getPacketType(&type);
     147           0 :   RADIOLIB_ASSERT(state);
     148           0 :   if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
     149           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     150             :   }
     151             :     
     152             :   // convert to int to avoid bunch of math
     153           0 :   int bw_div2 = bw / 2 + 0.01f;
     154             : 
     155             :   // check allowed bandwidth values
     156           0 :   switch (bw_div2)  {
     157           0 :     case 15:
     158           0 :       this->bandwidth = RADIOLIB_LR2021_LORA_BW_31;
     159           0 :       break;
     160           0 :     case 20:
     161           0 :       this->bandwidth = RADIOLIB_LR2021_LORA_BW_41;
     162           0 :       break;
     163           0 :     case 31:
     164           0 :       this->bandwidth = RADIOLIB_LR2021_LORA_BW_62;
     165           0 :       break;
     166           0 :     case 41:
     167           0 :       this->bandwidth = RADIOLIB_LR2021_LORA_BW_83;
     168           0 :       break;
     169           0 :     case 50:
     170           0 :       this->bandwidth = RADIOLIB_LR2021_LORA_BW_101;
     171           0 :       break;
     172           0 :     case 101:
     173           0 :       this->bandwidth = RADIOLIB_LR2021_LORA_BW_203;
     174           0 :       break;
     175           0 :     case 62:
     176           0 :       this->bandwidth = RADIOLIB_LR2021_LORA_BW_125;
     177           0 :       break;
     178           0 :     case 125:
     179           0 :       this->bandwidth = RADIOLIB_LR2021_LORA_BW_250;
     180           0 :       break;
     181           0 :     case 203:
     182           0 :       this->bandwidth = RADIOLIB_LR2021_LORA_BW_406;
     183           0 :       break;
     184           0 :     case 250:
     185           0 :       this->bandwidth = RADIOLIB_LR2021_LORA_BW_500;
     186           0 :       break;
     187           0 :     case 406:
     188           0 :       this->bandwidth = RADIOLIB_LR2021_LORA_BW_812;
     189           0 :       break;
     190           0 :     case 500:
     191           0 :       this->bandwidth = RADIOLIB_LR2021_LORA_BW_1000;
     192           0 :       break;
     193           0 :     default:
     194           0 :       return(RADIOLIB_ERR_INVALID_BANDWIDTH);
     195             :   }
     196             : 
     197             :   // update modulation parameters
     198           0 :   this->bandwidthKhz = bw;
     199           0 :   return(setLoRaModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
     200             : }
     201             : 
     202           0 : int16_t LR2021::setSpreadingFactor(uint8_t sf, bool legacy) {
     203             :   // check active modem
     204           0 :   uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     205           0 :   int16_t state = getPacketType(&type);
     206           0 :   RADIOLIB_ASSERT(state);
     207           0 :   if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
     208           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     209             :   }
     210             : 
     211           0 :   RADIOLIB_CHECK_RANGE(sf, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
     212             : 
     213             :   //! \TODO: [LR2021] enable SF6 legacy mode
     214             :   if(legacy && (sf == 6)) {
     215             :     //this->mod->SPIsetRegValue(RADIOLIB_LR11X0_REG_SF6_SX127X_COMPAT, RADIOLIB_LR11X0_SF6_SX127X, 18, 18);
     216             :   }
     217             : 
     218             :   // update modulation parameters
     219           0 :   this->spreadingFactor = sf;
     220           0 :   return(setLoRaModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
     221             : }
     222             : 
     223           0 : int16_t LR2021::setCodingRate(uint8_t cr, bool longInterleave) {
     224             :   // check active modem
     225           0 :   uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     226           0 :   int16_t state = getPacketType(&type);
     227           0 :   RADIOLIB_ASSERT(state);
     228           0 :   if(type == RADIOLIB_LR2021_PACKET_TYPE_LORA) {
     229           0 :     RADIOLIB_CHECK_RANGE(cr, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
     230             : 
     231           0 :     if(longInterleave) {
     232           0 :       switch(cr) {
     233           0 :         case 4:
     234           0 :           this->codingRate = 0;
     235           0 :           break;
     236           0 :         case 5:
     237             :         case 6:
     238           0 :           this->codingRate = cr;
     239           0 :           break;
     240           0 :         case 8: 
     241           0 :           this->codingRate = cr - 1;
     242           0 :           break;
     243           0 :         default:
     244           0 :           return(RADIOLIB_ERR_INVALID_CODING_RATE);
     245             :       }
     246             :     
     247             :     } else {
     248           0 :       this->codingRate = cr - 4;
     249             :     
     250             :     }
     251             : 
     252             :     // update modulation parameters
     253           0 :     return(setLoRaModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
     254             : 
     255           0 :   } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
     256           0 :     if(cr > RADIOLIB_LR2021_FLRC_CR_2_3) {
     257           0 :       return(RADIOLIB_ERR_INVALID_CODING_RATE);
     258             :     }
     259             : 
     260             :     // update modulation parameters
     261           0 :     this->codingRateFlrc = cr;
     262           0 :     return(setFlrcModulationParams(this->bitRateFlrc, this->codingRateFlrc, this->pulseShape));
     263             :   
     264             :   }
     265             :   
     266           0 :   return(RADIOLIB_ERR_WRONG_MODEM);
     267             : }
     268             : 
     269           0 : int16_t LR2021::setSyncWord(uint8_t syncWord) {
     270             :   // check active modem
     271           0 :   uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     272           0 :   int16_t state = getPacketType(&type);
     273           0 :   RADIOLIB_ASSERT(state);
     274           0 :   if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
     275           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     276             :   }
     277             :   
     278           0 :   return(setLoRaSyncword(syncWord));
     279             : }
     280             : 
     281           1 : int16_t LR2021::setPreambleLength(size_t preambleLength) {
     282             :   // check active modem
     283           1 :   uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     284           1 :   int16_t state = getPacketType(&type);
     285           1 :   RADIOLIB_ASSERT(state);
     286           0 :   if(type == RADIOLIB_LR2021_PACKET_TYPE_LORA) {
     287           0 :     this->preambleLengthLoRa = preambleLength;
     288           0 :     return(setLoRaPacketParams(this->preambleLengthLoRa, this->headerType, 
     289           0 :       (this->headerType == RADIOLIB_LR2021_LORA_HEADER_IMPLICIT) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled));
     290             :   
     291           0 :   } else if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
     292           0 :     this->preambleLengthGFSK = preambleLength;
     293           0 :     this->preambleDetLength = (preambleLength / 8) << 3;
     294           0 :     return(setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, 
     295           0 :       (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
     296             :   
     297           0 :   } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) {
     298           0 :     this->preambleLengthGFSK = preambleLength;
     299           0 :     this->preambleDetLength = (preambleLength / 8) << 3;
     300           0 :     return(setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, 
     301           0 :       (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
     302             :     
     303           0 :   } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
     304           0 :     if((preambleLength % 4) != 0) {
     305           0 :       return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH);
     306             :     }
     307           0 :     this->preambleLengthGFSK = (preambleLength / 4) - 1;
     308           0 :     return(setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, 
     309           0 :       (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH));
     310             : 
     311             :   }
     312             : 
     313           0 :   return(RADIOLIB_ERR_WRONG_MODEM);
     314             : }
     315             : 
     316           0 : int16_t LR2021::setTCXO(float voltage, uint32_t delay) {
     317             :   // check if TCXO is enabled at all
     318           0 :   if(this->XTAL) {
     319           0 :     return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE);
     320             :   }
     321             : 
     322             :   // set mode to standby
     323           0 :   standby();
     324             : 
     325             :   // check oscillator startup error flag and clear it
     326           0 :   uint16_t errors = 0;
     327           0 :   int16_t state = getErrors(&errors);
     328           0 :   RADIOLIB_ASSERT(state);
     329           0 :   if(errors & RADIOLIB_LR2021_HF_XOSC_START_ERR) {
     330           0 :     clearErrors();
     331             :   }
     332             : 
     333             :   // check 0 V disable
     334           0 :   if(fabsf(voltage - 0.0f) <= 0.001f) {
     335           0 :     setTcxoMode(0, 0);
     336           0 :     return(reset());
     337             :   }
     338             : 
     339             :   // check allowed voltage values
     340           0 :   uint8_t tune = 0;
     341           0 :   if(fabsf(voltage - 1.6f) <= 0.001f) {
     342           0 :     tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_1_6;
     343           0 :   } else if(fabsf(voltage - 1.7f) <= 0.001f) {
     344           0 :     tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_1_7;
     345           0 :   } else if(fabsf(voltage - 1.8f) <= 0.001f) {
     346           0 :     tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_1_8;
     347           0 :   } else if(fabsf(voltage - 2.2f) <= 0.001f) {
     348           0 :     tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_2_2;
     349           0 :   } else if(fabsf(voltage - 2.4f) <= 0.001f) {
     350           0 :     tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_2_4;
     351           0 :   } else if(fabsf(voltage - 2.7f) <= 0.001f) {
     352           0 :     tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_2_7;
     353           0 :   } else if(fabsf(voltage - 3.0f) <= 0.001f) {
     354           0 :     tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_3_0;
     355           0 :   } else if(fabsf(voltage - 3.3f) <= 0.001f) {
     356           0 :     tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_3_3;
     357             :   } else {
     358           0 :     return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE);
     359             :   }
     360             : 
     361             :   // calculate delay value
     362           0 :   uint32_t delayValue = (uint32_t)((float)delay / 30.52f);
     363           0 :   if(delayValue == 0) {
     364           0 :     delayValue = 1;
     365             :   }
     366             :  
     367             :   // enable TCXO control
     368           0 :   return(setTcxoMode(tune, delayValue));
     369             : }
     370             : 
     371           0 : int16_t LR2021::setCRC(uint8_t len, uint32_t initial, uint32_t polynomial, bool inverted) {
     372             :   // check active modem
     373           0 :   uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     374           0 :   int16_t state = getPacketType(&type);
     375           0 :   RADIOLIB_ASSERT(state);
     376           0 :   if(type == RADIOLIB_LR2021_PACKET_TYPE_LORA) {
     377             :     // LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion
     378           0 :     this->crcTypeLoRa = len > 0;
     379           0 :     return(setLoRaPacketParams(this->preambleLengthLoRa, this->headerType, 
     380           0 :       (this->packetType == RADIOLIB_LR2021_LORA_HEADER_IMPLICIT) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled));
     381             :   
     382           0 :   } else if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
     383           0 :     if(len > 4) {
     384           0 :       return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
     385             :     }
     386             : 
     387           0 :     this->crcTypeGFSK = len;
     388           0 :     if((this->crcTypeGFSK != RADIOLIB_LR2021_GFSK_OOK_CRC_OFF) && inverted) {
     389           0 :       this->crcTypeGFSK += 0x08;
     390             :     }
     391             : 
     392           0 :     state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, 
     393           0 :       (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
     394           0 :     RADIOLIB_ASSERT(state);
     395             : 
     396           0 :     return(setGfskCrcParams(polynomial, initial));
     397             : 
     398           0 :   } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) {
     399           0 :     if(len > 4) {
     400           0 :       return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
     401             :     }
     402             : 
     403           0 :     this->crcTypeGFSK = len;
     404           0 :     if((this->crcTypeGFSK != RADIOLIB_LR2021_GFSK_OOK_CRC_OFF) && inverted) {
     405           0 :       this->crcTypeGFSK += 0x08;
     406             :     }
     407             : 
     408           0 :     state = setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, 
     409           0 :       (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
     410           0 :     RADIOLIB_ASSERT(state);
     411             : 
     412           0 :     return(setOokCrcParams(polynomial, initial));
     413             :   
     414           0 :   } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
     415           0 :     if((len == 1) || (len > 4)) {
     416           0 :       return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
     417             :     }
     418             :     
     419           0 :     this->crcLenGFSK = len ? len - 1 : 0;
     420           0 :     return(setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, 
     421           0 :       (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH));
     422             :       
     423             :   }
     424             : 
     425           0 :   return(RADIOLIB_ERR_WRONG_MODEM);
     426             : }
     427             : 
     428           1 : int16_t LR2021::invertIQ(bool enable) {
     429             :   // check active modem
     430           1 :   uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     431           1 :   int16_t state = getPacketType(&type);
     432           1 :   RADIOLIB_ASSERT(state);
     433           0 :   if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
     434           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     435             :   }
     436             : 
     437           0 :   this->invertIQEnabled = enable;
     438           0 :   return(setLoRaPacketParams(this->preambleLengthLoRa, this->headerType, 
     439           0 :     (this->packetType == RADIOLIB_LR2021_LORA_HEADER_IMPLICIT) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled));
     440             : }
     441             : 
     442           1 : int16_t LR2021::setBitRate(float br) {
     443             :   // check active modem
     444           1 :   uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     445           1 :   int16_t state = getPacketType(&type);
     446           1 :   RADIOLIB_ASSERT(state);
     447           0 :   if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
     448           0 :     RADIOLIB_CHECK_RANGE(br, 0.5f, 2000.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
     449             :     //! \TODO: [LR2021] implement fractional bit rate configuration
     450           0 :     this->bitRate = br * 1000.0f;
     451           0 :     state = setGfskModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev);
     452           0 :     return(state);
     453             :   
     454           0 :   } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) {
     455           0 :     RADIOLIB_CHECK_RANGE(br, 0.5f, 2000.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
     456             :     //! \TODO: [LR2021] implement fractional bit rate configuration
     457           0 :     this->bitRate = br * 1000.0f;
     458             :     //! \TODO: [LR2021] implement OOK magnitude depth configuration
     459           0 :     state = setOokModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, RADIOLIB_LR2021_OOK_DEPTH_FULL);
     460           0 :     return(state);
     461             :     
     462           0 :   } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
     463           0 :      if((uint16_t)br == 260) {
     464           0 :       this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_260;
     465           0 :     } else if((uint16_t)br == 325) {
     466           0 :       this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_325;
     467           0 :     } else if((uint16_t)br == 520) {
     468           0 :       this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_520;
     469           0 :     } else if((uint16_t)br == 650) {
     470           0 :       this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_650;
     471           0 :     } else if((uint16_t)br == 1040) {
     472           0 :       this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_1040;
     473           0 :     } else if((uint16_t)br == 1300) {
     474           0 :       this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_1300;
     475           0 :     } else if((uint16_t)br == 2080) {
     476           0 :       this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_2080;
     477           0 :     } else if((uint16_t)br == 2600) {
     478           0 :       this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_2600;
     479             :     } else {
     480           0 :       return(RADIOLIB_ERR_INVALID_BIT_RATE);
     481             :     }
     482             : 
     483             :     // it is slightly weird to reuse the GFSK bitrate variable in this way
     484             :     // but if GFSK gets enabled it should get reset anyway ... I think
     485           0 :     this->bitRate = br;
     486             : 
     487             :     // update modulation parameters
     488           0 :     return(setFlrcModulationParams(this->bitRateFlrc, this->codingRateFlrc, this->pulseShape));
     489             :   }
     490             : 
     491           0 :   return(RADIOLIB_ERR_WRONG_MODEM);  
     492             : }
     493             : 
     494           1 : int16_t LR2021::setFrequencyDeviation(float freqDev) {
     495             :   // check active modem
     496           1 :   uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     497           1 :   int16_t state = getPacketType(&type);
     498           1 :   RADIOLIB_ASSERT(state);
     499           0 :   if(type != RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
     500           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     501             :   }
     502             : 
     503             :   // set frequency deviation to lowest available setting (required for digimodes)
     504           0 :   float newFreqDev = freqDev;
     505           0 :   if(freqDev < 0.6f) {
     506           0 :     newFreqDev = 0.6f;
     507             :   }
     508             : 
     509           0 :   RADIOLIB_CHECK_RANGE(newFreqDev, 0.6f, 500.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
     510           0 :   this->frequencyDev = newFreqDev * 1000.0f;
     511           0 :   state = setGfskModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev);
     512           0 :   return(state);
     513             : }
     514             : 
     515           0 : int16_t LR2021::setRxBandwidth(float rxBw) {
     516             :   // check active modem
     517           0 :   uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     518           0 :   int16_t state = getPacketType(&type);
     519           0 :   RADIOLIB_ASSERT(state);
     520           0 :   if(!((type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) || 
     521           0 :        (type == RADIOLIB_LR2021_PACKET_TYPE_OOK))) {
     522           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     523             :   }
     524             : 
     525           0 :   const uint8_t rxBwLut[] = {
     526             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_4_8,
     527             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_5_8,
     528             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_7_4,
     529             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_9_7,
     530             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_12_0,
     531             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_14_9,
     532             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_19_2,
     533             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_23_1,
     534             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_29_8,
     535             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_38_5,
     536             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_46_3,
     537             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_59_5,
     538             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_76_9,
     539             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_92_6,
     540             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_119_0,
     541             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_153_8,
     542             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_185_2,
     543             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_238_1,
     544             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_307_7,
     545             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_370_4,
     546             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_476_2,
     547             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_555_6,
     548             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_666_7,
     549             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_769_2,
     550             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_1111,
     551             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_2222,
     552             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_2666,
     553             :     RADIOLIB_LR2021_GFSK_OOK_RX_BW_3076,
     554             :   };
     555             : 
     556           0 :   state = findRxBw(rxBw, rxBwLut, sizeof(rxBwLut)/sizeof(rxBwLut[0]), 3076.0f, &this->rxBandwidth);
     557           0 :   RADIOLIB_ASSERT(state);
     558             : 
     559             :   // update modulation parameters
     560           0 :   if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
     561           0 :     state = setGfskModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev);
     562             :   } else {
     563           0 :     state = setOokModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, RADIOLIB_LR2021_OOK_DEPTH_FULL);
     564             :   }
     565           0 :   return(state);
     566             : }
     567             : 
     568           1 : int16_t LR2021::setSyncWord(uint8_t* syncWord, size_t len) {
     569           1 :   if(len > RADIOLIB_LR2021_GFSK_SYNC_WORD_LEN) {
     570           0 :     return(RADIOLIB_ERR_INVALID_SYNC_WORD);
     571             :   }
     572             : 
     573             :   // check active modem
     574           1 :   uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     575           1 :   int16_t state = getPacketType(&type);
     576           1 :   RADIOLIB_ASSERT(state);
     577             : 
     578           0 :   uint32_t sync = 0;
     579           0 :   switch(type) {
     580           0 :     case(RADIOLIB_LR2021_PACKET_TYPE_GFSK):
     581             :       // default to MSB-first
     582           0 :       return(setGfskSyncword(const_cast<const uint8_t*>(syncWord), len, true));
     583             :     
     584           0 :       case(RADIOLIB_LR2021_PACKET_TYPE_OOK):
     585             :       // default to MSB-first
     586           0 :       return(setOokSyncword(const_cast<const uint8_t*>(syncWord), len, true));
     587             :     
     588           0 :     case(RADIOLIB_LR2021_PACKET_TYPE_LORA):
     589             :       // with length set to 1 and LoRa modem active, assume it is the LoRa sync word
     590           0 :       if(len > 1) {
     591           0 :         return(RADIOLIB_ERR_INVALID_SYNC_WORD);
     592             :       }
     593           0 :       return(setSyncWord(syncWord[0]));
     594             :     
     595           0 :     case(RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS):
     596             :       // with length set to 4 and LR-FHSS modem active, assume it is the LR-FHSS sync word
     597           0 :       if(len != sizeof(uint32_t)) {
     598           0 :         return(RADIOLIB_ERR_INVALID_SYNC_WORD);
     599             :       }
     600           0 :       memcpy(&sync, syncWord, sizeof(uint32_t));
     601           0 :       return(lrFhssSetSyncword(sync));
     602             :     
     603           0 :     case(RADIOLIB_LR2021_PACKET_TYPE_FLRC):
     604             :       // FLRC requires 16 or 32-bit sync word
     605           0 :       if(!((len == 0) || (len == 2) || (len == 4))) {
     606           0 :         return(RADIOLIB_ERR_INVALID_SYNC_WORD);
     607             :       }
     608             : 
     609             :       // update sync word length
     610           0 :       this->syncWordLength = len;
     611           0 :       state = setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, 
     612           0 :         (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH);
     613           0 :       RADIOLIB_ASSERT(state);
     614             : 
     615           0 :       sync |= (uint32_t)syncWord[0] << 24;
     616           0 :       sync |= (uint32_t)syncWord[1] << 16;
     617           0 :       sync |= (uint32_t)syncWord[2] << 8;
     618           0 :       sync |= (uint32_t)syncWord[3];
     619           0 :       return(setFlrcSyncWord(1, sync));
     620             :   }
     621             : 
     622           0 :   return(RADIOLIB_ERR_WRONG_MODEM);
     623             : }
     624             : 
     625           1 : int16_t LR2021::setDataShaping(uint8_t sh) {
     626             :   // check active modem
     627           1 :   uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     628           1 :   int16_t state = getPacketType(&type);
     629           1 :   RADIOLIB_ASSERT(state);
     630             : 
     631             :   // set data shaping
     632           0 :   switch(sh) {
     633           0 :     case RADIOLIB_SHAPING_NONE:
     634           0 :       this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_NONE;
     635           0 :       break;
     636           0 :     case RADIOLIB_SHAPING_0_3:
     637           0 :       this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_0_3;
     638           0 :       break;
     639           0 :     case RADIOLIB_SHAPING_0_5:
     640           0 :       this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_0_5;
     641           0 :       break;
     642           0 :     case RADIOLIB_SHAPING_0_7:
     643           0 :       this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_0_7;
     644           0 :       break;
     645           0 :     case RADIOLIB_SHAPING_1_0:
     646           0 :       this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_1_0;
     647           0 :       break;
     648           0 :     default:
     649           0 :       return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
     650             :   }
     651             : 
     652             :   // update modulation parameters
     653           0 :   if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
     654           0 :     return(setFlrcModulationParams(this->bitRateFlrc, this->codingRateFlrc, this->pulseShape));
     655           0 :   } else if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
     656           0 :     return(setGfskModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
     657           0 :   } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) {
     658           0 :     return(setOokModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, RADIOLIB_LR2021_OOK_DEPTH_FULL));
     659             :   }
     660           0 :   return(RADIOLIB_ERR_WRONG_MODEM);
     661             : }
     662             : 
     663           1 : int16_t LR2021::setEncoding(uint8_t encoding) {
     664             :   // check active modem
     665           1 :   uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     666           1 :   int16_t state = getPacketType(&type);
     667           1 :   RADIOLIB_ASSERT(state);
     668             : 
     669           0 :   switch(type) {
     670           0 :     case(RADIOLIB_LR2021_PACKET_TYPE_GFSK):
     671           0 :       return(setWhitening(encoding == RADIOLIB_ENCODING_WHITENING));
     672             :     
     673           0 :     case(RADIOLIB_LR2021_PACKET_TYPE_OOK):
     674           0 :       switch(encoding) {
     675           0 :         case(RADIOLIB_ENCODING_NRZ):
     676             :         case(RADIOLIB_ENCODING_WHITENING):
     677           0 :           return(setWhitening(encoding == RADIOLIB_ENCODING_WHITENING));
     678             :         
     679           0 :         case(RADIOLIB_ENCODING_MANCHESTER):
     680           0 :           state = setWhitening(false);
     681           0 :           RADIOLIB_ASSERT(state);
     682           0 :           this->whitening = RADIOLIB_LR2021_OOK_MANCHESTER_ON;
     683           0 :           return(setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, 
     684           0 :             (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
     685             :         
     686           0 :         case(RADIOLIB_ENCODING_MANCHESTER_INV):
     687           0 :           state = setWhitening(false);
     688           0 :           RADIOLIB_ASSERT(state);
     689           0 :           this->whitening = RADIOLIB_LR2021_OOK_MANCHESTER_ON_INV;
     690           0 :           return(setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, 
     691           0 :             (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
     692             :         
     693           0 :         default:
     694           0 :           return(RADIOLIB_ERR_INVALID_ENCODING);
     695             :       }
     696             :     
     697           0 :     default:
     698           0 :       return(RADIOLIB_ERR_WRONG_MODEM);
     699             :   }
     700             : 
     701             :   return(state);
     702             : }
     703             : 
     704           0 : int16_t LR2021::fixedPacketLengthMode(uint8_t len) {
     705           0 :   return(setPacketMode(RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, len));
     706             : }
     707             : 
     708           0 : int16_t LR2021::variablePacketLengthMode(uint8_t maxLen) {
     709           0 :   return(setPacketMode(RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_VARIABLE_8BIT, maxLen));
     710             : }
     711             : 
     712           0 : int16_t LR2021::setWhitening(bool enabled, uint16_t initial) {
     713             :   // check active modem
     714           0 :   uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     715           0 :   int16_t state = getPacketType(&type);
     716           0 :   RADIOLIB_ASSERT(state);
     717             :   
     718           0 :   switch(type) {
     719           0 :     case(RADIOLIB_LR2021_PACKET_TYPE_GFSK):
     720             :       //! \TODO: [LR2021] Implement SX128x-compatible whitening
     721           0 :       if(enabled) {
     722           0 :         state = setGfskWhiteningParams(RADIOLIB_LR2021_GFSK_WHITENING_TYPE_SX126X_LR11XX, initial);
     723           0 :         RADIOLIB_ASSERT(state);
     724             :       }
     725           0 :       this->whitening = enabled;
     726           0 :       return(setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, 
     727           0 :         (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
     728             :     
     729           0 :     case(RADIOLIB_LR2021_PACKET_TYPE_OOK):
     730           0 :       this->whitening = enabled;
     731           0 :       if(enabled) {
     732             :         //! \TODO: [LR2021] Implement configurable index and polynomial
     733           0 :         state = setOokWhiteningParams(12, 0x01FF, initial);
     734             :       } else {
     735           0 :         state = setOokWhiteningParams(0, 0, 0);
     736             :       }
     737           0 :       RADIOLIB_ASSERT(state);
     738           0 :       return(setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, 
     739           0 :         (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
     740             :   }
     741             : 
     742           0 :   return(RADIOLIB_ERR_WRONG_MODEM);
     743             : }
     744             : 
     745           1 : int16_t LR2021::setDataRate(DataRate_t dr, ModemType_t modem ) {
     746             :   // get the current modem
     747             :   ModemType_t currentModem;
     748           1 :   int16_t state = this->getModem(&currentModem);
     749           1 :   RADIOLIB_ASSERT(state);
     750             : 
     751             :   // switch over if the requested modem is different
     752           0 :   if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) {
     753           0 :     state = this->standby();
     754           0 :     RADIOLIB_ASSERT(state);
     755           0 :     state = this->setModem(modem);
     756           0 :     RADIOLIB_ASSERT(state);
     757             :   }
     758             :   
     759           0 :   if(modem == RADIOLIB_MODEM_NONE) {
     760           0 :     modem = currentModem;
     761             :   }
     762             : 
     763             :   // select interpretation based on modem
     764           0 :   if(modem == RADIOLIB_MODEM_FSK) {
     765             :     // set the bit rate
     766           0 :     state = this->setBitRate(dr.fsk.bitRate);
     767           0 :     RADIOLIB_ASSERT(state);
     768             : 
     769             :     // set the frequency deviation
     770           0 :     state = this->setFrequencyDeviation(dr.fsk.freqDev);
     771             : 
     772           0 :   } else if(modem == RADIOLIB_MODEM_LORA) {
     773             :     // set the spreading factor
     774           0 :     state = this->setSpreadingFactor(dr.lora.spreadingFactor);
     775           0 :     RADIOLIB_ASSERT(state);
     776             : 
     777             :     // set the bandwidth
     778           0 :     state = this->setBandwidth(dr.lora.bandwidth);
     779           0 :     RADIOLIB_ASSERT(state);
     780             : 
     781             :     // set the coding rate
     782           0 :     state = this->setCodingRate(dr.lora.codingRate);
     783             :   
     784           0 :   } else if(modem == RADIOLIB_MODEM_LRFHSS) {
     785             :     // set the basic config
     786           0 :     state = this->setLrFhssConfig(dr.lrFhss.bw, dr.lrFhss.cr);
     787           0 :     RADIOLIB_ASSERT(state);
     788             : 
     789             :     // set hopping grid
     790           0 :     this->lrFhssGrid = dr.lrFhss.narrowGrid ? RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_FCC;
     791             :   
     792             :   }
     793             : 
     794           0 :   return(state);
     795             : }
     796             : 
     797           1 : int16_t LR2021::checkDataRate(DataRate_t dr, ModemType_t modem) {
     798           1 :   int16_t state = RADIOLIB_ERR_UNKNOWN;
     799             : 
     800             :   // retrieve modem if not supplied
     801           1 :   if(modem == RADIOLIB_MODEM_NONE) {
     802           1 :     state = this->getModem(&modem);
     803           1 :     RADIOLIB_ASSERT(state);
     804             :   }
     805             : 
     806             :   // select interpretation based on modem
     807           0 :   if(modem == RADIOLIB_MODEM_FSK) {
     808           0 :     RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5f, 2000.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
     809           0 :     RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6f,  500.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
     810           0 :     return(RADIOLIB_ERR_NONE);
     811             : 
     812           0 :   } else if(modem == RADIOLIB_MODEM_LORA) {
     813           0 :     RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
     814           0 :     RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
     815           0 :     RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
     816           0 :     return(RADIOLIB_ERR_NONE);
     817             :   
     818             :   }
     819             : 
     820           0 :   return(state);
     821             : }
     822             : 
     823           0 : int16_t LR2021::setLrFhssConfig(uint8_t bw, uint8_t cr, uint8_t hdrCount, uint16_t hopSeed) {
     824             :   // check active modem
     825           0 :   uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     826           0 :   int16_t state = getPacketType(&type);
     827           0 :   RADIOLIB_ASSERT(state);
     828           0 :   if(type != RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS) {
     829           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     830             :   }
     831             : 
     832             :   // check and cache all parameters
     833           0 :   RADIOLIB_CHECK_RANGE((int8_t)cr, (int8_t)RADIOLIB_LRXXXX_LR_FHSS_CR_5_6, (int8_t)RADIOLIB_LRXXXX_LR_FHSS_CR_1_3, RADIOLIB_ERR_INVALID_CODING_RATE);
     834           0 :   this->lrFhssCr = cr;
     835           0 :   RADIOLIB_CHECK_RANGE((int8_t)bw, (int8_t)RADIOLIB_LRXXXX_LR_FHSS_BW_39_06, (int8_t)RADIOLIB_LRXXXX_LR_FHSS_BW_1574_2, RADIOLIB_ERR_INVALID_BANDWIDTH);
     836           0 :   this->lrFhssBw = bw;
     837           0 :   RADIOLIB_CHECK_RANGE(hdrCount, 1, 4, RADIOLIB_ERR_INVALID_BIT_RANGE);
     838           0 :   this->lrFhssHdrCount = hdrCount;
     839           0 :   RADIOLIB_CHECK_RANGE((int16_t)hopSeed, (int16_t)0x000, (int16_t)0x1FF, RADIOLIB_ERR_INVALID_DATA_SHAPING);
     840           0 :   this->lrFhssHopSeq = hopSeed;
     841           0 :   return(RADIOLIB_ERR_NONE);
     842             : }
     843             : 
     844           0 : int16_t LR2021::setRxBoostedGainMode(uint8_t level) {
     845           0 :   if(this->highFreq) {
     846           0 :     this->gainModeHf = level;
     847             :   } else {
     848           0 :     this->gainModeLf = level;
     849             :   }
     850           0 :   return(this->setRxPath(this->highFreq ? RADIOLIB_LR2021_RX_PATH_HF : RADIOLIB_LR2021_RX_PATH_LF, this->highFreq ? this->gainModeHf : this->gainModeLf));
     851             : }
     852             : 
     853           0 : int16_t LR2021::setPacketMode(uint8_t mode, uint8_t len) {
     854             :   // check active modem
     855           0 :   uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     856           0 :   int16_t state = getPacketType(&type);
     857           0 :   RADIOLIB_ASSERT(state);
     858           0 :   if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
     859             :     // set requested packet mode
     860           0 :     state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, mode, len, this->crcTypeGFSK, this->whitening);
     861           0 :     RADIOLIB_ASSERT(state);
     862             : 
     863             :     // update cached value
     864           0 :     this->packetType = mode;
     865           0 :     this->implicitLen = len;
     866           0 :     return(state);
     867             :   
     868           0 :   } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) {
     869             :     // set requested packet mode
     870           0 :     state = setOokPacketParams(this->preambleLengthGFSK, this->addrComp, mode, len, this->crcTypeGFSK, this->whitening);
     871           0 :     RADIOLIB_ASSERT(state);
     872             : 
     873             :     // update cached value
     874           0 :     this->packetType = mode;
     875           0 :     this->implicitLen = len;
     876           0 :     return(state);
     877             :   
     878           0 :   } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
     879           0 :     state = setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, mode == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, len);
     880           0 :     RADIOLIB_ASSERT(state);
     881             : 
     882           0 :     this->packetType = mode;
     883           0 :     this->implicitLen = len;
     884           0 :     return(state);
     885             :   
     886             :   }
     887             : 
     888           0 :   return(RADIOLIB_ERR_WRONG_MODEM);
     889             : }
     890             : 
     891           0 : int16_t LR2021::setLoRaHeaderType(uint8_t hdrType, size_t len) {
     892           0 :   uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     893           0 :   int16_t state = getPacketType(&modem);
     894           0 :   RADIOLIB_ASSERT(state);
     895           0 :   if(modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
     896           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     897             :   }
     898             : 
     899             :   // set requested packet mode
     900           0 :   state = setLoRaPacketParams(this->preambleLengthLoRa, hdrType, len, this->crcTypeLoRa, this->invertIQEnabled);
     901           0 :   RADIOLIB_ASSERT(state);
     902             : 
     903             :   // update cached value
     904           0 :   this->headerType = hdrType;
     905           0 :   this->implicitLen = len;
     906             : 
     907           0 :   return(state);
     908             : }
     909             : 
     910           0 : int16_t LR2021::implicitHeader(size_t len) {
     911           0 :   return(this->setLoRaHeaderType(RADIOLIB_LR2021_LORA_HEADER_IMPLICIT, len));
     912             : }
     913             : 
     914           0 : int16_t LR2021::explicitHeader() {
     915           0 :   return(this->setLoRaHeaderType(RADIOLIB_LR2021_LORA_HEADER_EXPLICIT));
     916             : }
     917             : 
     918           0 : int16_t LR2021::setNodeAddress(uint8_t nodeAddr) {
     919             :   // check active modem
     920           0 :   uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     921           0 :   int16_t state = getPacketType(&type);
     922           0 :   RADIOLIB_ASSERT(state);
     923           0 :   if(type != RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
     924           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     925             :   }
     926             : 
     927             :   // enable address filtering (node only)
     928           0 :   this->addrComp = RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_NODE;
     929           0 :   state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, 
     930           0 :     (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
     931           0 :   RADIOLIB_ASSERT(state);
     932             : 
     933             :   // set node address
     934           0 :   this->node = nodeAddr;
     935           0 :   return(setGfskAddress(this->node, 0));
     936             : }
     937             : 
     938           0 : int16_t LR2021::setBroadcastAddress(uint8_t broadAddr) {
     939             :   // check active modem
     940           0 :   uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     941           0 :   int16_t state = getPacketType(&type);
     942           0 :   RADIOLIB_ASSERT(state);
     943           0 :   if(type != RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
     944           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     945             :   }
     946             : 
     947             :   // enable address filtering (node and broadcast)
     948           0 :   this->addrComp = RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_NODE_BROADCAST;
     949           0 :   state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, 
     950           0 :     (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
     951           0 :   RADIOLIB_ASSERT(state);
     952             : 
     953             :   // set node and broadcast address
     954           0 :   return(setGfskAddress(this->node, broadAddr));
     955             : }
     956             : 
     957           0 : int16_t LR2021::disableAddressFiltering() {
     958             :   // check active modem
     959           0 :   uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     960           0 :   int16_t state = getPacketType(&type);
     961           0 :   RADIOLIB_ASSERT(state);
     962           0 :   if(type != RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
     963           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     964             :   }
     965             : 
     966             :   // disable address filtering
     967           0 :   this->addrComp = RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_DISABLED;
     968           0 :   return(setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, 
     969           0 :     (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
     970             : }
     971             : 
     972           0 : int16_t LR2021::ookDetector(uint16_t pattern, uint8_t len, uint8_t repeats, bool syncRaw, bool rising, uint8_t sofLen) {
     973             :   // check active modem
     974           0 :   uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
     975           0 :   int16_t state = getPacketType(&type);
     976           0 :   RADIOLIB_ASSERT(state);
     977           0 :   if(type != RADIOLIB_LR2021_PACKET_TYPE_OOK) {
     978           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     979             :   }
     980             : 
     981           0 :   return(setOokDetector(pattern, len - 1, repeats, syncRaw, rising, sofLen));
     982             : }
     983             : 
     984           0 : int16_t LR2021::setOokDetectionThreshold(int16_t level) {
     985           0 :   int16_t levelRaw = 64 + level;
     986           0 :   return(this->writeRegMemMask32(RADIOLIB_LR2021_REG_OOK_DETECTION_THRESHOLD, (0x7FUL << 20), (uint32_t)levelRaw << 20));
     987             : }
     988             : 
     989           0 : int16_t LR2021::setSideDetector(const LR2021LoRaSideDetector_t* cfg, size_t numDetectors) {
     990             :   // some basic sanity checks
     991           0 :   if((cfg == nullptr) || (numDetectors == 0)) {
     992           0 :     return(RADIOLIB_ERR_NONE);
     993             :   }
     994             : 
     995           0 :   if(numDetectors > 3) {
     996           0 :     return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
     997             :   }
     998             : 
     999             :   // if bandwidth is higher than 500 kHz, at most 2 side detectors are allowed
    1000           0 :   if((this->bandwidthKhz > 500.0f) && (numDetectors > 2)) {
    1001           0 :     return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
    1002             :   }
    1003             : 
    1004             :   // if the primary spreading factor is 10, 11 or 12, at most 2 side detectors are allowed
    1005           0 :   if((this->spreadingFactor >= 10) && (numDetectors > 2)) {
    1006           0 :     return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
    1007             :   }
    1008             : 
    1009             :   // condition of the primary spreading factor being the smallest/largest is not checked
    1010             :   // this is intentional, because it depends on whether the user wants to start Rx or CAD
    1011             : 
    1012           0 :   uint8_t detectors[3] = { 0 };
    1013           0 :   uint8_t syncWords[3] = { 0 };
    1014           0 :   uint8_t minSf = this->spreadingFactor;
    1015           0 :   uint32_t sumDetFactors = 0;
    1016           0 :   for(size_t i = 0; i < numDetectors; i++) {
    1017             :     // all side-detector spreading factors must be higher than the primary one
    1018             :     //! \todo [LR2021] implement multi-SF for CAD (main SF must be smallest!)
    1019           0 :     if(this->spreadingFactor >= cfg[i].sf) {
    1020           0 :       return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
    1021             :     }
    1022             : 
    1023             :     // the difference between maximum and minimum spreading factor used must be less than or equal to 4
    1024           0 :     if(cfg[i].sf - minSf > 4) {
    1025           0 :       return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
    1026             :     }
    1027             : 
    1028           0 :     if(cfg[i].sf < minSf) { minSf = cfg[i].sf; }
    1029             : 
    1030           0 :     detectors[i] = cfg[i].sf << 4 | cfg[i].ldro << 2 | cfg[i].invertIQ;
    1031           0 :     syncWords[i] = cfg[i].syncWord;
    1032           0 :     sumDetFactors += 10 + (((cfg[i].sf - 5) >> 1) << 1);
    1033             :   }
    1034             : 
    1035             :   // sum of detection factors multiplied by BW must be smaller than 32E6
    1036           0 :   if(sumDetFactors*(uint32_t)this->bandwidthKhz >= 32000UL) {
    1037           0 :     return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
    1038             :   }
    1039             : 
    1040             :   // all spreading factors must be different
    1041           0 :   if(numDetectors >= 2) {
    1042           0 :     if(cfg[0].sf == cfg[1].sf) { 
    1043           0 :       return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
    1044             :     }
    1045             :   }
    1046             : 
    1047           0 :   if(numDetectors == 3) {
    1048           0 :     if((cfg[1].sf == cfg[2].sf) || (cfg[0].sf == cfg[2].sf)) { 
    1049           0 :       return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
    1050             :     }
    1051             :   }
    1052             : 
    1053             :   // check active modem
    1054           0 :   uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
    1055           0 :   int16_t state = getPacketType(&type);
    1056           0 :   RADIOLIB_ASSERT(state);
    1057           0 :   if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
    1058           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1059             :   }
    1060             : 
    1061           0 :   state = setLoRaSideDetConfig(detectors, numDetectors);
    1062           0 :   RADIOLIB_ASSERT(state);
    1063             : 
    1064           0 :   return(setLoRaSideDetSyncword(syncWords, numDetectors));
    1065             : }
    1066             : 
    1067           0 : int16_t LR2021::setGain(uint8_t gain) {
    1068           0 :   if(gain > 13) {
    1069           0 :     return(RADIOLIB_ERR_INVALID_GAIN);
    1070             :   }
    1071           0 :   return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_AGC_GAIN_MANUAL, true, &gain, sizeof(gain)));
    1072             : }
    1073             : 
    1074             : #endif

Generated by: LCOV version 1.14