LCOV - code coverage report
Current view: top level - src/modules/SX126x - SX126x_config.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 464 0.0 %
Date: 2025-10-24 15:14:50 Functions: 0 45 0.0 %

          Line data    Source code
       1             : #include "SX126x.h"
       2             : 
       3             : #include <math.h>
       4             : #include <string.h>
       5             : 
       6             : // this file contains all configuration methods
       7             : // of the SX126x, which let user control the
       8             : // modulation properties, packet configuration etc.
       9             : 
      10             : #if !RADIOLIB_EXCLUDE_SX126X
      11             : 
      12           0 : void SX126x::setDio1Action(void (*func)(void)) {
      13           0 :   this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptRising);
      14           0 : }
      15             : 
      16           0 : void SX126x::clearDio1Action() {
      17           0 :   this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()));
      18           0 : }
      19             : 
      20           0 : void SX126x::setPacketReceivedAction(void (*func)(void)) {
      21           0 :   this->setDio1Action(func);
      22           0 : }
      23             : 
      24           0 : void SX126x::clearPacketReceivedAction() {
      25           0 :   this->clearDio1Action();
      26           0 : }
      27             : 
      28           0 : void SX126x::setPacketSentAction(void (*func)(void)) {
      29           0 :   this->setDio1Action(func);
      30           0 : }
      31             : 
      32           0 : void SX126x::clearPacketSentAction() {
      33           0 :   this->clearDio1Action();
      34           0 : }
      35             : 
      36           0 : void SX126x::setChannelScanAction(void (*func)(void)) {
      37           0 :   this->setDio1Action(func);
      38           0 : }
      39             : 
      40           0 : void SX126x::clearChannelScanAction() {
      41           0 :   this->clearDio1Action();
      42           0 : }
      43             : 
      44           0 : int16_t SX126x::setBandwidth(float bw) {
      45             :   // check active modem
      46           0 :   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
      47           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
      48             :   }
      49             : 
      50             :   // ensure byte conversion doesn't overflow
      51           0 :   RADIOLIB_CHECK_RANGE(bw, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
      52             : 
      53             :   // check allowed bandwidth values
      54           0 :   uint8_t bw_div2 = bw / 2 + 0.01f;
      55           0 :   switch (bw_div2)  {
      56           0 :     case 3: // 7.8:
      57           0 :       this->bandwidth = RADIOLIB_SX126X_LORA_BW_7_8;
      58           0 :       break;
      59           0 :     case 5: // 10.4:
      60           0 :       this->bandwidth = RADIOLIB_SX126X_LORA_BW_10_4;
      61           0 :       break;
      62           0 :     case 7: // 15.6:
      63           0 :       this->bandwidth = RADIOLIB_SX126X_LORA_BW_15_6;
      64           0 :       break;
      65           0 :     case 10: // 20.8:
      66           0 :       this->bandwidth = RADIOLIB_SX126X_LORA_BW_20_8;
      67           0 :       break;
      68           0 :     case 15: // 31.25:
      69           0 :       this->bandwidth = RADIOLIB_SX126X_LORA_BW_31_25;
      70           0 :       break;
      71           0 :     case 20: // 41.7:
      72           0 :       this->bandwidth = RADIOLIB_SX126X_LORA_BW_41_7;
      73           0 :       break;
      74           0 :     case 31: // 62.5:
      75           0 :       this->bandwidth = RADIOLIB_SX126X_LORA_BW_62_5;
      76           0 :       break;
      77           0 :     case 62: // 125.0:
      78           0 :       this->bandwidth = RADIOLIB_SX126X_LORA_BW_125_0;
      79           0 :       break;
      80           0 :     case 125: // 250.0
      81           0 :       this->bandwidth = RADIOLIB_SX126X_LORA_BW_250_0;
      82           0 :       break;
      83           0 :     case 250: // 500.0
      84           0 :       this->bandwidth = RADIOLIB_SX126X_LORA_BW_500_0;
      85           0 :       break;
      86           0 :     default:
      87           0 :       return(RADIOLIB_ERR_INVALID_BANDWIDTH);
      88             :   }
      89             : 
      90             :   // update modulation parameters
      91           0 :   this->bandwidthKhz = bw;
      92           0 :   return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
      93             : }
      94             : 
      95           0 : int16_t SX126x::setSpreadingFactor(uint8_t sf) {
      96             :   // check active modem
      97           0 :   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
      98           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
      99             :   }
     100             : 
     101           0 :   RADIOLIB_CHECK_RANGE(sf, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
     102             : 
     103             :   // update modulation parameters
     104           0 :   this->spreadingFactor = sf;
     105           0 :   return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
     106             : }
     107             : 
     108           0 : int16_t SX126x::setCodingRate(uint8_t cr, bool longInterleave) {
     109             :   // check active modem
     110           0 :   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
     111           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     112             :   }
     113             : 
     114           0 :   RADIOLIB_CHECK_RANGE(cr, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
     115             : 
     116           0 :   if(longInterleave) {
     117           0 :     switch(cr) {
     118           0 :       case 4:
     119           0 :         this->codingRate = 0;
     120           0 :         break;
     121           0 :       case 5:
     122             :       case 6:
     123           0 :         this->codingRate = cr;
     124           0 :         break;
     125           0 :       case 8: 
     126           0 :         this->codingRate = cr - 1;
     127           0 :         break;
     128           0 :       default:
     129           0 :         return(RADIOLIB_ERR_INVALID_CODING_RATE);
     130             :     }
     131             :   } else {
     132           0 :     this->codingRate = cr - 4;
     133             :   }
     134             : 
     135             :   // update modulation parameters
     136           0 :   return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
     137             : }
     138             : 
     139           0 : int16_t SX126x::setSyncWord(uint8_t syncWord, uint8_t controlBits) {
     140             :   // check active modem
     141           0 :   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
     142           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     143             :   }
     144             : 
     145             :   // update register
     146           0 :   const uint8_t data[2] = {(uint8_t)((syncWord & 0xF0) | ((controlBits & 0xF0) >> 4)), (uint8_t)(((syncWord & 0x0F) << 4) | (controlBits & 0x0F))};
     147           0 :   return(writeRegister(RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB, data, 2));
     148             : }
     149             : 
     150           0 : int16_t SX126x::setCurrentLimit(float currentLimit) {
     151             :   // check allowed range
     152           0 :   if(!((currentLimit >= 0) && (currentLimit <= 140))) {
     153           0 :     return(RADIOLIB_ERR_INVALID_CURRENT_LIMIT);
     154             :   }
     155             : 
     156             :   // calculate raw value
     157           0 :   uint8_t rawLimit = (uint8_t)(currentLimit / 2.5f);
     158             : 
     159             :   // update register
     160           0 :   return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &rawLimit, 1));
     161             : }
     162             : 
     163           0 : float SX126x::getCurrentLimit() {
     164             :   // get the raw value
     165           0 :   uint8_t ocp = 0;
     166           0 :   readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
     167             : 
     168             :   // return the actual value
     169           0 :   return((float)ocp * 2.5f);
     170             : }
     171             : 
     172           0 : int16_t SX126x::setPreambleLength(size_t preambleLength) {
     173           0 :   uint8_t modem = getPacketType();
     174           0 :   if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
     175           0 :     this->preambleLengthLoRa = preambleLength;
     176           0 :     return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled));
     177           0 :   } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
     178           0 :     this->preambleLengthFSK = preambleLength;
     179             :     // maximum preamble detector length is limited by sync word length
     180             :     // for details, see the note in SX1261 datasheet, Rev 2.1, section 6.2.2.1, page 45
     181           0 :     uint8_t maxDetLen = RADIOLIB_MIN(this->syncWordLength, this->preambleLengthFSK);
     182           0 :     this->preambleDetLength = maxDetLen >= 32 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 :
     183             :                               maxDetLen >= 24 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 :
     184             :                               maxDetLen >= 16 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 :
     185             :                               maxDetLen >   0 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 :
     186             :                               RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF;
     187           0 :     return(setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType));
     188             :   }
     189             : 
     190           0 :   return(RADIOLIB_ERR_UNKNOWN);
     191             : }
     192             : 
     193           0 : int16_t SX126x::setFrequencyDeviation(float freqDev) {
     194             :   // check active modem
     195           0 :   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
     196           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     197             :   }
     198             : 
     199             :   // set frequency deviation to lowest available setting (required for digimodes)
     200           0 :   float newFreqDev = freqDev;
     201           0 :   if(freqDev < 0.0f) {
     202           0 :     newFreqDev = 0.6f;
     203             :   }
     204             : 
     205           0 :   RADIOLIB_CHECK_RANGE(newFreqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
     206             : 
     207             :   // calculate raw frequency deviation value
     208           0 :   uint32_t freqDevRaw = (uint32_t)(((newFreqDev * 1000.0f) * (float)((uint32_t)(1) << 25)) / (RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0f));
     209             : 
     210             :   // check modulation parameters
     211           0 :   this->frequencyDev = freqDevRaw;
     212             : 
     213             :   // update modulation parameters
     214           0 :   return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
     215             : }
     216             : 
     217           0 : int16_t SX126x::setBitRate(float br) {
     218             :   // check active modem
     219           0 :   uint8_t modem = getPacketType();
     220           0 :   if((modem != RADIOLIB_SX126X_PACKET_TYPE_GFSK) &&
     221           0 :      (modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) &&
     222             :      (modem != RADIOLIB_SX126X_PACKET_TYPE_BPSK)) {
     223           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     224             :   }
     225             : 
     226           0 :   if(modem == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
     227           0 :     RADIOLIB_CHECK_RANGE(br, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
     228           0 :   } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_BPSK) {
     229             :     // this should be just either 100 or 600 bps, not the range
     230             :     // but the BPSK support is so experimental it probably does not matter
     231           0 :     RADIOLIB_CHECK_RANGE(br, 0.1f, 0.6f, RADIOLIB_ERR_INVALID_BIT_RATE);
     232             :   }
     233             : 
     234             :   // calculate raw bit rate value
     235           0 :   uint32_t brRaw = (uint32_t)((RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0f * 32.0f) / (br * 1000.0f));
     236             : 
     237             :   // check modulation parameters
     238           0 :   this->bitRate = brRaw;
     239             : 
     240             :   // update modulation parameters
     241           0 :   int16_t state = RADIOLIB_ERR_UNKNOWN;
     242           0 :   if(modem == RADIOLIB_SX126X_PACKET_TYPE_BPSK) {
     243           0 :     state = setModulationParamsBPSK(this->bitRate);
     244             :   } else {
     245           0 :     state = setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev);
     246             :   }
     247           0 :   RADIOLIB_ASSERT(state);
     248             : 
     249             :   // apply workaround or reset it, as needed
     250           0 :   return(fixGFSK());
     251             : }
     252             : 
     253           0 : int16_t SX126x::setDataRate(DataRate_t dr, ModemType_t modem) {
     254             :   // get the current modem
     255             :   ModemType_t currentModem;
     256           0 :   int16_t state = this->getModem(&currentModem);
     257           0 :   RADIOLIB_ASSERT(state);
     258             : 
     259             :   // switch over if the requested modem is different
     260           0 :   if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) {
     261           0 :     state = this->standby();
     262           0 :     RADIOLIB_ASSERT(state);
     263           0 :     state = this->setModem(modem);
     264           0 :     RADIOLIB_ASSERT(state);
     265             :   }
     266             :   
     267           0 :   if(modem == RADIOLIB_MODEM_NONE) {
     268           0 :     modem = currentModem;
     269             :   }
     270             : 
     271             :   // select interpretation based on modem
     272           0 :   if(modem == RADIOLIB_MODEM_FSK) {
     273             :     // set the bit rate
     274           0 :     state = this->setBitRate(dr.fsk.bitRate);
     275           0 :     RADIOLIB_ASSERT(state);
     276             : 
     277             :     // set the frequency deviation
     278           0 :     state = this->setFrequencyDeviation(dr.fsk.freqDev);
     279             : 
     280           0 :   } else if(modem == RADIOLIB_MODEM_LORA) {
     281             :     // set the spreading factor
     282           0 :     state = this->setSpreadingFactor(dr.lora.spreadingFactor);
     283           0 :     RADIOLIB_ASSERT(state);
     284             : 
     285             :     // set the bandwidth
     286           0 :     state = this->setBandwidth(dr.lora.bandwidth);
     287           0 :     RADIOLIB_ASSERT(state);
     288             : 
     289             :     // set the coding rate
     290           0 :     state = this->setCodingRate(dr.lora.codingRate);
     291             :   
     292           0 :   } else if(modem == RADIOLIB_MODEM_LRFHSS) {
     293             :     // set the basic config
     294           0 :     state = this->setLrFhssConfig(dr.lrFhss.bw, dr.lrFhss.cr);
     295           0 :     RADIOLIB_ASSERT(state);
     296             : 
     297             :     // set hopping grid
     298           0 :     this->lrFhssGridNonFcc = dr.lrFhss.narrowGrid ? RADIOLIB_SX126X_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_SX126X_LR_FHSS_GRID_STEP_FCC;
     299             : 
     300             :   }
     301             : 
     302           0 :   return(state);
     303             : }
     304             : 
     305             : 
     306           0 : int16_t SX126x::checkDataRate(DataRate_t dr, ModemType_t modem) {
     307           0 :   int16_t state = RADIOLIB_ERR_UNKNOWN;
     308             : 
     309             :   // retrieve modem if not supplied
     310           0 :   if(modem == RADIOLIB_MODEM_NONE) {
     311           0 :     state = this->getModem(&modem);
     312           0 :     RADIOLIB_ASSERT(state);
     313             :   }
     314             : 
     315             :   // select interpretation based on modem
     316           0 :   if(modem == RADIOLIB_MODEM_FSK) {
     317           0 :     RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
     318           0 :     RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
     319           0 :     return(RADIOLIB_ERR_NONE);
     320             : 
     321           0 :   } else if(modem == RADIOLIB_MODEM_LORA) {
     322           0 :     RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
     323           0 :     RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
     324           0 :     RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
     325           0 :     return(RADIOLIB_ERR_NONE);
     326             :   
     327             :   }
     328             : 
     329           0 :   return(state);
     330             : }
     331             : 
     332           0 : int16_t SX126x::setRxBandwidth(float rxBw) {
     333             :   // check active modem
     334           0 :   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
     335           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     336             :   }
     337             : 
     338             :   // check modulation parameters
     339             :   /*if(2 * this->frequencyDev + this->bitRate > rxBw * 1000.0) {
     340             :     return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS);
     341             :   }*/
     342           0 :   this->rxBandwidthKhz = rxBw;
     343             : 
     344             :   // check allowed receiver bandwidth values
     345           0 :   if(fabsf(rxBw - 4.8f) <= 0.001f) {
     346           0 :     this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_4_8;
     347           0 :   } else if(fabsf(rxBw - 5.8f) <= 0.001f) {
     348           0 :     this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_5_8;
     349           0 :   } else if(fabsf(rxBw - 7.3f) <= 0.001f) {
     350           0 :     this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_7_3;
     351           0 :   } else if(fabsf(rxBw - 9.7f) <= 0.001f) {
     352           0 :     this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_9_7;
     353           0 :   } else if(fabsf(rxBw - 11.7f) <= 0.001f) {
     354           0 :     this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_11_7;
     355           0 :   } else if(fabsf(rxBw - 14.6f) <= 0.001f) {
     356           0 :     this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_14_6;
     357           0 :   } else if(fabsf(rxBw - 19.5f) <= 0.001f) {
     358           0 :     this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_19_5;
     359           0 :   } else if(fabsf(rxBw - 23.4f) <= 0.001f) {
     360           0 :     this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_23_4;
     361           0 :   } else if(fabsf(rxBw - 29.3f) <= 0.001f) {
     362           0 :     this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_29_3;
     363           0 :   } else if(fabsf(rxBw - 39.0f) <= 0.001f) {
     364           0 :     this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_39_0;
     365           0 :   } else if(fabsf(rxBw - 46.9f) <= 0.001f) {
     366           0 :     this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_46_9;
     367           0 :   } else if(fabsf(rxBw - 58.6f) <= 0.001f) {
     368           0 :     this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_58_6;
     369           0 :   } else if(fabsf(rxBw - 78.2f) <= 0.001f) {
     370           0 :     this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_78_2;
     371           0 :   } else if(fabsf(rxBw - 93.8f) <= 0.001f) {
     372           0 :     this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_93_8;
     373           0 :   } else if(fabsf(rxBw - 117.3f) <= 0.001f) {
     374           0 :     this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_117_3;
     375           0 :   } else if(fabsf(rxBw - 156.2f) <= 0.001f) {
     376           0 :     this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_156_2;
     377           0 :   } else if(fabsf(rxBw - 187.2f) <= 0.001f) {
     378           0 :     this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_187_2;
     379           0 :   } else if(fabsf(rxBw - 234.3f) <= 0.001f) {
     380           0 :     this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_234_3;
     381           0 :   } else if(fabsf(rxBw - 312.0f) <= 0.001f) {
     382           0 :     this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_312_0;
     383           0 :   } else if(fabsf(rxBw - 373.6f) <= 0.001f) {
     384           0 :     this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_373_6;
     385           0 :   } else if(fabsf(rxBw - 467.0f) <= 0.001f) {
     386           0 :     this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_467_0;
     387             :   } else {
     388           0 :     return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH);
     389             :   }
     390             : 
     391             :   // update modulation parameters
     392           0 :   return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
     393             : }
     394             : 
     395           0 : int16_t SX126x::setRxBoostedGainMode(bool rxbgm, bool persist) {
     396             :   // update RX gain setting register
     397           0 :   uint8_t rxGain = rxbgm ? RADIOLIB_SX126X_RX_GAIN_BOOSTED : RADIOLIB_SX126X_RX_GAIN_POWER_SAVING;
     398           0 :   int16_t state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN, &rxGain, 1);
     399           0 :   RADIOLIB_ASSERT(state);
     400             : 
     401             :   // add Rx Gain register to retention memory if requested
     402           0 :   if(persist) {
     403             :     // values and registers below are specified in SX126x datasheet v2.1 section 9.6, just below table 9-3
     404           0 :     const uint8_t data[] = { 0x01, (uint8_t)((RADIOLIB_SX126X_REG_RX_GAIN >> 8) & 0xFF), (uint8_t)(RADIOLIB_SX126X_REG_RX_GAIN & 0xFF) };
     405           0 :     state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_0, data, 3);
     406             :   }
     407             : 
     408           0 :   return(state);
     409             : }
     410             : 
     411           0 : int16_t SX126x::setDataShaping(uint8_t sh) {
     412             :   // check active modem
     413           0 :   uint8_t modem = getPacketType();
     414           0 :   if((modem != RADIOLIB_SX126X_PACKET_TYPE_GFSK) && (modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS)) {
     415           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     416             :   }
     417             : 
     418             :   // set data shaping
     419           0 :   switch(sh) {
     420           0 :     case RADIOLIB_SHAPING_NONE:
     421           0 :       this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_NONE;
     422           0 :       break;
     423           0 :     case RADIOLIB_SHAPING_0_3:
     424           0 :       this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_3;
     425           0 :       break;
     426           0 :     case RADIOLIB_SHAPING_0_5:
     427           0 :       this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5;
     428           0 :       break;
     429           0 :     case RADIOLIB_SHAPING_0_7:
     430           0 :       this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_7;
     431           0 :       break;
     432           0 :     case RADIOLIB_SHAPING_1_0:
     433           0 :       this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_1;
     434           0 :       break;
     435           0 :     default:
     436           0 :       return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
     437             :   }
     438             : 
     439             :   // update modulation parameters
     440           0 :   return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
     441             : }
     442             : 
     443           0 : int16_t SX126x::setSyncWord(uint8_t* syncWord, size_t len) {
     444             :   // check active modem
     445           0 :   uint8_t modem = getPacketType();
     446           0 :   if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
     447             :     // check sync word Length
     448           0 :     if(len > 8) {
     449           0 :       return(RADIOLIB_ERR_INVALID_SYNC_WORD);
     450             :     }
     451             : 
     452             :     // write sync word
     453           0 :     int16_t state = writeRegister(RADIOLIB_SX126X_REG_SYNC_WORD_0, syncWord, len);
     454           0 :     RADIOLIB_ASSERT(state);
     455             : 
     456             :     // update packet parameters
     457           0 :     this->syncWordLength = len * 8;
     458             :     
     459             :     // maximum preamble detector length is limited by sync word length
     460             :     // for details, see the note in SX1261 datasheet, Rev 2.1, section 6.2.2.1, page 45
     461           0 :     uint8_t maxDetLen = RADIOLIB_MIN(this->syncWordLength, this->preambleLengthFSK);
     462           0 :     this->preambleDetLength = maxDetLen >= 32 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 :
     463             :                               maxDetLen >= 24 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 :
     464             :                               maxDetLen >= 16 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 :
     465             :                               maxDetLen >   0 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 :
     466             :                               RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF;
     467           0 :     state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType);
     468             : 
     469           0 :     return(state);
     470             :   
     471           0 :   } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
     472             :     // with length set to 1 and LoRa modem active, assume it is the LoRa sync word
     473           0 :     if(len > 1) {
     474           0 :       return(RADIOLIB_ERR_INVALID_SYNC_WORD);
     475             :     }
     476           0 :     return(setSyncWord(syncWord[0]));
     477             : 
     478           0 :   } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
     479             :     // with length set to 4 and LR-FHSS modem active, assume it is the LR-FHSS sync word
     480           0 :     if(len != sizeof(uint32_t)) {
     481           0 :       return(RADIOLIB_ERR_INVALID_SYNC_WORD);
     482             :     }
     483           0 :     memcpy(this->lrFhssSyncWord, syncWord, sizeof(uint32_t));
     484             :   
     485             :   }
     486             : 
     487           0 :   return(RADIOLIB_ERR_WRONG_MODEM);
     488             : }
     489             : 
     490           0 : int16_t SX126x::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) {
     491             :   // check active modem
     492           0 :   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
     493           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     494             :   }
     495             : 
     496             :   // check sync word Length
     497           0 :   if(bitsLen > 0x40) {
     498           0 :     return(RADIOLIB_ERR_INVALID_SYNC_WORD);
     499             :   }
     500             : 
     501           0 :   uint8_t bytesLen = bitsLen / 8;
     502           0 :   if ((bitsLen % 8) != 0) {
     503           0 :     bytesLen++;
     504             :   }
     505             : 
     506           0 :   return(setSyncWord(syncWord, bytesLen));
     507             : }
     508             : 
     509           0 : int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool inverted) {
     510             :   // check active modem
     511           0 :   uint8_t modem = getPacketType();
     512             : 
     513           0 :   if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
     514             :     // update packet parameters
     515           0 :     switch(len) {
     516           0 :       case 0:
     517           0 :         this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_OFF;
     518           0 :         break;
     519           0 :       case 1:
     520           0 :         if(inverted) {
     521           0 :           this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE_INV;
     522             :         } else {
     523           0 :           this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE;
     524             :         }
     525           0 :         break;
     526           0 :       case 2:
     527           0 :         if(inverted) {
     528           0 :           this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV;
     529             :         } else {
     530           0 :           this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE;
     531             :         }
     532           0 :         break;
     533           0 :       default:
     534           0 :         return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
     535             :     }
     536             : 
     537           0 :     int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType);
     538           0 :     RADIOLIB_ASSERT(state);
     539             : 
     540             :     // write initial CRC value
     541           0 :     uint8_t data[2] = {(uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF)};
     542           0 :     state = writeRegister(RADIOLIB_SX126X_REG_CRC_INITIAL_MSB, data, 2);
     543           0 :     RADIOLIB_ASSERT(state);
     544             : 
     545             :     // write CRC polynomial value
     546           0 :     data[0] = (uint8_t)((polynomial >> 8) & 0xFF);
     547           0 :     data[1] = (uint8_t)(polynomial & 0xFF);
     548           0 :     state = writeRegister(RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_MSB, data, 2);
     549             : 
     550           0 :     return(state);
     551             : 
     552           0 :   } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
     553             :     // LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion
     554             : 
     555             :     // update packet parameters
     556           0 :     if(len) {
     557           0 :       this->crcTypeLoRa = RADIOLIB_SX126X_LORA_CRC_ON;
     558             :     } else {
     559           0 :       this->crcTypeLoRa = RADIOLIB_SX126X_LORA_CRC_OFF;
     560             :     }
     561             : 
     562           0 :     return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled));
     563             :   }
     564             : 
     565           0 :   return(RADIOLIB_ERR_UNKNOWN);
     566             : }
     567             : 
     568           0 : int16_t SX126x::setWhitening(bool enabled, uint16_t initial) {
     569             :   // check active modem
     570           0 :   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
     571           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     572             :   }
     573             : 
     574           0 :   int16_t state = RADIOLIB_ERR_NONE;
     575           0 :   if(!enabled) {
     576             :     // disable whitening
     577           0 :     this->whitening = RADIOLIB_SX126X_GFSK_WHITENING_OFF;
     578             : 
     579           0 :     state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType);
     580           0 :     RADIOLIB_ASSERT(state);
     581             : 
     582             :   } else {
     583             :     // enable whitening
     584           0 :     this->whitening = RADIOLIB_SX126X_GFSK_WHITENING_ON;
     585             : 
     586             :     // write initial whitening value
     587             :     // as per note on pg. 65 of datasheet v1.2: "The user should not change the value of the 7 MSB's of this register"
     588             :     uint8_t data[2];
     589             :     // first read the actual value and mask 7 MSB which we can not change
     590             :     // if different value is written in 7 MSB, the Rx won't even work (tested on HW)
     591           0 :     state = readRegister(RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB, data, 1);
     592           0 :     RADIOLIB_ASSERT(state);
     593             : 
     594           0 :     data[0] = (data[0] & 0xFE) | (uint8_t)((initial >> 8) & 0x01);
     595           0 :     data[1] = (uint8_t)(initial & 0xFF);
     596           0 :     state = writeRegister(RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB, data, 2);
     597           0 :     RADIOLIB_ASSERT(state);
     598             : 
     599           0 :     state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType);
     600           0 :     RADIOLIB_ASSERT(state);
     601             :   }
     602           0 :   return(state);
     603             : }
     604             : 
     605           0 : int16_t SX126x::fixedPacketLengthMode(uint8_t len) {
     606           0 :   return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_FIXED, len));
     607             : }
     608             : 
     609           0 : int16_t SX126x::variablePacketLengthMode(uint8_t maxLen) {
     610           0 :   return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_VARIABLE, maxLen));
     611             : }
     612           0 : int16_t SX126x::implicitHeader(size_t len) {
     613           0 :   return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_IMPLICIT, len));
     614             : }
     615             : 
     616           0 : int16_t SX126x::explicitHeader() {
     617           0 :   return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_EXPLICIT));
     618             : }
     619             : 
     620           0 : int16_t SX126x::setRegulatorLDO() {
     621           0 :   return(setRegulatorMode(RADIOLIB_SX126X_REGULATOR_LDO));
     622             : }
     623             : 
     624           0 : int16_t SX126x::setRegulatorDCDC() {
     625           0 :   return(setRegulatorMode(RADIOLIB_SX126X_REGULATOR_DC_DC));
     626             : }
     627             : 
     628           0 : int16_t SX126x::setEncoding(uint8_t encoding) {
     629           0 :   return(setWhitening(encoding));
     630             : }
     631             : 
     632           0 : void SX126x::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) {
     633           0 :   this->mod->setRfSwitchPins(rxEn, txEn);
     634           0 : }
     635             : 
     636           0 : void SX126x::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) {
     637           0 :   this->mod->setRfSwitchTable(pins, table);
     638           0 : }
     639             : 
     640           0 : int16_t SX126x::forceLDRO(bool enable) {
     641             :   // check active modem
     642           0 :   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
     643           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     644             :   }
     645             : 
     646             :   // update modulation parameters
     647           0 :   this->ldroAuto = false;
     648           0 :   this->ldrOptimize = (uint8_t)enable;
     649           0 :   return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
     650             : }
     651             : 
     652           0 : int16_t SX126x::autoLDRO() {
     653           0 :   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
     654           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     655             :   }
     656             : 
     657           0 :   this->ldroAuto = true;
     658           0 :   return(RADIOLIB_ERR_NONE);
     659             : }
     660             : 
     661           0 : int16_t SX126x::invertIQ(bool enable) {
     662           0 :   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
     663           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     664             :   }
     665             : 
     666           0 :   if(enable) {
     667           0 :     this->invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_INVERTED;
     668             :   } else {
     669           0 :     this->invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_STANDARD;
     670             :   }
     671             : 
     672           0 :   return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled));
     673             : }
     674             : 
     675           0 : int16_t SX126x::setTCXO(float voltage, uint32_t delay) {
     676             :   // check if TCXO is enabled at all
     677           0 :   if(this->XTAL) {
     678           0 :     return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE);
     679             :   }
     680             : 
     681             :   // set mode to standby
     682           0 :   standby();
     683             : 
     684             :   // check RADIOLIB_SX126X_XOSC_START_ERR flag and clear it
     685           0 :   if(getDeviceErrors() & RADIOLIB_SX126X_XOSC_START_ERR) {
     686           0 :     clearDeviceErrors();
     687             :   }
     688             : 
     689             :   // check 0 V disable
     690           0 :   if(fabsf(voltage - 0.0f) <= 0.001f) {
     691           0 :     return(reset(true));
     692             :   }
     693             : 
     694             :   // check alowed voltage values
     695             :   uint8_t data[4];
     696           0 :   if(fabsf(voltage - 1.6f) <= 0.001f) {
     697           0 :     data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_6;
     698           0 :   } else if(fabsf(voltage - 1.7f) <= 0.001f) {
     699           0 :     data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_7;
     700           0 :   } else if(fabsf(voltage - 1.8f) <= 0.001f) {
     701           0 :     data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_8;
     702           0 :   } else if(fabsf(voltage - 2.2f) <= 0.001f) {
     703           0 :     data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_2;
     704           0 :   } else if(fabsf(voltage - 2.4f) <= 0.001f) {
     705           0 :     data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_4;
     706           0 :   } else if(fabsf(voltage - 2.7f) <= 0.001f) {
     707           0 :     data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_7;
     708           0 :   } else if(fabsf(voltage - 3.0f) <= 0.001f) {
     709           0 :     data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_3_0;
     710           0 :   } else if(fabsf(voltage - 3.3f) <= 0.001f) {
     711           0 :     data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_3_3;
     712             :   } else {
     713           0 :     return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE);
     714             :   }
     715             : 
     716             :   // calculate delay
     717           0 :   uint32_t delayValue = (float)delay / 15.625f;
     718           0 :   data[1] = (uint8_t)((delayValue >> 16) & 0xFF);
     719           0 :   data[2] = (uint8_t)((delayValue >> 8) & 0xFF);
     720           0 :   data[3] = (uint8_t)(delayValue & 0xFF);
     721             : 
     722           0 :   this->tcxoDelay = delay;
     723             : 
     724             :   // enable TCXO control on DIO3
     725           0 :   return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL, data, 4));
     726             : }
     727             : 
     728           0 : int16_t SX126x::setDio2AsRfSwitch(bool enable) {
     729           0 :   uint8_t data = enable ? RADIOLIB_SX126X_DIO2_AS_RF_SWITCH : RADIOLIB_SX126X_DIO2_AS_IRQ;
     730           0 :   return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1));
     731             : }
     732           0 : int16_t SX126x::setPaRampTime(uint8_t rampTime) {
     733           0 :   return(this->setTxParams(this->pwr, rampTime));
     734             : }
     735             : 
     736           0 : int16_t SX126x::setPacketMode(uint8_t mode, uint8_t len) {
     737             :   // check active modem
     738           0 :   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
     739           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     740             :   }
     741             : 
     742             :   // set requested packet mode
     743           0 :   int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, mode, len);
     744           0 :   RADIOLIB_ASSERT(state);
     745             : 
     746             :   // update cached value
     747           0 :   this->packetType = mode;
     748           0 :   return(state);
     749             : }
     750             : 
     751           0 : int16_t SX126x::setHeaderType(uint8_t hdrType, size_t len) {
     752             :   // check active modem
     753           0 :   if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
     754           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     755             :   }
     756             : 
     757             :   // set requested packet mode
     758           0 :   int16_t state = setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, len, hdrType, this->invertIQEnabled);
     759           0 :   RADIOLIB_ASSERT(state);
     760             : 
     761             :   // update cached value
     762           0 :   this->headerType = hdrType;
     763           0 :   this->implicitLen = len;
     764             : 
     765           0 :   return(state);
     766             : }
     767             : 
     768           0 : int16_t SX126x::setFrequencyRaw(float freq) {
     769             :   // calculate raw value
     770           0 :   this->freqMHz = freq;
     771           0 :   uint32_t frf = (this->freqMHz * (uint32_t(1) << RADIOLIB_SX126X_DIV_EXPONENT)) / RADIOLIB_SX126X_CRYSTAL_FREQ;
     772           0 :   return(setRfFrequency(frf));
     773             : }
     774             : 
     775           0 : int16_t SX126x::config(uint8_t modem) {
     776             :   // reset buffer base address
     777           0 :   int16_t state = setBufferBaseAddress();
     778           0 :   RADIOLIB_ASSERT(state);
     779             : 
     780             :   // set modem
     781             :   uint8_t data[7];
     782           0 :   data[0] = modem;
     783           0 :   state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_TYPE, data, 1);
     784           0 :   RADIOLIB_ASSERT(state);
     785             : 
     786             :   // set Rx/Tx fallback mode to STDBY_RC
     787           0 :   data[0] = this->standbyXOSC ? RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC : RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC;
     788           0 :   state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1);
     789           0 :   RADIOLIB_ASSERT(state);
     790             : 
     791             :   // set some CAD parameters - will be overwritten when calling CAD anyway
     792           0 :   data[0] = RADIOLIB_SX126X_CAD_ON_8_SYMB;
     793           0 :   data[1] = this->spreadingFactor + 13;
     794           0 :   data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN;
     795           0 :   data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY;
     796           0 :   data[4] = 0x00;
     797           0 :   data[5] = 0x00;
     798           0 :   data[6] = 0x00;
     799           0 :   state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7);
     800           0 :   RADIOLIB_ASSERT(state);
     801             : 
     802             :   // clear IRQ
     803           0 :   state = clearIrqStatus();
     804           0 :   state |= setDioIrqParams(RADIOLIB_SX126X_IRQ_NONE, RADIOLIB_SX126X_IRQ_NONE);
     805           0 :   RADIOLIB_ASSERT(state);
     806             : 
     807             :   // calibrate all blocks
     808           0 :   data[0] = RADIOLIB_SX126X_CALIBRATE_ALL;
     809           0 :   state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE, data, 1, true, false);
     810           0 :   RADIOLIB_ASSERT(state);
     811             : 
     812             :   // wait for calibration completion
     813           0 :   this->mod->hal->delay(5);
     814           0 :   while(this->mod->hal->digitalRead(this->mod->getGpio())) {
     815           0 :     this->mod->hal->yield();
     816             :   }
     817             : 
     818             :   // check calibration result
     819           0 :   state = this->mod->SPIcheckStream();
     820             : 
     821             :   // if something failed, show the device errors
     822             :   #if RADIOLIB_DEBUG_BASIC
     823             :   if(state != RADIOLIB_ERR_NONE) {
     824             :     // unless mode is forced to standby, device errors will be 0
     825             :     standby();
     826             :     uint16_t errors = getDeviceErrors();
     827             :     RADIOLIB_DEBUG_BASIC_PRINTLN("Calibration failed, device errors: 0x%X", errors);
     828             :   }
     829             :   #endif
     830             : 
     831           0 :   return(state);
     832             : }
     833             : 
     834             : #endif

Generated by: LCOV version 1.14