LCOV - code coverage report
Current view: top level - src/modules/SX127x - SX127x.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 235 1024 22.9 %
Date: 2026-02-22 10:42:45 Functions: 43 112 38.4 %

          Line data    Source code
       1             : #include "SX127x.h"
       2             : #include <math.h>
       3             : #if !RADIOLIB_EXCLUDE_SX127X
       4             : 
       5          18 : SX127x::SX127x(Module* mod) : PhysicalLayer() {
       6          18 :   this->freqStep = RADIOLIB_SX127X_FREQUENCY_STEP_SIZE;
       7          18 :   this->maxPacketLength = RADIOLIB_SX127X_MAX_PACKET_LENGTH;
       8          18 :   this->mod = mod;
       9          18 : }
      10             : 
      11           0 : int16_t SX127x::begin(const uint8_t* chipVersions, uint8_t numVersions, uint8_t syncWord, uint16_t preambleLength) {
      12             :   // set module properties
      13           0 :   this->mod->init();
      14           0 :   this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
      15           0 :   this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput);
      16             : 
      17             :   // set IRQ mapping - it is different for LoRa and FSK mode
      18           0 :   this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_TX_DONE;
      19           0 :   this->irqMap[RADIOLIB_IRQ_RX_DONE] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_DONE;
      20           0 :   this->irqMap[RADIOLIB_IRQ_PREAMBLE_DETECTED] = RADIOLIB_IRQ_NOT_SUPPORTED;
      21           0 :   this->irqMap[RADIOLIB_IRQ_SYNC_WORD_VALID] = RADIOLIB_IRQ_NOT_SUPPORTED;
      22           0 :   this->irqMap[RADIOLIB_IRQ_HEADER_VALID] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_VALID_HEADER;
      23           0 :   this->irqMap[RADIOLIB_IRQ_HEADER_ERR] = RADIOLIB_IRQ_NOT_SUPPORTED;
      24           0 :   this->irqMap[RADIOLIB_IRQ_CRC_ERR] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR;
      25           0 :   this->irqMap[RADIOLIB_IRQ_CAD_DONE] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DONE;
      26           0 :   this->irqMap[RADIOLIB_IRQ_CAD_DETECTED] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED;
      27           0 :   this->irqMap[RADIOLIB_IRQ_TIMEOUT] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT;
      28             : 
      29             :   // try to find the SX127x chip
      30           0 :   if(!SX127x::findChip(chipVersions, numVersions)) {
      31             :     RADIOLIB_DEBUG_BASIC_PRINTLN("No SX127x found!");
      32           0 :     this->mod->term();
      33           0 :     return(RADIOLIB_ERR_CHIP_NOT_FOUND);
      34             :   }
      35             :   RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX127x");
      36             : 
      37             :   // set mode to standby
      38           0 :   int16_t state = standby();
      39           0 :   RADIOLIB_ASSERT(state);
      40             : 
      41             :   // configure settings not accessible by API
      42           0 :   state = config();
      43           0 :   RADIOLIB_ASSERT(state);
      44             : 
      45             :   // check active modem
      46           0 :   if(getActiveModem() != RADIOLIB_SX127X_LORA) {
      47             :     // set LoRa mode
      48           0 :     state = setActiveModem(RADIOLIB_SX127X_LORA);
      49           0 :     RADIOLIB_ASSERT(state);
      50             :   }
      51             : 
      52             :   // set LoRa sync word
      53           0 :   state = SX127x::setSyncWord(syncWord);
      54           0 :   RADIOLIB_ASSERT(state);
      55             : 
      56             :   // set over current protection
      57           0 :   state = SX127x::setCurrentLimit(60);
      58           0 :   RADIOLIB_ASSERT(state);
      59             : 
      60             :   // set preamble length
      61           0 :   state = SX127x::setPreambleLength(preambleLength);
      62           0 :   RADIOLIB_ASSERT(state);
      63             : 
      64             :   // disable IQ inversion
      65           0 :   state = SX127x::invertIQ(false);
      66           0 :   RADIOLIB_ASSERT(state);
      67             : 
      68           0 :   return(state);
      69             : }
      70             : 
      71           0 : int16_t SX127x::beginFSK(const uint8_t* chipVersions, uint8_t numVersions, float freqDev, float rxBw, uint16_t preambleLength, bool enableOOK) {
      72             :   // set module properties
      73           0 :   this->mod->init();
      74           0 :   this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
      75           0 :   this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput);
      76             : 
      77             :   // set IRQ mapping - it is different for LoRa and FSK mode
      78           0 :   this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_SX127X_FLAG_PACKET_SENT << 8;
      79           0 :   this->irqMap[RADIOLIB_IRQ_RX_DONE] = RADIOLIB_SX127X_FLAG_PAYLOAD_READY << 8;
      80           0 :   this->irqMap[RADIOLIB_IRQ_PREAMBLE_DETECTED] = RADIOLIB_SX127X_FLAG_PREAMBLE_DETECT << 0;
      81           0 :   this->irqMap[RADIOLIB_IRQ_SYNC_WORD_VALID] = RADIOLIB_SX127X_FLAG_SYNC_ADDRESS_MATCH << 0;
      82           0 :   this->irqMap[RADIOLIB_IRQ_HEADER_VALID] = RADIOLIB_IRQ_NOT_SUPPORTED;
      83           0 :   this->irqMap[RADIOLIB_IRQ_HEADER_ERR] = RADIOLIB_IRQ_NOT_SUPPORTED;
      84           0 :   this->irqMap[RADIOLIB_IRQ_CRC_ERR] = RADIOLIB_IRQ_NOT_SUPPORTED;
      85           0 :   this->irqMap[RADIOLIB_IRQ_CAD_DONE] = RADIOLIB_IRQ_NOT_SUPPORTED;
      86           0 :   this->irqMap[RADIOLIB_IRQ_CAD_DETECTED] = RADIOLIB_IRQ_NOT_SUPPORTED;
      87           0 :   this->irqMap[RADIOLIB_IRQ_TIMEOUT] = RADIOLIB_SX127X_FLAG_TIMEOUT << 0;
      88             : 
      89             :   // try to find the SX127x chip
      90           0 :   if(!SX127x::findChip(chipVersions, numVersions)) {
      91             :     RADIOLIB_DEBUG_BASIC_PRINTLN("No SX127x found!");
      92           0 :     this->mod->term();
      93           0 :     return(RADIOLIB_ERR_CHIP_NOT_FOUND);
      94             :   }
      95             :   RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX127x");
      96             : 
      97             :   // set mode to standby
      98           0 :   int16_t state = standby();
      99           0 :   RADIOLIB_ASSERT(state);
     100             : 
     101             :   // check currently active modem
     102           0 :   if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
     103             :     // set FSK mode
     104           0 :     state = setActiveModem(RADIOLIB_SX127X_FSK_OOK);
     105           0 :     RADIOLIB_ASSERT(state);
     106             :   }
     107             : 
     108             :   // enable/disable OOK
     109           0 :   state = setOOK(enableOOK);
     110           0 :   RADIOLIB_ASSERT(state);
     111             : 
     112             :   // set frequency deviation
     113           0 :   state = SX127x::setFrequencyDeviation(freqDev);
     114           0 :   RADIOLIB_ASSERT(state);
     115             : 
     116             :   // set AFC bandwidth
     117           0 :   state = SX127x::setAFCBandwidth(rxBw);
     118           0 :   RADIOLIB_ASSERT(state);
     119             : 
     120             :   // set AFC&AGC trigger to RSSI (both in OOK and FSK)
     121           0 :   state = SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_RSSI_INTERRUPT);
     122           0 :   RADIOLIB_ASSERT(state);
     123             : 
     124             :   // enable AFC
     125           0 :   state = SX127x::setAFC(false);
     126           0 :   RADIOLIB_ASSERT(state);
     127             : 
     128             :   // set receiver bandwidth
     129           0 :   state = SX127x::setRxBandwidth(rxBw);
     130           0 :   RADIOLIB_ASSERT(state);
     131             : 
     132             :   // set over current protection
     133           0 :   state = SX127x::setCurrentLimit(60);
     134           0 :   RADIOLIB_ASSERT(state);
     135             : 
     136             :   // set preamble length
     137           0 :   state = SX127x::setPreambleLength(preambleLength);
     138           0 :   RADIOLIB_ASSERT(state);
     139             : 
     140             :   // set preamble polarity
     141           0 :   state = invertPreamble(false);
     142           0 :   RADIOLIB_ASSERT(state);
     143             : 
     144             :   // set default sync word
     145           0 :   uint8_t syncWord[] = {0x12, 0xAD};
     146           0 :   state = setSyncWord(syncWord, 2);
     147           0 :   RADIOLIB_ASSERT(state);
     148             : 
     149             :   // disable address filtering
     150           0 :   state = disableAddressFiltering();
     151           0 :   RADIOLIB_ASSERT(state);
     152             : 
     153             :   // set default RSSI measurement config
     154           0 :   state = setRSSIConfig(2);
     155           0 :   RADIOLIB_ASSERT(state);
     156             : 
     157             :   // set default encoding
     158           0 :   state = setEncoding(RADIOLIB_ENCODING_NRZ);
     159           0 :   RADIOLIB_ASSERT(state);
     160             : 
     161             :   // set default packet length mode
     162           0 :   state = variablePacketLengthMode();
     163             : 
     164           0 :   return(state);
     165             : }
     166             : 
     167           6 : int16_t SX127x::transmit(const uint8_t* data, size_t len, uint8_t addr) {
     168             :   // set mode to standby
     169           6 :   int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
     170           6 :   RADIOLIB_ASSERT(state);
     171             : 
     172           0 :   int16_t modem = getActiveModem();
     173           0 :   RadioLibTime_t start = 0;
     174           0 :   RadioLibTime_t timeout = 0;
     175           0 :   RadioLibTime_t toa = getTimeOnAir(len);
     176           0 :   if(modem == RADIOLIB_SX127X_LORA) {
     177             :     // calculate timeout in ms (150 % of expected time-on-air)
     178           0 :     timeout = (toa * 1.5) / 1000;
     179             : 
     180           0 :   } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
     181             :     // calculate timeout in ms (5ms + 500 % of expected time-on-air)
     182           0 :     timeout = 5 + (toa * 5) / 1000;
     183             : 
     184             :   } else {
     185           0 :     return(RADIOLIB_ERR_UNKNOWN);
     186             :   
     187             :   }
     188             : 
     189             :   // start transmission
     190             :   RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout);
     191           0 :   state = startTransmit(data, len, addr);
     192           0 :   RADIOLIB_ASSERT(state);
     193             : 
     194             :   // wait for packet transmission or timeout
     195           0 :   start = this->mod->hal->millis();
     196           0 :   while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
     197           0 :     this->mod->hal->yield();
     198           0 :     if(this->mod->hal->millis() - start > timeout) {
     199           0 :       finishTransmit();
     200           0 :       return(RADIOLIB_ERR_TX_TIMEOUT);
     201             :     }
     202             :   }
     203             : 
     204           0 :   return(finishTransmit());
     205             : }
     206             : 
     207           6 : int16_t SX127x::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) {
     208             :   // set mode to standby
     209           6 :   int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
     210           6 :   RADIOLIB_ASSERT(state);
     211             : 
     212             :   // calculate timeout based on the configured modem
     213           0 :   RadioLibTime_t timeoutInternal = timeout;
     214           0 :   uint32_t timeoutValue = 0;
     215           0 :   if(!timeoutInternal) {
     216             :     // calculate timeout (500 % of expected time-one-air)
     217           0 :     size_t maxLen = len;
     218           0 :     if(len == 0) { maxLen = RADIOLIB_SX127X_MAX_PACKET_LENGTH; }
     219           0 :     timeoutInternal = (getTimeOnAir(maxLen) * 5) / 1000;
     220             : 
     221             :     // convert to symbols
     222           0 :     float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth;
     223           0 :     timeoutValue = (float)timeoutInternal / symbolLength;
     224             :   }
     225             : 
     226             :   RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeoutInternal);
     227             : 
     228             :   // start reception
     229           0 :   state = startReceive(timeoutValue, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, len);
     230           0 :   RADIOLIB_ASSERT(state);
     231             : 
     232             :   // wait for packet reception or timeout
     233           0 :   bool softTimeout = false;
     234           0 :   RadioLibTime_t start = this->mod->hal->millis();
     235           0 :   while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
     236           0 :     this->mod->hal->yield();
     237             :     // check the blocking timeout
     238           0 :     if(this->mod->hal->millis() - start > timeoutInternal) {
     239           0 :       softTimeout = true;
     240           0 :       break;
     241             :     }
     242             :   }
     243             : 
     244             :   // check whether this was a timeout or not
     245           0 :   if(softTimeout || (getIRQFlags() & this->irqMap[RADIOLIB_IRQ_TIMEOUT])) {
     246           0 :     (void)finishReceive();
     247           0 :     return(RADIOLIB_ERR_RX_TIMEOUT);
     248             :   }
     249             : 
     250             :   // read the received data
     251           0 :   return(readData(data, len));
     252             : }
     253             : 
     254           0 : void SX127x::reset() {
     255             :   // should be implemented in derived class
     256           0 : }
     257             : 
     258           6 : int16_t SX127x::scanChannel() {
     259             :   // the configuration is not actually used
     260           6 :   const ChannelScanConfig_t cfg = { .rssi = { .limit = 0 } };
     261          12 :   return(scanChannel(cfg));
     262             : }
     263             : 
     264          12 : int16_t SX127x::scanChannel(const ChannelScanConfig_t &config) {
     265             :   (void)config;
     266             : 
     267             :   // start CAD
     268          12 :   int16_t state = startChannelScan();
     269          12 :   RADIOLIB_ASSERT(state);
     270             : 
     271             :   // wait for channel activity detected or timeout
     272           0 :   while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
     273           0 :     this->mod->hal->yield();
     274           0 :     if(this->mod->hal->digitalRead(this->mod->getGpio())) {
     275           0 :       return(RADIOLIB_PREAMBLE_DETECTED);
     276             :     }
     277             :   }
     278             : 
     279           0 :   return(RADIOLIB_CHANNEL_FREE);
     280             : }
     281             : 
     282           6 : int16_t SX127x::sleep() {
     283             :   // set RF switch (if present)
     284           6 :   this->mod->setRfSwitchState(Module::MODE_IDLE);
     285             : 
     286             :   // set mode to sleep
     287           6 :   int16_t state = setMode(RADIOLIB_SX127X_SLEEP);
     288             :   
     289             :   // wait for SX127x to safely enter sleep mode
     290           6 :   this->mod->hal->delay(1);
     291             : 
     292           6 :   return(state);
     293             : }
     294             : 
     295          30 : int16_t SX127x::standby() {
     296             :   // set RF switch (if present)
     297          30 :   this->mod->setRfSwitchState(Module::MODE_IDLE);
     298             : 
     299             :   // set mode to standby
     300          30 :   return(setMode(RADIOLIB_SX127X_STANDBY));
     301             : }
     302             : 
     303           6 : int16_t SX127x::standby(uint8_t mode) {
     304             :   (void)mode;
     305           6 :   return(standby());
     306             : }
     307             : 
     308           6 : int16_t SX127x::transmitDirect(uint32_t frf) {
     309             :   // check modem
     310           6 :   if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
     311           6 :     return(RADIOLIB_ERR_WRONG_MODEM);
     312             :   }
     313             : 
     314             :   // set RF switch (if present)
     315           0 :   this->mod->setRfSwitchState(Module::MODE_TX);
     316             : 
     317             :   // user requested to start transmitting immediately (required for RTTY)
     318           0 :   if(frf != 0) {
     319           0 :     this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FRF_MSB, (frf & 0xFF0000) >> 16);
     320           0 :     this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FRF_MID, (frf & 0x00FF00) >> 8);
     321           0 :     this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FRF_LSB, frf & 0x0000FF);
     322             : 
     323           0 :     return(setMode(RADIOLIB_SX127X_TX));
     324             :   }
     325             : 
     326             :   // activate direct mode
     327           0 :   int16_t state = directMode();
     328           0 :   RADIOLIB_ASSERT(state);
     329             : 
     330             :   // apply fixes to errata
     331             :   RADIOLIB_ERRATA_SX127X(false);
     332             : 
     333             :   // start transmitting
     334           0 :   return(setMode(RADIOLIB_SX127X_TX));
     335             : }
     336             : 
     337           6 : int16_t SX127x::receiveDirect() {
     338             :   // check modem
     339           6 :   if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
     340           6 :     return(RADIOLIB_ERR_WRONG_MODEM);
     341             :   }
     342             : 
     343             :   // set RF switch (if present)
     344           0 :   this->mod->setRfSwitchState(Module::MODE_RX);
     345             : 
     346             :   // activate direct mode
     347           0 :   int16_t state = directMode();
     348           0 :   RADIOLIB_ASSERT(state);
     349             : 
     350             :   // apply fixes to errata
     351             :   RADIOLIB_ERRATA_SX127X(true);
     352             : 
     353             :   // start receiving
     354           0 :   return(setMode(RADIOLIB_SX127X_RX));
     355             : }
     356             : 
     357           0 : int16_t SX127x::directMode() {
     358             :   // set mode to standby
     359           0 :   int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
     360           0 :   RADIOLIB_ASSERT(state);
     361             : 
     362             :   // set DIO mapping
     363           0 :   state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_CONT_DCLK | RADIOLIB_SX127X_DIO2_CONT_DATA, 5, 2);
     364           0 :   RADIOLIB_ASSERT(state);
     365             : 
     366             :   // enable receiver startup without preamble or RSSI
     367           0 :   state = SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_NONE);
     368           0 :   RADIOLIB_ASSERT(state);
     369             : 
     370             :   // set continuous mode
     371           0 :   return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_2, RADIOLIB_SX127X_DATA_MODE_CONTINUOUS, 6, 6));
     372             : }
     373             : 
     374           0 : int16_t SX127x::packetMode() {
     375             :   // check modem
     376           0 :   if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
     377           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     378             :   }
     379             : 
     380           0 :   return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_2, RADIOLIB_SX127X_DATA_MODE_PACKET, 6, 6));
     381             : }
     382             : 
     383           6 : int16_t SX127x::startReceive() {
     384           6 :   return(this->startReceive(0, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0));
     385             : }
     386             : 
     387           0 : void SX127x::setDio0Action(void (*func)(void), uint32_t dir) {
     388           0 :   this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, dir);
     389           0 : }
     390             : 
     391           0 : void SX127x::clearDio0Action() {
     392           0 :   this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()));
     393           0 : }
     394             : 
     395           0 : void SX127x::setDio1Action(void (*func)(void), uint32_t dir) {
     396           0 :   if(this->mod->getGpio() == RADIOLIB_NC) {
     397           0 :     return;
     398             :   }
     399           0 :   this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getGpio()), func, dir);
     400             : }
     401             : 
     402           0 : void SX127x::clearDio1Action() {
     403           0 :   if(this->mod->getGpio() == RADIOLIB_NC) {
     404           0 :     return;
     405             :   }
     406           0 :   this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getGpio()));
     407             : }
     408             : 
     409           0 : void SX127x::setPacketReceivedAction(void (*func)(void)) {
     410           0 :   this->setDio0Action(func, this->mod->hal->GpioInterruptRising);
     411           0 : }
     412             : 
     413           0 : void SX127x::clearPacketReceivedAction() {
     414           0 :   this->clearDio0Action();
     415           0 : }
     416             : 
     417           0 : void SX127x::setPacketSentAction(void (*func)(void)) {
     418           0 :   this->setDio0Action(func, this->mod->hal->GpioInterruptRising);
     419           0 : }
     420             : 
     421           0 : void SX127x::clearPacketSentAction() {
     422           0 :   this->clearDio0Action();
     423           0 : }
     424             : 
     425           0 : void SX127x::setChannelScanAction(void (*func)(void)) {
     426           0 :   this->setDio0Action(func, this->mod->hal->GpioInterruptRising);
     427           0 : }
     428             : 
     429           0 : void SX127x::clearChannelScanAction() {
     430           0 :   this->clearDio0Action();
     431           0 : }
     432             : 
     433           0 : void SX127x::setFifoEmptyAction(void (*func)(void)) {
     434             :   // set DIO1 to the FIFO empty event (the register setting is done in startTransmit)
     435           0 :   setDio1Action(func, this->mod->hal->GpioInterruptRising);
     436           0 : }
     437             : 
     438           0 : void SX127x::clearFifoEmptyAction() {
     439           0 :   clearDio1Action();
     440           0 : }
     441             : 
     442           0 : void SX127x::setFifoThreshold(uint8_t threshold) {
     443           0 :   this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, threshold, 5, 0);
     444           0 : }
     445             : 
     446           0 : void SX127x::setFifoFullAction(void (*func)(void)) {
     447             :   // set the interrupt
     448           0 :   this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_FIFO_THRESH, 5, 0);
     449           0 :   this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_PACK_FIFO_LEVEL, 5, 4);
     450             : 
     451             :   // set DIO1 to the FIFO full event
     452           0 :   setDio1Action(func, this->mod->hal->GpioInterruptRising);
     453           0 : }
     454             : 
     455           0 : void SX127x::clearFifoFullAction() {
     456           0 :   clearDio1Action();
     457           0 :   this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, 0x00, 5, 4);
     458           0 : }
     459             : 
     460           0 : void SX127x::errataFix(bool rx) {
     461             :   (void)rx;
     462             :   // should be implemented in derived class
     463           0 : }
     464             : 
     465           0 : bool SX127x::fifoAdd(uint8_t* data, int totalLen, int* remLen) {
     466             :   // subtract first (this may be the first time we get to modify the remaining length)
     467           0 :   *remLen -= RADIOLIB_SX127X_FIFO_THRESH - 1;
     468             : 
     469             :   // check if there is still something left to send
     470           0 :   if(*remLen <= 0) {
     471             :     // we're done
     472           0 :     return(true);
     473             :   }
     474             : 
     475             :   // calculate the number of bytes we can copy
     476           0 :   int len = *remLen;
     477           0 :   if(len > RADIOLIB_SX127X_FIFO_THRESH - 1) {
     478           0 :     len = RADIOLIB_SX127X_FIFO_THRESH - 1;
     479             :   }
     480             : 
     481             :   // copy the bytes to the FIFO
     482           0 :   this->mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_FIFO, &data[totalLen - *remLen], len);
     483             : 
     484             :   // we're not done yet
     485           0 :   return(false);
     486             : }
     487             : 
     488           0 : bool SX127x::fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen) {
     489             :   // get pointer to the correct position in data buffer
     490           0 :   uint8_t* dataPtr = const_cast<uint8_t*>(&data[*rcvLen]);
     491             : 
     492             :   // check how much data are we still expecting
     493           0 :   uint8_t len = RADIOLIB_SX127X_FIFO_THRESH - 1;
     494           0 :   if(totalLen - *rcvLen < len) {
     495             :     // we're nearly at the end
     496           0 :     len = totalLen - *rcvLen;
     497             :   }
     498             : 
     499             :   // get the data
     500           0 :   this->mod->SPIreadRegisterBurst(RADIOLIB_SX127X_REG_FIFO, len, dataPtr);
     501           0 :   *rcvLen = *rcvLen + len;
     502             : 
     503             :   // check if we're done
     504           0 :   if(*rcvLen >= totalLen) {
     505           0 :     return(true);
     506             :   }
     507           0 :   return(false);
     508             : }
     509             : 
     510           6 : int16_t SX127x::finishTransmit() {
     511             :   // wait for at least 1 bit at the lowest possible bit rate before clearing IRQ flags
     512             :   // not doing this and clearing RADIOLIB_SX127X_FLAG_FIFO_OVERRUN will dump the FIFO,
     513             :   // which can lead to mangling of the last bit (#808)
     514           6 :   mod->hal->delayMicroseconds(1000000/1200);
     515             : 
     516             :   // clear interrupt flags
     517           6 :   clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
     518             : 
     519             :   // set mode to standby to disable transmitter/RF switch
     520           6 :   return(standby());
     521             : }
     522             : 
     523           6 : int16_t SX127x::readData(uint8_t* data, size_t len) {
     524           6 :   int16_t modem = getActiveModem();
     525             : 
     526             :   // get packet length
     527           6 :   size_t length = getPacketLength();
     528           6 :   size_t dumpLen = 0;
     529           6 :   if((len != 0) && (len < length)) {
     530             :     // user requested less data than we got, only return what was requested
     531           6 :     dumpLen = length - len;
     532           6 :     length = len;
     533             :   }
     534             : 
     535             :   // check payload CRC
     536           6 :   int16_t state = RADIOLIB_ERR_NONE;
     537           6 :   if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_IRQ_FLAGS, 5, 5) == RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR) {
     538           6 :     state = RADIOLIB_ERR_CRC_MISMATCH;
     539             :   }
     540             : 
     541           6 :   if(modem == RADIOLIB_SX127X_LORA) {
     542             :     // check packet header integrity
     543           6 :     if(this->crcEnabled && (state == RADIOLIB_ERR_NONE)  && (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 6, 6) == 0)) {
     544             :       // CRC is disabled according to packet header and enabled according to user
     545             :       // most likely damaged packet header
     546           0 :       state = RADIOLIB_ERR_LORA_HEADER_DAMAGED;
     547             :     } 
     548             :     // set FIFO read pointer to the start of the current packet
     549           6 :     int16_t addr = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FIFO_RX_CURRENT_ADDR);
     550           6 :     if (addr >= 0) {
     551           6 :       this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, addr);
     552             :     }
     553             : 
     554           0 :   } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
     555             :     // check address filtering
     556           0 :     uint8_t filter = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 2, 1);
     557           0 :     if((filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE) || (filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) {
     558           0 :       this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_FIFO);
     559             :     }
     560             :   }
     561             : 
     562             :   // read packet data
     563           6 :   this->mod->SPIreadRegisterBurst(RADIOLIB_SX127X_REG_FIFO, length, data);
     564             : 
     565             :   // dump the bytes that weren't requested
     566           6 :   if(dumpLen != 0) {
     567           6 :     clearFIFO(dumpLen);
     568             :   }
     569             : 
     570             :   // clear internal flag so getPacketLength can return the new packet length
     571           6 :   this->packetLengthQueried = false;
     572             : 
     573             :   // clear interrupt flags
     574           6 :   clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
     575             : 
     576           6 :   return(state);
     577             : }
     578             : 
     579           6 : int16_t SX127x::finishReceive() {
     580             :   // set mode to standby to disable RF switch
     581           6 :   int16_t state = standby();
     582           6 :   RADIOLIB_ASSERT(state);
     583             : 
     584             :   // clear interrupt flags
     585           0 :   return(clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL));
     586             : }
     587             : 
     588          18 : int16_t SX127x::startChannelScan() {
     589             :   // the configuration is not actually used
     590          18 :   const ChannelScanConfig_t cfg = { .rssi = { .limit = 0 } };
     591          36 :   return(startChannelScan(cfg));
     592             : }
     593             : 
     594          24 : int16_t SX127x::startChannelScan(const ChannelScanConfig_t &config) {
     595             :   (void)config;
     596             : 
     597             :   // check active modem
     598          24 :   if(getActiveModem() != RADIOLIB_SX127X_LORA) {
     599           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     600             :   }
     601             : 
     602             :   // set mode to standby
     603          24 :   int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
     604          24 :   RADIOLIB_ASSERT(state);
     605             : 
     606             :   // clear interrupt flags
     607           0 :   clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
     608             : 
     609             :   // set DIO pin mapping
     610           0 :   state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_CAD_DONE | RADIOLIB_SX127X_DIO1_LORA_CAD_DETECTED, 7, 4);
     611           0 :   RADIOLIB_ASSERT(state);
     612             : 
     613             :   // set RF switch (if present)
     614           0 :   this->mod->setRfSwitchState(Module::MODE_RX);
     615             : 
     616             :   // set mode to CAD
     617           0 :   state = setMode(RADIOLIB_SX127X_CAD);
     618           0 :   return(state);
     619             : }
     620             : 
     621           6 : int16_t SX127x::getChannelScanResult() {
     622           6 :   if((this->getIRQFlags() & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED) == RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED) {
     623           6 :     return(RADIOLIB_PREAMBLE_DETECTED);
     624             :   }
     625           0 :   return(RADIOLIB_CHANNEL_FREE);
     626             : }
     627             : 
     628           6 : int16_t SX127x::setSyncWord(uint8_t syncWord) {
     629             :   // check active modem
     630           6 :   if(getActiveModem() != RADIOLIB_SX127X_LORA) {
     631           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     632             :   }
     633             : 
     634             :   // set mode to standby
     635           6 :   setMode(RADIOLIB_SX127X_STANDBY);
     636             : 
     637             :   // write register
     638           6 :   return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_WORD, syncWord));
     639             : }
     640             : 
     641           0 : int16_t SX127x::setCurrentLimit(uint8_t currentLimit) {
     642             :   // check allowed range
     643           0 :   if(!(((currentLimit >= 45) && (currentLimit <= 240)) || (currentLimit == 0))) {
     644           0 :     return(RADIOLIB_ERR_INVALID_CURRENT_LIMIT);
     645             :   }
     646             : 
     647             :   // set mode to standby
     648           0 :   int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
     649             : 
     650             :   // set OCP limit
     651             :   uint8_t raw;
     652           0 :   if(currentLimit == 0) {
     653             :     // limit set to 0, disable OCP
     654           0 :     state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OCP, RADIOLIB_SX127X_OCP_OFF, 5, 5);
     655           0 :   } else if(currentLimit <= 120) {
     656           0 :     raw = (currentLimit - 45) / 5;
     657           0 :     state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OCP, RADIOLIB_SX127X_OCP_ON | raw, 5, 0);
     658           0 :   } else if(currentLimit <= 240) {
     659           0 :     raw = (currentLimit + 30) / 10;
     660           0 :     state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OCP, RADIOLIB_SX127X_OCP_ON | raw, 5, 0);
     661             :   }
     662           0 :   return(state);
     663             : }
     664             : 
     665           6 : int16_t SX127x::setPreambleLength(size_t preambleLength) {
     666             :   // set mode to standby
     667           6 :   int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
     668           6 :   RADIOLIB_ASSERT(state);
     669             : 
     670             :   // check active modem
     671           0 :   uint8_t modem = getActiveModem();
     672           0 :   if(modem == RADIOLIB_SX127X_LORA) {
     673             :     // check allowed range
     674           0 :     if(preambleLength < 6) {
     675           0 :       return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH);
     676             :     }
     677             : 
     678             :     // set preamble length
     679           0 :     state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB, (uint8_t)((preambleLength >> 8) & 0xFF));
     680           0 :     state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB, (uint8_t)(preambleLength & 0xFF));
     681           0 :     return(state);
     682             : 
     683           0 :   } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
     684             :     // set preamble length (in bytes)
     685           0 :     uint16_t numBytes = preambleLength / 8;
     686           0 :     state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK, (uint8_t)((numBytes >> 8) & 0xFF));
     687           0 :     state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK, (uint8_t)(numBytes & 0xFF));
     688           0 :     return(state);
     689             :   }
     690             : 
     691           0 :   return(RADIOLIB_ERR_UNKNOWN);
     692             : }
     693             : 
     694           0 : int16_t SX127x::invertPreamble(bool enable) {
     695             :   // set mode to standby
     696           0 :   int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
     697           0 :   RADIOLIB_ASSERT(state);
     698             : 
     699             :   // check active modem
     700           0 :   uint8_t modem = getActiveModem();
     701           0 :   if(modem == RADIOLIB_SX127X_LORA) {
     702           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     703           0 :   } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
     704             :     // set preamble polarity
     705           0 :     uint8_t polarity = enable ? RADIOLIB_SX127X_PREAMBLE_POLARITY_AA : RADIOLIB_SX127X_PREAMBLE_POLARITY_55;
     706           0 :     state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, polarity, 5, 5);
     707           0 :     return(state);
     708             :   }
     709             : 
     710           0 :   return(RADIOLIB_ERR_UNKNOWN);
     711             : }
     712             : 
     713           0 : float SX127x::getFrequencyError(bool autoCorrect) {
     714           0 :   int16_t modem = getActiveModem();
     715           0 :   if(modem == RADIOLIB_SX127X_LORA) {
     716             :     // get raw frequency error
     717           0 :     uint32_t raw = (uint32_t)this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_MSB, 3, 0) << 16;
     718           0 :     raw |= (uint16_t)this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_MID) << 8;
     719           0 :     raw |= this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_LSB);
     720             : 
     721           0 :     uint32_t base = (uint32_t)2 << 23;
     722             :     float error;
     723             : 
     724             :     // check the first bit
     725           0 :     if(raw & 0x80000) {
     726             :       // frequency error is negative
     727           0 :       raw |= (uint32_t)0xFFF00000;
     728           0 :       raw = ~raw + 1;
     729           0 :       error = (((float)raw * (float)base)/32000000.0f) * (this->bandwidth/500.0f) * -1.0f;
     730             :     } else {
     731           0 :       error = (((float)raw * (float)base)/32000000.0f) * (this->bandwidth/500.0f);
     732             :     }
     733             : 
     734           0 :     if(autoCorrect) {
     735             :       // adjust LoRa modem data rate
     736           0 :       float ppmOffset = 0.95f * (error/32.0f);
     737           0 :       this->mod->SPIwriteRegister(0x27, (uint8_t)ppmOffset);
     738             :     }
     739             : 
     740           0 :     return(error);
     741             : 
     742           0 :   } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
     743             :     // get raw frequency error
     744           0 :     uint16_t raw = (uint16_t)this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_MSB_FSK) << 8;
     745           0 :     raw |= this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_LSB_FSK);
     746             : 
     747           0 :     uint32_t base = 1;
     748             :     float error;
     749             : 
     750             :     // check the first bit
     751           0 :     if(raw & 0x8000) {
     752             :       // frequency error is negative
     753           0 :       raw |= (uint32_t)0xFFF00000;
     754           0 :       raw = ~raw + 1;
     755           0 :       error = (float)raw * (32000000.0f / (float)(base << 19)) * -1.0f;
     756             :     } else {
     757           0 :       error = (float)raw * (32000000.0f / (float)(base << 19));
     758             :     }
     759             : 
     760           0 :     return(error);
     761             :   }
     762             : 
     763           0 :   return(RADIOLIB_ERR_UNKNOWN);
     764             : }
     765             : 
     766           0 : float SX127x::getAFCError()
     767             : {
     768             :   // check active modem
     769           0 :   int16_t modem = getActiveModem();
     770           0 :   if(modem != RADIOLIB_SX127X_FSK_OOK) {
     771           0 :     return 0;
     772             :   }
     773             : 
     774             :   // get raw frequency error
     775           0 :   int16_t raw = (uint16_t)this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_AFC_MSB) << 8;
     776           0 :   raw |= this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_AFC_LSB);
     777             : 
     778           0 :   uint32_t base = 1;
     779           0 :   return raw * (32000000.0f / (float)(base << 19));
     780             : }
     781             : 
     782          12 : float SX127x::getSNR() {
     783             :   // check active modem
     784          12 :   if(getActiveModem() != RADIOLIB_SX127X_LORA) {
     785           0 :     return(0);
     786             :   }
     787             : 
     788             :   // get SNR value
     789          12 :   int8_t rawSNR = (int8_t)this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PKT_SNR_VALUE);
     790          12 :   return(rawSNR / 4.0);
     791             : }
     792             : 
     793           6 : int16_t SX127x::setBitRateCommon(float br, uint8_t fracRegAddr) {
     794             :   // check active modem
     795           6 :   if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
     796           6 :     return(RADIOLIB_ERR_WRONG_MODEM);
     797             :   }
     798             : 
     799             :   // check allowed bit rate
     800             :   // datasheet says 1.2 kbps should be the smallest possible, but 0.512 works fine
     801           0 :   if(ookEnabled) {
     802           0 :     RADIOLIB_CHECK_RANGE(br, 0.5f, 32.768002f, RADIOLIB_ERR_INVALID_BIT_RATE);      // Found that 32.768 is 32.768002
     803             :   } else {
     804           0 :     RADIOLIB_CHECK_RANGE(br, 0.5f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
     805             :   }
     806             : 
     807             :   // set mode to STANDBY
     808           0 :   int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
     809           0 :   RADIOLIB_ASSERT(state);
     810             : 
     811             :   // set bit rate
     812           0 :   uint16_t bitRateRaw = (RADIOLIB_SX127X_CRYSTAL_FREQ * 1000.0f) / br;
     813           0 :   state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BITRATE_MSB, (bitRateRaw & 0xFF00) >> 8, 7, 0);
     814           0 :   state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BITRATE_LSB, bitRateRaw & 0x00FF, 7, 0);
     815             : 
     816             :   // set fractional part of bit rate
     817           0 :   if(!ookEnabled) {
     818           0 :     float bitRateRem = ((RADIOLIB_SX127X_CRYSTAL_FREQ * 1000.0f) / br) - (float)bitRateRaw;
     819           0 :     uint8_t bitRateFrac = bitRateRem * 16;
     820           0 :     state |= this->mod->SPIsetRegValue(fracRegAddr, bitRateFrac, 7, 0);
     821             :   }
     822             : 
     823           0 :   if(state == RADIOLIB_ERR_NONE) {
     824           0 :     this->bitRate = br;
     825             :   }
     826           0 :   return(state);
     827             : }
     828             : 
     829           6 : int16_t SX127x::setFrequencyDeviation(float freqDev) {
     830             :   // check active modem
     831           6 :   if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
     832           6 :     return(RADIOLIB_ERR_WRONG_MODEM);
     833             :   }
     834             : 
     835             :   // set frequency deviation to lowest available setting (required for digimodes)
     836           0 :   float newFreqDev = freqDev;
     837           0 :   if(freqDev < 0.0f) {
     838           0 :     newFreqDev = 0.6f;
     839             :   }
     840             : 
     841             :   // check frequency deviation range
     842           0 :   if(!((newFreqDev + this->bitRate/2.0f <= 250.0f) && (freqDev <= 200.0f))) {
     843           0 :     return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
     844             :   }
     845             : 
     846           0 :   this->frequencyDev = newFreqDev;
     847             : 
     848             :   // set mode to STANDBY
     849           0 :   int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
     850           0 :   RADIOLIB_ASSERT(state);
     851             : 
     852             :   // set allowed frequency deviation
     853           0 :   uint32_t base = 1;
     854           0 :   uint32_t FDEV = (newFreqDev * (base << 19)) / 32000;
     855           0 :   state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FDEV_MSB, (FDEV & 0xFF00) >> 8, 5, 0);
     856           0 :   state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FDEV_LSB, FDEV & 0x00FF, 7, 0);
     857           0 :   return(state);
     858             : }
     859             : 
     860           0 : uint8_t SX127x::calculateBWManExp(float bandwidth)
     861             : {
     862           0 :   for(uint8_t e = 7; e >= 1; e--) {
     863           0 :     for(int8_t m = 2; m >= 0; m--) {
     864           0 :       float point = (RADIOLIB_SX127X_CRYSTAL_FREQ * 1000000.0f)/(((4 * m) + 16) * ((uint32_t)1 << (e + 2)));
     865           0 :       if(fabsf(bandwidth - ((point / 1000.0f) + 0.05f)) <= 0.5f) {
     866           0 :         return((m << 3) | e);
     867             :       }
     868             :     }
     869             :   }
     870           0 :   return 0;
     871             : }
     872             : 
     873           0 : int16_t SX127x::setRxBandwidth(float rxBw) {
     874             :   // check active modem
     875           0 :   if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
     876           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     877             :   }
     878             : 
     879           0 :   RADIOLIB_CHECK_RANGE(rxBw, 2.6f, 250.0f, RADIOLIB_ERR_INVALID_RX_BANDWIDTH);
     880             : 
     881             :   // set mode to STANDBY
     882           0 :   int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
     883           0 :   RADIOLIB_ASSERT(state);
     884             : 
     885             :   // set Rx bandwidth
     886           0 :   return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_BW, calculateBWManExp(rxBw), 4, 0));
     887             : }
     888             : 
     889           0 : int16_t SX127x::setAFCBandwidth(float rxBw) {
     890             :   // check active modem
     891           0 :   if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK){
     892           0 :       return(RADIOLIB_ERR_WRONG_MODEM);
     893             :   }
     894             : 
     895           0 :   RADIOLIB_CHECK_RANGE(rxBw, 2.6f, 250.0f, RADIOLIB_ERR_INVALID_RX_BANDWIDTH);
     896             : 
     897             :   // set mode to STANDBY
     898           0 :   int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
     899           0 :   RADIOLIB_ASSERT(state);
     900             : 
     901             :   // set AFC bandwidth
     902           0 :   return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_AFC_BW, calculateBWManExp(rxBw), 4, 0));
     903             : }
     904             : 
     905           0 : int16_t SX127x::setAFC(bool isEnabled) {
     906             :   // check active modem
     907           0 :   if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
     908           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     909             :   }
     910             : 
     911             :   //set AFC auto on/off
     912           0 :   return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, isEnabled ? RADIOLIB_SX127X_AFC_AUTO_ON : RADIOLIB_SX127X_AFC_AUTO_OFF, 4, 4));
     913             : }
     914             : 
     915           0 : int16_t SX127x::setAFCAGCTrigger(uint8_t trigger) {
     916           0 :   if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
     917           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     918             :   }
     919             : 
     920             :   //set AFC&AGC trigger
     921           0 :   return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, trigger, 2, 0));
     922             : }
     923             : 
     924           6 : int16_t SX127x::setSyncWord(uint8_t* syncWord, size_t len) {
     925             :   // check active modem
     926           6 :   uint8_t modem = getActiveModem();
     927           6 :   if(modem == RADIOLIB_SX127X_FSK_OOK) {
     928             : 
     929             :     // disable sync word in case len is 0
     930           0 :     if(len == 0) {
     931           0 :       int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, RADIOLIB_SX127X_SYNC_OFF, 4, 4);
     932           0 :       return(state);
     933             :     }
     934             : 
     935           0 :     RADIOLIB_CHECK_RANGE(len, 1, 8, RADIOLIB_ERR_INVALID_SYNC_WORD);
     936             : 
     937             :     // sync word must not contain value 0x00
     938           0 :     for(size_t i = 0; i < len; i++) {
     939           0 :       if(syncWord[i] == 0x00) {
     940           0 :         return(RADIOLIB_ERR_INVALID_SYNC_WORD);
     941             :       }
     942             :     }
     943             : 
     944             :     // enable sync word recognition
     945           0 :     int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, RADIOLIB_SX127X_SYNC_ON, 4, 4);
     946           0 :     state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, len - 1, 2, 0);
     947           0 :     RADIOLIB_ASSERT(state);
     948             : 
     949             :     // set sync word
     950           0 :     this->mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_SYNC_VALUE_1, syncWord, len);
     951           0 :     return(RADIOLIB_ERR_NONE);
     952             :   
     953           6 :   } else if(modem == RADIOLIB_SX127X_LORA) {
     954             :     // with length set to 1 and LoRa modem active, assume it is the LoRa sync word
     955           6 :     if(len > 1) {
     956           0 :       return(RADIOLIB_ERR_INVALID_SYNC_WORD);
     957             :     }
     958             : 
     959           6 :     return(this->setSyncWord(syncWord[0]));
     960             :   }
     961             : 
     962           0 :   return(RADIOLIB_ERR_WRONG_MODEM);
     963             : }
     964             : 
     965           0 : int16_t SX127x::setNodeAddress(uint8_t nodeAddr) {
     966             :   // check active modem
     967           0 :   if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
     968           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     969             :   }
     970             : 
     971             :   // enable address filtering (node only)
     972           0 :   int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_ADDRESS_FILTERING_NODE, 2, 1);
     973           0 :   RADIOLIB_ASSERT(state);
     974             : 
     975             :   // set node address
     976           0 :   return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_NODE_ADRS, nodeAddr));
     977             : }
     978             : 
     979           0 : int16_t SX127x::setBroadcastAddress(uint8_t broadAddr) {
     980             :   // check active modem
     981           0 :   if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
     982           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     983             :   }
     984             : 
     985             :   // enable address filtering (node + broadcast)
     986           0 :   int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST, 2, 1);
     987           0 :   RADIOLIB_ASSERT(state);
     988             : 
     989             :   // set broadcast address
     990           0 :   return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BROADCAST_ADRS, broadAddr));
     991             : }
     992             : 
     993           0 : int16_t SX127x::disableAddressFiltering() {
     994             :   // check active modem
     995           0 :   if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
     996           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     997             :   }
     998             : 
     999             :   // disable address filtering
    1000           0 :   int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_ADDRESS_FILTERING_OFF, 2, 1);
    1001           0 :   RADIOLIB_ASSERT(state);
    1002             : 
    1003             :   // set node address to default (0x00)
    1004           0 :   state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_NODE_ADRS, 0x00);
    1005           0 :   RADIOLIB_ASSERT(state);
    1006             : 
    1007             :   // set broadcast address to default (0x00)
    1008           0 :   return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BROADCAST_ADRS, 0x00));
    1009             : }
    1010             : 
    1011           0 : int16_t SX127x::setOokThresholdType(uint8_t type) {
    1012             :   // check active modem
    1013           0 :   if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
    1014           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1015             :   }
    1016           0 :   return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, type, 4, 3, 5));
    1017             : }
    1018             : 
    1019           0 : int16_t SX127x::setOokFixedOrFloorThreshold(uint8_t value) {
    1020             :   // check active modem
    1021           0 :   if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
    1022           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1023             :   }
    1024           0 :   return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_FIX, value, 7, 0, 5));
    1025             : }
    1026             : 
    1027           0 : int16_t SX127x::setOokPeakThresholdDecrement(uint8_t value) {
    1028             :   // check active modem
    1029           0 :   if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
    1030           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1031             :   }
    1032           0 :   return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_AVG, value, 7, 5, 5));
    1033             : }
    1034             : 
    1035           0 : int16_t SX127x::setOokPeakThresholdStep(uint8_t value) {
    1036             :   // check active modem
    1037           0 :   if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
    1038           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1039             :   }
    1040           0 :   return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, value, 2, 0, 5));
    1041             : }
    1042             : 
    1043           0 : int16_t SX127x::enableBitSync() {
    1044           0 :   return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, RADIOLIB_SX127X_BIT_SYNC_ON, 5, 5, 5));
    1045             : }
    1046             : 
    1047           0 : int16_t SX127x::disableBitSync() {
    1048           0 :   return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, RADIOLIB_SX127X_BIT_SYNC_OFF, 5, 5, 5));
    1049             : }
    1050             : 
    1051           0 : int16_t SX127x::setOOK(bool enableOOK) {
    1052             :   // check active modem
    1053           0 :   if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
    1054           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1055             :   }
    1056             : 
    1057             :   // set OOK and if successful, save the new setting
    1058           0 :   int16_t state = RADIOLIB_ERR_NONE;
    1059           0 :   if(enableOOK) {
    1060           0 :     state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX127X_MODULATION_OOK, 6, 5, 5);
    1061           0 :     state |= SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_RSSI_INTERRUPT);
    1062             :   } else {
    1063           0 :     state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX127X_MODULATION_FSK, 6, 5, 5);
    1064           0 :     state |= SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_BOTH);
    1065             :   }
    1066           0 :   if(state == RADIOLIB_ERR_NONE) {
    1067           0 :     ookEnabled = enableOOK;
    1068             :   }
    1069             : 
    1070           0 :   return(state);
    1071             : }
    1072             : 
    1073           0 : int16_t SX127x::setFrequencyRaw(float newFreq) {
    1074           0 :   int16_t state = RADIOLIB_ERR_NONE;
    1075             : 
    1076             :   // set mode to standby if not FHSS
    1077           0 :   if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) == RADIOLIB_SX127X_HOP_PERIOD_OFF) {
    1078           0 :     state = setMode(RADIOLIB_SX127X_STANDBY);
    1079             :   }
    1080             : 
    1081             :   // calculate register values
    1082           0 :   uint32_t FRF = (newFreq * (uint32_t(1) << RADIOLIB_SX127X_DIV_EXPONENT)) / RADIOLIB_SX127X_CRYSTAL_FREQ;
    1083             : 
    1084             :   // write registers
    1085             :   // lsb needs to be written no matter what in order for the module to update the frequency
    1086           0 :   state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FRF_MSB, (FRF & 0xFF0000) >> 16);
    1087           0 :   state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FRF_MID, (FRF & 0x00FF00) >> 8);
    1088           0 :   state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FRF_LSB, FRF & 0x0000FF, 7U, 0U, 2U, 0xFF, true);
    1089           0 :   return(state);
    1090             : }
    1091             : 
    1092          12 : size_t SX127x::getPacketLength(bool update) {
    1093          12 :   int16_t modem = getActiveModem();
    1094             : 
    1095          12 :   if(modem == RADIOLIB_SX127X_LORA) {
    1096          12 :     if(!this->implicitHdr) {
    1097             :       // get packet length for explicit header mode
    1098          12 :       return(this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_RX_NB_BYTES));
    1099             : 
    1100             :     } else {
    1101             :       // return the cached value for implicit header mode
    1102           0 :       return(this->packetLength);
    1103             :     }
    1104             : 
    1105           0 :   } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
    1106             :     // get packet length
    1107           0 :     if(!this->packetLengthQueried && update) {
    1108           0 :       if (this->packetLengthConfig == RADIOLIB_SX127X_PACKET_VARIABLE) {
    1109           0 :         this->packetLength = this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_FIFO);
    1110             :       } else {
    1111           0 :         this->packetLength = this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK);
    1112             :       }
    1113           0 :       this->packetLengthQueried = true;
    1114             :     }
    1115             :   }
    1116             : 
    1117           0 :   return(this->packetLength);
    1118             : }
    1119             : 
    1120           0 : int16_t SX127x::getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC) {
    1121           0 :   int16_t state = RADIOLIB_ERR_NONE;
    1122             : 
    1123             :   // check if in explicit header mode
    1124           0 :   if(this->implicitHdr) {
    1125           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1126             :   }
    1127             : 
    1128           0 :   if(cr) { *cr = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_STAT, 7, 5) >> 5; }
    1129           0 :   if(hasCRC) { *hasCRC = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 6, 6) != 0; }
    1130             : 
    1131           0 :   return(state);
    1132             : }
    1133             : 
    1134           0 : int16_t SX127x::fixedPacketLengthMode(uint8_t len) {
    1135           0 :   return(SX127x::setPacketMode(RADIOLIB_SX127X_PACKET_FIXED, len));
    1136             : }
    1137             : 
    1138           0 : int16_t SX127x::variablePacketLengthMode(uint8_t maxLen) {
    1139           0 :   return(SX127x::setPacketMode(RADIOLIB_SX127X_PACKET_VARIABLE, maxLen));
    1140             : }
    1141             : 
    1142          14 : float SX127x::getNumSymbols(size_t len, DataRate_t dr, PacketConfig_t pc) {
    1143             :   // get Low Data Rate optimization flag
    1144          14 :   float de = pc.lora.ldrOptimize ? 1.0f : 0.0f;
    1145             : 
    1146             :   // get explicit/implicit header enabled flag
    1147          14 :   float ih = (float) pc.lora.implicitHeader;
    1148             : 
    1149             :   // get CRC enabled flag
    1150          14 :   float crc = (float) pc.lora.crcEnabled;
    1151             : 
    1152             :   // get number of preamble symbols
    1153          14 :   float n_pre = (float) pc.lora.preambleLength;
    1154             : 
    1155             :   // get number of payload symbols
    1156          14 :   float n_pay = 8.0f + RADIOLIB_MAX(ceilf((8.0f * (float) len - 4.0f * (float) dr.lora.spreadingFactor + 28.0f + 16.0f * crc - 20.0f * ih) / (4.0f * (float) dr.lora.spreadingFactor - 8.0f * de)) * (float) dr.lora.codingRate, 0.0f);
    1157             : 
    1158             :   // add 4.25 symbols for the sync
    1159          14 :   return(n_pre + n_pay + 4.25f);
    1160             : }
    1161             : 
    1162          24 : RadioLibTime_t SX127x::calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) {
    1163          24 :   if (modem == RADIOLIB_MODEM_LORA) {
    1164             :     // get symbol length in us
    1165          14 :     float symbolLength = (float) (uint32_t(1) << dr.lora.spreadingFactor) / (float) dr.lora.bandwidth;
    1166             : 
    1167             :     // get number of symbols
    1168          14 :     float n_sym = getNumSymbols(len, dr, pc);
    1169             : 
    1170             :     // get time-on-air in us
    1171          14 :     return ceil((double)symbolLength * (double)n_sym) * 1000;
    1172             : 
    1173          10 :   } else if(modem == RADIOLIB_MODEM_FSK) {
    1174             :     
    1175             :     // calculate time-on-air in us {[(length in bytes) * (8 bits / 1 byte)] / [(Bit Rate in kbps) * (1000 bps / 1 kbps)]} * (1000000 us in 1 sec)
    1176           4 :     return((uint32_t) ((((float)(pc.fsk.crcLength * 8) + pc.fsk.syncWordLength + pc.fsk.preambleLength + (float) (len * 8)) / (dr.fsk.bitRate * 1000.0f)) * 1000000.0f));
    1177             :   } else {
    1178           6 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1179             :   }
    1180             :   
    1181             :   return(RADIOLIB_ERR_UNKNOWN);
    1182             : }
    1183             : 
    1184           6 : RadioLibTime_t SX127x::getTimeOnAir(size_t len) {
    1185           6 :   uint8_t modem = getActiveModem();
    1186           6 :   DataRate_t dr = {};
    1187           6 :   PacketConfig_t pc = {};
    1188             : 
    1189           6 :   switch (modem) {
    1190           6 :     case(RADIOLIB_SX127X_LORA): {
    1191           6 :       dr.lora.spreadingFactor = this->spreadingFactor;
    1192           6 :       dr.lora.bandwidth = this->bandwidth;
    1193           6 :       dr.lora.codingRate = this->codingRate;
    1194             : 
    1195             :       // Get number of preamble symbols
    1196           6 :       uint16_t n_pre = ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB));
    1197             : 
    1198           6 :       pc.lora.preambleLength = n_pre;
    1199           6 :       pc.lora.implicitHeader = this->implicitHdr;
    1200           6 :       pc.lora.crcEnabled = this->crcEnabled;
    1201           6 :       pc.lora.ldrOptimize = this->ldroEnabled;
    1202             : 
    1203           6 :       return(calculateTimeOnAir((ModemType_t)RADIOLIB_MODEM_LORA, dr, pc, len));
    1204             :     }
    1205           0 :     case(RADIOLIB_SX127X_FSK_OOK): {
    1206           0 :       dr.fsk.bitRate = this->bitRate;
    1207           0 :       dr.fsk.freqDev = this->frequencyDev;
    1208             : 
    1209             :       // get number of bits preamble
    1210           0 :       uint16_t n_pre = (uint16_t) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK)) * 8;
    1211             :       // get the number of bits of the sync word
    1212           0 :       uint8_t n_syncWord = (uint8_t) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, 2, 0) + 1) * 8);
    1213             :       // get CRC enabled status
    1214           0 :       bool crcEn = (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 4, 4) == RADIOLIB_SX127X_CRC_ON);
    1215             : 
    1216           0 :       pc.fsk.preambleLength = n_pre;
    1217           0 :       pc.fsk.syncWordLength = n_syncWord;
    1218           0 :       pc.fsk.crcLength = (uint8_t)(crcEn * 2);
    1219             : 
    1220           0 :       if (this->packetLengthConfig == RADIOLIB_SX127X_PACKET_FIXED) {
    1221             :         // if packet size fixed -> len = fixed packet length
    1222           0 :         len = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK);
    1223             :       } else {
    1224             :         // if packet variable -> Add 1 extra byte for payload length
    1225           0 :         len += 1;
    1226             :       }
    1227             : 
    1228           0 :       return(calculateTimeOnAir((ModemType_t)RADIOLIB_MODEM_FSK, dr, pc, len));
    1229             :     }
    1230           0 :     default:
    1231           0 :       return(RADIOLIB_ERR_WRONG_MODEM);
    1232             :   }
    1233             : }
    1234             : 
    1235           6 : RadioLibTime_t SX127x::calculateRxTimeout(RadioLibTime_t timeoutUs) {
    1236           6 :   RadioLibTime_t timeout = 0;
    1237           6 :   if(getActiveModem() == RADIOLIB_SX127X_LORA) {
    1238             :     // for LoRa, the timeout is given as the number of symbols
    1239             :     // the calling function should provide some extra width, as this number of symbols is truncated to integer
    1240             :     // the order of operators is swapped here to decrease the effects of this truncation error
    1241           6 :     float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth;
    1242           6 :     timeout = (timeoutUs / symbolLength) / 1000;
    1243             :   
    1244             :   } else {
    1245             :     // for FSK, the timeout is in units of 16x bit time
    1246           0 :     timeout = ((float)timeoutUs / ((16.0f * 1000.0f) / this->bitRate));
    1247             :   
    1248             :   }
    1249             : 
    1250           6 :   return(timeout);
    1251             : }
    1252             : 
    1253           6 : uint32_t SX127x::getIrqFlags() {
    1254           6 :   return((uint32_t)this->getIRQFlags());
    1255             : }
    1256             : 
    1257           6 : int16_t SX127x::setIrqFlags(uint32_t irq) {
    1258             :   // this is a bit convoluted, but unfortunately SX127x IRQ flags are not used to enable/disable that IRQ ...
    1259             :   // in addition, the configuration is often mutually exclusive, so we iterate over the set bits in a loop
    1260           6 :   uint8_t usedPinFlags = 0;
    1261           6 :   bool conflict = false;
    1262           6 :   int16_t modem = getActiveModem();
    1263           6 :   int16_t state = RADIOLIB_ERR_NONE;
    1264         198 :   for(uint8_t i = 0; i <= 31; i++) {
    1265             :     // check if the bit is set
    1266         192 :     uint32_t irqBit = irq & (1UL << i);
    1267         192 :     if(!irqBit) {
    1268         192 :       continue;
    1269             :     }
    1270             : 
    1271             :     // if not, decode it
    1272           0 :     uint8_t dioNum = 0; // DIO pin number and register value to set (address and MSB/LSB can be inferred)
    1273           0 :     uint8_t regVal = 0;
    1274           0 :     if(modem == RADIOLIB_SX127X_LORA) {
    1275           0 :       switch(irqBit) {
    1276           0 :         case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_TX_DONE):
    1277           0 :           dioNum = 0;
    1278           0 :           regVal = RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT;
    1279           0 :           break;
    1280           0 :         case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_DONE):
    1281           0 :           dioNum = 0;
    1282           0 :           regVal = RADIOLIB_SX127X_DIO0_LORA_RX_DONE;
    1283           0 :           break;
    1284           0 :         case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_VALID_HEADER):
    1285           0 :           dioNum = 3;
    1286           0 :           regVal = RADIOLIB_SX127X_DIO3_LORA_VALID_HEADER;
    1287           0 :           break;
    1288           0 :         case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR):
    1289           0 :           dioNum = 3;
    1290           0 :           regVal = RADIOLIB_SX127X_DIO3_LORA_PAYLOAD_CRC_ERROR;
    1291           0 :           break;
    1292           0 :         case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DONE):
    1293           0 :           dioNum = 0;
    1294           0 :           regVal = RADIOLIB_SX127X_DIO0_LORA_CAD_DONE;
    1295           0 :           break;
    1296           0 :         case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED):
    1297           0 :           dioNum = 1;
    1298           0 :           regVal = RADIOLIB_SX127X_DIO1_LORA_CAD_DETECTED;
    1299           0 :           break;
    1300           0 :         case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT):
    1301           0 :           dioNum = 1;
    1302           0 :           regVal = RADIOLIB_SX127X_DIO1_LORA_RX_TIMEOUT;
    1303           0 :           break;
    1304           0 :         default:
    1305           0 :           return(RADIOLIB_ERR_UNSUPPORTED);
    1306             :       }
    1307             :     
    1308           0 :     } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
    1309           0 :       switch(irqBit) {
    1310           0 :         case(RADIOLIB_SX127X_FLAG_PACKET_SENT << 8):
    1311           0 :           dioNum = 0;
    1312           0 :           regVal = RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT;
    1313           0 :           break;
    1314           0 :         case(RADIOLIB_SX127X_FLAG_PAYLOAD_READY << 8):
    1315           0 :           dioNum = 0;
    1316           0 :           regVal = RADIOLIB_SX127X_DIO0_PACK_PAYLOAD_READY;
    1317           0 :           break;
    1318           0 :         case(RADIOLIB_SX127X_FLAG_PREAMBLE_DETECT << 0):
    1319           0 :           dioNum = 4;
    1320           0 :           regVal = RADIOLIB_SX127X_DIO4_PACK_RSSI_PREAMBLE_DETECT;
    1321           0 :           break;
    1322           0 :         case(RADIOLIB_SX127X_FLAG_SYNC_ADDRESS_MATCH << 0):
    1323           0 :           dioNum = 2;
    1324           0 :           regVal = RADIOLIB_SX127X_DIO2_PACK_SYNC_ADDRESS;
    1325           0 :           break;
    1326           0 :         case(RADIOLIB_SX127X_FLAG_TIMEOUT << 0):
    1327           0 :           dioNum = 2;
    1328           0 :           regVal = RADIOLIB_SX127X_DIO2_PACK_TIMEOUT;
    1329           0 :           break;
    1330           0 :         default:
    1331           0 :           return(RADIOLIB_ERR_UNSUPPORTED);
    1332             :       }
    1333             :     }
    1334             : 
    1335             :     // check if this DIO pin has been set already
    1336           0 :     if(usedPinFlags & (1UL << dioNum)) {
    1337             :       // uh oh, this pin is used!
    1338             :       RADIOLIB_DEBUG_PRINTLN("Unable to set IRQ %04x on DIO%d due to conflict!", irqBit, (int)dioNum);
    1339           0 :       conflict = true;
    1340           0 :       continue;
    1341             :     }
    1342             : 
    1343             :     // DIO pin is unused, set the flag and configure it
    1344           0 :     usedPinFlags |= (1UL << dioNum);
    1345           0 :     uint8_t addr = (dioNum > 3) ? RADIOLIB_SX127X_REG_DIO_MAPPING_2 : RADIOLIB_SX127X_REG_DIO_MAPPING_1;
    1346           0 :     uint8_t msb = 7 - 2*(dioNum % 4);
    1347           0 :     state = this->mod->SPIsetRegValue(addr, regVal, msb, msb - 1);
    1348           0 :     RADIOLIB_ASSERT(state);
    1349             :   }
    1350             : 
    1351             :   // if there was at least one conflict, this flag is set
    1352           6 :   if(conflict) {
    1353           0 :     return(RADIOLIB_ERR_INVALID_IRQ);
    1354             :   }
    1355             : 
    1356           6 :   return(state);
    1357             : }
    1358             : 
    1359          24 : int16_t SX127x::clearIrqFlags(uint32_t irq) {
    1360          24 :   int16_t modem = getActiveModem();
    1361          24 :   if(modem == RADIOLIB_SX127X_LORA) {
    1362          24 :     this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, (uint8_t)irq);
    1363          24 :     return(RADIOLIB_ERR_NONE);
    1364             :   
    1365           0 :   } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
    1366           0 :     this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_1, (uint8_t)irq);
    1367           0 :     this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_2, (uint8_t)(irq >> 8));
    1368           0 :     return(RADIOLIB_ERR_NONE);
    1369             :   }
    1370             : 
    1371           0 :   return(RADIOLIB_ERR_UNKNOWN);
    1372             : }
    1373             : 
    1374           0 : int16_t SX127x::setCrcFiltering(bool enable) {
    1375           0 :   this->crcOn = enable;
    1376             : 
    1377           0 :   if (enable == true) {
    1378           0 :     return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_ON, 4, 4));
    1379             :   } else {
    1380           0 :     return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_OFF, 4, 4));
    1381             :   }
    1382             : }
    1383             : 
    1384           0 : int16_t SX127x::setRSSIThreshold(float dbm) {
    1385           0 :   RADIOLIB_CHECK_RANGE(dbm, -127.5f, 0.0f, RADIOLIB_ERR_INVALID_RSSI_THRESHOLD);
    1386             : 
    1387           0 :   return this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_THRESH, (uint8_t)(-2.0f * dbm), 7, 0);
    1388             : }
    1389             : 
    1390           0 : int16_t SX127x::setRSSIConfig(uint8_t smoothingSamples, int8_t offset) {
    1391             :   // check active modem
    1392           0 :   if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
    1393           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1394             :   }
    1395             : 
    1396             :   // set mode to standby
    1397           0 :   int16_t state = standby();
    1398           0 :   RADIOLIB_ASSERT(state);
    1399             : 
    1400             :   // check provided values
    1401           0 :   if(!(smoothingSamples <= 7)) {
    1402           0 :     return(RADIOLIB_ERR_INVALID_NUM_SAMPLES);
    1403             :   }
    1404             : 
    1405           0 :   RADIOLIB_CHECK_RANGE(offset, -16, 15, RADIOLIB_ERR_INVALID_RSSI_OFFSET);
    1406             : 
    1407             :   // calculate the two's complement
    1408           0 :   uint8_t offsetRaw = RADIOLIB_ABS(offset);
    1409           0 :   offsetRaw ^= 0x1F;
    1410           0 :   offsetRaw += 1;
    1411           0 :   offsetRaw &= 0x1F;
    1412             : 
    1413             :   // set new register values
    1414           0 :   state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_CONFIG, offsetRaw << 3, 7, 3);
    1415           0 :   state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_CONFIG, smoothingSamples, 2, 0);
    1416           0 :   return(state);
    1417             : }
    1418             : 
    1419           6 : int16_t SX127x::setEncoding(uint8_t encoding) {
    1420             :   // check active modem
    1421           6 :   if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
    1422           6 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1423             :   }
    1424             : 
    1425             :   // set encoding
    1426           0 :   switch(encoding) {
    1427           0 :     case RADIOLIB_ENCODING_NRZ:
    1428           0 :       return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_DC_FREE_NONE, 6, 5));
    1429           0 :     case RADIOLIB_ENCODING_MANCHESTER:
    1430           0 :       return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_DC_FREE_MANCHESTER, 6, 5));
    1431           0 :     case RADIOLIB_ENCODING_WHITENING:
    1432           0 :       return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_DC_FREE_WHITENING, 6, 5));
    1433           0 :     default:
    1434           0 :       return(RADIOLIB_ERR_INVALID_ENCODING);
    1435             :   }
    1436             : }
    1437             : 
    1438          12 : uint16_t SX127x::getIRQFlags() {
    1439             :   // check active modem
    1440          12 :   if(getActiveModem() == RADIOLIB_SX127X_LORA) {
    1441             :     // LoRa, just 8-bit value
    1442          12 :     return((uint16_t)this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS));
    1443             : 
    1444             :   } else {
    1445             :     // FSK, the IRQ flags are 16 bits in total
    1446           0 :     uint16_t flags = ((uint16_t)this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_2)) << 8;
    1447           0 :     flags |= (uint16_t)this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_1);
    1448           0 :     return(flags);
    1449             :   }
    1450             : 
    1451             : }
    1452             : 
    1453           0 : uint8_t SX127x::getModemStatus() {
    1454             :   // check active modem
    1455           0 :   if(getActiveModem() != RADIOLIB_SX127X_LORA) {
    1456           0 :     return(0x00);
    1457             :   }
    1458             : 
    1459             :   // read the register
    1460           0 :   return(this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_MODEM_STAT));
    1461             : }
    1462             : 
    1463           0 : void SX127x::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) {
    1464           0 :   this->mod->setRfSwitchPins(rxEn, txEn);
    1465           0 : }
    1466             : 
    1467           0 : void SX127x::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) {
    1468           0 :   this->mod->setRfSwitchTable(pins, table);
    1469           0 : }
    1470             : 
    1471           6 : uint8_t SX127x::randomByte() {
    1472             :   // check active modem
    1473           6 :   uint8_t rssiValueReg = RADIOLIB_SX127X_REG_RSSI_WIDEBAND;
    1474           6 :   if(getActiveModem() == RADIOLIB_SX127X_FSK_OOK) {
    1475           0 :     rssiValueReg = RADIOLIB_SX127X_REG_RSSI_VALUE_FSK;
    1476             :   }
    1477             : 
    1478             :   // set mode to Rx
    1479           6 :   setMode(RADIOLIB_SX127X_RX);
    1480             : 
    1481             :   // wait a bit for the RSSI reading to stabilise
    1482           6 :   this->mod->hal->delay(10);
    1483             : 
    1484             :   // read RSSI value 8 times, always keep just the least significant bit
    1485           6 :   uint8_t randByte = 0x00;
    1486          54 :   for(uint8_t i = 0; i < 8; i++) {
    1487          48 :     randByte |= ((this->mod->SPIreadRegister(rssiValueReg) & 0x01) << i);
    1488             :   }
    1489             : 
    1490             :   // set mode to standby
    1491           6 :   setMode(RADIOLIB_SX127X_STANDBY);
    1492             : 
    1493           6 :   return(randByte);
    1494             : }
    1495             : 
    1496           0 : int16_t SX127x::getChipVersion() {
    1497           0 :   return(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_VERSION));
    1498             : }
    1499             : 
    1500           0 : int8_t SX127x::getTempRaw() {
    1501           0 :   int8_t temp = 0;
    1502             :   uint8_t previousOpMode;
    1503             :   uint8_t ival;
    1504             : 
    1505             :   // save current Op Mode
    1506           0 :   previousOpMode = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_OP_MODE);
    1507             : 
    1508             :   // check if we need to step out of LoRa mode first
    1509           0 :   if((previousOpMode & RADIOLIB_SX127X_LORA) == RADIOLIB_SX127X_LORA) {
    1510           0 :     this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_LORA | RADIOLIB_SX127X_SLEEP));
    1511             :   }
    1512             : 
    1513             :   // put device in FSK sleep
    1514           0 :   this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_FSK_OOK | RADIOLIB_SX127X_SLEEP));
    1515             : 
    1516             :   // put device in FSK RxSynth
    1517           0 :   this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_FSK_OOK | RADIOLIB_SX127X_FSRX));
    1518             : 
    1519             :   // enable temperature reading
    1520           0 :   this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_IMAGE_CAL, RADIOLIB_SX127X_TEMP_MONITOR_ON, 0, 0);
    1521             : 
    1522             :   // wait
    1523           0 :   this->mod->hal->delayMicroseconds(200);
    1524             : 
    1525             :   // disable temperature reading
    1526           0 :   this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_IMAGE_CAL, RADIOLIB_SX127X_TEMP_MONITOR_OFF, 0, 0);
    1527             : 
    1528             :   // put device in FSK sleep
    1529           0 :   this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_FSK_OOK | RADIOLIB_SX127X_SLEEP));
    1530             : 
    1531             :   // read temperature
    1532           0 :   ival = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_TEMP);
    1533             : 
    1534             :   // convert very raw value
    1535           0 :   if((ival & 0x80) == 0x80) {
    1536           0 :     temp = 255 - ival;
    1537             :   } else {
    1538           0 :     temp = -1 * ival;
    1539             :   }
    1540             : 
    1541             :   // check if we need to step back into LoRa mode
    1542           0 :   if((previousOpMode & RADIOLIB_SX127X_LORA) == RADIOLIB_SX127X_LORA) {
    1543           0 :     this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_LORA | RADIOLIB_SX127X_SLEEP));
    1544             :   }
    1545             : 
    1546             :   // reload previous Op Mode
    1547           0 :   this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, previousOpMode);
    1548             : 
    1549           0 :   return(temp);
    1550             : }
    1551             : 
    1552           6 : Module* SX127x::getMod() {
    1553           6 :   return(this->mod);
    1554             : }
    1555             : 
    1556           0 : int16_t SX127x::config() {
    1557             :   // turn off frequency hopping
    1558           0 :   int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, RADIOLIB_SX127X_HOP_PERIOD_OFF);
    1559           0 :   return(state);
    1560             : }
    1561             : 
    1562           0 : int16_t SX127x::configFSK() {
    1563             :   // set RSSI threshold
    1564           0 :   int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_THRESH, RADIOLIB_SX127X_RSSI_THRESHOLD);
    1565           0 :   RADIOLIB_ASSERT(state);
    1566             : 
    1567             :   // reset FIFO flag
    1568           0 :   this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_2, RADIOLIB_SX127X_FLAG_FIFO_OVERRUN);
    1569             : 
    1570             :   // set packet configuration
    1571           0 :   state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_PACKET_VARIABLE | RADIOLIB_SX127X_DC_FREE_NONE | RADIOLIB_SX127X_CRC_ON | RADIOLIB_SX127X_CRC_AUTOCLEAR_ON | RADIOLIB_SX127X_ADDRESS_FILTERING_OFF | RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT, 7, 0);
    1572           0 :   state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_2, RADIOLIB_SX127X_DATA_MODE_PACKET | RADIOLIB_SX127X_IO_HOME_OFF, 6, 5);
    1573           0 :   RADIOLIB_ASSERT(state);
    1574             : 
    1575             :   // set FIFO threshold
    1576           0 :   state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_TX_START_FIFO_NOT_EMPTY, 7, 7);
    1577           0 :   state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_FIFO_THRESH, 5, 0);
    1578           0 :   RADIOLIB_ASSERT(state);
    1579             : 
    1580             :   // disable Rx timeouts
    1581           0 :   state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_TIMEOUT_1, RADIOLIB_SX127X_TIMEOUT_RX_RSSI_OFF);
    1582           0 :   state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_TIMEOUT_2, RADIOLIB_SX127X_TIMEOUT_RX_PREAMBLE_OFF);
    1583           0 :   state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_TIMEOUT_3, RADIOLIB_SX127X_TIMEOUT_SIGNAL_SYNC_OFF);
    1584           0 :   RADIOLIB_ASSERT(state);
    1585             : 
    1586             :   // enable preamble detector
    1587           0 :   state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_DETECT, RADIOLIB_SX127X_PREAMBLE_DETECTOR_ON | RADIOLIB_SX127X_PREAMBLE_DETECTOR_2_BYTE | RADIOLIB_SX127X_PREAMBLE_DETECTOR_TOL);
    1588             : 
    1589           0 :   return(state);
    1590             : }
    1591             : 
    1592           0 : int16_t SX127x::setPacketMode(uint8_t mode, uint8_t len) {
    1593             :   // check packet length
    1594           0 :   if(len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK) {
    1595           0 :     return(RADIOLIB_ERR_PACKET_TOO_LONG);
    1596             :   }
    1597             : 
    1598             :   // check active modem
    1599           0 :   if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
    1600           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1601             :   }
    1602             : 
    1603             :   // set to fixed packet length
    1604           0 :   int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, mode, 7, 7);
    1605           0 :   RADIOLIB_ASSERT(state);
    1606             : 
    1607             :   // set length to register
    1608           0 :   state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK, len);
    1609           0 :   RADIOLIB_ASSERT(state);
    1610             : 
    1611             :   // update cached value
    1612           0 :   this->packetLengthConfig = mode;
    1613           0 :   return(state);
    1614             : }
    1615             : 
    1616           0 : bool SX127x::findChip(const uint8_t* vers, uint8_t num) {
    1617           0 :   uint8_t i = 0;
    1618           0 :   bool flagFound = false;
    1619           0 :   while((i < 10) && !flagFound) {
    1620             :     // reset the module
    1621           0 :     reset();
    1622             : 
    1623             :     // check version register
    1624           0 :     int16_t version = getChipVersion();
    1625           0 :     for(uint8_t j = 0; j < num; j++) {
    1626           0 :       if(version == vers[j]) {
    1627           0 :         flagFound = true;
    1628           0 :         break;
    1629             :       }
    1630             :     }
    1631             : 
    1632           0 :     if(!flagFound) {
    1633             :       RADIOLIB_DEBUG_BASIC_PRINTLN("SX127x not found! (%d of 10 tries) RADIOLIB_SX127X_REG_VERSION == 0x%04X", i + 1, version);
    1634           0 :       this->mod->hal->delay(10);
    1635           0 :       i++;
    1636             :     }
    1637             :   
    1638             :   }
    1639             : 
    1640           0 :   return(flagFound);
    1641             : }
    1642             : 
    1643         126 : int16_t SX127x::setMode(uint8_t mode) {
    1644         126 :   uint8_t checkMask = 0xFF;
    1645         126 :   if((getActiveModem() == RADIOLIB_SX127X_FSK_OOK) && (mode == RADIOLIB_SX127X_RX)) {
    1646             :     // disable checking of RX bit in FSK RX mode, as it sometimes seem to fail (#276)
    1647           0 :     checkMask = 0xFE;
    1648             :   }
    1649         126 :   return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, mode, 2, 0, 5, checkMask));
    1650             : }
    1651             : 
    1652         328 : int16_t SX127x::getActiveModem() {
    1653         328 :   return(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_OP_MODE, 7, 7));
    1654             : }
    1655             : 
    1656           0 : int16_t SX127x::setActiveModem(uint8_t modem) {
    1657             :   // set mode to SLEEP
    1658           0 :   int16_t state = setMode(RADIOLIB_SX127X_SLEEP);
    1659             : 
    1660             :   // set modem
    1661             :   // low frequency access (bit 3) automatically resets when switching modem
    1662             :   // so we exclude it from the check 
    1663           0 :   state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, modem, 7, 7, 5, 0xF7);
    1664             : 
    1665             :   // set mode to STANDBY
    1666           0 :   state |= setMode(RADIOLIB_SX127X_STANDBY);
    1667           0 :   return(state);
    1668             : }
    1669             : 
    1670           6 : void SX127x::clearFIFO(size_t count) {
    1671        1530 :   while(count) {
    1672        1524 :     this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_FIFO);
    1673        1524 :     count--;
    1674             :   }
    1675           6 : }
    1676             : 
    1677           6 : int16_t SX127x::invertIQ(bool enable) {
    1678             :   // check active modem
    1679           6 :   if(getActiveModem() != RADIOLIB_SX127X_LORA) {
    1680           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1681             :   }
    1682             : 
    1683             :   // Tx path inversion is swapped, because it seems that setting it according to the datsheet
    1684             :   // will actually lead to the wrong inversion. See https://github.com/jgromes/RadioLib/issues/778
    1685             :   int16_t state;
    1686           6 :   if(enable) {
    1687           0 :     state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_RXPATH_ON, 6, 6);
    1688           0 :     state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_TXPATH_OFF, 0, 0);
    1689           0 :     state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ2, RADIOLIB_SX127X_IQ2_ENABLE);
    1690             :   } else {
    1691           6 :     state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_RXPATH_OFF, 6, 6);
    1692           6 :     state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_TXPATH_ON, 0, 0);
    1693           6 :     state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ2, RADIOLIB_SX127X_IQ2_DISABLE);
    1694             :   }
    1695             : 
    1696           6 :   return(state);
    1697             : }
    1698             : 
    1699          18 : int16_t SX127x::getModem(ModemType_t* modem) {
    1700          18 :   RADIOLIB_ASSERT_PTR(modem);
    1701             : 
    1702          18 :   int16_t packetType = getActiveModem();
    1703          18 :   switch(packetType) {
    1704          18 :     case(RADIOLIB_SX127X_LORA):
    1705          18 :       *modem = ModemType_t::RADIOLIB_MODEM_LORA;
    1706          18 :       return(RADIOLIB_ERR_NONE);
    1707           0 :     case(RADIOLIB_SX127X_FSK_OOK):
    1708           0 :       *modem = ModemType_t::RADIOLIB_MODEM_FSK;
    1709           0 :       return(RADIOLIB_ERR_NONE);
    1710             :   }
    1711             :   
    1712           0 :   return(RADIOLIB_ERR_WRONG_MODEM);
    1713             : }
    1714             : 
    1715          24 : int16_t SX127x::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) {
    1716             :   int16_t state;
    1717             : 
    1718          24 :   switch(mode) {
    1719          18 :     case(RADIOLIB_RADIO_MODE_RX): {
    1720          18 :       this->rxMode = RADIOLIB_SX127X_RXCONTINUOUS;
    1721             : 
    1722             :       // set mode to standby
    1723          18 :       state = setMode(RADIOLIB_SX127X_STANDBY);
    1724          18 :       RADIOLIB_ASSERT(state);
    1725             : 
    1726             :       // set DIO pin mapping
    1727           0 :       state = this->setIrqFlags(getIrqMapped(cfg->receive.irqFlags & cfg->receive.irqMask));
    1728           0 :       RADIOLIB_ASSERT(state);
    1729             : 
    1730           0 :       int16_t modem = getActiveModem();
    1731           0 :       if(modem == RADIOLIB_SX127X_LORA) {
    1732             :         // if max(uint32_t) is used, revert to RxContinuous
    1733           0 :         if(cfg->receive.timeout == 0xFFFFFFFF) {
    1734           0 :           cfg->receive.timeout = 0;
    1735             :         }
    1736           0 :         if(cfg->receive.timeout != 0) {
    1737             :           // for non-zero timeout value, change mode to Rx single and set the timeout
    1738           0 :           this->rxMode = RADIOLIB_SX127X_RXSINGLE;
    1739           0 :           uint8_t msb_sym = (cfg->receive.timeout > 0x3FF) ? 0x3 : (uint8_t)(cfg->receive.timeout >> 8);
    1740           0 :           uint8_t lsb_sym = (cfg->receive.timeout > 0x3FF) ? 0xFF : (uint8_t)(cfg->receive.timeout & 0xFF);
    1741           0 :           state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, msb_sym, 1, 0);
    1742           0 :           state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYMB_TIMEOUT_LSB, lsb_sym);
    1743           0 :           RADIOLIB_ASSERT(state);
    1744             :         }
    1745             : 
    1746             :         // in FHSS mode, enable channel change interrupt
    1747           0 :         if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) {
    1748           0 :           state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 5, 4);
    1749             :         }
    1750             : 
    1751             :         // in implicit header mode, use the provided length if it is nonzero
    1752             :         // otherwise we trust the user has previously set the payload length manually
    1753           0 :         if((this->implicitHdr) && (cfg->receive.len != 0)) {
    1754           0 :           state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, cfg->receive.len);
    1755           0 :           this->packetLength = cfg->receive.len;
    1756             :         }
    1757             : 
    1758             :         // apply fixes to errata
    1759             :         RADIOLIB_ERRATA_SX127X(true);
    1760             : 
    1761             :         // clear interrupt flags
    1762           0 :         clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
    1763             : 
    1764             :         // set FIFO pointers
    1765           0 :         state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_RX_BASE_ADDR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX);
    1766           0 :         state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX);
    1767           0 :         RADIOLIB_ASSERT(state);
    1768             : 
    1769           0 :       } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
    1770             :         // for non-zero timeout value, emulate timeout
    1771           0 :         state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_TIMEOUT_3, cfg->receive.timeout & 0xFF);
    1772           0 :         RADIOLIB_ASSERT(state);
    1773             : 
    1774             :         // clear interrupt flags
    1775           0 :         clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
    1776             : 
    1777             :         // FSK modem does not actually distinguish between Rx single and continuous mode,
    1778             :         // Rx single is emulated using timeout
    1779           0 :         this->rxMode = RADIOLIB_SX127X_RX;
    1780             :       }
    1781           0 :     } break;
    1782             :   
    1783           6 :     case(RADIOLIB_RADIO_MODE_TX): {
    1784             :       // set mode to standby
    1785           6 :       state = setMode(RADIOLIB_SX127X_STANDBY);
    1786             : 
    1787           6 :       int16_t modem = getActiveModem();
    1788           6 :       if(modem == RADIOLIB_SX127X_LORA) {
    1789             :         // check packet length
    1790           6 :         if(cfg->transmit.len > RADIOLIB_SX127X_MAX_PACKET_LENGTH) {
    1791           0 :           return(RADIOLIB_ERR_PACKET_TOO_LONG);
    1792             :         }
    1793             : 
    1794             :         // set DIO mapping
    1795           6 :         if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) {
    1796           6 :           this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_TX_DONE | RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 7, 4);
    1797             :         } else {
    1798           0 :           this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_TX_DONE, 7, 6);
    1799             :         }
    1800             : 
    1801             :         // apply fixes to errata
    1802             :         RADIOLIB_ERRATA_SX127X(false);
    1803             : 
    1804             :         // clear interrupt flags
    1805           6 :         clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
    1806             : 
    1807             :         // set packet length
    1808           6 :         state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, cfg->transmit.len);
    1809             : 
    1810             :         // set FIFO pointers
    1811           6 :         state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_TX_BASE_ADDR, RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX);
    1812           6 :         state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX);
    1813             : 
    1814           0 :       } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
    1815             :         // clear interrupt flags
    1816           0 :         clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
    1817             : 
    1818             :         // set DIO mapping
    1819           0 :         if(cfg->transmit.len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK) {
    1820           0 :           this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_PACK_FIFO_EMPTY, 5, 4);
    1821             :         } else {
    1822           0 :           this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT, 7, 6);
    1823             :         }
    1824             : 
    1825             :         // set packet length - increased by 1 when address filter is enabled
    1826           0 :         uint8_t filter = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 2, 1);
    1827           0 :         if(this->packetLengthConfig == RADIOLIB_SX127X_PACKET_VARIABLE) {
    1828           0 :           if((filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE) || (filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) {
    1829           0 :             this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, cfg->transmit.len + 1);
    1830           0 :             this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, cfg->transmit.addr);
    1831             :           } else {
    1832           0 :             this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, cfg->transmit.len);
    1833             :           }
    1834             :         
    1835             :         }
    1836             :       
    1837             :       }
    1838             : 
    1839             :       // write packet to FIFO
    1840           6 :       size_t packetLen = cfg->transmit.len;
    1841           6 :       if((modem == RADIOLIB_SX127X_FSK_OOK) && (cfg->transmit.len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK)) {
    1842           0 :         packetLen = RADIOLIB_SX127X_FIFO_THRESH - 1;
    1843           0 :         this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_TX_START_FIFO_NOT_EMPTY, 7, 7);
    1844             :       }
    1845           6 :       this->mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_FIFO, cfg->transmit.data, packetLen);
    1846           6 :     } break;
    1847             :     
    1848           0 :     default:
    1849           0 :       return(RADIOLIB_ERR_UNSUPPORTED);
    1850             :   }
    1851             : 
    1852           6 :   this->stagedMode = mode;
    1853           6 :   return(state);
    1854             : }
    1855             : 
    1856           6 : int16_t SX127x::launchMode() {
    1857             :   int16_t state;
    1858           6 :   switch(this->stagedMode) {
    1859           6 :     case(RADIOLIB_RADIO_MODE_RX): {
    1860           6 :       this->mod->setRfSwitchState(Module::MODE_RX);
    1861           6 :       state = setMode(this->rxMode);
    1862           6 :       RADIOLIB_ASSERT(state);
    1863           0 :     } break;
    1864             :   
    1865           0 :     case(RADIOLIB_RADIO_MODE_TX): {
    1866           0 :       this->mod->setRfSwitchState(Module::MODE_TX);
    1867           0 :       state = setMode(RADIOLIB_SX127X_TX);
    1868           0 :       RADIOLIB_ASSERT(state);
    1869           0 :     } break;
    1870             :     
    1871           0 :     default:
    1872           0 :       return(RADIOLIB_ERR_UNSUPPORTED);
    1873             :   }
    1874             : 
    1875           0 :   this->stagedMode = RADIOLIB_RADIO_MODE_NONE;
    1876           0 :   return(state);
    1877             : }
    1878             : 
    1879             : #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE
    1880           0 : void SX127x::setDirectAction(void (*func)(void)) {
    1881           0 :   setDio1Action(func, this->mod->hal->GpioInterruptRising);
    1882           0 : }
    1883             : 
    1884           0 : void SX127x::readBit(uint32_t pin) {
    1885           0 :   updateDirectBuffer((uint8_t)this->mod->hal->digitalRead(pin));
    1886           0 : }
    1887             : #endif
    1888             : 
    1889           0 : int16_t SX127x::setFHSSHoppingPeriod(uint8_t freqHoppingPeriod) {
    1890           0 :   return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, freqHoppingPeriod));
    1891             : }
    1892             : 
    1893           0 : uint8_t SX127x::getFHSSHoppingPeriod(void) {
    1894           0 :   return(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD));
    1895             : }
    1896             : 
    1897           0 : uint8_t SX127x::getFHSSChannel(void) {
    1898           0 :   return(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 5, 0));
    1899             : }
    1900             : 
    1901           0 : void SX127x::clearFHSSInt(void) {
    1902           0 :   int16_t modem = getActiveModem();
    1903           0 :   if(modem == RADIOLIB_SX127X_LORA) {
    1904           0 :     this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL);
    1905           0 :   } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
    1906           0 :     return; //These are not the interrupts you are looking for
    1907             :   }
    1908             : }
    1909             : 
    1910           0 : int16_t SX127x::setDIOMapping(uint32_t pin, uint32_t value) {
    1911           0 :   if (pin > 5)
    1912           0 :     return RADIOLIB_ERR_INVALID_DIO_PIN;
    1913             : 
    1914           0 :   if (pin < 4)
    1915           0 :     return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, value, 7 - 2 * pin, 6 - 2 * pin));
    1916             :   else
    1917           0 :     return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_2, value, 15 - 2 * pin, 14 - 2 * pin));
    1918             : }
    1919             : 
    1920           0 : int16_t SX127x::setDIOPreambleDetect(bool usePreambleDetect) {
    1921           0 :   return this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_2, (usePreambleDetect) ? RADIOLIB_SX127X_DIO_MAP_PREAMBLE_DETECT : RADIOLIB_SX127X_DIO_MAP_RSSI, 0, 0);
    1922             : }
    1923             : 
    1924           6 : float SX127x::getRSSI(bool packet, bool skipReceive, int16_t offset) {
    1925           6 :   if(getActiveModem() == RADIOLIB_SX127X_LORA) {
    1926           6 :     if(packet) {
    1927             :       // LoRa packet mode, get RSSI of the last packet
    1928           6 :       float lastPacketRSSI = offset + this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PKT_RSSI_VALUE);
    1929             : 
    1930             :       // spread-spectrum modulation signal can be received below noise floor
    1931             :       // check last packet SNR and if it's less than 0, add it to reported RSSI to get the correct value
    1932           6 :       float lastPacketSNR = SX127x::getSNR();
    1933           6 :       if(lastPacketSNR < 0.0f) {
    1934           6 :         lastPacketRSSI += lastPacketSNR;
    1935             :       }
    1936           6 :       return(lastPacketRSSI);
    1937             : 
    1938             :     } else {
    1939             :       // LoRa instant, get current RSSI
    1940           0 :       float currentRSSI = offset + this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE);
    1941           0 :       return(currentRSSI);
    1942             :     }
    1943             :   
    1944             :   } else {
    1945             :     // for FSK, there is no packet RSSI
    1946             : 
    1947             :     // enable listen mode
    1948           0 :     if(!skipReceive) {
    1949           0 :       startReceive();
    1950             :     }
    1951             : 
    1952             :     // read the value for FSK
    1953           0 :     float rssi = (float)this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE_FSK) / -2.0f;
    1954             : 
    1955             :     // set mode back to standby
    1956           0 :     if(!skipReceive) {
    1957           0 :       standby();
    1958             :     }
    1959             : 
    1960             :     // return the value
    1961           0 :     return(rssi);
    1962             :   }
    1963             : }
    1964             : 
    1965           0 : int16_t SX127x::setHeaderType(uint8_t headerType, uint8_t bitIndex, size_t len) {
    1966             :   // check active modem
    1967           0 :   if(getActiveModem() != RADIOLIB_SX127X_LORA) {
    1968           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1969             :   }
    1970             : 
    1971             :   // set requested packet mode
    1972           0 :   int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, headerType, bitIndex, bitIndex);
    1973           0 :   RADIOLIB_ASSERT(state);
    1974             : 
    1975             :   // set length to register
    1976           0 :   state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len);
    1977           0 :   RADIOLIB_ASSERT(state);
    1978             : 
    1979             :   // update cached value
    1980           0 :   SX127x::packetLength = len;
    1981             : 
    1982           0 :   return(state);
    1983             : }
    1984             : 
    1985           0 : int16_t SX127x::setLowBatteryThreshold(int8_t level, uint32_t pin) {
    1986             :   // check disable
    1987           0 :   if(level < 0) {
    1988           0 :     return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LOW_BAT, RADIOLIB_SX127X_LOW_BAT_OFF, 3, 3));
    1989             :   }
    1990             : 
    1991             :   // enable detector and set the threshold
    1992           0 :   int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LOW_BAT, RADIOLIB_SX127X_LOW_BAT_ON | level, 3, 0);
    1993           0 :   RADIOLIB_ASSERT(state);
    1994             : 
    1995             :   // set DIO mapping
    1996           0 :   switch(pin) {
    1997           0 :     case(0):
    1998           0 :       return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_TEMP_CHANGE_LOW_BAT, 7, 6));
    1999           0 :     case(3):
    2000           0 :       return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO3_CONT_TEMP_CHANGE_LOW_BAT, 1, 0));
    2001           0 :     case(4):
    2002           0 :       return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_2, RADIOLIB_SX127X_DIO4_PACK_TEMP_CHANGE_LOW_BAT, 7, 6));
    2003             :   }
    2004           0 :   return(RADIOLIB_ERR_INVALID_DIO_PIN);
    2005             : }
    2006             : 
    2007             : #endif

Generated by: LCOV version 1.14