LCOV - code coverage report
Current view: top level - src/modules/LR2021 - LR2021_config.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 62 640 9.7 %
Date: 2026-07-20 05:22:49 Functions: 14 41 34.1 %

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

Generated by: LCOV version 1.14