LUA: show protocol2 only on receivers with serial1_TX or PWM pins defined (#2999)
[ExpressLRS.git] / src / lib / SX1280Driver / SX1280.cpp
blob5a040ae33a4d27e225c8b62c89ceb55b4ac7ae71
1 #include "SX1280_Regs.h"
2 #include "SX1280_hal.h"
3 #include "SX1280.h"
4 #include "logging.h"
5 #include "RFAMP_hal.h"
6 #include <math.h>
8 SX1280Hal hal;
9 SX1280Driver *SX1280Driver::instance = NULL;
11 RFAMP_hal RFAMP;
13 //DEBUG_SX1280_OTA_TIMING
15 /* Steps for startup
17 1. If not in STDBY_RC mode, then go to this mode by sending the command:
18 SetStandby(STDBY_RC)
20 2. Define the LoRa® packet type by sending the command:
21 SetPacketType(PACKET_TYPE_LORA)
23 3. Define the RF frequency by sending the command:
24 SetRfFrequency(rfFrequency)
25 The LSB of rfFrequency is equal to the PLL step i.e. 52e6/2^18 Hz. SetRfFrequency() defines the Tx frequency.
27 4. Indicate the addresses where the packet handler will read (txBaseAddress in Tx) or write (rxBaseAddress in Rx) the first
28 byte of the data payload by sending the command:
29 SetBufferBaseAddress(txBaseAddress, rxBaseAddress)
30 Note:
31 txBaseAddress and rxBaseAddress are offset relative to the beginning of the data memory map.
33 5. Define the modulation parameter signal BW SF CR
36 #if defined(DEBUG_SX1280_OTA_TIMING)
37 static uint32_t beginTX;
38 static uint32_t endTX;
39 #endif
42 * Period Base from table 11-24, page 79 datasheet rev 3.2
43 * SX1280_RADIO_TICK_SIZE_0015_US = 15625 nanos
44 * SX1280_RADIO_TICK_SIZE_0062_US = 62500 nanos
45 * SX1280_RADIO_TICK_SIZE_1000_US = 1000000 nanos
46 * SX1280_RADIO_TICK_SIZE_4000_US = 4000000 nanos
48 #define RX_TIMEOUT_PERIOD_BASE SX1280_RADIO_TICK_SIZE_0015_US
49 #define RX_TIMEOUT_PERIOD_BASE_NANOS 15625
51 #ifdef USE_HARDWARE_DCDC
52 #ifndef OPT_USE_HARDWARE_DCDC
53 #define OPT_USE_HARDWARE_DCDC true
54 #endif
55 #else
56 #define OPT_USE_HARDWARE_DCDC false
57 #endif
59 SX1280Driver::SX1280Driver(): SX12xxDriverCommon()
61 instance = this;
62 timeout = 0xffff;
63 currOpmode = SX1280_MODE_SLEEP;
64 lastSuccessfulPacketRadio = SX12XX_Radio_1;
65 fallBackMode = SX1280_MODE_STDBY_RC;
68 void SX1280Driver::End()
70 if (currOpmode != SX1280_MODE_SLEEP)
72 SetMode(SX1280_MODE_SLEEP, SX12XX_Radio_All);
74 hal.end();
75 RFAMP.TXRXdisable();
76 RemoveCallbacks();
77 currFreq = (uint32_t)((double)2400000000 / (double)FREQ_STEP);
78 PayloadLength = 8; // Dummy default value which is overwritten during setup.
81 bool SX1280Driver::Begin(uint32_t minimumFrequency, uint32_t maximumFrequency)
83 hal.init();
84 hal.IsrCallback_1 = &SX1280Driver::IsrCallback_1;
85 hal.IsrCallback_2 = &SX1280Driver::IsrCallback_2;
87 hal.reset();
88 DBGLN("SX1280 Begin");
90 RFAMP.init();
92 SetMode(SX1280_MODE_STDBY_RC, SX12XX_Radio_All); // Put in STDBY_RC mode. Must be SX1280_MODE_STDBY_RC for SX1280_RADIO_SET_REGULATORMODE to be set.
94 uint16_t firmwareRev = (((hal.ReadRegister(REG_LR_FIRMWARE_VERSION_MSB, SX12XX_Radio_1)) << 8) | (hal.ReadRegister(REG_LR_FIRMWARE_VERSION_MSB + 1, SX12XX_Radio_1)));
95 DBGLN("Read Vers sx1280 #1: %d", firmwareRev);
96 if ((firmwareRev == 0) || (firmwareRev == 65535))
98 // SPI communication failed, just return without configuration
99 return false;
102 hal.WriteRegister(0x0891, (hal.ReadRegister(0x0891, SX12XX_Radio_1) | 0xC0), SX12XX_Radio_1); //default is low power mode, switch to high sensitivity instead
104 if (GPIO_PIN_NSS_2 != UNDEF_PIN)
106 firmwareRev = (((hal.ReadRegister(REG_LR_FIRMWARE_VERSION_MSB, SX12XX_Radio_2)) << 8) | (hal.ReadRegister(REG_LR_FIRMWARE_VERSION_MSB + 1, SX12XX_Radio_2)));
107 DBGLN("Read Vers sx1280 #2: %d", firmwareRev);
108 if ((firmwareRev == 0) || (firmwareRev == 65535))
110 // SPI communication failed, just return without configuration
111 return false;
114 hal.WriteRegister(0x0891, (hal.ReadRegister(0x0891, SX12XX_Radio_2) | 0xC0), SX12XX_Radio_2); //default is low power mode, switch to high sensitivity instead
117 #if defined(TARGET_RX)
118 fallBackMode = SX1280_MODE_FS;
119 hal.WriteCommand(SX1280_RADIO_SET_AUTOFS, 0x01, SX12XX_Radio_All); //Enable auto FS
120 #else
122 Do not enable for dual radio TX.
123 When SX1280_RADIO_SET_AUTOFS is set and tlm received by only 1 of the 2 radios, that radio will go into FS mode and the other
124 into Standby mode. After the following SPI command for tx mode, busy will go high for differing periods of time because 1 is
125 transitioning from FS mode and the other from Standby mode. This causes the tx done dio of the 2 radios to occur at very different times.
127 if (GPIO_PIN_NSS_2 == UNDEF_PIN)
129 fallBackMode = SX1280_MODE_FS;
130 hal.WriteCommand(SX1280_RADIO_SET_AUTOFS, 0x01, SX12XX_Radio_All); //Enable auto FS
132 #endif
134 // Force the next power update, and the lowest power
135 pwrCurrent = PWRPENDING_NONE;
136 SetOutputPower(SX1280_POWER_MIN);
137 CommitOutputPower();
138 #if defined(USE_HARDWARE_DCDC)
139 if (OPT_USE_HARDWARE_DCDC)
141 hal.WriteCommand(SX1280_RADIO_SET_REGULATORMODE, SX1280_USE_DCDC, SX12XX_Radio_All); // Enable DCDC converter instead of LDO
143 #endif
145 return true;
148 void SX1280Driver::startCWTest(uint32_t freq, SX12XX_Radio_Number_t radioNumber)
150 uint8_t buffer; // we just need a buffer for the write command
151 SetFrequencyHz(freq, radioNumber);
152 CommitOutputPower();
153 RFAMP.TXenable(radioNumber);
154 hal.WriteCommand(SX1280_RADIO_SET_TXCONTINUOUSWAVE, &buffer, 0, radioNumber);
157 void SX1280Driver::Config(uint8_t bw, uint8_t sf, uint8_t cr, uint32_t regfreq,
158 uint8_t PreambleLength, bool InvertIQ, uint8_t _PayloadLength, uint32_t interval,
159 uint32_t flrcSyncWord, uint16_t flrcCrcSeed, uint8_t flrc)
161 uint8_t const mode = (flrc) ? SX1280_PACKET_TYPE_FLRC : SX1280_PACKET_TYPE_LORA;
163 PayloadLength = _PayloadLength;
164 IQinverted = InvertIQ;
165 packet_mode = mode;
166 SetMode(SX1280_MODE_STDBY_RC, SX12XX_Radio_All);
167 hal.WriteCommand(SX1280_RADIO_SET_PACKETTYPE, mode, SX12XX_Radio_All, 20);
168 if (mode == SX1280_PACKET_TYPE_FLRC)
170 DBG("Config FLRC ");
171 ConfigModParamsFLRC(bw, cr, sf);
172 SetPacketParamsFLRC(SX1280_FLRC_PACKET_FIXED_LENGTH, PreambleLength, _PayloadLength, flrcSyncWord, flrcCrcSeed, cr);
174 else
176 DBG("Config LoRa ");
177 ConfigModParamsLoRa(bw, sf, cr);
178 #if defined(DEBUG_FREQ_CORRECTION)
179 SX1280_RadioLoRaPacketLengthsModes_t packetLengthType = SX1280_LORA_PACKET_VARIABLE_LENGTH;
180 #else
181 SX1280_RadioLoRaPacketLengthsModes_t packetLengthType = SX1280_LORA_PACKET_FIXED_LENGTH;
182 #endif
183 SetPacketParamsLoRa(PreambleLength, packetLengthType, _PayloadLength, InvertIQ);
185 SetFrequencyReg(regfreq);
186 SetRxTimeoutUs(interval);
188 uint16_t dio1Mask = SX1280_IRQ_TX_DONE | SX1280_IRQ_RX_DONE;
189 uint16_t irqMask = SX1280_IRQ_TX_DONE | SX1280_IRQ_RX_DONE | SX1280_IRQ_SYNCWORD_VALID | SX1280_IRQ_SYNCWORD_ERROR | SX1280_IRQ_CRC_ERROR;
190 SetDioIrqParams(irqMask, dio1Mask);
193 void SX1280Driver::SetRxTimeoutUs(uint32_t interval)
195 if (interval)
197 timeout = interval * 1000 / RX_TIMEOUT_PERIOD_BASE_NANOS; // number of periods for the SX1280 to timeout
199 else
201 timeout = 0xFFFF; // no timeout, continuous mode
205 /***
206 * @brief: Schedule an output power change after the next transmit
207 ***/
208 void SX1280Driver::SetOutputPower(int8_t power)
210 uint8_t pwrNew = constrain(power, SX1280_POWER_MIN, SX1280_POWER_MAX) + (-SX1280_POWER_MIN);
212 if ((pwrPending == PWRPENDING_NONE && pwrCurrent != pwrNew) || pwrPending != pwrNew)
214 pwrPending = pwrNew;
215 DBGLN("SetPower: %u", pwrPending);
219 void ICACHE_RAM_ATTR SX1280Driver::CommitOutputPower()
221 if (pwrPending == PWRPENDING_NONE)
222 return;
224 pwrCurrent = pwrPending;
225 pwrPending = PWRPENDING_NONE;
226 uint8_t buf[2] = { pwrCurrent, (uint8_t)SX1280_RADIO_RAMP_04_US };
227 hal.WriteCommand(SX1280_RADIO_SET_TXPARAMS, buf, sizeof(buf), SX12XX_Radio_All);
230 void SX1280Driver::SetMode(SX1280_RadioOperatingModes_t OPmode, SX12XX_Radio_Number_t radioNumber, uint32_t incomingTimeout)
233 Comment out since it is difficult to keep track of dual radios.
234 When checking SPI it is also useful to see every possible SPI transaction to make sure it fits when required.
236 // if (OPmode == currOpmode)
237 // {
238 // return;
239 // }
241 WORD_ALIGNED_ATTR uint8_t buf[3];
242 uint16_t tempTimeout;
244 switch (OPmode)
247 case SX1280_MODE_SLEEP:
248 hal.WriteCommand(SX1280_RADIO_SET_SLEEP, (uint8_t)0x01, radioNumber);
249 break;
251 case SX1280_MODE_CALIBRATION:
252 break;
254 case SX1280_MODE_STDBY_RC:
255 hal.WriteCommand(SX1280_RADIO_SET_STANDBY, SX1280_STDBY_RC, radioNumber, 1500);
256 break;
258 // The DC-DC supply regulation is automatically powered in STDBY_XOSC mode.
259 case SX1280_MODE_STDBY_XOSC:
260 hal.WriteCommand(SX1280_RADIO_SET_STANDBY, SX1280_STDBY_XOSC, radioNumber, 50);
261 break;
263 case SX1280_MODE_FS:
264 hal.WriteCommand(SX1280_RADIO_SET_FS, (uint8_t)0x00, radioNumber, 70);
265 break;
267 case SX1280_MODE_RX:
268 tempTimeout = incomingTimeout ? (incomingTimeout * 1000 / RX_TIMEOUT_PERIOD_BASE_NANOS) : timeout;
269 buf[0] = RX_TIMEOUT_PERIOD_BASE;
270 buf[1] = tempTimeout >> 8;
271 buf[2] = tempTimeout & 0xFF;
272 hal.WriteCommand(SX1280_RADIO_SET_RX, buf, sizeof(buf), radioNumber, 100);
273 break;
275 case SX1280_MODE_RX_CONT:
276 buf[0] = RX_TIMEOUT_PERIOD_BASE;
277 buf[1] = 0xFFFF >> 8;
278 buf[2] = 0xFFFF & 0xFF;
279 hal.WriteCommand(SX1280_RADIO_SET_RX, buf, sizeof(buf), radioNumber, 100);
280 break;
282 case SX1280_MODE_TX:
283 //uses timeout Time-out duration = periodBase * periodBaseCount
284 buf[0] = RX_TIMEOUT_PERIOD_BASE;
285 buf[1] = 0xFF; // no timeout set for now
286 buf[2] = 0xFF; // TODO dynamic timeout based on expected onairtime
287 hal.WriteCommand(SX1280_RADIO_SET_TX, buf, sizeof(buf), radioNumber, 100);
288 break;
290 case SX1280_MODE_CAD:
291 break;
293 default:
294 break;
297 currOpmode = OPmode;
300 void SX1280Driver::ConfigModParamsLoRa(uint8_t bw, uint8_t sf, uint8_t cr)
302 // Care must therefore be taken to ensure that modulation parameters are set using the command
303 // SetModulationParam() only after defining the packet type SetPacketType() to be used
305 WORD_ALIGNED_ATTR uint8_t rfparams[3] = {sf, bw, cr};
307 hal.WriteCommand(SX1280_RADIO_SET_MODULATIONPARAMS, rfparams, sizeof(rfparams), SX12XX_Radio_All, 25);
309 switch (sf)
311 case SX1280_LORA_SF5:
312 case SX1280_LORA_SF6:
313 hal.WriteRegister(SX1280_REG_SF_ADDITIONAL_CONFIG, 0x1E, SX12XX_Radio_All); // for SF5 or SF6
314 break;
315 case SX1280_LORA_SF7:
316 case SX1280_LORA_SF8:
317 hal.WriteRegister(SX1280_REG_SF_ADDITIONAL_CONFIG, 0x37, SX12XX_Radio_All); // for SF7 or SF8
318 break;
319 default:
320 hal.WriteRegister(SX1280_REG_SF_ADDITIONAL_CONFIG, 0x32, SX12XX_Radio_All); // for SF9, SF10, SF11, SF12
322 // Datasheet in LoRa Operation says "After SetModulationParams command:
323 // In all cases 0x1 must be written to the Frequency Error Compensation mode register 0x093C"
324 // However, this causes CRC errors for SF9 when using a high deviation TX (145kHz) and not using Explicit Header mode.
325 // The default register value (0x1b) seems most compatible, so don't mess with it
326 // InvertIQ=0 0x00=No reception 0x01=Poor reception w/o Explicit Header 0x02=OK 0x03=OK
327 // InvertIQ=1 0x00, 0x01, 0x02, and 0x03=Poor reception w/o Explicit Header
328 // hal.WriteRegister(SX1280_REG_FREQ_ERR_CORRECTION, 0x03, SX12XX_Radio_All);
331 void SX1280Driver::SetPacketParamsLoRa(uint8_t PreambleLength, SX1280_RadioLoRaPacketLengthsModes_t HeaderType,
332 uint8_t PayloadLength, uint8_t InvertIQ)
334 uint8_t buf[7];
336 buf[0] = PreambleLength;
337 buf[1] = HeaderType;
338 buf[2] = PayloadLength;
339 buf[3] = SX1280_LORA_CRC_OFF;
340 buf[4] = InvertIQ ? SX1280_LORA_IQ_INVERTED : SX1280_LORA_IQ_NORMAL;
341 buf[5] = 0x00;
342 buf[6] = 0x00;
344 hal.WriteCommand(SX1280_RADIO_SET_PACKETPARAMS, buf, sizeof(buf), SX12XX_Radio_All, 20);
346 // FEI only triggers in Lora mode when the header is present :(
347 modeSupportsFei = HeaderType == SX1280_LORA_PACKET_VARIABLE_LENGTH;
350 void SX1280Driver::ConfigModParamsFLRC(uint8_t bw, uint8_t cr, uint8_t bt)
352 WORD_ALIGNED_ATTR uint8_t rfparams[3] = {bw, cr, bt};
353 hal.WriteCommand(SX1280_RADIO_SET_MODULATIONPARAMS, rfparams, sizeof(rfparams), SX12XX_Radio_All, 110);
356 void SX1280Driver::SetPacketParamsFLRC(uint8_t HeaderType,
357 uint8_t PreambleLength,
358 uint8_t PayloadLength,
359 uint32_t syncWord,
360 uint16_t crcSeed,
361 uint8_t cr)
363 if (PreambleLength < 8)
364 PreambleLength = 8;
365 PreambleLength = ((PreambleLength / 4) - 1) << 4;
367 uint8_t buf[7];
368 buf[0] = PreambleLength; // AGCPreambleLength
369 buf[1] = SX1280_FLRC_SYNC_WORD_LEN_P32S; // SyncWordLength
370 buf[2] = SX1280_FLRC_RX_MATCH_SYNC_WORD_1; // SyncWordMatch
371 buf[3] = HeaderType; // PacketType
372 buf[4] = PayloadLength; // PayloadLength
373 buf[5] = SX1280_FLRC_CRC_3_BYTE; // CrcLength
374 buf[6] = 0x08; // Must be whitening disabled
375 hal.WriteCommand(SX1280_RADIO_SET_PACKETPARAMS, buf, sizeof(buf), SX12XX_Radio_All, 30);
377 // CRC seed (use dedicated cipher)
378 buf[0] = (uint8_t)(crcSeed >> 8);
379 buf[1] = (uint8_t)crcSeed;
380 hal.WriteRegister(SX1280_REG_FLRC_CRC_SEED, buf, 2, SX12XX_Radio_All);
382 // Set SyncWord1
383 buf[0] = (uint8_t)(syncWord >> 24);
384 buf[1] = (uint8_t)(syncWord >> 16);
385 buf[2] = (uint8_t)(syncWord >> 8);
386 buf[3] = (uint8_t)syncWord;
388 // DS_SX1280-1_V3.2.pdf - 16.4 FLRC Modem: Increased PER in FLRC Packets with Synch Word
389 if (((cr == SX1280_FLRC_CR_1_2) || (cr == SX1280_FLRC_CR_3_4)) &&
390 ((buf[0] == 0x8C && buf[1] == 0x38) || (buf[0] == 0x63 && buf[1] == 0x0E)))
392 uint8_t temp = buf[0];
393 buf[0] = buf[1];
394 buf[1] = temp;
395 // For SX1280_FLRC_CR_3_4 the datasheet also says
396 // "In addition to this the two LSB values XX XX must not be in the range 0x0000 to 0x3EFF"
397 if (cr == SX1280_FLRC_CR_3_4 && buf[3] <= 0x3e)
398 buf[3] |= 0x80; // 0x80 or 0x40 would work
401 hal.WriteRegister(SX1280_REG_FLRC_SYNC_WORD, buf, 4, SX12XX_Radio_All);
403 // FEI only works in Lora and Ranging mode
404 modeSupportsFei = false;
407 void ICACHE_RAM_ATTR SX1280Driver::SetFrequencyHz(uint32_t freq, SX12XX_Radio_Number_t radioNumber)
409 uint32_t regfreq = (uint32_t)((double)freq / (double)FREQ_STEP);
411 SetFrequencyReg(regfreq, radioNumber);
414 void ICACHE_RAM_ATTR SX1280Driver::SetFrequencyReg(uint32_t regfreq, SX12XX_Radio_Number_t radioNumber)
416 WORD_ALIGNED_ATTR uint8_t buf[3] = {0};
418 buf[0] = (uint8_t)((regfreq >> 16) & 0xFF);
419 buf[1] = (uint8_t)((regfreq >> 8) & 0xFF);
420 buf[2] = (uint8_t)(regfreq & 0xFF);
422 hal.WriteCommand(SX1280_RADIO_SET_RFFREQUENCY, buf, sizeof(buf), radioNumber);
424 currFreq = regfreq;
427 void SX1280Driver::SetFIFOaddr(uint8_t txBaseAddr, uint8_t rxBaseAddr)
429 uint8_t buf[2];
431 buf[0] = txBaseAddr;
432 buf[1] = rxBaseAddr;
433 hal.WriteCommand(SX1280_RADIO_SET_BUFFERBASEADDRESS, buf, sizeof(buf), SX12XX_Radio_All);
436 void SX1280Driver::SetDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask)
438 uint8_t buf[8];
440 buf[0] = (uint8_t)((irqMask >> 8) & 0x00FF);
441 buf[1] = (uint8_t)(irqMask & 0x00FF);
442 buf[2] = (uint8_t)((dio1Mask >> 8) & 0x00FF);
443 buf[3] = (uint8_t)(dio1Mask & 0x00FF);
444 buf[4] = (uint8_t)((dio2Mask >> 8) & 0x00FF);
445 buf[5] = (uint8_t)(dio2Mask & 0x00FF);
446 buf[6] = (uint8_t)((dio3Mask >> 8) & 0x00FF);
447 buf[7] = (uint8_t)(dio3Mask & 0x00FF);
449 hal.WriteCommand(SX1280_RADIO_SET_DIOIRQPARAMS, buf, sizeof(buf), SX12XX_Radio_All);
452 uint16_t ICACHE_RAM_ATTR SX1280Driver::GetIrqStatus(SX12XX_Radio_Number_t radioNumber)
454 uint8_t status[2];
456 hal.ReadCommand(SX1280_RADIO_GET_IRQSTATUS, status, 2, radioNumber);
457 return status[0] << 8 | status[1];
460 void ICACHE_RAM_ATTR SX1280Driver::ClearIrqStatus(uint16_t irqMask, SX12XX_Radio_Number_t radioNumber)
462 uint8_t buf[2];
464 buf[0] = (uint8_t)(((uint16_t)irqMask >> 8) & 0x00FF);
465 buf[1] = (uint8_t)((uint16_t)irqMask & 0x00FF);
467 hal.WriteCommand(SX1280_RADIO_CLR_IRQSTATUS, buf, sizeof(buf), radioNumber);
470 void ICACHE_RAM_ATTR SX1280Driver::TXnbISR()
472 currOpmode = SX1280_MODE_FS; // radio goes to FS after TX
473 #ifdef DEBUG_SX1280_OTA_TIMING
474 endTX = micros();
475 DBGLN("TOA: %d", endTX - beginTX);
476 #endif
477 CommitOutputPower();
478 TXdoneCallback();
481 void ICACHE_RAM_ATTR SX1280Driver::TXnb(uint8_t * data, uint8_t size, SX12XX_Radio_Number_t radioNumber)
483 transmittingRadio = radioNumber;
485 //catch TX timeout
486 if (currOpmode == SX1280_MODE_TX)
488 DBGLN("Timeout!");
489 SetMode(fallBackMode, SX12XX_Radio_All);
490 ClearIrqStatus(SX1280_IRQ_RADIO_ALL, SX12XX_Radio_All);
491 TXnbISR();
492 return;
495 if (radioNumber == SX12XX_Radio_NONE)
497 instance->SetMode(fallBackMode, SX12XX_Radio_All);
498 return;
501 #if defined(DEBUG_RCVR_SIGNAL_STATS)
502 if (radioNumber == SX12XX_Radio_All || radioNumber == SX12XX_Radio_1)
504 instance->rxSignalStats[0].telem_count++;
506 if (radioNumber == SX12XX_Radio_All || radioNumber == SX12XX_Radio_2)
508 instance->rxSignalStats[1].telem_count++;
510 #endif
512 // Normal diversity mode
513 if (GPIO_PIN_NSS_2 != UNDEF_PIN && radioNumber != SX12XX_Radio_All)
515 // Make sure the unused radio is in FS mode and will not receive the tx packet.
516 if (radioNumber == SX12XX_Radio_1)
518 instance->SetMode(fallBackMode, SX12XX_Radio_2);
520 else
522 instance->SetMode(fallBackMode, SX12XX_Radio_1);
526 RFAMP.TXenable(radioNumber); // do first to allow PA stablise
527 hal.WriteBuffer(0x00, data, size, radioNumber); //todo fix offset to equal fifo addr
528 instance->SetMode(SX1280_MODE_TX, radioNumber);
530 #ifdef DEBUG_SX1280_OTA_TIMING
531 beginTX = micros();
532 #endif
535 bool ICACHE_RAM_ATTR SX1280Driver::RXnbISR(uint16_t irqStatus, SX12XX_Radio_Number_t radioNumber)
537 // In continuous receive mode, the device stays in Rx mode
538 if (timeout != 0xFFFF)
540 // From table 11-28, pg 81 datasheet rev 3.2
541 // upon successsful receipt, when the timer is active or in single mode, it returns to STDBY_RC
542 // but because we have AUTO_FS enabled we automatically transition to state SX1280_MODE_FS
543 currOpmode = SX1280_MODE_FS;
546 rx_status fail = SX12XX_RX_OK;
547 // The SYNCWORD_VALID bit isn't set on LoRa, it has no synch (sic) word, and CRC is only on for FLRC
548 if (packet_mode == SX1280_PACKET_TYPE_FLRC)
550 fail = ((irqStatus & SX1280_IRQ_CRC_ERROR) ? SX12XX_RX_CRC_FAIL : SX12XX_RX_OK) |
551 ((irqStatus & SX1280_IRQ_SYNCWORD_VALID) ? SX12XX_RX_OK : SX12XX_RX_SYNCWORD_ERROR) |
552 ((irqStatus & SX1280_IRQ_SYNCWORD_ERROR) ? SX12XX_RX_SYNCWORD_ERROR : SX12XX_RX_OK);
554 if (fail == SX12XX_RX_OK)
556 uint8_t const FIFOaddr = GetRxBufferAddr(radioNumber);
557 hal.ReadBuffer(FIFOaddr, RXdataBuffer, PayloadLength, radioNumber);
560 return RXdoneCallback(fail);
563 void ICACHE_RAM_ATTR SX1280Driver::RXnb(SX1280_RadioOperatingModes_t rxMode, uint32_t incomingTimeout)
565 RFAMP.RXenable();
566 SetMode(rxMode, SX12XX_Radio_All, incomingTimeout);
569 uint8_t ICACHE_RAM_ATTR SX1280Driver::GetRxBufferAddr(SX12XX_Radio_Number_t radioNumber)
571 WORD_ALIGNED_ATTR uint8_t status[2] = {0};
572 hal.ReadCommand(SX1280_RADIO_GET_RXBUFFERSTATUS, status, 2, radioNumber);
573 return status[1];
576 void ICACHE_RAM_ATTR SX1280Driver::GetStatus(SX12XX_Radio_Number_t radioNumber)
578 uint8_t status = 0;
579 hal.ReadCommand(SX1280_RADIO_GET_STATUS, (uint8_t *)&status, 1, radioNumber);
580 DBGLN("Status: %x, %x, %x", (0b11100000 & status) >> 5, (0b00011100 & status) >> 2, 0b00000001 & status);
583 bool ICACHE_RAM_ATTR SX1280Driver::GetFrequencyErrorbool()
585 // Only need the highest bit of the 20-bit FEI to determine the direction
586 uint8_t feiMsb = hal.ReadRegister(SX1280_REG_LR_ESTIMATED_FREQUENCY_ERROR_MSB, lastSuccessfulPacketRadio);
587 // fei & (1 << 19) and flip sign if IQinverted
588 if (feiMsb & 0x08)
589 return IQinverted;
590 else
591 return !IQinverted;
594 int8_t ICACHE_RAM_ATTR SX1280Driver::GetRssiInst(SX12XX_Radio_Number_t radioNumber)
596 uint8_t status = 0;
598 hal.ReadCommand(SX1280_RADIO_GET_RSSIINST, (uint8_t *)&status, 1, radioNumber);
599 return -(int8_t)(status / 2);
602 void ICACHE_RAM_ATTR SX1280Driver::GetLastPacketStats()
604 SX12XX_Radio_Number_t radio[2] = {SX12XX_Radio_1, SX12XX_Radio_2};
605 bool gotRadio[2] = {false, false}; // one-radio default.
606 uint8_t processingRadioIdx = (instance->processingPacketRadio == SX12XX_Radio_1) ? 0 : 1;
607 uint8_t secondRadioIdx = !processingRadioIdx;
609 // processingRadio always passed the sanity check here
610 gotRadio[processingRadioIdx] = true;
612 // if it's a dual radio, and if it's the first IRQ
613 // (don't need this if it's the second IRQ, because we know the first IRQ is already failed)
614 if (instance->isFirstRxIrq && GPIO_PIN_NSS_2 != UNDEF_PIN)
616 bool isSecondRadioGotData = false;
618 uint16_t secondIrqStatus = instance->GetIrqStatus(radio[secondRadioIdx]);
619 if(secondIrqStatus&SX1280_IRQ_RX_DONE)
621 rx_status second_rx_fail = SX12XX_RX_OK;
622 if (packet_mode == SX1280_PACKET_TYPE_FLRC)
624 second_rx_fail = ((secondIrqStatus & SX1280_IRQ_CRC_ERROR) ? SX12XX_RX_CRC_FAIL : SX12XX_RX_OK) |
625 ((secondIrqStatus & SX1280_IRQ_SYNCWORD_VALID) ? SX12XX_RX_OK : SX12XX_RX_SYNCWORD_ERROR) |
626 ((secondIrqStatus & SX1280_IRQ_SYNCWORD_ERROR) ? SX12XX_RX_SYNCWORD_ERROR : SX12XX_RX_OK);
628 if (second_rx_fail == SX12XX_RX_OK)
630 uint8_t const FIFOaddr = GetRxBufferAddr(radio[secondRadioIdx]);
631 WORD_ALIGNED_ATTR uint8_t RXdataBuffer_second[RXBuffSize];
632 hal.ReadBuffer (FIFOaddr, RXdataBuffer_second, PayloadLength, radio[secondRadioIdx]);
634 // if the second packet is same to the first, it's valid
635 if(memcmp(RXdataBuffer, RXdataBuffer_second, PayloadLength) == 0)
637 isSecondRadioGotData = true;
642 // second radio received the same packet to the processing radio
643 gotRadio[secondRadioIdx] = isSecondRadioGotData;
644 #if defined(DEBUG_RCVR_SIGNAL_STATS)
645 if(!isSecondRadioGotData)
647 instance->rxSignalStats[secondRadioIdx].fail_count++;
649 #endif
652 uint8_t status[2];
653 int8_t rssi[2];
654 int8_t snr[2];
656 for(uint8_t i=0;i<2;i++)
658 if (gotRadio[i])
660 hal.ReadCommand(SX1280_RADIO_GET_PACKETSTATUS, status, 2, radio[i]);
662 if (packet_mode == SX1280_PACKET_TYPE_FLRC)
664 // No SNR in FLRC mode
665 rssi[i] = -(int8_t)(status[1] / 2);
666 snr[i] = 0;
668 else
670 // LoRa mode has both RSSI and SNR
671 rssi[i] = -(int8_t)(status[0] / 2);
672 snr[i] = (int8_t)status[1];
674 // https://www.mouser.com/datasheet/2/761/DS_SX1280-1_V2.2-1511144.pdf p84
675 // need to subtract SNR from RSSI when SNR <= 0;
676 int8_t negOffset = (snr[i] < 0) ? (snr[i] / RADIO_SNR_SCALE) : 0;
677 rssi[i] += negOffset;
680 // If radio # is 0, update LastPacketRSSI, otherwise LastPacketRSSI2
681 (i == 0) ? LastPacketRSSI = rssi[i] : LastPacketRSSI2 = rssi[i];
682 // Update whatever SNRs we have
683 LastPacketSNRRaw = snr[i];
687 // by default, set the last successful packet radio to be the current processing radio (which got a successful packet)
688 instance->lastSuccessfulPacketRadio = instance->processingPacketRadio;
690 // when both radio got the packet, use the better RSSI one
691 if(gotRadio[0] && gotRadio[1])
693 LastPacketSNRRaw = instance->fuzzy_snr(snr[0], snr[1], instance->FuzzySNRThreshold);
694 // Update the last successful packet radio to be the one with better signal strength
695 instance->lastSuccessfulPacketRadio = (rssi[0]>rssi[1])? radio[0]: radio[1];
698 #if defined(DEBUG_RCVR_SIGNAL_STATS)
699 // stat updates
700 for (uint8_t i = 0; i < 2; i++)
702 if (gotRadio[i])
704 instance->rxSignalStats[i].irq_count++;
705 instance->rxSignalStats[i].rssi_sum += rssi[i];
706 instance->rxSignalStats[i].snr_sum += snr[i];
707 if (snr[i] > instance->rxSignalStats[i].snr_max)
709 instance->rxSignalStats[i].snr_max = snr[i];
711 LastPacketSNRRaw = snr[i];
714 if(gotRadio[0] || gotRadio[1])
716 instance->irq_count_or++;
718 if(gotRadio[0] && gotRadio[1])
720 instance->irq_count_both++;
722 #endif
725 void ICACHE_RAM_ATTR SX1280Driver::IsrCallback_1()
727 instance->IsrCallback(SX12XX_Radio_1);
730 void ICACHE_RAM_ATTR SX1280Driver::IsrCallback_2()
732 instance->IsrCallback(SX12XX_Radio_2);
735 void ICACHE_RAM_ATTR SX1280Driver::IsrCallback(SX12XX_Radio_Number_t radioNumber)
737 instance->processingPacketRadio = radioNumber;
738 SX12XX_Radio_Number_t irqClearRadio = radioNumber;
740 uint16_t irqStatus = instance->GetIrqStatus(radioNumber);
741 if (irqStatus & SX1280_IRQ_TX_DONE)
743 RFAMP.TXRXdisable();
744 instance->TXnbISR();
745 irqClearRadio = SX12XX_Radio_All;
747 else if (irqStatus & SX1280_IRQ_RX_DONE)
749 if (instance->RXnbISR(irqStatus, radioNumber))
751 irqClearRadio = SX12XX_Radio_All; // Packet received so clear all radios and dont spend extra time retrieving data.
753 #if defined(DEBUG_RCVR_SIGNAL_STATS)
754 else
756 instance->rxSignalStats[(radioNumber == SX12XX_Radio_1) ? 0 : 1].fail_count++;
758 #endif
759 instance->isFirstRxIrq = false; // RX isr is already fired in this period. (reset to true in tock)
761 else if (irqStatus == SX1280_IRQ_RADIO_NONE)
763 return;
765 instance->ClearIrqStatus(SX1280_IRQ_RADIO_ALL, irqClearRadio);