acid-drop

- Hacking the planet from a LilyGo T-Deck using custom firmware
git clone git://git.acid.vegas/acid-drop.git
Log | Files | Refs | Archive | README | LICENSE

SX1278.cpp (19762B)

      1 #include "SX1278.h"
      2 #if !defined(RADIOLIB_EXCLUDE_SX127X)
      3 
      4 SX1278::SX1278(Module* mod) : SX127x(mod) {
      5 
      6 }
      7 
      8 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) {
      9   // execute common part
     10   int16_t state = SX127x::begin(RADIOLIB_SX1278_CHIP_VERSION, syncWord, preambleLength);
     11   RADIOLIB_ASSERT(state);
     12 
     13   // configure publicly accessible settings
     14   state = setBandwidth(bw);
     15   RADIOLIB_ASSERT(state);
     16 
     17   state = setFrequency(freq);
     18   RADIOLIB_ASSERT(state);
     19 
     20   state = setSpreadingFactor(sf);
     21   RADIOLIB_ASSERT(state);
     22 
     23   state = setCodingRate(cr);
     24   RADIOLIB_ASSERT(state);
     25 
     26   state = setOutputPower(power);
     27   RADIOLIB_ASSERT(state);
     28 
     29   state = setGain(gain);
     30   RADIOLIB_ASSERT(state);
     31 
     32   return(state);
     33 }
     34 
     35 int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) {
     36   // execute common part
     37   int16_t state = SX127x::beginFSK(RADIOLIB_SX1278_CHIP_VERSION, br, freqDev, rxBw, preambleLength, enableOOK);
     38   RADIOLIB_ASSERT(state);
     39 
     40   // configure settings not accessible by API
     41   state = configFSK();
     42   RADIOLIB_ASSERT(state);
     43 
     44   // configure publicly accessible settings
     45   state = setFrequency(freq);
     46   RADIOLIB_ASSERT(state);
     47 
     48   state = setOutputPower(power);
     49   RADIOLIB_ASSERT(state);
     50 
     51   if(enableOOK) {
     52     state = setDataShapingOOK(RADIOLIB_SHAPING_NONE);
     53     RADIOLIB_ASSERT(state);
     54   } else {
     55     state = setDataShaping(RADIOLIB_SHAPING_NONE);
     56     RADIOLIB_ASSERT(state);
     57   }
     58 
     59   return(state);
     60 }
     61 
     62 void SX1278::reset() {
     63   _mod->pinMode(_mod->getRst(), OUTPUT);
     64   _mod->digitalWrite(_mod->getRst(), LOW);
     65   _mod->delay(1);
     66   _mod->digitalWrite(_mod->getRst(), HIGH);
     67   _mod->delay(5);
     68 }
     69 
     70 int16_t SX1278::setFrequency(float freq) {
     71   RADIOLIB_CHECK_RANGE(freq, 137.0, 525.0, RADIOLIB_ERR_INVALID_FREQUENCY);
     72 
     73   // set frequency and if successful, save the new setting
     74   int16_t state = SX127x::setFrequencyRaw(freq);
     75   if(state == RADIOLIB_ERR_NONE) {
     76     SX127x::_freq = freq;
     77   }
     78   return(state);
     79 }
     80 
     81 int16_t SX1278::setBandwidth(float bw) {
     82   // check active modem
     83   if(getActiveModem() != RADIOLIB_SX127X_LORA) {
     84     return(RADIOLIB_ERR_WRONG_MODEM);
     85   }
     86 
     87   uint8_t newBandwidth;
     88 
     89   // check allowed bandwidth values
     90   if(fabs(bw - 7.8) <= 0.001) {
     91     newBandwidth = RADIOLIB_SX1278_BW_7_80_KHZ;
     92   } else if(fabs(bw - 10.4) <= 0.001) {
     93     newBandwidth = RADIOLIB_SX1278_BW_10_40_KHZ;
     94   } else if(fabs(bw - 15.6) <= 0.001) {
     95     newBandwidth = RADIOLIB_SX1278_BW_15_60_KHZ;
     96   } else if(fabs(bw - 20.8) <= 0.001) {
     97     newBandwidth = RADIOLIB_SX1278_BW_20_80_KHZ;
     98   } else if(fabs(bw - 31.25) <= 0.001) {
     99     newBandwidth = RADIOLIB_SX1278_BW_31_25_KHZ;
    100   } else if(fabs(bw - 41.7) <= 0.001) {
    101     newBandwidth = RADIOLIB_SX1278_BW_41_70_KHZ;
    102   } else if(fabs(bw - 62.5) <= 0.001) {
    103     newBandwidth = RADIOLIB_SX1278_BW_62_50_KHZ;
    104   } else if(fabs(bw - 125.0) <= 0.001) {
    105     newBandwidth = RADIOLIB_SX1278_BW_125_00_KHZ;
    106   } else if(fabs(bw - 250.0) <= 0.001) {
    107     newBandwidth = RADIOLIB_SX1278_BW_250_00_KHZ;
    108   } else if(fabs(bw - 500.0) <= 0.001) {
    109     newBandwidth = RADIOLIB_SX1278_BW_500_00_KHZ;
    110   } else {
    111     return(RADIOLIB_ERR_INVALID_BANDWIDTH);
    112   }
    113 
    114   // set bandwidth and if successful, save the new setting
    115   int16_t state = SX1278::setBandwidthRaw(newBandwidth);
    116   if(state == RADIOLIB_ERR_NONE) {
    117     SX127x::_bw = bw;
    118 
    119     // calculate symbol length and set low data rate optimization, if auto-configuration is enabled
    120     if(_ldroAuto) {
    121       float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw;
    122       RADIOLIB_DEBUG_PRINT("Symbol length: ");
    123       RADIOLIB_DEBUG_PRINT(symbolLength);
    124       RADIOLIB_DEBUG_PRINTLN(" ms");
    125       if(symbolLength >= 16.0) {
    126         state = _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3);
    127       } else {
    128         state = _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3);
    129       }
    130     }
    131   }
    132   return(state);
    133 }
    134 
    135 int16_t SX1278::setSpreadingFactor(uint8_t sf) {
    136   // check active modem
    137   if(getActiveModem() != RADIOLIB_SX127X_LORA) {
    138     return(RADIOLIB_ERR_WRONG_MODEM);
    139   }
    140 
    141   uint8_t newSpreadingFactor;
    142 
    143   // check allowed spreading factor values
    144   switch(sf) {
    145     case 6:
    146       newSpreadingFactor = RADIOLIB_SX127X_SF_6;
    147       break;
    148     case 7:
    149       newSpreadingFactor = RADIOLIB_SX127X_SF_7;
    150       break;
    151     case 8:
    152       newSpreadingFactor = RADIOLIB_SX127X_SF_8;
    153       break;
    154     case 9:
    155       newSpreadingFactor = RADIOLIB_SX127X_SF_9;
    156       break;
    157     case 10:
    158       newSpreadingFactor = RADIOLIB_SX127X_SF_10;
    159       break;
    160     case 11:
    161       newSpreadingFactor = RADIOLIB_SX127X_SF_11;
    162       break;
    163     case 12:
    164       newSpreadingFactor = RADIOLIB_SX127X_SF_12;
    165       break;
    166     default:
    167       return(RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
    168   }
    169 
    170   // set spreading factor and if successful, save the new setting
    171   int16_t state = SX1278::setSpreadingFactorRaw(newSpreadingFactor);
    172   if(state == RADIOLIB_ERR_NONE) {
    173     SX127x::_sf = sf;
    174 
    175     // calculate symbol length and set low data rate optimization, if auto-configuration is enabled
    176     if(_ldroAuto) {
    177       float symbolLength = (float)(uint32_t(1) << SX127x::_sf) / (float)SX127x::_bw;
    178       RADIOLIB_DEBUG_PRINT("Symbol length: ");
    179       RADIOLIB_DEBUG_PRINT(symbolLength);
    180       RADIOLIB_DEBUG_PRINTLN(" ms");
    181       if(symbolLength >= 16.0) {
    182         state = _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3);
    183       } else {
    184         state = _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3);
    185       }
    186     }
    187   }
    188   return(state);
    189 }
    190 
    191 int16_t SX1278::setCodingRate(uint8_t cr) {
    192   // check active modem
    193   if(getActiveModem() != RADIOLIB_SX127X_LORA) {
    194     return(RADIOLIB_ERR_WRONG_MODEM);
    195   }
    196 
    197   uint8_t newCodingRate;
    198 
    199   // check allowed coding rate values
    200   switch(cr) {
    201     case 5:
    202       newCodingRate = RADIOLIB_SX1278_CR_4_5;
    203       break;
    204     case 6:
    205       newCodingRate = RADIOLIB_SX1278_CR_4_6;
    206       break;
    207     case 7:
    208       newCodingRate = RADIOLIB_SX1278_CR_4_7;
    209       break;
    210     case 8:
    211       newCodingRate = RADIOLIB_SX1278_CR_4_8;
    212       break;
    213     default:
    214       return(RADIOLIB_ERR_INVALID_CODING_RATE);
    215   }
    216 
    217   // set coding rate and if successful, save the new setting
    218   int16_t state = SX1278::setCodingRateRaw(newCodingRate);
    219   if(state == RADIOLIB_ERR_NONE) {
    220     SX127x::_cr = cr;
    221   }
    222   return(state);
    223 }
    224 
    225 int16_t SX1278::setOutputPower(int8_t power, bool useRfo) {
    226   // check allowed power range
    227   if(useRfo) {
    228     // RFO output
    229     RADIOLIB_CHECK_RANGE(power, -3, 15, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
    230   } else {
    231     // PA_BOOST output, check high-power operation
    232     if(power != 20) {
    233       RADIOLIB_CHECK_RANGE(power, 2, 17, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
    234     }
    235   }
    236 
    237   // set mode to standby
    238   int16_t state = SX127x::standby();
    239 
    240   if(useRfo) {
    241     uint8_t paCfg = 0;
    242     if(power < 0) {
    243       // low power mode RFO output
    244       paCfg = RADIOLIB_SX1278_LOW_POWER | (power + 3);
    245     } else {
    246       // high power mode RFO output
    247       paCfg = RADIOLIB_SX1278_MAX_POWER | power;
    248     }
    249 
    250     state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_RFO, 7, 7);
    251     state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, paCfg, 6, 0);
    252     state |= _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0);
    253 
    254   } else {
    255     if(power != 20) {
    256       // power is 2 - 17 dBm, enable PA1 + PA2 on PA_BOOST
    257       state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7);
    258       state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX1278_MAX_POWER | (power - 2), 6, 0);
    259       state |= _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0);
    260 
    261     } else {
    262       // power is 20 dBm, enable PA1 + PA2 on PA_BOOST and enable high power control
    263       state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7);
    264       state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX1278_MAX_POWER | 0x0F, 6, 0);
    265       state |= _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_ON, 2, 0);
    266 
    267     }
    268   }
    269 
    270   return(state);
    271 }
    272 
    273 int16_t SX1278::setGain(uint8_t gain) {
    274   // check allowed range
    275   if(gain > 6) {
    276     return(RADIOLIB_ERR_INVALID_GAIN);
    277   }
    278 
    279   // set mode to standby
    280   int16_t state = SX127x::standby();
    281 
    282   // get modem
    283   int16_t modem = getActiveModem();
    284   if(modem == RADIOLIB_SX127X_LORA){
    285     // set gain
    286     if(gain == 0) {
    287       // gain set to 0, enable AGC loop
    288       state |= _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_AGC_AUTO_ON, 2, 2);
    289     } else {
    290       state |= _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_AGC_AUTO_OFF, 2, 2);
    291       state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON);
    292     }
    293 
    294   } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
    295     // set gain
    296     if(gain == 0) {
    297       // gain set to 0, enable AGC loop
    298       state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX127X_AGC_AUTO_ON, 3, 3);
    299     } else {
    300       state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX1278_AGC_AUTO_OFF, 3, 3);
    301       state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON);
    302     }
    303 
    304   }
    305 
    306   return(state);
    307 }
    308 
    309 int16_t SX1278::setDataShaping(uint8_t sh) {
    310   // check active modem
    311   if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
    312     return(RADIOLIB_ERR_WRONG_MODEM);
    313   }
    314 
    315   // check modulation
    316   if(SX127x::_ook) {
    317     // we're in OOK mode, the only thing we can do is disable
    318     if(sh == RADIOLIB_SHAPING_NONE) {
    319       return(setDataShapingOOK(0));
    320     }
    321 
    322     return(RADIOLIB_ERR_INVALID_MODULATION);
    323   }
    324 
    325   // set mode to standby
    326   int16_t state = SX127x::standby();
    327   RADIOLIB_ASSERT(state);
    328 
    329   // set data shaping
    330   switch(sh) {
    331     case RADIOLIB_SHAPING_NONE:
    332       return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_NO_SHAPING, 6, 5));
    333     case RADIOLIB_SHAPING_0_3:
    334       return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_0_3, 6, 5));
    335     case RADIOLIB_SHAPING_0_5:
    336       return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_0_5, 6, 5));
    337     case RADIOLIB_SHAPING_1_0:
    338       return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_1_0, 6, 5));
    339     default:
    340       return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
    341   }
    342 }
    343 
    344 int16_t SX1278::setDataShapingOOK(uint8_t sh) {
    345   // check active modem
    346   if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
    347     return(RADIOLIB_ERR_WRONG_MODEM);
    348   }
    349 
    350   // check modulation
    351   if(!SX127x::_ook) {
    352     return(RADIOLIB_ERR_INVALID_MODULATION);
    353   }
    354 
    355   // set mode to standby
    356   int16_t state = SX127x::standby();
    357 
    358   // set data shaping
    359   switch(sh) {
    360     case 0:
    361       state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_NO_SHAPING, 6, 5);
    362       break;
    363     case 1:
    364       state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_OOK_FILTER_BR, 6, 5);
    365       break;
    366     case 2:
    367       state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_OOK_FILTER_2BR, 6, 5);
    368       break;
    369     default:
    370       return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
    371   }
    372 
    373   return(state);
    374 }
    375 
    376 float SX1278::getRSSI(bool skipReceive) {
    377   if(getActiveModem() == RADIOLIB_SX127X_LORA) {
    378     // for LoRa, get RSSI of the last packet
    379     float lastPacketRSSI;
    380 
    381     // RSSI calculation uses different constant for low-frequency and high-frequency ports
    382     if(_freq < 868.0) {
    383       lastPacketRSSI = -164 + _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PKT_RSSI_VALUE);
    384     } else {
    385       lastPacketRSSI = -157 + _mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PKT_RSSI_VALUE);
    386     }
    387 
    388     // spread-spectrum modulation signal can be received below noise floor
    389     // check last packet SNR and if it's less than 0, add it to reported RSSI to get the correct value
    390     float lastPacketSNR = SX127x::getSNR();
    391     if(lastPacketSNR < 0.0) {
    392       lastPacketRSSI += lastPacketSNR;
    393     }
    394 
    395     return(lastPacketRSSI);
    396 
    397   } else {
    398     // enable listen mode
    399     if(!skipReceive) {
    400       startReceive();
    401     }
    402 
    403     // read the value for FSK
    404     float rssi = (float)_mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE_FSK) / -2.0;
    405 
    406     // set mode back to standby
    407     if(!skipReceive) {
    408       standby();
    409     }
    410 
    411     // return the value
    412     return(rssi);
    413   }
    414 }
    415 
    416 int16_t SX1278::setCRC(bool enable, bool mode) {
    417   if(getActiveModem() == RADIOLIB_SX127X_LORA) {
    418     // set LoRa CRC
    419     SX127x::_crcEnabled = enable;
    420     if(enable) {
    421       return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1278_RX_CRC_MODE_ON, 2, 2));
    422     } else {
    423       return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1278_RX_CRC_MODE_OFF, 2, 2));
    424     }
    425   } else {
    426     // set FSK CRC
    427     int16_t state = RADIOLIB_ERR_NONE;
    428     if(enable) {
    429       state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_ON, 4, 4);
    430     } else {
    431       state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_OFF, 4, 4);
    432     }
    433     RADIOLIB_ASSERT(state);
    434 
    435     // set FSK CRC mode
    436     if(mode) {
    437       return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_IBM, 0, 0));
    438     } else {
    439       return(_mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT, 0, 0));
    440     }
    441   }
    442 }
    443 
    444 int16_t SX1278::forceLDRO(bool enable) {
    445   if(getActiveModem() != RADIOLIB_SX127X_LORA) {
    446     return(RADIOLIB_ERR_WRONG_MODEM);
    447   }
    448 
    449   _ldroAuto = false;
    450   if(enable) {
    451     return(_mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3));
    452   } else {
    453     return(_mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3));
    454   }
    455 }
    456 
    457 int16_t SX1278::autoLDRO() {
    458   if(getActiveModem() != RADIOLIB_SX127X_LORA) {
    459     return(RADIOLIB_ERR_WRONG_MODEM);
    460   }
    461 
    462   _ldroAuto = true;
    463   return(RADIOLIB_ERR_NONE);
    464 }
    465 
    466 int16_t SX1278::implicitHeader(size_t len) {
    467   return(setHeaderType(RADIOLIB_SX1278_HEADER_IMPL_MODE, len));
    468 }
    469 
    470 int16_t SX1278::explicitHeader() {
    471   return(setHeaderType(RADIOLIB_SX1278_HEADER_EXPL_MODE));
    472 }
    473 
    474 int16_t SX1278::setBandwidthRaw(uint8_t newBandwidth) {
    475   // set mode to standby
    476   int16_t state = SX127x::standby();
    477 
    478   // write register
    479   state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newBandwidth, 7, 4);
    480   return(state);
    481 }
    482 
    483 int16_t SX1278::setSpreadingFactorRaw(uint8_t newSpreadingFactor) {
    484   // set mode to standby
    485   int16_t state = SX127x::standby();
    486 
    487   // write registers
    488   if(newSpreadingFactor == RADIOLIB_SX127X_SF_6) {
    489     state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1278_HEADER_IMPL_MODE, 0, 0);
    490     state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX127X_SF_6 | RADIOLIB_SX127X_TX_MODE_SINGLE | (SX127x::_crcEnabled ? RADIOLIB_SX1278_RX_CRC_MODE_ON : RADIOLIB_SX1278_RX_CRC_MODE_OFF), 7, 2);
    491     state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_6, 2, 0);
    492     state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_6);
    493   } else {
    494     state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1278_HEADER_EXPL_MODE, 0, 0);
    495     state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | RADIOLIB_SX127X_TX_MODE_SINGLE | (SX127x::_crcEnabled ? RADIOLIB_SX1278_RX_CRC_MODE_ON : RADIOLIB_SX1278_RX_CRC_MODE_OFF), 7, 2);
    496     state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0);
    497     state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_7_12);
    498   }
    499   return(state);
    500 }
    501 
    502 int16_t SX1278::setCodingRateRaw(uint8_t newCodingRate) {
    503   // set mode to standby
    504   int16_t state = SX127x::standby();
    505 
    506   // write register
    507   state |= _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newCodingRate, 3, 1);
    508   return(state);
    509 }
    510 
    511 int16_t SX1278::setHeaderType(uint8_t headerType, size_t len) {
    512   // check active modem
    513   if(getActiveModem() != RADIOLIB_SX127X_LORA) {
    514     return(RADIOLIB_ERR_WRONG_MODEM);
    515   }
    516 
    517   // set requested packet mode
    518   int16_t state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, headerType, 0, 0);
    519   RADIOLIB_ASSERT(state);
    520 
    521   // set length to register
    522   state = _mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len);
    523   RADIOLIB_ASSERT(state);
    524 
    525   // update cached value
    526   _packetLength = len;
    527 
    528   return(state);
    529 }
    530 
    531 int16_t SX1278::configFSK() {
    532   // configure common registers
    533   int16_t state = SX127x::configFSK();
    534   RADIOLIB_ASSERT(state);
    535 
    536   // set fast PLL hop
    537   state = _mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PLL_HOP, RADIOLIB_SX127X_FAST_HOP_ON, 7, 7);
    538   return(state);
    539 }
    540 
    541 void SX1278::errataFix(bool rx) {
    542   // only apply in LoRa mode
    543   if(getActiveModem() != RADIOLIB_SX127X_LORA) {
    544     return;
    545   }
    546 
    547   // sensitivity optimization for 500kHz bandwidth
    548   // see SX1276/77/78 Errata, section 2.1 for details
    549   if(fabs(_bw - 500.0) <= 0.001) {
    550     if((_freq >= 862.0) && (_freq <= 1020.0)) {
    551       _mod->SPIwriteRegister(0x36, 0x02);
    552       _mod->SPIwriteRegister(0x3a, 0x64);
    553     } else if((_freq >= 410.0) && (_freq <= 525.0)) {
    554       _mod->SPIwriteRegister(0x36, 0x02);
    555       _mod->SPIwriteRegister(0x3a, 0x7F);
    556     }
    557   }
    558 
    559   // mitigation of receiver spurious response
    560   // see SX1276/77/78 Errata, section 2.3 for details
    561 
    562   // figure out what we need to set
    563   uint8_t fixedRegs[3] = { 0x00, 0x00, 0x00 };
    564   float rxFreq = _freq;
    565   if(fabs(_bw - 7.8) <= 0.001) {
    566     fixedRegs[0] = 0b0000000;
    567     fixedRegs[1] = 0x48;
    568     fixedRegs[2] = 0x00;
    569     rxFreq += 0.00781;
    570   } else if(fabs(_bw - 10.4) <= 0.001) {
    571     fixedRegs[0] = 0b0000000;
    572     fixedRegs[1] = 0x44;
    573     fixedRegs[2] = 0x00;
    574     rxFreq += 0.01042;
    575   } else if(fabs(_bw - 15.6) <= 0.001) {
    576     fixedRegs[0] = 0b0000000;
    577     fixedRegs[1] = 0x44;
    578     fixedRegs[2] = 0x00;
    579     rxFreq += 0.01562;
    580   } else if(fabs(_bw - 20.8) <= 0.001) {
    581     fixedRegs[0] = 0b0000000;
    582     fixedRegs[1] = 0x44;
    583     fixedRegs[2] = 0x00;
    584     rxFreq += 0.02083;
    585   } else if(fabs(_bw - 31.25) <= 0.001) {
    586     fixedRegs[0] = 0b0000000;
    587     fixedRegs[1] = 0x44;
    588     fixedRegs[2] = 0x00;
    589     rxFreq += 0.03125;
    590   } else if(fabs(_bw - 41.7) <= 0.001) {
    591     fixedRegs[0] = 0b0000000;
    592     fixedRegs[1] = 0x44;
    593     fixedRegs[2] = 0x00;
    594     rxFreq += 0.04167;
    595   } else if(fabs(_bw - 62.5) <= 0.001) {
    596     fixedRegs[0] = 0b0000000;
    597     fixedRegs[1] = 0x40;
    598     fixedRegs[2] = 0x00;
    599   } else if(fabs(_bw - 125.0) <= 0.001) {
    600     fixedRegs[0] = 0b0000000;
    601     fixedRegs[1] = 0x40;
    602     fixedRegs[2] = 0x00;
    603   } else if(fabs(_bw - 250.0) <= 0.001) {
    604     fixedRegs[0] = 0b0000000;
    605     fixedRegs[1] = 0x40;
    606     fixedRegs[2] = 0x00;
    607   } else if(fabs(_bw - 500.0) <= 0.001) {
    608     fixedRegs[0] = 0b1000000;
    609     fixedRegs[1] = _mod->SPIreadRegister(0x2F);
    610     fixedRegs[2] = _mod->SPIreadRegister(0x30);
    611   } else {
    612     return;
    613   }
    614 
    615   // first, go to standby
    616   standby();
    617 
    618   // shift the freqency up when receiving, or restore the original when transmitting
    619   if(rx) {
    620     SX127x::setFrequencyRaw(rxFreq);
    621   } else {
    622     SX127x::setFrequencyRaw(_freq);
    623   }
    624 
    625   // finally, apply errata fixes
    626   _mod->SPIsetRegValue(0x31, fixedRegs[0], 7, 7);
    627   _mod->SPIsetRegValue(0x2F, fixedRegs[1]);
    628   _mod->SPIsetRegValue(0x30, fixedRegs[2]);
    629 }
    630 
    631 #endif