1 #include "SX1280_Regs.h"
2 #include "SX1280_hal.h"
9 SX1280Driver
*SX1280Driver::instance
= NULL
;
13 //DEBUG_SX1280_OTA_TIMING
17 1. If not in STDBY_RC mode, then go to this mode by sending the command:
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)
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
;
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
56 #define OPT_USE_HARDWARE_DCDC false
59 SX1280Driver::SX1280Driver(): SX12xxDriverCommon()
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
);
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
)
84 hal
.IsrCallback_1
= &SX1280Driver::IsrCallback_1
;
85 hal
.IsrCallback_2
= &SX1280Driver::IsrCallback_2
;
88 DBGLN("SX1280 Begin");
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
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
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
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
134 // Force the next power update, and the lowest power
135 pwrCurrent
= PWRPENDING_NONE
;
136 SetOutputPower(SX1280_POWER_MIN
);
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
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
);
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
;
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
)
171 ConfigModParamsFLRC(bw
, cr
, sf
);
172 SetPacketParamsFLRC(SX1280_FLRC_PACKET_FIXED_LENGTH
, PreambleLength
, _PayloadLength
, flrcSyncWord
, flrcCrcSeed
, cr
);
177 ConfigModParamsLoRa(bw
, sf
, cr
);
178 #if defined(DEBUG_FREQ_CORRECTION)
179 SX1280_RadioLoRaPacketLengthsModes_t packetLengthType
= SX1280_LORA_PACKET_VARIABLE_LENGTH
;
181 SX1280_RadioLoRaPacketLengthsModes_t packetLengthType
= SX1280_LORA_PACKET_FIXED_LENGTH
;
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
)
197 timeout
= interval
* 1000 / RX_TIMEOUT_PERIOD_BASE_NANOS
; // number of periods for the SX1280 to timeout
201 timeout
= 0xFFFF; // no timeout, continuous mode
206 * @brief: Schedule an output power change after the next transmit
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
)
215 DBGLN("SetPower: %u", pwrPending
);
219 void ICACHE_RAM_ATTR
SX1280Driver::CommitOutputPower()
221 if (pwrPending
== PWRPENDING_NONE
)
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)
241 WORD_ALIGNED_ATTR
uint8_t buf
[3];
242 uint16_t tempTimeout
;
247 case SX1280_MODE_SLEEP
:
248 hal
.WriteCommand(SX1280_RADIO_SET_SLEEP
, (uint8_t)0x01, radioNumber
);
251 case SX1280_MODE_CALIBRATION
:
254 case SX1280_MODE_STDBY_RC
:
255 hal
.WriteCommand(SX1280_RADIO_SET_STANDBY
, SX1280_STDBY_RC
, radioNumber
, 1500);
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);
264 hal
.WriteCommand(SX1280_RADIO_SET_FS
, (uint8_t)0x00, radioNumber
, 70);
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);
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);
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);
290 case SX1280_MODE_CAD
:
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);
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
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
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
)
336 buf
[0] = PreambleLength
;
338 buf
[2] = PayloadLength
;
339 buf
[3] = SX1280_LORA_CRC_OFF
;
340 buf
[4] = InvertIQ
? SX1280_LORA_IQ_INVERTED
: SX1280_LORA_IQ_NORMAL
;
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
,
363 if (PreambleLength
< 8)
365 PreambleLength
= ((PreambleLength
/ 4) - 1) << 4;
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
);
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];
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
);
427 void SX1280Driver::SetFIFOaddr(uint8_t txBaseAddr
, uint8_t 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
)
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
)
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
)
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
475 DBGLN("TOA: %d", endTX
- beginTX
);
481 void ICACHE_RAM_ATTR
SX1280Driver::TXnb(uint8_t * data
, uint8_t size
, SX12XX_Radio_Number_t radioNumber
)
483 transmittingRadio
= radioNumber
;
486 if (currOpmode
== SX1280_MODE_TX
)
489 SetMode(fallBackMode
, SX12XX_Radio_All
);
490 ClearIrqStatus(SX1280_IRQ_RADIO_ALL
, SX12XX_Radio_All
);
495 if (radioNumber
== SX12XX_Radio_NONE
)
497 instance
->SetMode(fallBackMode
, SX12XX_Radio_All
);
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
++;
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
);
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
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
)
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
);
576 void ICACHE_RAM_ATTR
SX1280Driver::GetStatus(SX12XX_Radio_Number_t radioNumber
)
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
594 int8_t ICACHE_RAM_ATTR
SX1280Driver::GetRssiInst(SX12XX_Radio_Number_t radioNumber
)
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
++;
656 for(uint8_t i
=0;i
<2;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);
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)
700 for (uint8_t i
= 0; i
< 2; 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
++;
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
)
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)
756 instance
->rxSignalStats
[(radioNumber
== SX12XX_Radio_1
) ? 0 : 1].fail_count
++;
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
)
765 instance
->ClearIrqStatus(SX1280_IRQ_RADIO_ALL
, irqClearRadio
);