Line data Source code
1 : #include "SX127x.h"
2 : #include <math.h>
3 : #if !RADIOLIB_EXCLUDE_SX127X
4 :
5 18 : SX127x::SX127x(Module* mod) : PhysicalLayer() {
6 18 : this->freqStep = RADIOLIB_SX127X_FREQUENCY_STEP_SIZE;
7 18 : this->maxPacketLength = RADIOLIB_SX127X_MAX_PACKET_LENGTH;
8 18 : this->mod = mod;
9 18 : }
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, bool enableOOK) {
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(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 &config) {
265 : (void)config;
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 &config) {
595 : (void)config;
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 : uint8_t SX127x::calculateBWManExp(float bandwidth)
861 : {
862 0 : for(uint8_t e = 7; e >= 1; e--) {
863 0 : for(int8_t m = 2; m >= 0; m--) {
864 0 : float point = (RADIOLIB_SX127X_CRYSTAL_FREQ * 1000000.0f)/(((4 * m) + 16) * ((uint32_t)1 << (e + 2)));
865 0 : if(fabsf(bandwidth - ((point / 1000.0f) + 0.05f)) <= 0.5f) {
866 0 : return((m << 3) | e);
867 : }
868 : }
869 : }
870 0 : return 0;
871 : }
872 :
873 0 : int16_t SX127x::setRxBandwidth(float rxBw) {
874 : // check active modem
875 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
876 0 : return(RADIOLIB_ERR_WRONG_MODEM);
877 : }
878 :
879 0 : RADIOLIB_CHECK_RANGE(rxBw, 2.6f, 250.0f, RADIOLIB_ERR_INVALID_RX_BANDWIDTH);
880 :
881 : // set mode to STANDBY
882 0 : int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
883 0 : RADIOLIB_ASSERT(state);
884 :
885 : // set Rx bandwidth
886 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_BW, calculateBWManExp(rxBw), 4, 0));
887 : }
888 :
889 0 : int16_t SX127x::setAFCBandwidth(float rxBw) {
890 : // check active modem
891 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK){
892 0 : return(RADIOLIB_ERR_WRONG_MODEM);
893 : }
894 :
895 0 : RADIOLIB_CHECK_RANGE(rxBw, 2.6f, 250.0f, RADIOLIB_ERR_INVALID_RX_BANDWIDTH);
896 :
897 : // set mode to STANDBY
898 0 : int16_t state = setMode(RADIOLIB_SX127X_STANDBY);
899 0 : RADIOLIB_ASSERT(state);
900 :
901 : // set AFC bandwidth
902 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_AFC_BW, calculateBWManExp(rxBw), 4, 0));
903 : }
904 :
905 0 : int16_t SX127x::setAFC(bool isEnabled) {
906 : // check active modem
907 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
908 0 : return(RADIOLIB_ERR_WRONG_MODEM);
909 : }
910 :
911 : //set AFC auto on/off
912 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, isEnabled ? RADIOLIB_SX127X_AFC_AUTO_ON : RADIOLIB_SX127X_AFC_AUTO_OFF, 4, 4));
913 : }
914 :
915 0 : int16_t SX127x::setAFCAGCTrigger(uint8_t trigger) {
916 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
917 0 : return(RADIOLIB_ERR_WRONG_MODEM);
918 : }
919 :
920 : //set AFC&AGC trigger
921 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, trigger, 2, 0));
922 : }
923 :
924 6 : int16_t SX127x::setSyncWord(uint8_t* syncWord, size_t len) {
925 : // check active modem
926 6 : uint8_t modem = getActiveModem();
927 6 : if(modem == RADIOLIB_SX127X_FSK_OOK) {
928 :
929 : // disable sync word in case len is 0
930 0 : if(len == 0) {
931 0 : int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, RADIOLIB_SX127X_SYNC_OFF, 4, 4);
932 0 : return(state);
933 : }
934 :
935 0 : RADIOLIB_CHECK_RANGE(len, 1, 8, RADIOLIB_ERR_INVALID_SYNC_WORD);
936 :
937 : // sync word must not contain value 0x00
938 0 : for(size_t i = 0; i < len; i++) {
939 0 : if(syncWord[i] == 0x00) {
940 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
941 : }
942 : }
943 :
944 : // enable sync word recognition
945 0 : int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, RADIOLIB_SX127X_SYNC_ON, 4, 4);
946 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, len - 1, 2, 0);
947 0 : RADIOLIB_ASSERT(state);
948 :
949 : // set sync word
950 0 : this->mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_SYNC_VALUE_1, syncWord, len);
951 0 : return(RADIOLIB_ERR_NONE);
952 :
953 6 : } else if(modem == RADIOLIB_SX127X_LORA) {
954 : // with length set to 1 and LoRa modem active, assume it is the LoRa sync word
955 6 : if(len > 1) {
956 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
957 : }
958 :
959 6 : return(this->setSyncWord(syncWord[0]));
960 : }
961 :
962 0 : return(RADIOLIB_ERR_WRONG_MODEM);
963 : }
964 :
965 0 : int16_t SX127x::setNodeAddress(uint8_t nodeAddr) {
966 : // check active modem
967 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
968 0 : return(RADIOLIB_ERR_WRONG_MODEM);
969 : }
970 :
971 : // enable address filtering (node only)
972 0 : int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_ADDRESS_FILTERING_NODE, 2, 1);
973 0 : RADIOLIB_ASSERT(state);
974 :
975 : // set node address
976 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_NODE_ADRS, nodeAddr));
977 : }
978 :
979 0 : int16_t SX127x::setBroadcastAddress(uint8_t broadAddr) {
980 : // check active modem
981 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
982 0 : return(RADIOLIB_ERR_WRONG_MODEM);
983 : }
984 :
985 : // enable address filtering (node + broadcast)
986 0 : int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST, 2, 1);
987 0 : RADIOLIB_ASSERT(state);
988 :
989 : // set broadcast address
990 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BROADCAST_ADRS, broadAddr));
991 : }
992 :
993 0 : int16_t SX127x::disableAddressFiltering() {
994 : // check active modem
995 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
996 0 : return(RADIOLIB_ERR_WRONG_MODEM);
997 : }
998 :
999 : // disable address filtering
1000 0 : int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_ADDRESS_FILTERING_OFF, 2, 1);
1001 0 : RADIOLIB_ASSERT(state);
1002 :
1003 : // set node address to default (0x00)
1004 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_NODE_ADRS, 0x00);
1005 0 : RADIOLIB_ASSERT(state);
1006 :
1007 : // set broadcast address to default (0x00)
1008 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_BROADCAST_ADRS, 0x00));
1009 : }
1010 :
1011 0 : int16_t SX127x::setOokThresholdType(uint8_t type) {
1012 : // check active modem
1013 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
1014 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1015 : }
1016 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, type, 4, 3, 5));
1017 : }
1018 :
1019 0 : int16_t SX127x::setOokFixedOrFloorThreshold(uint8_t value) {
1020 : // check active modem
1021 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
1022 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1023 : }
1024 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_FIX, value, 7, 0, 5));
1025 : }
1026 :
1027 0 : int16_t SX127x::setOokPeakThresholdDecrement(uint8_t value) {
1028 : // check active modem
1029 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
1030 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1031 : }
1032 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_AVG, value, 7, 5, 5));
1033 : }
1034 :
1035 0 : int16_t SX127x::setOokPeakThresholdStep(uint8_t value) {
1036 : // check active modem
1037 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
1038 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1039 : }
1040 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, value, 2, 0, 5));
1041 : }
1042 :
1043 0 : int16_t SX127x::enableBitSync() {
1044 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, RADIOLIB_SX127X_BIT_SYNC_ON, 5, 5, 5));
1045 : }
1046 :
1047 0 : int16_t SX127x::disableBitSync() {
1048 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OOK_PEAK, RADIOLIB_SX127X_BIT_SYNC_OFF, 5, 5, 5));
1049 : }
1050 :
1051 0 : int16_t SX127x::setOOK(bool enableOOK) {
1052 : // check active modem
1053 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
1054 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1055 : }
1056 :
1057 : // set OOK and if successful, save the new setting
1058 0 : int16_t state = RADIOLIB_ERR_NONE;
1059 0 : if(enableOOK) {
1060 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX127X_MODULATION_OOK, 6, 5, 5);
1061 0 : state |= SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_RSSI_INTERRUPT);
1062 : } else {
1063 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, RADIOLIB_SX127X_MODULATION_FSK, 6, 5, 5);
1064 0 : state |= SX127x::setAFCAGCTrigger(RADIOLIB_SX127X_RX_TRIGGER_BOTH);
1065 : }
1066 0 : if(state == RADIOLIB_ERR_NONE) {
1067 0 : ookEnabled = enableOOK;
1068 : }
1069 :
1070 0 : return(state);
1071 : }
1072 :
1073 0 : int16_t SX127x::setFrequencyRaw(float newFreq) {
1074 0 : int16_t state = RADIOLIB_ERR_NONE;
1075 :
1076 : // set mode to standby if not FHSS
1077 0 : if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) == RADIOLIB_SX127X_HOP_PERIOD_OFF) {
1078 0 : state = setMode(RADIOLIB_SX127X_STANDBY);
1079 : }
1080 :
1081 : // calculate register values
1082 0 : uint32_t FRF = (newFreq * (uint32_t(1) << RADIOLIB_SX127X_DIV_EXPONENT)) / RADIOLIB_SX127X_CRYSTAL_FREQ;
1083 :
1084 : // write registers
1085 : // lsb needs to be written no matter what in order for the module to update the frequency
1086 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FRF_MSB, (FRF & 0xFF0000) >> 16);
1087 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FRF_MID, (FRF & 0x00FF00) >> 8);
1088 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FRF_LSB, FRF & 0x0000FF, 7U, 0U, 2U, 0xFF, true);
1089 0 : return(state);
1090 : }
1091 :
1092 12 : size_t SX127x::getPacketLength(bool update) {
1093 12 : int16_t modem = getActiveModem();
1094 :
1095 12 : if(modem == RADIOLIB_SX127X_LORA) {
1096 12 : if(!this->implicitHdr) {
1097 : // get packet length for explicit header mode
1098 12 : return(this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_RX_NB_BYTES));
1099 :
1100 : } else {
1101 : // return the cached value for implicit header mode
1102 0 : return(this->packetLength);
1103 : }
1104 :
1105 0 : } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
1106 : // get packet length
1107 0 : if(!this->packetLengthQueried && update) {
1108 0 : if (this->packetLengthConfig == RADIOLIB_SX127X_PACKET_VARIABLE) {
1109 0 : this->packetLength = this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_FIFO);
1110 : } else {
1111 0 : this->packetLength = this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK);
1112 : }
1113 0 : this->packetLengthQueried = true;
1114 : }
1115 : }
1116 :
1117 0 : return(this->packetLength);
1118 : }
1119 :
1120 0 : int16_t SX127x::getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC) {
1121 0 : int16_t state = RADIOLIB_ERR_NONE;
1122 :
1123 : // check if in explicit header mode
1124 0 : if(this->implicitHdr) {
1125 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1126 : }
1127 :
1128 0 : if(cr) { *cr = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_MODEM_STAT, 7, 5) >> 5; }
1129 0 : if(hasCRC) { *hasCRC = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 6, 6) != 0; }
1130 :
1131 0 : return(state);
1132 : }
1133 :
1134 0 : int16_t SX127x::fixedPacketLengthMode(uint8_t len) {
1135 0 : return(SX127x::setPacketMode(RADIOLIB_SX127X_PACKET_FIXED, len));
1136 : }
1137 :
1138 0 : int16_t SX127x::variablePacketLengthMode(uint8_t maxLen) {
1139 0 : return(SX127x::setPacketMode(RADIOLIB_SX127X_PACKET_VARIABLE, maxLen));
1140 : }
1141 :
1142 14 : float SX127x::getNumSymbols(size_t len, DataRate_t dr, PacketConfig_t pc) {
1143 : // get Low Data Rate optimization flag
1144 14 : float de = pc.lora.ldrOptimize ? 1.0f : 0.0f;
1145 :
1146 : // get explicit/implicit header enabled flag
1147 14 : float ih = (float) pc.lora.implicitHeader;
1148 :
1149 : // get CRC enabled flag
1150 14 : float crc = (float) pc.lora.crcEnabled;
1151 :
1152 : // get number of preamble symbols
1153 14 : float n_pre = (float) pc.lora.preambleLength;
1154 :
1155 : // get number of payload symbols
1156 14 : 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);
1157 :
1158 : // add 4.25 symbols for the sync
1159 14 : return(n_pre + n_pay + 4.25f);
1160 : }
1161 :
1162 24 : RadioLibTime_t SX127x::calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) {
1163 24 : if (modem == RADIOLIB_MODEM_LORA) {
1164 : // get symbol length in us
1165 14 : float symbolLength = (float) (uint32_t(1) << dr.lora.spreadingFactor) / (float) dr.lora.bandwidth;
1166 :
1167 : // get number of symbols
1168 14 : float n_sym = getNumSymbols(len, dr, pc);
1169 :
1170 : // get time-on-air in us
1171 14 : return ceil((double)symbolLength * (double)n_sym) * 1000;
1172 :
1173 10 : } else if(modem == RADIOLIB_MODEM_FSK) {
1174 :
1175 : // 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)
1176 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));
1177 : } else {
1178 6 : return(RADIOLIB_ERR_WRONG_MODEM);
1179 : }
1180 :
1181 : return(RADIOLIB_ERR_UNKNOWN);
1182 : }
1183 :
1184 6 : RadioLibTime_t SX127x::getTimeOnAir(size_t len) {
1185 6 : uint8_t modem = getActiveModem();
1186 6 : DataRate_t dr = {};
1187 6 : PacketConfig_t pc = {};
1188 :
1189 6 : switch (modem) {
1190 6 : case(RADIOLIB_SX127X_LORA): {
1191 6 : dr.lora.spreadingFactor = this->spreadingFactor;
1192 6 : dr.lora.bandwidth = this->bandwidth;
1193 6 : dr.lora.codingRate = this->codingRate;
1194 :
1195 : // Get number of preamble symbols
1196 6 : uint16_t n_pre = ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_MSB) << 8) | this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PREAMBLE_LSB));
1197 :
1198 6 : pc.lora.preambleLength = n_pre;
1199 6 : pc.lora.implicitHeader = this->implicitHdr;
1200 6 : pc.lora.crcEnabled = this->crcEnabled;
1201 6 : pc.lora.ldrOptimize = this->ldroEnabled;
1202 :
1203 6 : return(calculateTimeOnAir((ModemType_t)RADIOLIB_MODEM_LORA, dr, pc, len));
1204 : }
1205 0 : case(RADIOLIB_SX127X_FSK_OOK): {
1206 0 : dr.fsk.bitRate = this->bitRate;
1207 0 : dr.fsk.freqDev = this->frequencyDev;
1208 :
1209 : // get number of bits preamble
1210 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;
1211 : // get the number of bits of the sync word
1212 0 : uint8_t n_syncWord = (uint8_t) ((this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_SYNC_CONFIG, 2, 0) + 1) * 8);
1213 : // get CRC enabled status
1214 0 : bool crcEn = (this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 4, 4) == RADIOLIB_SX127X_CRC_ON);
1215 :
1216 0 : pc.fsk.preambleLength = n_pre;
1217 0 : pc.fsk.syncWordLength = n_syncWord;
1218 0 : pc.fsk.crcLength = (uint8_t)(crcEn * 2);
1219 :
1220 0 : if (this->packetLengthConfig == RADIOLIB_SX127X_PACKET_FIXED) {
1221 : // if packet size fixed -> len = fixed packet length
1222 0 : len = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK);
1223 : } else {
1224 : // if packet variable -> Add 1 extra byte for payload length
1225 0 : len += 1;
1226 : }
1227 :
1228 0 : return(calculateTimeOnAir((ModemType_t)RADIOLIB_MODEM_FSK, dr, pc, len));
1229 : }
1230 0 : default:
1231 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1232 : }
1233 : }
1234 :
1235 6 : RadioLibTime_t SX127x::calculateRxTimeout(RadioLibTime_t timeoutUs) {
1236 6 : RadioLibTime_t timeout = 0;
1237 6 : if(getActiveModem() == RADIOLIB_SX127X_LORA) {
1238 : // for LoRa, the timeout is given as the number of symbols
1239 : // the calling function should provide some extra width, as this number of symbols is truncated to integer
1240 : // the order of operators is swapped here to decrease the effects of this truncation error
1241 6 : float symbolLength = (float) (uint32_t(1) << this->spreadingFactor) / (float) this->bandwidth;
1242 6 : timeout = (timeoutUs / symbolLength) / 1000;
1243 :
1244 : } else {
1245 : // for FSK, the timeout is in units of 16x bit time
1246 0 : timeout = ((float)timeoutUs / ((16.0f * 1000.0f) / this->bitRate));
1247 :
1248 : }
1249 :
1250 6 : return(timeout);
1251 : }
1252 :
1253 6 : uint32_t SX127x::getIrqFlags() {
1254 6 : return((uint32_t)this->getIRQFlags());
1255 : }
1256 :
1257 6 : int16_t SX127x::setIrqFlags(uint32_t irq) {
1258 : // this is a bit convoluted, but unfortunately SX127x IRQ flags are not used to enable/disable that IRQ ...
1259 : // in addition, the configuration is often mutually exclusive, so we iterate over the set bits in a loop
1260 6 : uint8_t usedPinFlags = 0;
1261 6 : bool conflict = false;
1262 6 : int16_t modem = getActiveModem();
1263 6 : int16_t state = RADIOLIB_ERR_NONE;
1264 198 : for(uint8_t i = 0; i <= 31; i++) {
1265 : // check if the bit is set
1266 192 : uint32_t irqBit = irq & (1UL << i);
1267 192 : if(!irqBit) {
1268 192 : continue;
1269 : }
1270 :
1271 : // if not, decode it
1272 0 : uint8_t dioNum = 0; // DIO pin number and register value to set (address and MSB/LSB can be inferred)
1273 0 : uint8_t regVal = 0;
1274 0 : if(modem == RADIOLIB_SX127X_LORA) {
1275 0 : switch(irqBit) {
1276 0 : case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_TX_DONE):
1277 0 : dioNum = 0;
1278 0 : regVal = RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT;
1279 0 : break;
1280 0 : case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_DONE):
1281 0 : dioNum = 0;
1282 0 : regVal = RADIOLIB_SX127X_DIO0_LORA_RX_DONE;
1283 0 : break;
1284 0 : case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_VALID_HEADER):
1285 0 : dioNum = 3;
1286 0 : regVal = RADIOLIB_SX127X_DIO3_LORA_VALID_HEADER;
1287 0 : break;
1288 0 : case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR):
1289 0 : dioNum = 3;
1290 0 : regVal = RADIOLIB_SX127X_DIO3_LORA_PAYLOAD_CRC_ERROR;
1291 0 : break;
1292 0 : case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DONE):
1293 0 : dioNum = 0;
1294 0 : regVal = RADIOLIB_SX127X_DIO0_LORA_CAD_DONE;
1295 0 : break;
1296 0 : case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED):
1297 0 : dioNum = 1;
1298 0 : regVal = RADIOLIB_SX127X_DIO1_LORA_CAD_DETECTED;
1299 0 : break;
1300 0 : case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT):
1301 0 : dioNum = 1;
1302 0 : regVal = RADIOLIB_SX127X_DIO1_LORA_RX_TIMEOUT;
1303 0 : break;
1304 0 : default:
1305 0 : return(RADIOLIB_ERR_UNSUPPORTED);
1306 : }
1307 :
1308 0 : } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
1309 0 : switch(irqBit) {
1310 0 : case(RADIOLIB_SX127X_FLAG_PACKET_SENT << 8):
1311 0 : dioNum = 0;
1312 0 : regVal = RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT;
1313 0 : break;
1314 0 : case(RADIOLIB_SX127X_FLAG_PAYLOAD_READY << 8):
1315 0 : dioNum = 0;
1316 0 : regVal = RADIOLIB_SX127X_DIO0_PACK_PAYLOAD_READY;
1317 0 : break;
1318 0 : case(RADIOLIB_SX127X_FLAG_PREAMBLE_DETECT << 0):
1319 0 : dioNum = 4;
1320 0 : regVal = RADIOLIB_SX127X_DIO4_PACK_RSSI_PREAMBLE_DETECT;
1321 0 : break;
1322 0 : case(RADIOLIB_SX127X_FLAG_SYNC_ADDRESS_MATCH << 0):
1323 0 : dioNum = 2;
1324 0 : regVal = RADIOLIB_SX127X_DIO2_PACK_SYNC_ADDRESS;
1325 0 : break;
1326 0 : case(RADIOLIB_SX127X_FLAG_TIMEOUT << 0):
1327 0 : dioNum = 2;
1328 0 : regVal = RADIOLIB_SX127X_DIO2_PACK_TIMEOUT;
1329 0 : break;
1330 0 : default:
1331 0 : return(RADIOLIB_ERR_UNSUPPORTED);
1332 : }
1333 : }
1334 :
1335 : // check if this DIO pin has been set already
1336 0 : if(usedPinFlags & (1UL << dioNum)) {
1337 : // uh oh, this pin is used!
1338 : RADIOLIB_DEBUG_PRINTLN("Unable to set IRQ %04x on DIO%d due to conflict!", irqBit, (int)dioNum);
1339 0 : conflict = true;
1340 0 : continue;
1341 : }
1342 :
1343 : // DIO pin is unused, set the flag and configure it
1344 0 : usedPinFlags |= (1UL << dioNum);
1345 0 : uint8_t addr = (dioNum > 3) ? RADIOLIB_SX127X_REG_DIO_MAPPING_2 : RADIOLIB_SX127X_REG_DIO_MAPPING_1;
1346 0 : uint8_t msb = 7 - 2*(dioNum % 4);
1347 0 : state = this->mod->SPIsetRegValue(addr, regVal, msb, msb - 1);
1348 0 : RADIOLIB_ASSERT(state);
1349 : }
1350 :
1351 : // if there was at least one conflict, this flag is set
1352 6 : if(conflict) {
1353 0 : return(RADIOLIB_ERR_INVALID_IRQ);
1354 : }
1355 :
1356 6 : return(state);
1357 : }
1358 :
1359 24 : int16_t SX127x::clearIrqFlags(uint32_t irq) {
1360 24 : int16_t modem = getActiveModem();
1361 24 : if(modem == RADIOLIB_SX127X_LORA) {
1362 24 : this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, (uint8_t)irq);
1363 24 : return(RADIOLIB_ERR_NONE);
1364 :
1365 0 : } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
1366 0 : this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_1, (uint8_t)irq);
1367 0 : this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_2, (uint8_t)(irq >> 8));
1368 0 : return(RADIOLIB_ERR_NONE);
1369 : }
1370 :
1371 0 : return(RADIOLIB_ERR_UNKNOWN);
1372 : }
1373 :
1374 0 : int16_t SX127x::setCrcFiltering(bool enable) {
1375 0 : this->crcOn = enable;
1376 :
1377 0 : if (enable == true) {
1378 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_ON, 4, 4));
1379 : } else {
1380 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_OFF, 4, 4));
1381 : }
1382 : }
1383 :
1384 0 : int16_t SX127x::setRSSIThreshold(float dbm) {
1385 0 : RADIOLIB_CHECK_RANGE(dbm, -127.5f, 0.0f, RADIOLIB_ERR_INVALID_RSSI_THRESHOLD);
1386 :
1387 0 : return this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_THRESH, (uint8_t)(-2.0f * dbm), 7, 0);
1388 : }
1389 :
1390 0 : int16_t SX127x::setRSSIConfig(uint8_t smoothingSamples, int8_t offset) {
1391 : // check active modem
1392 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
1393 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1394 : }
1395 :
1396 : // set mode to standby
1397 0 : int16_t state = standby();
1398 0 : RADIOLIB_ASSERT(state);
1399 :
1400 : // check provided values
1401 0 : if(!(smoothingSamples <= 7)) {
1402 0 : return(RADIOLIB_ERR_INVALID_NUM_SAMPLES);
1403 : }
1404 :
1405 0 : RADIOLIB_CHECK_RANGE(offset, -16, 15, RADIOLIB_ERR_INVALID_RSSI_OFFSET);
1406 :
1407 : // calculate the two's complement
1408 0 : uint8_t offsetRaw = RADIOLIB_ABS(offset);
1409 0 : offsetRaw ^= 0x1F;
1410 0 : offsetRaw += 1;
1411 0 : offsetRaw &= 0x1F;
1412 :
1413 : // set new register values
1414 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_CONFIG, offsetRaw << 3, 7, 3);
1415 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_CONFIG, smoothingSamples, 2, 0);
1416 0 : return(state);
1417 : }
1418 :
1419 6 : int16_t SX127x::setEncoding(uint8_t encoding) {
1420 : // check active modem
1421 6 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
1422 6 : return(RADIOLIB_ERR_WRONG_MODEM);
1423 : }
1424 :
1425 : // set encoding
1426 0 : switch(encoding) {
1427 0 : case RADIOLIB_ENCODING_NRZ:
1428 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_DC_FREE_NONE, 6, 5));
1429 0 : case RADIOLIB_ENCODING_MANCHESTER:
1430 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_DC_FREE_MANCHESTER, 6, 5));
1431 0 : case RADIOLIB_ENCODING_WHITENING:
1432 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_DC_FREE_WHITENING, 6, 5));
1433 0 : default:
1434 0 : return(RADIOLIB_ERR_INVALID_ENCODING);
1435 : }
1436 : }
1437 :
1438 12 : uint16_t SX127x::getIRQFlags() {
1439 : // check active modem
1440 12 : if(getActiveModem() == RADIOLIB_SX127X_LORA) {
1441 : // LoRa, just 8-bit value
1442 12 : return((uint16_t)this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS));
1443 :
1444 : } else {
1445 : // FSK, the IRQ flags are 16 bits in total
1446 0 : uint16_t flags = ((uint16_t)this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_2)) << 8;
1447 0 : flags |= (uint16_t)this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_1);
1448 0 : return(flags);
1449 : }
1450 :
1451 : }
1452 :
1453 0 : uint8_t SX127x::getModemStatus() {
1454 : // check active modem
1455 0 : if(getActiveModem() != RADIOLIB_SX127X_LORA) {
1456 0 : return(0x00);
1457 : }
1458 :
1459 : // read the register
1460 0 : return(this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_MODEM_STAT));
1461 : }
1462 :
1463 0 : void SX127x::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) {
1464 0 : this->mod->setRfSwitchPins(rxEn, txEn);
1465 0 : }
1466 :
1467 0 : void SX127x::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) {
1468 0 : this->mod->setRfSwitchTable(pins, table);
1469 0 : }
1470 :
1471 6 : uint8_t SX127x::randomByte() {
1472 : // check active modem
1473 6 : uint8_t rssiValueReg = RADIOLIB_SX127X_REG_RSSI_WIDEBAND;
1474 6 : if(getActiveModem() == RADIOLIB_SX127X_FSK_OOK) {
1475 0 : rssiValueReg = RADIOLIB_SX127X_REG_RSSI_VALUE_FSK;
1476 : }
1477 :
1478 : // set mode to Rx
1479 6 : setMode(RADIOLIB_SX127X_RX);
1480 :
1481 : // wait a bit for the RSSI reading to stabilise
1482 6 : this->mod->hal->delay(10);
1483 :
1484 : // read RSSI value 8 times, always keep just the least significant bit
1485 6 : uint8_t randByte = 0x00;
1486 54 : for(uint8_t i = 0; i < 8; i++) {
1487 48 : randByte |= ((this->mod->SPIreadRegister(rssiValueReg) & 0x01) << i);
1488 : }
1489 :
1490 : // set mode to standby
1491 6 : setMode(RADIOLIB_SX127X_STANDBY);
1492 :
1493 6 : return(randByte);
1494 : }
1495 :
1496 0 : int16_t SX127x::getChipVersion() {
1497 0 : return(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_VERSION));
1498 : }
1499 :
1500 0 : int8_t SX127x::getTempRaw() {
1501 0 : int8_t temp = 0;
1502 : uint8_t previousOpMode;
1503 : uint8_t ival;
1504 :
1505 : // save current Op Mode
1506 0 : previousOpMode = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_OP_MODE);
1507 :
1508 : // check if we need to step out of LoRa mode first
1509 0 : if((previousOpMode & RADIOLIB_SX127X_LORA) == RADIOLIB_SX127X_LORA) {
1510 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_LORA | RADIOLIB_SX127X_SLEEP));
1511 : }
1512 :
1513 : // put device in FSK sleep
1514 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_FSK_OOK | RADIOLIB_SX127X_SLEEP));
1515 :
1516 : // put device in FSK RxSynth
1517 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_FSK_OOK | RADIOLIB_SX127X_FSRX));
1518 :
1519 : // enable temperature reading
1520 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_IMAGE_CAL, RADIOLIB_SX127X_TEMP_MONITOR_ON, 0, 0);
1521 :
1522 : // wait
1523 0 : this->mod->hal->delayMicroseconds(200);
1524 :
1525 : // disable temperature reading
1526 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_IMAGE_CAL, RADIOLIB_SX127X_TEMP_MONITOR_OFF, 0, 0);
1527 :
1528 : // put device in FSK sleep
1529 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_FSK_OOK | RADIOLIB_SX127X_SLEEP));
1530 :
1531 : // read temperature
1532 0 : ival = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_TEMP);
1533 :
1534 : // convert very raw value
1535 0 : if((ival & 0x80) == 0x80) {
1536 0 : temp = 255 - ival;
1537 : } else {
1538 0 : temp = -1 * ival;
1539 : }
1540 :
1541 : // check if we need to step back into LoRa mode
1542 0 : if((previousOpMode & RADIOLIB_SX127X_LORA) == RADIOLIB_SX127X_LORA) {
1543 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, (RADIOLIB_SX127X_LORA | RADIOLIB_SX127X_SLEEP));
1544 : }
1545 :
1546 : // reload previous Op Mode
1547 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, previousOpMode);
1548 :
1549 0 : return(temp);
1550 : }
1551 :
1552 6 : Module* SX127x::getMod() {
1553 6 : return(this->mod);
1554 : }
1555 :
1556 0 : int16_t SX127x::config() {
1557 : // turn off frequency hopping
1558 0 : int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, RADIOLIB_SX127X_HOP_PERIOD_OFF);
1559 0 : return(state);
1560 : }
1561 :
1562 0 : int16_t SX127x::configFSK() {
1563 : // set RSSI threshold
1564 0 : int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RSSI_THRESH, RADIOLIB_SX127X_RSSI_THRESHOLD);
1565 0 : RADIOLIB_ASSERT(state);
1566 :
1567 : // reset FIFO flag
1568 0 : this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_2, RADIOLIB_SX127X_FLAG_FIFO_OVERRUN);
1569 :
1570 : // set packet configuration
1571 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);
1572 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_2, RADIOLIB_SX127X_DATA_MODE_PACKET | RADIOLIB_SX127X_IO_HOME_OFF, 6, 5);
1573 0 : RADIOLIB_ASSERT(state);
1574 :
1575 : // set FIFO threshold
1576 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_TX_START_FIFO_NOT_EMPTY, 7, 7);
1577 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_FIFO_THRESH, 5, 0);
1578 0 : RADIOLIB_ASSERT(state);
1579 :
1580 : // disable Rx timeouts
1581 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_TIMEOUT_1, RADIOLIB_SX127X_TIMEOUT_RX_RSSI_OFF);
1582 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_TIMEOUT_2, RADIOLIB_SX127X_TIMEOUT_RX_PREAMBLE_OFF);
1583 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_TIMEOUT_3, RADIOLIB_SX127X_TIMEOUT_SIGNAL_SYNC_OFF);
1584 0 : RADIOLIB_ASSERT(state);
1585 :
1586 : // enable preamble detector
1587 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);
1588 :
1589 0 : return(state);
1590 : }
1591 :
1592 0 : int16_t SX127x::setPacketMode(uint8_t mode, uint8_t len) {
1593 : // check packet length
1594 0 : if(len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK) {
1595 0 : return(RADIOLIB_ERR_PACKET_TOO_LONG);
1596 : }
1597 :
1598 : // check active modem
1599 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
1600 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1601 : }
1602 :
1603 : // set to fixed packet length
1604 0 : int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, mode, 7, 7);
1605 0 : RADIOLIB_ASSERT(state);
1606 :
1607 : // set length to register
1608 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH_FSK, len);
1609 0 : RADIOLIB_ASSERT(state);
1610 :
1611 : // update cached value
1612 0 : this->packetLengthConfig = mode;
1613 0 : return(state);
1614 : }
1615 :
1616 0 : bool SX127x::findChip(const uint8_t* vers, uint8_t num) {
1617 0 : uint8_t i = 0;
1618 0 : bool flagFound = false;
1619 0 : while((i < 10) && !flagFound) {
1620 : // reset the module
1621 0 : reset();
1622 :
1623 : // check version register
1624 0 : int16_t version = getChipVersion();
1625 0 : for(uint8_t j = 0; j < num; j++) {
1626 0 : if(version == vers[j]) {
1627 0 : flagFound = true;
1628 0 : break;
1629 : }
1630 : }
1631 :
1632 0 : if(!flagFound) {
1633 : RADIOLIB_DEBUG_BASIC_PRINTLN("SX127x not found! (%d of 10 tries) RADIOLIB_SX127X_REG_VERSION == 0x%04X", i + 1, version);
1634 0 : this->mod->hal->delay(10);
1635 0 : i++;
1636 : }
1637 :
1638 : }
1639 :
1640 0 : return(flagFound);
1641 : }
1642 :
1643 126 : int16_t SX127x::setMode(uint8_t mode) {
1644 126 : uint8_t checkMask = 0xFF;
1645 126 : if((getActiveModem() == RADIOLIB_SX127X_FSK_OOK) && (mode == RADIOLIB_SX127X_RX)) {
1646 : // disable checking of RX bit in FSK RX mode, as it sometimes seem to fail (#276)
1647 0 : checkMask = 0xFE;
1648 : }
1649 126 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, mode, 2, 0, 5, checkMask));
1650 : }
1651 :
1652 328 : int16_t SX127x::getActiveModem() {
1653 328 : return(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_OP_MODE, 7, 7));
1654 : }
1655 :
1656 0 : int16_t SX127x::setActiveModem(uint8_t modem) {
1657 : // set mode to SLEEP
1658 0 : int16_t state = setMode(RADIOLIB_SX127X_SLEEP);
1659 :
1660 : // set modem
1661 : // low frequency access (bit 3) automatically resets when switching modem
1662 : // so we exclude it from the check
1663 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_OP_MODE, modem, 7, 7, 5, 0xF7);
1664 :
1665 : // set mode to STANDBY
1666 0 : state |= setMode(RADIOLIB_SX127X_STANDBY);
1667 0 : return(state);
1668 : }
1669 :
1670 6 : void SX127x::clearFIFO(size_t count) {
1671 1530 : while(count) {
1672 1524 : this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_FIFO);
1673 1524 : count--;
1674 : }
1675 6 : }
1676 :
1677 6 : int16_t SX127x::invertIQ(bool enable) {
1678 : // check active modem
1679 6 : if(getActiveModem() != RADIOLIB_SX127X_LORA) {
1680 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1681 : }
1682 :
1683 : // Tx path inversion is swapped, because it seems that setting it according to the datsheet
1684 : // will actually lead to the wrong inversion. See https://github.com/jgromes/RadioLib/issues/778
1685 : int16_t state;
1686 6 : if(enable) {
1687 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_RXPATH_ON, 6, 6);
1688 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_TXPATH_OFF, 0, 0);
1689 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ2, RADIOLIB_SX127X_IQ2_ENABLE);
1690 : } else {
1691 6 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_RXPATH_OFF, 6, 6);
1692 6 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ, RADIOLIB_SX127X_INVERT_IQ_TXPATH_ON, 0, 0);
1693 6 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_INVERT_IQ2, RADIOLIB_SX127X_IQ2_DISABLE);
1694 : }
1695 :
1696 6 : return(state);
1697 : }
1698 :
1699 18 : int16_t SX127x::getModem(ModemType_t* modem) {
1700 18 : RADIOLIB_ASSERT_PTR(modem);
1701 :
1702 18 : int16_t packetType = getActiveModem();
1703 18 : switch(packetType) {
1704 18 : case(RADIOLIB_SX127X_LORA):
1705 18 : *modem = ModemType_t::RADIOLIB_MODEM_LORA;
1706 18 : return(RADIOLIB_ERR_NONE);
1707 0 : case(RADIOLIB_SX127X_FSK_OOK):
1708 0 : *modem = ModemType_t::RADIOLIB_MODEM_FSK;
1709 0 : return(RADIOLIB_ERR_NONE);
1710 : }
1711 :
1712 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1713 : }
1714 :
1715 24 : int16_t SX127x::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) {
1716 : int16_t state;
1717 :
1718 24 : switch(mode) {
1719 18 : case(RADIOLIB_RADIO_MODE_RX): {
1720 18 : this->rxMode = RADIOLIB_SX127X_RXCONTINUOUS;
1721 :
1722 : // set mode to standby
1723 18 : state = setMode(RADIOLIB_SX127X_STANDBY);
1724 18 : RADIOLIB_ASSERT(state);
1725 :
1726 : // set DIO pin mapping
1727 0 : state = this->setIrqFlags(getIrqMapped(cfg->receive.irqFlags & cfg->receive.irqMask));
1728 0 : RADIOLIB_ASSERT(state);
1729 :
1730 0 : int16_t modem = getActiveModem();
1731 0 : if(modem == RADIOLIB_SX127X_LORA) {
1732 : // if max(uint32_t) is used, revert to RxContinuous
1733 0 : if(cfg->receive.timeout == 0xFFFFFFFF) {
1734 0 : cfg->receive.timeout = 0;
1735 : }
1736 0 : if(cfg->receive.timeout != 0) {
1737 : // for non-zero timeout value, change mode to Rx single and set the timeout
1738 0 : this->rxMode = RADIOLIB_SX127X_RXSINGLE;
1739 0 : uint8_t msb_sym = (cfg->receive.timeout > 0x3FF) ? 0x3 : (uint8_t)(cfg->receive.timeout >> 8);
1740 0 : uint8_t lsb_sym = (cfg->receive.timeout > 0x3FF) ? 0xFF : (uint8_t)(cfg->receive.timeout & 0xFF);
1741 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, msb_sym, 1, 0);
1742 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_SYMB_TIMEOUT_LSB, lsb_sym);
1743 0 : RADIOLIB_ASSERT(state);
1744 : }
1745 :
1746 : // in FHSS mode, enable channel change interrupt
1747 0 : if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) {
1748 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_LORA_FHSS_CHANGE_CHANNEL, 5, 4);
1749 : }
1750 :
1751 : // in implicit header mode, use the provided length if it is nonzero
1752 : // otherwise we trust the user has previously set the payload length manually
1753 0 : if((this->implicitHdr) && (cfg->receive.len != 0)) {
1754 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, cfg->receive.len);
1755 0 : this->packetLength = cfg->receive.len;
1756 : }
1757 :
1758 : // apply fixes to errata
1759 : RADIOLIB_ERRATA_SX127X(true);
1760 :
1761 : // clear interrupt flags
1762 0 : clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
1763 :
1764 : // set FIFO pointers
1765 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_RX_BASE_ADDR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX);
1766 0 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX);
1767 0 : RADIOLIB_ASSERT(state);
1768 :
1769 0 : } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
1770 : // for non-zero timeout value, emulate timeout
1771 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_TIMEOUT_3, cfg->receive.timeout & 0xFF);
1772 0 : RADIOLIB_ASSERT(state);
1773 :
1774 : // clear interrupt flags
1775 0 : clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
1776 :
1777 : // FSK modem does not actually distinguish between Rx single and continuous mode,
1778 : // Rx single is emulated using timeout
1779 0 : this->rxMode = RADIOLIB_SX127X_RX;
1780 : }
1781 0 : } break;
1782 :
1783 6 : case(RADIOLIB_RADIO_MODE_TX): {
1784 : // set mode to standby
1785 6 : state = setMode(RADIOLIB_SX127X_STANDBY);
1786 :
1787 6 : int16_t modem = getActiveModem();
1788 6 : if(modem == RADIOLIB_SX127X_LORA) {
1789 : // check packet length
1790 6 : if(cfg->transmit.len > RADIOLIB_SX127X_MAX_PACKET_LENGTH) {
1791 0 : return(RADIOLIB_ERR_PACKET_TOO_LONG);
1792 : }
1793 :
1794 : // set DIO mapping
1795 6 : if(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD) > RADIOLIB_SX127X_HOP_PERIOD_OFF) {
1796 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);
1797 : } else {
1798 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_TX_DONE, 7, 6);
1799 : }
1800 :
1801 : // apply fixes to errata
1802 : RADIOLIB_ERRATA_SX127X(false);
1803 :
1804 : // clear interrupt flags
1805 6 : clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
1806 :
1807 : // set packet length
1808 6 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, cfg->transmit.len);
1809 :
1810 : // set FIFO pointers
1811 6 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_TX_BASE_ADDR, RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX);
1812 6 : state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_ADDR_PTR, RADIOLIB_SX127X_FIFO_TX_BASE_ADDR_MAX);
1813 :
1814 0 : } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
1815 : // clear interrupt flags
1816 0 : clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL);
1817 :
1818 : // set DIO mapping
1819 0 : if(cfg->transmit.len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK) {
1820 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_PACK_FIFO_EMPTY, 5, 4);
1821 : } else {
1822 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT, 7, 6);
1823 : }
1824 :
1825 : // set packet length - increased by 1 when address filter is enabled
1826 0 : uint8_t filter = this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, 2, 1);
1827 0 : if(this->packetLengthConfig == RADIOLIB_SX127X_PACKET_VARIABLE) {
1828 0 : if((filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE) || (filter == RADIOLIB_SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) {
1829 0 : this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, cfg->transmit.len + 1);
1830 0 : this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, cfg->transmit.addr);
1831 : } else {
1832 0 : this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_FIFO, cfg->transmit.len);
1833 : }
1834 :
1835 : }
1836 :
1837 : }
1838 :
1839 : // write packet to FIFO
1840 6 : size_t packetLen = cfg->transmit.len;
1841 6 : if((modem == RADIOLIB_SX127X_FSK_OOK) && (cfg->transmit.len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK)) {
1842 0 : packetLen = RADIOLIB_SX127X_FIFO_THRESH - 1;
1843 0 : this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_THRESH, RADIOLIB_SX127X_TX_START_FIFO_NOT_EMPTY, 7, 7);
1844 : }
1845 6 : this->mod->SPIwriteRegisterBurst(RADIOLIB_SX127X_REG_FIFO, cfg->transmit.data, packetLen);
1846 6 : } break;
1847 :
1848 0 : default:
1849 0 : return(RADIOLIB_ERR_UNSUPPORTED);
1850 : }
1851 :
1852 6 : this->stagedMode = mode;
1853 6 : return(state);
1854 : }
1855 :
1856 6 : int16_t SX127x::launchMode() {
1857 : int16_t state;
1858 6 : switch(this->stagedMode) {
1859 6 : case(RADIOLIB_RADIO_MODE_RX): {
1860 6 : this->mod->setRfSwitchState(Module::MODE_RX);
1861 6 : state = setMode(this->rxMode);
1862 6 : RADIOLIB_ASSERT(state);
1863 0 : } break;
1864 :
1865 0 : case(RADIOLIB_RADIO_MODE_TX): {
1866 0 : this->mod->setRfSwitchState(Module::MODE_TX);
1867 0 : state = setMode(RADIOLIB_SX127X_TX);
1868 0 : RADIOLIB_ASSERT(state);
1869 0 : } break;
1870 :
1871 0 : default:
1872 0 : return(RADIOLIB_ERR_UNSUPPORTED);
1873 : }
1874 :
1875 0 : this->stagedMode = RADIOLIB_RADIO_MODE_NONE;
1876 0 : return(state);
1877 : }
1878 :
1879 : #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE
1880 0 : void SX127x::setDirectAction(void (*func)(void)) {
1881 0 : setDio1Action(func, this->mod->hal->GpioInterruptRising);
1882 0 : }
1883 :
1884 0 : void SX127x::readBit(uint32_t pin) {
1885 0 : updateDirectBuffer((uint8_t)this->mod->hal->digitalRead(pin));
1886 0 : }
1887 : #endif
1888 :
1889 0 : int16_t SX127x::setFHSSHoppingPeriod(uint8_t freqHoppingPeriod) {
1890 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD, freqHoppingPeriod));
1891 : }
1892 :
1893 0 : uint8_t SX127x::getFHSSHoppingPeriod(void) {
1894 0 : return(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_PERIOD));
1895 : }
1896 :
1897 0 : uint8_t SX127x::getFHSSChannel(void) {
1898 0 : return(this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_HOP_CHANNEL, 5, 0));
1899 : }
1900 :
1901 0 : void SX127x::clearFHSSInt(void) {
1902 0 : int16_t modem = getActiveModem();
1903 0 : if(modem == RADIOLIB_SX127X_LORA) {
1904 0 : this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, RADIOLIB_SX127X_CLEAR_IRQ_FLAG_FHSS_CHANGE_CHANNEL);
1905 0 : } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
1906 0 : return; //These are not the interrupts you are looking for
1907 : }
1908 : }
1909 :
1910 0 : int16_t SX127x::setDIOMapping(uint32_t pin, uint32_t value) {
1911 0 : if (pin > 5)
1912 0 : return RADIOLIB_ERR_INVALID_DIO_PIN;
1913 :
1914 0 : if (pin < 4)
1915 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, value, 7 - 2 * pin, 6 - 2 * pin));
1916 : else
1917 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_2, value, 15 - 2 * pin, 14 - 2 * pin));
1918 : }
1919 :
1920 0 : int16_t SX127x::setDIOPreambleDetect(bool usePreambleDetect) {
1921 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);
1922 : }
1923 :
1924 6 : float SX127x::getRSSI(bool packet, bool skipReceive, int16_t offset) {
1925 6 : if(getActiveModem() == RADIOLIB_SX127X_LORA) {
1926 6 : if(packet) {
1927 : // LoRa packet mode, get RSSI of the last packet
1928 6 : float lastPacketRSSI = offset + this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_PKT_RSSI_VALUE);
1929 :
1930 : // spread-spectrum modulation signal can be received below noise floor
1931 : // check last packet SNR and if it's less than 0, add it to reported RSSI to get the correct value
1932 6 : float lastPacketSNR = SX127x::getSNR();
1933 6 : if(lastPacketSNR < 0.0f) {
1934 6 : lastPacketRSSI += lastPacketSNR;
1935 : }
1936 6 : return(lastPacketRSSI);
1937 :
1938 : } else {
1939 : // LoRa instant, get current RSSI
1940 0 : float currentRSSI = offset + this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE);
1941 0 : return(currentRSSI);
1942 : }
1943 :
1944 : } else {
1945 : // for FSK, there is no packet RSSI
1946 :
1947 : // enable listen mode
1948 0 : if(!skipReceive) {
1949 0 : startReceive();
1950 : }
1951 :
1952 : // read the value for FSK
1953 0 : float rssi = (float)this->mod->SPIgetRegValue(RADIOLIB_SX127X_REG_RSSI_VALUE_FSK) / -2.0f;
1954 :
1955 : // set mode back to standby
1956 0 : if(!skipReceive) {
1957 0 : standby();
1958 : }
1959 :
1960 : // return the value
1961 0 : return(rssi);
1962 : }
1963 : }
1964 :
1965 0 : int16_t SX127x::setHeaderType(uint8_t headerType, uint8_t bitIndex, size_t len) {
1966 : // check active modem
1967 0 : if(getActiveModem() != RADIOLIB_SX127X_LORA) {
1968 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1969 : }
1970 :
1971 : // set requested packet mode
1972 0 : int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, headerType, bitIndex, bitIndex);
1973 0 : RADIOLIB_ASSERT(state);
1974 :
1975 : // set length to register
1976 0 : state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len);
1977 0 : RADIOLIB_ASSERT(state);
1978 :
1979 : // update cached value
1980 0 : SX127x::packetLength = len;
1981 :
1982 0 : return(state);
1983 : }
1984 :
1985 0 : int16_t SX127x::setLowBatteryThreshold(int8_t level, uint32_t pin) {
1986 : // check disable
1987 0 : if(level < 0) {
1988 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LOW_BAT, RADIOLIB_SX127X_LOW_BAT_OFF, 3, 3));
1989 : }
1990 :
1991 : // enable detector and set the threshold
1992 0 : int16_t state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LOW_BAT, RADIOLIB_SX127X_LOW_BAT_ON | level, 3, 0);
1993 0 : RADIOLIB_ASSERT(state);
1994 :
1995 : // set DIO mapping
1996 0 : switch(pin) {
1997 0 : case(0):
1998 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_TEMP_CHANGE_LOW_BAT, 7, 6));
1999 0 : case(3):
2000 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO3_CONT_TEMP_CHANGE_LOW_BAT, 1, 0));
2001 0 : case(4):
2002 0 : return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_2, RADIOLIB_SX127X_DIO4_PACK_TEMP_CHANGE_LOW_BAT, 7, 6));
2003 : }
2004 0 : return(RADIOLIB_ERR_INVALID_DIO_PIN);
2005 : }
2006 :
2007 : #endif
|