LCOV - code coverage report
Current view: top level - src/modules/SX127x - SX127x.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 244 1053 23.2 %
Date: 2026-11-08 19:43:08 Functions: 45 109 41.3 %

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

Generated by: LCOV version 1.14