LCOV - code coverage report
Current view: top level - src/modules/SX127x - SX1278.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 71 460 15.4 %
Date: 2026-06-30 18:21:43 Functions: 14 33 42.4 %

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

Generated by: LCOV version 1.14