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