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