6 void inline SX127xDriver::nullCallback(void) {}
7 SX127xDriver
*SX127xDriver::instance
= NULL
;
9 void (*SX127xDriver::RXdoneCallback
)() = &nullCallback
;
10 void (*SX127xDriver::TXdoneCallback
)() = &nullCallback
;
12 void (*SX127xDriver::TXtimeout
)() = &nullCallback
;
13 void (*SX127xDriver::RXtimeout
)() = &nullCallback
;
15 volatile WORD_ALIGNED_ATTR
uint8_t SX127xDriver::TXdataBuffer
[TXRXBuffSize
] = {0};
16 volatile WORD_ALIGNED_ATTR
uint8_t SX127xDriver::RXdataBuffer
[TXRXBuffSize
] = {0};
18 const uint8_t SX127x_AllowedSyncwords
[105] =
19 {0, 5, 6, 7, 11, 12, 13, 15, 18,
20 21, 23, 26, 29, 30, 31, 33, 34,
21 37, 38, 39, 40, 42, 44, 50, 51,
22 54, 55, 57, 58, 59, 61, 63, 65,
23 67, 68, 71, 77, 78, 79, 80, 82,
24 84, 86, 89, 92, 94, 96, 97, 99,
25 101, 102, 105, 106, 109, 111, 113, 115,
26 117, 118, 119, 121, 122, 124, 126, 127,
27 129, 130, 138, 143, 161, 170, 172, 173,
28 175, 180, 181, 182, 187, 190, 191, 192,
29 193, 196, 199, 201, 204, 205, 208, 209,
30 212, 213, 219, 220, 221, 223, 227, 229,
31 235, 239, 240, 242, 243, 246, 247, 255};
33 //////////////////////////////////////////////
35 SX127xDriver::SX127xDriver()
40 bool SX127xDriver::Begin()
42 DBGLN("SX127x Driver Begin");
43 hal
.IsrCallback
= &SX127xDriver::IsrCallback
;
57 void SX127xDriver::End()
59 SetMode(SX127x_OPMODE_SLEEP
);
61 TXdoneCallback
= &nullCallback
; // remove callbacks
62 RXdoneCallback
= &nullCallback
;
65 void SX127xDriver::ConfigLoraDefaults()
67 hal
.writeRegister(SX127X_REG_OP_MODE
, SX127x_OPMODE_SLEEP
);
68 hal
.writeRegister(SX127X_REG_OP_MODE
, ModFSKorLoRa
); //must be written in sleep mode
69 SetMode(SX127x_OPMODE_STANDBY
);
71 hal
.writeRegister(SX127X_REG_PAYLOAD_LENGTH
, PayloadLength
);
72 SetSyncWord(currSyncWord
);
73 hal
.writeRegister(SX127X_REG_FIFO_TX_BASE_ADDR
, SX127X_FIFO_TX_BASE_ADDR_MAX
);
74 hal
.writeRegister(SX127X_REG_FIFO_RX_BASE_ADDR
, SX127X_FIFO_RX_BASE_ADDR_MAX
);
75 hal
.setRegValue(SX127X_REG_DIO_MAPPING_1
, 0b11000000, 7, 6); //undocumented "hack", looking at Table 18 from datasheet SX127X_REG_DIO_MAPPING_1 = 11 appears to be unspported by infact it generates an intterupt on both RXdone and TXdone, this saves switching modes.
76 hal
.writeRegister(SX127X_REG_LNA
, SX127X_LNA_BOOST_ON
);
77 hal
.writeRegister(SX1278_REG_MODEM_CONFIG_3
, SX1278_AGC_AUTO_ON
| SX1278_LOW_DATA_RATE_OPT_OFF
);
78 hal
.setRegValue(SX127X_REG_OCP
, SX127X_OCP_ON
| SX127X_OCP_150MA
, 5, 0); //150ma max current
79 SetPreambleLength(SX127X_PREAMBLE_LENGTH_LSB
);
80 hal
.setRegValue(SX127X_REG_INVERT_IQ
, (uint8_t)IQinverted
, 6, 6);
83 void SX127xDriver::SetBandwidthCodingRate(SX127x_Bandwidth bw
, SX127x_CodingRate cr
)
85 if ((currBW
!= bw
) || (currCR
!= cr
))
87 if (currSF
== SX127x_SF_6
) // set SF6 optimizations
89 hal
.writeRegister(SX127X_REG_MODEM_CONFIG_1
, bw
| cr
| SX1278_HEADER_IMPL_MODE
);
90 hal
.setRegValue(SX127X_REG_MODEM_CONFIG_2
, SX1278_RX_CRC_MODE_OFF
, 2, 2);
96 hal
.writeRegister(SX127X_REG_MODEM_CONFIG_1
, bw
| cr
| SX1278_HEADER_EXPL_MODE
);
100 hal
.writeRegister(SX127X_REG_MODEM_CONFIG_1
, bw
| cr
| SX1278_HEADER_IMPL_MODE
);
105 hal
.setRegValue(SX127X_REG_MODEM_CONFIG_2
, SX1278_RX_CRC_MODE_ON
, 2, 2);
109 hal
.setRegValue(SX127X_REG_MODEM_CONFIG_2
, SX1278_RX_CRC_MODE_OFF
, 2, 2);
113 if (bw
== SX127x_BW_500_00_KHZ
)
115 //datasheet errata reconmendation http://caxapa.ru/thumbs/972894/SX1276_77_8_ErrataNote_1.1_STD.pdf
116 hal
.writeRegister(0x36, 0x02);
117 hal
.writeRegister(0x3a, 0x64);
121 hal
.writeRegister(0x36, 0x03);
128 bool SyncWordOk(uint8_t syncWord
)
130 for (unsigned int i
= 0; i
< sizeof(SX127x_AllowedSyncwords
); i
++)
132 if (syncWord
== SX127x_AllowedSyncwords
[i
])
140 void SX127xDriver::SetSyncWord(uint8_t syncWord
)
142 uint8_t _syncWord
= syncWord
;
144 while (SyncWordOk(_syncWord
) == false)
149 if(syncWord
!= _syncWord
){
150 DBGLN("Using syncword: %d instead of: %d", _syncWord
, syncWord
);
153 hal
.writeRegister(SX127X_REG_SYNC_WORD
, _syncWord
);
154 currSyncWord
= _syncWord
;
157 void SX127xDriver::SetOutputPower(uint8_t Power
)
159 SetMode(SX127x_OPMODE_STANDBY
);
160 #if defined(USE_SX1276_RFO_HF)
161 hal
.writeRegister(SX127X_REG_PA_CONFIG
, SX127X_PA_SELECT_RFO
| SX127X_MAX_OUTPUT_POWER
| Power
);
163 hal
.writeRegister(SX127X_REG_PA_CONFIG
, SX127X_PA_SELECT_BOOST
| SX127X_MAX_OUTPUT_POWER
| Power
);
168 void SX127xDriver::SetPreambleLength(uint8_t PreambleLen
)
170 if (currPreambleLen
!= PreambleLen
)
172 hal
.writeRegister(SX127X_REG_PREAMBLE_LSB
, PreambleLen
);
173 currPreambleLen
= PreambleLen
;
177 void SX127xDriver::SetSpreadingFactor(SX127x_SpreadingFactor sf
)
181 hal
.setRegValue(SX127X_REG_MODEM_CONFIG_2
, sf
| SX127X_TX_MODE_SINGLE
, 7, 3);
182 if (sf
== SX127x_SF_6
)
184 hal
.setRegValue(SX127X_REG_DETECT_OPTIMIZE
, SX127X_DETECT_OPTIMIZE_SF_6
, 2, 0);
185 hal
.writeRegister(SX127X_REG_DETECTION_THRESHOLD
, SX127X_DETECTION_THRESHOLD_SF_6
);
189 hal
.setRegValue(SX127X_REG_DETECT_OPTIMIZE
, SX127X_DETECT_OPTIMIZE_SF_7_12
, 2, 0);
190 hal
.writeRegister(SX127X_REG_DETECTION_THRESHOLD
, SX127X_DETECTION_THRESHOLD_SF_7_12
);
196 void ICACHE_RAM_ATTR
SX127xDriver::SetFrequencyHz(uint32_t freq
)
199 SetMode(SX127x_OPMODE_STANDBY
);
201 int32_t FRQ
= ((uint32_t)((double)freq
/ (double)FREQ_STEP
));
203 uint8_t FRQ_MSB
= (uint8_t)((FRQ
>> 16) & 0xFF);
204 uint8_t FRQ_MID
= (uint8_t)((FRQ
>> 8) & 0xFF);
205 uint8_t FRQ_LSB
= (uint8_t)(FRQ
& 0xFF);
207 WORD_ALIGNED_ATTR
uint8_t outbuff
[3] = {FRQ_MSB
, FRQ_MID
, FRQ_LSB
}; //check speedup
209 hal
.writeRegisterBurst(SX127X_REG_FRF_MSB
, outbuff
, sizeof(outbuff
));
212 void ICACHE_RAM_ATTR
SX127xDriver::SetFrequencyReg(uint32_t freq
)
215 SetMode(SX127x_OPMODE_STANDBY
);
217 uint8_t FRQ_MSB
= (uint8_t)((freq
>> 16) & 0xFF);
218 uint8_t FRQ_MID
= (uint8_t)((freq
>> 8) & 0xFF);
219 uint8_t FRQ_LSB
= (uint8_t)(freq
& 0xFF);
221 WORD_ALIGNED_ATTR
uint8_t outbuff
[3] = {FRQ_MSB
, FRQ_MID
, FRQ_LSB
}; //check speedup
223 hal
.writeRegisterBurst(SX127X_REG_FRF_MSB
, outbuff
, sizeof(outbuff
));
226 bool SX127xDriver::DetectChip()
229 bool flagFound
= false;
230 while ((i
< 3) && !flagFound
)
232 uint8_t version
= hal
.readRegister(SX127X_REG_VERSION
);
240 DBGLN(" not found! (%d of 3 tries) REG_VERSION == 0x%x", i
+1, version
);
248 DBGLN(" not found!");
253 DBGLN(" found! (match by REG_VERSION == 0x12)");
255 hal
.setRegValue(SX127X_REG_OP_MODE
, SX127x_OPMODE_SLEEP
, 2, 0);
259 /////////////////////////////////////TX functions/////////////////////////////////////////
261 void ICACHE_RAM_ATTR
SX127xDriver::TXnbISR()
263 currOpmode
= SX127x_OPMODE_STANDBY
; //goes into standby after transmission
264 //TXdoneMicros = micros();
268 void ICACHE_RAM_ATTR
SX127xDriver::TXnb()
270 // if (currOpmode == SX127x_OPMODE_TX)
272 // DBGLN("abort TX");
273 // return; // we were already TXing so abort. this should never happen!!!
275 SetMode(SX127x_OPMODE_STANDBY
);
278 //TXstartMicros = micros();
279 //HeadRoom = TXstartMicros - TXdoneMicros;
281 hal
.writeRegister(SX127X_REG_FIFO_ADDR_PTR
, SX127X_FIFO_TX_BASE_ADDR_MAX
);
282 hal
.writeRegisterFIFO(TXdataBuffer
, PayloadLength
);
284 SetMode(SX127x_OPMODE_TX
);
287 ///////////////////////////////////RX Functions Non-Blocking///////////////////////////////////////////
289 void ICACHE_RAM_ATTR
SX127xDriver::RXnbISR()
291 hal
.readRegisterFIFO(RXdataBuffer
, PayloadLength
);
292 LastPacketRSSI
= GetLastPacketRSSI();
293 LastPacketSNR
= GetLastPacketSNR();
297 void ICACHE_RAM_ATTR
SX127xDriver::RXnb()
299 // if (currOpmode == SX127x_OPMODE_RXCONTINUOUS)
301 // DBGLN("abort RX");
302 // return; // we were already TXing so abort
304 SetMode(SX127x_OPMODE_STANDBY
);
306 hal
.writeRegister(SX127X_REG_FIFO_ADDR_PTR
, SX127X_FIFO_RX_BASE_ADDR_MAX
);
307 SetMode(SX127x_OPMODE_RXCONTINUOUS
);
310 void ICACHE_RAM_ATTR
SX127xDriver::SetMode(SX127x_RadioOPmodes mode
)
311 { //if radio is not already in the required mode set it to the requested mod
312 if (currOpmode
!= mode
)
314 hal
.writeRegister(ModFSKorLoRa
| SX127X_REG_OP_MODE
, mode
);
319 void SX127xDriver::Config(SX127x_Bandwidth bw
, SX127x_SpreadingFactor sf
, SX127x_CodingRate cr
, uint32_t freq
, uint8_t preambleLen
, bool InvertIQ
, uint8_t PayloadLength
)
321 Config(bw
, sf
, cr
, freq
, preambleLen
, currSyncWord
, InvertIQ
, PayloadLength
);
324 void SX127xDriver::Config(SX127x_Bandwidth bw
, SX127x_SpreadingFactor sf
, SX127x_CodingRate cr
, uint32_t freq
, uint8_t preambleLen
, uint8_t syncWord
, bool InvertIQ
, uint8_t PayloadLength
)
326 PayloadLength
= PayloadLength
;
327 IQinverted
= InvertIQ
;
328 ConfigLoraDefaults();
329 SetPreambleLength(preambleLen
);
330 SetOutputPower(currPWR
);
331 SetSpreadingFactor(sf
);
332 SetBandwidthCodingRate(bw
, cr
);
333 SetFrequencyReg(freq
);
336 uint32_t ICACHE_RAM_ATTR
SX127xDriver::GetCurrBandwidth()
340 case SX127x_BW_7_80_KHZ
:
342 case SX127x_BW_10_40_KHZ
:
344 case SX127x_BW_15_60_KHZ
:
346 case SX127x_BW_20_80_KHZ
:
348 case SX127x_BW_31_25_KHZ
:
350 case SX127x_BW_41_70_KHZ
:
352 case SX127x_BW_62_50_KHZ
:
354 case SX127x_BW_125_00_KHZ
:
356 case SX127x_BW_250_00_KHZ
:
358 case SX127x_BW_500_00_KHZ
:
364 uint32_t ICACHE_RAM_ATTR
SX127xDriver::GetCurrBandwidthNormalisedShifted() // this is basically just used for speedier calc of the freq offset, pre compiled for 32mhz xtal
369 case SX127x_BW_7_80_KHZ
:
371 case SX127x_BW_10_40_KHZ
:
373 case SX127x_BW_15_60_KHZ
:
375 case SX127x_BW_20_80_KHZ
:
377 case SX127x_BW_31_25_KHZ
:
379 case SX127x_BW_41_70_KHZ
:
381 case SX127x_BW_62_50_KHZ
:
383 case SX127x_BW_125_00_KHZ
:
385 case SX127x_BW_250_00_KHZ
:
387 case SX127x_BW_500_00_KHZ
:
394 * Set the PPMcorrection register to adjust data rate to frequency error
395 * @param offset is in Hz or FREQ_STEP (FREQ_HZ_TO_REG_VAL) units, whichever
396 * was used to SetFrequencyHz/SetFrequencyReg
398 void ICACHE_RAM_ATTR
SX127xDriver::SetPPMoffsetReg(int32_t offset
)
400 int8_t offsetPPM
= (offset
* 1e6
/ currFreq
) * 95 / 100;
401 hal
.writeRegister(SX127x_PPMOFFSET
, (uint8_t)offsetPPM
);
404 bool ICACHE_RAM_ATTR
SX127xDriver::GetFrequencyErrorbool()
406 return (hal
.readRegister(SX127X_REG_FEI_MSB
) & 0b1000) >> 3; // returns true if pos freq error, neg if false
409 int32_t ICACHE_RAM_ATTR
SX127xDriver::GetFrequencyError()
412 WORD_ALIGNED_ATTR
uint8_t reg
[3] = {0x0, 0x0, 0x0};
413 hal
.readRegisterBurst(SX127X_REG_FEI_MSB
, sizeof(reg
), reg
);
415 uint32_t RegFei
= ((reg
[0] & 0b0111) << 16) + (reg
[1] << 8) + reg
[2];
417 int32_t intFreqError
= RegFei
;
419 if ((reg
[0] & 0b1000) >> 3)
421 intFreqError
-= 524288; // Sign bit is on
424 int32_t fErrorHZ
= (intFreqError
>> 3) * (SX127xDriver::GetCurrBandwidthNormalisedShifted()); // bit shift hackery so we don't have to use floaty bois; the >> 3 is intentional and is a simplification of the formula on page 114 of sx1276 datasheet
430 uint8_t ICACHE_RAM_ATTR
SX127xDriver::UnsignedGetLastPacketRSSI()
432 return (hal
.getRegValue(SX127X_REG_PKT_RSSI_VALUE
));
435 int8_t ICACHE_RAM_ATTR
SX127xDriver::GetLastPacketRSSI()
437 return (-157 + hal
.getRegValue(SX127X_REG_PKT_RSSI_VALUE
));
440 int8_t ICACHE_RAM_ATTR
SX127xDriver::GetCurrRSSI()
442 return (-157 + hal
.getRegValue(SX127X_REG_RSSI_VALUE
));
445 int8_t ICACHE_RAM_ATTR
SX127xDriver::GetLastPacketSNR()
447 int8_t rawSNR
= (int8_t)hal
.getRegValue(SX127X_REG_PKT_SNR_VALUE
);
451 uint8_t ICACHE_RAM_ATTR
SX127xDriver::GetIrqFlags()
453 return hal
.getRegValue(SX127X_REG_IRQ_FLAGS
);
456 void ICACHE_RAM_ATTR
SX127xDriver::ClearIrqFlags()
458 hal
.writeRegister(SX127X_REG_IRQ_FLAGS
, 0b11111111);
461 // int16_t MeasureNoiseFloor() TODO disabled for now
463 // int NUM_READS = RSSI_FLOOR_NUM_READS * FHSSgetChannelCount();
464 // float returnval = 0;
466 // for (uint32_t freq = 0; freq < FHSSgetChannelCount(); freq++)
468 // FHSSsetCurrIndex(freq);
469 // Radio.SetMode(SX127X_CAD);
471 // for (int i = 0; i < RSSI_FLOOR_NUM_READS; i++)
473 // returnval = returnval + Radio.GetCurrRSSI();
477 // returnval = returnval / NUM_READS;
478 // return (returnval);
481 // uint8_t SX127xDriver::RunCAD() TODO
483 // SetMode(SX127X_STANDBY);
485 // hal.setRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_CAD_DONE | SX127X_DIO1_CAD_DETECTED, 7, 4);
487 // SetMode(SX127X_CAD);
490 // uint32_t startTime = millis();
492 // while (!digitalRead(SX127x_dio0))
494 // if (millis() > (startTime + 500))
496 // return (CHANNEL_FREE);
501 // if (digitalRead(SX127x_dio1))
504 // return (PREAMBLE_DETECTED);
510 // return (CHANNEL_FREE);
513 void ICACHE_RAM_ATTR
SX127xDriver::IsrCallback()
515 uint8_t irqStatus
= instance
->GetIrqFlags();
516 instance
->ClearIrqFlags();
517 if ((irqStatus
& SX127X_CLEAR_IRQ_FLAG_TX_DONE
))
519 else if ((irqStatus
& SX127X_CLEAR_IRQ_FLAG_RX_DONE
))