LCOV - code coverage report
Current view: top level - src/modules/SX127x - SX127x.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 19 1023 1.9 %
Date: 2025-10-24 15:14:50 Functions: 3 111 2.7 %

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

Generated by: LCOV version 1.14