/ RNode_Firmware_CE_G2 / sx128x.cpp
sx128x.cpp
  1  // Copyright Sandeep Mistry, Mark Qvist and Jacob Eva.
  2  // Licensed under the MIT license.
  3  
  4  #include "Boards.h"
  5  
  6  #if MODEM == SX1280
  7  #include "sx128x.h"
  8  
  9  #define MCU_1284P 0x91
 10  #define MCU_2560  0x92
 11  #define MCU_ESP32 0x81
 12  #define MCU_NRF52 0x71
 13  #if defined(__AVR_ATmega1284P__)
 14    #define PLATFORM PLATFORM_AVR
 15    #define MCU_VARIANT MCU_1284P
 16  #elif defined(__AVR_ATmega2560__)
 17    #define PLATFORM PLATFORM_AVR
 18    #define MCU_VARIANT MCU_2560
 19  #elif defined(ESP32)
 20    #define PLATFORM PLATFORM_ESP32
 21    #define MCU_VARIANT MCU_ESP32
 22  #elif defined(NRF52840_XXAA)
 23    #define PLATFORM PLATFORM_NRF52
 24    #define MCU_VARIANT MCU_NRF52
 25  #endif
 26  
 27  #ifndef MCU_VARIANT
 28    #error No MCU variant defined, cannot compile
 29  #endif
 30  
 31  #if MCU_VARIANT == MCU_ESP32
 32    #if MCU_VARIANT == MCU_ESP32 and !defined(CONFIG_IDF_TARGET_ESP32S3)
 33      #include "hal/wdt_hal.h"
 34    #endif
 35    #define ISR_VECT IRAM_ATTR
 36  #else
 37    #define ISR_VECT
 38  #endif
 39  
 40  // SX128x registers
 41  #define OP_RF_FREQ_8X               0x86
 42  #define OP_SLEEP_8X                 0x84
 43  #define OP_STANDBY_8X               0x80
 44  #define OP_TX_8X                    0x83
 45  #define OP_RX_8X                    0x82
 46  #define OP_SET_IRQ_FLAGS_8X         0x8D
 47  #define OP_CLEAR_IRQ_STATUS_8X      0x97
 48  #define OP_GET_IRQ_STATUS_8X        0x15
 49  #define OP_RX_BUFFER_STATUS_8X      0x17
 50  #define OP_PACKET_STATUS_8X         0x1D
 51  #define OP_CURRENT_RSSI_8X          0x1F
 52  #define OP_MODULATION_PARAMS_8X     0x8B
 53  #define OP_PACKET_PARAMS_8X         0x8C
 54  #define OP_STATUS_8X                0xC0
 55  #define OP_TX_PARAMS_8X             0x8E
 56  #define OP_PACKET_TYPE_8X           0x8A
 57  #define OP_BUFFER_BASE_ADDR_8X      0x8F
 58  #define OP_READ_REGISTER_8X         0x19
 59  #define OP_WRITE_REGISTER_8X        0x18
 60  #define IRQ_TX_DONE_MASK_8X         0x01
 61  #define IRQ_RX_DONE_MASK_8X         0x02
 62  #define IRQ_HEADER_DET_MASK_8X      0x10
 63  #define IRQ_HEADER_ERROR_MASK_8X    0x20
 64  #define IRQ_PAYLOAD_CRC_ERROR_MASK_8X 0x40
 65  
 66  #define MODE_LONG_RANGE_MODE_8X     0x01
 67  
 68  #define OP_FIFO_WRITE_8X            0x1A
 69  #define OP_FIFO_READ_8X             0x1B
 70  #define IRQ_PREAMBLE_DET_MASK_8X    0x80
 71  
 72  #define REG_PACKET_SIZE             0x901
 73  #define REG_FIRM_VER_MSB            0x154
 74  #define REG_FIRM_VER_LSB            0x153
 75  
 76  #define XTAL_FREQ_8X (double)52000000
 77  #define FREQ_DIV_8X (double)pow(2.0, 18.0)
 78  #define FREQ_STEP_8X (double)(XTAL_FREQ_8X / FREQ_DIV_8X)
 79  
 80  #if defined(NRF52840_XXAA)
 81    extern SPIClass spiModem;
 82    #define SPI spiModem
 83  #endif
 84  
 85  extern SPIClass SPI;
 86  
 87  #define MAX_PKT_LENGTH           255
 88  
 89  sx128x::sx128x() :
 90    _spiSettings(8E6, MSBFIRST, SPI_MODE0),
 91    _ss(LORA_DEFAULT_SS_PIN), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN), _rxen(pin_rxen), _busy(LORA_DEFAULT_BUSY_PIN), _txen(pin_txen),
 92    _frequency(0), _txp(0), _sf(0x05), _bw(0x34), _cr(0x01), _packetIndex(0), _implicitHeaderMode(0), _payloadLength(255), _crcMode(0), _fifo_tx_addr_ptr(0),
 93    _fifo_rx_addr_ptr(0), _rxPacketLength(0), _preinit_done(false), _tcxo(false) { setTimeout(0); }
 94  
 95  bool ISR_VECT sx128x::getPacketValidity() {
 96      uint8_t buf[2];
 97      buf[0] = 0x00;
 98      buf[1] = 0x00;
 99      executeOpcodeRead(OP_GET_IRQ_STATUS_8X, buf, 2);
100      executeOpcode(OP_CLEAR_IRQ_STATUS_8X, buf, 2);
101      if ((buf[1] & IRQ_PAYLOAD_CRC_ERROR_MASK_8X) == 0) { return true; }
102      else { return false; }
103  }
104  
105  void ISR_VECT sx128x::onDio0Rise() {
106      BaseType_t int_status = taskENTER_CRITICAL_FROM_ISR();
107      // On the SX1280, there is a bug which can cause the busy line
108      // to remain high if a high amount of packets are received when
109      // in continuous RX mode. This is documented as Errata 16.1 in
110      // the SX1280 datasheet v3.2 (page 149)
111      // Therefore, the modem is set into receive mode each time a packet is received.
112      if (sx128x_modem.getPacketValidity()) { sx128x_modem.receive(); sx128x_modem.handleDio0Rise(); }
113      else                                  { sx128x_modem.receive(); }
114  
115      taskEXIT_CRITICAL_FROM_ISR(int_status);
116  }
117  
118  void sx128x::handleDio0Rise() {
119      _packetIndex = 0;
120      uint8_t rxbuf[2] = {0};
121      executeOpcodeRead(OP_RX_BUFFER_STATUS_8X, rxbuf, 2);
122  
123      // If implicit header mode is enabled, use pre-set packet length as payload length instead.
124      // See SX1280 datasheet v3.2, page 92
125      if (_implicitHeaderMode == 0x80) { _rxPacketLength = _payloadLength; }
126      else                             { _rxPacketLength = rxbuf[0]; }
127  
128      if (_receive_callback) { _receive_callback(_rxPacketLength); }
129  }
130  
131  bool sx128x::preInit() {
132    pinMode(_ss, OUTPUT);
133    digitalWrite(_ss, HIGH);
134    
135    // TODO: Check if this change causes issues on any platforms
136    #if MCU_VARIANT == MCU_ESP32
137      #if BOARD_MODEL == BOARD_T3S3 || BOARD_MODEL == BOARD_HELTEC32_V3 || BOARD_MODEL == BOARD_HELTEC32_V4 || BOARD_MODEL == BOARD_TDECK
138        SPI.begin(pin_sclk, pin_miso, pin_mosi, pin_cs);
139      #else
140        SPI.begin();
141      #endif
142    #else
143      SPI.begin();
144    #endif
145  
146    // Detect modem (retry for up to 500ms)
147    long start = millis();
148    uint8_t version_msb;
149    uint8_t version_lsb;
150    while (((millis() - start) < 500) && (millis() >= start)) {
151        version_msb = readRegister(REG_FIRM_VER_MSB);
152        version_lsb = readRegister(REG_FIRM_VER_LSB);
153        if ((version_msb == 0xB7 && version_lsb == 0xA9) || (version_msb == 0xB5 && version_lsb == 0xA9)) { break; }
154        delay(100);
155    }
156  
157    if ((version_msb != 0xB7 || version_lsb != 0xA9) && (version_msb != 0xB5 || version_lsb != 0xA9)) { return false; }
158    _preinit_done = true;
159    return true;
160  }
161  
162  uint8_t ISR_VECT sx128x::readRegister(uint16_t address) { return singleTransfer(OP_READ_REGISTER_8X, address, 0x00); }
163  void sx128x::writeRegister(uint16_t address, uint8_t value) { singleTransfer(OP_WRITE_REGISTER_8X, address, value); }
164  
165  uint8_t ISR_VECT sx128x::singleTransfer(uint8_t opcode, uint16_t address, uint8_t value) {
166      waitOnBusy();
167      uint8_t response;
168      digitalWrite(_ss, LOW);
169  
170      SPI.beginTransaction(_spiSettings);
171      SPI.transfer(opcode);
172      SPI.transfer((address & 0xFF00) >> 8);
173      SPI.transfer(address & 0x00FF);
174      if (opcode == OP_READ_REGISTER_8X) { SPI.transfer(0x00); }
175      response = SPI.transfer(value);
176      SPI.endTransaction();
177      digitalWrite(_ss, HIGH);
178  
179      return response;
180  }
181  
182  void sx128x::rxAntEnable() {
183      if (_txen != -1) { digitalWrite(_txen, LOW); }
184      if (_rxen != -1) { digitalWrite(_rxen, HIGH); }
185  }
186  
187  void sx128x::txAntEnable() {
188      if (_txen != -1) { digitalWrite(_txen, HIGH); }
189      if (_rxen != -1) { digitalWrite(_rxen, LOW); }
190  }
191  
192  void sx128x::loraMode() {
193      uint8_t mode = MODE_LONG_RANGE_MODE_8X;
194      executeOpcode(OP_PACKET_TYPE_8X, &mode, 1);
195  }
196  
197  void sx128x::waitOnBusy() {
198    unsigned long time = millis();
199    while (digitalRead(_busy) == HIGH) {
200      if (millis() >= (time + 100)) { break; }
201    }
202  }
203  
204  void sx128x::executeOpcode(uint8_t opcode, uint8_t *buffer, uint8_t size) {
205      waitOnBusy();
206      digitalWrite(_ss, LOW);
207      SPI.beginTransaction(_spiSettings);
208      SPI.transfer(opcode);
209      for (int i = 0; i < size; i++) { SPI.transfer(buffer[i]); }
210      SPI.endTransaction();
211      digitalWrite(_ss, HIGH);
212  }
213  
214  void sx128x::executeOpcodeRead(uint8_t opcode, uint8_t *buffer, uint8_t size) {
215      waitOnBusy();
216      digitalWrite(_ss, LOW);
217      SPI.beginTransaction(_spiSettings);
218      SPI.transfer(opcode);
219      SPI.transfer(0x00);
220      for (int i = 0; i < size; i++) { buffer[i] = SPI.transfer(0x00); }
221      SPI.endTransaction();
222      digitalWrite(_ss, HIGH);
223  }
224  
225  void sx128x::writeBuffer(const uint8_t* buffer, size_t size) {
226      waitOnBusy();
227      digitalWrite(_ss, LOW);
228      SPI.beginTransaction(_spiSettings);
229      SPI.transfer(OP_FIFO_WRITE_8X);
230      SPI.transfer(_fifo_tx_addr_ptr);
231      for (int i = 0; i < size; i++) { SPI.transfer(buffer[i]); _fifo_tx_addr_ptr++; }
232      SPI.endTransaction();
233      digitalWrite(_ss, HIGH);
234  }
235  
236  void sx128x::readBuffer(uint8_t* buffer, size_t size) {
237      waitOnBusy();
238      digitalWrite(_ss, LOW);
239      SPI.beginTransaction(_spiSettings);
240      SPI.transfer(OP_FIFO_READ_8X);
241      SPI.transfer(_fifo_rx_addr_ptr);
242      SPI.transfer(0x00);
243      for (int i = 0; i < size; i++) { buffer[i] = SPI.transfer(0x00); }
244      SPI.endTransaction();
245      digitalWrite(_ss, HIGH);
246  }
247  
248  void sx128x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr) {
249    // because there is no access to these registers on the sx1280, we have
250    // to set all these parameters at once or not at all.
251    uint8_t buf[3];
252    buf[0] = sf << 4;
253    buf[1] = bw;
254    buf[2] = cr;
255    executeOpcode(OP_MODULATION_PARAMS_8X, buf, 3);
256  
257    if (sf <= 6) {      writeRegister(0x925, 0x1E); }
258    else if (sf <= 8) { writeRegister(0x925, 0x37); }
259    else if (sf >= 9) { writeRegister(0x925, 0x32); }
260    writeRegister(0x093C, 0x1);
261  }
262  
263  uint8_t preamble_e = 0;
264  uint8_t preamble_m = 0;
265  uint32_t last_me_result_target = 0;
266  extern long lora_preamble_symbols;
267  void sx128x::setPacketParams(uint32_t target_preamble_symbols, uint8_t headermode, uint8_t payload_length, uint8_t crc) {  
268    if (last_me_result_target != target_preamble_symbols) {
269      // Calculate exponent and mantissa values for modem
270      if (target_preamble_symbols >= 0xF000) target_preamble_symbols = 0xF000;
271      uint32_t calculated_preamble_symbols;
272      uint8_t e = 1;
273      uint8_t m = 1;
274      while (e <= 15) {
275        while (m <= 15) {
276          calculated_preamble_symbols = m * (pow(2,e));
277          if (calculated_preamble_symbols >= target_preamble_symbols-4) break;
278          m++;
279        }
280  
281        if (calculated_preamble_symbols >= target_preamble_symbols-4) break;
282        m = 1; e++;
283      }
284  
285      last_me_result_target = target_preamble_symbols;
286      lora_preamble_symbols = calculated_preamble_symbols+4;
287      _preambleLength = lora_preamble_symbols;
288  
289      preamble_e = e;
290      preamble_m = m;
291    }
292  
293    uint8_t buf[7];
294    buf[0] = (preamble_e << 4) | preamble_m;
295    buf[1] = headermode;
296    buf[2] = payload_length;
297    buf[3] = crc;
298    buf[4] = 0x40; // Standard IQ setting (no inversion)
299    buf[5] = 0x00; // Unused params
300    buf[6] = 0x00; 
301  
302    executeOpcode(OP_PACKET_PARAMS_8X, buf, 7);
303  }
304  
305  void sx128x::reset() {
306    if (_reset != -1) {
307      pinMode(_reset, OUTPUT);
308      digitalWrite(_reset, LOW);
309      delay(10);
310      digitalWrite(_reset, HIGH);
311      delay(10);
312    }
313  }
314  
315  int sx128x::begin(unsigned long frequency) {
316    reset();
317  
318    if (_rxen != -1) { pinMode(_rxen, OUTPUT); }
319    if (_txen != -1) { pinMode(_txen, OUTPUT); }
320    if (_busy != -1) { pinMode(_busy, INPUT); }
321  
322    if (!_preinit_done) {
323      if (!preInit()) {
324        return false;
325      }
326    }
327  
328    standby();
329    loraMode();
330    rxAntEnable();
331    setFrequency(frequency);
332  
333    // TODO: Implement LNA boost
334    //writeRegister(REG_LNA, 0x96);
335  
336    setModulationParams(_sf, _bw, _cr);
337    setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
338    setTxPower(_txp);
339  
340    // Set base addresses
341    uint8_t basebuf[2] = {0};
342    executeOpcode(OP_BUFFER_BASE_ADDR_8X, basebuf, 2);
343  
344    _radio_online = true;
345    return 1;
346  }
347  
348  void sx128x::end() {
349    sleep();
350    SPI.end();
351    _bitrate = 0;
352    _radio_online = false;
353    _preinit_done = false;
354  }
355  
356  int sx128x::beginPacket(int implicitHeader) {
357    standby();
358  
359    if (implicitHeader) { implicitHeaderMode(); }
360    else { explicitHeaderMode(); }
361  
362    _payloadLength = 0;
363    _fifo_tx_addr_ptr = 0;
364    setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
365  
366    return 1;
367  }
368  
369  int sx128x::endPacket() {
370    setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
371    txAntEnable();
372  
373    // Put in single TX mode
374    uint8_t timeout[3] = {0};
375    executeOpcode(OP_TX_8X, timeout, 3);
376  
377    uint8_t buf[2];
378    buf[0] = 0x00;
379    buf[1] = 0x00;
380    executeOpcodeRead(OP_GET_IRQ_STATUS_8X, buf, 2);
381  
382    // Wait for TX done
383    bool timed_out = false;
384    uint32_t w_timeout = millis()+LORA_MODEM_TIMEOUT_MS;
385    while ((millis() < w_timeout) && ((buf[1] & IRQ_TX_DONE_MASK_8X) == 0)) {
386      buf[0] = 0x00;
387      buf[1] = 0x00;
388      executeOpcodeRead(OP_GET_IRQ_STATUS_8X, buf, 2);
389      yield();
390    }
391  
392    if (!(millis() < w_timeout)) { timed_out = true; }
393  
394    // clear IRQ's
395    uint8_t mask[2];
396    mask[0] = 0x00;
397    mask[1] = IRQ_TX_DONE_MASK_8X;
398    executeOpcode(OP_CLEAR_IRQ_STATUS_8X, mask, 2);
399    
400    if (timed_out) { return 0; }
401    else           { return 1; }
402  }
403  
404  unsigned long preamble_detected_at = 0;
405  extern long lora_preamble_time_ms;
406  extern long lora_header_time_ms;
407  bool false_preamble_detected = false;
408  bool sx128x::dcd() {
409    uint8_t buf[2] = {0}; executeOpcodeRead(OP_GET_IRQ_STATUS_8X, buf, 2);
410    uint32_t now = millis();
411  
412    bool header_detected = false;
413    bool carrier_detected = false;
414  
415    if ((buf[1] & IRQ_HEADER_DET_MASK_8X) != 0) { header_detected = true; carrier_detected = true; }
416    else { header_detected = false; }
417  
418    if ((buf[0] & IRQ_PREAMBLE_DET_MASK_8X) != 0) {
419      carrier_detected = true;
420      if (preamble_detected_at == 0) { preamble_detected_at = now; }
421      if (now - preamble_detected_at > lora_preamble_time_ms + lora_header_time_ms) {
422        preamble_detected_at = 0;
423        if (!header_detected) { false_preamble_detected = true; }
424        uint8_t clearbuf[2]  = {0}; clearbuf[0] = IRQ_PREAMBLE_DET_MASK_8X;
425        executeOpcode(OP_CLEAR_IRQ_STATUS_8X, clearbuf, 2);
426      }
427    }
428  
429    // TODO: Maybe there's a way of unlatching the RSSI
430    // status without re-activating receive mode?
431    if (false_preamble_detected) { sx128x_modem.receive(); false_preamble_detected = false; }
432    return carrier_detected;
433  }
434  
435  
436  uint8_t sx128x::currentRssiRaw() {
437      uint8_t byte = 0;
438      executeOpcodeRead(OP_CURRENT_RSSI_8X, &byte, 1);
439      return byte;
440  }
441  
442  int ISR_VECT sx128x::currentRssi() {
443      uint8_t byte = 0;
444      executeOpcodeRead(OP_CURRENT_RSSI_8X, &byte, 1);
445      int rssi = -byte / 2;
446      return rssi;
447  }
448  
449  uint8_t sx128x::packetRssiRaw() {
450      uint8_t buf[5] = {0};
451      executeOpcodeRead(OP_PACKET_STATUS_8X, buf, 5);
452      return buf[0];
453  }
454  
455  int ISR_VECT sx128x::packetRssi(uint8_t pkt_snr_raw) {
456      // TODO: May need more calculations here
457      uint8_t buf[5] = {0};
458      executeOpcodeRead(OP_PACKET_STATUS_8X, buf, 5);
459      int pkt_rssi = -buf[0] / 2;
460      return pkt_rssi;
461  }
462  
463  uint8_t ISR_VECT sx128x::packetSnrRaw() {
464      uint8_t buf[5] = {0};
465      executeOpcodeRead(OP_PACKET_STATUS_8X, buf, 5);
466      return buf[1];
467  }
468  
469  float ISR_VECT sx128x::packetSnr() {
470      uint8_t buf[5] = {0};
471      executeOpcodeRead(OP_PACKET_STATUS_8X, buf, 5);
472      return float(buf[1]) * 0.25;
473  }
474  
475  long sx128x::packetFrequencyError() {
476    // TODO: Implement this, page 120 of sx1280 datasheet
477    int32_t freqError = 0;
478    const float fError = 0.0;
479    return static_cast<long>(fError);
480  }
481  
482  void sx128x::flush() { }
483  int ISR_VECT sx128x::available() { return _rxPacketLength - _packetIndex; }
484  size_t sx128x::write(uint8_t byte) { return write(&byte, sizeof(byte)); }
485  size_t sx128x::write(const uint8_t *buffer, size_t size) {
486    if ((_payloadLength + size) > MAX_PKT_LENGTH) { size = MAX_PKT_LENGTH - _payloadLength; }
487    writeBuffer(buffer, size);
488    _payloadLength = _payloadLength + size;
489    return size;
490  }
491  
492  int ISR_VECT sx128x::read() {
493    if (!available()) { return -1; }
494  
495    // If received new packet
496    if (_packetIndex == 0) {
497      uint8_t rxbuf[2] = {0};
498      executeOpcodeRead(OP_RX_BUFFER_STATUS_8X, rxbuf, 2);
499      int size;
500      
501      // If implicit header mode is enabled, read packet length as payload length instead.
502      // See SX1280 datasheet v3.2, page 92
503      if (_implicitHeaderMode == 0x80) {
504        size = _payloadLength;
505      } else {
506        size = rxbuf[0];
507      }
508  
509      _fifo_rx_addr_ptr = rxbuf[1];
510      if (size > 255) { size = 255; }
511  
512      readBuffer(_packet, size);
513    }
514  
515    uint8_t byte = _packet[_packetIndex];
516    _packetIndex++;
517    return byte;
518  }
519  
520  int sx128x::peek() {
521    if (!available()) { return -1; }
522    uint8_t b = _packet[_packetIndex];
523    return b;
524  }
525  
526  
527  void sx128x::onReceive(void(*callback)(int)) {
528    _receive_callback = callback;
529  
530    if (callback) {
531      pinMode(_dio0, INPUT);
532  
533      // Set preamble and header detection irqs, plus dio0 mask
534      uint8_t buf[8];
535  
536      // Set irq masks, enable all
537      buf[0] = 0xFF; 
538      buf[1] = 0xFF;
539  
540      // On the SX1280, no RxDone IRQ is generated if a packet is received with
541      // an invalid header, but the modem will be taken out of single RX mode.
542      // This can cause the modem to not receive packets until it is reset
543      // again. This is documented as Errata 16.2 in the SX1280 datasheet v3.2
544      // (page 150) Below, the header error IRQ is mapped to dio0 so that the
545      // modem can be set into RX mode again on reception of a corrupted
546      // header.
547      // set dio0 masks
548      buf[2] = 0x00;
549      buf[3] = IRQ_RX_DONE_MASK_8X | IRQ_HEADER_ERROR_MASK_8X; 
550  
551      // Set dio1 masks
552      buf[4] = 0x00; 
553      buf[5] = 0x00;
554  
555      // Set dio2 masks
556      buf[6] = 0x00; 
557      buf[7] = 0x00;
558  
559      executeOpcode(OP_SET_IRQ_FLAGS_8X, buf, 8);
560  
561      #ifdef SPI_HAS_NOTUSINGINTERRUPT
562          SPI.usingInterrupt(digitalPinToInterrupt(_dio0));
563      #endif
564  
565      attachInterrupt(digitalPinToInterrupt(_dio0), onDio0Rise, RISING);
566  
567    } else {
568      detachInterrupt(digitalPinToInterrupt(_dio0));
569      #ifdef SPI_HAS_NOTUSINGINTERRUPT
570        _spiModem->notUsingInterrupt(digitalPinToInterrupt(_dio0));
571      #endif
572    }
573  }
574  
575  void sx128x::receive(int size) {
576    if (size > 0) {
577      implicitHeaderMode();
578      // Tell radio payload length
579      //_rxPacketLength = size;
580      //_payloadLength = size;
581      //setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
582    } else {
583      explicitHeaderMode();
584    }
585  
586    rxAntEnable();
587  
588    // On the SX1280, there is a bug which can cause the busy line
589    // to remain high if a high amount of packets are received when
590    // in continuous RX mode. This is documented as Errata 16.1 in
591    // the SX1280 datasheet v3.2 (page 149)
592    // Therefore, the modem is set to single RX mode below instead.
593  
594    // uint8_t mode[3] = {0x03, 0xFF, 0xFF}; // Countinuous RX mode
595    uint8_t mode[3] = {0}; // single RX mode
596    executeOpcode(OP_RX_8X, mode, 3);
597  }
598  
599  void sx128x::standby() {
600      uint8_t byte = 0x01; // Always use STDBY_XOSC
601      executeOpcode(OP_STANDBY_8X, &byte, 1); 
602  }
603  
604  void sx128x::setPins(int ss, int reset, int dio0, int busy, int rxen, int txen) {
605    _ss = ss;
606    _reset = reset;
607    _dio0 = dio0;
608    _busy = busy;
609    _rxen = rxen;
610    _txen = txen;
611  }
612  
613  void sx128x::setTxPower(int level, int outputPin) {
614      uint8_t tx_buf[2];
615  
616      // RAK4631 with WisBlock SX1280 module (LIBSYS002)
617      #if BOARD_VARIANT == MODEL_13 || BOARD_VARIANT == MODEL_21
618        if (level > 27)     { level = 27; }
619        else if (level < 0) { level = 0; }
620  
621        _txp = level;
622        int reg_value;
623        switch (level) {
624          case 0:
625            reg_value = -18;
626            break;
627          case 1:
628            reg_value = -16;
629            break;
630          case 2:
631            reg_value = -15;
632            break;
633          case 3:
634            reg_value = -14;
635            break;
636          case 4:
637            reg_value = -13;
638            break;
639          case 5:
640            reg_value = -12;
641            break;
642          case 6:
643            reg_value = -11;
644            break;
645          case 7:
646            reg_value = -9;
647            break;
648          case 8:
649            reg_value = -8;
650            break;
651          case 9:
652            reg_value = -7;
653            break;
654          case 10:
655            reg_value = -6;
656            break;
657          case 11:
658            reg_value = -5;
659            break;
660          case 12:
661            reg_value = -4;
662            break;
663          case 13:
664            reg_value = -3;
665            break;
666          case 14:
667            reg_value = -2;
668            break;
669          case 15:
670            reg_value = -1;
671            break;
672          case 16:
673            reg_value = 0;
674            break;
675          case 17:
676            reg_value = 1;
677            break;
678          case 18:
679            reg_value = 2;
680            break;
681          case 19:
682            reg_value = 3;
683            break;
684          case 20:
685            reg_value = 4;
686            break;
687          case 21:
688            reg_value = 5;
689            break;
690          case 22:
691            reg_value = 6;
692            break;
693          case 23:
694            reg_value = 7;
695            break;
696          case 24:
697            reg_value = 8;
698            break;
699          case 25:
700            reg_value = 9;
701            break;
702          case 26:
703            reg_value = 12;
704            break;
705          case 27:
706            reg_value = 13;
707            break;
708          default:
709            reg_value = 0;
710            break;
711        }
712  
713        tx_buf[0] = reg_value + 18;
714        tx_buf[1] = 0xE0; // Ramping time, 20 microseconds
715        executeOpcode(OP_TX_PARAMS_8X, tx_buf, 2);
716  
717      // T3S3 SX1280 PA
718      #elif BOARD_VARIANT == MODEL_AC
719        if (level > 20) { level = 20; }
720        else if (level < 0) { level = 0; }
721  
722        _txp = level;
723        int reg_value;
724        switch (level) {
725          case 0:
726            reg_value = -18;
727            break;
728          case 1:
729            reg_value = -17;
730            break;
731          case 2:
732            reg_value = -16;
733            break;
734          case 3:
735            reg_value = -15;
736            break;
737          case 4:
738            reg_value = -14;
739            break;
740          case 5:
741            reg_value = -13;
742            break;
743          case 6:
744            reg_value = -12;
745            break;
746          case 7:
747            reg_value = -10;
748            break;
749          case 8:
750            reg_value = -9;
751            break;
752          case 9:
753            reg_value = -8;
754            break;
755          case 10:
756            reg_value = -7;
757            break;
758          case 11:
759            reg_value = -6;
760            break;
761          case 12:
762            reg_value = -5;
763            break;
764          case 13:
765            reg_value = -4;
766            break;
767          case 14:
768            reg_value = -3;
769            break;
770          case 15:
771            reg_value = -2;
772            break;
773          case 16:
774            reg_value = -1;
775            break;
776          case 17:
777            reg_value = 0;
778            break;
779          case 18:
780            reg_value = 1;
781            break;
782          case 19:
783            reg_value = 2;
784            break;
785          case 20:
786            reg_value = 3;
787            break;
788          default:
789            reg_value = 0;
790            break;
791        }
792        tx_buf[0] = reg_value;
793        tx_buf[1] = 0xE0; // Ramping time, 20 microseconds
794  
795      // For SX1280 boards with no specific PA requirements
796      #else
797        if (level > 13)       { level = 13; }
798        else if (level < -18) { level = -18; }
799        _txp = level;
800        tx_buf[0] = level + 18;
801        tx_buf[1] = 0xE0; // Ramping time, 20 microseconds
802      #endif
803      
804      executeOpcode(OP_TX_PARAMS_8X, tx_buf, 2);
805  }
806  
807  void sx128x::setFrequency(uint32_t frequency) {
808    _frequency = frequency;
809    uint8_t buf[3];
810    uint32_t freq = (uint32_t)((double)frequency / (double)FREQ_STEP_8X);
811    buf[0] = ((freq >> 16) & 0xFF);
812    buf[1] = ((freq >> 8) & 0xFF);
813    buf[2] = (freq & 0xFF);
814  
815    executeOpcode(OP_RF_FREQ_8X, buf, 3);
816  }
817  
818  uint32_t sx128x::getFrequency() {
819    // We can't read the frequency on the sx1280
820    uint32_t frequency = _frequency;
821    return frequency;
822  }
823  
824  void sx128x::setSpreadingFactor(int sf) {
825    if (sf < 5) { sf = 5; }
826    else if (sf > 12) { sf = 12; }
827    _sf = sf;
828  
829    setModulationParams(sf, _bw, _cr);
830    handleLowDataRate();
831  }
832  
833  uint32_t sx128x::getSignalBandwidth() {
834    int bw = _bw;
835    switch (bw) {
836      case 0x34: return 203.125E3;
837      case 0x26: return 406.25E3;
838      case 0x18: return 812.5E3;
839      case 0x0A: return 1625E3;
840    }
841    
842    return 0;
843  }
844  
845  void sx128x::setSignalBandwidth(uint32_t sbw) {
846    if      (sbw <= 203.125E3) { _bw = 0x34; }
847    else if (sbw <= 406.25E3)  { _bw = 0x26; }
848    else if (sbw <= 812.5E3)   { _bw = 0x18; }
849    else                       { _bw = 0x0A; }
850  
851    setModulationParams(_sf, _bw, _cr);
852    handleLowDataRate();
853    optimizeModemSensitivity();
854  }
855  
856  // TODO: add support for new interleaving scheme, see page 117 of sx1280 datasheet
857  void sx128x::setCodingRate4(int denominator) {
858    if (denominator < 5) { denominator = 5; }
859    else if (denominator > 8) { denominator = 8; }
860    _cr = denominator - 4;
861    setModulationParams(_sf, _bw, _cr);
862  }
863  
864  extern bool lora_low_datarate;
865  void sx128x::handleLowDataRate() {
866    if (_sf > 10) { lora_low_datarate = true; }
867    else          { lora_low_datarate = false; }
868  }
869  
870  void sx128x::optimizeModemSensitivity() { } // TODO: Check if there's anything the sx1280 can do here
871  uint8_t sx128x::getCodingRate4() { return _cr + 4; }
872  void sx128x::setPreambleLength(long preamble_symbols) { setPacketParams(preamble_symbols, _implicitHeaderMode, _payloadLength, _crcMode); }
873  void sx128x::setSyncWord(int sw) { } // TODO: Implement
874  void sx128x::enableTCXO() { } // TODO: Need to check how to implement on sx1280
875  void sx128x::disableTCXO() { } // TODO: Need to check how to implement on sx1280
876  void sx128x::sleep() { uint8_t byte = 0x00; executeOpcode(OP_SLEEP_8X, &byte, 1); }
877  uint8_t sx128x::getTxPower() { return _txp; }
878  uint8_t sx128x::getSpreadingFactor() { return _sf; }
879  void sx128x::enableCrc() { _crcMode = 0x20; setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); }
880  void sx128x::disableCrc() { _crcMode = 0; setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); }
881  void sx128x::setSPIFrequency(uint32_t frequency) { _spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0); }
882  void sx128x::explicitHeaderMode() {  _implicitHeaderMode = 0; setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); }
883  void sx128x::implicitHeaderMode() { _implicitHeaderMode = 0x80; setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); }
884  void sx128x::dumpRegisters(Stream& out) { for (int i = 0; i < 128; i++) { out.print("0x"); out.print(i, HEX); out.print(": 0x"); out.println(readRegister(i), HEX); } }
885  
886  sx128x sx128x_modem;
887  #endif