LCOV - code coverage report
Current view: top level - src/modules/SX128x - SX128x.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 264 1018 25.9 %
Date: 2026-11-08 19:43:08 Functions: 58 102 56.9 %

          Line data    Source code
       1             : #include "SX128x.h"
       2             : #include <math.h>
       3             : #include <string.h>
       4             : #if !RADIOLIB_EXCLUDE_SX128X
       5             : 
       6          13 : SX128x::SX128x(Module* mod) : PhysicalLayer() {
       7          13 :   this->freqStep = RADIOLIB_SX128X_FREQUENCY_STEP_SIZE;
       8          13 :   this->maxPacketLength = RADIOLIB_SX128X_MAX_PACKET_LENGTH;
       9          13 :   this->mod = mod;
      10          13 :   this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_SX128X_IRQ_TX_DONE;
      11          13 :   this->irqMap[RADIOLIB_IRQ_RX_DONE] = RADIOLIB_SX128X_IRQ_RX_DONE;
      12          13 :   this->irqMap[RADIOLIB_IRQ_PREAMBLE_DETECTED] = RADIOLIB_SX128X_IRQ_PREAMBLE_DETECTED;
      13          13 :   this->irqMap[RADIOLIB_IRQ_SYNC_WORD_VALID] = RADIOLIB_SX128X_IRQ_SYNC_WORD_VALID;
      14          13 :   this->irqMap[RADIOLIB_IRQ_HEADER_VALID] = RADIOLIB_SX128X_IRQ_HEADER_VALID;
      15          13 :   this->irqMap[RADIOLIB_IRQ_HEADER_ERR] = RADIOLIB_SX128X_IRQ_HEADER_ERROR;
      16          13 :   this->irqMap[RADIOLIB_IRQ_CRC_ERR] = RADIOLIB_SX128X_IRQ_CRC_ERROR;
      17          13 :   this->irqMap[RADIOLIB_IRQ_CAD_DONE] = RADIOLIB_SX128X_IRQ_CAD_DONE;
      18          13 :   this->irqMap[RADIOLIB_IRQ_CAD_DETECTED] = RADIOLIB_SX128X_IRQ_CAD_DETECTED;
      19          13 :   this->irqMap[RADIOLIB_IRQ_TIMEOUT] = RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT;
      20          13 :   this->powerMin = RADIOLIB_SX128X_POUT_MIN;
      21          13 :   this->powerMax = RADIOLIB_SX128X_POUT_MAX;
      22          13 :   this->paSteps = this->powerMax - this->powerMin + 1;
      23          13 : }
      24             : 
      25           0 : int16_t SX128x::begin(const ConfigLoRa_t& cfg) {
      26             :   // initialize LoRa modulation variables
      27           0 :   this->bandwidthHz = cfg.bandwidth;
      28           0 :   this->spreadingFactor = RADIOLIB_SX128X_LORA_SF_9;
      29           0 :   this->codingRateLoRa = RADIOLIB_SX128X_LORA_CR_4_7;
      30             : 
      31             :   // initialize LoRa packet variables
      32           0 :   this->preambleLengthLoRa = cfg.preambleLength;
      33           0 :   this->headerType = RADIOLIB_SX128X_LORA_HEADER_EXPLICIT;
      34           0 :   this->payloadLen = 0xFF;
      35           0 :   this->crcLoRa = RADIOLIB_SX128X_LORA_CRC_ON;
      36             : 
      37             :   // set module properties and perform initial setup
      38           0 :   int16_t state = this->modSetup(RADIOLIB_SX128X_PACKET_TYPE_LORA);
      39           0 :   RADIOLIB_ASSERT(state);
      40             : 
      41             :   // configure publicly accessible settings
      42           0 :   state = setFrequency(cfg.frequency);
      43           0 :   RADIOLIB_ASSERT(state);
      44             : 
      45           0 :   state = setBandwidth(cfg.bandwidth);
      46           0 :   RADIOLIB_ASSERT(state);
      47             : 
      48           0 :   state = setSpreadingFactor(cfg.spreadingFactor);
      49           0 :   RADIOLIB_ASSERT(state);
      50             : 
      51           0 :   state = setCodingRate(cfg.codingRate);
      52           0 :   RADIOLIB_ASSERT(state);
      53             : 
      54           0 :   state = setSyncWord(cfg.syncWord);
      55           0 :   RADIOLIB_ASSERT(state);
      56             : 
      57           0 :   state = setPreambleLength(cfg.preambleLength);
      58           0 :   RADIOLIB_ASSERT(state);
      59             : 
      60           0 :   state = setOutputPower(cfg.power);
      61           0 :   return(state);
      62             : }
      63             : 
      64           0 : int16_t SX128x::beginGFSK(const ConfigFSK_t& cfg) {
      65             :   // initialize GFSK modulation variables
      66           0 :   this->bitRateBps = cfg.bitRate;
      67           0 :   this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4;
      68           0 :   this->modIndexReal = 1.0;
      69           0 :   this->modIndex = RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_00;
      70           0 :   this->shaping = RADIOLIB_SX128X_BLE_GFSK_BT_0_5;
      71             : 
      72             :   // initialize GFSK packet variables
      73           0 :   this->preambleLengthGFSK = cfg.preambleLength;
      74           0 :   this->syncWordLen = 2;
      75           0 :   this->syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1;
      76           0 :   this->crcGFSK = RADIOLIB_SX128X_GFSK_FLRC_CRC_2_BYTE;
      77           0 :   this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON;
      78             : 
      79             :   // set module properties and perform initial setup
      80           0 :   int16_t state = this->modSetup(RADIOLIB_SX128X_PACKET_TYPE_GFSK);
      81           0 :   RADIOLIB_ASSERT(state);
      82             : 
      83             :   // configure publicly accessible settings
      84           0 :   state = setFrequency(cfg.frequency);
      85           0 :   RADIOLIB_ASSERT(state);
      86             : 
      87           0 :   state = setBitRate(cfg.bitRate);
      88           0 :   RADIOLIB_ASSERT(state);
      89             : 
      90           0 :   state = setFrequencyDeviation(cfg.frequencyDeviation);
      91           0 :   RADIOLIB_ASSERT(state);
      92             : 
      93           0 :   state = setOutputPower(cfg.power);
      94           0 :   RADIOLIB_ASSERT(state);
      95             : 
      96           0 :   state = setPreambleLength(cfg.preambleLength);
      97           0 :   RADIOLIB_ASSERT(state);
      98             : 
      99           0 :   state = setDataShaping(RADIOLIB_SHAPING_0_5);
     100           0 :   RADIOLIB_ASSERT(state);
     101             : 
     102             :   // set publicly accessible settings that are not a part of begin method
     103           0 :   uint8_t sync[] = { 0x12, 0xAD };
     104           0 :   state = setSyncWord(sync, 2);
     105           0 :   RADIOLIB_ASSERT(state);
     106             : 
     107           0 :   state = setEncoding(RADIOLIB_ENCODING_NRZ);
     108           0 :   return(state);
     109             : }
     110             : 
     111           0 : int16_t SX128x::beginBLE(const ConfigBLE_t& cfg) {
     112             :   // initialize BLE modulation variables
     113           0 :   this->bitRateBps = cfg.bitRate;
     114           0 :   this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4;
     115           0 :   this->modIndexReal = 1.0;
     116           0 :   this->modIndex = RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_00;
     117           0 :   this->shaping = RADIOLIB_SX128X_BLE_GFSK_BT_0_5;
     118             : 
     119             :   // initialize BLE packet variables
     120           0 :   this->crcGFSK = RADIOLIB_SX128X_BLE_CRC_3_BYTE;
     121           0 :   this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON;
     122             : 
     123             :   // set module properties and perform initial setup
     124           0 :   int16_t state = this->modSetup(RADIOLIB_SX128X_PACKET_TYPE_BLE);
     125           0 :   RADIOLIB_ASSERT(state);
     126             : 
     127             :   // configure publicly accessible settings
     128           0 :   state = setFrequency(cfg.frequency);
     129           0 :   RADIOLIB_ASSERT(state);
     130             : 
     131           0 :   state = setBitRate(cfg.bitRate);
     132           0 :   RADIOLIB_ASSERT(state);
     133             : 
     134           0 :   state = setFrequencyDeviation(cfg.frequencyDeviation);
     135           0 :   RADIOLIB_ASSERT(state);
     136             : 
     137           0 :   state = setOutputPower(cfg.power);
     138           0 :   RADIOLIB_ASSERT(state);
     139             : 
     140           0 :   state = setDataShaping(cfg.dataShaping);
     141           0 :   return(state);
     142             : }
     143             : 
     144           0 : int16_t SX128x::beginFLRC(const ConfigFLRC_t& cfg) {
     145             :   // initialize FLRC modulation variables
     146           0 :   this->bitRateBps = cfg.bitRate;
     147           0 :   this->bitRate = RADIOLIB_SX128X_FLRC_BR_0_650_BW_0_6;
     148           0 :   this->codingRateFLRC = RADIOLIB_SX128X_FLRC_CR_3_4;
     149           0 :   this->shaping = RADIOLIB_SX128X_FLRC_BT_0_5;
     150             : 
     151             :   // initialize FLRC packet variables
     152           0 :   this->preambleLengthGFSK = cfg.preambleLength;
     153           0 :   this->syncWordLen = 2;
     154           0 :   this->syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1;
     155           0 :   this->crcGFSK = RADIOLIB_SX128X_GFSK_FLRC_CRC_2_BYTE;
     156           0 :   this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_OFF;
     157             : 
     158             :   // set module properties and perform initial setup
     159           0 :   int16_t state = this->modSetup(RADIOLIB_SX128X_PACKET_TYPE_FLRC);
     160           0 :   RADIOLIB_ASSERT(state);
     161             : 
     162             :   // configure publicly accessible settings
     163           0 :   state = setFrequency(cfg.frequency);
     164           0 :   RADIOLIB_ASSERT(state);
     165             : 
     166           0 :   state = setBitRate(cfg.bitRate);
     167           0 :   RADIOLIB_ASSERT(state);
     168             : 
     169           0 :   state = setCodingRate(cfg.codingRate);
     170           0 :   RADIOLIB_ASSERT(state);
     171             : 
     172           0 :   state = setOutputPower(cfg.power);
     173           0 :   RADIOLIB_ASSERT(state);
     174             : 
     175           0 :   state = setPreambleLength(cfg.preambleLength);
     176           0 :   RADIOLIB_ASSERT(state);
     177             : 
     178           0 :   state = setDataShaping(cfg.dataShaping);
     179           0 :   RADIOLIB_ASSERT(state);
     180             : 
     181             :   // set publicly accessible settings that are not a part of begin method
     182           0 :   uint8_t sync[] = { 0x2D, 0x01, 0x4B, 0x1D };
     183           0 :   state = setSyncWord(sync, 4);
     184           0 :   return(state);
     185             : }
     186             : 
     187           0 : int16_t SX128x::reset(bool verify) {
     188             :   // run the reset sequence - same as SX126x, as SX128x docs don't seem to mention this
     189           0 :   this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput);
     190           0 :   this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow);
     191           0 :   this->mod->hal->delay(1);
     192           0 :   this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh);
     193             : 
     194             :   // return immediately when verification is disabled
     195           0 :   if(!verify) {
     196           0 :     return(RADIOLIB_ERR_NONE);
     197             :   }
     198             : 
     199             :   // set mode to standby
     200           0 :   RadioLibTime_t start = this->mod->hal->millis();
     201             :   while(true) {
     202             :     // try to set mode to standby
     203             :     // force usage of RC standby here - if this is being called during startup,
     204             :     // and user set standbyXOSC to true with TCXO, this would attempt to use the TCXO
     205           0 :     int16_t state = standby(RADIOLIB_SX128X_STANDBY_RC);
     206           0 :     if(state == RADIOLIB_ERR_NONE) {
     207             :       // standby command successful
     208           0 :       return(RADIOLIB_ERR_NONE);
     209             :     }
     210             : 
     211             :     // standby command failed, check timeout and try again
     212           0 :     if(this->mod->hal->millis() - start >= 3000) {
     213             :       // timed out, possibly incorrect wiring
     214           0 :       return(state);
     215             :     }
     216             : 
     217             :     // wait a bit to not spam the module
     218           0 :     this->mod->hal->delay(10);
     219           0 :   }
     220             : }
     221             : 
     222           3 : int16_t SX128x::transmit(const uint8_t* data, size_t len, uint8_t addr) {
     223             :   // check packet length
     224           3 :   if(this->codingRateLoRa == RADIOLIB_SX128X_LORA_CR_4_8_LI && this->crcLoRa == RADIOLIB_SX128X_LORA_CRC_ON) {
     225             :     // Long Interleaver at CR 4/8 supports up to 253 bytes if CRC is enabled
     226           0 :     if(len > RADIOLIB_SX128X_MAX_PACKET_LENGTH - 2) {
     227           0 :       return(RADIOLIB_ERR_PACKET_TOO_LONG);
     228             :     }
     229           3 :   } else if(len > RADIOLIB_SX128X_MAX_PACKET_LENGTH) {
     230           0 :     return(RADIOLIB_ERR_PACKET_TOO_LONG);
     231             :   }
     232             : 
     233             :   // check active modem
     234           3 :   uint8_t modem = getPacketType();
     235           3 :   if(modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING) {
     236           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     237             :   }
     238             : 
     239             :   // set mode to standby
     240           3 :   int16_t state = standby();
     241           3 :   RADIOLIB_ASSERT(state);
     242             : 
     243             :   // calculate timeout in ms (5ms + 500 % of expected time-on-air)
     244           0 :   RadioLibTime_t timeout = 5 + (getTimeOnAir(len) * 5) / 1000;
     245             :   RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout);
     246             : 
     247             :   // start transmission
     248           0 :   state = startTransmit(data, len, addr);
     249           0 :   RADIOLIB_ASSERT(state);
     250             : 
     251             :   // wait for packet transmission or timeout
     252           0 :   RadioLibTime_t start = this->mod->hal->millis();
     253           0 :   while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
     254           0 :     this->mod->hal->yield();
     255           0 :     if(this->mod->hal->millis() - start > timeout) {
     256           0 :       finishTransmit();
     257           0 :       return(RADIOLIB_ERR_TX_TIMEOUT);
     258             :     }
     259             :   }
     260             : 
     261           0 :   return(finishTransmit());
     262             : }
     263             : 
     264           3 : int16_t SX128x::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) {
     265             :   // check active modem
     266           3 :   uint8_t modem = getPacketType();
     267           3 :   if(modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING) {
     268           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     269             :   }
     270             : 
     271             :   // set mode to standby
     272           3 :   int16_t state = standby();
     273           3 :   RADIOLIB_ASSERT(state);
     274             : 
     275           0 :   RadioLibTime_t timeoutInternal = timeout;
     276           0 :   if(!timeoutInternal) {
     277             :     // calculate timeout (500 % of expected time-one-air)
     278           0 :     size_t maxLen = len;
     279           0 :     if(len == 0) { maxLen = RADIOLIB_SX128X_MAX_PACKET_LENGTH; }
     280           0 :     timeoutInternal = (getTimeOnAir(maxLen) * 5) / 1000;
     281             :   }
     282             : 
     283             :   RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeoutInternal);
     284             : 
     285             :   // start reception
     286           0 :   uint32_t timeoutValue = timeoutInternal / 4UL;
     287           0 :   state = startReceive(timeoutValue);
     288           0 :   RADIOLIB_ASSERT(state);
     289             : 
     290             :   // wait for packet reception or timeout
     291           0 :   bool softTimeout = false;
     292           0 :   RadioLibTime_t start = this->mod->hal->millis();
     293           0 :   while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
     294           0 :     this->mod->hal->yield();
     295             :     // safety check, the timeout should be done by the radio
     296           0 :     if(this->mod->hal->millis() - start > timeoutInternal) {
     297           0 :       softTimeout = true;
     298           0 :       break;
     299             :     }
     300             :   }
     301             : 
     302             :   // if it was a timeout, this will return an error code
     303           0 :   state = standby();
     304           0 :   if((state != RADIOLIB_ERR_NONE) && (state != RADIOLIB_ERR_SPI_CMD_TIMEOUT)) {
     305           0 :     return(state);
     306             :   }
     307             : 
     308             :   // check whether this was a timeout or not
     309           0 :   if(softTimeout || (getIrqStatus() & this->irqMap[RADIOLIB_IRQ_TIMEOUT])) {
     310           0 :     (void)finishReceive();
     311           0 :     return(RADIOLIB_ERR_RX_TIMEOUT);
     312             :   }
     313             : 
     314             :   // read the received data
     315           0 :   return(readData(data, len));
     316             : }
     317             : 
     318           3 : int16_t SX128x::transmitDirect(uint32_t frf) {
     319             :   // set RF switch (if present)
     320           3 :   this->mod->setRfSwitchState(Module::MODE_TX);
     321             : 
     322             :   // user requested to start transmitting immediately (required for RTTY)
     323           3 :   int16_t state = RADIOLIB_ERR_NONE;
     324           3 :   if(frf != 0) {
     325           0 :     state = setRfFrequency(frf);
     326             :   }
     327           3 :   RADIOLIB_ASSERT(state);
     328             : 
     329             :   // start transmitting
     330           3 :   return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_TX_CONTINUOUS_WAVE, NULL, 0));
     331             : }
     332             : 
     333           3 : int16_t SX128x::receiveDirect() {
     334             :   // set RF switch (if present)
     335           3 :   this->mod->setRfSwitchState(Module::MODE_RX);
     336             : 
     337             :   // SX128x is unable to output received data directly
     338           3 :   return(RADIOLIB_ERR_UNKNOWN);
     339             : }
     340             : 
     341           3 : int16_t SX128x::scanChannel() {
     342           3 :   ChannelScanConfig_t cfg = {
     343             :     .cad = {
     344             :       .symNum = RADIOLIB_SX128X_CAD_PARAM_DEFAULT,
     345             :       .detPeak = 0,
     346             :       .detMin = 0,
     347             :       .exitMode = 0,
     348             :       .rxTimeout = 0,
     349             :       .rxSymbols = 0,
     350             :       .irqFlags = RADIOLIB_IRQ_CAD_DEFAULT_FLAGS,
     351             :       .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK,
     352             :     },
     353             :   };
     354           6 :   return(this->scanChannel(cfg));
     355             : }
     356             : 
     357           6 : int16_t SX128x::scanChannel(const ChannelScanConfig_t &cfg) {
     358             :   // set mode to CAD
     359           6 :   int16_t state = startChannelScan(cfg);
     360           6 :   RADIOLIB_ASSERT(state);
     361             : 
     362             :   // wait for channel activity detected or timeout
     363           0 :   while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
     364           0 :     this->mod->hal->yield();
     365             :   }
     366             : 
     367             :   // check CAD result
     368           0 :   return(getChannelScanResult());
     369             : }
     370             : 
     371           3 : int16_t SX128x::sleep() {
     372           3 :   return(SX128x::sleep(true));
     373             : }
     374             : 
     375           3 : int16_t SX128x::sleep(bool retainConfig) {
     376             :   // set RF switch (if present)
     377           3 :   this->mod->setRfSwitchState(Module::MODE_IDLE);
     378             : 
     379           3 :   uint8_t sleepConfig = RADIOLIB_SX128X_SLEEP_DATA_BUFFER_RETAIN | RADIOLIB_SX128X_SLEEP_DATA_RAM_RETAIN;
     380           3 :   if(!retainConfig) {
     381           0 :     sleepConfig = RADIOLIB_SX128X_SLEEP_DATA_BUFFER_FLUSH | RADIOLIB_SX128X_SLEEP_DATA_RAM_FLUSH;
     382             :   }
     383           3 :   int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SAVE_CONTEXT, NULL, 0, false, false);
     384           3 :   RADIOLIB_ASSERT(state);
     385           0 :   state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_SLEEP, &sleepConfig, 1, false, false);
     386             : 
     387             :   // wait for SX128x to safely enter sleep mode
     388           0 :   this->mod->hal->delay(1);
     389             : 
     390           0 :   return(state);
     391             : }
     392             : 
     393          15 : int16_t SX128x::standby() {
     394          15 :   return(SX128x::standby(this->standbyXOSC ? RADIOLIB_SX128X_STANDBY_XOSC : RADIOLIB_SX128X_STANDBY_RC));
     395             : }
     396             : 
     397          18 : int16_t SX128x::standby(uint8_t mode) {
     398          18 :   return(SX128x::standby(mode, true));
     399             : }
     400             : 
     401          18 : int16_t SX128x::standby(uint8_t mode, bool wakeup) {
     402             :   // set RF switch (if present)
     403          18 :   this->mod->setRfSwitchState(Module::MODE_IDLE);
     404             : 
     405          18 :   if(wakeup) {
     406             :     // send a NOP command - this pulls the NSS low to exit the sleep mode,
     407             :     // while preventing interference with possible other SPI transactions
     408          18 :     (void)this->mod->SPIwriteStream((uint16_t)RADIOLIB_SX128X_CMD_NOP, NULL, 0, false, false);
     409             :   }
     410             : 
     411          18 :   const uint8_t data[] = { mode };
     412          36 :   return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_STANDBY, data, 1));
     413             : }
     414             : 
     415           0 : void SX128x::setDio1Action(void (*func)(void)) {
     416           0 :   this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptRising);
     417           0 : }
     418             : 
     419           0 : void SX128x::clearDio1Action() {
     420           0 :   this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()));
     421           0 : }
     422             : 
     423           3 : int16_t SX128x::startReceive() {
     424           3 :   return(this->startReceive(RADIOLIB_SX128X_RX_TIMEOUT_INF, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0));
     425             : }
     426             : 
     427           3 : int16_t SX128x::readData(uint8_t* data, size_t len) {
     428             :   // check active modem
     429           3 :   if(getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_RANGING) {
     430           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
     431             :   }
     432             : 
     433             :   // set mode to standby
     434           3 :   int16_t state = standby();
     435           3 :   RADIOLIB_ASSERT(state);
     436             : 
     437             :   // check integrity CRC
     438           0 :   uint16_t irq = getIrqStatus();
     439           0 :   int16_t crcState = RADIOLIB_ERR_NONE;
     440             :   // Report CRC mismatch when there's a payload CRC error, or a header error and no valid header (to avoid false alarm from previous packet)
     441           0 :   if((irq & RADIOLIB_SX128X_IRQ_CRC_ERROR) || ((irq & RADIOLIB_SX128X_IRQ_HEADER_ERROR) && !(irq & RADIOLIB_SX128X_IRQ_HEADER_VALID))) {
     442           0 :     crcState = RADIOLIB_ERR_CRC_MISMATCH;
     443             :   }
     444             : 
     445             :   // get packet length and Rx buffer offset
     446           0 :   uint8_t offset = 0;
     447           0 :   size_t length = getPacketLength(true, &offset);
     448           0 :   if((len != 0) && (len < length)) {
     449             :     // user requested less data than we got, only return what was requested
     450           0 :     length = len;
     451             :   }
     452             : 
     453             :   // read packet data starting at offset 
     454           0 :   state = readBuffer(data, length, offset);
     455           0 :   RADIOLIB_ASSERT(state);
     456             : 
     457             :   // clear interrupt flags
     458           0 :   state = clearIrqStatus();
     459             : 
     460             :   // check if CRC failed - this is done after reading data to give user the option to keep them
     461           0 :   RADIOLIB_ASSERT(crcState);
     462             : 
     463           0 :   return(state);
     464             : }
     465             : 
     466           3 : int16_t SX128x::finishReceive() {
     467             :   // set mode to standby to disable RF switch
     468           3 :   int16_t state = standby();
     469           3 :   RADIOLIB_ASSERT(state);
     470             : 
     471             :   // clear interrupt flags
     472           0 :   return(clearIrqStatus());
     473             : }
     474             : 
     475           3 : uint32_t SX128x::getIrqFlags() {
     476           3 :   return((uint32_t)this->getIrqStatus());
     477             : }
     478             : 
     479           3 : int16_t SX128x::setIrqFlags(uint32_t irq) {
     480           3 :   return(this->setDioIrqParams(irq, irq));
     481             : }
     482             : 
     483           6 : int16_t SX128x::clearIrqFlags(uint32_t irq) {
     484           6 :   return(this->clearIrqStatus(irq));
     485             : }
     486             : 
     487           3 : int16_t SX128x::startChannelScan() {
     488           3 :   ChannelScanConfig_t cfg = {
     489             :     .cad = {
     490             :       .symNum = RADIOLIB_SX128X_CAD_PARAM_DEFAULT,
     491             :       .detPeak = 0,
     492             :       .detMin = 0,
     493             :       .exitMode = 0,
     494             :       .rxTimeout = 0,
     495             :       .rxSymbols = 0,
     496             :       .irqFlags = RADIOLIB_IRQ_CAD_DEFAULT_FLAGS,
     497             :       .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK,
     498             :     },
     499             :   };
     500           6 :   return(this->startChannelScan(cfg));
     501             : }
     502             : 
     503          12 : int16_t SX128x::startChannelScan(const ChannelScanConfig_t &cfg) {
     504             :   // check active modem
     505          12 :   if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) {
     506          12 :     return(RADIOLIB_ERR_WRONG_MODEM);
     507             :   }
     508             : 
     509             :   // set mode to standby
     510           0 :   int16_t state = standby();
     511           0 :   RADIOLIB_ASSERT(state);
     512             : 
     513             :   // set DIO pin mapping
     514           0 :   state = setDioIrqParams(getIrqMapped(cfg.cad.irqFlags), getIrqMapped(cfg.cad.irqMask));
     515           0 :   RADIOLIB_ASSERT(state);
     516             : 
     517             :   // clear interrupt flags
     518           0 :   state = clearIrqStatus();
     519           0 :   RADIOLIB_ASSERT(state);
     520             : 
     521             :   // set RF switch (if present)
     522           0 :   this->mod->setRfSwitchState(Module::MODE_RX);
     523             : 
     524             :   // set mode to CAD
     525           0 :   return(setCad(cfg.cad.symNum));
     526             : }
     527             : 
     528           3 : int16_t SX128x::getChannelScanResult() {
     529             :   // check active modem
     530           3 :   if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) {
     531           3 :     return(RADIOLIB_ERR_WRONG_MODEM);
     532             :   }
     533             : 
     534             :   // check CAD result
     535           0 :   uint16_t cadResult = getIrqStatus();
     536           0 :   int16_t state = RADIOLIB_ERR_UNKNOWN;
     537           0 :   if(cadResult & RADIOLIB_SX128X_IRQ_CAD_DETECTED) {
     538             :     // detected some LoRa activity
     539           0 :     state = RADIOLIB_LORA_DETECTED;
     540           0 :   } else if(cadResult & RADIOLIB_SX128X_IRQ_CAD_DONE) {
     541             :     // channel is free
     542           0 :     state = RADIOLIB_CHANNEL_FREE;
     543             :   }
     544             : 
     545           0 :   clearIrqStatus();
     546           0 :   return(state);
     547             : }
     548             : 
     549           3 : int16_t SX128x::setFrequency(uint32_t freq) {
     550           3 :   RADIOLIB_CHECK_RANGE(freq, RADIOLIB_UNIT_MEGA(2400), RADIOLIB_UNIT_MEGA(2500), RADIOLIB_ERR_INVALID_FREQUENCY);
     551             : 
     552             :   // calculate raw value
     553           0 :   uint32_t frf = ((uint64_t)freq * (uint64_t)((uint64_t)1 << RADIOLIB_SX128X_DIV_EXPONENT)) / RADIOLIB_UNIT_MEGA(RADIOLIB_SX128X_CRYSTAL_FREQ);
     554           0 :   return(setRfFrequency(frf));
     555             : }
     556             : 
     557           3 : int16_t SX128x::setBandwidth(uint32_t bw) {
     558             :   // check active modem
     559           3 :   uint8_t modem = getPacketType();
     560           3 :   if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) {
     561             :     // check range for LoRa
     562           0 :     RADIOLIB_CHECK_RANGE(bw, 203125, 1625000, RADIOLIB_ERR_INVALID_BANDWIDTH);
     563           3 :   } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING) {
     564             :     // check range for ranging
     565           0 :     RADIOLIB_CHECK_RANGE(bw, 406250, 1625000, RADIOLIB_ERR_INVALID_BANDWIDTH);
     566             :   } else {
     567           3 :     return(RADIOLIB_ERR_WRONG_MODEM);
     568             :   }
     569             : 
     570           0 :   switch(bw) {
     571           0 :     case(203125):
     572           0 :       this->bandwidth = RADIOLIB_SX128X_LORA_BW_203_125;
     573           0 :       break;
     574           0 :     case(406250):
     575           0 :       this->bandwidth = RADIOLIB_SX128X_LORA_BW_406_25;
     576           0 :       break;
     577           0 :     case(812500):
     578           0 :       this->bandwidth = RADIOLIB_SX128X_LORA_BW_812_50;
     579           0 :       break;
     580           0 :     case(1625000):
     581           0 :       this->bandwidth = RADIOLIB_SX128X_LORA_BW_1625_00;
     582           0 :       break;
     583           0 :     default:
     584           0 :       return(RADIOLIB_ERR_INVALID_BANDWIDTH);
     585             :   }
     586             : 
     587             :   // update modulation parameters
     588           0 :   this->bandwidthHz = bw;
     589           0 :   return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRateLoRa));
     590             : }
     591             : 
     592           3 : int16_t SX128x::setSpreadingFactor(uint8_t sf) {
     593             :   // check active modem
     594           3 :   uint8_t modem = getPacketType();
     595           3 :   if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) {
     596             :     // check range for LoRa
     597           0 :     RADIOLIB_CHECK_RANGE(sf, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
     598           3 :   } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING) {
     599             :     // check range for ranging
     600           0 :     RADIOLIB_CHECK_RANGE(sf, 5, 10, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
     601             :   } else {
     602           3 :     return(RADIOLIB_ERR_WRONG_MODEM);
     603             :   }
     604             : 
     605             :   // update modulation parameters
     606           0 :   this->spreadingFactor = sf << 4;
     607           0 :   int16_t state = setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRateLoRa);
     608           0 :   RADIOLIB_ASSERT(state);
     609             : 
     610             :   // update mystery register in LoRa mode - SX1280 datasheet rev 3.2 section 14.4.1
     611           0 :   if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) {
     612           0 :     uint8_t data = 0;
     613           0 :     if((this->spreadingFactor == RADIOLIB_SX128X_LORA_SF_5) || (this->spreadingFactor == RADIOLIB_SX128X_LORA_SF_6)) {
     614           0 :       data = 0x1E;
     615           0 :     } else if((this->spreadingFactor == RADIOLIB_SX128X_LORA_SF_7) || (this->spreadingFactor == RADIOLIB_SX128X_LORA_SF_8)) {
     616           0 :       data = 0x37;
     617             :     } else {
     618           0 :       data = 0x32;
     619             :     }
     620           0 :     state = SX128x::writeRegister(RADIOLIB_SX128X_REG_LORA_SF_CONFIG, &data, 1);
     621           0 :     RADIOLIB_ASSERT(state);
     622             : 
     623             :     // this register must also be updated for some reason
     624           0 :     state = SX128x::readRegister(RADIOLIB_SX128X_REG_FREQ_ERROR_CORRECTION, &data, 1);
     625           0 :     RADIOLIB_ASSERT(state);
     626             : 
     627           0 :     data |= 0x01;
     628           0 :     state = SX128x::writeRegister(RADIOLIB_SX128X_REG_FREQ_ERROR_CORRECTION, &data, 1);
     629           0 :     RADIOLIB_ASSERT(state);
     630             :   }
     631             : 
     632           0 :   return(state);
     633             : }
     634             : 
     635           3 : int16_t SX128x::setCodingRate(uint8_t cr, bool longInterleaving) {
     636             :   // check active modem
     637           3 :   uint8_t modem = getPacketType();
     638             : 
     639             :   // LoRa/ranging
     640           3 :   if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) {
     641           0 :     RADIOLIB_CHECK_RANGE(cr, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
     642             : 
     643             :     // update modulation parameters
     644           0 :     if(longInterleaving && (modem == RADIOLIB_SX128X_PACKET_TYPE_LORA)) {
     645           0 :       switch(cr) {
     646           0 :         case 4:
     647           0 :           this->codingRateLoRa = 0;
     648           0 :           break;
     649           0 :         case 5:
     650             :         case 6:
     651           0 :           this->codingRateLoRa = cr;
     652           0 :           break;
     653           0 :         case 8: 
     654           0 :           this->codingRateLoRa = cr - 1;
     655           0 :           break;
     656           0 :         default:
     657           0 :           return(RADIOLIB_ERR_INVALID_CODING_RATE);
     658             :       }
     659             :     } else {
     660           0 :       this->codingRateLoRa = cr - 4;
     661             :     }
     662           0 :     return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRateLoRa));
     663             : 
     664             :   // FLRC
     665           3 :   } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC) {
     666           0 :     RADIOLIB_CHECK_RANGE(cr, 2, 4, RADIOLIB_ERR_INVALID_CODING_RATE);
     667             : 
     668             :     // update modulation parameters
     669           0 :     this->codingRateFLRC = (cr - 2) * 2;
     670           0 :     return(setModulationParams(this->bitRate, this->codingRateFLRC, this->shaping));
     671             :   }
     672             : 
     673           3 :   return(RADIOLIB_ERR_WRONG_MODEM);
     674             : }
     675             : 
     676           3 : int16_t SX128x::setOutputPower(int8_t power) {
     677             :   // apply offset for external PA
     678           3 :   int8_t pwr = power;
     679           3 :   int16_t state = this->applyOutputPowerOffset(RADIOLIB_SX128X_POUT_MIN, &power, &pwr);
     680           3 :   RADIOLIB_ASSERT(state);
     681             : 
     682           3 :   this->txPower = pwr - RADIOLIB_SX128X_POUT_MIN;
     683           3 :   return(setTxParams(this->txPower));
     684             : }
     685             : 
     686           3 : int16_t SX128x::setModem(ModemType_t modem) {
     687           3 :   switch(modem) {
     688           0 :     case(ModemType_t::RADIOLIB_MODEM_LORA): {
     689           0 :       ConfigLoRa_t cfg;
     690           0 :       return(this->begin(cfg));
     691             :     } break;
     692           0 :     case(ModemType_t::RADIOLIB_MODEM_FSK): {
     693           0 :       ConfigFSK_t cfg;
     694           0 :       return(this->beginGFSK(cfg));
     695             :     } break;
     696           3 :     default:
     697           3 :       return(RADIOLIB_ERR_WRONG_MODEM);
     698             :   }
     699             : }
     700             : 
     701           9 : int16_t SX128x::getModem(ModemType_t* modem) {
     702           9 :   RADIOLIB_ASSERT_PTR(modem);
     703             : 
     704           9 :   switch(getPacketType()) {
     705           0 :     case(RADIOLIB_SX128X_PACKET_TYPE_LORA):
     706           0 :       *modem = ModemType_t::RADIOLIB_MODEM_LORA;
     707           0 :       return(RADIOLIB_ERR_NONE);
     708           0 :     case(RADIOLIB_SX128X_PACKET_TYPE_GFSK):
     709           0 :       *modem = ModemType_t::RADIOLIB_MODEM_FSK;
     710           0 :       return(RADIOLIB_ERR_NONE);
     711             :   }
     712             :   
     713           9 :   return(RADIOLIB_ERR_WRONG_MODEM);
     714             : }
     715             : 
     716           3 : int16_t SX128x::getMode(RadioModeType_t* mode) {
     717           3 :   RADIOLIB_ASSERT_PTR(mode);
     718             : 
     719           3 :   const uint8_t status = getStatus();
     720           3 :   if(status == RADIOLIB_SX128X_STATUS_SPI_FAILED) {
     721           3 :     return(RADIOLIB_ERR_SPI_CMD_FAILED);
     722             :   }
     723             : 
     724             :   // sleep is not among the modes this can report: the chip does not answer SPI while asleep
     725           0 :   switch(status & 0b11100000) {
     726           0 :     case(RADIOLIB_SX128X_STATUS_MODE_STDBY_RC):
     727             :     case(RADIOLIB_SX128X_STATUS_MODE_STDBY_XOSC):
     728           0 :       *mode = RADIOLIB_RADIO_MODE_STANDBY;
     729           0 :       break;
     730           0 :     case(RADIOLIB_SX128X_STATUS_MODE_RX):
     731           0 :       *mode = RADIOLIB_RADIO_MODE_RX;
     732           0 :       break;
     733           0 :     case(RADIOLIB_SX128X_STATUS_MODE_TX):
     734           0 :       *mode = RADIOLIB_RADIO_MODE_TX;
     735           0 :       break;
     736           0 :     default:
     737             :       // frequency synthesis, or a value the datasheet leaves unassigned
     738           0 :       *mode = RADIOLIB_RADIO_MODE_NONE;
     739           0 :       break;
     740             :   }
     741             : 
     742           0 :   return(RADIOLIB_ERR_NONE);
     743             : }
     744             : 
     745           3 : int16_t SX128x::setPreambleLength(size_t preambleLength, size_t preambleDetLength) {
     746             :   (void)preambleDetLength;
     747             :   
     748           3 :   uint8_t modem = getPacketType();
     749           3 :   if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) {
     750             :     // LoRa or ranging
     751             :     // the actual limit is 491520, however, some platforms (notably AVR) limit size_t to 16 bits
     752           0 :     RADIOLIB_CHECK_RANGE(preambleLength, 2, 65534, RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH);
     753             : 
     754             :     // check preamble length is even - no point even trying odd numbers
     755           0 :     if(preambleLength % 2 != 0) {
     756           0 :       return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH);
     757             :     }
     758             : 
     759             :     // calculate exponent and mantissa values (use the next longer preamble if there's no exact match)
     760           0 :     uint8_t e = 1;
     761           0 :     uint8_t m = 1;
     762           0 :     uint32_t len = 0;
     763           0 :     for(; e <= 15; e++) {
     764           0 :       for(m = 1; m <= 15; m++) {
     765           0 :         len = m * (uint32_t(1) << e);
     766           0 :         if(len >= preambleLength) {
     767           0 :           break;
     768             :         }
     769             :       }
     770           0 :       if(len >= preambleLength) {
     771           0 :         break;
     772             :       }
     773             :     }
     774             : 
     775             :     // update packet parameters
     776           0 :     this->preambleLengthLoRa = (e << 4) | m;
     777           0 :     return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled));
     778             : 
     779           3 :   } else if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC)) {
     780             :     // GFSK or FLRC
     781           0 :     RADIOLIB_CHECK_RANGE(preambleLength, 4, 32, RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH);
     782             : 
     783             :     // check preamble length is multiple of 4
     784           0 :     if(preambleLength % 4 != 0) {
     785           0 :       return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH);
     786             :     }
     787             : 
     788             :     // update packet parameters
     789           0 :     this->preambleLengthGFSK = ((preambleLength / 4) - 1) << 4;
     790           0 :     return(setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, this->packetType));
     791             :   }
     792             : 
     793           3 :   return(RADIOLIB_ERR_WRONG_MODEM);
     794             : }
     795             : 
     796           3 : int16_t SX128x::checkDataRate(DataRate_t dr, ModemType_t modem) {
     797           3 :   int16_t state = RADIOLIB_ERR_UNKNOWN;
     798             : 
     799             :   // retrieve modem if not supplied
     800           3 :   if(modem == RADIOLIB_MODEM_NONE) {
     801           3 :     state = this->getModem(&modem);
     802           3 :     RADIOLIB_ASSERT(state);
     803             :   }
     804             : 
     805             :   // select interpretation based on modem
     806           0 :   if(modem == RADIOLIB_MODEM_FSK) {
     807           0 :     RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, RADIOLIB_UNIT_KILO(125), RADIOLIB_UNIT_KILO(2000), RADIOLIB_ERR_INVALID_BIT_RATE);
     808           0 :     RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 62500, RADIOLIB_UNIT_KILO(1000), RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
     809           0 :     return(RADIOLIB_ERR_NONE);
     810             : 
     811           0 :   } else if(modem == RADIOLIB_MODEM_LORA) {
     812           0 :     RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
     813           0 :     RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, RADIOLIB_UNIT_KILO(203), RADIOLIB_UNIT_KILO(1625), RADIOLIB_ERR_INVALID_BANDWIDTH);
     814           0 :     RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
     815           0 :     return(RADIOLIB_ERR_NONE);
     816             :   
     817             :   }
     818             : 
     819           0 :   return(state);
     820             : }
     821             : 
     822           3 : int16_t SX128x::setBitRate(uint32_t br) {
     823             :   // check active modem
     824           3 :   uint8_t modem = getPacketType();
     825             : 
     826             :   // GFSK/BLE
     827           3 :   if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE)) {
     828           0 :     switch(br) {
     829           0 :       case(RADIOLIB_UNIT_KILO(125)):
     830           0 :         this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_125_BW_0_3;
     831           0 :         break;
     832           0 :       case(RADIOLIB_UNIT_KILO(250)):
     833           0 :         this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_250_BW_0_6;
     834           0 :         break;
     835           0 :       case(RADIOLIB_UNIT_KILO(400)):
     836           0 :         this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_400_BW_1_2;
     837           0 :         break;
     838           0 :       case(RADIOLIB_UNIT_KILO(500)):
     839           0 :         this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_500_BW_1_2;
     840           0 :         break;
     841           0 :       case(RADIOLIB_UNIT_KILO(800)):
     842           0 :         this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4;
     843           0 :         break;
     844           0 :       case(RADIOLIB_UNIT_KILO(1000)):
     845           0 :         this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_1_000_BW_2_4;
     846           0 :         break;
     847           0 :       case(RADIOLIB_UNIT_KILO(1600)):
     848           0 :         this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_1_600_BW_2_4;
     849           0 :         break;
     850           0 :       case(RADIOLIB_UNIT_KILO(2000)):
     851           0 :         this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_2_000_BW_2_4;
     852           0 :         break;
     853           0 :       default:
     854           0 :         return(RADIOLIB_ERR_INVALID_BIT_RATE);
     855             :     }
     856             : 
     857             :     // update modulation parameters
     858           0 :     this->bitRateBps = br;
     859           0 :     return(setModulationParams(this->bitRate, this->modIndex, this->shaping));
     860             : 
     861             :   // FLRC
     862           3 :   } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC) {
     863           0 :     switch(br) {
     864           0 :       case(RADIOLIB_UNIT_KILO(260)):
     865           0 :         this->bitRate = RADIOLIB_SX128X_FLRC_BR_0_260_BW_0_3;
     866           0 :         break;
     867           0 :       case(RADIOLIB_UNIT_KILO(325)):
     868           0 :         this->bitRate = RADIOLIB_SX128X_FLRC_BR_0_325_BW_0_3;
     869           0 :         break;
     870           0 :       case(RADIOLIB_UNIT_KILO(520)):
     871           0 :         this->bitRate = RADIOLIB_SX128X_FLRC_BR_0_520_BW_0_6;
     872           0 :         break;
     873           0 :       case(RADIOLIB_UNIT_KILO(650)):
     874           0 :         this->bitRate = RADIOLIB_SX128X_FLRC_BR_0_650_BW_0_6;
     875           0 :         break;
     876           0 :       case(RADIOLIB_UNIT_KILO(1000)):
     877           0 :         this->bitRate = RADIOLIB_SX128X_FLRC_BR_1_000_BW_1_2;
     878           0 :         break;
     879           0 :       case(RADIOLIB_UNIT_KILO(1300)):
     880           0 :         this->bitRate = RADIOLIB_SX128X_FLRC_BR_1_300_BW_1_2;
     881           0 :         break;
     882           0 :       default:
     883           0 :         return(RADIOLIB_ERR_INVALID_BIT_RATE);
     884             :     }
     885             : 
     886             :     // update modulation parameters
     887           0 :     this->bitRateBps = br;
     888           0 :     return(setModulationParams(this->bitRate, this->codingRateFLRC, this->shaping));
     889             : 
     890             :   }
     891             : 
     892           3 :   return(RADIOLIB_ERR_WRONG_MODEM);
     893             : }
     894             : 
     895           3 : int16_t SX128x::setFrequencyDeviation(uint32_t freqDev) {
     896             :   // check active modem
     897           3 :   uint8_t modem = getPacketType();
     898           3 :   if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE))) {
     899           3 :     return(RADIOLIB_ERR_WRONG_MODEM);
     900             :   }
     901             : 
     902             :   // set frequency deviation to lowest available setting (required for digimodes)
     903           0 :   uint32_t newFreqDev = freqDev ? freqDev : 62500;
     904           0 :   RADIOLIB_CHECK_RANGE(newFreqDev, 62500, RADIOLIB_UNIT_KILO(1000), RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
     905             : 
     906             :   // override for the lowest possible frequency deviation - required for some PhysicalLayer protocols
     907           0 :   if(freqDev == 0) {
     908           0 :     this->modIndex = RADIOLIB_SX128X_BLE_GFSK_MOD_IND_0_35;
     909           0 :     this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_125_BW_0_3;
     910           0 :     return(setModulationParams(this->bitRate, this->modIndex, this->shaping));
     911             :   }
     912             : 
     913             :   // update modulation parameters
     914           0 :   uint8_t modInd = (uint8_t)((8.0f * ((float)newFreqDev / (float)this->bitRateBps)) - 1.0f);
     915           0 :   if(modInd > RADIOLIB_SX128X_BLE_GFSK_MOD_IND_4_00) {
     916           0 :     return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS);
     917             :   }
     918             : 
     919             :   // update modulation parameters
     920           0 :   this->frequencyDev = newFreqDev;
     921           0 :   this->modIndex = modInd;
     922           0 :   return(setModulationParams(this->bitRate, this->modIndex, this->shaping));
     923             : }
     924             : 
     925           3 : int16_t SX128x::setDataShaping(uint8_t sh) {
     926             :   // check active modem
     927           3 :   uint8_t modem = getPacketType();
     928           3 :   if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC))) {
     929           3 :     return(RADIOLIB_ERR_WRONG_MODEM);
     930             :   }
     931             : 
     932             :   // set data this->shaping
     933           0 :   switch(sh) {
     934           0 :     case RADIOLIB_SHAPING_NONE:
     935           0 :       this->shaping = RADIOLIB_SX128X_BLE_GFSK_BT_OFF;
     936           0 :       break;
     937           0 :     case RADIOLIB_SHAPING_0_5:
     938           0 :       this->shaping = RADIOLIB_SX128X_BLE_GFSK_BT_0_5;
     939           0 :       break;
     940           0 :     case RADIOLIB_SHAPING_1_0:
     941           0 :       this->shaping = RADIOLIB_SX128X_BLE_GFSK_BT_1_0;
     942           0 :       break;
     943           0 :     default:
     944           0 :       return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
     945             :   }
     946             : 
     947             :   // update modulation parameters
     948           0 :   if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE)) {
     949           0 :     return(setModulationParams(this->bitRate, this->modIndex, this->shaping));
     950             :   } else {
     951           0 :     return(setModulationParams(this->bitRate, this->codingRateFLRC, this->shaping));
     952             :   }
     953             : }
     954             : 
     955           3 : int16_t SX128x::setSyncWord(uint8_t* sync, size_t len) {
     956             :   // check active modem
     957           3 :   uint8_t modem = getPacketType();
     958           3 :   if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC))) {
     959           3 :     return(RADIOLIB_ERR_WRONG_MODEM);
     960             :   }
     961             : 
     962           0 :   if(modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) {
     963             :     // GFSK can use up to 5 bytes as sync word
     964           0 :     if(len > 5) {
     965           0 :       return(RADIOLIB_ERR_INVALID_SYNC_WORD);
     966             :     }
     967             : 
     968             :     // calculate sync word length parameter value
     969           0 :     if(len > 0) {
     970           0 :       this->syncWordLen = (len - 1)*2;
     971             :     }
     972             : 
     973             :   } else {
     974             :     // FLRC requires 32-bit sync word
     975           0 :     if(!((len == 0) || (len == 4))) {
     976           0 :       return(RADIOLIB_ERR_INVALID_SYNC_WORD);
     977             :     }
     978             : 
     979             :     // save sync word length parameter value
     980           0 :     this->syncWordLen = len;
     981             :   }
     982             : 
     983             :   // update sync word
     984           0 :   int16_t state = SX128x::writeRegister(RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_4 + (5 - len), sync, len);
     985           0 :   RADIOLIB_ASSERT(state);
     986             : 
     987             :   // update packet parameters
     988           0 :   if(this->syncWordLen == 0) {
     989           0 :     this->syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_OFF;
     990             :   } else {
     991             :     /// \todo add support for multiple sync words
     992           0 :     this->syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1;
     993             :   }
     994           0 :   return(setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, this->packetType));
     995             : }
     996             : 
     997           0 : int16_t SX128x::setSyncWord(uint8_t syncWord, uint8_t controlBits) {
     998             :   // check active modem
     999           0 :   if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) {
    1000           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1001             :   }
    1002             : 
    1003             :   // update register
    1004           0 :   const uint8_t data[2] = {(uint8_t)((syncWord & 0xF0) | ((controlBits & 0xF0) >> 4)), (uint8_t)(((syncWord & 0x0F) << 4) | (controlBits & 0x0F))};
    1005           0 :   return(writeRegister(RADIOLIB_SX128X_REG_LORA_SYNC_WORD_MSB, data, 2));
    1006             : }
    1007             : 
    1008           0 : int16_t SX128x::setCRC(uint8_t len, uint32_t initial, uint16_t polynomial) {
    1009             :   // check active modem
    1010           0 :   uint8_t modem = getPacketType();
    1011             : 
    1012             :   int16_t state;
    1013           0 :   if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC)) {
    1014             :     // update packet parameters
    1015           0 :     if(modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) {
    1016           0 :       if(len > 2) {
    1017           0 :         return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
    1018             :       }
    1019             :     } else {
    1020           0 :       if(len > 3) {
    1021           0 :         return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
    1022             :       }
    1023             :     }
    1024           0 :     this->crcGFSK = len << 4;
    1025           0 :     state = setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, this->packetType);
    1026           0 :     RADIOLIB_ASSERT(state);
    1027             : 
    1028             :     // set initial CRC value
    1029           0 :     uint8_t data[] = { (uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF) };
    1030           0 :     state = writeRegister(RADIOLIB_SX128X_REG_CRC_INITIAL_MSB, data, 2);
    1031           0 :     RADIOLIB_ASSERT(state);
    1032             : 
    1033             :     // set CRC polynomial
    1034           0 :     data[0] = (uint8_t)((polynomial >> 8) & 0xFF);
    1035           0 :     data[1] = (uint8_t)(polynomial & 0xFF);
    1036           0 :     state = writeRegister(RADIOLIB_SX128X_REG_CRC_POLYNOMIAL_MSB, data, 2);
    1037           0 :     return(state);
    1038             : 
    1039           0 :   } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) {
    1040             :     // update packet parameters
    1041           0 :     if(len == 0) {
    1042           0 :       this->crcBLE = RADIOLIB_SX128X_BLE_CRC_OFF;
    1043           0 :     } else if(len == 3) {
    1044           0 :       this->crcBLE = RADIOLIB_SX128X_BLE_CRC_3_BYTE;
    1045             :     } else {
    1046           0 :       return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
    1047             :     }
    1048           0 :     state = setPacketParamsBLE(this->connectionState, this->crcBLE, this->bleTestPayload, this->whitening);
    1049           0 :     RADIOLIB_ASSERT(state);
    1050             : 
    1051             :     // set initial CRC value
    1052           0 :     const uint8_t data[] = { (uint8_t)((initial >> 16) & 0xFF), (uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF) };
    1053           0 :     state = writeRegister(RADIOLIB_SX128X_REG_BLE_CRC_INITIAL_MSB, data, 3);
    1054           0 :     return(state);
    1055             : 
    1056           0 :   } else if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) {
    1057             :     // update packet parameters
    1058           0 :     if(len == 0) {
    1059           0 :       this->crcLoRa = RADIOLIB_SX128X_LORA_CRC_OFF;
    1060           0 :     } else if(len == 2) {
    1061           0 :       this->crcLoRa = RADIOLIB_SX128X_LORA_CRC_ON;
    1062             :     } else {
    1063           0 :       return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
    1064             :     }
    1065           0 :     state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled);
    1066           0 :     return(state);
    1067             :   }
    1068             : 
    1069           0 :   return(RADIOLIB_ERR_UNKNOWN);
    1070             : }
    1071             : 
    1072           3 : int16_t SX128x::setWhitening(bool enabled) {
    1073             :   // check active modem
    1074           3 :   uint8_t modem = getPacketType();
    1075           3 :   if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE))) {
    1076           3 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1077             :   }
    1078             : 
    1079             :   // update packet parameters
    1080           0 :   if(enabled) {
    1081           0 :     this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON;
    1082             :   } else {
    1083           0 :     this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_OFF;
    1084             :   }
    1085             : 
    1086           0 :   if(modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) {
    1087           0 :     return(setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, this->packetType));
    1088             :   }
    1089           0 :   return(setPacketParamsBLE(this->connectionState, this->crcBLE, this->bleTestPayload, this->whitening));
    1090             : }
    1091             : 
    1092           0 : int16_t SX128x::setAccessAddress(uint32_t addr) {
    1093             :   // check active modem
    1094           0 :   if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_BLE) {
    1095           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1096             :   }
    1097             : 
    1098             :   // set the address
    1099           0 :   const uint8_t addrBuff[] = { (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) };
    1100           0 :   return(SX128x::writeRegister(RADIOLIB_SX128X_REG_ACCESS_ADDRESS_BYTE_3, addrBuff, 4));
    1101             : }
    1102             : 
    1103           0 : int16_t SX128x::setHighSensitivityMode(bool enable) {
    1104             :   // read the current registers
    1105           0 :   uint8_t RxGain = 0;
    1106           0 :   int16_t state = readRegister(RADIOLIB_SX128X_REG_GAIN_MODE, &RxGain, 1);
    1107           0 :   RADIOLIB_ASSERT(state);
    1108             : 
    1109           0 :   if(enable) {
    1110           0 :     RxGain |= 0xC0; // Set bits 6 and 7
    1111             :   } else {
    1112           0 :     RxGain &= ~0xC0; // Unset bits 6 and 7
    1113             :   }
    1114             : 
    1115             :   // update all values
    1116           0 :   state = writeRegister(RADIOLIB_SX128X_REG_GAIN_MODE, &RxGain, 1);
    1117           0 :   return(state);
    1118             : }
    1119             : 
    1120           0 : int16_t SX128x::setGainControl(uint8_t gain) {
    1121             :   // read the current registers
    1122           0 :   uint8_t ManualGainSetting = 0;
    1123           0 :   int16_t state = readRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_2, &ManualGainSetting, 1);
    1124           0 :   RADIOLIB_ASSERT(state);
    1125           0 :   uint8_t LNAGainValue = 0;
    1126           0 :   state = readRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_SETTING, &LNAGainValue, 1);
    1127           0 :   RADIOLIB_ASSERT(state);
    1128           0 :   uint8_t LNAGainControl = 0;
    1129           0 :   state = readRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_1, &LNAGainControl, 1);
    1130           0 :   RADIOLIB_ASSERT(state);
    1131             : 
    1132             :   // set the gain
    1133           0 :   if (gain > 0 && gain < 14) {
    1134             :     // Set manual gain
    1135           0 :     ManualGainSetting &= ~0x01; // Set bit 0 to 0 (Enable Manual Gain Control)
    1136           0 :     LNAGainValue &= 0xF0; // Bits 0, 1, 2 and 3 to 0
    1137           0 :     LNAGainValue |= gain; // Set bits 0, 1, 2 and 3 to Manual Gain Setting (1-13)
    1138           0 :     LNAGainControl |= 0x80; // Set bit 7 to 1 (Enable Manual Gain Control)
    1139             :   } else {
    1140             :     // Set automatic gain if 0 or out of range
    1141           0 :     ManualGainSetting |= 0x01; // Set bit 0 to 1 (Enable Automatic Gain Control)
    1142           0 :     LNAGainValue &= 0xF0; // Bits 0, 1, 2 and 3 to 0
    1143           0 :     LNAGainValue |= 0x0A; // Set bits 0, 1, 2 and 3 to Manual Gain Setting (1-13)
    1144           0 :     LNAGainControl &= ~0x80; // Set bit 7 to 0 (Enable Automatic Gain Control)
    1145             :   }
    1146             : 
    1147             :   // update all values
    1148           0 :   state = writeRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_2, &ManualGainSetting, 1);
    1149           0 :   RADIOLIB_ASSERT(state);
    1150           0 :   state = writeRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_SETTING, &LNAGainValue, 1);
    1151           0 :   RADIOLIB_ASSERT(state);
    1152           0 :   state = writeRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_1, &LNAGainControl, 1);
    1153           0 :   return(state);
    1154             : }
    1155             : 
    1156           3 : float SX128x::getRSSI() {
    1157             :   // get packet status
    1158             :   uint8_t packetStatus[5];
    1159           3 :   this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_PACKET_STATUS, packetStatus, 5);
    1160             : 
    1161             :   // check active modem
    1162           3 :   uint8_t modem = getPacketType();
    1163           3 :   if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) {
    1164             :     // LoRa or ranging
    1165           0 :     uint8_t rssiSync = packetStatus[0];
    1166           0 :     float rssiMeasured = -1.0 * rssiSync/2.0;
    1167           0 :     float snr = getSNR();
    1168           0 :     if(snr <= 0.0f) {
    1169           0 :       return(rssiMeasured - snr);
    1170             :     } else {
    1171           0 :       return(rssiMeasured);
    1172             :     }
    1173             :   } else {
    1174             :     // GFSK, BLE or FLRC
    1175           3 :     uint8_t rssiSync = packetStatus[1];
    1176           3 :     return(-1.0 * rssiSync/2.0);
    1177             :   }
    1178             : }
    1179             : 
    1180           0 : float SX128x::getRSSI(bool packet) {
    1181           0 :   if(!packet) {
    1182             :     // get instantaneous RSSI value
    1183           0 :     uint8_t data[3] = {0, 0, 0}; // RssiInst, Status, RFU
    1184           0 :     this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_RSSI_INST, data, 3);
    1185           0 :     return((float)data[0] / (-2.0f));
    1186             :   } else {
    1187           0 :     return(this->getRSSI());
    1188             :   }
    1189             : }
    1190             : 
    1191           3 : float SX128x::getSNR() {
    1192             :   // check active modem
    1193           3 :   uint8_t modem = getPacketType();
    1194           3 :   if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING))) {
    1195           3 :     return(0.0);
    1196             :   }
    1197             : 
    1198             :   // get packet status
    1199             :   uint8_t packetStatus[5];
    1200           0 :   this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_PACKET_STATUS, packetStatus, 5);
    1201             : 
    1202             :   // calculate real SNR
    1203           0 :   uint8_t snr = packetStatus[1];
    1204           0 :   if(snr < 128) {
    1205           0 :     return(snr/4.0);
    1206             :   } else {
    1207           0 :     return((snr - 256)/4.0f);
    1208             :   }
    1209             : }
    1210             : 
    1211           0 : int32_t SX128x::getFrequencyError() {
    1212             :   // check active modem
    1213           0 :   uint8_t modem = getPacketType();
    1214           0 :   if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING))) {
    1215           0 :     return(0.0);
    1216             :   }
    1217             : 
    1218             :   // read the raw frequency error register values
    1219           0 :   uint8_t efeRaw[3] = {0};
    1220           0 :   int16_t state = readRegister(RADIOLIB_SX128X_REG_FEI_MSB, &efeRaw[0], 1);
    1221           0 :   RADIOLIB_ASSERT(state);
    1222           0 :   state = readRegister(RADIOLIB_SX128X_REG_FEI_MID, &efeRaw[1], 1);
    1223           0 :   RADIOLIB_ASSERT(state);
    1224           0 :   state = readRegister(RADIOLIB_SX128X_REG_FEI_LSB, &efeRaw[2], 1);
    1225           0 :   RADIOLIB_ASSERT(state);
    1226           0 :   uint32_t raw = ((uint32_t) efeRaw[0] << 16) | ((uint32_t) efeRaw[1] << 8) | efeRaw[2];
    1227           0 :   raw &= 0x0FFFFF;
    1228             : 
    1229             :   // check the first bit
    1230           0 :   int32_t error = 0;
    1231           0 :   if (raw & 0x80000) {
    1232             :     // frequency error is negative
    1233           0 :     raw |= (uint32_t) 0xFFF00000;
    1234           0 :     raw = ~raw + 1;
    1235           0 :     error = raw * this->bandwidthHz * (155.0f / -160000000.0f);
    1236             :   } else {
    1237           0 :     error = raw * this->bandwidthHz * (155.0f / 160000000.0f);
    1238             :   }
    1239             : 
    1240           0 :   return(error);
    1241             : }
    1242             : 
    1243           3 : size_t SX128x::getPacketLength(bool update) {
    1244           3 :   return(this->getPacketLength(update, NULL));
    1245             : }
    1246             : 
    1247           3 : size_t SX128x::getPacketLength(bool update, uint8_t* offset) {
    1248             :   (void)update;
    1249             : 
    1250             :   // in implicit mode, return the cached value
    1251           3 :   if((getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_LORA) && (this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT)) {
    1252           0 :     return(this->payloadLen);
    1253             :   }
    1254             : 
    1255           3 :   uint8_t rxBufStatus[2] = {0, 0};
    1256           3 :   this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2);
    1257             : 
    1258           3 :   if(offset) { *offset = rxBufStatus[1]; }
    1259             : 
    1260           3 :   return((size_t)rxBufStatus[0]);
    1261             : }
    1262             : 
    1263           0 : int16_t SX128x::getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC) {
    1264           0 :   int16_t state = RADIOLIB_ERR_NONE;
    1265             : 
    1266             :   // check if in explicit header mode
    1267           0 :   if(this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) {
    1268           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1269             :   }
    1270             : 
    1271           0 :   if(cr) { *cr = this->mod->SPIgetRegValue(RADIOLIB_SX128X_REG_LORA_RX_CODING_RATE, 6, 4) >> 4; }
    1272           0 :   if(hasCRC) { *hasCRC = (this->mod->SPIgetRegValue(RADIOLIB_SX128X_REG_FEI_MSB, 4, 4) != 0); }
    1273             : 
    1274           0 :   return(state);
    1275             : }
    1276             : 
    1277           0 : int16_t SX128x::fixedPacketLengthMode(uint8_t len) {
    1278           0 :   return(setPacketMode(RADIOLIB_SX128X_GFSK_FLRC_PACKET_FIXED, len));
    1279             : }
    1280             : 
    1281           0 : int16_t SX128x::variablePacketLengthMode(uint8_t maxLen) {
    1282           0 :   return(setPacketMode(RADIOLIB_SX128X_GFSK_FLRC_PACKET_VARIABLE, maxLen));
    1283             : }
    1284             : 
    1285          13 : RadioLibTime_t SX128x::calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) {
    1286          13 :   if((modem != ModemType_t::RADIOLIB_MODEM_LORA) && (modem != ModemType_t::RADIOLIB_MODEM_FSK)) {
    1287           3 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1288             :   }
    1289             : 
    1290          10 :   if(modem == ModemType_t::RADIOLIB_MODEM_LORA) {
    1291           6 :     uint32_t symbolLength_us = (RADIOLIB_UNIT_MEGA(1) << dr.lora.spreadingFactor) / dr.lora.bandwidth;
    1292             :       
    1293             :     // as per SX1280 datasheet rev 3.3 section 7.4.4
    1294             :     // it looks like SF>10 has the same effect on number of symbols as LDRO has on sub-GHz LoRa (different SF denominator)
    1295             :     // force LDRO in that case so that the number of symbols is correct
    1296           6 :     if(dr.lora.spreadingFactor > 10) {
    1297           3 :       pc.lora.ldrOptimize = true;
    1298             :     }
    1299             : 
    1300           6 :     size_t nSymbol_x4 = PhysicalLayer::getNumSymbols(dr, pc, len) * 4;
    1301           6 :     return((symbolLength_us * nSymbol_x4) / 4);
    1302             :   }
    1303             : 
    1304           4 :   return(PhysicalLayer::calculateTimeOnAir(modem, dr, pc, len));
    1305             : }
    1306             : 
    1307           3 : RadioLibTime_t SX128x::getTimeOnAir(size_t len) {
    1308             :   // check active modem
    1309           3 :   uint8_t modem = getPacketType();
    1310           3 :   DataRate_t dr = {};
    1311           3 :   PacketConfig_t pc = {};
    1312           3 :   size_t packetLen = len;
    1313           3 :   if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) {
    1314           0 :     uint8_t sf = this->spreadingFactor >> 4;
    1315           0 :     uint8_t cr = this->codingRateLoRa;
    1316             :     // We assume same calculation for short and long interleaving, so map CR values 0-4 and 5-7 to the same values
    1317           0 :     if (cr < 5) {
    1318           0 :       cr = cr + 4;
    1319           0 :     } else if (cr == 7) {
    1320           0 :       cr = cr + 1;
    1321             :     }
    1322             :     
    1323           0 :     dr.lora.spreadingFactor = sf;
    1324           0 :     dr.lora.codingRate = cr;
    1325           0 :     dr.lora.bandwidth = this->bandwidthHz;
    1326             : 
    1327           0 :     uint16_t preambleLength = (this->preambleLengthLoRa & 0x0F) * (uint32_t(1) << ((this->preambleLengthLoRa & 0xF0) >> 4));
    1328             :     
    1329           0 :     pc.lora.preambleLength = preambleLength;
    1330           0 :     pc.lora.implicitHeader = this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT;
    1331           0 :     pc.lora.crcEnabled = this->crcLoRa == RADIOLIB_SX128X_LORA_CRC_ON;
    1332           0 :     pc.lora.ldrOptimize = false;
    1333             : 
    1334           0 :     return(calculateTimeOnAir(ModemType_t::RADIOLIB_MODEM_LORA, dr, pc, packetLen));
    1335             : 
    1336           3 :   } else if (modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) {
    1337           0 :     dr.fsk.bitRate = this->bitRateBps;
    1338           0 :     dr.fsk.freqDev = this->frequencyDev;
    1339             : 
    1340           0 :     pc.fsk.preambleLength = ((uint16_t)this->preambleLengthGFSK >> 2) + 4;
    1341           0 :     pc.fsk.syncWordLength = ((this->syncWordLen >> 1) + 1) * 8;
    1342           0 :     pc.fsk.crcLength = this->crcGFSK >> 4;
    1343             : 
    1344           0 :     if(this->packetType != RADIOLIB_SX128X_GFSK_FLRC_PACKET_FIXED) {
    1345           0 :       packetLen++;
    1346             :     }
    1347             : 
    1348           0 :     return(calculateTimeOnAir(ModemType_t::RADIOLIB_MODEM_FSK, dr, pc, packetLen));
    1349             :   } else {
    1350           3 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1351             :   }
    1352             : 
    1353             : }
    1354             : 
    1355           3 : RadioLibTime_t SX128x::calculateRxTimeout(RadioLibTime_t timeoutUs) {
    1356             :   // the timeout value is given in units of 15.625 microseconds
    1357             :   // the calling function should provide some extra width, as this number of units is truncated to integer
    1358           3 :   RadioLibTime_t timeout = timeoutUs / 15.625f;
    1359           3 :   return(timeout);
    1360             : }
    1361             : 
    1362           0 : int16_t SX128x::implicitHeader(size_t len) {
    1363           0 :   return(setHeaderType(RADIOLIB_SX128X_LORA_HEADER_IMPLICIT, len));
    1364             : }
    1365             : 
    1366           0 : int16_t SX128x::explicitHeader() {
    1367           0 :   return(setHeaderType(RADIOLIB_SX128X_LORA_HEADER_EXPLICIT));
    1368             : }
    1369             : 
    1370           3 : int16_t SX128x::setEncoding(uint8_t encoding) {
    1371           3 :   return(setWhitening(encoding));
    1372             : }
    1373             : 
    1374           0 : void SX128x::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) {
    1375           0 :   this->mod->setRfSwitchPins(rxEn, txEn);
    1376           0 : }
    1377             : 
    1378           0 : void SX128x::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) {
    1379           0 :   this->mod->setRfSwitchTable(pins, table);
    1380           0 : }
    1381             : 
    1382           0 : int16_t SX128x::setStandbyXOSC(bool enable) {
    1383             :   // set the internal variable
    1384           0 :   this->standbyXOSC = enable;
    1385             : 
    1386             :   // call standby to start the oscillator
    1387           0 :   int16_t state = this->standbyXOSC ? standby(RADIOLIB_SX128X_STANDBY_XOSC) : standby(RADIOLIB_SX128X_STANDBY_RC);
    1388           0 :   return state;
    1389             : }
    1390             : 
    1391           3 : uint8_t SX128x::randomByte() {
    1392             :   // it's unclear whether SX128x can measure RSSI while not receiving a packet
    1393             :   // this method is implemented only for PhysicalLayer compatibility
    1394           3 :   return(0);
    1395             : }
    1396             : 
    1397           3 : int16_t SX128x::invertIQ(bool enable) {
    1398           3 :   if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) {
    1399           3 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1400             :   }
    1401             : 
    1402           0 :   if(enable) {
    1403           0 :     this->invertIQEnabled = RADIOLIB_SX128X_LORA_IQ_INVERTED;
    1404             :   } else {
    1405           0 :     this->invertIQEnabled = RADIOLIB_SX128X_LORA_IQ_STANDARD;
    1406             :   }
    1407             : 
    1408           0 :   return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled));
    1409             : }
    1410             : 
    1411          12 : int16_t SX128x::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) {
    1412             :   int16_t state;
    1413             : 
    1414          12 :   switch(mode) {
    1415           9 :     case(RADIOLIB_RADIO_MODE_RX): {
    1416             :       // in implicit header mode, use the provided length if it is nonzero
    1417             :       // otherwise we trust the user has previously set the payload length manually
    1418           9 :       if((this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) && (cfg->receive.len != 0)) {
    1419           0 :         this->payloadLen = cfg->receive.len;
    1420             :       }
    1421             :       
    1422             :       // check active modem
    1423           9 :       if(getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_RANGING) {
    1424           0 :         return(RADIOLIB_ERR_WRONG_MODEM);
    1425             :       }
    1426             : 
    1427             :       // set DIO mapping
    1428           9 :       if(cfg->receive.timeout != RADIOLIB_SX128X_RX_TIMEOUT_INF) {
    1429           6 :         cfg->receive.irqMask |= (1UL << RADIOLIB_IRQ_TIMEOUT);
    1430             :       }
    1431             : 
    1432           9 :       state = setDioIrqParams(getIrqMapped(cfg->receive.irqFlags), getIrqMapped(cfg->receive.irqMask));
    1433           9 :       RADIOLIB_ASSERT(state);
    1434             : 
    1435             :       // set buffer pointers
    1436           0 :       state = setBufferBaseAddress();
    1437           0 :       RADIOLIB_ASSERT(state);
    1438             : 
    1439             :       // clear interrupt flags
    1440           0 :       state = clearIrqStatus();
    1441           0 :       RADIOLIB_ASSERT(state);
    1442             : 
    1443             :       // set implicit mode and expected len if applicable
    1444           0 :       if((this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_LORA)) {
    1445           0 :         state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled);
    1446           0 :         RADIOLIB_ASSERT(state);
    1447             :       }
    1448             :       // if max(uint32_t) is used, revert to RxContinuous
    1449           0 :       if(cfg->receive.timeout == 0xFFFFFFFF) {
    1450           0 :         cfg->receive.timeout = 0xFFFF;
    1451             :       }
    1452           0 :       this->rxTimeout = cfg->receive.timeout;
    1453           0 :     } break;
    1454             :   
    1455           3 :     case(RADIOLIB_RADIO_MODE_TX): {
    1456             :       // check packet length
    1457           3 :       if(cfg->transmit.len > RADIOLIB_SX128X_MAX_PACKET_LENGTH) {
    1458           0 :         return(RADIOLIB_ERR_PACKET_TOO_LONG);
    1459             :       }
    1460             : 
    1461             :       // set packet Length
    1462           3 :       uint8_t modem = getPacketType();
    1463           3 :       if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) {
    1464           0 :         state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, cfg->transmit.len, this->crcLoRa, this->invertIQEnabled);
    1465           3 :       } else if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC)) {
    1466           0 :         state = setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, this->packetType, cfg->transmit.len);
    1467           3 :       } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) {
    1468           0 :         state = setPacketParamsBLE(this->connectionState, this->crcBLE, this->bleTestPayload, this->whitening);
    1469             :       } else {
    1470           3 :         return(RADIOLIB_ERR_WRONG_MODEM);
    1471             :       }
    1472           0 :       RADIOLIB_ASSERT(state);
    1473             : 
    1474             :       // update output power
    1475           0 :       state = setTxParams(this->txPower);
    1476           0 :       RADIOLIB_ASSERT(state);
    1477             : 
    1478             :       // set buffer pointers
    1479           0 :       state = setBufferBaseAddress();
    1480           0 :       RADIOLIB_ASSERT(state);
    1481             : 
    1482             :       // write packet to buffer - unless the caller already did that with writeTxBuffer,
    1483             :       // which it signals by leaving the payload pointer empty
    1484           0 :       if(cfg->transmit.data != NULL) {
    1485           0 :         if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) {
    1486             :           // first 2 bytes of BLE payload are PDU header
    1487           0 :           state = writeBuffer(cfg->transmit.data, cfg->transmit.len, 2);
    1488             :         } else {
    1489           0 :           state = writeBuffer(cfg->transmit.data, cfg->transmit.len);
    1490             :         }
    1491           0 :         RADIOLIB_ASSERT(state);
    1492             :       }
    1493             : 
    1494             :       // set DIO mapping
    1495           0 :       state = setDioIrqParams(RADIOLIB_SX128X_IRQ_TX_DONE | RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT, RADIOLIB_SX128X_IRQ_TX_DONE);
    1496           0 :       RADIOLIB_ASSERT(state);
    1497             : 
    1498             :       // clear interrupt flags
    1499           0 :       state = clearIrqStatus();
    1500           0 :       RADIOLIB_ASSERT(state);
    1501           0 :     } break;
    1502             :     
    1503           0 :     default:
    1504           0 :       return(RADIOLIB_ERR_UNSUPPORTED);
    1505             :   }
    1506             : 
    1507           0 :   this->stagedMode = mode;
    1508           0 :   return(state);
    1509             : }
    1510             : 
    1511           3 : int16_t SX128x::writeTxBuffer(const uint8_t* data, size_t len) {
    1512           3 :   if(data == NULL) {
    1513           0 :     return(RADIOLIB_ERR_NULL_POINTER);
    1514             :   }
    1515           3 :   if(len > RADIOLIB_SX128X_MAX_PACKET_LENGTH) {
    1516           0 :     return(RADIOLIB_ERR_PACKET_TOO_LONG);
    1517             :   }
    1518             : 
    1519             :   // set buffer pointers
    1520           3 :   int16_t state = setBufferBaseAddress();
    1521           3 :   RADIOLIB_ASSERT(state);
    1522             : 
    1523             :   // first 2 bytes of BLE payload are PDU header
    1524           0 :   const uint8_t offset = (getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_BLE) ? 2 : 0;
    1525           0 :   return(writeBuffer(data, (uint8_t)len, offset));
    1526             : }
    1527             : 
    1528           3 : int16_t SX128x::clearTxBuffer() {
    1529             :   // the data buffer is overwritten by the next write, so there is nothing to discard
    1530           3 :   return(RADIOLIB_ERR_NONE);
    1531             : }
    1532             : 
    1533           3 : int16_t SX128x::launchMode() {
    1534             :   int16_t state;
    1535           3 :   switch(this->stagedMode) {
    1536           3 :     case(RADIOLIB_RADIO_MODE_RX): {
    1537           3 :       this->mod->setRfSwitchState(Module::MODE_RX);
    1538           3 :       state = setRx(this->rxTimeout);
    1539           3 :       RADIOLIB_ASSERT(state);
    1540           0 :     } break;
    1541             :   
    1542           0 :     case(RADIOLIB_RADIO_MODE_TX): {
    1543           0 :       this->mod->setRfSwitchState(Module::MODE_TX);
    1544           0 :       state = setTx(RADIOLIB_SX128X_TX_TIMEOUT_NONE);
    1545           0 :       RADIOLIB_ASSERT(state);
    1546             : 
    1547             :       // wait for BUSY to go low (= PA ramp up done)
    1548           0 :       while(this->mod->hal->digitalRead(this->mod->getGpio())) {
    1549           0 :         this->mod->hal->yield();
    1550             :       }
    1551           0 :     } break;
    1552             :     
    1553           0 :     default:
    1554           0 :       return(RADIOLIB_ERR_UNSUPPORTED);
    1555             :   }
    1556             : 
    1557           0 :   this->stagedMode = RADIOLIB_RADIO_MODE_NONE;
    1558           0 :   return(state);
    1559             : }
    1560             : 
    1561             : #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE
    1562           0 : void SX128x::setDirectAction(void (*func)(void)) {
    1563             :   // SX128x is unable to perform direct mode reception
    1564             :   // this method is implemented only for PhysicalLayer compatibility
    1565             :   (void)func;
    1566           0 : }
    1567             : 
    1568           0 : void SX128x::readBit(uint32_t pin) {
    1569             :   // SX128x is unable to perform direct mode reception
    1570             :   // this method is implemented only for PhysicalLayer compatibility
    1571             :   (void)pin;
    1572           0 : }
    1573             : #endif
    1574             : 
    1575           0 : Module* SX128x::getMod() {
    1576           0 :   return(this->mod);
    1577             : }
    1578             : 
    1579           0 : int16_t SX128x::modSetup(uint8_t modem) {
    1580             :   // set module properties
    1581           0 :   int16_t state = this->mod->init();
    1582           0 :   RADIOLIB_ASSERT(state);
    1583           0 :   this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
    1584           0 :   this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput);
    1585           0 :   this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16;
    1586           0 :   this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8;
    1587           0 :   this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8;
    1588           0 :   this->mod->spiConfig.statusPos = 0;
    1589           0 :   this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX128X_CMD_READ_REGISTER;
    1590           0 :   this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX128X_CMD_WRITE_REGISTER;
    1591           0 :   this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX128X_CMD_NOP;
    1592           0 :   this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX128X_CMD_GET_STATUS;
    1593           0 :   this->mod->spiConfig.stream = true;
    1594           0 :   this->mod->spiConfig.parseStatusCb = SPIparseStatus;
    1595             : 
    1596             :   // find the chip - this will also reset the module and verify the module
    1597           0 :   if(!SX128x::findChip(this->chipType)) {
    1598             :     RADIOLIB_DEBUG_BASIC_PRINTLN("No SX128x found!");
    1599           0 :     state = this->mod->term();
    1600           0 :     RADIOLIB_ASSERT(state);
    1601           0 :     return(RADIOLIB_ERR_CHIP_NOT_FOUND);
    1602             :   }
    1603             :   RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x");
    1604             : 
    1605             :   // configure settings not accessible by API
    1606           0 :   return(config(modem));
    1607             : }
    1608             : 
    1609           3 : uint8_t SX128x::getStatus() {
    1610           3 :   const uint8_t cmd = RADIOLIB_SX128X_CMD_GET_STATUS;
    1611           3 :   uint8_t data = 0;
    1612             :   
    1613             :   // unlike SX126x, the very first command byte sent is not reservedm, but the status
    1614             :   // to handle this correctly, we have to temporarily set the status width to 0,
    1615             :   // and then read one byte
    1616           3 :   this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_0;
    1617             : 
    1618             :   // additionally, to be fully comply with the datasheet, we have to send out the GetStatus command byte
    1619             :   // see https://github.com/jgromes/RadioLib/issues/1872 for details
    1620           3 :   this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX128X_CMD_GET_STATUS;
    1621           3 :   (void)this->mod->SPItransferStream(NULL, 0, false, &cmd, &data, 1, true);
    1622             : 
    1623             :   // restore everything, GetStatus is the only exchange which behaves like this
    1624           3 :   this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX128X_CMD_NOP;
    1625           3 :   this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8;
    1626           3 :   return(data);
    1627             : }
    1628             : 
    1629           0 : int16_t SX128x::writeRegister(uint16_t addr, const uint8_t* data, uint8_t numBytes) {
    1630           0 :   this->mod->SPIwriteRegisterBurst(addr, data, numBytes);
    1631           0 :   return(RADIOLIB_ERR_NONE);
    1632             : }
    1633             : 
    1634           0 : int16_t SX128x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) {
    1635             :   // send the command
    1636           0 :   this->mod->SPIreadRegisterBurst(addr, numBytes, data);
    1637             : 
    1638             :   // check the status
    1639           0 :   int16_t state = this->mod->SPIcheckStream();
    1640           0 :   return(state);
    1641             : }
    1642             : 
    1643           0 : int16_t SX128x::writeBuffer(const uint8_t* data, uint8_t numBytes, uint8_t offset) {
    1644           0 :   const uint8_t cmd[] = { RADIOLIB_SX128X_CMD_WRITE_BUFFER, offset };
    1645           0 :   return(this->mod->SPIwriteStream(cmd, 2, data, numBytes));
    1646             : }
    1647             : 
    1648           0 : int16_t SX128x::readBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) {
    1649           0 :   const uint8_t cmd[] = { RADIOLIB_SX128X_CMD_READ_BUFFER, offset };
    1650           0 :   return(this->mod->SPIreadStream(cmd, 2, data, numBytes));
    1651             : }
    1652             : 
    1653           0 : int16_t SX128x::setTx(uint16_t periodBaseCount, uint8_t periodBase) {
    1654           0 :   const uint8_t data[] = { periodBase, (uint8_t)((periodBaseCount >> 8) & 0xFF), (uint8_t)(periodBaseCount & 0xFF) };
    1655           0 :   return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_TX, data, 3));
    1656             : }
    1657             : 
    1658           3 : int16_t SX128x::setRx(uint16_t periodBaseCount, uint8_t periodBase) {
    1659           3 :   const uint8_t data[] = { periodBase, (uint8_t)((periodBaseCount >> 8) & 0xFF), (uint8_t)(periodBaseCount & 0xFF) };
    1660           6 :   return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RX, data, 3));
    1661             : }
    1662             : 
    1663           0 : int16_t SX128x::setCad(uint8_t symbolNum) {
    1664             :   // configure parameters
    1665           0 :   int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_CAD_PARAMS, &symbolNum, 1);
    1666           0 :   RADIOLIB_ASSERT(state);
    1667             : 
    1668             :   // start CAD
    1669           0 :   return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_CAD, NULL, 0));
    1670             : }
    1671             : 
    1672          87 : uint8_t SX128x::getPacketType() {
    1673          87 :   uint8_t data = 0xFF;
    1674          87 :   this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_PACKET_TYPE, &data, 1);
    1675          87 :   return(data);
    1676             : }
    1677             : 
    1678           0 : int16_t SX128x::setRfFrequency(uint32_t frf) {
    1679           0 :   const uint8_t data[] = { (uint8_t)((frf >> 16) & 0xFF), (uint8_t)((frf >> 8) & 0xFF), (uint8_t)(frf & 0xFF) };
    1680           0 :   return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RF_FREQUENCY, data, 3));
    1681             : }
    1682             : 
    1683           3 : int16_t SX128x::setTxParams(uint8_t pwr, uint8_t rampTime) {
    1684           3 :   const uint8_t data[] = { pwr, rampTime };
    1685           6 :   return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_TX_PARAMS, data, 2));
    1686             : }
    1687             : 
    1688           3 : int16_t SX128x::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) {
    1689           3 :   const uint8_t data[] = { txBaseAddress, rxBaseAddress };
    1690           6 :   return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2));
    1691             : }
    1692             : 
    1693           0 : int16_t SX128x::setModulationParams(uint8_t modParam1, uint8_t modParam2, uint8_t modParam3) {
    1694           0 :   const uint8_t data[] = { modParam1, modParam2, modParam3 };
    1695           0 :   return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_MODULATION_PARAMS, data, 3));
    1696             : }
    1697             : 
    1698           0 : int16_t SX128x::setPacketParamsGFSK(uint8_t preambleLen, uint8_t syncLen, uint8_t syncMatch, uint8_t crcLen, uint8_t whiten, uint8_t hdrType, uint8_t payLen) {
    1699           0 :   const uint8_t data[] = { preambleLen, syncLen, syncMatch, hdrType, payLen, crcLen, whiten };
    1700           0 :   return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7));
    1701             : }
    1702             : 
    1703           0 : int16_t SX128x::setPacketParamsBLE(uint8_t connState, uint8_t crcLen, uint8_t bleTest, uint8_t whiten) {
    1704           0 :   const uint8_t data[] = { connState, crcLen, bleTest, whiten, 0x00, 0x00, 0x00 };
    1705           0 :   return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7));
    1706             : }
    1707             : 
    1708           0 : int16_t SX128x::setPacketParamsLoRa(uint8_t preambleLen, uint8_t hdrType, uint8_t payLen, uint8_t crc, uint8_t invIQ) {
    1709           0 :   const uint8_t data[] = { preambleLen, hdrType, payLen, crc, invIQ, 0x00, 0x00 };
    1710           0 :   return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7));
    1711             : }
    1712             : 
    1713          12 : int16_t SX128x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) {
    1714          12 :   const uint8_t data[] = { (uint8_t)((irqMask >> 8) & 0xFF), (uint8_t)(irqMask & 0xFF),
    1715          12 :                      (uint8_t)((dio1Mask >> 8) & 0xFF), (uint8_t)(dio1Mask & 0xFF),
    1716          12 :                      (uint8_t)((dio2Mask >> 8) & 0xFF), (uint8_t)(dio2Mask & 0xFF),
    1717          12 :                      (uint8_t)((dio3Mask >> 8) & 0xFF), (uint8_t)(dio3Mask & 0xFF) };
    1718          24 :   return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_DIO_IRQ_PARAMS, data, 8));
    1719             : }
    1720             : 
    1721           3 : uint16_t SX128x::getIrqStatus() {
    1722           3 :   uint8_t data[] = { 0x00, 0x00 };
    1723           3 :   this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_IRQ_STATUS, data, 2);
    1724           3 :   return(((uint16_t)(data[0]) << 8) | data[1]);
    1725             : }
    1726             : 
    1727           6 : int16_t SX128x::clearIrqStatus(uint16_t clearIrqParams) {
    1728           6 :   const uint8_t data[] = { (uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF) };
    1729          12 :   return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_CLEAR_IRQ_STATUS, data, 2));
    1730             : }
    1731             : 
    1732           0 : int16_t SX128x::setRangingRole(uint8_t role) {
    1733           0 :   const uint8_t data[] = { role };
    1734           0 :   return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RANGING_ROLE, data, 1));
    1735             : }
    1736             : 
    1737           0 : int16_t SX128x::setPacketType(uint8_t type) {
    1738           0 :   const uint8_t data[] = { type };
    1739           0 :   return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_TYPE, data, 1));
    1740             : }
    1741             : 
    1742           0 : int16_t SX128x::setPacketMode(uint8_t mode, uint8_t len) {
    1743             :   // check active modem
    1744           0 :   uint8_t modem = getPacketType();
    1745           0 :   if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC))) {
    1746           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1747             :   }
    1748             : 
    1749             :   // set requested packet mode
    1750           0 :   int16_t state = setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, mode, len);
    1751           0 :   RADIOLIB_ASSERT(state);
    1752             : 
    1753             :   // update cached value
    1754           0 :   this->packetType = mode;
    1755           0 :   return(state);
    1756             : }
    1757             : 
    1758           0 : int16_t SX128x::setHeaderType(uint8_t hdrType, size_t len) {
    1759             :   // check active modem
    1760           0 :   uint8_t modem = getPacketType();
    1761           0 :   if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING))) {
    1762           0 :     return(RADIOLIB_ERR_WRONG_MODEM);
    1763             :   }
    1764             : 
    1765             :   // update packet parameters
    1766           0 :   this->headerType = hdrType;
    1767           0 :   this->payloadLen = len;
    1768           0 :   return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled));
    1769             : }
    1770             : 
    1771           0 : int16_t SX128x::config(uint8_t modem) {
    1772             :   // reset buffer base address
    1773           0 :   int16_t state = setBufferBaseAddress();
    1774           0 :   RADIOLIB_ASSERT(state);
    1775             : 
    1776             :   // set modem
    1777             :   uint8_t data[1];
    1778           0 :   data[0] = modem;
    1779           0 :   state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_TYPE, data, 1);
    1780           0 :   RADIOLIB_ASSERT(state);
    1781             : 
    1782             :   // set CAD parameters
    1783           0 :   data[0] = RADIOLIB_SX128X_CAD_ON_8_SYMB;
    1784           0 :   state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_CAD_PARAMS, data, 1);
    1785           0 :   RADIOLIB_ASSERT(state);
    1786             : 
    1787             :   // set regulator mode to DC-DC
    1788           0 :   data[0] = RADIOLIB_SX128X_REGULATOR_DC_DC;
    1789           0 :   state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_REGULATOR_MODE, data, 1);
    1790           0 :   RADIOLIB_ASSERT(state);
    1791             : 
    1792           0 :   return(RADIOLIB_ERR_NONE);
    1793             : }
    1794             : 
    1795           0 : int16_t SX128x::SPIparseStatus(uint8_t in) {
    1796           0 :   if((in & 0b00011100) == RADIOLIB_SX128X_STATUS_CMD_TIMEOUT) {
    1797           0 :     return(RADIOLIB_ERR_SPI_CMD_TIMEOUT);
    1798           0 :   } else if((in & 0b00011100) == RADIOLIB_SX128X_STATUS_CMD_ERROR) {
    1799           0 :     return(RADIOLIB_ERR_SPI_CMD_INVALID);
    1800           0 :   } else if((in & 0b00011100) == RADIOLIB_SX128X_STATUS_CMD_FAILED) {
    1801           0 :     return(RADIOLIB_ERR_SPI_CMD_FAILED);
    1802           0 :   } else if((in == 0x00) || (in == 0xFF)) {
    1803           0 :     return(RADIOLIB_ERR_CHIP_NOT_FOUND);
    1804             :   }
    1805           0 :   return(RADIOLIB_ERR_NONE);
    1806             : }
    1807             : 
    1808           0 : bool SX128x::findChip(const char* verStr) {
    1809           0 :   uint8_t i = 0;
    1810           0 :   bool flagFound = false;
    1811           0 :   while((i < 10) && !flagFound) {
    1812             :     // reset the module
    1813           0 :     reset(true);
    1814             : 
    1815             :     // read the version string
    1816           0 :     char version[16] = { 0 };
    1817           0 :     this->mod->SPIreadRegisterBurst(RADIOLIB_SX128X_REG_VERSION_STRING, 16, reinterpret_cast<uint8_t*>(version));
    1818             : 
    1819             :     // check version register
    1820           0 :     if(strncmp(verStr, version, 6) == 0) {
    1821             :       RADIOLIB_DEBUG_BASIC_PRINTLN("Found SX128x: RADIOLIB_SX128X_REG_VERSION_STRING:");
    1822             :       RADIOLIB_DEBUG_BASIC_HEXDUMP(reinterpret_cast<uint8_t*>(version), 16, RADIOLIB_SX128X_REG_VERSION_STRING);
    1823             :       RADIOLIB_DEBUG_BASIC_PRINTLN();
    1824           0 :       flagFound = true;
    1825             :     } else {
    1826             :       #if RADIOLIB_DEBUG_BASIC
    1827             :         RADIOLIB_DEBUG_BASIC_PRINTLN("SX128x not found! (%d of 10 tries) RADIOLIB_SX128X_REG_VERSION_STRING:", i + 1);
    1828             :         RADIOLIB_DEBUG_BASIC_HEXDUMP(reinterpret_cast<uint8_t*>(version), 16, RADIOLIB_SX128X_REG_VERSION_STRING);
    1829             :         RADIOLIB_DEBUG_BASIC_PRINTLN("Expected string: %s", verStr);
    1830             :       #endif
    1831           0 :       this->mod->hal->delay(10);
    1832           0 :       i++;
    1833             :     }
    1834             :   }
    1835             : 
    1836           0 :   return(flagFound);
    1837             : }
    1838             : 
    1839             : #endif

Generated by: LCOV version 1.14