LCOV - code coverage report
Current view: top level - src/modules/SX128x - SX128x.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 258 1062 24.3 %
Date: 2026-10-11 07:31:10 Functions: 56 112 50.0 %

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

Generated by: LCOV version 1.14