Line data Source code
1 : #include "LR11x0.h"
2 :
3 : #include <math.h>
4 : #include <string.h>
5 :
6 : #if !RADIOLIB_EXCLUDE_LR11X0
7 :
8 16 : LR11x0::LR11x0(Module* mod) : LRxxxx(mod) {
9 16 : this->freqStep = RADIOLIB_LR11X0_FREQUENCY_STEP_SIZE;
10 16 : this->maxPacketLength = RADIOLIB_LR11X0_MAX_PACKET_LENGTH;
11 16 : this->implicitLen = RADIOLIB_LR11X0_MAX_PACKET_LENGTH;
12 16 : this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_LR11X0_IRQ_TX_DONE;
13 16 : this->irqMap[RADIOLIB_IRQ_RX_DONE] = RADIOLIB_LR11X0_IRQ_RX_DONE;
14 16 : this->irqMap[RADIOLIB_IRQ_PREAMBLE_DETECTED] = RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED;
15 16 : this->irqMap[RADIOLIB_IRQ_SYNC_WORD_VALID] = RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID;
16 16 : this->irqMap[RADIOLIB_IRQ_HEADER_VALID] = RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID;
17 16 : this->irqMap[RADIOLIB_IRQ_HEADER_ERR] = RADIOLIB_LR11X0_IRQ_HEADER_ERR;
18 16 : this->irqMap[RADIOLIB_IRQ_CRC_ERR] = RADIOLIB_LR11X0_IRQ_CRC_ERR;
19 16 : this->irqMap[RADIOLIB_IRQ_CAD_DONE] = RADIOLIB_LR11X0_IRQ_CAD_DONE;
20 16 : this->irqMap[RADIOLIB_IRQ_CAD_DETECTED] = RADIOLIB_LR11X0_IRQ_CAD_DETECTED;
21 16 : this->irqMap[RADIOLIB_IRQ_TIMEOUT] = RADIOLIB_LR11X0_IRQ_TIMEOUT;
22 16 : }
23 :
24 0 : int16_t LR11x0::begin(uint32_t bw, uint8_t sf, uint8_t cr, uint8_t syncWord, uint16_t preambleLength, bool high) {
25 : // set module properties and perform initial setup
26 0 : int16_t state = this->modSetup(RADIOLIB_LR11X0_PACKET_TYPE_LORA);
27 0 : RADIOLIB_ASSERT(state);
28 :
29 : // configure publicly accessible settings
30 0 : state = setBandwidth(bw, high);
31 0 : RADIOLIB_ASSERT(state);
32 :
33 0 : state = setSpreadingFactor(sf);
34 0 : RADIOLIB_ASSERT(state);
35 :
36 0 : state = setCodingRate(cr);
37 0 : RADIOLIB_ASSERT(state);
38 :
39 0 : state = setSyncWord(syncWord);
40 0 : RADIOLIB_ASSERT(state);
41 :
42 0 : state = setPreambleLength(preambleLength);
43 0 : RADIOLIB_ASSERT(state);
44 :
45 : // set publicly accessible settings that are not a part of begin method
46 0 : state = setCRC(2);
47 0 : RADIOLIB_ASSERT(state);
48 :
49 0 : state = invertIQ(false);
50 0 : RADIOLIB_ASSERT(state);
51 :
52 0 : state = setRegulatorLDO();
53 0 : RADIOLIB_ASSERT(state);
54 :
55 0 : return(RADIOLIB_ERR_NONE);
56 : }
57 :
58 0 : int16_t LR11x0::beginGFSK(uint32_t br, uint32_t freqDev, uint32_t rxBw, uint16_t preambleLength) {
59 : // set module properties and perform initial setup
60 0 : int16_t state = this->modSetup(RADIOLIB_LR11X0_PACKET_TYPE_GFSK);
61 0 : RADIOLIB_ASSERT(state);
62 :
63 : // configure publicly accessible settings
64 0 : state = setBitRate(br);
65 0 : RADIOLIB_ASSERT(state);
66 :
67 0 : state = setFrequencyDeviation(freqDev);
68 0 : RADIOLIB_ASSERT(state);
69 :
70 0 : state = setRxBandwidth(rxBw);
71 0 : RADIOLIB_ASSERT(state);
72 :
73 0 : state = setPreambleLength(preambleLength);
74 0 : RADIOLIB_ASSERT(state);
75 :
76 : // set publicly accessible settings that are not a part of begin method
77 0 : uint8_t sync[] = { 0x12, 0xAD };
78 0 : state = setSyncWord(sync, 2);
79 0 : RADIOLIB_ASSERT(state);
80 :
81 0 : state = setDataShaping(RADIOLIB_SHAPING_NONE);
82 0 : RADIOLIB_ASSERT(state);
83 :
84 0 : state = setEncoding(RADIOLIB_ENCODING_NRZ);
85 0 : RADIOLIB_ASSERT(state);
86 :
87 0 : state = variablePacketLengthMode(RADIOLIB_LR11X0_MAX_PACKET_LENGTH);
88 0 : RADIOLIB_ASSERT(state);
89 :
90 0 : state = setCRC(2);
91 0 : RADIOLIB_ASSERT(state);
92 :
93 0 : state = setRegulatorLDO();
94 0 : RADIOLIB_ASSERT(state);
95 :
96 0 : return(RADIOLIB_ERR_NONE);
97 : }
98 :
99 0 : int16_t LR11x0::beginLRFHSS(uint8_t bw, uint8_t cr, bool narrowGrid) {
100 : // set module properties and perform initial setup
101 0 : int16_t state = this->modSetup(RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS);
102 0 : RADIOLIB_ASSERT(state);
103 :
104 : // configure publicly accessible settings
105 0 : state = setLrFhssConfig(bw, cr, narrowGrid);
106 0 : RADIOLIB_ASSERT(state);
107 :
108 0 : uint8_t syncWord[] = { 0x12, 0xAD, 0x10, 0x1B };
109 0 : state = setSyncWord(syncWord, 4);
110 0 : RADIOLIB_ASSERT(state);
111 :
112 0 : state = setRegulatorLDO();
113 0 : RADIOLIB_ASSERT(state);
114 :
115 : // set fixed configuration
116 0 : return(setModulationParamsLrFhss(RADIOLIB_LRXXXX_LR_FHSS_BIT_RATE_RAW, RADIOLIB_LR11X0_LR_FHSS_SHAPING_GAUSSIAN_BT_1_0));
117 : }
118 :
119 0 : int16_t LR11x0::beginGNSS(uint8_t constellations) {
120 : // set module properties and perform initial setup - packet type does not matter
121 0 : int16_t state = this->modSetup(RADIOLIB_LR11X0_PACKET_TYPE_LORA);
122 0 : RADIOLIB_ASSERT(state);
123 :
124 0 : state = this->clearErrors();
125 0 : RADIOLIB_ASSERT(state);
126 :
127 : // set GNSS flag to reserve DIO11 for LF clock
128 0 : this->gnss = true;
129 0 : state = this->configLfClock(RADIOLIB_LR11X0_LF_BUSY_RELEASE_DISABLED | RADIOLIB_LR11X0_LF_CLK_XOSC);
130 0 : RADIOLIB_ASSERT(state);
131 :
132 0 : uint16_t errs = 0;
133 0 : state = this->getErrors(&errs);
134 0 : RADIOLIB_ASSERT(state);
135 0 : if(errs & 0x40) {
136 : RADIOLIB_DEBUG_BASIC_PRINTLN("LF_XOSC_START_ERR");
137 0 : return(RADIOLIB_ERR_SPI_CMD_FAILED);
138 : }
139 :
140 0 : state = this->gnssSetConstellationToUse(constellations);
141 0 : RADIOLIB_ASSERT(state);
142 :
143 0 : state = setRegulatorLDO();
144 0 : RADIOLIB_ASSERT(state);
145 :
146 0 : return(RADIOLIB_ERR_NONE);
147 : }
148 :
149 3 : int16_t LR11x0::transmit(const uint8_t* data, size_t len, uint8_t addr) {
150 : // set mode to standby
151 3 : int16_t state = standby();
152 3 : RADIOLIB_ASSERT(state);
153 :
154 : // check packet length
155 0 : if (this->codingRate > RADIOLIB_LR11X0_LORA_CR_4_8_SHORT) {
156 : // Long Interleaver needs at least 8 bytes
157 0 : if(len < 8) {
158 0 : return(RADIOLIB_ERR_PACKET_TOO_SHORT);
159 : }
160 :
161 : // Long Interleaver supports up to 253 bytes if CRC is enabled
162 0 : if (this->crcTypeLoRa == RADIOLIB_LRXXXX_LORA_CRC_ENABLED && (len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH - 2)) {
163 0 : return(RADIOLIB_ERR_PACKET_TOO_LONG);
164 : }
165 : }
166 0 : if(len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH) {
167 0 : return(RADIOLIB_ERR_PACKET_TOO_LONG);
168 : }
169 :
170 : // get currently active modem
171 0 : uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
172 0 : state = getPacketType(&modem);
173 0 : RADIOLIB_ASSERT(state);
174 0 : RadioLibTime_t timeout = getTimeOnAir(len);
175 0 : if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
176 : // calculate timeout (150% of expected time-on-air)
177 0 : timeout = (timeout * 3) / 2;
178 :
179 0 : } else if((modem == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) || (modem == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS)) {
180 : // calculate timeout (500% of expected time-on-air)
181 0 : timeout = timeout * 5;
182 :
183 : } else {
184 0 : return(RADIOLIB_ERR_UNKNOWN);
185 : }
186 :
187 : RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout);
188 :
189 : // start transmission
190 0 : state = startTransmit(data, len, addr);
191 0 : RADIOLIB_ASSERT(state);
192 :
193 : // wait for packet transmission or timeout
194 0 : RadioLibTime_t start = this->mod->hal->micros();
195 0 : while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
196 0 : this->mod->hal->yield();
197 0 : if(this->mod->hal->micros() - start > timeout) {
198 0 : finishTransmit();
199 0 : return(RADIOLIB_ERR_TX_TIMEOUT);
200 : }
201 : }
202 :
203 0 : return(finishTransmit());
204 : }
205 :
206 3 : int16_t LR11x0::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) {
207 : // set mode to standby
208 3 : int16_t state = standby();
209 3 : RADIOLIB_ASSERT(state);
210 :
211 : // calculate timeout based on the configured modem
212 0 : RadioLibTime_t timeoutInternal = timeout;
213 0 : if(!timeoutInternal) {
214 : // get currently active modem
215 0 : uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
216 0 : state = getPacketType(&modem);
217 0 : RADIOLIB_ASSERT(state);
218 0 : if((modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) || (modem == RADIOLIB_LR11X0_PACKET_TYPE_GFSK)) {
219 : // calculate timeout (500 % of expected time-one-air)
220 0 : size_t maxLen = len;
221 0 : if(len == 0) { maxLen = RADIOLIB_LR11X0_MAX_PACKET_LENGTH; }
222 0 : timeoutInternal = (getTimeOnAir(maxLen) * 5) / 1000;
223 :
224 0 : } else if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) {
225 : // this modem cannot receive
226 0 : return(RADIOLIB_ERR_WRONG_MODEM);
227 :
228 : } else {
229 0 : return(RADIOLIB_ERR_UNKNOWN);
230 :
231 : }
232 : }
233 :
234 : RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeoutInternal);
235 :
236 : // start reception
237 0 : uint32_t timeoutValue = (uint32_t)((float)timeoutInternal * (1000.0f / 30.52f));
238 : // or can be: timeoutValue = (uint32_t) (((uint64_t) timeoutInternal * 34360) >> 20);
239 0 : state = startReceive(timeoutValue);
240 0 : RADIOLIB_ASSERT(state);
241 :
242 : // wait for packet reception or timeout
243 0 : bool softTimeout = false;
244 0 : RadioLibTime_t start = this->mod->hal->millis();
245 0 : while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
246 0 : this->mod->hal->yield();
247 : // safety check, the timeout should be done by the radio
248 0 : if(this->mod->hal->millis() - start > timeoutInternal) {
249 0 : softTimeout = true;
250 0 : break;
251 : }
252 : }
253 :
254 : // if it was a timeout, this will return an error code
255 : // TODO taken from SX126x, does this really work?
256 0 : state = standby();
257 0 : if((state != RADIOLIB_ERR_NONE) && (state != RADIOLIB_ERR_SPI_CMD_TIMEOUT)) {
258 0 : return(state);
259 : }
260 :
261 : // check whether this was a timeout or not
262 0 : if(softTimeout || (getIrqFlags() & this->irqMap[RADIOLIB_IRQ_TIMEOUT])) {
263 0 : (void)finishReceive();
264 0 : return(RADIOLIB_ERR_RX_TIMEOUT);
265 : }
266 :
267 : // read the received data
268 0 : return(readData(data, len));
269 : }
270 :
271 3 : int16_t LR11x0::transmitDirect(uint32_t frf) {
272 : // set RF switch (if present)
273 3 : this->mod->setRfSwitchState(this->txMode);
274 :
275 : // user requested to start transmitting immediately (required for RTTY)
276 3 : int16_t state = RADIOLIB_ERR_NONE;
277 3 : if(frf != 0) {
278 0 : state = setRfFrequency(frf);
279 : }
280 3 : RADIOLIB_ASSERT(state);
281 :
282 : // start transmitting
283 3 : return(setTxCw());
284 : }
285 :
286 3 : int16_t LR11x0::receiveDirect() {
287 : // set RF switch (if present)
288 3 : this->mod->setRfSwitchState(Module::MODE_RX);
289 :
290 : // LR11x0 is unable to output received data directly
291 3 : return(RADIOLIB_ERR_UNKNOWN);
292 : }
293 :
294 3 : int16_t LR11x0::scanChannel() {
295 3 : ChannelScanConfig_t cfg = {
296 : .cad = {
297 : .symNum = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT,
298 : .detPeak = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT,
299 : .detMin = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT,
300 : .exitMode = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT,
301 : .rxTimeout = 0,
302 : .rxSymbols = 0,
303 : .irqFlags = RADIOLIB_IRQ_CAD_DEFAULT_FLAGS,
304 : .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK,
305 : },
306 : };
307 6 : return(this->scanChannel(cfg));
308 : }
309 :
310 6 : int16_t LR11x0::scanChannel(const ChannelScanConfig_t &config) {
311 : // set mode to CAD
312 6 : int state = startChannelScan(config);
313 6 : RADIOLIB_ASSERT(state);
314 :
315 : // wait for channel activity detected or timeout
316 0 : while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
317 0 : this->mod->hal->yield();
318 : }
319 :
320 : // check CAD result
321 0 : return(getChannelScanResult());
322 : }
323 :
324 12 : int16_t LR11x0::standby() {
325 12 : return(LR11x0::standby(this->standbyXOSC ? RADIOLIB_LR11X0_STANDBY_XOSC : RADIOLIB_LR11X0_STANDBY_RC));
326 : }
327 :
328 15 : int16_t LR11x0::standby(uint8_t mode) {
329 15 : return(LR11x0::standby(mode, true));
330 : }
331 :
332 15 : int16_t LR11x0::standby(uint8_t mode, bool wakeup) {
333 : // set RF switch (if present)
334 15 : this->mod->setRfSwitchState(Module::MODE_IDLE);
335 :
336 15 : if(wakeup) {
337 : // send a NOP command - this pulls the NSS low to exit the sleep mode,
338 : // while preventing interference with possible other SPI transactions
339 15 : (void)this->mod->SPIwriteStream((uint16_t)RADIOLIB_LR11X0_CMD_NOP, NULL, 0, false, false);
340 : }
341 :
342 15 : uint8_t buff[] = { mode };
343 30 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_STANDBY, true, buff, 1));
344 : }
345 :
346 3 : int16_t LR11x0::sleep() {
347 3 : return(LR11x0::sleep(true, 0));
348 : }
349 :
350 3 : int16_t LR11x0::sleep(bool retainConfig, uint32_t sleepTime) {
351 : // set RF switch (if present)
352 3 : this->mod->setRfSwitchState(Module::MODE_IDLE);
353 :
354 : uint8_t buff[] = {
355 3 : (uint8_t)retainConfig,
356 3 : (uint8_t)((sleepTime >> 24) & 0xFF), (uint8_t)((sleepTime >> 16) & 0xFF),
357 3 : (uint8_t)((sleepTime >> 16) & 0xFF), (uint8_t)(sleepTime & 0xFF),
358 3 : };
359 3 : if(sleepTime) {
360 0 : buff[0] |= RADIOLIB_LR11X0_SLEEP_WAKEUP_ENABLED;
361 : }
362 :
363 : // in sleep, the busy line will remain high, so we have to use this method to disable waiting for it to go low
364 3 : int16_t state = this->mod->SPIwriteStream(RADIOLIB_LR11X0_CMD_SET_SLEEP, buff, sizeof(buff), false, false);
365 :
366 : // wait for the module to safely enter sleep mode
367 3 : this->mod->hal->delay(1);
368 :
369 3 : return(state);
370 : }
371 :
372 3 : int16_t LR11x0::startReceive() {
373 3 : return(this->startReceive(RADIOLIB_LR11X0_RX_TIMEOUT_INF, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0));
374 : }
375 :
376 0 : int16_t LR11x0::startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask) {
377 : // datasheet claims time to go to sleep is ~500us, same to wake up, compensate for that with 1 ms + TCXO delay
378 0 : uint32_t transitionTime = this->tcxoDelay + 1000;
379 0 : sleepPeriod -= transitionTime;
380 :
381 : // divide by 30.517 microseconds (RTC period, 1/32.768 kHz)
382 0 : uint32_t rxPeriodRaw = (uint32_t)(((uint64_t)rxPeriod * 512UL) / 15625UL);
383 0 : uint32_t sleepPeriodRaw = (uint32_t)(((uint64_t)sleepPeriod * 512UL) / 15625UL);
384 :
385 : // check 24 bit limit and zero value (likely not intended)
386 0 : if((rxPeriodRaw & 0xFF000000) || (rxPeriodRaw == 0)) {
387 0 : return(RADIOLIB_ERR_INVALID_RX_PERIOD);
388 : }
389 :
390 : // this check of the high byte also catches underflow when we subtracted transitionTime
391 0 : if((sleepPeriodRaw & 0xFF000000) || (sleepPeriodRaw == 0)) {
392 0 : return(RADIOLIB_ERR_INVALID_SLEEP_PERIOD);
393 : }
394 :
395 : // set up Rx mode
396 0 : RadioModeConfig_t cfg = {
397 : .receive = {
398 : .timeout = RADIOLIB_LR11X0_RX_TIMEOUT_INF,
399 : .syncSymbols = 0,
400 : .irqFlags = irqFlags,
401 : .irqMask = irqMask,
402 : .len = 0,
403 : }
404 0 : };
405 0 : int16_t state = this->stageMode(RADIOLIB_RADIO_MODE_RX, &cfg);
406 0 : RADIOLIB_ASSERT(state);
407 :
408 0 : return(this->setRxDutyCycle(rxPeriodRaw, sleepPeriodRaw, RADIOLIB_LR11X0_RX_DUTY_CYCLE_MODE_RX));
409 : }
410 :
411 0 : int16_t LR11x0::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_t minSymbols, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask) {
412 : // calculate the sleep and wake periods
413 0 : uint32_t wakePeriod = 0;
414 0 : uint32_t sleepPeriod = 0;
415 : DataRate_t dr = {
416 : .lora = {
417 0 : .spreadingFactor = this->spreadingFactor,
418 0 : .bandwidth = this->bandwidthHz,
419 0 : .codingRate = this->codingRate,
420 : }
421 0 : };
422 0 : int16_t state = calculateRxDutyCycle(senderPreambleLength, this->preambleLengthLoRa, minSymbols, &dr, &wakePeriod, &sleepPeriod);
423 0 : RADIOLIB_ASSERT(state);
424 :
425 : // If our sleep period is shorter than our transition time, just use the standard startReceive
426 0 : if(sleepPeriod < this->tcxoDelay + 1016) {
427 0 : return(startReceive(RADIOLIB_LR11X0_RX_TIMEOUT_INF, irqFlags, irqMask));
428 : }
429 :
430 0 : return(startReceiveDutyCycle(wakePeriod, sleepPeriod, irqFlags, irqMask));
431 : }
432 :
433 3 : int16_t LR11x0::readData(uint8_t* data, size_t len) {
434 : // check active modem
435 3 : int16_t state = RADIOLIB_ERR_NONE;
436 3 : uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
437 3 : state = getPacketType(&modem);
438 3 : RADIOLIB_ASSERT(state);
439 0 : if((modem != RADIOLIB_LR11X0_PACKET_TYPE_LORA) &&
440 0 : (modem != RADIOLIB_LR11X0_PACKET_TYPE_GFSK)) {
441 0 : return(RADIOLIB_ERR_WRONG_MODEM);
442 : }
443 :
444 : // check integrity CRC
445 0 : uint32_t irq = getIrqStatus();
446 0 : int16_t crcState = RADIOLIB_ERR_NONE;
447 : // 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)
448 0 : if((irq & RADIOLIB_LR11X0_IRQ_CRC_ERR) || ((irq & RADIOLIB_LR11X0_IRQ_HEADER_ERR) && !(irq & RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID))) {
449 0 : crcState = RADIOLIB_ERR_CRC_MISMATCH;
450 : }
451 :
452 : // get packet length
453 : // the offset is needed since LR11x0 seems to move the buffer base by 4 bytes on every packet
454 0 : uint8_t offset = 0;
455 0 : size_t length = getPacketLength(true, &offset);
456 0 : if((len != 0) && (len < length)) {
457 : // user requested less data than we got, only return what was requested
458 0 : length = len;
459 : }
460 :
461 : // read packet data
462 0 : state = readBuffer8(data, length, offset);
463 0 : RADIOLIB_ASSERT(state);
464 :
465 : // clear the Rx buffer
466 0 : state = clearRxBuffer();
467 0 : RADIOLIB_ASSERT(state);
468 :
469 : // clear interrupt flags
470 0 : state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL);
471 :
472 : // check if CRC failed - this is done after reading data to give user the option to keep them
473 0 : RADIOLIB_ASSERT(crcState);
474 :
475 0 : return(state);
476 : }
477 :
478 3 : int16_t LR11x0::finishReceive() {
479 : // set mode to standby to disable RF switch
480 3 : int16_t state = standby();
481 3 : RADIOLIB_ASSERT(state);
482 :
483 : // clear interrupt flags
484 0 : return(clearIrqState(RADIOLIB_LR11X0_IRQ_ALL));
485 : }
486 :
487 3 : int16_t LR11x0::startChannelScan() {
488 3 : ChannelScanConfig_t cfg = {
489 : .cad = {
490 : .symNum = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT,
491 : .detPeak = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT,
492 : .detMin = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT,
493 : .exitMode = RADIOLIB_LR11X0_CAD_PARAM_DEFAULT,
494 : .rxTimeout = 0,
495 : .rxSymbols = 0,
496 : .irqFlags = RADIOLIB_IRQ_CAD_DEFAULT_FLAGS,
497 : .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK,
498 : },
499 : };
500 6 : return(this->startChannelScan(cfg));
501 : }
502 :
503 12 : int16_t LR11x0::startChannelScan(const ChannelScanConfig_t &cfg) {
504 : // check active modem
505 12 : int16_t state = RADIOLIB_ERR_NONE;
506 12 : uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
507 12 : state = getPacketType(&modem);
508 12 : RADIOLIB_ASSERT(state);
509 0 : if(modem != RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
510 0 : return(RADIOLIB_ERR_WRONG_MODEM);
511 : }
512 :
513 : // set mode to standby
514 0 : state = standby();
515 0 : RADIOLIB_ASSERT(state);
516 :
517 : // set RF switch (if present)
518 0 : this->mod->setRfSwitchState(Module::MODE_RX);
519 :
520 : // set DIO pin mapping
521 0 : uint16_t irqFlags = (cfg.cad.irqFlags == RADIOLIB_IRQ_NOT_SUPPORTED) ? RADIOLIB_LR11X0_IRQ_CAD_DETECTED | RADIOLIB_LR11X0_IRQ_CAD_DONE : cfg.cad.irqFlags;
522 0 : state = setDioIrqParams(getIrqMapped(irqFlags), getIrqMapped(irqFlags));
523 0 : RADIOLIB_ASSERT(state);
524 :
525 : // clear interrupt flags
526 0 : state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL);
527 0 : RADIOLIB_ASSERT(state);
528 :
529 : // set LoRa symbol timeout
530 0 : state = setLoRaSynchTimeout(cfg.cad.rxSymbols);
531 0 : RADIOLIB_ASSERT(state);
532 :
533 : // set mode to CAD
534 0 : return(startCad(cfg.cad.symNum, cfg.cad.detPeak, cfg.cad.detMin, cfg.cad.exitMode, cfg.cad.rxTimeout));
535 : }
536 :
537 3 : int16_t LR11x0::getChannelScanResult() {
538 : // check active modem
539 3 : int16_t state = RADIOLIB_ERR_NONE;
540 3 : uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
541 3 : state = getPacketType(&modem);
542 3 : RADIOLIB_ASSERT(state);
543 0 : if(modem != RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
544 0 : return(RADIOLIB_ERR_WRONG_MODEM);
545 : }
546 :
547 : // check CAD result
548 0 : uint32_t cadResult = getIrqStatus();
549 0 : if(cadResult & RADIOLIB_LR11X0_IRQ_CAD_DETECTED) {
550 : // detected some LoRa activity
551 0 : return(RADIOLIB_LORA_DETECTED);
552 0 : } else if(cadResult & RADIOLIB_LR11X0_IRQ_CAD_DONE) {
553 : // channel is free
554 0 : return(RADIOLIB_CHANNEL_FREE);
555 : }
556 :
557 0 : return(RADIOLIB_ERR_UNKNOWN);
558 : }
559 :
560 3 : int16_t LR11x0::setBandwidth(uint32_t bw) {
561 3 : return(this->setBandwidth(bw, false));
562 : }
563 :
564 3 : int16_t LR11x0::setBandwidth(uint32_t bw, bool high) {
565 : // check active modem
566 3 : uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
567 3 : int16_t state = getPacketType(&type);
568 3 : RADIOLIB_ASSERT(state);
569 0 : if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
570 0 : return(RADIOLIB_ERR_WRONG_MODEM);
571 : }
572 :
573 : // check allowed bandwidth values
574 0 : if(high) {
575 0 : switch(bw) {
576 0 : case(203125):
577 0 : this->bandwidth = RADIOLIB_LR11X0_LORA_BW_203_125;
578 0 : break;
579 0 : case(406250):
580 0 : this->bandwidth = RADIOLIB_LR11X0_LORA_BW_406_25;
581 0 : break;
582 0 : case(812500):
583 0 : this->bandwidth = RADIOLIB_LR11X0_LORA_BW_812_50;
584 0 : break;
585 0 : default:
586 0 : return(RADIOLIB_ERR_INVALID_BANDWIDTH);
587 : }
588 :
589 : } else {
590 0 : switch(bw) {
591 0 : case(62500):
592 0 : this->bandwidth = RADIOLIB_LR11X0_LORA_BW_62_5;
593 0 : break;
594 0 : case(RADIOLIB_UNIT_KILO(125)):
595 0 : this->bandwidth = RADIOLIB_LR11X0_LORA_BW_125_0;
596 0 : break;
597 0 : case(RADIOLIB_UNIT_KILO(250)):
598 0 : this->bandwidth = RADIOLIB_LR11X0_LORA_BW_250_0;
599 0 : break;
600 0 : case(RADIOLIB_UNIT_KILO(500)):
601 0 : this->bandwidth = RADIOLIB_LR11X0_LORA_BW_500_0;
602 0 : break;
603 0 : default:
604 0 : return(RADIOLIB_ERR_INVALID_BANDWIDTH);
605 : }
606 : }
607 :
608 : // update modulation parameters
609 0 : this->bandwidthHz = bw;
610 0 : return(setModulationParamsLoRa(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
611 : }
612 :
613 3 : int16_t LR11x0::setSpreadingFactor(uint8_t sf) {
614 3 : return(this->setSpreadingFactor(sf, false));
615 : }
616 :
617 3 : int16_t LR11x0::setSpreadingFactor(uint8_t sf, bool legacy) {
618 : // check active modem
619 3 : uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
620 3 : int16_t state = getPacketType(&type);
621 3 : RADIOLIB_ASSERT(state);
622 0 : if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
623 0 : return(RADIOLIB_ERR_WRONG_MODEM);
624 : }
625 :
626 0 : RADIOLIB_CHECK_RANGE(sf, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
627 :
628 0 : if(legacy && (sf == 6)) {
629 : // Enable LR1121 SF6 compatibility with SX127x family
630 : // Register 0xF20414: bit18 = 1, bit23 = 0
631 0 : state = this->writeRegMemMask32(RADIOLIB_LR11X0_REG_SF6_SX127X_COMPAT, (0x1UL << 18) | (0x1UL << 23), RADIOLIB_LR11X0_SF6_SX127X);
632 0 : RADIOLIB_ASSERT(state);
633 : }
634 :
635 : // update modulation parameters
636 0 : this->spreadingFactor = sf;
637 0 : return(setModulationParamsLoRa(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
638 : }
639 :
640 3 : int16_t LR11x0::setCodingRate(uint8_t cr, bool longInterleave) {
641 : // check active modem
642 3 : uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
643 3 : int16_t state = getPacketType(&type);
644 3 : RADIOLIB_ASSERT(state);
645 0 : if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
646 0 : return(RADIOLIB_ERR_WRONG_MODEM);
647 : }
648 :
649 0 : RADIOLIB_CHECK_RANGE(cr, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
650 :
651 0 : if(longInterleave) {
652 0 : switch(cr) {
653 0 : case 4:
654 0 : this->codingRate = 0;
655 0 : break;
656 0 : case 5:
657 : case 6:
658 0 : this->codingRate = cr;
659 0 : break;
660 0 : case 8:
661 0 : this->codingRate = cr - 1;
662 0 : break;
663 0 : default:
664 0 : return(RADIOLIB_ERR_INVALID_CODING_RATE);
665 : }
666 :
667 : } else {
668 0 : this->codingRate = cr - 4;
669 :
670 : }
671 :
672 : // update modulation parameters
673 0 : return(setModulationParamsLoRa(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
674 : }
675 :
676 0 : int16_t LR11x0::setSyncWord(uint8_t syncWord) {
677 : // check active modem
678 0 : uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
679 0 : int16_t state = getPacketType(&type);
680 0 : RADIOLIB_ASSERT(state);
681 0 : if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
682 0 : return(RADIOLIB_ERR_WRONG_MODEM);
683 : }
684 :
685 0 : return(setLoRaSyncWord(syncWord));
686 : }
687 :
688 3 : int16_t LR11x0::setBitRate(uint32_t br) {
689 3 : RADIOLIB_CHECK_RANGE(br, 600, RADIOLIB_UNIT_KILO(300), RADIOLIB_ERR_INVALID_BIT_RATE);
690 :
691 : // check active modem
692 0 : uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
693 0 : int16_t state = getPacketType(&type);
694 0 : RADIOLIB_ASSERT(state);
695 0 : if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
696 0 : return(RADIOLIB_ERR_WRONG_MODEM);
697 : }
698 :
699 : // set bit rate value
700 : // TODO implement fractional bit rate configuration
701 0 : this->bitRate = br;
702 0 : state = setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev);
703 0 : RADIOLIB_ASSERT(state);
704 :
705 : // apply workaround
706 0 : return(workaroundGFSK());
707 : }
708 :
709 3 : int16_t LR11x0::setFrequencyDeviation(uint32_t freqDev) {
710 : // check active modem
711 3 : uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
712 3 : int16_t state = getPacketType(&type);
713 3 : RADIOLIB_ASSERT(state);
714 0 : if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
715 0 : return(RADIOLIB_ERR_WRONG_MODEM);
716 : }
717 :
718 : // set frequency deviation to lowest available setting (required for digimodes)
719 0 : uint32_t newFreqDev = freqDev ? freqDev : 600;
720 :
721 0 : RADIOLIB_CHECK_RANGE(newFreqDev, 600, RADIOLIB_UNIT_KILO(200), RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
722 0 : this->frequencyDev = newFreqDev;
723 0 : state = setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev);
724 0 : RADIOLIB_ASSERT(state);
725 :
726 : // apply workaround
727 0 : return(workaroundGFSK());
728 : }
729 :
730 0 : int16_t LR11x0::setRxBandwidth(uint32_t rxBw) {
731 : // check active modem
732 0 : uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
733 0 : int16_t state = getPacketType(&type);
734 0 : RADIOLIB_ASSERT(state);
735 0 : if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
736 0 : return(RADIOLIB_ERR_WRONG_MODEM);
737 : }
738 :
739 : // check modulation parameters
740 : /*if(2 * this->frequencyDev + this->bitRate > rxBw * 1000.0f) {
741 : return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS);
742 : }*/
743 :
744 0 : const uint32_t rxBwAvg[] = {
745 : 5300, 6600, 8500, 10800, 13400, 17000, 21100, 26400,
746 : 34100, 42400, 52900, 68200, 84700, 105800, 136400,
747 : 169500, 211600, 272900, 339000, 423300, 515900,
748 : 611100, 717900, 940100, 1666500, 2444000, 2871000,
749 : };
750 :
751 0 : const uint8_t rxBwLut[] = {
752 : RADIOLIB_LR11X0_GFSK_RX_BW_4_8,
753 : RADIOLIB_LR11X0_GFSK_RX_BW_5_8,
754 : RADIOLIB_LR11X0_GFSK_RX_BW_7_3,
755 : RADIOLIB_LR11X0_GFSK_RX_BW_9_7,
756 : RADIOLIB_LR11X0_GFSK_RX_BW_11_7,
757 : RADIOLIB_LR11X0_GFSK_RX_BW_14_6,
758 : RADIOLIB_LR11X0_GFSK_RX_BW_19_5,
759 : RADIOLIB_LR11X0_GFSK_RX_BW_23_4,
760 : RADIOLIB_LR11X0_GFSK_RX_BW_29_3,
761 : RADIOLIB_LR11X0_GFSK_RX_BW_39_0,
762 : RADIOLIB_LR11X0_GFSK_RX_BW_46_9,
763 : RADIOLIB_LR11X0_GFSK_RX_BW_58_6,
764 : RADIOLIB_LR11X0_GFSK_RX_BW_78_2,
765 : RADIOLIB_LR11X0_GFSK_RX_BW_93_8,
766 : RADIOLIB_LR11X0_GFSK_RX_BW_117_3,
767 : RADIOLIB_LR11X0_GFSK_RX_BW_156_2,
768 : RADIOLIB_LR11X0_GFSK_RX_BW_187_2,
769 : RADIOLIB_LR11X0_GFSK_RX_BW_234_3,
770 : RADIOLIB_LR11X0_GFSK_RX_BW_312_0,
771 : RADIOLIB_LR11X0_GFSK_RX_BW_373_6,
772 : RADIOLIB_LR11X0_GFSK_RX_BW_467_0,
773 : };
774 :
775 0 : state = findRxBw(rxBw, rxBwAvg, rxBwLut, sizeof(rxBwLut)/sizeof(rxBwLut[0]), RADIOLIB_UNIT_KILO(467), &this->rxBandwidth);
776 0 : RADIOLIB_ASSERT(state);
777 :
778 : // update modulation parameters
779 0 : state = setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev);
780 0 : RADIOLIB_ASSERT(state);
781 :
782 : // apply workaround
783 0 : return(workaroundGFSK());
784 : }
785 :
786 3 : int16_t LR11x0::setSyncWord(uint8_t* syncWord, size_t len) {
787 3 : if((!syncWord) || (!len) || (len > RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN)) {
788 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
789 : }
790 :
791 : // check active modem
792 3 : uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
793 3 : int16_t state = getPacketType(&type);
794 3 : RADIOLIB_ASSERT(state);
795 0 : if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
796 : // update sync word length
797 0 : this->syncWordLength = len*8;
798 0 : state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType,
799 0 : (this->packetType == RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_FIXED) ? this->implicitLen : RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
800 0 : RADIOLIB_ASSERT(state);
801 :
802 : // sync word is passed most-significant byte first
803 0 : uint8_t fullSyncWord[RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN] = { 0 };
804 0 : memcpy(fullSyncWord, syncWord, len);
805 0 : return(setGfskSyncWord(fullSyncWord));
806 :
807 0 : } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
808 : // with length set to 1 and LoRa modem active, assume it is the LoRa sync word
809 0 : if(len > 1) {
810 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
811 : }
812 0 : return(setSyncWord(syncWord[0]));
813 :
814 0 : } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) {
815 : // with length set to 4 and LR-FHSS modem active, assume it is the LR-FHSS sync word
816 0 : if(len != sizeof(uint32_t)) {
817 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
818 : }
819 0 : uint32_t sync = 0;
820 0 : memcpy(&sync, syncWord, sizeof(uint32_t));
821 0 : return(lrFhssSetSyncWord(sync));
822 :
823 : }
824 :
825 0 : return(RADIOLIB_ERR_WRONG_MODEM);
826 : }
827 :
828 0 : int16_t LR11x0::setNodeAddress(uint8_t nodeAddr) {
829 : // check active modem
830 0 : uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
831 0 : int16_t state = getPacketType(&type);
832 0 : RADIOLIB_ASSERT(state);
833 0 : if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
834 0 : return(RADIOLIB_ERR_WRONG_MODEM);
835 : }
836 :
837 : // enable address filtering (node only)
838 0 : this->addrComp = RADIOLIB_LR11X0_GFSK_ADDR_FILTER_NODE;
839 0 : state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType,
840 0 : (this->packetType == RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_FIXED) ? this->implicitLen : RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
841 0 : RADIOLIB_ASSERT(state);
842 :
843 : // set node address
844 0 : this->node = nodeAddr;
845 0 : return(setPacketAdrs(this->node, 0));
846 : }
847 :
848 0 : int16_t LR11x0::setBroadcastAddress(uint8_t broadAddr) {
849 : // check active modem
850 0 : uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
851 0 : int16_t state = getPacketType(&type);
852 0 : RADIOLIB_ASSERT(state);
853 0 : if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
854 0 : return(RADIOLIB_ERR_WRONG_MODEM);
855 : }
856 :
857 : // enable address filtering (node and broadcast)
858 0 : this->addrComp = RADIOLIB_LR11X0_GFSK_ADDR_FILTER_NODE_BROADCAST;
859 0 : state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType,
860 0 : (this->packetType == RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_FIXED) ? this->implicitLen : RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
861 0 : RADIOLIB_ASSERT(state);
862 :
863 : // set node and broadcast address
864 0 : return(setPacketAdrs(this->node, broadAddr));
865 : }
866 :
867 0 : int16_t LR11x0::disableAddressFiltering() {
868 : // check active modem
869 0 : uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
870 0 : int16_t state = getPacketType(&type);
871 0 : RADIOLIB_ASSERT(state);
872 0 : if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
873 0 : return(RADIOLIB_ERR_WRONG_MODEM);
874 : }
875 :
876 : // disable address filtering
877 0 : this->addrComp = RADIOLIB_LR11X0_GFSK_ADDR_FILTER_DISABLED;
878 0 : return(setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType,
879 0 : (this->packetType == RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_FIXED) ? this->implicitLen : RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
880 : }
881 :
882 3 : int16_t LR11x0::setDataShaping(uint8_t sh) {
883 : // check active modem
884 3 : uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
885 3 : int16_t state = getPacketType(&type);
886 3 : RADIOLIB_ASSERT(state);
887 0 : if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
888 0 : return(RADIOLIB_ERR_WRONG_MODEM);
889 : }
890 :
891 : // set data shaping
892 0 : switch(sh) {
893 0 : case RADIOLIB_SHAPING_NONE:
894 0 : this->pulseShape = RADIOLIB_LR11X0_GFSK_SHAPING_NONE;
895 0 : break;
896 0 : case RADIOLIB_SHAPING_0_3:
897 0 : this->pulseShape = RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_0_3;
898 0 : break;
899 0 : case RADIOLIB_SHAPING_0_5:
900 0 : this->pulseShape = RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_0_5;
901 0 : break;
902 0 : case RADIOLIB_SHAPING_0_7:
903 0 : this->pulseShape = RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_0_7;
904 0 : break;
905 0 : case RADIOLIB_SHAPING_1_0:
906 0 : this->pulseShape = RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_1_0;
907 0 : break;
908 0 : default:
909 0 : return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
910 : }
911 :
912 : // update modulation parameters
913 0 : return(setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
914 : }
915 :
916 3 : int16_t LR11x0::setEncoding(uint8_t encoding) {
917 3 : return(setWhitening(encoding));
918 : }
919 :
920 0 : int16_t LR11x0::fixedPacketLengthMode(uint8_t len) {
921 0 : return(setPacketMode(RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_FIXED, len));
922 : }
923 :
924 0 : int16_t LR11x0::variablePacketLengthMode(uint8_t maxLen) {
925 0 : return(setPacketMode(RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_VARIABLE, maxLen));
926 : }
927 :
928 3 : int16_t LR11x0::setWhitening(bool enabled, uint16_t initial) {
929 : // check active modem
930 3 : uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
931 3 : int16_t state = getPacketType(&type);
932 3 : RADIOLIB_ASSERT(state);
933 0 : if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
934 0 : return(RADIOLIB_ERR_WRONG_MODEM);
935 : }
936 :
937 0 : if(!enabled) {
938 : // disable whitening
939 0 : this->whitening = RADIOLIB_LR11X0_GFSK_WHITENING_DISABLED;
940 :
941 : } else {
942 : // enable whitening
943 0 : this->whitening = RADIOLIB_LR11X0_GFSK_WHITENING_ENABLED;
944 :
945 : // write initial whitening value
946 0 : state = setGfskWhitParams(initial);
947 0 : RADIOLIB_ASSERT(state);
948 : }
949 :
950 0 : return(setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType,
951 0 : (this->packetType == RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_FIXED) ? this->implicitLen : RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
952 : }
953 :
954 3 : int16_t LR11x0::checkDataRate(DataRate_t dr, ModemType_t modem) {
955 3 : int16_t state = RADIOLIB_ERR_UNKNOWN;
956 :
957 : // retrieve modem if not supplied
958 3 : if(modem == RADIOLIB_MODEM_NONE) {
959 3 : state = this->getModem(&modem);
960 3 : RADIOLIB_ASSERT(state);
961 : }
962 :
963 : // select interpretation based on modem
964 0 : if(modem == RADIOLIB_MODEM_FSK) {
965 0 : RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 600, RADIOLIB_UNIT_KILO(300), RADIOLIB_ERR_INVALID_BIT_RATE);
966 0 : RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 600, RADIOLIB_UNIT_KILO(200), RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
967 0 : return(RADIOLIB_ERR_NONE);
968 :
969 0 : } else if(modem == RADIOLIB_MODEM_LORA) {
970 0 : RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
971 0 : RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 62500, RADIOLIB_UNIT_KILO(500), RADIOLIB_ERR_INVALID_BANDWIDTH);
972 0 : RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
973 0 : return(RADIOLIB_ERR_NONE);
974 :
975 : }
976 :
977 0 : return(state);
978 : }
979 :
980 3 : int16_t LR11x0::setPreambleLength(size_t preambleLength, size_t preambleDetLength) {
981 : // check active modem
982 3 : uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
983 3 : int16_t state = getPacketType(&type);
984 3 : RADIOLIB_ASSERT(state);
985 0 : if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
986 0 : this->preambleLengthLoRa = preambleLength;
987 0 : return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled));
988 0 : } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
989 0 : this->preambleLengthGFSK = preambleLength;
990 0 : this->preambleDetLength = preambleDetLength;
991 :
992 : // if no value is specified for preambleDetLength, use the value best corresponding to preambleLength
993 0 : if(preambleDetLength == 0xFFFFFFFF) {
994 0 : this->preambleDetLength = preambleLength >= 32 ? RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_32_BITS :
995 : preambleLength >= 24 ? RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_24_BITS :
996 : preambleLength >= 16 ? RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_16_BITS :
997 : preambleLength > 0 ? RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_8_BITS :
998 : RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_DISABLED;
999 : }
1000 0 : return(setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType,
1001 0 : (this->packetType == RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_FIXED) ? this->implicitLen : RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
1002 : }
1003 :
1004 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1005 : }
1006 :
1007 0 : int16_t LR11x0::setTCXO(RadioLibTCXOVoltage_t voltage, uint32_t delay) {
1008 : // set mode to standby
1009 : // force RC oscillator - typically this is called on startup,
1010 : // so we cannot rely on what the user may have provided
1011 0 : (void)standby(RADIOLIB_LR11X0_STANDBY_RC);
1012 :
1013 : // check RADIOLIB_LR11X0_ERROR_STAT_HF_XOSC_START_ERR flag and clear it
1014 0 : uint16_t errors = 0;
1015 0 : int16_t state = getErrors(&errors);
1016 0 : RADIOLIB_ASSERT(state);
1017 0 : if(errors & RADIOLIB_LR11X0_ERROR_STAT_HF_XOSC_START_ERR) {
1018 0 : clearErrors();
1019 : }
1020 :
1021 : // check disable
1022 0 : if(voltage == RadioLibTCXOVoltage_t::VoltageNone) {
1023 0 : setTcxoMode(0, 0);
1024 0 : return(reset());
1025 : }
1026 :
1027 : // check allowed voltage values
1028 0 : if(voltage > RadioLibTCXOVoltage_t::Voltage3V3) {
1029 0 : return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE);
1030 : }
1031 :
1032 : // calculate delay value
1033 0 : this->tcxoDelay = delay;
1034 0 : uint32_t delayValue = (uint32_t)((float)delay * (1.0f / 30.52f));
1035 0 : if(delayValue == 0) {
1036 0 : delayValue = 1;
1037 : }
1038 :
1039 : // enable TCXO control
1040 0 : return(setTcxoMode((uint8_t)voltage, delayValue));
1041 : }
1042 :
1043 0 : int16_t LR11x0::setCRC(uint8_t len, uint32_t initial, uint32_t polynomial, bool inverted) {
1044 : // check active modem
1045 0 : uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
1046 0 : int16_t state = getPacketType(&type);
1047 0 : RADIOLIB_ASSERT(state);
1048 0 : if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
1049 : // LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion
1050 0 : this->crcTypeLoRa = len > 0 ? RADIOLIB_LRXXXX_LORA_CRC_ENABLED : RADIOLIB_LRXXXX_LORA_CRC_DISABLED;
1051 0 : state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled);
1052 :
1053 0 : } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
1054 : // update packet parameters
1055 0 : switch(len) {
1056 0 : case 0:
1057 0 : this->crcTypeGFSK = RADIOLIB_LR11X0_GFSK_CRC_DISABLED;
1058 0 : break;
1059 0 : case 1:
1060 0 : if(inverted) {
1061 0 : this->crcTypeGFSK = RADIOLIB_LR11X0_GFSK_CRC_1_BYTE_INV;
1062 : } else {
1063 0 : this->crcTypeGFSK = RADIOLIB_LR11X0_GFSK_CRC_1_BYTE;
1064 : }
1065 0 : break;
1066 0 : case 2:
1067 0 : if(inverted) {
1068 0 : this->crcTypeGFSK = RADIOLIB_LR11X0_GFSK_CRC_2_BYTE_INV;
1069 : } else {
1070 0 : this->crcTypeGFSK = RADIOLIB_LR11X0_GFSK_CRC_2_BYTE;
1071 : }
1072 0 : break;
1073 0 : default:
1074 0 : return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
1075 : }
1076 :
1077 0 : this->crcLenGFSK = len;
1078 0 : state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType,
1079 0 : (this->packetType == RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_FIXED) ? this->implicitLen : RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
1080 0 : RADIOLIB_ASSERT(state);
1081 :
1082 0 : state = setGfskCrcParams(initial, polynomial);
1083 :
1084 : }
1085 :
1086 0 : return(state);
1087 : }
1088 :
1089 3 : int16_t LR11x0::invertIQ(bool enable) {
1090 : // check active modem
1091 3 : uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
1092 3 : int16_t state = getPacketType(&type);
1093 3 : RADIOLIB_ASSERT(state);
1094 0 : if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
1095 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1096 : }
1097 :
1098 0 : this->invertIQEnabled = enable;
1099 0 : return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled));
1100 : }
1101 :
1102 3 : float LR11x0::getRSSI() {
1103 3 : float val = 0;
1104 :
1105 : // check active modem
1106 3 : uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
1107 3 : (void)getPacketType(&type);
1108 3 : if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
1109 0 : (void)getPacketStatusLoRa(&val, NULL, NULL);
1110 :
1111 3 : } else if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
1112 0 : (void)getPacketStatusGFSK(NULL, &val, NULL, NULL);
1113 :
1114 : }
1115 :
1116 3 : return(val);
1117 : }
1118 :
1119 0 : float LR11x0::getRSSI(bool packet, bool skipReceive) {
1120 0 : float val = 0;
1121 :
1122 : // check if RSSI of packet is requested
1123 0 : if (packet) {
1124 0 : val = getRSSI();
1125 : } else {
1126 0 : if(!skipReceive) { (void)startReceive(); }
1127 0 : int16_t state = getRssiInst(&val);
1128 0 : if(!skipReceive) { (void)standby(); }
1129 0 : if(state != RADIOLIB_ERR_NONE) { return(0); }
1130 : }
1131 :
1132 0 : return(val);
1133 : }
1134 :
1135 3 : float LR11x0::getSNR() {
1136 3 : float val = 0;
1137 :
1138 : // check active modem
1139 3 : uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
1140 3 : (void)getPacketType(&type);
1141 3 : if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
1142 0 : (void)getPacketStatusLoRa(NULL, &val, NULL);
1143 : }
1144 :
1145 3 : return(val);
1146 : }
1147 :
1148 0 : float LR11x0::getVoltage() {
1149 : float val;
1150 0 : int16_t state = getVbat(&val);
1151 0 : if(state != RADIOLIB_ERR_NONE) {
1152 0 : return(0);
1153 : }
1154 :
1155 0 : return(val);
1156 : }
1157 :
1158 0 : float LR11x0::getTemperature() {
1159 : float val;
1160 0 : int16_t state = getTemp(&val);
1161 0 : if(state != RADIOLIB_ERR_NONE) {
1162 0 : return(0);
1163 : }
1164 :
1165 0 : return(val);
1166 : }
1167 :
1168 3 : size_t LR11x0::getPacketLength(bool update) {
1169 3 : return(this->getPacketLength(update, NULL));
1170 : }
1171 :
1172 3 : size_t LR11x0::getPacketLength(bool update, uint8_t* offset) {
1173 : (void)update;
1174 :
1175 : // in implicit mode, return the cached value if the offset was not requested
1176 3 : uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
1177 3 : (void)getPacketType(&type);
1178 3 : if((type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) && (this->headerType == RADIOLIB_LRXXXX_LORA_HEADER_IMPLICIT) && (!offset)) {
1179 0 : return(this->implicitLen);
1180 : }
1181 :
1182 : // if offset was requested, or in explicit mode, we always have to perform the SPI transaction
1183 3 : uint8_t len = 0;
1184 3 : int state = getRxBufferStatus(&len, offset);
1185 : (void)state;
1186 3 : return((size_t)len);
1187 : }
1188 :
1189 3 : RadioLibTime_t LR11x0::getTimeOnAir(size_t len) {
1190 : ModemType_t modem;
1191 3 : getModem(&modem);
1192 6 : return(LRxxxx::getToA(len, modem));
1193 : }
1194 :
1195 3 : uint32_t LR11x0::getIrqFlags() {
1196 3 : return((uint32_t)this->getIrqStatus());
1197 : }
1198 :
1199 3 : int16_t LR11x0::setIrqFlags(uint32_t irq) {
1200 3 : return(this->setDioIrqParams(irq, irq));
1201 : }
1202 :
1203 6 : int16_t LR11x0::clearIrqFlags(uint32_t irq) {
1204 6 : return(this->clearIrqState(irq));
1205 : }
1206 :
1207 3 : uint8_t LR11x0::randomByte() {
1208 3 : uint32_t num = 0;
1209 3 : (void)getRandomNumber(&num);
1210 3 : return((uint8_t)num);
1211 : }
1212 :
1213 0 : int16_t LR11x0::implicitHeader(size_t len) {
1214 0 : return(this->setHeaderType(RADIOLIB_LRXXXX_LORA_HEADER_IMPLICIT, len));
1215 : }
1216 :
1217 0 : int16_t LR11x0::explicitHeader() {
1218 0 : return(this->setHeaderType(RADIOLIB_LRXXXX_LORA_HEADER_EXPLICIT));
1219 : }
1220 :
1221 0 : int16_t LR11x0::setRegulatorLDO() {
1222 0 : return(this->setRegMode(RADIOLIB_LR11X0_REG_MODE_LDO));
1223 : }
1224 :
1225 0 : int16_t LR11x0::setRegulatorDCDC() {
1226 0 : return(this->setRegMode(RADIOLIB_LR11X0_REG_MODE_DC_DC));
1227 : }
1228 :
1229 0 : int16_t LR11x0::setRxBoostedGainMode(bool en) {
1230 0 : uint8_t buff[1] = { (uint8_t)en };
1231 0 : return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_RX_BOOSTED, true, buff, sizeof(buff)));
1232 : }
1233 :
1234 3 : int16_t LR11x0::setOutputPower(int8_t power, uint8_t paSel, uint8_t regPaSupply, uint8_t paDutyCycle, uint8_t paHpSel, uint8_t rampTime) {
1235 : // set PA config
1236 3 : int16_t state = setPaConfig(paSel, regPaSupply, paDutyCycle, paHpSel);
1237 3 : RADIOLIB_ASSERT(state);
1238 :
1239 : // set output power
1240 0 : state = setTxParams(power, rampTime);
1241 0 : return(state);
1242 : }
1243 :
1244 0 : void LR11x0::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) {
1245 : // find which pins are used
1246 0 : uint8_t enable = 0;
1247 0 : for(size_t i = 0; i < Module::RFSWITCH_MAX_PINS; i++) {
1248 : // check if this pin is unused
1249 0 : if(pins[i] == RADIOLIB_NC) {
1250 0 : continue;
1251 : }
1252 :
1253 : // only keep DIO pins, there may be some GPIOs in the switch tabke
1254 0 : if(pins[i] & RFSWITCH_PIN_FLAG) {
1255 0 : enable |= 1UL << RADIOLIB_LRXXXX_DIOx_VAL(pins[i]);
1256 : }
1257 :
1258 : }
1259 :
1260 : // now get the configuration
1261 0 : uint8_t modes[7] = { 0 };
1262 0 : for(size_t i = 0; i < 7; i++) {
1263 : // check end of table
1264 0 : if(table[i].mode == LR11x0::MODE_END_OF_TABLE) {
1265 0 : break;
1266 : }
1267 :
1268 : // get the mode ID in case the modes are out-of-order
1269 0 : uint8_t index = table[i].mode - LR11x0::MODE_STBY;
1270 :
1271 : // iterate over the pins
1272 0 : for(size_t j = 0; j < Module::RFSWITCH_MAX_PINS; j++) {
1273 : // only process modes for the DIOx pins, skip GPIO pins
1274 0 : if(!(pins[j] & RFSWITCH_PIN_FLAG)) {
1275 0 : continue;
1276 : }
1277 0 : modes[index] |= (table[i].values[j] == this->mod->hal->GpioLevelHigh) ? (1UL << j) : 0;
1278 : }
1279 : }
1280 :
1281 : // set it
1282 0 : this->setDioAsRfSwitch(enable, modes[0], modes[1], modes[2], modes[3], modes[4], modes[5], modes[6]);
1283 :
1284 : // also call the Module::setRfSwitchTable to cache the RF switch table
1285 : // we may need to re-apply it after modem switch
1286 0 : this->mod->setRfSwitchTable(pins, table);
1287 0 : }
1288 :
1289 0 : int16_t LR11x0::setStandbyXOSC(bool enable) {
1290 : // set the internal variable
1291 0 : this->standbyXOSC = enable;
1292 :
1293 : // call standby to start the oscillator
1294 0 : int16_t state = standby();
1295 0 : RADIOLIB_ASSERT(state);
1296 :
1297 : // update Rx/Tx fallback mode
1298 0 : uint8_t mode = this->standbyXOSC ? RADIOLIB_LR11X0_FALLBACK_MODE_STBY_XOSC : RADIOLIB_LR11X0_FALLBACK_MODE_STBY_RC;
1299 0 : return(this->setRxTxFallbackMode(mode));
1300 : }
1301 :
1302 0 : int16_t LR11x0::forceLDRO(bool enable) {
1303 : // check packet type
1304 0 : uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
1305 0 : int16_t state = getPacketType(&type);
1306 0 : RADIOLIB_ASSERT(state);
1307 0 : if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
1308 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1309 : }
1310 :
1311 : // update modulation parameters
1312 0 : this->ldroAuto = false;
1313 0 : this->ldrOptimize = (uint8_t)enable;
1314 0 : return(setModulationParamsLoRa(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
1315 : }
1316 :
1317 0 : int16_t LR11x0::autoLDRO() {
1318 0 : uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
1319 0 : int16_t state = getPacketType(&type);
1320 0 : RADIOLIB_ASSERT(state);
1321 0 : if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
1322 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1323 : }
1324 :
1325 0 : this->ldroAuto = true;
1326 0 : return(setModulationParamsLoRa(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
1327 : }
1328 :
1329 0 : int16_t LR11x0::setLrFhssConfig(uint8_t bw, uint8_t cr, bool narrowGrid, uint8_t hdrCount, uint16_t hopSeed) {
1330 : // check active modem
1331 0 : uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
1332 0 : int16_t state = getPacketType(&type);
1333 0 : RADIOLIB_ASSERT(state);
1334 0 : if(type != RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) {
1335 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1336 : }
1337 :
1338 : // check and cache all parameters
1339 0 : this->lrFhssGrid = narrowGrid ? RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_FCC;
1340 0 : RADIOLIB_CHECK_RANGE((int8_t)cr, (int8_t)RADIOLIB_LRXXXX_LR_FHSS_CR_5_6, (int8_t)RADIOLIB_LRXXXX_LR_FHSS_CR_1_3, RADIOLIB_ERR_INVALID_CODING_RATE);
1341 0 : this->lrFhssCr = cr;
1342 0 : RADIOLIB_CHECK_RANGE((int8_t)bw, (int8_t)RADIOLIB_LRXXXX_LR_FHSS_BW_39_06, (int8_t)RADIOLIB_LRXXXX_LR_FHSS_BW_1574_2, RADIOLIB_ERR_INVALID_BANDWIDTH);
1343 0 : this->lrFhssBw = bw;
1344 0 : RADIOLIB_CHECK_RANGE(hdrCount, 1, 4, RADIOLIB_ERR_INVALID_BIT_RANGE);
1345 0 : this->lrFhssHdrCount = hdrCount;
1346 0 : RADIOLIB_CHECK_RANGE((int16_t)hopSeed, (int16_t)0x000, (int16_t)0x1FF, RADIOLIB_ERR_INVALID_DATA_SHAPING);
1347 0 : this->lrFhssHopSeq = hopSeed;
1348 0 : return(RADIOLIB_ERR_NONE);
1349 : }
1350 :
1351 0 : int16_t LR11x0::getVersionInfo(LR11x0VersionInfo_t* info) {
1352 0 : RADIOLIB_ASSERT_PTR(info);
1353 :
1354 0 : int16_t state = this->getVersion(&info->hardware, &info->device, &info->fwMajor, &info->fwMinor);
1355 0 : RADIOLIB_ASSERT(state);
1356 :
1357 : // LR1121 does not have GNSS and WiFi scanning
1358 0 : if(this->chipType == RADIOLIB_LR11X0_DEVICE_LR1121) {
1359 0 : info->fwMajorWiFi = 0;
1360 0 : info->fwMinorWiFi = 0;
1361 0 : info->fwGNSS = 0;
1362 0 : info->almanacGNSS = 0;
1363 0 : return(RADIOLIB_ERR_NONE);
1364 : }
1365 :
1366 0 : state = this->wifiReadVersion(&info->fwMajorWiFi, &info->fwMinorWiFi);
1367 0 : RADIOLIB_ASSERT(state);
1368 0 : return(this->gnssReadVersion(&info->fwGNSS, &info->almanacGNSS));
1369 : }
1370 :
1371 0 : int16_t LR11x0::updateFirmware(const uint32_t* image, size_t size, bool nonvolatile) {
1372 0 : RADIOLIB_ASSERT_PTR(image);
1373 :
1374 : // put the device to bootloader mode
1375 0 : int16_t state = this->reboot(true);
1376 0 : RADIOLIB_ASSERT(state);
1377 0 : this->mod->hal->delay(500);
1378 :
1379 : // check we're in bootloader
1380 0 : uint8_t device = 0xFF;
1381 0 : state = this->getVersion(NULL, &device, NULL, NULL);
1382 0 : RADIOLIB_ASSERT(state);
1383 0 : if(device != RADIOLIB_LR11X0_DEVICE_BOOT) {
1384 : RADIOLIB_DEBUG_BASIC_PRINTLN("Failed to put device to bootloader mode, %02x != %02x", (unsigned int)device, (unsigned int)RADIOLIB_LR11X0_DEVICE_BOOT);
1385 0 : return(RADIOLIB_ERR_CHIP_NOT_FOUND);
1386 : }
1387 :
1388 : // erase the image
1389 0 : state = this->bootEraseFlash();
1390 0 : RADIOLIB_ASSERT(state);
1391 :
1392 : // wait for BUSY to go low
1393 0 : RadioLibTime_t start = this->mod->hal->millis();
1394 0 : while(this->mod->hal->digitalRead(this->mod->getGpio())) {
1395 0 : this->mod->hal->yield();
1396 0 : if(this->mod->hal->millis() - start >= 3000) {
1397 : RADIOLIB_DEBUG_BASIC_PRINTLN("BUSY pin timeout after erase!");
1398 0 : return(RADIOLIB_ERR_SPI_CMD_TIMEOUT);
1399 : }
1400 : }
1401 :
1402 : // upload the new image
1403 0 : const size_t maxLen = 64;
1404 0 : size_t rem = size % maxLen;
1405 0 : size_t numWrites = (rem == 0) ? (size / maxLen) : ((size / maxLen) + 1);
1406 : RADIOLIB_DEBUG_BASIC_PRINTLN("Writing image in %lu chunks, last chunk size is %lu words", (unsigned long)numWrites, (unsigned long)rem);
1407 0 : for(size_t i = 0; i < numWrites; i ++) {
1408 0 : uint32_t offset = i * maxLen;
1409 0 : uint32_t len = (i == (numWrites - 1)) ? rem : maxLen;
1410 : RADIOLIB_DEBUG_BASIC_PRINTLN("Writing chunk %d at offset %08lx (%u words)", (int)i, (unsigned long)offset, (unsigned int)len);
1411 0 : this->bootWriteFlashEncrypted(offset*sizeof(uint32_t), const_cast<uint32_t*>(&image[offset]), len, nonvolatile);
1412 : }
1413 :
1414 : // kick the device from bootloader
1415 0 : state = this->reset();
1416 0 : RADIOLIB_ASSERT(state);
1417 :
1418 : // verify we are no longer in bootloader
1419 0 : state = this->getVersion(NULL, &device, NULL, NULL);
1420 0 : RADIOLIB_ASSERT(state);
1421 0 : if(device == RADIOLIB_LR11X0_DEVICE_BOOT) {
1422 : RADIOLIB_DEBUG_BASIC_PRINTLN("Failed to kick device from bootloader mode, %02x == %02x", (unsigned int)device, (unsigned int)RADIOLIB_LR11X0_DEVICE_BOOT);
1423 0 : return(RADIOLIB_ERR_CHIP_NOT_FOUND);
1424 : }
1425 :
1426 0 : return(state);
1427 : }
1428 :
1429 12 : int16_t LR11x0::getModem(ModemType_t* modem) {
1430 12 : RADIOLIB_ASSERT_PTR(modem);
1431 :
1432 12 : uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
1433 12 : int16_t state = getPacketType(&type);
1434 12 : RADIOLIB_ASSERT(state);
1435 :
1436 0 : switch(type) {
1437 0 : case(RADIOLIB_LR11X0_PACKET_TYPE_LORA):
1438 0 : *modem = ModemType_t::RADIOLIB_MODEM_LORA;
1439 0 : return(RADIOLIB_ERR_NONE);
1440 0 : case(RADIOLIB_LR11X0_PACKET_TYPE_GFSK):
1441 0 : *modem = ModemType_t::RADIOLIB_MODEM_FSK;
1442 0 : return(RADIOLIB_ERR_NONE);
1443 0 : case(RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS):
1444 0 : *modem = ModemType_t::RADIOLIB_MODEM_LRFHSS;
1445 0 : return(RADIOLIB_ERR_NONE);
1446 : }
1447 :
1448 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1449 : }
1450 :
1451 3 : int16_t LR11x0::getMode(RadioModeType_t* mode) {
1452 3 : RADIOLIB_ASSERT_PTR(mode);
1453 :
1454 3 : uint8_t stat2 = 0;
1455 3 : int16_t state = getStatus(NULL, &stat2, NULL);
1456 3 : RADIOLIB_ASSERT(state);
1457 :
1458 0 : switch(stat2 & 0b00001110) {
1459 0 : case(RADIOLIB_LR11X0_STAT_2_MODE_SLEEP):
1460 0 : *mode = RADIOLIB_RADIO_MODE_SLEEP;
1461 0 : break;
1462 0 : case(RADIOLIB_LR11X0_STAT_2_MODE_STBY_RC):
1463 : case(RADIOLIB_LR11X0_STAT_2_MODE_STBY_OSC):
1464 0 : *mode = RADIOLIB_RADIO_MODE_STANDBY;
1465 0 : break;
1466 0 : case(RADIOLIB_LR11X0_STAT_2_MODE_RX):
1467 0 : *mode = RADIOLIB_RADIO_MODE_RX;
1468 0 : break;
1469 0 : case(RADIOLIB_LR11X0_STAT_2_MODE_TX):
1470 0 : *mode = RADIOLIB_RADIO_MODE_TX;
1471 0 : break;
1472 0 : default:
1473 : // frequency synthesis, or WiFi/GNSS geolocation
1474 0 : *mode = RADIOLIB_RADIO_MODE_NONE;
1475 0 : break;
1476 : }
1477 :
1478 0 : return(RADIOLIB_ERR_NONE);
1479 : }
1480 :
1481 12 : int16_t LR11x0::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) {
1482 : int16_t state;
1483 :
1484 12 : switch(mode) {
1485 9 : case(RADIOLIB_RADIO_MODE_RX): {
1486 : // check active modem
1487 9 : uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
1488 9 : state = getPacketType(&modem);
1489 9 : RADIOLIB_ASSERT(state);
1490 0 : if((modem != RADIOLIB_LR11X0_PACKET_TYPE_LORA) &&
1491 0 : (modem != RADIOLIB_LR11X0_PACKET_TYPE_GFSK)) {
1492 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1493 : }
1494 :
1495 : // in implicit LoRa header mode, use the provided length if it is nonzero
1496 : // otherwise we trust the user has previously set the payload length manually
1497 0 : if((this->headerType == RADIOLIB_LRXXXX_LORA_HEADER_IMPLICIT) &&
1498 0 : (modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) &&
1499 0 : (cfg->receive.len != 0)) {
1500 0 : this->implicitLen = cfg->receive.len;
1501 : }
1502 :
1503 : // set DIO mapping
1504 0 : if(cfg->receive.timeout != RADIOLIB_LR11X0_RX_TIMEOUT_INF) {
1505 0 : cfg->receive.irqMask |= (1UL << RADIOLIB_IRQ_TIMEOUT);
1506 : }
1507 0 : state = setDioIrqParams(getIrqMapped(cfg->receive.irqFlags & cfg->receive.irqMask));
1508 0 : RADIOLIB_ASSERT(state);
1509 :
1510 : // clear interrupt flags
1511 0 : state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL);
1512 0 : RADIOLIB_ASSERT(state);
1513 :
1514 : // restore maximum allowed received packet length (may have been changed by previous Tx)
1515 0 : if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
1516 0 : state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType,
1517 0 : (this->headerType == RADIOLIB_LRXXXX_LORA_HEADER_IMPLICIT) ? this->implicitLen : RADIOLIB_LR11X0_MAX_PACKET_LENGTH,
1518 0 : this->crcTypeLoRa, this->invertIQEnabled);
1519 0 : RADIOLIB_ASSERT(state);
1520 :
1521 0 : state = setLoRaSynchTimeout(cfg->receive.syncSymbols);
1522 :
1523 : } else {
1524 0 : state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType,
1525 0 : (this->packetType == RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_FIXED) ? this->implicitLen : RADIOLIB_LR11X0_MAX_PACKET_LENGTH,
1526 0 : this->crcTypeGFSK, this->whitening);
1527 :
1528 : }
1529 :
1530 : // set implicit mode and expected len if applicable
1531 : /*if((this->headerType == RADIOLIB_LRXXXX_LORA_HEADER_IMPLICIT) && (modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA)) {
1532 : state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, this->invertIQEnabled);
1533 : RADIOLIB_ASSERT(state);
1534 : }*/
1535 :
1536 : // if max(uint32_t) is used, revert to RxContinuous
1537 0 : if(cfg->receive.timeout == 0xFFFFFFFF) {
1538 0 : cfg->receive.timeout = 0xFFFFFF;
1539 : }
1540 0 : this->rxTimeout = cfg->receive.timeout;
1541 0 : } break;
1542 :
1543 3 : case(RADIOLIB_RADIO_MODE_TX): {
1544 : // check packet length
1545 3 : if(cfg->transmit.len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH) {
1546 3 : return(RADIOLIB_ERR_PACKET_TOO_LONG);
1547 : }
1548 :
1549 : // maximum packet length is decreased by 1 when address filtering is active
1550 3 : if((this->addrComp != RADIOLIB_LR11X0_GFSK_ADDR_FILTER_DISABLED) && (cfg->transmit.len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH - 1)) {
1551 0 : return(RADIOLIB_ERR_PACKET_TOO_LONG);
1552 : }
1553 :
1554 : // set packet Length
1555 3 : uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
1556 3 : state = getPacketType(&modem);
1557 3 : RADIOLIB_ASSERT(state);
1558 0 : if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
1559 0 : state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, cfg->transmit.len, this->crcTypeLoRa, this->invertIQEnabled);
1560 :
1561 0 : } else if(modem == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
1562 0 : state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, cfg->transmit.len, this->crcTypeGFSK, this->whitening);
1563 :
1564 0 : } else if(modem != RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) {
1565 0 : return(RADIOLIB_ERR_UNKNOWN);
1566 :
1567 : }
1568 0 : RADIOLIB_ASSERT(state);
1569 :
1570 : // set DIO mapping
1571 0 : state = setDioIrqParams(RADIOLIB_LR11X0_IRQ_TX_DONE | RADIOLIB_LR11X0_IRQ_TIMEOUT);
1572 0 : RADIOLIB_ASSERT(state);
1573 :
1574 0 : if(modem == RADIOLIB_LR11X0_PACKET_TYPE_LR_FHSS) {
1575 : // an LR-FHSS frame is built from the payload in this step, so it cannot be written ahead
1576 0 : if(cfg->transmit.data == NULL) {
1577 0 : return(RADIOLIB_ERR_UNSUPPORTED);
1578 : }
1579 :
1580 : // in LR-FHSS mode, the packet is built by the device
1581 : // TODO add configurable device offset
1582 0 : state = LRxxxx::lrFhssBuildFrame(RADIOLIB_LR11X0_CMD_LR_FHSS_BUILD_FRAME, this->lrFhssHdrCount, this->lrFhssCr, this->lrFhssGrid, true, this->lrFhssBw, this->lrFhssHopSeq, 0, cfg->transmit.data, cfg->transmit.len);
1583 0 : RADIOLIB_ASSERT(state);
1584 :
1585 0 : } else if(cfg->transmit.data != NULL) {
1586 : // write packet to buffer - unless the caller already did that with writeTxBuffer,
1587 : // which it signals by leaving the payload pointer empty
1588 0 : state = writeBuffer8(cfg->transmit.data, cfg->transmit.len);
1589 0 : RADIOLIB_ASSERT(state);
1590 :
1591 : }
1592 :
1593 : // clear interrupt flags
1594 0 : state = clearIrqState(RADIOLIB_LR11X0_IRQ_ALL);
1595 0 : RADIOLIB_ASSERT(state);
1596 0 : } break;
1597 :
1598 0 : default:
1599 0 : return(RADIOLIB_ERR_UNSUPPORTED);
1600 : }
1601 :
1602 0 : this->stagedMode = mode;
1603 0 : return(state);
1604 : }
1605 :
1606 3 : int16_t LR11x0::writeTxBuffer(const uint8_t* data, size_t len) {
1607 3 : if(data == NULL) {
1608 0 : return(RADIOLIB_ERR_NULL_POINTER);
1609 : }
1610 3 : if(len > RADIOLIB_LR11X0_MAX_PACKET_LENGTH) {
1611 0 : return(RADIOLIB_ERR_PACKET_TOO_LONG);
1612 : }
1613 :
1614 3 : return(writeBuffer8(data, len));
1615 : }
1616 :
1617 3 : int16_t LR11x0::clearTxBuffer() {
1618 : // the transmit buffer is separate from the receive buffer and is overwritten
1619 : // by the next write, so there is nothing to discard
1620 3 : return(RADIOLIB_ERR_NONE);
1621 : }
1622 :
1623 3 : int16_t LR11x0::launchMode() {
1624 : int16_t state;
1625 3 : switch(this->stagedMode) {
1626 3 : case(RADIOLIB_RADIO_MODE_RX): {
1627 3 : this->mod->setRfSwitchState(Module::MODE_RX);
1628 3 : state = setRx(this->rxTimeout);
1629 3 : } break;
1630 :
1631 0 : case(RADIOLIB_RADIO_MODE_TX): {
1632 0 : this->mod->setRfSwitchState(this->txMode);
1633 0 : state = setTx(RADIOLIB_LR11X0_TX_TIMEOUT_NONE);
1634 0 : RADIOLIB_ASSERT(state);
1635 :
1636 : // wait for BUSY to go low (= PA ramp up done)
1637 0 : while(this->mod->hal->digitalRead(this->mod->getGpio())) {
1638 0 : this->mod->hal->yield();
1639 : }
1640 0 : } break;
1641 :
1642 0 : default:
1643 0 : return(RADIOLIB_ERR_UNSUPPORTED);
1644 : }
1645 :
1646 3 : this->stagedMode = RADIOLIB_RADIO_MODE_NONE;
1647 3 : return(state);
1648 : }
1649 :
1650 0 : int16_t LR11x0::workaroundGFSK() {
1651 : // first, check we are using GFSK modem
1652 0 : uint8_t modem = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
1653 0 : int16_t state = getPacketType(&modem);
1654 0 : RADIOLIB_ASSERT(state);
1655 0 : if(modem != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
1656 : // not in GFSK, nothing to do here
1657 0 : return(RADIOLIB_ERR_NONE);
1658 : }
1659 :
1660 : // this seems to always be the first step (even when resetting)
1661 0 : state = this->writeRegMemMask32(RADIOLIB_LR11X0_REG_GFSK_FIX1, 0x30, 0x10);
1662 0 : RADIOLIB_ASSERT(state);
1663 :
1664 : // these are the default values that will be applied if nothing matches
1665 0 : uint32_t valFix2 = 0x01;
1666 0 : uint32_t valFix3 = 0x0A01;
1667 :
1668 : // next, decide what to change based on modulation properties
1669 0 : if((this->bitRate == 1200) && (this->frequencyDev == 5000) && (this->rxBandwidth == RADIOLIB_LR11X0_GFSK_RX_BW_19_5)) {
1670 : // workaround for 1.2 kbps
1671 0 : valFix2 = 0x04;
1672 :
1673 0 : } else if((this->bitRate == 600) && (this->frequencyDev == 800) && (this->rxBandwidth == RADIOLIB_LR11X0_GFSK_RX_BW_4_8)) {
1674 : // value to write depends on the frequency
1675 0 : valFix3 = (this->freqHz >= RADIOLIB_LR11X0_LF_CUTOFF_FREQ) ? 0x1100 : 0x0600;
1676 :
1677 : }
1678 :
1679 : // update the registers
1680 0 : state = this->writeRegMemMask32(RADIOLIB_LR11X0_REG_GFSK_FIX2, 0x05, valFix2);
1681 0 : RADIOLIB_ASSERT(state);
1682 0 : return(this->writeRegMemMask32(RADIOLIB_LR11X0_REG_GFSK_FIX3, 0x01FF03, valFix3));
1683 : }
1684 :
1685 0 : int16_t LR11x0::modSetup(uint8_t modem) {
1686 0 : int16_t state = this->mod->init();
1687 0 : RADIOLIB_ASSERT(state);
1688 0 : this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
1689 0 : this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput);
1690 0 : this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_LR11X0_CMD_READ_REG_MEM;
1691 0 : this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_LR11X0_CMD_WRITE_REG_MEM;
1692 0 : this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_LR11X0_CMD_NOP;
1693 0 : this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_LR11X0_CMD_GET_STATUS;
1694 0 : this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_32;
1695 0 : this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_8;
1696 0 : this->gnss = false;
1697 :
1698 : // try to find the LR11x0 chip - this will also reset the module at least once
1699 0 : bool unsupportedFw = false;
1700 0 : if(!LR11x0::findChip(this->chipType)) {
1701 : // 0x00 and 0xFF typically mean a failed SPI bus,
1702 : // any other device value is considered unsupported firmware
1703 0 : if((this->versionDevice == 0x00) || (this->versionDevice == 0xFF)) {
1704 : RADIOLIB_DEBUG_BASIC_PRINTLN("No LR11x0 found!");
1705 0 : state = this->mod->term();
1706 0 : RADIOLIB_ASSERT(state);
1707 0 : return(RADIOLIB_ERR_CHIP_NOT_FOUND);
1708 : }
1709 : RADIOLIB_DEBUG_BASIC_PRINTLN("Unsupported LR11x0 firmware detected, only firmware update is possible!");
1710 0 : unsupportedFw = true;
1711 : }
1712 : RADIOLIB_DEBUG_BASIC_PRINTLN("M\tLR11x0");
1713 :
1714 : // set mode to standby
1715 : // force the device to use RC oscillator, as XOSC may not be ready yet
1716 0 : state = standby(RADIOLIB_LR11X0_STANDBY_RC);
1717 0 : RADIOLIB_ASSERT(state);
1718 :
1719 : // set TCXO control, if requested
1720 0 : if(this->tcxoVoltage != RadioLibTCXOVoltage_t::VoltageNone) {
1721 0 : state = setTCXO(this->tcxoVoltage);
1722 0 : RADIOLIB_ASSERT(state);
1723 : }
1724 :
1725 : // with unsupported firmware, stop here and leave the device ready for firmware update
1726 0 : if(unsupportedFw) {
1727 0 : return(RADIOLIB_ERR_UNSUPPORTED_FIRMWARE);
1728 : }
1729 :
1730 : // configure settings not accessible by API
1731 0 : state = config(modem);
1732 0 : RADIOLIB_ASSERT(state);
1733 :
1734 : // restore RF switch configuration, if it exists
1735 : uint32_t pins[Module::RFSWITCH_MAX_PINS];
1736 0 : const Module::RfSwitchMode_t* table = nullptr;
1737 0 : this->mod->getRfSwitchTable(pins, &table);
1738 0 : if(table != nullptr) {
1739 0 : this->setRfSwitchTable(pins, table);
1740 : }
1741 :
1742 0 : return(state);
1743 : }
1744 :
1745 0 : bool LR11x0::findChip(uint8_t ver) {
1746 0 : uint8_t i = 0;
1747 0 : bool flagFound = false;
1748 : LR11x0VersionInfo_t versionInfo;
1749 0 : while((i < 10) && !flagFound) {
1750 : // reset the module
1751 0 : reset();
1752 :
1753 : // read the version
1754 0 : int16_t state = getVersionInfo(&versionInfo);
1755 0 : RADIOLIB_ASSERT(state);
1756 :
1757 0 : if((versionInfo.device == ver) || (versionInfo.device == RADIOLIB_LR11X0_DEVICE_BOOT)) {
1758 0 : this->versionDevice = versionInfo.device;
1759 : RADIOLIB_DEBUG_BASIC_PRINTLN("Found LR11x0: RADIOLIB_LR11X0_CMD_GET_VERSION = 0x%02x", versionInfo.device);
1760 : RADIOLIB_DEBUG_BASIC_PRINTLN("Base FW version: %d.%d", (int)versionInfo.fwMajor, (int)versionInfo.fwMinor);
1761 0 : if(this->chipType != RADIOLIB_LR11X0_DEVICE_LR1121) {
1762 : RADIOLIB_DEBUG_BASIC_PRINTLN("WiFi FW version: %d.%d", (int)versionInfo.fwMajorWiFi, (int)versionInfo.fwMinorWiFi);
1763 : RADIOLIB_DEBUG_BASIC_PRINTLN("GNSS FW version: %d.%d", (int)versionInfo.fwGNSS, (int)versionInfo.almanacGNSS);
1764 : }
1765 0 : if(versionInfo.device == RADIOLIB_LR11X0_DEVICE_BOOT) {
1766 : RADIOLIB_DEBUG_BASIC_PRINTLN("Warning: device is in bootloader mode! Only FW update is possible now.");
1767 : }
1768 0 : flagFound = true;
1769 : } else {
1770 : RADIOLIB_DEBUG_BASIC_PRINTLN("LR11x0 not found! (%d of 10 tries) RADIOLIB_LR11X0_CMD_GET_VERSION = 0x%02x", i + 1, versionInfo.device);
1771 : RADIOLIB_DEBUG_BASIC_PRINTLN("Expected: 0x%02x", ver);
1772 0 : this->versionDevice = versionInfo.device;
1773 0 : this->mod->hal->delay(10);
1774 0 : i++;
1775 : }
1776 : }
1777 :
1778 : // check the firmware is up-to-date
1779 0 : if(flagFound && (this->versionDevice != RADIOLIB_LR11X0_DEVICE_BOOT)) {
1780 0 : this->versionCombined = (uint16_t)versionInfo.fwMajor << 8 | (uint16_t)versionInfo.fwMinor;
1781 0 : const uint16_t latestVersions[] = RADIOLIB_LR11X0_FIRMWARE_LATEST;
1782 0 : const uint16_t latest = latestVersions[(versionInfo.device - 1) & 0x03];
1783 0 : if(this->versionCombined < latest) {
1784 : RADIOLIB_DEBUG_BASIC_PRINTLN("Detected outdated LR11x0 firmware (%04x < %04x)", this->versionCombined, latest);
1785 : RADIOLIB_DEBUG_BASIC_PRINTLN("It is strongly recommended to update the firmware to version %04x!", latest);
1786 : RADIOLIB_DEBUG_BASIC_PRINTLN("Outdated firmware may be missing some features and have security vulnerabilities");
1787 : RADIOLIB_DEBUG_BASIC_PRINTLN("See RadioLib/examples/LR11x0/LR11x0_Firmware_Update for details");
1788 : }
1789 : }
1790 :
1791 0 : return(flagFound);
1792 : }
1793 :
1794 0 : int16_t LR11x0::config(uint8_t modem) {
1795 0 : int16_t state = RADIOLIB_ERR_UNKNOWN;
1796 :
1797 : // set Rx/Tx fallback mode
1798 0 : state = this->setRxTxFallbackMode(this->standbyXOSC ? RADIOLIB_LR11X0_FALLBACK_MODE_STBY_XOSC : RADIOLIB_LR11X0_FALLBACK_MODE_STBY_RC);
1799 0 : RADIOLIB_ASSERT(state);
1800 :
1801 : // clear IRQ
1802 0 : state = this->clearIrqState(RADIOLIB_LR11X0_IRQ_ALL);
1803 0 : state |= this->setDioIrqParams(RADIOLIB_LR11X0_IRQ_NONE);
1804 0 : RADIOLIB_ASSERT(state);
1805 :
1806 : // calibrate all blocks
1807 0 : state = this->calibrate(RADIOLIB_LR11X0_CALIBRATE_ALL);
1808 :
1809 : // wait for calibration completion
1810 0 : this->mod->hal->delay(5);
1811 0 : while(this->mod->hal->digitalRead(this->mod->getGpio())) {
1812 0 : this->mod->hal->yield();
1813 : }
1814 :
1815 : // if something failed, show the device errors
1816 : #if RADIOLIB_DEBUG_BASIC
1817 : if(state != RADIOLIB_ERR_NONE) {
1818 : // unless mode is forced to standby, device errors will be 0
1819 : standby();
1820 : uint16_t errors = 0;
1821 : getErrors(&errors);
1822 : RADIOLIB_DEBUG_BASIC_PRINTLN("Calibration failed, device errors: 0x%X", errors);
1823 : }
1824 : #endif
1825 0 : RADIOLIB_ASSERT(state);
1826 :
1827 : // enable driving DIOs in sleep mode
1828 : // this prevents IRQ going high when the device goes to sleep
1829 : // especially when using Rx duty cycle, this would make it look like received packets
1830 : // there seems to be no measurable impact on power consumption in sleep mode
1831 : // also, LR1110 firmware before 0306 did not have this command
1832 0 : if(!((this->versionDevice == RADIOLIB_LR11X0_DEVICE_LR1110) && (this->versionCombined < 0x0306))) {
1833 0 : state = this->driveDiosInSleepMode(true);
1834 0 : RADIOLIB_ASSERT(state);
1835 : }
1836 :
1837 : // set modem
1838 0 : state = this->setPacketType(modem);
1839 0 : return(state);
1840 : }
1841 :
1842 0 : int16_t LR11x0::setPacketMode(uint8_t mode, uint8_t len) {
1843 : // check active modem
1844 0 : uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
1845 0 : int16_t state = getPacketType(&type);
1846 0 : RADIOLIB_ASSERT(state);
1847 0 : if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
1848 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1849 : }
1850 :
1851 : // set requested packet mode
1852 0 : state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, mode, len, this->crcTypeGFSK, this->whitening);
1853 0 : RADIOLIB_ASSERT(state);
1854 :
1855 : // update cached value
1856 0 : this->packetType = mode;
1857 0 : return(state);
1858 : }
1859 :
1860 0 : int16_t LR11x0::startCad(uint8_t symbolNum, uint8_t detPeak, uint8_t detMin, uint8_t exitMode, RadioLibTime_t timeout) {
1861 : // check active modem
1862 0 : uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
1863 0 : int16_t state = getPacketType(&type);
1864 0 : RADIOLIB_ASSERT(state);
1865 0 : if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
1866 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1867 : }
1868 :
1869 : // select CAD parameters
1870 : // TODO the magic numbers are based on Semtech examples, this is probably suboptimal
1871 0 : uint8_t num = symbolNum;
1872 0 : if(num == RADIOLIB_LR11X0_CAD_PARAM_DEFAULT) {
1873 0 : num = 2;
1874 : }
1875 :
1876 0 : const uint8_t detPeakValues[8] = { 48, 48, 50, 55, 55, 59, 61, 65 };
1877 0 : uint8_t peak = detPeak;
1878 0 : if(peak == RADIOLIB_LR11X0_CAD_PARAM_DEFAULT) {
1879 0 : peak = detPeakValues[this->spreadingFactor - 5];
1880 : }
1881 :
1882 0 : uint8_t min = detMin;
1883 0 : if(min == RADIOLIB_LR11X0_CAD_PARAM_DEFAULT) {
1884 0 : min = 10;
1885 : }
1886 :
1887 0 : uint8_t mode = exitMode;
1888 0 : if(mode == RADIOLIB_LR11X0_CAD_PARAM_DEFAULT) {
1889 0 : mode = RADIOLIB_LR11X0_CAD_EXIT_MODE_STBY_RC;
1890 : }
1891 :
1892 0 : uint32_t timeout_raw = (uint32_t)((float)timeout * (1.0f / 30.52f));
1893 :
1894 : // set CAD parameters
1895 : // TODO add configurable exit mode and timeout
1896 0 : state = setCadParams(num, peak, min, mode, timeout_raw);
1897 0 : RADIOLIB_ASSERT(state);
1898 :
1899 : // start CAD
1900 0 : return(setCad());
1901 : }
1902 :
1903 0 : int16_t LR11x0::setHeaderType(uint8_t hdrType, size_t len) {
1904 : // check active modem
1905 0 : uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
1906 0 : int16_t state = getPacketType(&type);
1907 0 : RADIOLIB_ASSERT(state);
1908 0 : if(type != RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
1909 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1910 : }
1911 :
1912 : // set requested packet mode
1913 0 : state = setPacketParamsLoRa(this->preambleLengthLoRa, hdrType, len, this->crcTypeLoRa, this->invertIQEnabled);
1914 0 : RADIOLIB_ASSERT(state);
1915 :
1916 : // update cached value
1917 0 : this->headerType = hdrType;
1918 0 : this->implicitLen = len;
1919 :
1920 0 : return(state);
1921 : }
1922 :
1923 0 : Module* LR11x0::getMod() {
1924 0 : return(this->mod);
1925 : }
1926 :
1927 : #endif
|