LCOV - code coverage report
Current view: top level - src/modules/SX127x - SX1278.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 71 439 16.2 %
Date: 2026-04-06 12:28:13 Functions: 14 31 45.2 %

          Line data    Source code
       1             : #include "SX1278.h"
       2             : #include <math.h>
       3             : #if !RADIOLIB_EXCLUDE_SX127X
       4             : 
       5           3 : SX1278::SX1278(Module* mod) : SX127x(mod) {
       6             : 
       7           3 : }
       8             : 
       9           0 : int16_t SX1278::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) {
      10             :   // execute common part
      11           0 :   const uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X };
      12           0 :   int16_t state = SX127x::begin(versions, 3, syncWord, preambleLength);
      13           0 :   RADIOLIB_ASSERT(state);
      14             : 
      15             :   // configure publicly accessible settings
      16           0 :   state = setBandwidth(bw);
      17           0 :   RADIOLIB_ASSERT(state);
      18             : 
      19           0 :   state = setFrequency(freq);
      20           0 :   RADIOLIB_ASSERT(state);
      21             : 
      22           0 :   state = setSpreadingFactor(sf);
      23           0 :   RADIOLIB_ASSERT(state);
      24             : 
      25           0 :   state = setCodingRate(cr);
      26           0 :   RADIOLIB_ASSERT(state);
      27             : 
      28           0 :   state = setOutputPower(power);
      29           0 :   RADIOLIB_ASSERT(state);
      30             : 
      31           0 :   state = setGain(gain);
      32           0 :   RADIOLIB_ASSERT(state);
      33             : 
      34             :   // set publicly accessible settings that are not a part of begin method
      35           0 :   state = setCRC(true);
      36           0 :   RADIOLIB_ASSERT(state);
      37             : 
      38           0 :   return(state);
      39             : }
      40             : 
      41           0 : int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) {
      42             :   // execute common part
      43           0 :   const uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X };
      44           0 :   int16_t state = SX127x::beginFSK(versions, 3, freqDev, rxBw, preambleLength, enableOOK);
      45           0 :   RADIOLIB_ASSERT(state);
      46             : 
      47             :   // configure settings not accessible by API
      48           0 :   state = configFSK();
      49           0 :   RADIOLIB_ASSERT(state);
      50             : 
      51             :   // configure publicly accessible settings
      52           0 :   state = setFrequency(freq);
      53           0 :   RADIOLIB_ASSERT(state);
      54             : 
      55           0 :   state = setBitRate(br);
      56           0 :   RADIOLIB_ASSERT(state);
      57             : 
      58           0 :   state = setOutputPower(power);
      59           0 :   RADIOLIB_ASSERT(state);
      60             : 
      61           0 :   if(enableOOK) {
      62           0 :     state = setDataShapingOOK(RADIOLIB_SHAPING_NONE);
      63           0 :     RADIOLIB_ASSERT(state);
      64             :   } else {
      65           0 :     state = setDataShaping(RADIOLIB_SHAPING_NONE);
      66           0 :     RADIOLIB_ASSERT(state);
      67             :   }
      68             : 
      69             :   // set publicly accessible settings that are not a part of begin method
      70           0 :   state = setCRC(true);
      71           0 :   RADIOLIB_ASSERT(state);
      72             : 
      73           0 :   return(state);
      74             : }
      75             : 
      76           0 : void SX1278::reset() {
      77           0 :   Module* mod = this->getMod();
      78           0 :   mod->hal->pinMode(mod->getRst(), mod->hal->GpioModeOutput);
      79           0 :   mod->hal->digitalWrite(mod->getRst(), mod->hal->GpioLevelLow);
      80           0 :   mod->hal->delay(1);
      81           0 :   mod->hal->digitalWrite(mod->getRst(), mod->hal->GpioLevelHigh);
      82           0 :   mod->hal->delay(5);
      83           0 : }
      84             : 
      85           1 : int16_t SX1278::setFrequency(float freq) {
      86             :   // NOTE: The datasheet specifies Band 2 as 410-525 MHz, but the hardware has been
      87             :   // verified to work down to ~395 MHz. The lower bound is set here to 395 MHz to
      88             :   // accommodate real-world use cases (e.g. TinyGS satellites, radiosondes) while
      89             :   // adding a small margin below the 400 MHz practical limit.
      90           1 :   if(!(((freq >= 137.0f) && (freq <= 175.0f)) ||
      91           1 :        ((freq >= 395.0f) && (freq <= 525.0f)))) {
      92           1 :     return(RADIOLIB_ERR_INVALID_FREQUENCY);
      93             :   }
      94             : 
      95             :   // set frequency and if successful, save the new setting
      96           0 :   int16_t state = SX127x::setFrequencyRaw(freq);
      97           0 :   if(state == RADIOLIB_ERR_NONE) {
      98           0 :     SX127x::frequency = freq;
      99             :   }
     100           0 :   return(state);
     101             : }
     102             : 
     103           0 : int16_t SX1278::setBandwidth(float bw) {
     104             :   // check active modem
     105           0 :   if(getActiveModem() != RADIOLIB_SX127X_LORA) {
     106           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     107             :   }
     108             : 
     109             :   uint8_t newBandwidth;
     110             : 
     111             :   // check allowed bandwidth values
     112           0 :   if(fabsf(bw - 7.8f) <= 0.001f) {
     113           0 :     newBandwidth = RADIOLIB_SX1278_BW_7_80_KHZ;
     114           0 :   } else if(fabsf(bw - 10.4f) <= 0.001f) {
     115           0 :     newBandwidth = RADIOLIB_SX1278_BW_10_40_KHZ;
     116           0 :   } else if(fabsf(bw - 15.6f) <= 0.001f) {
     117           0 :     newBandwidth = RADIOLIB_SX1278_BW_15_60_KHZ;
     118           0 :   } else if(fabsf(bw - 20.8f) <= 0.001f) {
     119           0 :     newBandwidth = RADIOLIB_SX1278_BW_20_80_KHZ;
     120           0 :   } else if(fabsf(bw - 31.25f) <= 0.001f) {
     121           0 :     newBandwidth = RADIOLIB_SX1278_BW_31_25_KHZ;
     122           0 :   } else if(fabsf(bw - 41.7f) <= 0.001f) {
     123           0 :     newBandwidth = RADIOLIB_SX1278_BW_41_70_KHZ;
     124           0 :   } else if(fabsf(bw - 62.5f) <= 0.001f) {
     125           0 :     newBandwidth = RADIOLIB_SX1278_BW_62_50_KHZ;
     126           0 :   } else if(fabsf(bw - 125.0f) <= 0.001f) {
     127           0 :     newBandwidth = RADIOLIB_SX1278_BW_125_00_KHZ;
     128           0 :   } else if(fabsf(bw - 250.0f) <= 0.001f) {
     129           0 :     newBandwidth = RADIOLIB_SX1278_BW_250_00_KHZ;
     130           0 :   } else if(fabsf(bw - 500.0f) <= 0.001f) {
     131           0 :     newBandwidth = RADIOLIB_SX1278_BW_500_00_KHZ;
     132             :   } else {
     133           0 :     return(RADIOLIB_ERR_INVALID_BANDWIDTH);
     134             :   }
     135             : 
     136             :   // set bandwidth and if successful, save the new setting
     137           0 :   int16_t state = SX1278::setBandwidthRaw(newBandwidth);
     138           0 :   if(state == RADIOLIB_ERR_NONE) {
     139           0 :     SX127x::bandwidth = bw;
     140             : 
     141             :     // calculate symbol length and set low data rate optimization, if auto-configuration is enabled
     142           0 :     if(this->ldroAuto) {
     143           0 :       float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth;
     144           0 :       Module* mod = this->getMod();
     145           0 :       if(symbolLength >= 16.0f) {
     146           0 :         this->ldroEnabled = true;
     147           0 :         state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3);
     148             :       } else {
     149           0 :         this->ldroEnabled = false;
     150           0 :         state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3);
     151             :       }
     152             :     }
     153             :   }
     154           0 :   return(state);
     155             : }
     156             : 
     157           2 : int16_t SX1278::setSpreadingFactor(uint8_t sf) {
     158             :   // check active modem
     159           2 :   if(getActiveModem() != RADIOLIB_SX127X_LORA) {
     160           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     161             :   }
     162             : 
     163             :   uint8_t newSpreadingFactor;
     164             : 
     165             :   // check allowed spreading factor values
     166           2 :   switch(sf) {
     167           0 :     case 6:
     168           0 :       newSpreadingFactor = RADIOLIB_SX127X_SF_6;
     169           0 :       break;
     170           0 :     case 7:
     171           0 :       newSpreadingFactor = RADIOLIB_SX127X_SF_7;
     172           0 :       break;
     173           0 :     case 8:
     174           0 :       newSpreadingFactor = RADIOLIB_SX127X_SF_8;
     175           0 :       break;
     176           0 :     case 9:
     177           0 :       newSpreadingFactor = RADIOLIB_SX127X_SF_9;
     178           0 :       break;
     179           0 :     case 10:
     180           0 :       newSpreadingFactor = RADIOLIB_SX127X_SF_10;
     181           0 :       break;
     182           0 :     case 11:
     183           0 :       newSpreadingFactor = RADIOLIB_SX127X_SF_11;
     184           0 :       break;
     185           0 :     case 12:
     186           0 :       newSpreadingFactor = RADIOLIB_SX127X_SF_12;
     187           0 :       break;
     188           2 :     default:
     189           2 :       return(RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
     190             :   }
     191             : 
     192             :   // set spreading factor and if successful, save the new setting
     193           0 :   int16_t state = SX1278::setSpreadingFactorRaw(newSpreadingFactor);
     194           0 :   if(state == RADIOLIB_ERR_NONE) {
     195           0 :     SX127x::spreadingFactor = sf;
     196             : 
     197             :     // calculate symbol length and set low data rate optimization, if auto-configuration is enabled
     198           0 :     if(this->ldroAuto) {
     199           0 :       float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth;
     200           0 :       Module* mod = this->getMod();
     201           0 :       if(symbolLength >= 16.0f) {
     202           0 :         state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3);
     203             :       } else {
     204           0 :         state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3);
     205             :       }
     206             :     }
     207             :   }
     208           0 :   return(state);
     209             : }
     210             : 
     211           0 : int16_t SX1278::setCodingRate(uint8_t cr) {
     212             :   // check active modem
     213           0 :   if(getActiveModem() != RADIOLIB_SX127X_LORA) {
     214           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     215             :   }
     216             : 
     217             :   uint8_t newCodingRate;
     218             : 
     219             :   // check allowed coding rate values
     220           0 :   switch(cr) {
     221           0 :     case 4:
     222           0 :       newCodingRate = RADIOLIB_SX1278_CR_4_4;
     223           0 :       break;
     224           0 :     case 5:
     225           0 :       newCodingRate = RADIOLIB_SX1278_CR_4_5;
     226           0 :       break;
     227           0 :     case 6:
     228           0 :       newCodingRate = RADIOLIB_SX1278_CR_4_6;
     229           0 :       break;
     230           0 :     case 7:
     231           0 :       newCodingRate = RADIOLIB_SX1278_CR_4_7;
     232           0 :       break;
     233           0 :     case 8:
     234           0 :       newCodingRate = RADIOLIB_SX1278_CR_4_8;
     235           0 :       break;
     236           0 :     default:
     237           0 :       return(RADIOLIB_ERR_INVALID_CODING_RATE);
     238             :   }
     239             : 
     240             :   // set coding rate and if successful, save the new setting
     241           0 :   int16_t state = SX1278::setCodingRateRaw(newCodingRate);
     242           0 :   if(state == RADIOLIB_ERR_NONE) {
     243           0 :     SX127x::codingRate = cr;
     244             :   }
     245           0 :   return(state);
     246             : }
     247             : 
     248           3 : int16_t SX1278::setBitRate(float br) {
     249           3 :   return(SX127x::setBitRateCommon(br, RADIOLIB_SX1278_REG_BIT_RATE_FRAC));
     250             : }
     251             : 
     252           2 : int16_t SX1278::setDataRate(DataRate_t dr, ModemType_t modem) {
     253             :   // get the current modem
     254             :   ModemType_t currentModem;
     255           2 :   int16_t state = this->getModem(&currentModem);
     256           2 :   RADIOLIB_ASSERT(state);
     257             : 
     258             :   // switch over if the requested modem is different
     259           2 :   if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) {
     260           0 :     state = this->standby();
     261           0 :     RADIOLIB_ASSERT(state);
     262           0 :     state = this->setModem(modem);
     263           0 :     RADIOLIB_ASSERT(state);
     264             :   }
     265             :   
     266           2 :   if(modem == RADIOLIB_MODEM_NONE) {
     267           2 :     modem = currentModem;
     268             :   }
     269             : 
     270             :   // select interpretation based on modem
     271           2 :   if(modem == RADIOLIB_MODEM_FSK) {
     272             :     // set the bit rate
     273           0 :     state = this->setBitRate(dr.fsk.bitRate);
     274           0 :     RADIOLIB_ASSERT(state);
     275             : 
     276             :     // set the frequency deviation
     277           0 :     state = this->setFrequencyDeviation(dr.fsk.freqDev);
     278             : 
     279           2 :   } else if(modem == RADIOLIB_MODEM_LORA) {
     280             :     // set the spreading factor
     281           2 :     state = this->setSpreadingFactor(dr.lora.spreadingFactor);
     282           2 :     RADIOLIB_ASSERT(state);
     283             : 
     284             :     // set the bandwidth
     285           0 :     state = this->setBandwidth(dr.lora.bandwidth);
     286           0 :     RADIOLIB_ASSERT(state);
     287             : 
     288             :     // set the coding rate
     289           0 :     state = this->setCodingRate(dr.lora.codingRate);
     290             :   }
     291             : 
     292           0 :   return(state);
     293             : }
     294             : 
     295           2 : int16_t SX1278::checkDataRate(DataRate_t dr, ModemType_t modem) {
     296           2 :   int16_t state = RADIOLIB_ERR_UNKNOWN;
     297             : 
     298             :   // retrieve modem if not supplied
     299           2 :   if(modem == RADIOLIB_MODEM_NONE) {
     300           2 :     state = this->getModem(&modem);
     301           2 :     RADIOLIB_ASSERT(state);
     302             :   }
     303             : 
     304             :   // select interpretation based on modem
     305           2 :   if(modem == RADIOLIB_MODEM_FSK) {
     306           0 :     RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
     307           0 :     if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0f <= 250.0f) && (dr.fsk.freqDev <= 200.0f))) {
     308           0 :       return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
     309             :     }
     310           0 :     return(RADIOLIB_ERR_NONE);
     311             : 
     312           2 :   } else if(modem == RADIOLIB_MODEM_LORA) {
     313           2 :     RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
     314           0 :     RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
     315           0 :     RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
     316           0 :     return(RADIOLIB_ERR_NONE);
     317             :   
     318             :   }
     319             : 
     320           0 :   return(state);
     321             : }
     322             : 
     323           3 : int16_t SX1278::setOutputPower(int8_t power) {
     324           3 :   return(this->setOutputPower(power, false));
     325             : }
     326             : 
     327           3 : int16_t SX1278::setOutputPower(int8_t power, bool forceRfo) {
     328             :   // check if power value is configurable
     329           3 :   bool useRfo = (power < 2) || forceRfo;
     330           3 :   int16_t state = checkOutputPower(power, NULL, useRfo);
     331           3 :   RADIOLIB_ASSERT(state);
     332             : 
     333             :   // set mode to standby
     334           3 :   state = SX127x::standby();
     335           3 :   Module* mod = this->getMod();
     336             : 
     337           3 :   if(useRfo) {
     338           3 :     uint8_t paCfg = 0;
     339           3 :     if(power < 0) {
     340             :       // low power mode RFO output
     341           0 :       paCfg = RADIOLIB_SX1278_LOW_POWER | (power + 3);
     342             :     } else {
     343             :       // high power mode RFO output
     344           3 :       paCfg = RADIOLIB_SX1278_MAX_POWER | power;
     345             :     }
     346             : 
     347           3 :     state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_RFO, 7, 7);
     348           3 :     state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, paCfg, 6, 0);
     349           3 :     state |= mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0);
     350             : 
     351             :   } else {
     352           0 :     if(power != 20) {
     353             :       // power is 2 - 17 dBm, enable PA1 + PA2 on PA_BOOST
     354           0 :       state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7);
     355           0 :       state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX1278_MAX_POWER | (power - 2), 6, 0);
     356           0 :       state |= mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0);
     357             : 
     358             :     } else {
     359             :       // power is 20 dBm, enable PA1 + PA2 on PA_BOOST and enable high power control
     360           0 :       state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7);
     361           0 :       state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX1278_MAX_POWER | 0x0F, 6, 0);
     362           0 :       state |= mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_ON, 2, 0);
     363             : 
     364             :     }
     365             :   }
     366             : 
     367           3 :   return(state);
     368             : }
     369             : 
     370           3 : int16_t SX1278::checkOutputPower(int8_t power, int8_t* clipped) {
     371           3 :   return(checkOutputPower(power, clipped, false));
     372             : }
     373             : 
     374           6 : int16_t SX1278::checkOutputPower(int8_t power, int8_t* clipped, bool useRfo) {
     375             :   // check allowed power range
     376           6 :   if(useRfo) {
     377             :     // RFO output
     378           3 :     if(clipped) {
     379           0 :       *clipped = RADIOLIB_MAX(-4, RADIOLIB_MIN(15, power));
     380             :     }
     381           3 :     RADIOLIB_CHECK_RANGE(power, -4, 15, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
     382             :   } else {
     383             :     // PA_BOOST output, check high-power operation
     384           3 :     if(clipped) {
     385           0 :       if(power != 20) {
     386           0 :         *clipped = RADIOLIB_MAX(2, RADIOLIB_MIN(17, power));
     387             :       } else {
     388           0 :         *clipped = 20;
     389             :       }
     390             :     }
     391           3 :     if(power != 20) {
     392           3 :       RADIOLIB_CHECK_RANGE(power, 2, 17, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
     393             :     }
     394             :   }
     395           3 :   return(RADIOLIB_ERR_NONE);
     396             : }
     397             : 
     398           0 : int16_t SX1278::setGain(uint8_t gain) {
     399             :   // check allowed range
     400           0 :   if(gain > 6) {
     401           0 :     return(RADIOLIB_ERR_INVALID_GAIN);
     402             :   }
     403             : 
     404             :   // set mode to standby
     405           0 :   int16_t state = SX127x::standby();
     406           0 :   Module* mod = this->getMod();
     407             : 
     408             :   // get modem
     409           0 :   int16_t modem = getActiveModem();
     410           0 :   if(modem == RADIOLIB_SX127X_LORA){
     411             :     // set gain
     412           0 :     if(gain == 0) {
     413             :       // gain set to 0, enable AGC loop
     414           0 :       state |= mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_AGC_AUTO_ON, 2, 2);
     415           0 :       state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, RADIOLIB_SX127X_LNA_BOOST_ON, 1, 0);
     416             :     } else {
     417           0 :       state |= mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_AGC_AUTO_OFF, 2, 2);
     418           0 :       state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON);
     419             :     }
     420             : 
     421           0 :   } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
     422             :     // set gain
     423           0 :     if(gain == 0) {
     424             :       // gain set to 0, enable AGC loop
     425           0 :       state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX127X_AGC_AUTO_ON, 3, 3);
     426             :     } else {
     427           0 :       state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX1278_AGC_AUTO_OFF, 3, 3);
     428           0 :       state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON);
     429             :     }
     430             : 
     431             :   }
     432             : 
     433           0 :   return(state);
     434             : }
     435             : 
     436           3 : int16_t SX1278::setDataShaping(uint8_t sh) {
     437             :   // check active modem
     438           3 :   if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
     439           3 :     return(RADIOLIB_ERR_WRONG_MODEM);
     440             :   }
     441             : 
     442             :   // check modulation
     443           0 :   if(SX127x::ookEnabled) {
     444             :     // we're in OOK mode, the only thing we can do is disable
     445           0 :     if(sh == RADIOLIB_SHAPING_NONE) {
     446           0 :       return(setDataShapingOOK(0));
     447             :     }
     448             : 
     449           0 :     return(RADIOLIB_ERR_INVALID_MODULATION);
     450             :   }
     451             : 
     452             :   // set mode to standby
     453           0 :   int16_t state = SX127x::standby();
     454           0 :   RADIOLIB_ASSERT(state);
     455             : 
     456             :   // set data shaping
     457           0 :   Module* mod = this->getMod();
     458           0 :   switch(sh) {
     459           0 :     case RADIOLIB_SHAPING_NONE:
     460           0 :       return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_NO_SHAPING, 6, 5));
     461           0 :     case RADIOLIB_SHAPING_0_3:
     462           0 :       return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_0_3, 6, 5));
     463           0 :     case RADIOLIB_SHAPING_0_5:
     464           0 :       return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_0_5, 6, 5));
     465           0 :     case RADIOLIB_SHAPING_1_0:
     466           0 :       return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_1_0, 6, 5));
     467           0 :     default:
     468           0 :       return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
     469             :   }
     470             : }
     471             : 
     472           0 : int16_t SX1278::setDataShapingOOK(uint8_t sh) {
     473             :   // check active modem
     474           0 :   if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
     475           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     476             :   }
     477             : 
     478             :   // check modulation
     479           0 :   if(!SX127x::ookEnabled) {
     480           0 :     return(RADIOLIB_ERR_INVALID_MODULATION);
     481             :   }
     482             : 
     483             :   // set mode to standby
     484           0 :   int16_t state = SX127x::standby();
     485             : 
     486             :   // set data shaping
     487           0 :   Module* mod = this->getMod();
     488           0 :   switch(sh) {
     489           0 :     case 0:
     490           0 :       state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_NO_SHAPING, 6, 5);
     491           0 :       break;
     492           0 :     case 1:
     493           0 :       state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_OOK_FILTER_BR, 6, 5);
     494           0 :       break;
     495           0 :     case 2:
     496           0 :       state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_OOK_FILTER_2BR, 6, 5);
     497           0 :       break;
     498           0 :     default:
     499           0 :       return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
     500             :   }
     501             : 
     502           0 :   return(state);
     503             : }
     504             : 
     505           3 : float SX1278::getRSSI() {
     506           3 :   return(SX1278::getRSSI(true, false));
     507             : }
     508             : 
     509           3 : float SX1278::getRSSI(bool packet, bool skipReceive) {
     510           3 :   int16_t offset = -157;
     511           3 :   if(frequency < 868.0f) {
     512           3 :     offset = -164;
     513             :   }
     514           3 :   return(SX127x::getRSSI(packet, skipReceive, offset));
     515             : }
     516             : 
     517           0 : int16_t SX1278::setCRC(bool enable, bool mode) {
     518           0 :   Module* mod = this->getMod();
     519           0 :   if(getActiveModem() == RADIOLIB_SX127X_LORA) {
     520             :     // set LoRa CRC
     521           0 :     SX127x::crcEnabled = enable;
     522           0 :     if(enable) {
     523           0 :       return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1278_RX_CRC_MODE_ON, 2, 2));
     524             :     } else {
     525           0 :       return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1278_RX_CRC_MODE_OFF, 2, 2));
     526             :     }
     527             :   } else {
     528             :     // set FSK CRC
     529           0 :     int16_t state = RADIOLIB_ERR_NONE;
     530           0 :     if(enable) {
     531           0 :       state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_ON, 4, 4);
     532             :     } else {
     533           0 :       state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_OFF, 4, 4);
     534             :     }
     535           0 :     RADIOLIB_ASSERT(state);
     536             : 
     537             :     // set FSK CRC mode
     538           0 :     if(mode) {
     539           0 :       return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_IBM, 0, 0));
     540             :     } else {
     541           0 :       return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT, 0, 0));
     542             :     }
     543             :   }
     544             : }
     545             : 
     546           0 : int16_t SX1278::forceLDRO(bool enable) {
     547           0 :   if(getActiveModem() != RADIOLIB_SX127X_LORA) {
     548           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     549             :   }
     550             : 
     551           0 :   Module* mod = this->getMod();
     552           0 :   this->ldroAuto = false;
     553           0 :   this->ldroEnabled = enable;
     554           0 :   if(enable) {
     555           0 :     return(mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3));
     556             :   } else {
     557           0 :     return(mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3));
     558             :   }
     559             : }
     560             : 
     561           0 : int16_t SX1278::autoLDRO() {
     562           0 :   if(getActiveModem() != RADIOLIB_SX127X_LORA) {
     563           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     564             :   }
     565             : 
     566           0 :   this->ldroAuto = true;
     567           0 :   return(RADIOLIB_ERR_NONE);
     568             : }
     569             : 
     570           0 : int16_t SX1278::implicitHeader(size_t len) {
     571           0 :   this->implicitHdr = true;
     572           0 :   return(setHeaderType(RADIOLIB_SX1278_HEADER_IMPL_MODE, 0, len));
     573             : }
     574             : 
     575           0 : int16_t SX1278::explicitHeader() {
     576           0 :   this->implicitHdr = false;
     577           0 :   return(setHeaderType(RADIOLIB_SX1278_HEADER_EXPL_MODE, 0));
     578             : }
     579             : 
     580           0 : int16_t SX1278::setBandwidthRaw(uint8_t newBandwidth) {
     581             :   // set mode to standby
     582           0 :   int16_t state = SX127x::standby();
     583             : 
     584             :   // write register
     585           0 :   Module* mod = this->getMod();
     586           0 :   state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newBandwidth, 7, 4);
     587           0 :   return(state);
     588             : }
     589             : 
     590           0 : int16_t SX1278::setSpreadingFactorRaw(uint8_t newSpreadingFactor) {
     591             :   // set mode to standby
     592           0 :   int16_t state = SX127x::standby();
     593             : 
     594             :   // write registers
     595           0 :   Module* mod = this->getMod();
     596           0 :   if(newSpreadingFactor == RADIOLIB_SX127X_SF_6) {
     597           0 :     this->implicitHdr = true;
     598           0 :     state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1278_HEADER_IMPL_MODE, 0, 0);
     599           0 :     state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX127X_SF_6 | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3);
     600           0 :     state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_6, 2, 0);
     601           0 :     state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_6);
     602             :   } else {
     603           0 :     this->implicitHdr = false;
     604           0 :     state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1278_HEADER_EXPL_MODE, 0, 0);
     605           0 :     state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3);
     606           0 :     state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0);
     607           0 :     state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_7_12);
     608             :   }
     609           0 :   return(state);
     610             : }
     611             : 
     612           0 : int16_t SX1278::setCodingRateRaw(uint8_t newCodingRate) {
     613             :   // set mode to standby
     614           0 :   int16_t state = SX127x::standby();
     615             : 
     616             :   // write register
     617           0 :   Module* mod = this->getMod();
     618           0 :   state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newCodingRate, 3, 1);
     619           0 :   return(state);
     620             : }
     621             : 
     622           0 : int16_t SX1278::configFSK() {
     623             :   // configure common registers
     624           0 :   int16_t state = SX127x::configFSK();
     625           0 :   RADIOLIB_ASSERT(state);
     626             : 
     627             :   // set fast PLL hop
     628           0 :   Module* mod = this->getMod();
     629           0 :   state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PLL_HOP, RADIOLIB_SX127X_FAST_HOP_ON, 7, 7);
     630           0 :   return(state);
     631             : }
     632             : 
     633           0 : void SX1278::errataFix(bool rx) {
     634             :   // only apply in LoRa mode
     635           0 :   if(getActiveModem() != RADIOLIB_SX127X_LORA) {
     636           0 :     return;
     637             :   }
     638             : 
     639             :   // sensitivity optimization for 500kHz bandwidth
     640             :   // see SX1276/77/78 Errata, section 2.1 for details
     641           0 :   Module* mod = this->getMod();
     642           0 :   if(fabsf(SX127x::bandwidth - 500.0f) <= 0.001f) {
     643           0 :     if((frequency >= 862.0f) && (frequency <= 1020.0f)) {
     644           0 :       mod->SPIwriteRegister(0x36, 0x02);
     645           0 :       mod->SPIwriteRegister(0x3a, 0x64);
     646           0 :     } else if((frequency >= 410.0f) && (frequency <= 525.0f)) {
     647           0 :       mod->SPIwriteRegister(0x36, 0x02);
     648           0 :       mod->SPIwriteRegister(0x3a, 0x7F);
     649             :     }
     650             :   }
     651             : 
     652             :   // mitigation of receiver spurious response
     653             :   // see SX1276/77/78 Errata, section 2.3 for details
     654             : 
     655             :   // figure out what we need to set
     656           0 :   uint8_t fixedRegs[3] = { 0x00, 0x00, 0x00 };
     657           0 :   float rxFreq = frequency;
     658           0 :   if(fabsf(SX127x::bandwidth - 7.8f) <= 0.001f) {
     659           0 :     fixedRegs[0] = 0b00000000;
     660           0 :     fixedRegs[1] = 0x48;
     661           0 :     fixedRegs[2] = 0x00;
     662           0 :     rxFreq += 0.00781f;
     663           0 :   } else if(fabsf(SX127x::bandwidth - 10.4f) <= 0.001f) {
     664           0 :     fixedRegs[0] = 0b00000000;
     665           0 :     fixedRegs[1] = 0x44;
     666           0 :     fixedRegs[2] = 0x00;
     667           0 :     rxFreq += 0.01042f;
     668           0 :   } else if(fabsf(SX127x::bandwidth - 15.6f) <= 0.001f) {
     669           0 :     fixedRegs[0] = 0b00000000;
     670           0 :     fixedRegs[1] = 0x44;
     671           0 :     fixedRegs[2] = 0x00;
     672           0 :     rxFreq += 0.01562f;
     673           0 :   } else if(fabsf(SX127x::bandwidth - 20.8f) <= 0.001f) {
     674           0 :     fixedRegs[0] = 0b00000000;
     675           0 :     fixedRegs[1] = 0x44;
     676           0 :     fixedRegs[2] = 0x00;
     677           0 :     rxFreq += 0.02083f;
     678           0 :   } else if(fabsf(SX127x::bandwidth - 31.25f) <= 0.001f) {
     679           0 :     fixedRegs[0] = 0b00000000;
     680           0 :     fixedRegs[1] = 0x44;
     681           0 :     fixedRegs[2] = 0x00;
     682           0 :     rxFreq += 0.03125f;
     683           0 :   } else if(fabsf(SX127x::bandwidth - 41.7f) <= 0.001f) {
     684           0 :     fixedRegs[0] = 0b00000000;
     685           0 :     fixedRegs[1] = 0x44;
     686           0 :     fixedRegs[2] = 0x00;
     687           0 :     rxFreq += 0.04167f;
     688           0 :   } else if(fabsf(SX127x::bandwidth - 62.5f) <= 0.001f) {
     689           0 :     fixedRegs[0] = 0b00000000;
     690           0 :     fixedRegs[1] = 0x40;
     691           0 :     fixedRegs[2] = 0x00;
     692           0 :   } else if(fabsf(SX127x::bandwidth - 125.0f) <= 0.001f) {
     693           0 :     fixedRegs[0] = 0b00000000;
     694           0 :     fixedRegs[1] = 0x40;
     695           0 :     fixedRegs[2] = 0x00;
     696           0 :   } else if(fabsf(SX127x::bandwidth - 250.0f) <= 0.001f) {
     697           0 :     fixedRegs[0] = 0b00000000;
     698           0 :     fixedRegs[1] = 0x40;
     699           0 :     fixedRegs[2] = 0x00;
     700           0 :   } else if(fabsf(SX127x::bandwidth - 500.0f) <= 0.001f) {
     701           0 :     fixedRegs[0] = 0b10000000;
     702           0 :     fixedRegs[1] = mod->SPIreadRegister(0x2F);
     703           0 :     fixedRegs[2] = mod->SPIreadRegister(0x30);
     704             :   } else {
     705           0 :     return;
     706             :   }
     707             : 
     708             :   // first, go to standby
     709           0 :   standby();
     710             : 
     711             :   // shift the freqency up when receiving, or restore the original when transmitting
     712           0 :   if(rx) {
     713           0 :     SX127x::setFrequencyRaw(rxFreq);
     714             :   } else {
     715           0 :     SX127x::setFrequencyRaw(frequency);
     716             :   }
     717             : 
     718             :   // finally, apply errata fixes
     719           0 :   mod->SPIsetRegValue(0x31, fixedRegs[0], 7, 7);
     720           0 :   mod->SPIsetRegValue(0x2F, fixedRegs[1]);
     721           0 :   mod->SPIsetRegValue(0x30, fixedRegs[2]);
     722             : }
     723             : 
     724           1 : int16_t SX1278::setModem(ModemType_t modem) {
     725           1 :   switch(modem) {
     726           0 :     case(ModemType_t::RADIOLIB_MODEM_LORA): {
     727           0 :       return(this->begin());
     728             :     } break;
     729           0 :     case(ModemType_t::RADIOLIB_MODEM_FSK): {
     730           0 :       return(this->beginFSK());
     731             :     } break;
     732           1 :     default:
     733           1 :       return(RADIOLIB_ERR_WRONG_MODEM);
     734             :   }
     735             : }
     736             : 
     737             : #endif

Generated by: LCOV version 1.14