/ 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