Line data Source code
1 : #include "SX127x.h"
2 : #include <math.h>
3 : #if !RADIOLIB_EXCLUDE_SX127X
4 :
5 22 : SX127x::SX127x(Module* mod) : PhysicalLayer() {
6 22 : this->freqStep = RADIOLIB_SX127X_FREQUENCY_STEP_SIZE;
7 22 : this->maxPacketLength = RADIOLIB_SX127X_MAX_PACKET_LENGTH;
8 22 : this->mod = mod;
9 22 : }
10 :
11 0 : int16_t SX127x::begin(const uint8_t* chipVersions, uint8_t numVersions, uint8_t syncWord, uint16_t preambleLength) {
12 : // set module properties
13 0 : this->mod->init();
14 0 : this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
15 0 : this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput);
16 :
17 : // set IRQ mapping - it is different for LoRa and FSK mode
18 0 : this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_TX_DONE;
19 0 : this->irqMap[RADIOLIB_IRQ_RX_DONE] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_DONE;
20 0 : this->irqMap[RADIOLIB_IRQ_PREAMBLE_DETECTED] = RADIOLIB_IRQ_NOT_SUPPORTED;
21 0 : this->irqMap[RADIOLIB_IRQ_SYNC_WORD_VALID] = RADIOLIB_IRQ_NOT_SUPPORTED;
22 0 : this->irqMap[RADIOLIB_IRQ_HEADER_VALID] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_VALID_HEADER;
23 0 : this->irqMap[RADIOLIB_IRQ_HEADER_ERR] = RADIOLIB_IRQ_NOT_SUPPORTED;
24 0 : this->irqMap[RADIOLIB_IRQ_CRC_ERR] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR;
25 0 : this->irqMap[RADIOLIB_IRQ_CAD_DONE] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DONE;
26 0 : this->irqMap[RADIOLIB_IRQ_CAD_DETECTED] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED;
27 0 : this->irqMap[RADIOLIB_IRQ_TIMEOUT] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT;
28 :
29 : // try to find the SX127x chip
30 0 : if(!SX127x::findChip(chipVersions, numVersions)) {
31 : RADIOLIB_DEBUG_BASIC_PRINTLN("No SX127x found!");
32 0 : this->mod->term();
33 0 : return(RADIOLIB_ERR_CHIP_NOT_FOUND);
34 : }
35 : RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX127x");
36 :
37 : // set mode to standby
38 0 : int16_t state = standby();
39 0 : RADIOLIB_ASSERT(state);
40 :
41 : // configure settings not accessible by API
42 0 : state = config();
43 0 : RADIOLIB_ASSERT(state);
44 :
45 : // check active modem
46 0 : if(getActiveModem() != RADIOLIB_SX127X_LORA) {
47 : // set LoRa mode
48 0 : state = setActiveModem(RADIOLIB_SX127X_LORA);
49 0 : RADIOLIB_ASSERT(state);
50 : }
51 :
52 : // set LoRa sync word
53 0 : state = SX127x::setSyncWord(syncWord);
54 0 : RADIOLIB_ASSERT(state);
55 :
56 : // set over current protection
57 0 : state = SX127x::setCurrentLimit(60);
58 0 : RADIOLIB_ASSERT(state);
59 :
60 : // set preamble length
61 0 : state = SX127x::setPreambleLength(preambleLength);
62 0 : RADIOLIB_ASSERT(state);
63 :
64 : // disable IQ inversion
65 0 : state = SX127x::invertIQ(false);
66 0 : RADIOLIB_ASSERT(state);
67 :
68 0 : return(state);
69 : }
70 :
71 0 : int16_t SX127x::beginFSK(const uint8_t* chipVersions, uint8_t numVersions, float freqDev, float rxBw, uint16_t preambleLength) {
72 : // set module properties
73 0 : this->mod->init();
74 0 : this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
75 0 : this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput);
76 :
77 : // set IRQ mapping - it is different for LoRa and FSK mode
78 0 : this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_SX127X_FLAG_PACKET_SENT << 8;
79 0 : this->irqMap[RADIOLIB_IRQ_RX_DONE] = RADIOLIB_SX127X_FLAG_PAYLOAD_READY << 8;
80 0 : this->irqMap[RADIOLIB_IRQ_PREAMBLE_DETECTED] = RADIOLIB_SX127X_FLAG_PREAMBLE_DETECT << 0;
81 0 : this->irqMap[RADIOLIB_IRQ_SYNC_WORD_VALID] = RADIOLIB_SX127X_FLAG_SYNC_ADDRESS_MATCH << 0;
82 0 : this->irqMap[RADIOLIB_IRQ_HEADER_VALID] = RADIOLIB_IRQ_NOT_SUPPORTED;
83 0 : this->irqMap[RADIOLIB_IRQ_HEADER_ERR] = RADIOLIB_IRQ_NOT_SUPPORTED;
84 0 : this->irqMap[RADIOLIB_IRQ_CRC_ERR] = RADIOLIB_IRQ_NOT_SUPPORTED;
85 0 : this->irqMap[RADIOLIB_IRQ_CAD_DONE] = RADIOLIB_IRQ_NOT_SUPPORTED;
86 0 : this->irqMap[RADIOLIB_IRQ_CAD_DETECTED] = RADIOLIB_IRQ_NOT_SUPPORTED;
87 0 : this->irqMap[RADIOLIB_IRQ_TIMEOUT] = RADIOLIB_SX127X_FLAG_TIMEOUT << 0;
88 :
89 : // try to find the SX127x chip
90 0 : if(!SX127x::findChip(chipVersions, numVersions)) {
91 : RADIOLIB_DEBUG_BASIC_PRINTLN("No SX127x found!");
92 0 : this->mod->term();
93 0 : return(RADIOLIB_ERR_CHIP_NOT_FOUND);
94 : }
95 : RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX127x");
96 :
97 : // set mode to standby
98 0 : int16_t state = standby();
99 0 : RADIOLIB_ASSERT(state);
100 :
101 : // check currently active modem
102 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
103 : // set FSK mode
104 0 : state = setActiveModem(RADIOLIB_SX127X_FSK_OOK);
105 0 : RADIOLIB_ASSERT(state);
106 : }
107 :
108 : // enable/disable OOK
109 0 : state = setOOK(this->enableOOK);
110 0 : RADIOLIB_ASSERT(state);
111 :
112 : // set frequency deviation
113 0 : state = SX127x::setFrequencyDeviation(freqDev);
114 0 : RADIOLIB_ASSERT(state);
115 :
116 : // set AFC bandwidth
117 0 : state = SX127x::setAFCBandwidth(rxBw);
118 0 : RADIOLIB_ASSERT(state);
119 :
120 : // set AFC&AGC trigger to RSSI (both in OOK and FSK)
121 0 : state = SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_RSSI_INTERRUPT);
122 0 : RADIOLIB_ASSERT(state);
123 :
124 : // enable AFC
125 0 : state = SX127x::setAFC(false);
126 0 : RADIOLIB_ASSERT(state);
127 :
128 : // set receiver bandwidth
129 0 : state = SX127x::setRxBandwidth(rxBw);
130 0 : RADIOLIB_ASSERT(state);
131 :
132 : // set over current protection
133 0 : state = SX127x::setCurrentLimit(60);
134 0 : RADIOLIB_ASSERT(state);
135 :
136 : // set preamble length
137 0 : state = SX127x::setPreambleLength(preambleLength);
138 0 : RADIOLIB_ASSERT(state);
139 :
140 : // set preamble polarity
141 0 : state = invertPreamble(false);
142 0 : RADIOLIB_ASSERT(state);
143 :
144 : // set default sync word
145 0 : uint8_t syncWord[] = {0x12, 0xAD};
146 0 : state = setSyncWord(syncWord, 2);
147 0 : RADIOLIB_ASSERT(state);
148 :
149 : // disable address filtering
150 0 : state = disableAddressFiltering();
151 0 : RADIOLIB_ASSERT(state);
152 :
153 : // set default RSSI measurement config
154 0 : state = setRSSIConfig(2);
155 0 : RADIOLIB_ASSERT(state);
156 :
157 : // set default encoding
158 0 : state = setEncoding(RADIOLIB_ENCODING_NRZ);
159 0 : RADIOLIB_ASSERT(state);
160 :
161 : // set default packet length mode
162 0 : state = variablePacketLengthMode();
163 :
164 0 : return(state);
165 : }
166 :
167 6 : int16_t SX127x::transmit(const uint8_t* data, size_t len, uint8_t addr) {
168 : // set mode to standby
169 6 : int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
170 6 : RADIOLIB_ASSERT(state);
171 :
172 0 : int16_t modem = getActiveModem();
173 0 : RadioLibTime_t start = 0;
174 0 : RadioLibTime_t timeout = 0;
175 0 : RadioLibTime_t toa = getTimeOnAir(len);
176 0 : if(modem == RADIOLIB_SX127X_LORA) {
177 : // calculate timeout in ms (150 % of expected time-on-air)
178 0 : timeout = (toa * 1.5) / 1000;
179 :
180 0 : } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
181 : // calculate timeout in ms (5ms + 500 % of expected time-on-air)
182 0 : timeout = 5 + (toa * 5) / 1000;
183 :
184 : } else {
185 0 : return(RADIOLIB_ERR_UNKNOWN);
186 :
187 : }
188 :
189 : // start transmission
190 : RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout);
191 0 : state = startTransmit(data, len, addr);
192 0 : RADIOLIB_ASSERT(state);
193 :
194 : // wait for packet transmission or timeout
195 0 : start = this->mod->hal->millis();
196 0 : while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
197 0 : this->mod->hal->yield();
198 0 : if(this->mod->hal->millis() - start > timeout) {
199 0 : finishTransmit();
200 0 : return(RADIOLIB_ERR_TX_TIMEOUT);
201 : }
202 : }
203 :
204 0 : return(finishTransmit());
205 : }
206 :
207 6 : int16_t SX127x::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) {
208 : // set mode to standby
209 6 : int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
210 6 : RADIOLIB_ASSERT(state);
211 :
212 : // calculate timeout based on the configured modem
213 0 : RadioLibTime_t timeoutInternal = timeout;
214 0 : uint32_t timeoutValue = 0;
215 0 : if(!timeoutInternal) {
216 : // calculate timeout (500 % of expected time-one-air)
217 0 : size_t maxLen = len;
218 0 : if(len == 0) { maxLen = RADIOLIB_SX127X_MAX_PACKET_LENGTH; }
219 0 : timeoutInternal = (getTimeOnAir(maxLen) * 5) / 1000;
220 :
221 : // convert to symbols
222 0 : float symbolLength = (float)(uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth;
223 0 : timeoutValue = (float)timeoutInternal / symbolLength;
224 : }
225 :
226 : RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeoutInternal);
227 :
228 : // start reception
229 0 : state = startReceive(timeoutValue, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, len);
230 0 : RADIOLIB_ASSERT(state);
231 :
232 : // wait for packet reception or timeout
233 0 : bool softTimeout = false;
234 0 : RadioLibTime_t start = this->mod->hal->millis();
235 0 : while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
236 0 : this->mod->hal->yield();
237 : // check the blocking timeout
238 0 : if(this->mod->hal->millis() - start > timeoutInternal) {
239 0 : softTimeout = true;
240 0 : break;
241 : }
242 : }
243 :
244 : // check whether this was a timeout or not
245 0 : if(softTimeout || (getIRQFlags() & this->irqMap[RADIOLIB_IRQ_TIMEOUT])) {
246 0 : (void)finishReceive();
247 0 : return(RADIOLIB_ERR_RX_TIMEOUT);
248 : }
249 :
250 : // read the received data
251 0 : return(readData(data, len));
252 : }
253 :
254 0 : void SX127x::reset() {
255 : // should be implemented in derived class
256 0 : }
257 :
258 6 : int16_t SX127x::scanChannel() {
259 : // the configuration is not actually used
260 6 : const ChannelScanConfig_t cfg = { .rssi = { .limit = 0 } };
261 12 : return(scanChannel(cfg));
262 : }
263 :
264 12 : int16_t SX127x::scanChannel(const ChannelScanConfig_t &cfg) {
265 : (void)cfg;
266 :
267 : // start CAD
268 12 : int16_t state = startChannelScan();
269 12 : RADIOLIB_ASSERT(state);
270 :
271 : // wait for channel activity detected or timeout
272 0 : while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
273 0 : this->mod->hal->yield();
274 0 : if(this->mod->hal->digitalRead(this->mod->getGpio())) {
275 0 : return(RADIOLIB_PREAMBLE_DETECTED);
276 : }
277 : }
278 :
279 0 : return(RADIOLIB_CHANNEL_FREE);
280 : }
281 :
282 6 : int16_t SX127x::sleep() {
283 : // set RF switch (if present)
284 6 : this->mod->setRfSwitchState(Module::MODE_IDLE);
285 :
286 : // set mode to sleep
287 6 : int16_t state = setMode(RADIOLIB_SX127X_SLEEP);
288 :
289 : // wait for SX127x to safely enter sleep mode
290 6 : this->mod->hal->delay(1);
291 :
292 6 : return(state);
293 : }
294 :
295 30 : int16_t SX127x::standby() {
296 : // set RF switch (if present)
297 30 : this->mod->setRfSwitchState(Module::MODE_IDLE);
298 :
299 : // set mode to standby
300 30 : return(setMode(RADIOLIB_SX127X_STANDBY));
301 : }
302 :
303 6 : int16_t SX127x::standby(uint8_t mode) {
304 : (void)mode;
305 6 : return(standby());
306 : }
307 :
308 6 : int16_t SX127x::transmitDirect(uint32_t frf) {
309 : // check modem
310 6 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
311 6 : return(RADIOLIB_ERR_WRONG_MODEM);
312 : }
313 :
314 : // set RF switch (if present)
315 0 : this->mod->setRfSwitchState(Module::MODE_TX);
316 :
317 : // user requested to start transmitting immediately (required for RTTY)
318 0 : if(frf != 0) {
319 0 : this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FRF_MSB, (frf & 0xFF0000) >> 16);
320 0 : this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FRF_MID, (frf & 0x00FF00) >> 8);
321 0 : this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FRF_LSB, frf & 0x0000FF);
322 :
323 0 : return(setMode(RADIOLIB_SX127X_TX));
324 : }
325 :
326 : // activate direct mode
327 0 : int16_t state = directMode();
328 0 : RADIOLIB_ASSERT(state);
329 :
330 : // apply fixes to errata
331 : RADIOLIB_ERRATA_SX127X(false);
332 :
333 : // start transmitting
334 0 : return(setMode(RADIOLIB_SX127X_TX));
335 : }
336 :
337 6 : int16_t SX127x::receiveDirect() {
338 : // check modem
339 6 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
340 6 : return(RADIOLIB_ERR_WRONG_MODEM);
341 : }
342 :
343 : // set RF switch (if present)
344 0 : this->mod->setRfSwitchState(Module::MODE_RX);
345 :
346 : // activate direct mode
347 0 : int16_t state = directMode();
348 0 : RADIOLIB_ASSERT(state);
349 :
350 : // apply fixes to errata
351 : RADIOLIB_ERRATA_SX127X(true);
352 :
353 : // start receiving
354 0 : return(setMode(RADIOLIB_SX127X_RX));
355 : }
356 :
357 0 : int16_t SX127x::directMode() {
358 : // set mode to standby
359 0 : int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
360 0 : RADIOLIB_ASSERT(state);
361 :
362 : // set DIO mapping
363 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_CONT_DCLK | RADIOLIB_SX127X_DIO2_CONT_DATA, 5, 2);
364 0 : RADIOLIB_ASSERT(state);
365 :
366 : // enable receiver startup without preamble or RSSI
367 0 : state = SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_NONE);
368 0 : RADIOLIB_ASSERT(state);
369 :
370 : // set continuous mode
371 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_2, RADIOLIB_SX127X_DATA_MODE_CONTINUOUS, 6, 6));
372 : }
373 :
374 0 : int16_t SX127x::packetMode() {
375 : // check modem
376 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
377 0 : return(RADIOLIB_ERR_WRONG_MODEM);
378 : }
379 :
380 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_2, RADIOLIB_SX127X_DATA_MODE_PACKET, 6, 6));
381 : }
382 :
383 6 : int16_t SX127x::startReceive() {
384 6 : return(this->startReceive(0, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0));
385 : }
386 :
387 0 : void SX127x::setDio0Action(void (*func)(void), uint32_t dir) {
388 0 : this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, dir);
389 0 : }
390 :
391 0 : void SX127x::clearDio0Action() {
392 0 : this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()));
393 0 : }
394 :
395 0 : void SX127x::setDio1Action(void (*func)(void), uint32_t dir) {
396 0 : if(this->mod->getGpio() == RADIOLIB_NC) {
397 0 : return;
398 : }
399 0 : this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getGpio()), func, dir);
400 : }
401 :
402 0 : void SX127x::clearDio1Action() {
403 0 : if(this->mod->getGpio() == RADIOLIB_NC) {
404 0 : return;
405 : }
406 0 : this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getGpio()));
407 : }
408 :
409 0 : void SX127x::setPacketReceivedAction(void (*func)(void)) {
410 0 : this->setDio0Action(func, this->mod->hal->GpioInterruptRising);
411 0 : }
412 :
413 0 : void SX127x::clearPacketReceivedAction() {
414 0 : this->clearDio0Action();
415 0 : }
416 :
417 0 : void SX127x::setPacketSentAction(void (*func)(void)) {
418 0 : this->setDio0Action(func, this->mod->hal->GpioInterruptRising);
419 0 : }
420 :
421 0 : void SX127x::clearPacketSentAction() {
422 0 : this->clearDio0Action();
423 0 : }
424 :
425 0 : void SX127x::setChannelScanAction(void (*func)(void)) {
426 0 : this->setDio0Action(func, this->mod->hal->GpioInterruptRising);
427 0 : }
428 :
429 0 : void SX127x::clearChannelScanAction() {
430 0 : this->clearDio0Action();
431 0 : }
432 :
433 0 : void SX127x::setFifoEmptyAction(void (*func)(void)) {
434 : // set DIO1 to the FIFO empty event (the register setting is done in startTransmit)
435 0 : setDio1Action(func, this->mod->hal->GpioInterruptRising);
436 0 : }
437 :
438 0 : void SX127x::clearFifoEmptyAction() {
439 0 : clearDio1Action();
440 0 : }
441 :
442 0 : void SX127x::setFifoThreshold(uint8_t threshold) {
443 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, threshold, 5, 0);
444 0 : }
445 :
446 0 : void SX127x::setFifoFullAction(void (*func)(void)) {
447 : // set the interrupt
448 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_FIFO_THRESH, 5, 0);
449 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_PACK_FIFO_LEVEL, 5, 4);
450 :
451 : // set DIO1 to the FIFO full event
452 0 : setDio1Action(func, this->mod->hal->GpioInterruptRising);
453 0 : }
454 :
455 0 : void SX127x::clearFifoFullAction() {
456 0 : clearDio1Action();
457 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, 0x00, 5, 4);
458 0 : }
459 :
460 0 : void SX127x::errataFix(bool rx) {
461 : (void)rx;
462 : // should be implemented in derived class
463 0 : }
464 :
465 0 : bool SX127x::fifoAdd(uint8_t* data, int totalLen, int* remLen) {
466 : // subtract first (this may be the first time we get to modify the remaining length)
467 0 : *remLen -= RADIOLIB_SX127X_FIFO_THRESH - 1;
468 :
469 : // check if there is still something left to send
470 0 : if(*remLen <= 0) {
471 : // we're done
472 0 : return(true);
473 : }
474 :
475 : // calculate the number of bytes we can copy
476 0 : int len = *remLen;
477 0 : if(len > RADIOLIB_SX127X_FIFO_THRESH - 1) {
478 0 : len = RADIOLIB_SX127X_FIFO_THRESH - 1;
479 : }
480 :
481 : // copy the bytes to the FIFO
482 0 : this->mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_FIFO, &data[totalLen - *remLen], len);
483 :
484 : // we're not done yet
485 0 : return(false);
486 : }
487 :
488 0 : bool SX127x::fifoGet(volatile uint8_t* data, int totalLen, volatile int* rcvLen) {
489 : // get pointer to the correct position in data buffer
490 0 : uint8_t* dataPtr = const_cast<uint8_t*>(&data[*rcvLen]);
491 :
492 : // check how much data are we still expecting
493 0 : uint8_t len = RADIOLIB_SX127X_FIFO_THRESH - 1;
494 0 : if(totalLen - *rcvLen < len) {
495 : // we're nearly at the end
496 0 : len = totalLen - *rcvLen;
497 : }
498 :
499 : // get the data
500 0 : this->mod->SPIreadRegisterBurst(RADIOLIB_SX127X_REG_FIFO, len, dataPtr);
501 0 : *rcvLen = *rcvLen + len;
502 :
503 : // check if we're done
504 0 : if(*rcvLen >= totalLen) {
505 0 : return(true);
506 : }
507 0 : return(false);
508 : }
509 :
510 6 : int16_t SX127x::finishTransmit() {
511 : // wait for at least 1 bit at the lowest possible bit rate before clearing IRQ flags
512 : // not doing this and clearing RADIOLIB_SX127X_FLAG_FIFO_OVERRUN will dump the FIFO,
513 : // which can lead to mangling of the last bit (#808)
514 6 : mod->hal->delayMicroseconds(1000000/1200);
515 :
516 : // clear interrupt flags
517 6 : clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
518 :
519 : // set mode to standby to disable transmitter/RF switch
520 6 : return(standby());
521 : }
522 :
523 6 : int16_t SX127x::readData(uint8_t* data, size_t len) {
524 6 : int16_t modem = getActiveModem();
525 :
526 : // get packet length
527 6 : size_t length = getPacketLength();
528 6 : size_t dumpLen = 0;
529 6 : if((len != 0) && (len < length)) {
530 : // user requested less data than we got, only return what was requested
531 6 : dumpLen = length - len;
532 6 : length = len;
533 : }
534 :
535 : // check payload CRC
536 6 : int16_t state = RADIOLIB_ERR_NONE;
537 6 : if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_IRQ_FLAGS, 5, 5) == RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR) {
538 6 : state = RADIOLIB_ERR_CRC_MISMATCH;
539 : }
540 :
541 6 : if(modem == RADIOLIB_SX127X_LORA) {
542 : // check packet header integrity
543 6 : if(this->crcEnabled && (state == RADIOLIB_ERR_NONE) && (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 6, 6) == 0)) {
544 : // CRC is disabled according to packet header and enabled according to user
545 : // most likely damaged packet header
546 0 : state = RADIOLIB_ERR_LORA_HEADER_DAMAGED;
547 : }
548 : // set FIFO read pointer to the start of the current packet
549 6 : int16_t addr = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FIFO_RX_CURRENT_ADDR);
550 6 : if (addr >= 0) {
551 6 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, addr);
552 : }
553 :
554 0 : } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
555 : // check address filtering
556 0 : uint8_t filter = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 2, 1);
557 0 : if((filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE) || (filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) {
558 0 : this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_FIFO);
559 : }
560 : }
561 :
562 : // read packet data
563 6 : this->mod->SPIreadRegisterBurst(RADIOLIB_SX127X_REG_FIFO, length, data);
564 :
565 : // dump the bytes that weren't requested
566 6 : if(dumpLen != 0) {
567 6 : clearFIFO(dumpLen);
568 : }
569 :
570 : // clear internal flag so getPacketLength can return the new packet length
571 6 : this->packetLengthQueried = false;
572 :
573 : // clear interrupt flags
574 6 : clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
575 :
576 6 : return(state);
577 : }
578 :
579 6 : int16_t SX127x::finishReceive() {
580 : // set mode to standby to disable RF switch
581 6 : int16_t state = standby();
582 6 : RADIOLIB_ASSERT(state);
583 :
584 : // clear interrupt flags
585 0 : return(clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL));
586 : }
587 :
588 18 : int16_t SX127x::startChannelScan() {
589 : // the configuration is not actually used
590 18 : const ChannelScanConfig_t cfg = { .rssi = { .limit = 0 } };
591 36 : return(startChannelScan(cfg));
592 : }
593 :
594 24 : int16_t SX127x::startChannelScan(const ChannelScanConfig_t &cfg) {
595 : (void)cfg;
596 :
597 : // check active modem
598 24 : if(getActiveModem() != RADIOLIB_SX127X_LORA) {
599 0 : return(RADIOLIB_ERR_WRONG_MODEM);
600 : }
601 :
602 : // set mode to standby
603 24 : int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
604 24 : RADIOLIB_ASSERT(state);
605 :
606 : // clear interrupt flags
607 0 : clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
608 :
609 : // set DIO pin mapping
610 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_CAD_DONE | RADIOLIB_SX127X_DIO1_LORA_CAD_DETECTED, 7, 4);
611 0 : RADIOLIB_ASSERT(state);
612 :
613 : // set RF switch (if present)
614 0 : this->mod->setRfSwitchState(Module::MODE_RX);
615 :
616 : // set mode to CAD
617 0 : state = setMode(RADIOLIB_SX127X_CAD);
618 0 : return(state);
619 : }
620 :
621 6 : int16_t SX127x::getChannelScanResult() {
622 6 : if((this->getIRQFlags() & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED) == RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED) {
623 6 : return(RADIOLIB_PREAMBLE_DETECTED);
624 : }
625 0 : return(RADIOLIB_CHANNEL_FREE);
626 : }
627 :
628 6 : int16_t SX127x::setSyncWord(uint8_t syncWord) {
629 : // check active modem
630 6 : if(getActiveModem() != RADIOLIB_SX127X_LORA) {
631 0 : return(RADIOLIB_ERR_WRONG_MODEM);
632 : }
633 :
634 : // set mode to standby
635 6 : setMode(RADIOLIB_SX127X_STANDBY);
636 :
637 : // write register
638 6 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_WORD, syncWord));
639 : }
640 :
641 0 : int16_t SX127x::setCurrentLimit(uint8_t currentLimit) {
642 : // check allowed range
643 0 : if(!(((currentLimit >= 45) && (currentLimit <= 240)) || (currentLimit == 0))) {
644 0 : return(RADIOLIB_ERR_INVALID_CURRENT_LIMIT);
645 : }
646 :
647 : // set mode to standby
648 0 : int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
649 :
650 : // set OCP limit
651 : uint8_t raw;
652 0 : if(currentLimit == 0) {
653 : // limit set to 0, disable OCP
654 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OCP, RADIOLIB_SX127X_OCP_OFF, 5, 5);
655 0 : } else if(currentLimit <= 120) {
656 0 : raw = (currentLimit - 45) / 5;
657 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OCP, RADIOLIB_SX127X_OCP_ON | raw, 5, 0);
658 0 : } else if(currentLimit <= 240) {
659 0 : raw = (currentLimit + 30) / 10;
660 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OCP, RADIOLIB_SX127X_OCP_ON | raw, 5, 0);
661 : }
662 0 : return(state);
663 : }
664 :
665 6 : int16_t SX127x::setPreambleLength(size_t preambleLength) {
666 : // set mode to standby
667 6 : int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
668 6 : RADIOLIB_ASSERT(state);
669 :
670 : // check active modem
671 0 : uint8_t modem = getActiveModem();
672 0 : if(modem == RADIOLIB_SX127X_LORA) {
673 : // check allowed range
674 0 : if(preambleLength < 6) {
675 0 : return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH);
676 : }
677 :
678 : // set preamble length
679 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB, (uint8_t)((preambleLength >> 8) & 0xFF));
680 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB, (uint8_t)(preambleLength & 0xFF));
681 0 : return(state);
682 :
683 0 : } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
684 : // set preamble length (in bytes)
685 0 : uint16_t numBytes = preambleLength / 8;
686 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK, (uint8_t)((numBytes >> 8) & 0xFF));
687 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK, (uint8_t)(numBytes & 0xFF));
688 0 : return(state);
689 : }
690 :
691 0 : return(RADIOLIB_ERR_UNKNOWN);
692 : }
693 :
694 0 : int16_t SX127x::invertPreamble(bool enable) {
695 : // set mode to standby
696 0 : int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
697 0 : RADIOLIB_ASSERT(state);
698 :
699 : // check active modem
700 0 : uint8_t modem = getActiveModem();
701 0 : if(modem == RADIOLIB_SX127X_LORA) {
702 0 : return(RADIOLIB_ERR_WRONG_MODEM);
703 0 : } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
704 : // set preamble polarity
705 0 : uint8_t polarity = enable ? RADIOLIB_SX127X_PREAMBLE_POLARITY_AA : RADIOLIB_SX127X_PREAMBLE_POLARITY_55;
706 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, polarity, 5, 5);
707 0 : return(state);
708 : }
709 :
710 0 : return(RADIOLIB_ERR_UNKNOWN);
711 : }
712 :
713 0 : float SX127x::getFrequencyError(bool autoCorrect) {
714 0 : int16_t modem = getActiveModem();
715 0 : if(modem == RADIOLIB_SX127X_LORA) {
716 : // get raw frequency error
717 0 : uint32_t raw = (uint32_t)this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_MSB, 3, 0) << 16;
718 0 : raw |= (uint16_t)this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_MID) << 8;
719 0 : raw |= this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_LSB);
720 :
721 0 : uint32_t base = (uint32_t)2 << 23;
722 : float error;
723 :
724 : // check the first bit
725 0 : if(raw & 0x80000) {
726 : // frequency error is negative
727 0 : raw |= (uint32_t)0xFFF00000;
728 0 : raw = ~raw + 1;
729 0 : error = (((float)raw * (float)base)/32000000.0f) * (this->bandwidth/500.0f) * -1.0f;
730 : } else {
731 0 : error = (((float)raw * (float)base)/32000000.0f) * (this->bandwidth/500.0f);
732 : }
733 :
734 0 : if(autoCorrect) {
735 : // adjust LoRa modem data rate
736 0 : float ppmOffset = 0.95f * (error/32.0f);
737 0 : this->mod->SPIwriteRegister(0x27, (uint8_t)ppmOffset);
738 : }
739 :
740 0 : return(error);
741 :
742 0 : } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
743 : // get raw frequency error
744 0 : uint16_t raw = (uint16_t)this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_MSB_FSK) << 8;
745 0 : raw |= this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_FEI_LSB_FSK);
746 :
747 0 : uint32_t base = 1;
748 : float error;
749 :
750 : // check the first bit
751 0 : if(raw & 0x8000) {
752 : // frequency error is negative
753 0 : raw |= (uint32_t)0xFFF00000;
754 0 : raw = ~raw + 1;
755 0 : error = (float)raw * (32000000.0f / (float)(base << 19)) * -1.0f;
756 : } else {
757 0 : error = (float)raw * (32000000.0f / (float)(base << 19));
758 : }
759 :
760 0 : return(error);
761 : }
762 :
763 0 : return(RADIOLIB_ERR_UNKNOWN);
764 : }
765 :
766 0 : float SX127x::getAFCError()
767 : {
768 : // check active modem
769 0 : int16_t modem = getActiveModem();
770 0 : if(modem != RADIOLIB_SX127X_FSK_OOK) {
771 0 : return 0;
772 : }
773 :
774 : // get raw frequency error
775 0 : int16_t raw = (uint16_t)this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_AFC_MSB) << 8;
776 0 : raw |= this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_AFC_LSB);
777 :
778 0 : uint32_t base = 1;
779 0 : return raw * (32000000.0f / (float)(base << 19));
780 : }
781 :
782 12 : float SX127x::getSNR() {
783 : // check active modem
784 12 : if(getActiveModem() != RADIOLIB_SX127X_LORA) {
785 0 : return(0);
786 : }
787 :
788 : // get SNR value
789 12 : int8_t rawSNR = (int8_t)this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PKT_SNR_VALUE);
790 12 : return(rawSNR / 4.0);
791 : }
792 :
793 6 : int16_t SX127x::setBitRateCommon(float br, uint8_t fracRegAddr) {
794 : // check active modem
795 6 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
796 6 : return(RADIOLIB_ERR_WRONG_MODEM);
797 : }
798 :
799 : // check allowed bit rate
800 : // datasheet says 1.2 kbps should be the smallest possible, but 0.512 works fine
801 0 : if(ookEnabled) {
802 0 : RADIOLIB_CHECK_RANGE(br, 0.5f, 32.768002f, RADIOLIB_ERR_INVALID_BIT_RATE); // Found that 32.768 is 32.768002
803 : } else {
804 0 : RADIOLIB_CHECK_RANGE(br, 0.5f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
805 : }
806 :
807 : // set mode to STANDBY
808 0 : int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
809 0 : RADIOLIB_ASSERT(state);
810 :
811 : // set bit rate
812 0 : uint16_t bitRateRaw = (RADIOLIB_SX127X_CRYSTAL_FREQ * 1000.0f) / br;
813 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BITRATE_MSB, (bitRateRaw & 0xFF00) >> 8, 7, 0);
814 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BITRATE_LSB, bitRateRaw & 0x00FF, 7, 0);
815 :
816 : // set fractional part of bit rate
817 0 : if(!ookEnabled) {
818 0 : float bitRateRem = ((RADIOLIB_SX127X_CRYSTAL_FREQ * 1000.0f) / br) - (float)bitRateRaw;
819 0 : uint8_t bitRateFrac = bitRateRem * 16;
820 0 : state |= this->mod->SPIsetRegValue(fracRegAddr, bitRateFrac, 7, 0);
821 : }
822 :
823 0 : if(state == RADIOLIB_ERR_NONE) {
824 0 : this->bitRate = br;
825 : }
826 0 : return(state);
827 : }
828 :
829 6 : int16_t SX127x::setFrequencyDeviation(float freqDev) {
830 : // check active modem
831 6 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
832 6 : return(RADIOLIB_ERR_WRONG_MODEM);
833 : }
834 :
835 : // set frequency deviation to lowest available setting (required for digimodes)
836 0 : float newFreqDev = freqDev;
837 0 : if(freqDev < 0.0f) {
838 0 : newFreqDev = 0.6f;
839 : }
840 :
841 : // check frequency deviation range
842 0 : if(!((newFreqDev + this->bitRate/2.0f <= 250.0f) && (freqDev <= 200.0f))) {
843 0 : return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
844 : }
845 :
846 0 : this->frequencyDev = newFreqDev;
847 :
848 : // set mode to STANDBY
849 0 : int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
850 0 : RADIOLIB_ASSERT(state);
851 :
852 : // set allowed frequency deviation
853 0 : uint32_t base = 1;
854 0 : uint32_t FDEV = (newFreqDev * (base << 19)) / 32000;
855 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FDEV_MSB, (FDEV & 0xFF00) >> 8, 5, 0);
856 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FDEV_LSB, FDEV & 0x00FF, 7, 0);
857 0 : return(state);
858 : }
859 :
860 0 : int16_t SX127x::setRxBandwidth(float rxBw) {
861 0 : return(this->setRxBw(rxBw, false));
862 : }
863 :
864 0 : int16_t SX127x::setAFCBandwidth(float rxBw) {
865 0 : return(this->setRxBw(rxBw, true));
866 : }
867 :
868 0 : int16_t SX127x::findRxBw(float rxBw, const uint8_t* lut, size_t lutSize, float rxBwMax, uint8_t* val) {
869 : // lookup tables to avoid comparing a whole bunch of floats
870 0 : const uint16_t rxBwAvg[] = {
871 : 29, 35, 46, 58, 71, 91, 115, 141,
872 : 182, 229, 282, 365, 459, 563, 729,
873 : 917, 1125, 1459, 1834, 2250,
874 : };
875 :
876 : // iterate through the table and find whether the user-provided value
877 : // is lower than the pre-computed average of the adjacent bandwidth values
878 : // if it is, we consider that to be a match even though the actual value is not precise
879 0 : uint16_t rxBwInt = rxBw*10.0f;
880 0 : for(size_t i = 0; i < (lutSize - 1); i++) {
881 0 : if(rxBwInt < rxBwAvg[i]) {
882 0 : *val = lut[i];
883 0 : return(RADIOLIB_ERR_NONE);
884 : }
885 : }
886 :
887 : // if nothing matched up to here, match with the last value
888 0 : if(rxBwInt <= rxBwMax*10) {
889 0 : *val = lut[lutSize - 1];
890 0 : return(RADIOLIB_ERR_NONE);
891 : }
892 :
893 0 : return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH);
894 : }
895 :
896 0 : int16_t SX127x::setRxBw(float rxBw, bool afc) {
897 : // check active modem
898 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK){
899 0 : return(RADIOLIB_ERR_WRONG_MODEM);
900 : }
901 :
902 0 : const uint8_t rxBwLut[] = {
903 : RADIOLIB_SX127X_RX_BW_2_6,
904 : RADIOLIB_SX127X_RX_BW_3_1,
905 : RADIOLIB_SX127X_RX_BW_3_9,
906 : RADIOLIB_SX127X_RX_BW_5_2,
907 : RADIOLIB_SX127X_RX_BW_6_3,
908 : RADIOLIB_SX127X_RX_BW_7_8,
909 : RADIOLIB_SX127X_RX_BW_10_4,
910 : RADIOLIB_SX127X_RX_BW_12_5,
911 : RADIOLIB_SX127X_RX_BW_15_6,
912 : RADIOLIB_SX127X_RX_BW_20_8,
913 : RADIOLIB_SX127X_RX_BW_25_0,
914 : RADIOLIB_SX127X_RX_BW_31_3,
915 : RADIOLIB_SX127X_RX_BW_41_7,
916 : RADIOLIB_SX127X_RX_BW_50_0,
917 : RADIOLIB_SX127X_RX_BW_62_5,
918 : RADIOLIB_SX127X_RX_BW_83_3,
919 : RADIOLIB_SX127X_RX_BW_100,
920 : RADIOLIB_SX127X_RX_BW_125,
921 : RADIOLIB_SX127X_RX_BW_167,
922 : RADIOLIB_SX127X_RX_BW_200,
923 : RADIOLIB_SX127X_RX_BW_250,
924 : };
925 :
926 0 : uint8_t rxBwRaw = 0;
927 0 : int16_t state = findRxBw(rxBw, rxBwLut, sizeof(rxBwLut)/sizeof(rxBwLut[0]), 250.0f, &rxBwRaw);
928 0 : RADIOLIB_ASSERT(state);
929 :
930 : // set mode to STANDBY
931 0 : state = setMode(RADIOLIB_SX127X_STANDBY);
932 0 : RADIOLIB_ASSERT(state);
933 :
934 : // set AFC bandwidth
935 0 : uint8_t reg = afc ? RADIOLIB_SX127X_REG_AFC_BW : RADIOLIB_SX127X_REG_RX_BW;
936 0 : return(this->mod->SPIsetRegValue(reg, rxBwRaw, 4, 0));
937 : }
938 :
939 0 : int16_t SX127x::setAFC(bool isEnabled) {
940 : // check active modem
941 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
942 0 : return(RADIOLIB_ERR_WRONG_MODEM);
943 : }
944 :
945 : //set AFC auto on/off
946 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, isEnabled ? RADIOLIB_SX127X_AFC_AUTO_ON : RADIOLIB_SX127X_AFC_AUTO_OFF, 4, 4));
947 : }
948 :
949 0 : int16_t SX127x::setAFCAGCTrigger(uint8_t trigger) {
950 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
951 0 : return(RADIOLIB_ERR_WRONG_MODEM);
952 : }
953 :
954 : //set AFC&AGC trigger
955 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, trigger, 2, 0));
956 : }
957 :
958 6 : int16_t SX127x::setSyncWord(uint8_t* syncWord, size_t len) {
959 : // check active modem
960 6 : uint8_t modem = getActiveModem();
961 6 : if(modem == RADIOLIB_SX127X_FSK_OOK) {
962 :
963 : // disable sync word in case len is 0
964 0 : if(len == 0) {
965 0 : int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, RADIOLIB_SX127X_SYNC_OFF, 4, 4);
966 0 : return(state);
967 : }
968 :
969 0 : RADIOLIB_CHECK_RANGE(len, 1, 8, RADIOLIB_ERR_INVALID_SYNC_WORD);
970 :
971 : // sync word must not contain value 0x00
972 0 : for(size_t i = 0; i < len; i++) {
973 0 : if(syncWord[i] == 0x00) {
974 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
975 : }
976 : }
977 :
978 : // enable sync word recognition
979 0 : int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, RADIOLIB_SX127X_SYNC_ON, 4, 4);
980 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, len - 1, 2, 0);
981 0 : RADIOLIB_ASSERT(state);
982 :
983 : // set sync word
984 0 : this->mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_SYNC_VALUE_1, syncWord, len);
985 0 : return(RADIOLIB_ERR_NONE);
986 :
987 6 : } else if(modem == RADIOLIB_SX127X_LORA) {
988 : // with length set to 1 and LoRa modem active, assume it is the LoRa sync word
989 6 : if(len > 1) {
990 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
991 : }
992 :
993 6 : return(this->setSyncWord(syncWord[0]));
994 : }
995 :
996 0 : return(RADIOLIB_ERR_WRONG_MODEM);
997 : }
998 :
999 0 : int16_t SX127x::setNodeAddress(uint8_t nodeAddr) {
1000 : // check active modem
1001 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
1002 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1003 : }
1004 :
1005 : // enable address filtering (node only)
1006 0 : int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_ADDRESS_FILTERING_NODE, 2, 1);
1007 0 : RADIOLIB_ASSERT(state);
1008 :
1009 : // set node address
1010 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_NODE_ADRS, nodeAddr));
1011 : }
1012 :
1013 0 : int16_t SX127x::setBroadcastAddress(uint8_t broadAddr) {
1014 : // check active modem
1015 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
1016 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1017 : }
1018 :
1019 : // enable address filtering (node + broadcast)
1020 0 : int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST, 2, 1);
1021 0 : RADIOLIB_ASSERT(state);
1022 :
1023 : // set broadcast address
1024 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BROADCAST_ADRS, broadAddr));
1025 : }
1026 :
1027 0 : int16_t SX127x::disableAddressFiltering() {
1028 : // check active modem
1029 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
1030 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1031 : }
1032 :
1033 : // disable address filtering
1034 0 : int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_ADDRESS_FILTERING_OFF, 2, 1);
1035 0 : RADIOLIB_ASSERT(state);
1036 :
1037 : // set node address to default (0x00)
1038 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_NODE_ADRS, 0x00);
1039 0 : RADIOLIB_ASSERT(state);
1040 :
1041 : // set broadcast address to default (0x00)
1042 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BROADCAST_ADRS, 0x00));
1043 : }
1044 :
1045 0 : int16_t SX127x::setOokThresholdType(uint8_t type) {
1046 : // check active modem
1047 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
1048 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1049 : }
1050 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, type, 4, 3, 5));
1051 : }
1052 :
1053 0 : int16_t SX127x::setOokFixedOrFloorThreshold(uint8_t value) {
1054 : // check active modem
1055 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
1056 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1057 : }
1058 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_FIX, value, 7, 0, 5));
1059 : }
1060 :
1061 0 : int16_t SX127x::setOokPeakThresholdDecrement(uint8_t value) {
1062 : // check active modem
1063 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
1064 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1065 : }
1066 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_AVG, value, 7, 5, 5));
1067 : }
1068 :
1069 0 : int16_t SX127x::setOokPeakThresholdStep(uint8_t value) {
1070 : // check active modem
1071 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
1072 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1073 : }
1074 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, value, 2, 0, 5));
1075 : }
1076 :
1077 0 : int16_t SX127x::enableBitSync() {
1078 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, RADIOLIB_SX127X_BIT_SYNC_ON, 5, 5, 5));
1079 : }
1080 :
1081 0 : int16_t SX127x::disableBitSync() {
1082 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, RADIOLIB_SX127X_BIT_SYNC_OFF, 5, 5, 5));
1083 : }
1084 :
1085 0 : int16_t SX127x::setOOK(bool enable) {
1086 : // check active modem
1087 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
1088 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1089 : }
1090 :
1091 : // set OOK and if successful, save the new setting
1092 0 : int16_t state = RADIOLIB_ERR_NONE;
1093 0 : if(enable) {
1094 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX127X_MODULATION_OOK, 6, 5, 5);
1095 0 : state |= SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_RSSI_INTERRUPT);
1096 : } else {
1097 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX127X_MODULATION_FSK, 6, 5, 5);
1098 0 : state |= SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_BOTH);
1099 : }
1100 0 : if(state == RADIOLIB_ERR_NONE) {
1101 0 : this->ookEnabled = enable;
1102 : }
1103 :
1104 0 : return(state);
1105 : }
1106 :
1107 0 : int16_t SX127x::setFrequencyRaw(float newFreq) {
1108 0 : int16_t state = RADIOLIB_ERR_NONE;
1109 :
1110 : // set mode to standby if not FHSS
1111 0 : if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) == RADIOLIB_SX127X_HOP_PERIOD_OFF) {
1112 0 : state = setMode(RADIOLIB_SX127X_STANDBY);
1113 : }
1114 :
1115 : // calculate register values
1116 0 : uint32_t FRF = (newFreq * (uint32_t(1) << RADIOLIB_SX127X_DIV_EXPONENT)) / RADIOLIB_SX127X_CRYSTAL_FREQ;
1117 :
1118 : // write registers
1119 : // lsb needs to be written no matter what in order for the module to update the frequency
1120 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FRF_MSB, (FRF & 0xFF0000) >> 16);
1121 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FRF_MID, (FRF & 0x00FF00) >> 8);
1122 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FRF_LSB, FRF & 0x0000FF, 7U, 0U, 2U, 0xFF, true);
1123 0 : return(state);
1124 : }
1125 :
1126 12 : size_t SX127x::getPacketLength(bool update) {
1127 12 : int16_t modem = getActiveModem();
1128 :
1129 12 : if(modem == RADIOLIB_SX127X_LORA) {
1130 12 : if(!this->implicitHdr) {
1131 : // get packet length for explicit header mode
1132 12 : return(this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_RX_NB_BYTES));
1133 :
1134 : } else {
1135 : // return the cached value for implicit header mode
1136 0 : return(this->packetLength);
1137 : }
1138 :
1139 0 : } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
1140 : // get packet length
1141 0 : if(!this->packetLengthQueried && update) {
1142 0 : if (this->packetLengthConfig == RADIOLIB_SX127X_PACKET_VARIABLE) {
1143 0 : this->packetLength = this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_FIFO);
1144 : } else {
1145 0 : this->packetLength = this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK);
1146 : }
1147 0 : this->packetLengthQueried = true;
1148 : }
1149 : }
1150 :
1151 0 : return(this->packetLength);
1152 : }
1153 :
1154 0 : int16_t SX127x::getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC) {
1155 0 : int16_t state = RADIOLIB_ERR_NONE;
1156 :
1157 : // check if in explicit header mode
1158 0 : if(this->implicitHdr) {
1159 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1160 : }
1161 :
1162 0 : if(cr) { *cr = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_STAT, 7, 5) >> 5; }
1163 0 : if(hasCRC) { *hasCRC = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 6, 6) != 0; }
1164 :
1165 0 : return(state);
1166 : }
1167 :
1168 0 : int16_t SX127x::fixedPacketLengthMode(uint8_t len) {
1169 0 : return(SX127x::setPacketMode(RADIOLIB_SX127X_PACKET_FIXED, len));
1170 : }
1171 :
1172 0 : int16_t SX127x::variablePacketLengthMode(uint8_t maxLen) {
1173 0 : return(SX127x::setPacketMode(RADIOLIB_SX127X_PACKET_VARIABLE, maxLen));
1174 : }
1175 :
1176 18 : float SX127x::getNumSymbols(size_t len, DataRate_t dr, PacketConfig_t pc) {
1177 : // get Low Data Rate optimization flag
1178 18 : float de = pc.lora.ldrOptimize ? 1.0f : 0.0f;
1179 :
1180 : // get explicit/implicit header enabled flag
1181 18 : float ih = (float) pc.lora.implicitHeader;
1182 :
1183 : // get CRC enabled flag
1184 18 : float crc = (float) pc.lora.crcEnabled;
1185 :
1186 : // get number of preamble symbols
1187 18 : float n_pre = (float) pc.lora.preambleLength;
1188 :
1189 : // get number of payload symbols
1190 18 : float n_pay = 8.0f + RADIOLIB_MAX(ceilf((8.0f * (float) len - 4.0f * (float) dr.lora.spreadingFactor + 28.0f + 16.0f * crc - 20.0f * ih) / (4.0f * (float) dr.lora.spreadingFactor - 8.0f * de)) * (float) dr.lora.codingRate, 0.0f);
1191 :
1192 : // add 4.25 symbols for the sync
1193 18 : return(n_pre + n_pay + 4.25f);
1194 : }
1195 :
1196 28 : RadioLibTime_t SX127x::calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) {
1197 28 : if (modem == RADIOLIB_MODEM_LORA) {
1198 : // get symbol length in us
1199 18 : float symbolLength = (float) (uint32_t(1) << dr.lora.spreadingFactor) / (float) dr.lora.bandwidth;
1200 :
1201 : // get number of symbols
1202 18 : float n_sym = getNumSymbols(len, dr, pc);
1203 :
1204 : // get time-on-air in us
1205 18 : return ceil((double)symbolLength * (double)n_sym) * 1000;
1206 :
1207 10 : } else if(modem == RADIOLIB_MODEM_FSK) {
1208 :
1209 : // calculate time-on-air in us {[(length in bytes) * (8 bits / 1 byte)] / [(Bit Rate in kbps) * (1000 bps / 1 kbps)]} * (1000000 us in 1 sec)
1210 4 : return((uint32_t) ((((float)(pc.fsk.crcLength * 8) + pc.fsk.syncWordLength + pc.fsk.preambleLength + (float) (len * 8)) / (dr.fsk.bitRate * 1000.0f)) * 1000000.0f));
1211 : } else {
1212 6 : return(RADIOLIB_ERR_WRONG_MODEM);
1213 : }
1214 :
1215 : return(RADIOLIB_ERR_UNKNOWN);
1216 : }
1217 :
1218 6 : RadioLibTime_t SX127x::getTimeOnAir(size_t len) {
1219 6 : uint8_t modem = getActiveModem();
1220 6 : DataRate_t dr = {};
1221 6 : PacketConfig_t pc = {};
1222 :
1223 6 : switch (modem) {
1224 6 : case(RADIOLIB_SX127X_LORA): {
1225 6 : dr.lora.spreadingFactor = this->spreadingFactor;
1226 6 : dr.lora.bandwidth = this->bandwidth;
1227 6 : dr.lora.codingRate = this->codingRate;
1228 :
1229 : // Get number of preamble symbols
1230 6 : uint16_t n_pre = ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB));
1231 :
1232 6 : pc.lora.preambleLength = n_pre;
1233 6 : pc.lora.implicitHeader = this->implicitHdr;
1234 6 : pc.lora.crcEnabled = this->crcEnabled;
1235 6 : pc.lora.ldrOptimize = this->ldroEnabled;
1236 :
1237 6 : return(calculateTimeOnAir((ModemType_t)RADIOLIB_MODEM_LORA, dr, pc, len));
1238 : }
1239 0 : case(RADIOLIB_SX127X_FSK_OOK): {
1240 0 : dr.fsk.bitRate = this->bitRate;
1241 0 : dr.fsk.freqDev = this->frequencyDev;
1242 :
1243 : // get number of bits preamble
1244 0 : uint16_t n_pre = (uint16_t) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB_FSK) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB_FSK)) * 8;
1245 : // get the number of bits of the sync word
1246 0 : uint8_t n_syncWord = (uint8_t) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, 2, 0) + 1) * 8);
1247 : // get CRC enabled status
1248 0 : bool crcEn = (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 4, 4) == RADIOLIB_SX127X_CRC_ON);
1249 :
1250 0 : pc.fsk.preambleLength = n_pre;
1251 0 : pc.fsk.syncWordLength = n_syncWord;
1252 0 : pc.fsk.crcLength = (uint8_t)(crcEn * 2);
1253 :
1254 0 : if (this->packetLengthConfig == RADIOLIB_SX127X_PACKET_FIXED) {
1255 : // if packet size fixed -> len = fixed packet length
1256 0 : len = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK);
1257 : } else {
1258 : // if packet variable -> Add 1 extra byte for payload length
1259 0 : len += 1;
1260 : }
1261 :
1262 0 : return(calculateTimeOnAir((ModemType_t)RADIOLIB_MODEM_FSK, dr, pc, len));
1263 : }
1264 0 : default:
1265 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1266 : }
1267 : }
1268 :
1269 6 : RadioLibTime_t SX127x::calculateRxTimeout(RadioLibTime_t timeoutUs) {
1270 6 : RadioLibTime_t timeout = 0;
1271 6 : if(getActiveModem() == RADIOLIB_SX127X_LORA) {
1272 : // for LoRa, the timeout is given as the number of symbols
1273 : // the calling function should provide some extra width, as this number of symbols is truncated to integer
1274 : // the order of operators is swapped here to decrease the effects of this truncation error
1275 6 : float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth;
1276 6 : timeout = (timeoutUs / symbolLength) / 1000;
1277 :
1278 : } else {
1279 : // for FSK, the timeout is in units of 16x bit time
1280 0 : timeout = ((float)timeoutUs / ((16.0f * 1000.0f) / this->bitRate));
1281 :
1282 : }
1283 :
1284 6 : return(timeout);
1285 : }
1286 :
1287 6 : uint32_t SX127x::getIrqFlags() {
1288 6 : return((uint32_t)this->getIRQFlags());
1289 : }
1290 :
1291 6 : int16_t SX127x::setIrqFlags(uint32_t irq) {
1292 : // this is a bit convoluted, but unfortunately SX127x IRQ flags are not used to enable/disable that IRQ ...
1293 : // in addition, the configuration is often mutually exclusive, so we iterate over the set bits in a loop
1294 6 : uint8_t usedPinFlags = 0;
1295 6 : bool conflict = false;
1296 6 : int16_t modem = getActiveModem();
1297 6 : int16_t state = RADIOLIB_ERR_NONE;
1298 198 : for(uint8_t i = 0; i <= 31; i++) {
1299 : // check if the bit is set
1300 192 : uint32_t irqBit = irq & (1UL << i);
1301 192 : if(!irqBit) {
1302 192 : continue;
1303 : }
1304 :
1305 : // if not, decode it
1306 0 : uint8_t dioNum = 0; // DIO pin number and register value to set (address and MSB/LSB can be inferred)
1307 0 : uint8_t regVal = 0;
1308 0 : if(modem == RADIOLIB_SX127X_LORA) {
1309 0 : switch(irqBit) {
1310 0 : case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_TX_DONE):
1311 0 : dioNum = 0;
1312 0 : regVal = RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT;
1313 0 : break;
1314 0 : case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_DONE):
1315 0 : dioNum = 0;
1316 0 : regVal = RADIOLIB_SX127X_DIO0_LORA_RX_DONE;
1317 0 : break;
1318 0 : case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_VALID_HEADER):
1319 0 : dioNum = 3;
1320 0 : regVal = RADIOLIB_SX127X_DIO3_LORA_VALID_HEADER;
1321 0 : break;
1322 0 : case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR):
1323 0 : dioNum = 3;
1324 0 : regVal = RADIOLIB_SX127X_DIO3_LORA_PAYLOAD_CRC_ERROR;
1325 0 : break;
1326 0 : case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DONE):
1327 0 : dioNum = 0;
1328 0 : regVal = RADIOLIB_SX127X_DIO0_LORA_CAD_DONE;
1329 0 : break;
1330 0 : case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED):
1331 0 : dioNum = 1;
1332 0 : regVal = RADIOLIB_SX127X_DIO1_LORA_CAD_DETECTED;
1333 0 : break;
1334 0 : case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT):
1335 0 : dioNum = 1;
1336 0 : regVal = RADIOLIB_SX127X_DIO1_LORA_RX_TIMEOUT;
1337 0 : break;
1338 0 : default:
1339 0 : return(RADIOLIB_ERR_UNSUPPORTED);
1340 : }
1341 :
1342 0 : } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
1343 0 : switch(irqBit) {
1344 0 : case(RADIOLIB_SX127X_FLAG_PACKET_SENT << 8):
1345 0 : dioNum = 0;
1346 0 : regVal = RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT;
1347 0 : break;
1348 0 : case(RADIOLIB_SX127X_FLAG_PAYLOAD_READY << 8):
1349 0 : dioNum = 0;
1350 0 : regVal = RADIOLIB_SX127X_DIO0_PACK_PAYLOAD_READY;
1351 0 : break;
1352 0 : case(RADIOLIB_SX127X_FLAG_PREAMBLE_DETECT << 0):
1353 0 : dioNum = 4;
1354 0 : regVal = RADIOLIB_SX127X_DIO4_PACK_RSSI_PREAMBLE_DETECT;
1355 0 : break;
1356 0 : case(RADIOLIB_SX127X_FLAG_SYNC_ADDRESS_MATCH << 0):
1357 0 : dioNum = 2;
1358 0 : regVal = RADIOLIB_SX127X_DIO2_PACK_SYNC_ADDRESS;
1359 0 : break;
1360 0 : case(RADIOLIB_SX127X_FLAG_TIMEOUT << 0):
1361 0 : dioNum = 2;
1362 0 : regVal = RADIOLIB_SX127X_DIO2_PACK_TIMEOUT;
1363 0 : break;
1364 0 : default:
1365 0 : return(RADIOLIB_ERR_UNSUPPORTED);
1366 : }
1367 : }
1368 :
1369 : // check if this DIO pin has been set already
1370 0 : if(usedPinFlags & (1UL << dioNum)) {
1371 : // uh oh, this pin is used!
1372 : RADIOLIB_DEBUG_PRINTLN("Unable to set IRQ %04x on DIO%d due to conflict!", irqBit, (int)dioNum);
1373 0 : conflict = true;
1374 0 : continue;
1375 : }
1376 :
1377 : // DIO pin is unused, set the flag and configure it
1378 0 : usedPinFlags |= (1UL << dioNum);
1379 0 : uint8_t addr = (dioNum > 3) ? RADIOLIB_SX127X_REG_DIO_MAPPING_2 : RADIOLIB_SX127X_REG_DIO_MAPPING_1;
1380 0 : uint8_t msb = 7 - 2*(dioNum % 4);
1381 0 : state = this->mod->SPIsetRegValue(addr, regVal, msb, msb - 1);
1382 0 : RADIOLIB_ASSERT(state);
1383 : }
1384 :
1385 : // if there was at least one conflict, this flag is set
1386 6 : if(conflict) {
1387 0 : return(RADIOLIB_ERR_INVALID_IRQ);
1388 : }
1389 :
1390 6 : return(state);
1391 : }
1392 :
1393 24 : int16_t SX127x::clearIrqFlags(uint32_t irq) {
1394 24 : int16_t modem = getActiveModem();
1395 24 : if(modem == RADIOLIB_SX127X_LORA) {
1396 24 : this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, (uint8_t)irq);
1397 24 : return(RADIOLIB_ERR_NONE);
1398 :
1399 0 : } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
1400 0 : this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_1, (uint8_t)irq);
1401 0 : this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_2, (uint8_t)(irq >> 8));
1402 0 : return(RADIOLIB_ERR_NONE);
1403 : }
1404 :
1405 0 : return(RADIOLIB_ERR_UNKNOWN);
1406 : }
1407 :
1408 0 : int16_t SX127x::setCrcFiltering(bool enable) {
1409 0 : this->crcOn = enable;
1410 :
1411 0 : if (enable == true) {
1412 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_ON, 4, 4));
1413 : } else {
1414 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_OFF, 4, 4));
1415 : }
1416 : }
1417 :
1418 0 : int16_t SX127x::setRSSIThreshold(float dbm) {
1419 0 : RADIOLIB_CHECK_RANGE(dbm, -127.5f, 0.0f, RADIOLIB_ERR_INVALID_RSSI_THRESHOLD);
1420 :
1421 0 : return this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_THRESH, (uint8_t)(-2.0f * dbm), 7, 0);
1422 : }
1423 :
1424 0 : int16_t SX127x::setRSSIConfig(uint8_t smoothingSamples, int8_t offset) {
1425 : // check active modem
1426 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
1427 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1428 : }
1429 :
1430 : // set mode to standby
1431 0 : int16_t state = standby();
1432 0 : RADIOLIB_ASSERT(state);
1433 :
1434 : // check provided values
1435 0 : if(!(smoothingSamples <= 7)) {
1436 0 : return(RADIOLIB_ERR_INVALID_NUM_SAMPLES);
1437 : }
1438 :
1439 0 : RADIOLIB_CHECK_RANGE(offset, -16, 15, RADIOLIB_ERR_INVALID_RSSI_OFFSET);
1440 :
1441 : // calculate the two's complement
1442 0 : uint8_t offsetRaw = RADIOLIB_ABS(offset);
1443 0 : offsetRaw ^= 0x1F;
1444 0 : offsetRaw += 1;
1445 0 : offsetRaw &= 0x1F;
1446 :
1447 : // set new register values
1448 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_CONFIG, offsetRaw << 3, 7, 3);
1449 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_CONFIG, smoothingSamples, 2, 0);
1450 0 : return(state);
1451 : }
1452 :
1453 6 : int16_t SX127x::setEncoding(uint8_t encoding) {
1454 : // check active modem
1455 6 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
1456 6 : return(RADIOLIB_ERR_WRONG_MODEM);
1457 : }
1458 :
1459 : // set encoding
1460 0 : switch(encoding) {
1461 0 : case RADIOLIB_ENCODING_NRZ:
1462 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_DC_FREE_NONE, 6, 5));
1463 0 : case RADIOLIB_ENCODING_MANCHESTER:
1464 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_DC_FREE_MANCHESTER, 6, 5));
1465 0 : case RADIOLIB_ENCODING_WHITENING:
1466 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_DC_FREE_WHITENING, 6, 5));
1467 0 : default:
1468 0 : return(RADIOLIB_ERR_INVALID_ENCODING);
1469 : }
1470 : }
1471 :
1472 12 : uint16_t SX127x::getIRQFlags() {
1473 : // check active modem
1474 12 : if(getActiveModem() == RADIOLIB_SX127X_LORA) {
1475 : // LoRa, just 8-bit value
1476 12 : return((uint16_t)this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS));
1477 :
1478 : } else {
1479 : // FSK, the IRQ flags are 16 bits in total
1480 0 : uint16_t flags = ((uint16_t)this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_2)) << 8;
1481 0 : flags |= (uint16_t)this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_1);
1482 0 : return(flags);
1483 : }
1484 :
1485 : }
1486 :
1487 0 : uint8_t SX127x::getModemStatus() {
1488 : // check active modem
1489 0 : if(getActiveModem() != RADIOLIB_SX127X_LORA) {
1490 0 : return(0x00);
1491 : }
1492 :
1493 : // read the register
1494 0 : return(this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_MODEM_STAT));
1495 : }
1496 :
1497 0 : void SX127x::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) {
1498 0 : this->mod->setRfSwitchPins(rxEn, txEn);
1499 0 : }
1500 :
1501 0 : void SX127x::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) {
1502 0 : this->mod->setRfSwitchTable(pins, table);
1503 0 : }
1504 :
1505 6 : uint8_t SX127x::randomByte() {
1506 : // check active modem
1507 6 : uint8_t rssiValueReg = RADIOLIB_SX127X_REG_RSSI_WIDEBAND;
1508 6 : if(getActiveModem() == RADIOLIB_SX127X_FSK_OOK) {
1509 0 : rssiValueReg = RADIOLIB_SX127X_REG_RSSI_VALUE_FSK;
1510 : }
1511 :
1512 : // set mode to Rx
1513 6 : setMode(RADIOLIB_SX127X_RX);
1514 :
1515 : // wait a bit for the RSSI reading to stabilise
1516 6 : this->mod->hal->delay(10);
1517 :
1518 : // read RSSI value 8 times, always keep just the least significant bit
1519 6 : uint8_t randByte = 0x00;
1520 54 : for(uint8_t i = 0; i < 8; i++) {
1521 48 : randByte |= ((this->mod->SPIreadRegister(rssiValueReg) & 0x01) << i);
1522 : }
1523 :
1524 : // set mode to standby
1525 6 : setMode(RADIOLIB_SX127X_STANDBY);
1526 :
1527 6 : return(randByte);
1528 : }
1529 :
1530 0 : int16_t SX127x::getChipVersion() {
1531 0 : return(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_VERSION));
1532 : }
1533 :
1534 0 : int8_t SX127x::getTempRaw() {
1535 0 : int8_t temp = 0;
1536 : uint8_t previousOpMode;
1537 : uint8_t ival;
1538 :
1539 : // save current Op Mode
1540 0 : previousOpMode = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_OP_MODE);
1541 :
1542 : // check if we need to step out of LoRa mode first
1543 0 : if((previousOpMode & RADIOLIB_SX127X_LORA) == RADIOLIB_SX127X_LORA) {
1544 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_LORA | RADIOLIB_SX127X_SLEEP));
1545 : }
1546 :
1547 : // put device in FSK sleep
1548 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_FSK_OOK | RADIOLIB_SX127X_SLEEP));
1549 :
1550 : // put device in FSK RxSynth
1551 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_FSK_OOK | RADIOLIB_SX127X_FSRX));
1552 :
1553 : // enable temperature reading
1554 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_IMAGE_CAL, RADIOLIB_SX127X_TEMP_MONITOR_ON, 0, 0);
1555 :
1556 : // wait
1557 0 : this->mod->hal->delayMicroseconds(200);
1558 :
1559 : // disable temperature reading
1560 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_IMAGE_CAL, RADIOLIB_SX127X_TEMP_MONITOR_OFF, 0, 0);
1561 :
1562 : // put device in FSK sleep
1563 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_FSK_OOK | RADIOLIB_SX127X_SLEEP));
1564 :
1565 : // read temperature
1566 0 : ival = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_TEMP);
1567 :
1568 : // convert very raw value
1569 0 : if((ival & 0x80) == 0x80) {
1570 0 : temp = 255 - ival;
1571 : } else {
1572 0 : temp = -1 * ival;
1573 : }
1574 :
1575 : // check if we need to step back into LoRa mode
1576 0 : if((previousOpMode & RADIOLIB_SX127X_LORA) == RADIOLIB_SX127X_LORA) {
1577 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_LORA | RADIOLIB_SX127X_SLEEP));
1578 : }
1579 :
1580 : // reload previous Op Mode
1581 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, previousOpMode);
1582 :
1583 0 : return(temp);
1584 : }
1585 :
1586 6 : Module* SX127x::getMod() {
1587 6 : return(this->mod);
1588 : }
1589 :
1590 0 : int16_t SX127x::config() {
1591 : // turn off frequency hopping
1592 0 : int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, RADIOLIB_SX127X_HOP_PERIOD_OFF);
1593 0 : return(state);
1594 : }
1595 :
1596 0 : int16_t SX127x::configFSK() {
1597 : // set RSSI threshold
1598 0 : int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_THRESH, RADIOLIB_SX127X_RSSI_THRESHOLD);
1599 0 : RADIOLIB_ASSERT(state);
1600 :
1601 : // reset FIFO flag
1602 0 : this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_2, RADIOLIB_SX127X_FLAG_FIFO_OVERRUN);
1603 :
1604 : // set packet configuration
1605 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_PACKET_VARIABLE | RADIOLIB_SX127X_DC_FREE_NONE | RADIOLIB_SX127X_CRC_ON | RADIOLIB_SX127X_CRC_AUTOCLEAR_ON | RADIOLIB_SX127X_ADDRESS_FILTERING_OFF | RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT, 7, 0);
1606 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_2, RADIOLIB_SX127X_DATA_MODE_PACKET | RADIOLIB_SX127X_IO_HOME_OFF, 6, 5);
1607 0 : RADIOLIB_ASSERT(state);
1608 :
1609 : // set FIFO threshold
1610 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_TX_START_FIFO_NOT_EMPTY, 7, 7);
1611 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_FIFO_THRESH, 5, 0);
1612 0 : RADIOLIB_ASSERT(state);
1613 :
1614 : // disable Rx timeouts
1615 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_TIMEOUT_1, RADIOLIB_SX127X_TIMEOUT_RX_RSSI_OFF);
1616 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_TIMEOUT_2, RADIOLIB_SX127X_TIMEOUT_RX_PREAMBLE_OFF);
1617 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_TIMEOUT_3, RADIOLIB_SX127X_TIMEOUT_SIGNAL_SYNC_OFF);
1618 0 : RADIOLIB_ASSERT(state);
1619 :
1620 : // enable preamble detector
1621 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_DETECT, RADIOLIB_SX127X_PREAMBLE_DETECTOR_ON | RADIOLIB_SX127X_PREAMBLE_DETECTOR_2_BYTE | RADIOLIB_SX127X_PREAMBLE_DETECTOR_TOL);
1622 :
1623 0 : return(state);
1624 : }
1625 :
1626 0 : int16_t SX127x::setPacketMode(uint8_t mode, uint8_t len) {
1627 : // check packet length
1628 0 : if(len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK) {
1629 0 : return(RADIOLIB_ERR_PACKET_TOO_LONG);
1630 : }
1631 :
1632 : // check active modem
1633 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
1634 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1635 : }
1636 :
1637 : // set to fixed packet length
1638 0 : int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, mode, 7, 7);
1639 0 : RADIOLIB_ASSERT(state);
1640 :
1641 : // set length to register
1642 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK, len);
1643 0 : RADIOLIB_ASSERT(state);
1644 :
1645 : // update cached value
1646 0 : this->packetLengthConfig = mode;
1647 0 : return(state);
1648 : }
1649 :
1650 0 : bool SX127x::findChip(const uint8_t* vers, uint8_t num) {
1651 0 : uint8_t i = 0;
1652 0 : bool flagFound = false;
1653 0 : while((i < 10) && !flagFound) {
1654 : // reset the module
1655 0 : reset();
1656 :
1657 : // check version register
1658 0 : int16_t version = getChipVersion();
1659 0 : for(uint8_t j = 0; j < num; j++) {
1660 0 : if(version == vers[j]) {
1661 0 : flagFound = true;
1662 0 : break;
1663 : }
1664 : }
1665 :
1666 0 : if(!flagFound) {
1667 : RADIOLIB_DEBUG_BASIC_PRINTLN("SX127x not found! (%d of 10 tries) RADIOLIB_SX127X_REG_VERSION == 0x%04X", i + 1, version);
1668 0 : this->mod->hal->delay(10);
1669 0 : i++;
1670 : }
1671 :
1672 : }
1673 :
1674 0 : return(flagFound);
1675 : }
1676 :
1677 126 : int16_t SX127x::setMode(uint8_t mode) {
1678 126 : uint8_t checkMask = 0xFF;
1679 126 : if((getActiveModem() == RADIOLIB_SX127X_FSK_OOK) && (mode == RADIOLIB_SX127X_RX)) {
1680 : // disable checking of RX bit in FSK RX mode, as it sometimes seem to fail (#276)
1681 0 : checkMask = 0xFE;
1682 : }
1683 126 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, mode, 2, 0, 5, checkMask));
1684 : }
1685 :
1686 328 : int16_t SX127x::getActiveModem() {
1687 328 : return(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_OP_MODE, 7, 7));
1688 : }
1689 :
1690 0 : int16_t SX127x::setActiveModem(uint8_t modem) {
1691 : // set mode to SLEEP
1692 0 : int16_t state = setMode(RADIOLIB_SX127X_SLEEP);
1693 :
1694 : // set modem
1695 : // low frequency access (bit 3) automatically resets when switching modem
1696 : // so we exclude it from the check
1697 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, modem, 7, 7, 5, 0xF7);
1698 :
1699 : // set mode to STANDBY
1700 0 : state |= setMode(RADIOLIB_SX127X_STANDBY);
1701 0 : return(state);
1702 : }
1703 :
1704 6 : void SX127x::clearFIFO(size_t count) {
1705 1530 : while(count) {
1706 1524 : this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_FIFO);
1707 1524 : count--;
1708 : }
1709 6 : }
1710 :
1711 6 : int16_t SX127x::invertIQ(bool enable) {
1712 : // check active modem
1713 6 : if(getActiveModem() != RADIOLIB_SX127X_LORA) {
1714 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1715 : }
1716 :
1717 : // Tx path inversion is swapped, because it seems that setting it according to the datsheet
1718 : // will actually lead to the wrong inversion. See https://github.com/jgromes/RadioLib/issues/778
1719 : int16_t state;
1720 6 : if(enable) {
1721 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_RXPATH_ON, 6, 6);
1722 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_TXPATH_OFF, 0, 0);
1723 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ2, RADIOLIB_SX127X_IQ2_ENABLE);
1724 : } else {
1725 6 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_RXPATH_OFF, 6, 6);
1726 6 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_TXPATH_ON, 0, 0);
1727 6 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ2, RADIOLIB_SX127X_IQ2_DISABLE);
1728 : }
1729 :
1730 6 : return(state);
1731 : }
1732 :
1733 18 : int16_t SX127x::getModem(ModemType_t* modem) {
1734 18 : RADIOLIB_ASSERT_PTR(modem);
1735 :
1736 18 : int16_t packetType = getActiveModem();
1737 18 : switch(packetType) {
1738 18 : case(RADIOLIB_SX127X_LORA):
1739 18 : *modem = ModemType_t::RADIOLIB_MODEM_LORA;
1740 18 : return(RADIOLIB_ERR_NONE);
1741 0 : case(RADIOLIB_SX127X_FSK_OOK):
1742 0 : *modem = ModemType_t::RADIOLIB_MODEM_FSK;
1743 0 : return(RADIOLIB_ERR_NONE);
1744 : }
1745 :
1746 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1747 : }
1748 :
1749 24 : int16_t SX127x::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) {
1750 : int16_t state;
1751 :
1752 24 : switch(mode) {
1753 18 : case(RADIOLIB_RADIO_MODE_RX): {
1754 18 : this->rxMode = RADIOLIB_SX127X_RXCONTINUOUS;
1755 :
1756 : // set mode to standby
1757 18 : state = setMode(RADIOLIB_SX127X_STANDBY);
1758 18 : RADIOLIB_ASSERT(state);
1759 :
1760 : // set DIO pin mapping
1761 0 : state = this->setIrqFlags(getIrqMapped(cfg->receive.irqFlags & cfg->receive.irqMask));
1762 0 : RADIOLIB_ASSERT(state);
1763 :
1764 0 : int16_t modem = getActiveModem();
1765 0 : if(modem == RADIOLIB_SX127X_LORA) {
1766 : // if max(uint32_t) is used, revert to RxContinuous
1767 0 : if(cfg->receive.timeout == 0xFFFFFFFF) {
1768 0 : cfg->receive.timeout = 0;
1769 : }
1770 0 : if(cfg->receive.timeout != 0) {
1771 : // for non-zero timeout value, change mode to Rx single and set the timeout
1772 0 : this->rxMode = RADIOLIB_SX127X_RXSINGLE;
1773 0 : uint8_t msb_sym = (cfg->receive.timeout > 0x3FF) ? 0x3 : (uint8_t)(cfg->receive.timeout >> 8);
1774 0 : uint8_t lsb_sym = (cfg->receive.timeout > 0x3FF) ? 0xFF : (uint8_t)(cfg->receive.timeout & 0xFF);
1775 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, msb_sym, 1, 0);
1776 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYMB_TIMEOUT_LSB, lsb_sym);
1777 0 : RADIOLIB_ASSERT(state);
1778 : }
1779 :
1780 : // in FHSS mode, enable channel change interrupt
1781 0 : if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) {
1782 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 5, 4);
1783 : }
1784 :
1785 : // in implicit header mode, use the provided length if it is nonzero
1786 : // otherwise we trust the user has previously set the payload length manually
1787 0 : if((this->implicitHdr) && (cfg->receive.len != 0)) {
1788 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, cfg->receive.len);
1789 0 : this->packetLength = cfg->receive.len;
1790 : }
1791 :
1792 : // apply fixes to errata
1793 : RADIOLIB_ERRATA_SX127X(true);
1794 :
1795 : // clear interrupt flags
1796 0 : clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
1797 :
1798 : // set FIFO pointers
1799 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_RX_BASE_ADDR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX);
1800 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX);
1801 0 : RADIOLIB_ASSERT(state);
1802 :
1803 0 : } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
1804 : // for non-zero timeout value, emulate timeout
1805 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_TIMEOUT_3, cfg->receive.timeout & 0xFF);
1806 0 : RADIOLIB_ASSERT(state);
1807 :
1808 : // clear interrupt flags
1809 0 : clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
1810 :
1811 : // FSK modem does not actually distinguish between Rx single and continuous mode,
1812 : // Rx single is emulated using timeout
1813 0 : this->rxMode = RADIOLIB_SX127X_RX;
1814 : }
1815 0 : } break;
1816 :
1817 6 : case(RADIOLIB_RADIO_MODE_TX): {
1818 : // set mode to standby
1819 6 : state = setMode(RADIOLIB_SX127X_STANDBY);
1820 :
1821 6 : int16_t modem = getActiveModem();
1822 6 : if(modem == RADIOLIB_SX127X_LORA) {
1823 : // check packet length
1824 6 : if(cfg->transmit.len > RADIOLIB_SX127X_MAX_PACKET_LENGTH) {
1825 0 : return(RADIOLIB_ERR_PACKET_TOO_LONG);
1826 : }
1827 :
1828 : // set DIO mapping
1829 6 : if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) {
1830 6 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_TX_DONE | RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 7, 4);
1831 : } else {
1832 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_TX_DONE, 7, 6);
1833 : }
1834 :
1835 : // apply fixes to errata
1836 : RADIOLIB_ERRATA_SX127X(false);
1837 :
1838 : // clear interrupt flags
1839 6 : clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
1840 :
1841 : // set packet length
1842 6 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, cfg->transmit.len);
1843 :
1844 : // set FIFO pointers
1845 6 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_TX_BASE_ADDR, RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX);
1846 6 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX);
1847 :
1848 0 : } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
1849 : // clear interrupt flags
1850 0 : clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
1851 :
1852 : // set DIO mapping
1853 0 : if(cfg->transmit.len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK) {
1854 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_PACK_FIFO_EMPTY, 5, 4);
1855 : } else {
1856 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT, 7, 6);
1857 : }
1858 :
1859 : // set packet length - increased by 1 when address filter is enabled
1860 0 : uint8_t filter = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 2, 1);
1861 0 : if(this->packetLengthConfig == RADIOLIB_SX127X_PACKET_VARIABLE) {
1862 0 : if((filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE) || (filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) {
1863 0 : this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, cfg->transmit.len + 1);
1864 0 : this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, cfg->transmit.addr);
1865 : } else {
1866 0 : this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, cfg->transmit.len);
1867 : }
1868 :
1869 : }
1870 :
1871 : }
1872 :
1873 : // write packet to FIFO
1874 6 : size_t packetLen = cfg->transmit.len;
1875 6 : if((modem == RADIOLIB_SX127X_FSK_OOK) && (cfg->transmit.len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK)) {
1876 0 : packetLen = RADIOLIB_SX127X_FIFO_THRESH - 1;
1877 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_TX_START_FIFO_NOT_EMPTY, 7, 7);
1878 : }
1879 6 : this->mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_FIFO, cfg->transmit.data, packetLen);
1880 6 : } break;
1881 :
1882 0 : default:
1883 0 : return(RADIOLIB_ERR_UNSUPPORTED);
1884 : }
1885 :
1886 6 : this->stagedMode = mode;
1887 6 : return(state);
1888 : }
1889 :
1890 6 : int16_t SX127x::launchMode() {
1891 : int16_t state;
1892 6 : switch(this->stagedMode) {
1893 6 : case(RADIOLIB_RADIO_MODE_RX): {
1894 6 : this->mod->setRfSwitchState(Module::MODE_RX);
1895 6 : state = setMode(this->rxMode);
1896 6 : RADIOLIB_ASSERT(state);
1897 0 : } break;
1898 :
1899 0 : case(RADIOLIB_RADIO_MODE_TX): {
1900 0 : this->mod->setRfSwitchState(Module::MODE_TX);
1901 0 : state = setMode(RADIOLIB_SX127X_TX);
1902 0 : RADIOLIB_ASSERT(state);
1903 0 : } break;
1904 :
1905 0 : default:
1906 0 : return(RADIOLIB_ERR_UNSUPPORTED);
1907 : }
1908 :
1909 0 : this->stagedMode = RADIOLIB_RADIO_MODE_NONE;
1910 0 : return(state);
1911 : }
1912 :
1913 : #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE
1914 0 : void SX127x::setDirectAction(void (*func)(void)) {
1915 0 : setDio1Action(func, this->mod->hal->GpioInterruptRising);
1916 0 : }
1917 :
1918 0 : void SX127x::readBit(uint32_t pin) {
1919 0 : updateDirectBuffer((uint8_t)this->mod->hal->digitalRead(pin));
1920 0 : }
1921 : #endif
1922 :
1923 0 : int16_t SX127x::setFHSSHoppingPeriod(uint8_t freqHoppingPeriod) {
1924 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, freqHoppingPeriod));
1925 : }
1926 :
1927 0 : uint8_t SX127x::getFHSSHoppingPeriod(void) {
1928 0 : return(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD));
1929 : }
1930 :
1931 0 : uint8_t SX127x::getFHSSChannel(void) {
1932 0 : return(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 5, 0));
1933 : }
1934 :
1935 0 : void SX127x::clearFHSSInt(void) {
1936 0 : int16_t modem = getActiveModem();
1937 0 : if(modem == RADIOLIB_SX127X_LORA) {
1938 0 : this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL);
1939 0 : } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
1940 0 : return; //These are not the interrupts you are looking for
1941 : }
1942 : }
1943 :
1944 0 : int16_t SX127x::setDIOMapping(uint32_t pin, uint32_t value) {
1945 0 : if (pin > 5)
1946 0 : return RADIOLIB_ERR_INVALID_DIO_PIN;
1947 :
1948 0 : if (pin < 4)
1949 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, value, 7 - 2 * pin, 6 - 2 * pin));
1950 : else
1951 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_2, value, 15 - 2 * pin, 14 - 2 * pin));
1952 : }
1953 :
1954 0 : int16_t SX127x::setDIOPreambleDetect(bool usePreambleDetect) {
1955 0 : return this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_2, (usePreambleDetect) ? RADIOLIB_SX127X_DIO_MAP_PREAMBLE_DETECT : RADIOLIB_SX127X_DIO_MAP_RSSI, 0, 0);
1956 : }
1957 :
1958 6 : float SX127x::getRSSICommon(bool packet, bool skipReceive, int16_t offset) {
1959 6 : if(getActiveModem() == RADIOLIB_SX127X_LORA) {
1960 6 : if(packet) {
1961 : // LoRa packet mode, get RSSI of the last packet
1962 6 : float lastPacketRSSI = offset + this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PKT_RSSI_VALUE);
1963 :
1964 : // spread-spectrum modulation signal can be received below noise floor
1965 : // check last packet SNR and if it's less than 0, add it to reported RSSI to get the correct value
1966 6 : float lastPacketSNR = SX127x::getSNR();
1967 6 : if(lastPacketSNR < 0.0f) {
1968 6 : lastPacketRSSI += lastPacketSNR;
1969 : }
1970 6 : return(lastPacketRSSI);
1971 :
1972 : } else {
1973 : // LoRa instant, get current RSSI
1974 0 : float currentRSSI = offset + this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE);
1975 0 : return(currentRSSI);
1976 : }
1977 :
1978 : } else {
1979 : // for FSK, there is no packet RSSI
1980 :
1981 : // enable listen mode
1982 0 : if(!skipReceive) {
1983 0 : startReceive();
1984 : }
1985 :
1986 : // read the value for FSK
1987 0 : float rssi = (float)this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE_FSK) / -2.0f;
1988 :
1989 : // set mode back to standby
1990 0 : if(!skipReceive) {
1991 0 : standby();
1992 : }
1993 :
1994 : // return the value
1995 0 : return(rssi);
1996 : }
1997 : }
1998 :
1999 0 : int16_t SX127x::setHeaderType(uint8_t headerType, uint8_t bitIndex, size_t len) {
2000 : // check active modem
2001 0 : if(getActiveModem() != RADIOLIB_SX127X_LORA) {
2002 0 : return(RADIOLIB_ERR_WRONG_MODEM);
2003 : }
2004 :
2005 : // set requested packet mode
2006 0 : int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, headerType, bitIndex, bitIndex);
2007 0 : RADIOLIB_ASSERT(state);
2008 :
2009 : // set length to register
2010 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len);
2011 0 : RADIOLIB_ASSERT(state);
2012 :
2013 : // update cached value
2014 0 : SX127x::packetLength = len;
2015 :
2016 0 : return(state);
2017 : }
2018 :
2019 0 : int16_t SX127x::setLowBatteryThreshold(int8_t level, uint32_t pin) {
2020 : // check disable
2021 0 : if(level < 0) {
2022 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LOW_BAT, RADIOLIB_SX127X_LOW_BAT_OFF, 3, 3));
2023 : }
2024 :
2025 : // enable detector and set the threshold
2026 0 : int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LOW_BAT, RADIOLIB_SX127X_LOW_BAT_ON | level, 3, 0);
2027 0 : RADIOLIB_ASSERT(state);
2028 :
2029 : // set DIO mapping
2030 0 : switch(pin) {
2031 0 : case(0):
2032 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_TEMP_CHANGE_LOW_BAT, 7, 6));
2033 0 : case(3):
2034 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO3_CONT_TEMP_CHANGE_LOW_BAT, 1, 0));
2035 0 : case(4):
2036 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_2, RADIOLIB_SX127X_DIO4_PACK_TEMP_CHANGE_LOW_BAT, 7, 6));
2037 : }
2038 0 : return(RADIOLIB_ERR_INVALID_DIO_PIN);
2039 : }
2040 :
2041 : #endif
|