Line data Source code
1 : #include "SX128x.h"
2 : #include <math.h>
3 : #include <string.h>
4 : #if !RADIOLIB_EXCLUDE_SX128X
5 :
6 13 : SX128x::SX128x(Module* mod) : PhysicalLayer() {
7 13 : this->freqStep = RADIOLIB_SX128X_FREQUENCY_STEP_SIZE;
8 13 : this->maxPacketLength = RADIOLIB_SX128X_MAX_PACKET_LENGTH;
9 13 : this->mod = mod;
10 13 : this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_SX128X_IRQ_TX_DONE;
11 13 : this->irqMap[RADIOLIB_IRQ_RX_DONE] = RADIOLIB_SX128X_IRQ_RX_DONE;
12 13 : this->irqMap[RADIOLIB_IRQ_PREAMBLE_DETECTED] = RADIOLIB_SX128X_IRQ_PREAMBLE_DETECTED;
13 13 : this->irqMap[RADIOLIB_IRQ_SYNC_WORD_VALID] = RADIOLIB_SX128X_IRQ_SYNC_WORD_VALID;
14 13 : this->irqMap[RADIOLIB_IRQ_HEADER_VALID] = RADIOLIB_SX128X_IRQ_HEADER_VALID;
15 13 : this->irqMap[RADIOLIB_IRQ_HEADER_ERR] = RADIOLIB_SX128X_IRQ_HEADER_ERROR;
16 13 : this->irqMap[RADIOLIB_IRQ_CRC_ERR] = RADIOLIB_SX128X_IRQ_CRC_ERROR;
17 13 : this->irqMap[RADIOLIB_IRQ_CAD_DONE] = RADIOLIB_SX128X_IRQ_CAD_DONE;
18 13 : this->irqMap[RADIOLIB_IRQ_CAD_DETECTED] = RADIOLIB_SX128X_IRQ_CAD_DETECTED;
19 13 : this->irqMap[RADIOLIB_IRQ_TIMEOUT] = RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT;
20 13 : }
21 :
22 0 : int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t pwr, uint16_t preambleLength) {
23 : // initialize LoRa modulation variables
24 0 : this->bandwidthKhz = bw;
25 0 : this->spreadingFactor = RADIOLIB_SX128X_LORA_SF_9;
26 0 : this->codingRateLoRa = RADIOLIB_SX128X_LORA_CR_4_7;
27 :
28 : // initialize LoRa packet variables
29 0 : this->preambleLengthLoRa = preambleLength;
30 0 : this->headerType = RADIOLIB_SX128X_LORA_HEADER_EXPLICIT;
31 0 : this->payloadLen = 0xFF;
32 0 : this->crcLoRa = RADIOLIB_SX128X_LORA_CRC_ON;
33 :
34 : // set module properties and perform initial setup
35 0 : int16_t state = this->modSetup(RADIOLIB_SX128X_PACKET_TYPE_LORA);
36 0 : RADIOLIB_ASSERT(state);
37 :
38 : // configure publicly accessible settings
39 0 : state = setFrequency(freq);
40 0 : RADIOLIB_ASSERT(state);
41 :
42 0 : state = setBandwidth(bw);
43 0 : RADIOLIB_ASSERT(state);
44 :
45 0 : state = setSpreadingFactor(sf);
46 0 : RADIOLIB_ASSERT(state);
47 :
48 0 : state = setCodingRate(cr);
49 0 : RADIOLIB_ASSERT(state);
50 :
51 0 : state = setSyncWord(syncWord);
52 0 : RADIOLIB_ASSERT(state);
53 :
54 0 : state = setPreambleLength(preambleLength);
55 0 : RADIOLIB_ASSERT(state);
56 :
57 0 : state = setOutputPower(pwr);
58 0 : RADIOLIB_ASSERT(state);
59 :
60 0 : return(state);
61 : }
62 :
63 0 : int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t pwr, uint16_t preambleLength) {
64 : // initialize GFSK modulation variables
65 0 : this->bitRateKbps = br;
66 0 : this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4;
67 0 : this->modIndexReal = 1.0;
68 0 : this->modIndex = RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_00;
69 0 : this->shaping = RADIOLIB_SX128X_BLE_GFSK_BT_0_5;
70 :
71 : // initialize GFSK packet variables
72 0 : this->preambleLengthGFSK = preambleLength;
73 0 : this->syncWordLen = 2;
74 0 : this->syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1;
75 0 : this->crcGFSK = RADIOLIB_SX128X_GFSK_FLRC_CRC_2_BYTE;
76 0 : this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON;
77 :
78 : // set module properties and perform initial setup
79 0 : int16_t state = this->modSetup(RADIOLIB_SX128X_PACKET_TYPE_GFSK);
80 0 : RADIOLIB_ASSERT(state);
81 :
82 : // configure publicly accessible settings
83 0 : state = setFrequency(freq);
84 0 : RADIOLIB_ASSERT(state);
85 :
86 0 : state = setBitRate(br);
87 0 : RADIOLIB_ASSERT(state);
88 :
89 0 : state = setFrequencyDeviation(freqDev);
90 0 : RADIOLIB_ASSERT(state);
91 :
92 0 : state = setOutputPower(pwr);
93 0 : RADIOLIB_ASSERT(state);
94 :
95 0 : state = setPreambleLength(preambleLength);
96 0 : RADIOLIB_ASSERT(state);
97 :
98 0 : state = setDataShaping(RADIOLIB_SHAPING_0_5);
99 0 : RADIOLIB_ASSERT(state);
100 :
101 : // set publicly accessible settings that are not a part of begin method
102 0 : uint8_t sync[] = { 0x12, 0xAD };
103 0 : state = setSyncWord(sync, 2);
104 0 : RADIOLIB_ASSERT(state);
105 :
106 0 : state = setEncoding(RADIOLIB_ENCODING_NRZ);
107 0 : RADIOLIB_ASSERT(state);
108 :
109 0 : return(state);
110 : }
111 :
112 0 : int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t pwr, uint8_t dataShaping) {
113 : // initialize BLE modulation variables
114 0 : this->bitRateKbps = br;
115 0 : this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4;
116 0 : this->modIndexReal = 1.0;
117 0 : this->modIndex = RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_00;
118 0 : this->shaping = RADIOLIB_SX128X_BLE_GFSK_BT_0_5;
119 :
120 : // initialize BLE packet variables
121 0 : this->crcGFSK = RADIOLIB_SX128X_BLE_CRC_3_BYTE;
122 0 : this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON;
123 :
124 : // set module properties and perform initial setup
125 0 : int16_t state = this->modSetup(RADIOLIB_SX128X_PACKET_TYPE_BLE);
126 0 : RADIOLIB_ASSERT(state);
127 :
128 : // configure publicly accessible settings
129 0 : state = setFrequency(freq);
130 0 : RADIOLIB_ASSERT(state);
131 :
132 0 : state = setBitRate(br);
133 0 : RADIOLIB_ASSERT(state);
134 :
135 0 : state = setFrequencyDeviation(freqDev);
136 0 : RADIOLIB_ASSERT(state);
137 :
138 0 : state = setOutputPower(pwr);
139 0 : RADIOLIB_ASSERT(state);
140 :
141 0 : state = setDataShaping(dataShaping);
142 0 : RADIOLIB_ASSERT(state);
143 :
144 0 : return(state);
145 : }
146 :
147 0 : int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t pwr, uint16_t preambleLength, uint8_t dataShaping) {
148 : // initialize FLRC modulation variables
149 0 : this->bitRateKbps = br;
150 0 : this->bitRate = RADIOLIB_SX128X_FLRC_BR_0_650_BW_0_6;
151 0 : this->codingRateFLRC = RADIOLIB_SX128X_FLRC_CR_3_4;
152 0 : this->shaping = RADIOLIB_SX128X_FLRC_BT_0_5;
153 :
154 : // initialize FLRC packet variables
155 0 : this->preambleLengthGFSK = preambleLength;
156 0 : this->syncWordLen = 2;
157 0 : this->syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1;
158 0 : this->crcGFSK = RADIOLIB_SX128X_GFSK_FLRC_CRC_2_BYTE;
159 0 : this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_OFF;
160 :
161 : // set module properties and perform initial setup
162 0 : int16_t state = this->modSetup(RADIOLIB_SX128X_PACKET_TYPE_FLRC);
163 0 : RADIOLIB_ASSERT(state);
164 :
165 : // configure publicly accessible settings
166 0 : state = setFrequency(freq);
167 0 : RADIOLIB_ASSERT(state);
168 :
169 0 : state = setBitRate(br);
170 0 : RADIOLIB_ASSERT(state);
171 :
172 0 : state = setCodingRate(cr);
173 0 : RADIOLIB_ASSERT(state);
174 :
175 0 : state = setOutputPower(pwr);
176 0 : RADIOLIB_ASSERT(state);
177 :
178 0 : state = setPreambleLength(preambleLength);
179 0 : RADIOLIB_ASSERT(state);
180 :
181 0 : state = setDataShaping(dataShaping);
182 0 : RADIOLIB_ASSERT(state);
183 :
184 : // set publicly accessible settings that are not a part of begin method
185 0 : uint8_t sync[] = { 0x2D, 0x01, 0x4B, 0x1D};
186 0 : state = setSyncWord(sync, 4);
187 0 : RADIOLIB_ASSERT(state);
188 :
189 0 : return(state);
190 : }
191 :
192 0 : int16_t SX128x::reset(bool verify) {
193 : // run the reset sequence - same as SX126x, as SX128x docs don't seem to mention this
194 0 : this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput);
195 0 : this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow);
196 0 : this->mod->hal->delay(1);
197 0 : this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh);
198 :
199 : // return immediately when verification is disabled
200 0 : if(!verify) {
201 0 : return(RADIOLIB_ERR_NONE);
202 : }
203 :
204 : // set mode to standby
205 0 : RadioLibTime_t start = this->mod->hal->millis();
206 : while(true) {
207 : // try to set mode to standby
208 0 : int16_t state = standby();
209 0 : if(state == RADIOLIB_ERR_NONE) {
210 : // standby command successful
211 0 : return(RADIOLIB_ERR_NONE);
212 : }
213 :
214 : // standby command failed, check timeout and try again
215 0 : if(this->mod->hal->millis() - start >= 3000) {
216 : // timed out, possibly incorrect wiring
217 0 : return(state);
218 : }
219 :
220 : // wait a bit to not spam the module
221 0 : this->mod->hal->delay(10);
222 0 : }
223 : }
224 :
225 3 : int16_t SX128x::transmit(const uint8_t* data, size_t len, uint8_t addr) {
226 : // check packet length
227 3 : if(this->codingRateLoRa == RADIOLIB_SX128X_LORA_CR_4_8_LI && this->crcLoRa == RADIOLIB_SX128X_LORA_CRC_ON) {
228 : // Long Interleaver at CR 4/8 supports up to 253 bytes if CRC is enabled
229 0 : if(len > RADIOLIB_SX128X_MAX_PACKET_LENGTH - 2) {
230 0 : return(RADIOLIB_ERR_PACKET_TOO_LONG);
231 : }
232 3 : } else if(len > RADIOLIB_SX128X_MAX_PACKET_LENGTH) {
233 0 : return(RADIOLIB_ERR_PACKET_TOO_LONG);
234 : }
235 :
236 : // check active modem
237 3 : uint8_t modem = getPacketType();
238 3 : if(modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING) {
239 0 : return(RADIOLIB_ERR_WRONG_MODEM);
240 : }
241 :
242 : // set mode to standby
243 3 : int16_t state = standby();
244 3 : RADIOLIB_ASSERT(state);
245 :
246 : // calculate timeout in ms (5ms + 500 % of expected time-on-air)
247 0 : RadioLibTime_t timeout = 5 + (getTimeOnAir(len) * 5) / 1000;
248 : RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout);
249 :
250 : // start transmission
251 0 : state = startTransmit(data, len, addr);
252 0 : RADIOLIB_ASSERT(state);
253 :
254 : // wait for packet transmission or timeout
255 0 : RadioLibTime_t start = this->mod->hal->millis();
256 0 : while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
257 0 : this->mod->hal->yield();
258 0 : if(this->mod->hal->millis() - start > timeout) {
259 0 : finishTransmit();
260 0 : return(RADIOLIB_ERR_TX_TIMEOUT);
261 : }
262 : }
263 :
264 0 : return(finishTransmit());
265 : }
266 :
267 3 : int16_t SX128x::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) {
268 : // check active modem
269 3 : uint8_t modem = getPacketType();
270 3 : if(modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING) {
271 0 : return(RADIOLIB_ERR_WRONG_MODEM);
272 : }
273 :
274 : // set mode to standby
275 3 : int16_t state = standby();
276 3 : RADIOLIB_ASSERT(state);
277 :
278 : // calculate timeout (1000% of expected time-on-air)
279 : // for most other modules, it is 500%, however, the overall datarates of SX128x are higher
280 : // so we use higher value for the default timeout
281 0 : RadioLibTime_t timeoutInternal = timeout;
282 0 : if(!timeoutInternal) {
283 0 : timeoutInternal = getTimeOnAir(len) * 10;
284 : }
285 : RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", (uint32_t)((timeout + 999) / 1000));
286 :
287 : // start reception
288 0 : uint32_t timeoutValue = (uint32_t)((float)timeoutInternal / 15.625f);
289 0 : state = startReceive(timeoutValue);
290 0 : RADIOLIB_ASSERT(state);
291 :
292 : // wait for packet reception or timeout
293 0 : bool softTimeout = false;
294 0 : RadioLibTime_t start = this->mod->hal->micros();
295 0 : while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
296 0 : this->mod->hal->yield();
297 : // safety check, the timeout should be done by the radio
298 0 : if(this->mod->hal->micros() - start > timeout) {
299 0 : softTimeout = true;
300 0 : break;
301 : }
302 : }
303 :
304 : // if it was a timeout, this will return an error code
305 0 : state = standby();
306 0 : if((state != RADIOLIB_ERR_NONE) && (state != RADIOLIB_ERR_SPI_CMD_TIMEOUT)) {
307 0 : return(state);
308 : }
309 :
310 : // check whether this was a timeout or not
311 0 : if(softTimeout || (getIrqStatus() & this->irqMap[RADIOLIB_IRQ_TIMEOUT])) {
312 0 : (void)finishReceive();
313 0 : return(RADIOLIB_ERR_RX_TIMEOUT);
314 : }
315 :
316 : // read the received data
317 0 : return(readData(data, len));
318 : }
319 :
320 3 : int16_t SX128x::transmitDirect(uint32_t frf) {
321 : // set RF switch (if present)
322 3 : this->mod->setRfSwitchState(Module::MODE_TX);
323 :
324 : // user requested to start transmitting immediately (required for RTTY)
325 3 : int16_t state = RADIOLIB_ERR_NONE;
326 3 : if(frf != 0) {
327 0 : state = setRfFrequency(frf);
328 : }
329 3 : RADIOLIB_ASSERT(state);
330 :
331 : // start transmitting
332 3 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_TX_CONTINUOUS_WAVE, NULL, 0));
333 : }
334 :
335 3 : int16_t SX128x::receiveDirect() {
336 : // set RF switch (if present)
337 3 : this->mod->setRfSwitchState(Module::MODE_RX);
338 :
339 : // SX128x is unable to output received data directly
340 3 : return(RADIOLIB_ERR_UNKNOWN);
341 : }
342 :
343 3 : int16_t SX128x::scanChannel() {
344 3 : ChannelScanConfig_t cfg = {
345 : .cad = {
346 : .symNum = RADIOLIB_SX128X_CAD_PARAM_DEFAULT,
347 : .detPeak = 0,
348 : .detMin = 0,
349 : .exitMode = 0,
350 : .timeout = 0,
351 : .irqFlags = RADIOLIB_IRQ_CAD_DEFAULT_FLAGS,
352 : .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK,
353 : },
354 : };
355 6 : return(this->scanChannel(cfg));
356 : }
357 :
358 6 : int16_t SX128x::scanChannel(const ChannelScanConfig_t &config) {
359 : // set mode to CAD
360 6 : int16_t state = startChannelScan(config);
361 6 : RADIOLIB_ASSERT(state);
362 :
363 : // wait for channel activity detected or timeout
364 0 : while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
365 0 : this->mod->hal->yield();
366 : }
367 :
368 : // check CAD result
369 0 : return(getChannelScanResult());
370 : }
371 :
372 3 : int16_t SX128x::sleep() {
373 3 : return(SX128x::sleep(true));
374 : }
375 :
376 3 : int16_t SX128x::sleep(bool retainConfig) {
377 : // set RF switch (if present)
378 3 : this->mod->setRfSwitchState(Module::MODE_IDLE);
379 :
380 3 : uint8_t sleepConfig = RADIOLIB_SX128X_SLEEP_DATA_BUFFER_RETAIN | RADIOLIB_SX128X_SLEEP_DATA_RAM_RETAIN;
381 3 : if(!retainConfig) {
382 0 : sleepConfig = RADIOLIB_SX128X_SLEEP_DATA_BUFFER_FLUSH | RADIOLIB_SX128X_SLEEP_DATA_RAM_FLUSH;
383 : }
384 3 : int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SAVE_CONTEXT, NULL, 0, false, false);
385 3 : RADIOLIB_ASSERT(state);
386 3 : state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_SLEEP, &sleepConfig, 1, false, false);
387 :
388 : // wait for SX128x to safely enter sleep mode
389 3 : this->mod->hal->delay(1);
390 :
391 3 : return(state);
392 : }
393 :
394 18 : int16_t SX128x::standby() {
395 18 : return(SX128x::standby(RADIOLIB_SX128X_STANDBY_RC));
396 : }
397 :
398 21 : int16_t SX128x::standby(uint8_t mode) {
399 21 : return(SX128x::standby(mode, true));
400 : }
401 :
402 21 : int16_t SX128x::standby(uint8_t mode, bool wakeup) {
403 : // set RF switch (if present)
404 21 : this->mod->setRfSwitchState(Module::MODE_IDLE);
405 :
406 21 : if(wakeup) {
407 : // send a NOP command - this pulls the NSS low to exit the sleep mode,
408 : // while preventing interference with possible other SPI transactions
409 21 : (void)this->mod->SPIwriteStream((uint16_t)RADIOLIB_SX128X_CMD_NOP, NULL, 0, false, false);
410 : }
411 :
412 21 : const uint8_t data[] = { mode };
413 42 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_STANDBY, data, 1));
414 : }
415 :
416 0 : void SX128x::setDio1Action(void (*func)(void)) {
417 0 : this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptRising);
418 0 : }
419 :
420 0 : void SX128x::clearDio1Action() {
421 0 : this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()));
422 0 : }
423 :
424 0 : void SX128x::setPacketReceivedAction(void (*func)(void)) {
425 0 : this->setDio1Action(func);
426 0 : }
427 :
428 0 : void SX128x::clearPacketReceivedAction() {
429 0 : this->clearDio1Action();
430 0 : }
431 :
432 0 : void SX128x::setPacketSentAction(void (*func)(void)) {
433 0 : this->setDio1Action(func);
434 0 : }
435 :
436 0 : void SX128x::clearPacketSentAction() {
437 0 : this->clearDio1Action();
438 0 : }
439 :
440 3 : int16_t SX128x::finishTransmit() {
441 : // clear interrupt flags
442 3 : clearIrqStatus();
443 :
444 : // set mode to standby to disable transmitter/RF switch
445 3 : return(standby());
446 : }
447 :
448 3 : int16_t SX128x::startReceive() {
449 3 : return(this->startReceive(RADIOLIB_SX128X_RX_TIMEOUT_INF, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0));
450 : }
451 :
452 3 : int16_t SX128x::readData(uint8_t* data, size_t len) {
453 : // check active modem
454 3 : if(getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_RANGING) {
455 0 : return(RADIOLIB_ERR_WRONG_MODEM);
456 : }
457 :
458 : // set mode to standby
459 3 : int16_t state = standby();
460 3 : RADIOLIB_ASSERT(state);
461 :
462 : // check integrity CRC
463 0 : uint16_t irq = getIrqStatus();
464 0 : int16_t crcState = RADIOLIB_ERR_NONE;
465 : // Report CRC mismatch when there's a payload CRC error, or a header error and no valid header (to avoid false alarm from previous packet)
466 0 : if((irq & RADIOLIB_SX128X_IRQ_CRC_ERROR) || ((irq & RADIOLIB_SX128X_IRQ_HEADER_ERROR) && !(irq & RADIOLIB_SX128X_IRQ_HEADER_VALID))) {
467 0 : crcState = RADIOLIB_ERR_CRC_MISMATCH;
468 : }
469 :
470 : // get packet length and Rx buffer offset
471 0 : uint8_t offset = 0;
472 0 : size_t length = getPacketLength(true, &offset);
473 0 : if((len != 0) && (len < length)) {
474 : // user requested less data than we got, only return what was requested
475 0 : length = len;
476 : }
477 :
478 : // read packet data starting at offset
479 0 : state = readBuffer(data, length, offset);
480 0 : RADIOLIB_ASSERT(state);
481 :
482 : // clear interrupt flags
483 0 : state = clearIrqStatus();
484 :
485 : // check if CRC failed - this is done after reading data to give user the option to keep them
486 0 : RADIOLIB_ASSERT(crcState);
487 :
488 0 : return(state);
489 : }
490 :
491 3 : int16_t SX128x::finishReceive() {
492 : // set mode to standby to disable RF switch
493 3 : int16_t state = standby();
494 3 : RADIOLIB_ASSERT(state);
495 :
496 : // clear interrupt flags
497 0 : return(clearIrqStatus());
498 : }
499 :
500 3 : uint32_t SX128x::getIrqFlags() {
501 3 : return((uint32_t)this->getIrqStatus());
502 : }
503 :
504 3 : int16_t SX128x::setIrqFlags(uint32_t irq) {
505 3 : return(this->setDioIrqParams(irq, irq));
506 : }
507 :
508 3 : int16_t SX128x::clearIrqFlags(uint32_t irq) {
509 3 : return(this->clearIrqStatus(irq));
510 : }
511 :
512 3 : int16_t SX128x::startChannelScan() {
513 3 : ChannelScanConfig_t cfg = {
514 : .cad = {
515 : .symNum = RADIOLIB_SX128X_CAD_PARAM_DEFAULT,
516 : .detPeak = 0,
517 : .detMin = 0,
518 : .exitMode = 0,
519 : .timeout = 0,
520 : .irqFlags = RADIOLIB_IRQ_CAD_DEFAULT_FLAGS,
521 : .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK,
522 : },
523 : };
524 6 : return(this->startChannelScan(cfg));
525 : }
526 :
527 12 : int16_t SX128x::startChannelScan(const ChannelScanConfig_t &config) {
528 : // check active modem
529 12 : if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) {
530 12 : return(RADIOLIB_ERR_WRONG_MODEM);
531 : }
532 :
533 : // set mode to standby
534 0 : int16_t state = standby();
535 0 : RADIOLIB_ASSERT(state);
536 :
537 : // set DIO pin mapping
538 0 : state = setDioIrqParams(getIrqMapped(config.cad.irqFlags), getIrqMapped(config.cad.irqMask));
539 0 : RADIOLIB_ASSERT(state);
540 :
541 : // clear interrupt flags
542 0 : state = clearIrqStatus();
543 0 : RADIOLIB_ASSERT(state);
544 :
545 : // set RF switch (if present)
546 0 : this->mod->setRfSwitchState(Module::MODE_RX);
547 :
548 : // set mode to CAD
549 0 : return(setCad(config.cad.symNum));
550 : }
551 :
552 3 : int16_t SX128x::getChannelScanResult() {
553 : // check active modem
554 3 : if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) {
555 3 : return(RADIOLIB_ERR_WRONG_MODEM);
556 : }
557 :
558 : // check CAD result
559 0 : uint16_t cadResult = getIrqStatus();
560 0 : int16_t state = RADIOLIB_ERR_UNKNOWN;
561 0 : if(cadResult & RADIOLIB_SX128X_IRQ_CAD_DETECTED) {
562 : // detected some LoRa activity
563 0 : state = RADIOLIB_LORA_DETECTED;
564 0 : } else if(cadResult & RADIOLIB_SX128X_IRQ_CAD_DONE) {
565 : // channel is free
566 0 : state = RADIOLIB_CHANNEL_FREE;
567 : }
568 :
569 0 : clearIrqStatus();
570 0 : return(state);
571 : }
572 :
573 3 : int16_t SX128x::setFrequency(float freq) {
574 3 : RADIOLIB_CHECK_RANGE(freq, 2400.0f, 2500.0f, RADIOLIB_ERR_INVALID_FREQUENCY);
575 :
576 : // calculate raw value
577 0 : uint32_t frf = (freq * (uint32_t(1) << RADIOLIB_SX128X_DIV_EXPONENT)) / RADIOLIB_SX128X_CRYSTAL_FREQ;
578 0 : return(setRfFrequency(frf));
579 : }
580 :
581 0 : int16_t SX128x::setBandwidth(float bw) {
582 : // check active modem
583 0 : uint8_t modem = getPacketType();
584 0 : if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) {
585 : // check range for LoRa
586 0 : RADIOLIB_CHECK_RANGE(bw, 203.125f, 1625.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
587 0 : } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING) {
588 : // check range for ranging
589 0 : RADIOLIB_CHECK_RANGE(bw, 406.25f, 1625.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
590 : } else {
591 0 : return(RADIOLIB_ERR_WRONG_MODEM);
592 : }
593 :
594 0 : if(fabsf(bw - 203.125f) <= 0.001f) {
595 0 : this->bandwidth = RADIOLIB_SX128X_LORA_BW_203_125;
596 0 : } else if(fabsf(bw - 406.25f) <= 0.001f) {
597 0 : this->bandwidth = RADIOLIB_SX128X_LORA_BW_406_25;
598 0 : } else if(fabsf(bw - 812.5f) <= 0.001f) {
599 0 : this->bandwidth = RADIOLIB_SX128X_LORA_BW_812_50;
600 0 : } else if(fabsf(bw - 1625.0f) <= 0.001f) {
601 0 : this->bandwidth = RADIOLIB_SX128X_LORA_BW_1625_00;
602 : } else {
603 0 : return(RADIOLIB_ERR_INVALID_BANDWIDTH);
604 : }
605 :
606 : // update modulation parameters
607 0 : this->bandwidthKhz = bw;
608 0 : return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRateLoRa));
609 : }
610 :
611 0 : int16_t SX128x::setSpreadingFactor(uint8_t sf) {
612 : // check active modem
613 0 : uint8_t modem = getPacketType();
614 0 : if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) {
615 : // check range for LoRa
616 0 : RADIOLIB_CHECK_RANGE(sf, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
617 0 : } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING) {
618 : // check range for ranging
619 0 : RADIOLIB_CHECK_RANGE(sf, 5, 10, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
620 : } else {
621 0 : return(RADIOLIB_ERR_WRONG_MODEM);
622 : }
623 :
624 : // update modulation parameters
625 0 : this->spreadingFactor = sf << 4;
626 0 : int16_t state = setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRateLoRa);
627 0 : RADIOLIB_ASSERT(state);
628 :
629 : // update mystery register in LoRa mode - SX1280 datasheet rev 3.2 section 14.4.1
630 0 : if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) {
631 0 : uint8_t data = 0;
632 0 : if((this->spreadingFactor == RADIOLIB_SX128X_LORA_SF_5) || (this->spreadingFactor == RADIOLIB_SX128X_LORA_SF_6)) {
633 0 : data = 0x1E;
634 0 : } else if((this->spreadingFactor == RADIOLIB_SX128X_LORA_SF_7) || (this->spreadingFactor == RADIOLIB_SX128X_LORA_SF_8)) {
635 0 : data = 0x37;
636 : } else {
637 0 : data = 0x32;
638 : }
639 0 : state = SX128x::writeRegister(RADIOLIB_SX128X_REG_LORA_SF_CONFIG, &data, 1);
640 0 : RADIOLIB_ASSERT(state);
641 :
642 : // this register must also be updated for some reason
643 0 : state = SX128x::readRegister(RADIOLIB_SX128X_REG_FREQ_ERROR_CORRECTION, &data, 1);
644 0 : RADIOLIB_ASSERT(state);
645 :
646 0 : data |= 0x01;
647 0 : state = SX128x::writeRegister(RADIOLIB_SX128X_REG_FREQ_ERROR_CORRECTION, &data, 1);
648 0 : RADIOLIB_ASSERT(state);
649 : }
650 :
651 0 : return(state);
652 : }
653 :
654 0 : int16_t SX128x::setCodingRate(uint8_t cr, bool longInterleaving) {
655 : // check active modem
656 0 : uint8_t modem = getPacketType();
657 :
658 : // LoRa/ranging
659 0 : if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) {
660 0 : RADIOLIB_CHECK_RANGE(cr, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
661 :
662 : // update modulation parameters
663 0 : if(longInterleaving && (modem == RADIOLIB_SX128X_PACKET_TYPE_LORA)) {
664 0 : switch(cr) {
665 0 : case 4:
666 0 : this->codingRateLoRa = 0;
667 0 : break;
668 0 : case 5:
669 : case 6:
670 0 : this->codingRateLoRa = cr;
671 0 : break;
672 0 : case 8:
673 0 : this->codingRateLoRa = cr - 1;
674 0 : break;
675 0 : default:
676 0 : return(RADIOLIB_ERR_INVALID_CODING_RATE);
677 : }
678 : } else {
679 0 : this->codingRateLoRa = cr - 4;
680 : }
681 0 : return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRateLoRa));
682 :
683 : // FLRC
684 0 : } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC) {
685 0 : RADIOLIB_CHECK_RANGE(cr, 2, 4, RADIOLIB_ERR_INVALID_CODING_RATE);
686 :
687 : // update modulation parameters
688 0 : this->codingRateFLRC = (cr - 2) * 2;
689 0 : return(setModulationParams(this->bitRate, this->codingRateFLRC, this->shaping));
690 : }
691 :
692 0 : return(RADIOLIB_ERR_WRONG_MODEM);
693 : }
694 :
695 3 : int16_t SX128x::setOutputPower(int8_t pwr) {
696 : // check if power value is configurable
697 3 : int16_t state = checkOutputPower(pwr, NULL);
698 3 : RADIOLIB_ASSERT(state);
699 :
700 3 : this->power = pwr + 18;
701 3 : return(setTxParams(this->power));
702 : }
703 :
704 6 : int16_t SX128x::checkOutputPower(int8_t pwr, int8_t* clipped) {
705 6 : if(clipped) {
706 0 : *clipped = RADIOLIB_MAX(-18, RADIOLIB_MIN(13, pwr));
707 : }
708 6 : RADIOLIB_CHECK_RANGE(pwr, -18, 13, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
709 6 : return(RADIOLIB_ERR_NONE);
710 : }
711 :
712 3 : int16_t SX128x::setModem(ModemType_t modem) {
713 3 : switch(modem) {
714 0 : case(ModemType_t::RADIOLIB_MODEM_LORA): {
715 0 : return(this->begin());
716 : } break;
717 0 : case(ModemType_t::RADIOLIB_MODEM_FSK): {
718 0 : return(this->beginGFSK());
719 : } break;
720 3 : default:
721 3 : return(RADIOLIB_ERR_WRONG_MODEM);
722 : }
723 : }
724 :
725 9 : int16_t SX128x::getModem(ModemType_t* modem) {
726 9 : RADIOLIB_ASSERT_PTR(modem);
727 :
728 9 : switch(getPacketType()) {
729 0 : case(RADIOLIB_SX128X_PACKET_TYPE_LORA):
730 0 : *modem = ModemType_t::RADIOLIB_MODEM_LORA;
731 0 : return(RADIOLIB_ERR_NONE);
732 0 : case(RADIOLIB_SX128X_PACKET_TYPE_GFSK):
733 0 : *modem = ModemType_t::RADIOLIB_MODEM_FSK;
734 0 : return(RADIOLIB_ERR_NONE);
735 : }
736 :
737 9 : return(RADIOLIB_ERR_WRONG_MODEM);
738 : }
739 :
740 3 : int16_t SX128x::setPreambleLength(size_t preambleLength) {
741 3 : uint8_t modem = getPacketType();
742 3 : if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) {
743 : // LoRa or ranging
744 : // the actual limit is 491520, however, some platforms (notably AVR) limit size_t to 16 bits
745 0 : RADIOLIB_CHECK_RANGE(preambleLength, 2, 65534, RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH);
746 :
747 : // check preamble length is even - no point even trying odd numbers
748 0 : if(preambleLength % 2 != 0) {
749 0 : return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH);
750 : }
751 :
752 : // calculate exponent and mantissa values (use the next longer preamble if there's no exact match)
753 0 : uint8_t e = 1;
754 0 : uint8_t m = 1;
755 0 : uint32_t len = 0;
756 0 : for(; e <= 15; e++) {
757 0 : for(m = 1; m <= 15; m++) {
758 0 : len = m * (uint32_t(1) << e);
759 0 : if(len >= preambleLength) {
760 0 : break;
761 : }
762 : }
763 0 : if(len >= preambleLength) {
764 0 : break;
765 : }
766 : }
767 :
768 : // update packet parameters
769 0 : this->preambleLengthLoRa = (e << 4) | m;
770 0 : return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled));
771 :
772 3 : } else if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC)) {
773 : // GFSK or FLRC
774 0 : RADIOLIB_CHECK_RANGE(preambleLength, 4, 32, RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH);
775 :
776 : // check preamble length is multiple of 4
777 0 : if(preambleLength % 4 != 0) {
778 0 : return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH);
779 : }
780 :
781 : // update packet parameters
782 0 : this->preambleLengthGFSK = ((preambleLength / 4) - 1) << 4;
783 0 : return(setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, this->packetType));
784 : }
785 :
786 3 : return(RADIOLIB_ERR_WRONG_MODEM);
787 : }
788 :
789 3 : int16_t SX128x::setDataRate(DataRate_t dr, ModemType_t modem) {
790 : // get the current modem
791 : ModemType_t currentModem;
792 3 : int16_t state = this->getModem(¤tModem);
793 3 : RADIOLIB_ASSERT(state);
794 :
795 : // switch over if the requested modem is different
796 0 : if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) {
797 0 : state = this->standby();
798 0 : RADIOLIB_ASSERT(state);
799 0 : state = this->setModem(modem);
800 0 : RADIOLIB_ASSERT(state);
801 : }
802 :
803 0 : if(modem == RADIOLIB_MODEM_NONE) {
804 0 : modem = currentModem;
805 : }
806 :
807 : // select interpretation based on modem
808 0 : if (modem == RADIOLIB_MODEM_LORA) {
809 0 : state = this->setBandwidth(dr.lora.bandwidth);
810 0 : RADIOLIB_ASSERT(state);
811 0 : state = this->setSpreadingFactor(dr.lora.spreadingFactor);
812 0 : RADIOLIB_ASSERT(state);
813 0 : state = this->setCodingRate(dr.lora.codingRate);
814 : } else {
815 0 : return(RADIOLIB_ERR_WRONG_MODEM);
816 : }
817 0 : return(state);
818 : }
819 :
820 3 : int16_t SX128x::checkDataRate(DataRate_t dr, ModemType_t modem) {
821 3 : int16_t state = RADIOLIB_ERR_UNKNOWN;
822 :
823 : // retrieve modem if not supplied
824 3 : if(modem == RADIOLIB_MODEM_NONE) {
825 3 : state = this->getModem(&modem);
826 3 : RADIOLIB_ASSERT(state);
827 : }
828 :
829 : // select interpretation based on modem
830 0 : if(modem == RADIOLIB_MODEM_FSK) {
831 0 : RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 125.0f, 2000.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
832 0 : RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 62.5f, 1000.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
833 0 : return(RADIOLIB_ERR_NONE);
834 :
835 0 : } else if(modem == RADIOLIB_MODEM_LORA) {
836 0 : RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
837 0 : RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 203.0f, 1625.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
838 0 : RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
839 0 : return(RADIOLIB_ERR_NONE);
840 :
841 : }
842 :
843 0 : return(state);
844 : }
845 :
846 3 : int16_t SX128x::setBitRate(float br) {
847 : // check active modem
848 3 : uint8_t modem = getPacketType();
849 :
850 : // GFSK/BLE
851 3 : if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE)) {
852 0 : if((uint16_t)br == 125) {
853 0 : this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_125_BW_0_3;
854 0 : } else if((uint16_t)br == 250) {
855 0 : this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_250_BW_0_6;
856 0 : } else if((uint16_t)br == 400) {
857 0 : this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_400_BW_1_2;
858 0 : } else if((uint16_t)br == 500) {
859 0 : this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_500_BW_1_2;
860 0 : } else if((uint16_t)br == 800) {
861 0 : this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4;
862 0 : } else if((uint16_t)br == 1000) {
863 0 : this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_1_000_BW_2_4;
864 0 : } else if((uint16_t)br == 1600) {
865 0 : this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_1_600_BW_2_4;
866 0 : } else if((uint16_t)br == 2000) {
867 0 : this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_2_000_BW_2_4;
868 : } else {
869 0 : return(RADIOLIB_ERR_INVALID_BIT_RATE);
870 : }
871 :
872 : // update modulation parameters
873 0 : this->bitRateKbps = (uint16_t)br;
874 0 : return(setModulationParams(this->bitRate, this->modIndex, this->shaping));
875 :
876 : // FLRC
877 3 : } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC) {
878 0 : if((uint16_t)br == 260) {
879 0 : this->bitRate = RADIOLIB_SX128X_FLRC_BR_0_260_BW_0_3;
880 0 : } else if((uint16_t)br == 325) {
881 0 : this->bitRate = RADIOLIB_SX128X_FLRC_BR_0_325_BW_0_3;
882 0 : } else if((uint16_t)br == 520) {
883 0 : this->bitRate = RADIOLIB_SX128X_FLRC_BR_0_520_BW_0_6;
884 0 : } else if((uint16_t)br == 650) {
885 0 : this->bitRate = RADIOLIB_SX128X_FLRC_BR_0_650_BW_0_6;
886 0 : } else if((uint16_t)br == 1000) {
887 0 : this->bitRate = RADIOLIB_SX128X_FLRC_BR_1_000_BW_1_2;
888 0 : } else if((uint16_t)br == 1300) {
889 0 : this->bitRate = RADIOLIB_SX128X_FLRC_BR_1_300_BW_1_2;
890 : } else {
891 0 : return(RADIOLIB_ERR_INVALID_BIT_RATE);
892 : }
893 :
894 : // update modulation parameters
895 0 : this->bitRateKbps = (uint16_t)br;
896 0 : return(setModulationParams(this->bitRate, this->codingRateFLRC, this->shaping));
897 :
898 : }
899 :
900 3 : return(RADIOLIB_ERR_WRONG_MODEM);
901 : }
902 :
903 3 : int16_t SX128x::setFrequencyDeviation(float freqDev) {
904 : // check active modem
905 3 : uint8_t modem = getPacketType();
906 3 : if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE))) {
907 3 : return(RADIOLIB_ERR_WRONG_MODEM);
908 : }
909 :
910 : // set frequency deviation to lowest available setting (required for digimodes)
911 0 : float newFreqDev = freqDev;
912 0 : if(freqDev < 0.0f) {
913 0 : newFreqDev = 62.5f;
914 : }
915 :
916 0 : RADIOLIB_CHECK_RANGE(newFreqDev, 62.5f, 1000.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
917 :
918 : // override for the lowest possible frequency deviation - required for some PhysicalLayer protocols
919 0 : if(newFreqDev == 0.0f) {
920 0 : this->modIndex = RADIOLIB_SX128X_BLE_GFSK_MOD_IND_0_35;
921 0 : this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_125_BW_0_3;
922 0 : return(setModulationParams(this->bitRate, this->modIndex, this->shaping));
923 : }
924 :
925 : // update modulation parameters
926 0 : uint8_t modInd = (uint8_t)((8.0f * (newFreqDev / (float)this->bitRateKbps)) - 1.0f);
927 0 : if(modInd > RADIOLIB_SX128X_BLE_GFSK_MOD_IND_4_00) {
928 0 : return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS);
929 : }
930 :
931 : // update modulation parameters
932 0 : this->frequencyDev = newFreqDev;
933 0 : this->modIndex = modInd;
934 0 : return(setModulationParams(this->bitRate, this->modIndex, this->shaping));
935 : }
936 :
937 3 : int16_t SX128x::setDataShaping(uint8_t sh) {
938 : // check active modem
939 3 : uint8_t modem = getPacketType();
940 3 : if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC))) {
941 3 : return(RADIOLIB_ERR_WRONG_MODEM);
942 : }
943 :
944 : // set data this->shaping
945 0 : switch(sh) {
946 0 : case RADIOLIB_SHAPING_NONE:
947 0 : this->shaping = RADIOLIB_SX128X_BLE_GFSK_BT_OFF;
948 0 : break;
949 0 : case RADIOLIB_SHAPING_0_5:
950 0 : this->shaping = RADIOLIB_SX128X_BLE_GFSK_BT_0_5;
951 0 : break;
952 0 : case RADIOLIB_SHAPING_1_0:
953 0 : this->shaping = RADIOLIB_SX128X_BLE_GFSK_BT_1_0;
954 0 : break;
955 0 : default:
956 0 : return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
957 : }
958 :
959 : // update modulation parameters
960 0 : if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE)) {
961 0 : return(setModulationParams(this->bitRate, this->modIndex, this->shaping));
962 : } else {
963 0 : return(setModulationParams(this->bitRate, this->codingRateFLRC, this->shaping));
964 : }
965 : }
966 :
967 3 : int16_t SX128x::setSyncWord(uint8_t* sync, size_t len) {
968 : // check active modem
969 3 : uint8_t modem = getPacketType();
970 3 : if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC))) {
971 3 : return(RADIOLIB_ERR_WRONG_MODEM);
972 : }
973 :
974 0 : if(modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) {
975 : // GFSK can use up to 5 bytes as sync word
976 0 : if(len > 5) {
977 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
978 : }
979 :
980 : // calculate sync word length parameter value
981 0 : if(len > 0) {
982 0 : this->syncWordLen = (len - 1)*2;
983 : }
984 :
985 : } else {
986 : // FLRC requires 32-bit sync word
987 0 : if(!((len == 0) || (len == 4))) {
988 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
989 : }
990 :
991 : // save sync word length parameter value
992 0 : this->syncWordLen = len;
993 : }
994 :
995 : // update sync word
996 0 : int16_t state = SX128x::writeRegister(RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_4 + (5 - len), sync, len);
997 0 : RADIOLIB_ASSERT(state);
998 :
999 : // update packet parameters
1000 0 : if(this->syncWordLen == 0) {
1001 0 : this->syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_OFF;
1002 : } else {
1003 : /// \todo add support for multiple sync words
1004 0 : this->syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1;
1005 : }
1006 0 : return(setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, this->packetType));
1007 : }
1008 :
1009 0 : int16_t SX128x::setSyncWord(uint8_t syncWord, uint8_t controlBits) {
1010 : // check active modem
1011 0 : if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) {
1012 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1013 : }
1014 :
1015 : // update register
1016 0 : const uint8_t data[2] = {(uint8_t)((syncWord & 0xF0) | ((controlBits & 0xF0) >> 4)), (uint8_t)(((syncWord & 0x0F) << 4) | (controlBits & 0x0F))};
1017 0 : return(writeRegister(RADIOLIB_SX128X_REG_LORA_SYNC_WORD_MSB, data, 2));
1018 : }
1019 :
1020 0 : int16_t SX128x::setCRC(uint8_t len, uint32_t initial, uint16_t polynomial) {
1021 : // check active modem
1022 0 : uint8_t modem = getPacketType();
1023 :
1024 : int16_t state;
1025 0 : if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC)) {
1026 : // update packet parameters
1027 0 : if(modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) {
1028 0 : if(len > 2) {
1029 0 : return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
1030 : }
1031 : } else {
1032 0 : if(len > 3) {
1033 0 : return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
1034 : }
1035 : }
1036 0 : this->crcGFSK = len << 4;
1037 0 : state = setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, this->packetType);
1038 0 : RADIOLIB_ASSERT(state);
1039 :
1040 : // set initial CRC value
1041 0 : uint8_t data[] = { (uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF) };
1042 0 : state = writeRegister(RADIOLIB_SX128X_REG_CRC_INITIAL_MSB, data, 2);
1043 0 : RADIOLIB_ASSERT(state);
1044 :
1045 : // set CRC polynomial
1046 0 : data[0] = (uint8_t)((polynomial >> 8) & 0xFF);
1047 0 : data[1] = (uint8_t)(polynomial & 0xFF);
1048 0 : state = writeRegister(RADIOLIB_SX128X_REG_CRC_POLYNOMIAL_MSB, data, 2);
1049 0 : return(state);
1050 :
1051 0 : } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) {
1052 : // update packet parameters
1053 0 : if(len == 0) {
1054 0 : this->crcBLE = RADIOLIB_SX128X_BLE_CRC_OFF;
1055 0 : } else if(len == 3) {
1056 0 : this->crcBLE = RADIOLIB_SX128X_BLE_CRC_3_BYTE;
1057 : } else {
1058 0 : return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
1059 : }
1060 0 : state = setPacketParamsBLE(this->connectionState, this->crcBLE, this->bleTestPayload, this->whitening);
1061 0 : RADIOLIB_ASSERT(state);
1062 :
1063 : // set initial CRC value
1064 0 : const uint8_t data[] = { (uint8_t)((initial >> 16) & 0xFF), (uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF) };
1065 0 : state = writeRegister(RADIOLIB_SX128X_REG_BLE_CRC_INITIAL_MSB, data, 3);
1066 0 : return(state);
1067 :
1068 0 : } else if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) {
1069 : // update packet parameters
1070 0 : if(len == 0) {
1071 0 : this->crcLoRa = RADIOLIB_SX128X_LORA_CRC_OFF;
1072 0 : } else if(len == 2) {
1073 0 : this->crcLoRa = RADIOLIB_SX128X_LORA_CRC_ON;
1074 : } else {
1075 0 : return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
1076 : }
1077 0 : state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled);
1078 0 : return(state);
1079 : }
1080 :
1081 0 : return(RADIOLIB_ERR_UNKNOWN);
1082 : }
1083 :
1084 3 : int16_t SX128x::setWhitening(bool enabled) {
1085 : // check active modem
1086 3 : uint8_t modem = getPacketType();
1087 3 : if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE))) {
1088 3 : return(RADIOLIB_ERR_WRONG_MODEM);
1089 : }
1090 :
1091 : // update packet parameters
1092 0 : if(enabled) {
1093 0 : this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON;
1094 : } else {
1095 0 : this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_OFF;
1096 : }
1097 :
1098 0 : if(modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) {
1099 0 : return(setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, this->packetType));
1100 : }
1101 0 : return(setPacketParamsBLE(this->connectionState, this->crcBLE, this->bleTestPayload, this->whitening));
1102 : }
1103 :
1104 0 : int16_t SX128x::setAccessAddress(uint32_t addr) {
1105 : // check active modem
1106 0 : if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_BLE) {
1107 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1108 : }
1109 :
1110 : // set the address
1111 0 : const uint8_t addrBuff[] = { (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) };
1112 0 : return(SX128x::writeRegister(RADIOLIB_SX128X_REG_ACCESS_ADDRESS_BYTE_3, addrBuff, 4));
1113 : }
1114 :
1115 0 : int16_t SX128x::setHighSensitivityMode(bool enable) {
1116 : // read the current registers
1117 0 : uint8_t RxGain = 0;
1118 0 : int16_t state = readRegister(RADIOLIB_SX128X_REG_GAIN_MODE, &RxGain, 1);
1119 0 : RADIOLIB_ASSERT(state);
1120 :
1121 0 : if(enable) {
1122 0 : RxGain |= 0xC0; // Set bits 6 and 7
1123 : } else {
1124 0 : RxGain &= ~0xC0; // Unset bits 6 and 7
1125 : }
1126 :
1127 : // update all values
1128 0 : state = writeRegister(RADIOLIB_SX128X_REG_GAIN_MODE, &RxGain, 1);
1129 0 : return(state);
1130 : }
1131 :
1132 0 : int16_t SX128x::setGainControl(uint8_t gain) {
1133 : // read the current registers
1134 0 : uint8_t ManualGainSetting = 0;
1135 0 : int16_t state = readRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_2, &ManualGainSetting, 1);
1136 0 : RADIOLIB_ASSERT(state);
1137 0 : uint8_t LNAGainValue = 0;
1138 0 : state = readRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_SETTING, &LNAGainValue, 1);
1139 0 : RADIOLIB_ASSERT(state);
1140 0 : uint8_t LNAGainControl = 0;
1141 0 : state = readRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_1, &LNAGainControl, 1);
1142 0 : RADIOLIB_ASSERT(state);
1143 :
1144 : // set the gain
1145 0 : if (gain > 0 && gain < 14) {
1146 : // Set manual gain
1147 0 : ManualGainSetting &= ~0x01; // Set bit 0 to 0 (Enable Manual Gain Control)
1148 0 : LNAGainValue &= 0xF0; // Bits 0, 1, 2 and 3 to 0
1149 0 : LNAGainValue |= gain; // Set bits 0, 1, 2 and 3 to Manual Gain Setting (1-13)
1150 0 : LNAGainControl |= 0x80; // Set bit 7 to 1 (Enable Manual Gain Control)
1151 : } else {
1152 : // Set automatic gain if 0 or out of range
1153 0 : ManualGainSetting |= 0x01; // Set bit 0 to 1 (Enable Automatic Gain Control)
1154 0 : LNAGainValue &= 0xF0; // Bits 0, 1, 2 and 3 to 0
1155 0 : LNAGainValue |= 0x0A; // Set bits 0, 1, 2 and 3 to Manual Gain Setting (1-13)
1156 0 : LNAGainControl &= ~0x80; // Set bit 7 to 0 (Enable Automatic Gain Control)
1157 : }
1158 :
1159 : // update all values
1160 0 : state = writeRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_2, &ManualGainSetting, 1);
1161 0 : RADIOLIB_ASSERT(state);
1162 0 : state = writeRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_SETTING, &LNAGainValue, 1);
1163 0 : RADIOLIB_ASSERT(state);
1164 0 : state = writeRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_1, &LNAGainControl, 1);
1165 0 : return(state);
1166 : }
1167 :
1168 3 : float SX128x::getRSSI() {
1169 : // get packet status
1170 : uint8_t packetStatus[5];
1171 3 : this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_PACKET_STATUS, packetStatus, 5);
1172 :
1173 : // check active modem
1174 3 : uint8_t modem = getPacketType();
1175 3 : if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) {
1176 : // LoRa or ranging
1177 0 : uint8_t rssiSync = packetStatus[0];
1178 0 : float rssiMeasured = -1.0 * rssiSync/2.0;
1179 0 : float snr = getSNR();
1180 0 : if(snr <= 0.0f) {
1181 0 : return(rssiMeasured - snr);
1182 : } else {
1183 0 : return(rssiMeasured);
1184 : }
1185 : } else {
1186 : // GFSK, BLE or FLRC
1187 3 : uint8_t rssiSync = packetStatus[1];
1188 3 : return(-1.0 * rssiSync/2.0);
1189 : }
1190 : }
1191 :
1192 0 : float SX128x::getRSSI(bool packet) {
1193 0 : if (!packet) {
1194 : // get instantaneous RSSI value
1195 0 : uint8_t data[3] = {0, 0, 0}; // RssiInst, Status, RFU
1196 0 : this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_RSSI_INST, data, 3);
1197 0 : return ((float)data[0] / (-2.0f));
1198 : } else {
1199 0 : return this->getRSSI();
1200 : }
1201 : }
1202 :
1203 3 : float SX128x::getSNR() {
1204 : // check active modem
1205 3 : uint8_t modem = getPacketType();
1206 3 : if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING))) {
1207 3 : return(0.0);
1208 : }
1209 :
1210 : // get packet status
1211 : uint8_t packetStatus[5];
1212 0 : this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_PACKET_STATUS, packetStatus, 5);
1213 :
1214 : // calculate real SNR
1215 0 : uint8_t snr = packetStatus[1];
1216 0 : if(snr < 128) {
1217 0 : return(snr/4.0);
1218 : } else {
1219 0 : return((snr - 256)/4.0f);
1220 : }
1221 : }
1222 :
1223 0 : float SX128x::getFrequencyError() {
1224 : // check active modem
1225 0 : uint8_t modem = getPacketType();
1226 0 : if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING))) {
1227 0 : return(0.0);
1228 : }
1229 :
1230 : // read the raw frequency error register values
1231 0 : uint8_t efeRaw[3] = {0};
1232 0 : int16_t state = readRegister(RADIOLIB_SX128X_REG_FEI_MSB, &efeRaw[0], 1);
1233 0 : RADIOLIB_ASSERT(state);
1234 0 : state = readRegister(RADIOLIB_SX128X_REG_FEI_MID, &efeRaw[1], 1);
1235 0 : RADIOLIB_ASSERT(state);
1236 0 : state = readRegister(RADIOLIB_SX128X_REG_FEI_LSB, &efeRaw[2], 1);
1237 0 : RADIOLIB_ASSERT(state);
1238 0 : uint32_t efe = ((uint32_t) efeRaw[0] << 16) | ((uint32_t) efeRaw[1] << 8) | efeRaw[2];
1239 0 : efe &= 0x0FFFFF;
1240 :
1241 0 : float error = 0;
1242 :
1243 : // check the first bit
1244 0 : if (efe & 0x80000) {
1245 : // frequency error is negative
1246 0 : efe |= (uint32_t) 0xFFF00000;
1247 0 : efe = ~efe + 1;
1248 0 : error = 1.55f * (float) efe / (1600.0f / this->bandwidthKhz) * -1.0f;
1249 : } else {
1250 0 : error = 1.55f * (float) efe / (1600.0f / this->bandwidthKhz);
1251 : }
1252 :
1253 0 : return(error);
1254 : }
1255 :
1256 3 : size_t SX128x::getPacketLength(bool update) {
1257 3 : return(this->getPacketLength(update, NULL));
1258 : }
1259 :
1260 3 : size_t SX128x::getPacketLength(bool update, uint8_t* offset) {
1261 : (void)update;
1262 :
1263 : // in implicit mode, return the cached value
1264 3 : if((getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_LORA) && (this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT)) {
1265 0 : return(this->payloadLen);
1266 : }
1267 :
1268 3 : uint8_t rxBufStatus[2] = {0, 0};
1269 3 : this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2);
1270 :
1271 3 : if(offset) { *offset = rxBufStatus[1]; }
1272 :
1273 3 : return((size_t)rxBufStatus[0]);
1274 : }
1275 :
1276 0 : int16_t SX128x::getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC) {
1277 0 : int16_t state = RADIOLIB_ERR_NONE;
1278 :
1279 : // check if in explicit header mode
1280 0 : if(this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) {
1281 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1282 : }
1283 :
1284 0 : if(cr) { *cr = this->mod->SPIgetRegValue(RADIOLIB_SX128X_REG_LORA_RX_CODING_RATE, 6, 4) >> 4; }
1285 0 : if(hasCRC) { *hasCRC = (this->mod->SPIgetRegValue(RADIOLIB_SX128X_REG_FEI_MSB, 4, 4) != 0); }
1286 :
1287 0 : return(state);
1288 : }
1289 :
1290 0 : int16_t SX128x::fixedPacketLengthMode(uint8_t len) {
1291 0 : return(setPacketMode(RADIOLIB_SX128X_GFSK_FLRC_PACKET_FIXED, len));
1292 : }
1293 :
1294 0 : int16_t SX128x::variablePacketLengthMode(uint8_t maxLen) {
1295 0 : return(setPacketMode(RADIOLIB_SX128X_GFSK_FLRC_PACKET_VARIABLE, maxLen));
1296 : }
1297 :
1298 13 : RadioLibTime_t SX128x::calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) {
1299 13 : switch(modem) {
1300 6 : case (ModemType_t::RADIOLIB_MODEM_LORA): {
1301 : // calculate number of symbols
1302 6 : float N_symbol = 0;
1303 6 : uint8_t sf = dr.lora.spreadingFactor;
1304 6 : float cr = (float)dr.lora.codingRate;
1305 :
1306 : // get SF coefficients
1307 6 : float coeff1 = 0;
1308 6 : int16_t coeff2 = 0;
1309 6 : int16_t coeff3 = 0;
1310 6 : if(sf < 7) {
1311 : // SF5, SF6
1312 3 : coeff1 = 6.25;
1313 3 : coeff2 = 4*sf;
1314 3 : coeff3 = 4*sf;
1315 3 : } else if(sf < 11) {
1316 : // SF7. SF8, SF9, SF10
1317 0 : coeff1 = 4.25;
1318 0 : coeff2 = 4*sf + 8;
1319 0 : coeff3 = 4*sf;
1320 : } else {
1321 : // SF11, SF12
1322 3 : coeff1 = 4.25;
1323 3 : coeff2 = 4*sf + 8;
1324 3 : coeff3 = 4*(sf - 2);
1325 : }
1326 :
1327 : // get CRC length
1328 6 : int16_t N_bitCRC = 16;
1329 6 : if(!pc.lora.crcEnabled) {
1330 0 : N_bitCRC = 0;
1331 : }
1332 :
1333 : // get header length
1334 6 : int16_t N_symbolHeader = 20;
1335 6 : if(pc.lora.implicitHeader) {
1336 0 : N_symbolHeader = 0;
1337 : }
1338 :
1339 : // calculate number of LoRa preamble symbols
1340 6 : uint32_t N_symbolPreamble = pc.lora.preambleLength;
1341 :
1342 : // calculate the number of symbols
1343 6 : N_symbol = (float)N_symbolPreamble + coeff1 + 8.0f + ceilf((float)RADIOLIB_MAX((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * cr;
1344 :
1345 : // get time-on-air in us
1346 6 : return(((uint32_t(1) << sf) / dr.lora.bandwidth) * N_symbol * 1000.0f);
1347 : }
1348 4 : case (ModemType_t::RADIOLIB_MODEM_FSK):
1349 4 : return((((float)(pc.fsk.crcLength * 8) + pc.fsk.syncWordLength + pc.fsk.preambleLength + (uint32_t)len * 8) / (dr.fsk.bitRate / 1000.0f)));
1350 :
1351 3 : default:
1352 3 : return(RADIOLIB_ERR_WRONG_MODEM);
1353 : }
1354 :
1355 : }
1356 :
1357 3 : RadioLibTime_t SX128x::getTimeOnAir(size_t len) {
1358 : // check active modem
1359 3 : uint8_t modem = getPacketType();
1360 3 : DataRate_t dr = {};
1361 3 : PacketConfig_t pc = {};
1362 :
1363 3 : if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) {
1364 0 : uint8_t sf = this->spreadingFactor >> 4;
1365 0 : uint8_t cr = this->codingRateLoRa;
1366 : // We assume same calculation for short and long interleaving, so map CR values 0-4 and 5-7 to the same values
1367 0 : if (cr < 5) {
1368 0 : cr = cr + 4;
1369 0 : } else if (cr == 7) {
1370 0 : cr = cr + 1;
1371 : }
1372 :
1373 0 : dr.lora.spreadingFactor = sf;
1374 0 : dr.lora.codingRate = cr;
1375 0 : dr.lora.bandwidth = this->bandwidthKhz;
1376 :
1377 0 : uint16_t preambleLength = (this->preambleLengthLoRa & 0x0F) * (uint32_t(1) << ((this->preambleLengthLoRa & 0xF0) >> 4));
1378 :
1379 0 : pc.lora.preambleLength = preambleLength;
1380 0 : pc.lora.implicitHeader = this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT;
1381 0 : pc.lora.crcEnabled = this->crcLoRa == RADIOLIB_SX128X_LORA_CRC_ON;
1382 0 : pc.lora.ldrOptimize = false;
1383 :
1384 0 : return(calculateTimeOnAir(ModemType_t::RADIOLIB_MODEM_LORA, dr, pc, len));
1385 3 : } else if (modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) {
1386 0 : dr.fsk.bitRate = (float)this->bitRateKbps;
1387 0 : dr.fsk.freqDev = this->frequencyDev;
1388 :
1389 0 : pc.fsk.preambleLength = ((uint16_t)this->preambleLengthGFSK >> 2) + 4;
1390 0 : pc.fsk.syncWordLength = ((this->syncWordLen >> 1) + 1) * 8;
1391 0 : pc.fsk.crcLength = this->crcGFSK >> 4;
1392 :
1393 0 : return(calculateTimeOnAir(ModemType_t::RADIOLIB_MODEM_FSK, dr, pc, len));
1394 : } else {
1395 3 : return(RADIOLIB_ERR_WRONG_MODEM);
1396 : }
1397 :
1398 : }
1399 :
1400 3 : RadioLibTime_t SX128x::calculateRxTimeout(RadioLibTime_t timeoutUs) {
1401 : // the timeout value is given in units of 15.625 microseconds
1402 : // the calling function should provide some extra width, as this number of units is truncated to integer
1403 3 : RadioLibTime_t timeout = timeoutUs / 15.625f;
1404 3 : return(timeout);
1405 : }
1406 :
1407 0 : int16_t SX128x::implicitHeader(size_t len) {
1408 0 : return(setHeaderType(RADIOLIB_SX128X_LORA_HEADER_IMPLICIT, len));
1409 : }
1410 :
1411 0 : int16_t SX128x::explicitHeader() {
1412 0 : return(setHeaderType(RADIOLIB_SX128X_LORA_HEADER_EXPLICIT));
1413 : }
1414 :
1415 3 : int16_t SX128x::setEncoding(uint8_t encoding) {
1416 3 : return(setWhitening(encoding));
1417 : }
1418 :
1419 0 : void SX128x::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) {
1420 0 : this->mod->setRfSwitchPins(rxEn, txEn);
1421 0 : }
1422 :
1423 0 : void SX128x::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) {
1424 0 : this->mod->setRfSwitchTable(pins, table);
1425 0 : }
1426 :
1427 3 : uint8_t SX128x::randomByte() {
1428 : // it's unclear whether SX128x can measure RSSI while not receiving a packet
1429 : // this method is implemented only for PhysicalLayer compatibility
1430 3 : return(0);
1431 : }
1432 :
1433 3 : int16_t SX128x::invertIQ(bool enable) {
1434 3 : if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) {
1435 3 : return(RADIOLIB_ERR_WRONG_MODEM);
1436 : }
1437 :
1438 0 : if(enable) {
1439 0 : this->invertIQEnabled = RADIOLIB_SX128X_LORA_IQ_INVERTED;
1440 : } else {
1441 0 : this->invertIQEnabled = RADIOLIB_SX128X_LORA_IQ_STANDARD;
1442 : }
1443 :
1444 0 : return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled));
1445 : }
1446 :
1447 12 : int16_t SX128x::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) {
1448 : int16_t state;
1449 :
1450 12 : switch(mode) {
1451 9 : case(RADIOLIB_RADIO_MODE_RX): {
1452 : // in implicit header mode, use the provided length if it is nonzero
1453 : // otherwise we trust the user has previously set the payload length manually
1454 9 : if((this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) && (cfg->receive.len != 0)) {
1455 0 : this->payloadLen = cfg->receive.len;
1456 : }
1457 :
1458 : // check active modem
1459 9 : if(getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_RANGING) {
1460 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1461 : }
1462 :
1463 : // set DIO mapping
1464 9 : if(cfg->receive.timeout != RADIOLIB_SX128X_RX_TIMEOUT_INF) {
1465 6 : cfg->receive.irqMask |= (1UL << RADIOLIB_IRQ_TIMEOUT);
1466 : }
1467 :
1468 9 : state = setDioIrqParams(getIrqMapped(cfg->receive.irqFlags), getIrqMapped(cfg->receive.irqMask));
1469 9 : RADIOLIB_ASSERT(state);
1470 :
1471 : // set buffer pointers
1472 0 : state = setBufferBaseAddress();
1473 0 : RADIOLIB_ASSERT(state);
1474 :
1475 : // clear interrupt flags
1476 0 : state = clearIrqStatus();
1477 0 : RADIOLIB_ASSERT(state);
1478 :
1479 : // set implicit mode and expected len if applicable
1480 0 : if((this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_LORA)) {
1481 0 : state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled);
1482 0 : RADIOLIB_ASSERT(state);
1483 : }
1484 : // if max(uint32_t) is used, revert to RxContinuous
1485 0 : if(cfg->receive.timeout == 0xFFFFFFFF) {
1486 0 : cfg->receive.timeout = 0xFFFF;
1487 : }
1488 0 : this->rxTimeout = cfg->receive.timeout;
1489 0 : } break;
1490 :
1491 3 : case(RADIOLIB_RADIO_MODE_TX): {
1492 : // check packet length
1493 3 : if(cfg->transmit.len > RADIOLIB_SX128X_MAX_PACKET_LENGTH) {
1494 0 : return(RADIOLIB_ERR_PACKET_TOO_LONG);
1495 : }
1496 :
1497 : // set packet Length
1498 3 : uint8_t modem = getPacketType();
1499 3 : if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) {
1500 0 : state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, cfg->transmit.len, this->crcLoRa, this->invertIQEnabled);
1501 3 : } else if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC)) {
1502 0 : state = setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, this->packetType, cfg->transmit.len);
1503 3 : } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) {
1504 0 : state = setPacketParamsBLE(this->connectionState, this->crcBLE, this->bleTestPayload, this->whitening);
1505 : } else {
1506 3 : return(RADIOLIB_ERR_WRONG_MODEM);
1507 : }
1508 0 : RADIOLIB_ASSERT(state);
1509 :
1510 : // update output power
1511 0 : state = setTxParams(this->power);
1512 0 : RADIOLIB_ASSERT(state);
1513 :
1514 : // set buffer pointers
1515 0 : state = setBufferBaseAddress();
1516 0 : RADIOLIB_ASSERT(state);
1517 :
1518 : // write packet to buffer
1519 0 : if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) {
1520 : // first 2 bytes of BLE payload are PDU header
1521 0 : state = writeBuffer(cfg->transmit.data, cfg->transmit.len, 2);
1522 0 : RADIOLIB_ASSERT(state);
1523 : } else {
1524 0 : state = writeBuffer(cfg->transmit.data, cfg->transmit.len);
1525 0 : RADIOLIB_ASSERT(state);
1526 : }
1527 :
1528 : // set DIO mapping
1529 0 : state = setDioIrqParams(RADIOLIB_SX128X_IRQ_TX_DONE | RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT, RADIOLIB_SX128X_IRQ_TX_DONE);
1530 0 : RADIOLIB_ASSERT(state);
1531 :
1532 : // clear interrupt flags
1533 0 : state = clearIrqStatus();
1534 0 : RADIOLIB_ASSERT(state);
1535 0 : } break;
1536 :
1537 0 : default:
1538 0 : return(RADIOLIB_ERR_UNSUPPORTED);
1539 : }
1540 :
1541 0 : this->stagedMode = mode;
1542 0 : return(state);
1543 : }
1544 :
1545 3 : int16_t SX128x::launchMode() {
1546 : int16_t state;
1547 3 : switch(this->stagedMode) {
1548 3 : case(RADIOLIB_RADIO_MODE_RX): {
1549 3 : this->mod->setRfSwitchState(Module::MODE_RX);
1550 3 : state = setRx(this->rxTimeout);
1551 3 : RADIOLIB_ASSERT(state);
1552 0 : } break;
1553 :
1554 0 : case(RADIOLIB_RADIO_MODE_TX): {
1555 0 : this->mod->setRfSwitchState(Module::MODE_TX);
1556 0 : state = setTx(RADIOLIB_SX128X_TX_TIMEOUT_NONE);
1557 0 : RADIOLIB_ASSERT(state);
1558 :
1559 : // wait for BUSY to go low (= PA ramp up done)
1560 0 : while(this->mod->hal->digitalRead(this->mod->getGpio())) {
1561 0 : this->mod->hal->yield();
1562 : }
1563 0 : } break;
1564 :
1565 0 : default:
1566 0 : return(RADIOLIB_ERR_UNSUPPORTED);
1567 : }
1568 :
1569 0 : this->stagedMode = RADIOLIB_RADIO_MODE_NONE;
1570 0 : return(state);
1571 : }
1572 :
1573 : #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE
1574 0 : void SX128x::setDirectAction(void (*func)(void)) {
1575 : // SX128x is unable to perform direct mode reception
1576 : // this method is implemented only for PhysicalLayer compatibility
1577 : (void)func;
1578 0 : }
1579 :
1580 0 : void SX128x::readBit(uint32_t pin) {
1581 : // SX128x is unable to perform direct mode reception
1582 : // this method is implemented only for PhysicalLayer compatibility
1583 : (void)pin;
1584 0 : }
1585 : #endif
1586 :
1587 0 : Module* SX128x::getMod() {
1588 0 : return(this->mod);
1589 : }
1590 :
1591 0 : int16_t SX128x::modSetup(uint8_t modem) {
1592 : // set module properties
1593 0 : this->mod->init();
1594 0 : this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
1595 0 : this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput);
1596 0 : this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16;
1597 0 : this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8;
1598 0 : this->mod->spiConfig.statusPos = 1;
1599 0 : this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX128X_CMD_READ_REGISTER;
1600 0 : this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX128X_CMD_WRITE_REGISTER;
1601 0 : this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX128X_CMD_NOP;
1602 0 : this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX128X_CMD_GET_STATUS;
1603 0 : this->mod->spiConfig.stream = true;
1604 0 : this->mod->spiConfig.parseStatusCb = SPIparseStatus;
1605 :
1606 : // find the chip - this will also reset the module and verify the module
1607 0 : if(!SX128x::findChip(this->chipType)) {
1608 : RADIOLIB_DEBUG_BASIC_PRINTLN("No SX128x found!");
1609 0 : this->mod->term();
1610 0 : return(RADIOLIB_ERR_CHIP_NOT_FOUND);
1611 : }
1612 : RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x");
1613 :
1614 : // configure settings not accessible by API
1615 0 : return(config(modem));
1616 : }
1617 :
1618 0 : uint8_t SX128x::getStatus() {
1619 0 : uint8_t data = 0;
1620 0 : this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_STATUS, &data, 0);
1621 0 : return(data);
1622 : }
1623 :
1624 0 : int16_t SX128x::writeRegister(uint16_t addr, const uint8_t* data, uint8_t numBytes) {
1625 0 : this->mod->SPIwriteRegisterBurst(addr, data, numBytes);
1626 0 : return(RADIOLIB_ERR_NONE);
1627 : }
1628 :
1629 0 : int16_t SX128x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) {
1630 : // send the command
1631 0 : this->mod->SPIreadRegisterBurst(addr, numBytes, data);
1632 :
1633 : // check the status
1634 0 : int16_t state = this->mod->SPIcheckStream();
1635 0 : return(state);
1636 : }
1637 :
1638 0 : int16_t SX128x::writeBuffer(const uint8_t* data, uint8_t numBytes, uint8_t offset) {
1639 0 : const uint8_t cmd[] = { RADIOLIB_SX128X_CMD_WRITE_BUFFER, offset };
1640 0 : return(this->mod->SPIwriteStream(cmd, 2, data, numBytes));
1641 : }
1642 :
1643 0 : int16_t SX128x::readBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) {
1644 0 : const uint8_t cmd[] = { RADIOLIB_SX128X_CMD_READ_BUFFER, offset };
1645 0 : return(this->mod->SPIreadStream(cmd, 2, data, numBytes));
1646 : }
1647 :
1648 0 : int16_t SX128x::setTx(uint16_t periodBaseCount, uint8_t periodBase) {
1649 0 : const uint8_t data[] = { periodBase, (uint8_t)((periodBaseCount >> 8) & 0xFF), (uint8_t)(periodBaseCount & 0xFF) };
1650 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_TX, data, 3));
1651 : }
1652 :
1653 3 : int16_t SX128x::setRx(uint16_t periodBaseCount, uint8_t periodBase) {
1654 3 : const uint8_t data[] = { periodBase, (uint8_t)((periodBaseCount >> 8) & 0xFF), (uint8_t)(periodBaseCount & 0xFF) };
1655 6 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RX, data, 3));
1656 : }
1657 :
1658 0 : int16_t SX128x::setCad(uint8_t symbolNum) {
1659 : // configure parameters
1660 0 : int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_CAD_PARAMS, &symbolNum, 1);
1661 0 : RADIOLIB_ASSERT(state);
1662 :
1663 : // start CAD
1664 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_CAD, NULL, 0));
1665 : }
1666 :
1667 78 : uint8_t SX128x::getPacketType() {
1668 78 : uint8_t data = 0xFF;
1669 78 : this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_PACKET_TYPE, &data, 1);
1670 78 : return(data);
1671 : }
1672 :
1673 0 : int16_t SX128x::setRfFrequency(uint32_t frf) {
1674 0 : const uint8_t data[] = { (uint8_t)((frf >> 16) & 0xFF), (uint8_t)((frf >> 8) & 0xFF), (uint8_t)(frf & 0xFF) };
1675 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RF_FREQUENCY, data, 3));
1676 : }
1677 :
1678 3 : int16_t SX128x::setTxParams(uint8_t pwr, uint8_t rampTime) {
1679 3 : const uint8_t data[] = { pwr, rampTime };
1680 6 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_TX_PARAMS, data, 2));
1681 : }
1682 :
1683 0 : int16_t SX128x::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) {
1684 0 : const uint8_t data[] = { txBaseAddress, rxBaseAddress };
1685 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2));
1686 : }
1687 :
1688 0 : int16_t SX128x::setModulationParams(uint8_t modParam1, uint8_t modParam2, uint8_t modParam3) {
1689 0 : const uint8_t data[] = { modParam1, modParam2, modParam3 };
1690 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_MODULATION_PARAMS, data, 3));
1691 : }
1692 :
1693 0 : int16_t SX128x::setPacketParamsGFSK(uint8_t preambleLen, uint8_t syncLen, uint8_t syncMatch, uint8_t crcLen, uint8_t whiten, uint8_t hdrType, uint8_t payLen) {
1694 0 : const uint8_t data[] = { preambleLen, syncLen, syncMatch, hdrType, payLen, crcLen, whiten };
1695 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7));
1696 : }
1697 :
1698 0 : int16_t SX128x::setPacketParamsBLE(uint8_t connState, uint8_t crcLen, uint8_t bleTest, uint8_t whiten) {
1699 0 : const uint8_t data[] = { connState, crcLen, bleTest, whiten, 0x00, 0x00, 0x00 };
1700 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7));
1701 : }
1702 :
1703 0 : int16_t SX128x::setPacketParamsLoRa(uint8_t preambleLen, uint8_t hdrType, uint8_t payLen, uint8_t crc, uint8_t invIQ) {
1704 0 : const uint8_t data[] = { preambleLen, hdrType, payLen, crc, invIQ, 0x00, 0x00 };
1705 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7));
1706 : }
1707 :
1708 12 : int16_t SX128x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) {
1709 12 : const uint8_t data[] = { (uint8_t)((irqMask >> 8) & 0xFF), (uint8_t)(irqMask & 0xFF),
1710 12 : (uint8_t)((dio1Mask >> 8) & 0xFF), (uint8_t)(dio1Mask & 0xFF),
1711 12 : (uint8_t)((dio2Mask >> 8) & 0xFF), (uint8_t)(dio2Mask & 0xFF),
1712 12 : (uint8_t)((dio3Mask >> 8) & 0xFF), (uint8_t)(dio3Mask & 0xFF) };
1713 24 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_DIO_IRQ_PARAMS, data, 8));
1714 : }
1715 :
1716 3 : uint16_t SX128x::getIrqStatus() {
1717 3 : uint8_t data[] = { 0x00, 0x00 };
1718 3 : this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_IRQ_STATUS, data, 2);
1719 3 : return(((uint16_t)(data[0]) << 8) | data[1]);
1720 : }
1721 :
1722 6 : int16_t SX128x::clearIrqStatus(uint16_t clearIrqParams) {
1723 6 : const uint8_t data[] = { (uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF) };
1724 12 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_CLEAR_IRQ_STATUS, data, 2));
1725 : }
1726 :
1727 0 : int16_t SX128x::setRangingRole(uint8_t role) {
1728 0 : const uint8_t data[] = { role };
1729 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RANGING_ROLE, data, 1));
1730 : }
1731 :
1732 0 : int16_t SX128x::setPacketType(uint8_t type) {
1733 0 : const uint8_t data[] = { type };
1734 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_TYPE, data, 1));
1735 : }
1736 :
1737 0 : int16_t SX128x::setPacketMode(uint8_t mode, uint8_t len) {
1738 : // check active modem
1739 0 : uint8_t modem = getPacketType();
1740 0 : if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC))) {
1741 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1742 : }
1743 :
1744 : // set requested packet mode
1745 0 : int16_t state = setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, mode, len);
1746 0 : RADIOLIB_ASSERT(state);
1747 :
1748 : // update cached value
1749 0 : this->packetType = mode;
1750 0 : return(state);
1751 : }
1752 :
1753 0 : int16_t SX128x::setHeaderType(uint8_t hdrType, size_t len) {
1754 : // check active modem
1755 0 : uint8_t modem = getPacketType();
1756 0 : if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING))) {
1757 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1758 : }
1759 :
1760 : // update packet parameters
1761 0 : this->headerType = hdrType;
1762 0 : this->payloadLen = len;
1763 0 : return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled));
1764 : }
1765 :
1766 0 : int16_t SX128x::config(uint8_t modem) {
1767 : // reset buffer base address
1768 0 : int16_t state = setBufferBaseAddress();
1769 0 : RADIOLIB_ASSERT(state);
1770 :
1771 : // set modem
1772 : uint8_t data[1];
1773 0 : data[0] = modem;
1774 0 : state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_TYPE, data, 1);
1775 0 : RADIOLIB_ASSERT(state);
1776 :
1777 : // set CAD parameters
1778 0 : data[0] = RADIOLIB_SX128X_CAD_ON_8_SYMB;
1779 0 : state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_CAD_PARAMS, data, 1);
1780 0 : RADIOLIB_ASSERT(state);
1781 :
1782 : // set regulator mode to DC-DC
1783 0 : data[0] = RADIOLIB_SX128X_REGULATOR_DC_DC;
1784 0 : state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_REGULATOR_MODE, data, 1);
1785 0 : RADIOLIB_ASSERT(state);
1786 :
1787 0 : return(RADIOLIB_ERR_NONE);
1788 : }
1789 :
1790 0 : int16_t SX128x::SPIparseStatus(uint8_t in) {
1791 0 : if((in & 0b00011100) == RADIOLIB_SX128X_STATUS_CMD_TIMEOUT) {
1792 0 : return(RADIOLIB_ERR_SPI_CMD_TIMEOUT);
1793 0 : } else if((in & 0b00011100) == RADIOLIB_SX128X_STATUS_CMD_ERROR) {
1794 0 : return(RADIOLIB_ERR_SPI_CMD_INVALID);
1795 0 : } else if((in & 0b00011100) == RADIOLIB_SX128X_STATUS_CMD_FAILED) {
1796 0 : return(RADIOLIB_ERR_SPI_CMD_FAILED);
1797 0 : } else if((in == 0x00) || (in == 0xFF)) {
1798 0 : return(RADIOLIB_ERR_CHIP_NOT_FOUND);
1799 : }
1800 0 : return(RADIOLIB_ERR_NONE);
1801 : }
1802 :
1803 0 : bool SX128x::findChip(const char* verStr) {
1804 0 : uint8_t i = 0;
1805 0 : bool flagFound = false;
1806 0 : while((i < 10) && !flagFound) {
1807 : // reset the module
1808 0 : reset(true);
1809 :
1810 : // read the version string
1811 0 : char version[16] = { 0 };
1812 0 : this->mod->SPIreadRegisterBurst(RADIOLIB_SX128X_REG_VERSION_STRING, 16, reinterpret_cast<uint8_t*>(version));
1813 :
1814 : // check version register
1815 0 : if(strncmp(verStr, version, 6) == 0) {
1816 : RADIOLIB_DEBUG_BASIC_PRINTLN("Found SX128x: RADIOLIB_SX128X_REG_VERSION_STRING:");
1817 : RADIOLIB_DEBUG_BASIC_HEXDUMP(reinterpret_cast<uint8_t*>(version), 16, RADIOLIB_SX128X_REG_VERSION_STRING);
1818 : RADIOLIB_DEBUG_BASIC_PRINTLN();
1819 0 : flagFound = true;
1820 : } else {
1821 : #if RADIOLIB_DEBUG_BASIC
1822 : RADIOLIB_DEBUG_BASIC_PRINTLN("SX128x not found! (%d of 10 tries) RADIOLIB_SX128X_REG_VERSION_STRING:", i + 1);
1823 : RADIOLIB_DEBUG_BASIC_HEXDUMP(reinterpret_cast<uint8_t*>(version), 16, RADIOLIB_SX128X_REG_VERSION_STRING);
1824 : RADIOLIB_DEBUG_BASIC_PRINTLN("Expected string: %s", verStr);
1825 : #endif
1826 0 : this->mod->hal->delay(10);
1827 0 : i++;
1828 : }
1829 : }
1830 :
1831 0 : return(flagFound);
1832 : }
1833 :
1834 : #endif
|