Line data Source code
1 : #include "LR2021.h"
2 :
3 : #include <string.h>
4 : #include <math.h>
5 :
6 : #if !RADIOLIB_EXCLUDE_LR2021
7 :
8 1 : LR2021::LR2021(Module* mod) : LRxxxx(mod) {
9 1 : this->freqStep = RADIOLIB_LR2021_FREQUENCY_STEP_SIZE;
10 1 : this->maxPacketLength = RADIOLIB_LR2021_MAX_PACKET_LENGTH;
11 1 : this->implicitLen = RADIOLIB_LR2021_MAX_PACKET_LENGTH;
12 1 : this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_LR2021_IRQ_TX_DONE;
13 1 : this->irqMap[RADIOLIB_IRQ_RX_DONE] = RADIOLIB_LR2021_IRQ_RX_DONE;
14 1 : this->irqMap[RADIOLIB_IRQ_PREAMBLE_DETECTED] = RADIOLIB_LR2021_IRQ_PREAMBLE_DETECTED;
15 1 : this->irqMap[RADIOLIB_IRQ_SYNC_WORD_VALID] = RADIOLIB_LR2021_IRQ_LORA_HEADER_VALID;
16 1 : this->irqMap[RADIOLIB_IRQ_HEADER_VALID] = RADIOLIB_LR2021_IRQ_LORA_HEADER_VALID;
17 1 : this->irqMap[RADIOLIB_IRQ_HEADER_ERR] = RADIOLIB_LR2021_IRQ_LORA_HDR_CRC_ERROR;
18 1 : this->irqMap[RADIOLIB_IRQ_CRC_ERR] = RADIOLIB_LR2021_IRQ_CRC_ERROR;
19 1 : this->irqMap[RADIOLIB_IRQ_CAD_DONE] = RADIOLIB_LR2021_IRQ_CAD_DONE;
20 1 : this->irqMap[RADIOLIB_IRQ_CAD_DETECTED] = RADIOLIB_LR2021_IRQ_CAD_DETECTED;
21 1 : this->irqMap[RADIOLIB_IRQ_TIMEOUT] = RADIOLIB_LR2021_IRQ_TIMEOUT;
22 1 : }
23 :
24 0 : int16_t LR2021::begin(const ConfigLoRa_t& cfg) {
25 : // set module properties and perform initial setup
26 0 : int16_t state = this->modSetup(cfg.frequency, RADIOLIB_LR2021_PACKET_TYPE_LORA);
27 0 : RADIOLIB_ASSERT(state);
28 :
29 : // configure publicly accessible settings
30 0 : state = setBandwidth(cfg.bandwidth);
31 0 : RADIOLIB_ASSERT(state);
32 :
33 0 : state = setSpreadingFactor(cfg.spreadingFactor);
34 0 : RADIOLIB_ASSERT(state);
35 :
36 0 : state = setCodingRate(cfg.codingRate);
37 0 : RADIOLIB_ASSERT(state);
38 :
39 0 : state = setSyncWord(cfg.syncWord);
40 0 : RADIOLIB_ASSERT(state);
41 :
42 0 : state = setOutputPower(cfg.power);
43 0 : RADIOLIB_ASSERT(state);
44 :
45 0 : state = setPreambleLength(cfg.preambleLength);
46 0 : RADIOLIB_ASSERT(state);
47 :
48 : // set publicly accessible settings that are not a part of begin method
49 0 : state = setCRC(2);
50 0 : RADIOLIB_ASSERT(state);
51 :
52 0 : state = invertIQ(false);
53 0 : return(state);
54 : }
55 :
56 0 : int16_t LR2021::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, float tcxoVoltage) {
57 0 : ConfigLoRa_t cfg;
58 0 : cfg.frequency = freq;
59 0 : cfg.bandwidth = bw;
60 0 : cfg.spreadingFactor = sf;
61 0 : cfg.codingRate = cr;
62 0 : cfg.syncWord = syncWord;
63 0 : cfg.power = power;
64 0 : cfg.preambleLength = preambleLength;
65 0 : this->tcxoVoltage = tcxoVoltage;
66 0 : return(begin(cfg));
67 : }
68 :
69 0 : int16_t LR2021::beginGFSK(const ConfigFSK_t& cfg) {
70 0 : this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_153_8;
71 0 : this->frequencyDev = cfg.frequencyDeviation * 1000.0f;
72 :
73 : // set module properties and perform initial setup
74 0 : int16_t state = this->modSetup(cfg.frequency, RADIOLIB_LR2021_PACKET_TYPE_GFSK);
75 0 : RADIOLIB_ASSERT(state);
76 :
77 : // configure publicly accessible settings
78 0 : state = setBitRate(cfg.bitRate);
79 0 : RADIOLIB_ASSERT(state);
80 :
81 0 : state = setFrequencyDeviation(cfg.frequencyDeviation);
82 0 : RADIOLIB_ASSERT(state);
83 :
84 0 : state = setRxBandwidth(cfg.receiverBandwidth);
85 0 : RADIOLIB_ASSERT(state);
86 :
87 0 : state = setOutputPower(cfg.power);
88 0 : RADIOLIB_ASSERT(state);
89 :
90 0 : state = setPreambleLength(cfg.preambleLength);
91 0 : RADIOLIB_ASSERT(state);
92 :
93 : // set publicly accessible settings that are not a part of begin method
94 0 : uint8_t sync[] = { 0x12, 0xAD };
95 0 : state = setSyncWord(sync, 2);
96 0 : RADIOLIB_ASSERT(state);
97 :
98 0 : state = setDataShaping(RADIOLIB_SHAPING_NONE);
99 0 : RADIOLIB_ASSERT(state);
100 :
101 0 : state = setEncoding(RADIOLIB_ENCODING_NRZ);
102 0 : RADIOLIB_ASSERT(state);
103 :
104 0 : state = variablePacketLengthMode(RADIOLIB_LR2021_MAX_PACKET_LENGTH);
105 0 : RADIOLIB_ASSERT(state);
106 :
107 0 : state = setCRC(2);
108 0 : return(state);
109 : }
110 :
111 0 : int16_t LR2021::beginGFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage) {
112 0 : ConfigFSK_t cfg;
113 0 : cfg.frequency = freq;
114 0 : cfg.bitRate = br;
115 0 : cfg.frequencyDeviation = freqDev;
116 0 : cfg.receiverBandwidth = rxBw;
117 0 : cfg.power = power;
118 0 : cfg.preambleLength = preambleLength;
119 0 : this->tcxoVoltage = tcxoVoltage;
120 0 : return(beginGFSK(cfg));
121 : }
122 :
123 0 : int16_t LR2021::beginOOK(const ConfigOOK_t& cfg) {
124 0 : this->rxBandwidth = RADIOLIB_LR2021_GFSK_OOK_RX_BW_153_8;
125 :
126 : // set module properties and perform initial setup
127 0 : int16_t state = this->modSetup(cfg.frequency, RADIOLIB_LR2021_PACKET_TYPE_OOK);
128 0 : RADIOLIB_ASSERT(state);
129 :
130 : // configure publicly accessible settings
131 0 : state = setBitRate(cfg.bitRate);
132 0 : RADIOLIB_ASSERT(state);
133 :
134 0 : state = setRxBandwidth(cfg.receiverBandwidth);
135 0 : RADIOLIB_ASSERT(state);
136 :
137 0 : state = setOutputPower(cfg.power);
138 0 : RADIOLIB_ASSERT(state);
139 :
140 0 : state = setPreambleLength(cfg.preambleLength);
141 0 : RADIOLIB_ASSERT(state);
142 :
143 : // set publicly accessible settings that are not a part of begin method
144 0 : uint8_t sync[] = { 0x12, 0xAD };
145 0 : state = setSyncWord(sync, 2);
146 0 : RADIOLIB_ASSERT(state);
147 :
148 0 : state = setDataShaping(RADIOLIB_SHAPING_NONE);
149 0 : RADIOLIB_ASSERT(state);
150 :
151 0 : state = setEncoding(RADIOLIB_ENCODING_NRZ);
152 0 : RADIOLIB_ASSERT(state);
153 :
154 0 : state = variablePacketLengthMode(RADIOLIB_LR2021_MAX_PACKET_LENGTH);
155 0 : RADIOLIB_ASSERT(state);
156 :
157 0 : state = setCRC(2);
158 0 : return(state);
159 : }
160 :
161 0 : int16_t LR2021::beginOOK(float freq, float br, float rxBw, int8_t power, uint16_t preambleLength, float tcxoVoltage) {
162 0 : ConfigOOK_t cfg;
163 0 : cfg.frequency = freq;
164 0 : cfg.bitRate = br;
165 0 : cfg.receiverBandwidth = rxBw;
166 0 : cfg.power = power;
167 0 : cfg.preambleLength = preambleLength;
168 0 : this->tcxoVoltage = tcxoVoltage;
169 0 : return(beginOOK(cfg));
170 : }
171 :
172 0 : int16_t LR2021::beginLRFHSS(const ConfigLRFHSS_t& cfg) {
173 : // set module properties and perform initial setup
174 0 : int16_t state = this->modSetup(cfg.frequency, RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS);
175 0 : RADIOLIB_ASSERT(state);
176 :
177 : // set grid spacing
178 0 : this->lrFhssGrid = cfg.narrowGrid ? RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_FCC;
179 :
180 : // configure publicly accessible settings
181 0 : state = setLrFhssConfig(cfg.bandwidth, cfg.codingRate);
182 0 : RADIOLIB_ASSERT(state);
183 :
184 0 : state = setOutputPower(cfg.power);
185 0 : RADIOLIB_ASSERT(state);
186 :
187 0 : uint8_t syncWord[] = { 0x12, 0xAD, 0x10, 0x1B };
188 0 : state = setSyncWord(syncWord, 4);
189 0 : return(state);
190 : }
191 :
192 0 : int16_t LR2021::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, bool narrowGrid, int8_t power, float tcxoVoltage) {
193 0 : ConfigLRFHSS_t cfg;
194 0 : cfg.frequency = freq;
195 0 : cfg.bandwidth = bw;
196 0 : cfg.codingRate = cr;
197 0 : cfg.narrowGrid = narrowGrid;
198 0 : cfg.power = power;
199 0 : this->tcxoVoltage = tcxoVoltage;
200 0 : return(beginLRFHSS(cfg));
201 : }
202 :
203 0 : int16_t LR2021::beginFLRC(const ConfigFLRC_t& cfg) {
204 : // initialize FLRC modulation variables
205 0 : this->bitRateFlrc = cfg.bitRate;
206 0 : this->codingRateFlrc = RADIOLIB_LR2021_FLRC_CR_3_4;
207 0 : this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_0_5;
208 :
209 : // initialize FLRC packet variables
210 0 : this->preambleLengthGFSK = cfg.preambleLength;
211 0 : this->crcLenGFSK = 1;
212 :
213 : // set module properties and perform initial setup
214 0 : int16_t state = this->modSetup(cfg.frequency, RADIOLIB_LR2021_PACKET_TYPE_FLRC);
215 0 : RADIOLIB_ASSERT(state);
216 :
217 : // configure publicly accessible settings
218 0 : state = setBitRate(cfg.bitRate);
219 0 : RADIOLIB_ASSERT(state);
220 :
221 0 : state = setCodingRate(cfg.codingRate);
222 0 : RADIOLIB_ASSERT(state);
223 :
224 0 : state = setOutputPower(cfg.power);
225 0 : RADIOLIB_ASSERT(state);
226 :
227 0 : state = setPreambleLength(cfg.preambleLength);
228 0 : RADIOLIB_ASSERT(state);
229 :
230 0 : state = setDataShaping(cfg.dataShaping);
231 0 : RADIOLIB_ASSERT(state);
232 :
233 : // set publicly accessible settings that are not a part of begin method
234 0 : uint8_t sync[] = { 0x2D, 0x01, 0x4B, 0x1D};
235 0 : state = setSyncWord(sync, 4);
236 0 : RADIOLIB_ASSERT(state);
237 :
238 0 : state = variablePacketLengthMode(RADIOLIB_LR2021_MAX_PACKET_LENGTH);
239 0 : RADIOLIB_ASSERT(state);
240 :
241 0 : state = setCRC(2);
242 0 : return(state);
243 : }
244 :
245 0 : int16_t LR2021::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t pwr, uint16_t preambleLength, uint8_t dataShaping, float tcxoVoltage) {
246 0 : ConfigFLRC_t cfg;
247 0 : cfg.frequency = freq;
248 0 : cfg.bitRate = br;
249 0 : cfg.codingRate = cr;
250 0 : cfg.power = pwr;
251 0 : cfg.preambleLength = preambleLength;
252 0 : cfg.dataShaping = dataShaping;
253 0 : this->tcxoVoltage = tcxoVoltage;
254 0 : return(beginFLRC(cfg));
255 : }
256 :
257 1 : int16_t LR2021::transmit(const uint8_t* data, size_t len, uint8_t addr) {
258 : // set mode to standby
259 1 : int16_t state = standby();
260 1 : RADIOLIB_ASSERT(state);
261 :
262 : // check packet length
263 0 : if (this->codingRate > RADIOLIB_LR2021_LORA_CR_4_8) {
264 : // Long Interleaver needs at least 8 bytes
265 0 : if(len < 8) {
266 0 : return(RADIOLIB_ERR_PACKET_TOO_SHORT);
267 : }
268 :
269 : // Long Interleaver supports up to 253 bytes if CRC is enabled
270 0 : if (this->crcTypeLoRa == RADIOLIB_LR2021_LORA_CRC_ENABLED && (len > RADIOLIB_LR2021_MAX_PACKET_LENGTH - 2)) {
271 0 : return(RADIOLIB_ERR_PACKET_TOO_LONG);
272 : }
273 : }
274 0 : if(len > RADIOLIB_LR2021_MAX_PACKET_LENGTH) {
275 0 : return(RADIOLIB_ERR_PACKET_TOO_LONG);
276 : }
277 :
278 : // get currently active modem
279 0 : uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
280 0 : state = getPacketType(&modem);
281 0 : RADIOLIB_ASSERT(state);
282 0 : RadioLibTime_t timeout = getTimeOnAir(len);
283 0 : if(modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) {
284 : // calculate timeout (150% of expected time-on-air)
285 0 : timeout = (timeout * 3) / 2;
286 :
287 0 : } else if((modem == RADIOLIB_LR2021_PACKET_TYPE_GFSK) ||
288 0 : (modem == RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS) ||
289 0 : (modem == RADIOLIB_LR2021_PACKET_TYPE_FLRC) ||
290 0 : (modem == RADIOLIB_LR2021_PACKET_TYPE_OOK)) {
291 : // calculate timeout (500% of expected time-on-air)
292 0 : timeout = timeout * 5;
293 :
294 : } else {
295 0 : return(RADIOLIB_ERR_WRONG_MODEM);
296 : }
297 :
298 : RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu us", timeout);
299 :
300 : // start transmission
301 0 : state = startTransmit(data, len, addr);
302 0 : RADIOLIB_ASSERT(state);
303 :
304 : // wait for packet transmission or timeout
305 0 : RadioLibTime_t start = this->mod->hal->micros();
306 0 : while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
307 0 : this->mod->hal->yield();
308 0 : if(this->mod->hal->micros() - start > timeout) {
309 0 : finishTransmit();
310 0 : return(RADIOLIB_ERR_TX_TIMEOUT);
311 : }
312 : }
313 :
314 0 : return(finishTransmit());
315 : }
316 :
317 1 : int16_t LR2021::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) {
318 : // set mode to standby
319 1 : int16_t state = standby();
320 1 : RADIOLIB_ASSERT(state);
321 :
322 : // calculate timeout based on the configured modem
323 0 : RadioLibTime_t timeoutInternal = timeout;
324 0 : if(!timeoutInternal) {
325 : // get currently active modem
326 0 : uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
327 0 : state = getPacketType(&modem);
328 0 : RADIOLIB_ASSERT(state);
329 0 : if((modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) ||
330 0 : (modem == RADIOLIB_LR2021_PACKET_TYPE_GFSK) ||
331 0 : (modem == RADIOLIB_LR2021_PACKET_TYPE_FLRC) ||
332 0 : (modem == RADIOLIB_LR2021_PACKET_TYPE_OOK)) {
333 : // calculate timeout (500 % of expected time-one-air)
334 0 : size_t maxLen = len;
335 0 : if(len == 0) { maxLen = RADIOLIB_LR2021_MAX_PACKET_LENGTH; }
336 0 : timeoutInternal = (getTimeOnAir(maxLen) * 5) / 1000;
337 :
338 0 : } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS) {
339 : // this modem cannot receive
340 0 : return(RADIOLIB_ERR_WRONG_MODEM);
341 :
342 : } else {
343 0 : return(RADIOLIB_ERR_UNKNOWN);
344 :
345 : }
346 : }
347 :
348 : RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeoutInternal);
349 :
350 : // start reception
351 0 : uint32_t timeoutValue = (uint32_t)(((float)timeoutInternal * 1000.0f) / 30.52f);
352 0 : state = startReceive(timeoutValue);
353 0 : RADIOLIB_ASSERT(state);
354 :
355 : // wait for packet reception or timeout
356 0 : bool softTimeout = false;
357 0 : RadioLibTime_t start = this->mod->hal->millis();
358 0 : while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
359 0 : this->mod->hal->yield();
360 : // safety check, the timeout should be done by the radio
361 0 : if(this->mod->hal->millis() - start > timeoutInternal) {
362 0 : softTimeout = true;
363 0 : break;
364 : }
365 : }
366 :
367 : // if it was a timeout, this will return an error code
368 : //! \TODO: [LR2021] taken from SX126x, does this really work?
369 0 : state = standby();
370 0 : if((state != RADIOLIB_ERR_NONE) && (state != RADIOLIB_ERR_SPI_CMD_TIMEOUT)) {
371 0 : return(state);
372 : }
373 :
374 : // check whether this was a timeout or not
375 0 : if(softTimeout || (getIrqFlags() & this->irqMap[RADIOLIB_IRQ_TIMEOUT])) {
376 0 : (void)finishReceive();
377 0 : return(RADIOLIB_ERR_RX_TIMEOUT);
378 : }
379 :
380 : // read the received data
381 0 : return(readData(data, len));
382 : }
383 :
384 1 : int16_t LR2021::transmitDirect(uint32_t frf) {
385 : // set RF switch (if present)
386 1 : this->mod->setRfSwitchState(Module::MODE_TX);
387 :
388 : // user requested to start transmitting immediately (required for RTTY)
389 1 : int16_t state = RADIOLIB_ERR_NONE;
390 1 : if(frf != 0) {
391 0 : state = setRfFrequency(frf);
392 : }
393 1 : RADIOLIB_ASSERT(state);
394 :
395 : // start transmitting
396 1 : return(setTxTestMode(RADIOLIB_LR2021_TX_TEST_MODE_CW));
397 : }
398 :
399 1 : int16_t LR2021::receiveDirect() {
400 : // set RF switch (if present)
401 1 : this->mod->setRfSwitchState(Module::MODE_RX);
402 :
403 : // LR2021 is unable to output received data directly
404 1 : return(RADIOLIB_ERR_UNKNOWN);
405 : }
406 :
407 1 : int16_t LR2021::scanChannel() {
408 1 : ChannelScanConfig_t cfg = {
409 : .cad = {
410 : .symNum = RADIOLIB_LR2021_CAD_PARAM_DEFAULT,
411 : .detPeak = RADIOLIB_LR2021_CAD_PARAM_DEFAULT,
412 : .detMin = RADIOLIB_LR2021_CAD_PARAM_DEFAULT,
413 : .exitMode = RADIOLIB_LR2021_CAD_PARAM_DEFAULT,
414 : .timeout = 0,
415 : .irqFlags = RADIOLIB_IRQ_CAD_DEFAULT_FLAGS,
416 : .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK,
417 : },
418 : };
419 2 : return(this->scanChannel(cfg));
420 : }
421 :
422 2 : int16_t LR2021::scanChannel(const ChannelScanConfig_t &cfg) {
423 : // set mode to CAD
424 2 : int state = startChannelScan(cfg);
425 2 : RADIOLIB_ASSERT(state);
426 :
427 : // wait for channel activity detected or timeout
428 0 : while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
429 0 : this->mod->hal->yield();
430 : }
431 :
432 : // check CAD result
433 0 : return(getChannelScanResult());
434 : }
435 :
436 5 : int16_t LR2021::standby() {
437 5 : return(this->standby(RADIOLIB_LR2021_STANDBY_RC));
438 : }
439 :
440 6 : int16_t LR2021::standby(uint8_t mode) {
441 6 : return(this->standby(mode, true));
442 : }
443 :
444 6 : int16_t LR2021::standby(uint8_t mode, bool wakeup) {
445 : // set RF switch (if present)
446 6 : this->mod->setRfSwitchState(Module::MODE_IDLE);
447 :
448 6 : if(wakeup) {
449 : // send a NOP command - this pulls the NSS low to exit the sleep mode,
450 : // while preventing interference with possible other SPI transactions
451 6 : (void)this->mod->SPIwriteStream((uint16_t)RADIOLIB_LR2021_CMD_NOP, NULL, 0, false, false);
452 : }
453 :
454 6 : uint8_t buff[] = { mode };
455 12 : return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_STANDBY, true, buff, sizeof(buff)));
456 : }
457 :
458 1 : int16_t LR2021::sleep() {
459 1 : return(this->sleep(true, 0));
460 : }
461 :
462 1 : int16_t LR2021::sleep(bool retainConfig, uint32_t sleepTime) {
463 : // set RF switch (if present)
464 1 : this->mod->setRfSwitchState(Module::MODE_IDLE);
465 :
466 : uint8_t buff[] = { (uint8_t)(retainConfig ? RADIOLIB_LR2021_SLEEP_RETENTION_ENABLED : RADIOLIB_LR2021_SLEEP_RETENTION_DISABLED),
467 1 : (uint8_t)((sleepTime >> 24) & 0xFF), (uint8_t)((sleepTime >> 16) & 0xFF),
468 1 : (uint8_t)((sleepTime >> 8) & 0xFF), (uint8_t)(sleepTime & 0xFF),
469 1 : };
470 :
471 : // in sleep, the busy line will remain high, so we have to use this method to disable waiting for it to go low
472 1 : int16_t state = this->mod->SPIwriteStream(RADIOLIB_LR2021_CMD_SET_SLEEP, buff, sizeof(buff), false, false);
473 :
474 : // wait for the module to safely enter sleep mode
475 1 : this->mod->hal->delay(1);
476 :
477 1 : return(state);
478 : }
479 :
480 1 : size_t LR2021::getPacketLength(bool update) {
481 : (void)update;
482 :
483 : // in implicit mode, return the cached value
484 1 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
485 1 : (void)getPacketType(&type);
486 1 : if((type == RADIOLIB_LR2021_PACKET_TYPE_LORA) && (this->headerType == RADIOLIB_LR2021_LORA_HEADER_IMPLICIT)) {
487 0 : return(this->implicitLen);
488 : }
489 :
490 1 : uint16_t len = 0;
491 1 : (void)getRxPktLength(&len);
492 1 : return((size_t)len);
493 : }
494 :
495 1 : int16_t LR2021::finishTransmit() {
496 : // clear interrupt flags
497 1 : clearIrqState(RADIOLIB_LR2021_IRQ_ALL);
498 :
499 : // set mode to standby to disable transmitter/RF switch
500 1 : return(standby());
501 : }
502 :
503 1 : int16_t LR2021::startReceive() {
504 1 : return(this->startReceive(RADIOLIB_LR2021_RX_TIMEOUT_INF, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0));
505 : }
506 :
507 0 : int16_t LR2021::startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask) {
508 : // datasheet claims time to go to sleep is ~500us, same to wake up, compensate for that with 1 ms + TCXO delay
509 0 : uint32_t transitionTime = this->tcxoDelay + 1000;
510 0 : sleepPeriod -= transitionTime;
511 :
512 : // divide by 30.517 microseconds (RTC period, 1/32.768 kHz)
513 : // the datasheet claims the RTC frequency is 32 kHz; however, using that makes the timing inaccurate
514 : // so it looks like the actual value is the 32.768 kHz used on the previous LR11xx chips
515 0 : uint32_t rxPeriodRaw = (rxPeriod * 32768UL) / 1000000UL;
516 0 : uint32_t sleepPeriodRaw = (sleepPeriod * 32768UL) / 1000000UL;
517 :
518 : // check 24 bit limit and zero value (likely not intended)
519 0 : if((rxPeriodRaw & 0xFF000000) || (rxPeriodRaw == 0)) {
520 0 : return(RADIOLIB_ERR_INVALID_RX_PERIOD);
521 : }
522 :
523 : // this check of the high byte also catches underflow when we subtracted transitionTime
524 0 : if((sleepPeriodRaw & 0xFF000000) || (sleepPeriodRaw == 0)) {
525 0 : return(RADIOLIB_ERR_INVALID_SLEEP_PERIOD);
526 : }
527 :
528 : // set up Rx mode
529 0 : RadioModeConfig_t cfg = {
530 : .receive = {
531 : .timeout = RADIOLIB_LR2021_RX_TIMEOUT_INF,
532 : .irqFlags = irqFlags,
533 : .irqMask = irqMask,
534 : .len = 0,
535 : }
536 0 : };
537 0 : int16_t state = this->stageMode(RADIOLIB_RADIO_MODE_RX, &cfg);
538 0 : RADIOLIB_ASSERT(state);
539 :
540 : // on LR2021, the second parameter is total period of the cycle, not the sleep duration
541 0 : return(this->setRxDutyCycle(rxPeriodRaw, rxPeriodRaw + sleepPeriodRaw, RADIOLIB_LR2021_RX_DUTY_CYCLE_MODE_RX));
542 : }
543 :
544 0 : int16_t LR2021::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_t minSymbols, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask) {
545 : // calculate the sleep and wake periods
546 0 : uint32_t wakePeriod = 0;
547 0 : uint32_t sleepPeriod = 0;
548 : DataRate_t dr = {
549 : .lora = {
550 0 : .spreadingFactor = this->spreadingFactor,
551 0 : .bandwidth = this->bandwidthKhz,
552 0 : .codingRate = this->codingRate,
553 : }
554 0 : };
555 0 : int16_t state = calculateRxDutyCycle(senderPreambleLength, this->preambleLengthLoRa, minSymbols, &dr, &wakePeriod, &sleepPeriod);
556 0 : RADIOLIB_ASSERT(state);
557 :
558 : // If our sleep period is shorter than our transition time, just use the standard startReceive
559 0 : if(sleepPeriod < this->tcxoDelay + 1016) {
560 0 : return(startReceive(RADIOLIB_LR2021_RX_TIMEOUT_INF, irqFlags, irqMask));
561 : }
562 :
563 0 : return(startReceiveDutyCycle(wakePeriod, sleepPeriod, irqFlags, irqMask));
564 : }
565 :
566 1 : int16_t LR2021::readData(uint8_t* data, size_t len) {
567 : // check active modem
568 1 : int16_t state = RADIOLIB_ERR_NONE;
569 1 : uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
570 1 : state = getPacketType(&modem);
571 1 : RADIOLIB_ASSERT(state);
572 0 : if((modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) &&
573 0 : (modem != RADIOLIB_LR2021_PACKET_TYPE_GFSK) &&
574 0 : (modem != RADIOLIB_LR2021_PACKET_TYPE_FLRC) &&
575 0 : (modem != RADIOLIB_LR2021_PACKET_TYPE_OOK)) {
576 0 : return(RADIOLIB_ERR_WRONG_MODEM);
577 : }
578 :
579 : // check integrity CRC
580 0 : uint32_t irq = getIrqStatus();
581 0 : int16_t crcState = RADIOLIB_ERR_NONE;
582 : // report CRC mismatch when there's a payload CRC error
583 0 : if(irq & RADIOLIB_LR2021_IRQ_CRC_ERROR) {
584 0 : crcState = RADIOLIB_ERR_CRC_MISMATCH;
585 : }
586 :
587 : // for LoRa modem and explicit header mode, check also also header valid flag
588 0 : if((modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) &&
589 0 : (this->headerType == RADIOLIB_LR2021_LORA_HEADER_EXPLICIT) &&
590 0 : (!(irq & RADIOLIB_LR2021_IRQ_LORA_HEADER_VALID))) {
591 0 : crcState = RADIOLIB_ERR_LORA_HEADER_DAMAGED;
592 : }
593 :
594 : // get packet length
595 0 : size_t length = getPacketLength();
596 0 : if((len != 0) && (len < length)) {
597 : // user requested less data than we got, only return what was requested
598 0 : length = len;
599 : }
600 :
601 : // read packet data
602 0 : state = readRadioRxFifo(data, length);
603 0 : RADIOLIB_ASSERT(state);
604 :
605 : // clear the Rx buffer
606 0 : state = clearRxFifo();
607 0 : RADIOLIB_ASSERT(state);
608 :
609 : // clear interrupt flags
610 0 : state = clearIrqState(RADIOLIB_LR2021_IRQ_ALL);
611 :
612 : // check if CRC failed - this is done after reading data to give user the option to keep them
613 0 : RADIOLIB_ASSERT(crcState);
614 :
615 0 : return(state);
616 : }
617 :
618 1 : int16_t LR2021::finishReceive() {
619 : // set mode to standby to disable RF switch
620 1 : int16_t state = standby();
621 1 : RADIOLIB_ASSERT(state);
622 :
623 : // clear interrupt flags
624 0 : return(clearIrqState(RADIOLIB_LR2021_IRQ_ALL));
625 : }
626 :
627 1 : int16_t LR2021::startChannelScan() {
628 1 : ChannelScanConfig_t cfg = {
629 : .cad = {
630 : .symNum = RADIOLIB_LR2021_CAD_PARAM_DEFAULT,
631 : .detPeak = RADIOLIB_LR2021_CAD_PARAM_DEFAULT,
632 : .detMin = RADIOLIB_LR2021_CAD_PARAM_DEFAULT,
633 : .exitMode = RADIOLIB_LR2021_CAD_PARAM_DEFAULT,
634 : .timeout = 0,
635 : .irqFlags = RADIOLIB_IRQ_CAD_DEFAULT_FLAGS,
636 : .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK,
637 : },
638 : };
639 2 : return(this->startChannelScan(cfg));
640 : }
641 :
642 4 : int16_t LR2021::startChannelScan(const ChannelScanConfig_t &cfg) {
643 : // check active modem
644 4 : int16_t state = RADIOLIB_ERR_NONE;
645 4 : uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
646 4 : state = getPacketType(&modem);
647 4 : RADIOLIB_ASSERT(state);
648 0 : if(modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
649 0 : return(RADIOLIB_ERR_WRONG_MODEM);
650 : }
651 :
652 : // set mode to standby
653 0 : state = standby();
654 0 : RADIOLIB_ASSERT(state);
655 :
656 : // set RF switch (if present)
657 0 : this->mod->setRfSwitchState(Module::MODE_RX);
658 :
659 : // set DIO pin mapping
660 0 : uint32_t irqFlags = (cfg.cad.irqFlags == RADIOLIB_IRQ_NOT_SUPPORTED) ? RADIOLIB_LR2021_IRQ_CAD_DETECTED | RADIOLIB_LR2021_IRQ_CAD_DONE : cfg.cad.irqFlags;
661 0 : state = setDioIrqConfig(this->irqDioNum, getIrqMapped(irqFlags));
662 0 : RADIOLIB_ASSERT(state);
663 :
664 : // clear interrupt flags
665 0 : state = clearIrqState(RADIOLIB_LR2021_IRQ_ALL);
666 0 : RADIOLIB_ASSERT(state);
667 :
668 : // set mode to CAD
669 0 : return(startCad(cfg.cad.symNum, cfg.cad.detPeak, this->fastCad, cfg.cad.exitMode, cfg.cad.timeout));
670 : }
671 :
672 1 : int16_t LR2021::getChannelScanResult() {
673 : // check active modem
674 1 : int16_t state = RADIOLIB_ERR_NONE;
675 1 : uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
676 1 : state = getPacketType(&modem);
677 1 : RADIOLIB_ASSERT(state);
678 0 : if(modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
679 0 : return(RADIOLIB_ERR_WRONG_MODEM);
680 : }
681 :
682 : // check CAD result
683 0 : uint32_t cadResult = getIrqStatus();
684 0 : if(cadResult & RADIOLIB_LR2021_IRQ_CAD_DETECTED) {
685 : // detected some LoRa activity
686 0 : return(RADIOLIB_LORA_DETECTED);
687 0 : } else if(cadResult & RADIOLIB_LR2021_IRQ_CAD_DONE) {
688 : // channel is free
689 0 : return(RADIOLIB_CHANNEL_FREE);
690 : }
691 :
692 0 : return(RADIOLIB_ERR_UNKNOWN);
693 : }
694 :
695 1 : uint32_t LR2021::getIrqFlags() {
696 1 : return(getIrqStatus());
697 : }
698 :
699 1 : int16_t LR2021::setIrqFlags(uint32_t irq) {
700 1 : return(this->setDioIrqConfig(this->irqDioNum, irq));
701 : }
702 :
703 1 : int16_t LR2021::clearIrqFlags(uint32_t irq) {
704 1 : return(this->clearIrqState(irq));
705 : }
706 :
707 1 : int16_t LR2021::setModem(ModemType_t modem) {
708 1 : switch(modem) {
709 0 : case(ModemType_t::RADIOLIB_MODEM_LORA): {
710 0 : return(this->begin());
711 : } break;
712 0 : case(ModemType_t::RADIOLIB_MODEM_FSK): {
713 0 : return(this->beginGFSK());
714 : } break;
715 0 : case(ModemType_t::RADIOLIB_MODEM_LRFHSS): {
716 0 : return(this->beginLRFHSS());
717 : } break;
718 1 : default:
719 1 : return(RADIOLIB_ERR_WRONG_MODEM);
720 : }
721 : }
722 :
723 0 : Module* LR2021::getMod() {
724 0 : return(this->mod);
725 : }
726 :
727 0 : int16_t LR2021::modSetup(float freq, uint8_t modem) {
728 0 : this->mod->init();
729 0 : this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
730 0 : this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput);
731 0 : this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_LR2021_CMD_READ_REG_MEM_32;
732 0 : this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_LR2021_CMD_WRITE_REG_MEM_32;
733 0 : this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_LR2021_CMD_NOP;
734 0 : this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_LR2021_CMD_GET_STATUS;
735 0 : this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_24;
736 0 : this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_STATUS] = Module::BITS_16;
737 :
738 : // try to find the chip - this will also reset the module at least once
739 0 : if(!this->findChip()) {
740 : RADIOLIB_DEBUG_BASIC_PRINTLN("No LR2021 found!");
741 0 : this->mod->term();
742 0 : return(RADIOLIB_ERR_CHIP_NOT_FOUND);
743 : }
744 : RADIOLIB_DEBUG_BASIC_PRINTLN("M\tLR2021");
745 :
746 : // set mode to standby
747 0 : int16_t state = standby();
748 0 : RADIOLIB_ASSERT(state);
749 :
750 : // set TCXO control, if requested
751 0 : if(this->tcxoVoltage > 0.0f) {
752 0 : state = setTCXO(this->tcxoVoltage);
753 0 : RADIOLIB_ASSERT(state);
754 : }
755 :
756 : // configure settings not accessible by API
757 0 : state = config(modem);
758 0 : RADIOLIB_ASSERT(state);
759 :
760 0 : state = setFrequency(freq);
761 0 : return(state);
762 : }
763 :
764 0 : bool LR2021::findChip(void) {
765 : // this is the only version mentioned in datasheet
766 0 : const uint8_t expMajor = 0x01;
767 0 : const uint8_t expMinor = 0x18;
768 :
769 0 : uint8_t i = 0;
770 0 : bool flagFound = false;
771 0 : uint8_t fwMajor = 0, fwMinor = 0;
772 0 : while((i < 10) && !flagFound) {
773 : // reset the module
774 0 : reset();
775 :
776 : // read the version
777 0 : int16_t state = getVersion(&fwMajor, &fwMinor);
778 0 : RADIOLIB_ASSERT(state);
779 :
780 0 : if((fwMajor == expMajor) && (fwMinor == expMinor)) {
781 : RADIOLIB_DEBUG_BASIC_PRINTLN("Found LR2021");
782 : RADIOLIB_DEBUG_BASIC_PRINTLN("Base FW version: %d.%d", (int)fwMajor, (int)fwMinor);
783 0 : flagFound = true;
784 : } else {
785 : RADIOLIB_DEBUG_BASIC_PRINTLN("LR2021 not found! (%d of 10 tries) FW version: = %d.%d", (int)i, (int)fwMajor, (int)fwMinor);
786 : RADIOLIB_DEBUG_BASIC_PRINTLN("Expected: %d.%d", (int)expMajor, (int)expMinor);
787 0 : this->mod->hal->delay(10);
788 0 : i++;
789 : }
790 : }
791 :
792 0 : return(flagFound);
793 : }
794 :
795 0 : int16_t LR2021::config(uint8_t modem) {
796 : // set Rx/Tx fallback mode to STDBY_RC
797 0 : int16_t state = this->setRxTxFallbackMode(RADIOLIB_LR2021_FALLBACK_MODE_STBY_RC);
798 0 : RADIOLIB_ASSERT(state);
799 :
800 : // clear IRQ
801 0 : state = this->clearIrqState(RADIOLIB_LR2021_IRQ_ALL);
802 0 : RADIOLIB_ASSERT(state);
803 :
804 : // validate DIO pin number
805 0 : if((this->irqDioNum < 5) || (this->irqDioNum > 11)) {
806 0 : return(RADIOLIB_ERR_INVALID_DIO_PIN);
807 : }
808 :
809 : // set the DIO to IRQ
810 : // DIO5 can only be pull up
811 0 : uint8_t pull = this->irqDioNum == 5 ? RADIOLIB_LR2021_DIO_SLEEP_PULL_UP : RADIOLIB_LR2021_DIO_SLEEP_PULL_DOWN;
812 0 : state = this->setDioFunction(this->irqDioNum, RADIOLIB_LR2021_DIO_FUNCTION_IRQ, pull);
813 0 : RADIOLIB_ASSERT(state);
814 :
815 : // calibrate all blocks
816 0 : state = this->calibrate(RADIOLIB_LR2021_CALIBRATE_ALL);
817 :
818 : // wait for calibration completion
819 0 : this->mod->hal->delay(5);
820 0 : while(this->mod->hal->digitalRead(this->mod->getGpio())) {
821 0 : this->mod->hal->yield();
822 : }
823 :
824 : // if something failed, show the device errors
825 : #if RADIOLIB_DEBUG_BASIC
826 : if(state != RADIOLIB_ERR_NONE) {
827 : uint16_t errors = 0;
828 : getErrors(&errors);
829 : RADIOLIB_DEBUG_BASIC_PRINTLN("Calibration failed, device errors: 0x%X", errors);
830 : }
831 : #else
832 0 : RADIOLIB_ASSERT(state);
833 : #endif
834 :
835 : // set modem
836 0 : state = this->setPacketType(modem);
837 0 : return(state);
838 : }
839 :
840 0 : int16_t LR2021::startCad(uint8_t symbolNum, uint8_t detPeak, bool fast, uint8_t exitMode, RadioLibTime_t timeout) {
841 : // check active modem
842 0 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
843 0 : int16_t state = getPacketType(&type);
844 0 : RADIOLIB_ASSERT(state);
845 0 : if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
846 0 : return(RADIOLIB_ERR_WRONG_MODEM);
847 : }
848 :
849 : // select CAD parameters
850 0 : uint8_t num = symbolNum;
851 0 : if(num == RADIOLIB_LR2021_CAD_PARAM_DEFAULT) {
852 0 : num = 2;
853 : }
854 :
855 : // reference values from the datasheet for 2 symbols
856 : //! \TODO: [LR2021] allow CAD peak detection autoconfiguration
857 0 : const uint8_t detPeakValues[8] = { 56, 56, 56, 58, 58, 60, 64, 68 };
858 0 : uint8_t peak = detPeak;
859 0 : if(peak == RADIOLIB_LR2021_CAD_PARAM_DEFAULT) {
860 0 : peak = detPeakValues[this->spreadingFactor - 5];
861 : }
862 :
863 : // in Fast CAD mode enable acceleration
864 0 : uint8_t pnrDelta = fast ? RADIOLIB_LR2021_LORA_CAD_PNR_DELTA_FAST : RADIOLIB_LR2021_LORA_CAD_PNR_DELTA_STANDARD;
865 :
866 0 : uint8_t mode = exitMode;
867 0 : if(mode == RADIOLIB_LR2021_CAD_PARAM_DEFAULT) {
868 0 : mode = RADIOLIB_LR2021_CAD_EXIT_MODE_FALLBACK;
869 : }
870 :
871 0 : uint32_t timeout_raw = (float)timeout / 30.52f;
872 :
873 : // set LoRa CAD parameters
874 : // preamble only mode is intentionally disabled, as it is unreliable according to the datasheet
875 0 : state = setLoRaCadParams(num, false, pnrDelta, mode, timeout_raw, peak);
876 0 : RADIOLIB_ASSERT(state);
877 :
878 : // start LoraCAD
879 0 : return(setLoRaCad());
880 : }
881 :
882 1 : RadioLibTime_t LR2021::getTimeOnAir(size_t len) {
883 1 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
884 1 : int16_t state = getPacketType(&type);
885 1 : RADIOLIB_ASSERT(state);
886 :
887 0 : switch(type) {
888 : // basic modems are supported by the LRxxxx base class
889 0 : case(RADIOLIB_LR2021_PACKET_TYPE_LORA):
890 0 : return(LRxxxx::getToA(len, ModemType_t::RADIOLIB_MODEM_LORA));
891 0 : case(RADIOLIB_LR2021_PACKET_TYPE_GFSK):
892 0 : return(LRxxxx::getToA(len, ModemType_t::RADIOLIB_MODEM_FSK));
893 0 : case(RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS):
894 0 : return(LRxxxx::getToA(len, ModemType_t::RADIOLIB_MODEM_LRFHSS));
895 0 : case(RADIOLIB_LR2021_PACKET_TYPE_FLRC): {
896 : //! \todo [LR2021] Add FLRC to the modems supported in ModemType_t
897 :
898 : // calculate the bits of the uncoded part of the packet
899 0 : size_t n_uncoded_bits = (this->preambleLengthGFSK + 1)*4 + 21 + this->syncWordLength*8;
900 0 : if(this->packetType != RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) { n_uncoded_bits+= 16; }
901 :
902 : // calculate bits in the coded part
903 0 : size_t n_coded_bits = len*8;
904 0 : if(this->crcLenGFSK != 0) { n_coded_bits += (this->crcLenGFSK + 1)*8; }
905 0 : if(this->codingRateFlrc <= RADIOLIB_LR2021_FLRC_CR_3_4) { n_coded_bits += 6; }
906 0 : float n_coded_bits_flt = n_coded_bits;
907 0 : switch(this->codingRateFlrc) {
908 0 : case(RADIOLIB_LR2021_FLRC_CR_1_2):
909 0 : n_coded_bits += 6;
910 0 : n_coded_bits_flt = (float)n_coded_bits*2.0f;
911 0 : break;
912 0 : case(RADIOLIB_LR2021_FLRC_CR_3_4):
913 0 : n_coded_bits += 6;
914 0 : n_coded_bits_flt = ((float)n_coded_bits*4.0f)/3.0f;
915 0 : break;
916 0 : case(RADIOLIB_LR2021_FLRC_CR_2_3):
917 0 : n_coded_bits_flt = ((float)n_coded_bits*3.0f)/2.0f;
918 0 : break;
919 : }
920 0 : n_coded_bits = n_coded_bits_flt + 0.5f;
921 :
922 : // now calculate the real time on air
923 0 : return((float)(n_uncoded_bits + n_coded_bits) / (float)(this->bitRate / 1000.0f));
924 : }
925 : }
926 :
927 : RADIOLIB_DEBUG_BASIC_PRINTLN("Called getTimeOnAir() for invalid modem (%02x)!", type);
928 0 : return(0);
929 : }
930 :
931 3 : int16_t LR2021::getModem(ModemType_t* modem) {
932 3 : RADIOLIB_ASSERT_PTR(modem);
933 :
934 3 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
935 3 : int16_t state = getPacketType(&type);
936 3 : RADIOLIB_ASSERT(state);
937 :
938 0 : switch(type) {
939 0 : case(RADIOLIB_LR2021_PACKET_TYPE_LORA):
940 0 : *modem = ModemType_t::RADIOLIB_MODEM_LORA;
941 0 : return(RADIOLIB_ERR_NONE);
942 0 : case(RADIOLIB_LR2021_PACKET_TYPE_GFSK):
943 0 : *modem = ModemType_t::RADIOLIB_MODEM_FSK;
944 0 : return(RADIOLIB_ERR_NONE);
945 0 : case(RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS):
946 0 : *modem = ModemType_t::RADIOLIB_MODEM_LRFHSS;
947 0 : return(RADIOLIB_ERR_NONE);
948 : }
949 :
950 0 : return(RADIOLIB_ERR_WRONG_MODEM);
951 : }
952 :
953 4 : int16_t LR2021::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) {
954 : int16_t state;
955 :
956 4 : switch(mode) {
957 3 : case(RADIOLIB_RADIO_MODE_RX): {
958 : // check active modem
959 3 : uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
960 3 : state = getPacketType(&modem);
961 3 : RADIOLIB_ASSERT(state);
962 0 : if((modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) &&
963 0 : (modem != RADIOLIB_LR2021_PACKET_TYPE_GFSK) &&
964 0 : (modem != RADIOLIB_LR2021_PACKET_TYPE_FLRC) &&
965 0 : (modem != RADIOLIB_LR2021_PACKET_TYPE_OOK)) {
966 0 : return(RADIOLIB_ERR_WRONG_MODEM);
967 : }
968 :
969 : // set the correct Rx path
970 0 : state = setRxPath(this->highFreq ? RADIOLIB_LR2021_RX_PATH_HF : RADIOLIB_LR2021_RX_PATH_LF, this->highFreq ? this->gainModeHf : this->gainModeLf);
971 0 : RADIOLIB_ASSERT(state);
972 :
973 : // set DIO mapping
974 0 : if(cfg->receive.timeout != RADIOLIB_LR2021_RX_TIMEOUT_INF) {
975 0 : cfg->receive.irqMask |= (1UL << RADIOLIB_IRQ_TIMEOUT);
976 : }
977 0 : state = setDioIrqConfig(this->irqDioNum, getIrqMapped(cfg->receive.irqFlags & cfg->receive.irqMask));
978 0 : RADIOLIB_ASSERT(state);
979 :
980 : // clear interrupt flags
981 0 : state = clearIrqState(RADIOLIB_LR2021_IRQ_ALL);
982 0 : RADIOLIB_ASSERT(state);
983 :
984 : // set implicit mode and expected len if applicable
985 0 : if((this->headerType == RADIOLIB_LR2021_LORA_HEADER_IMPLICIT) && (modem == RADIOLIB_LR2021_PACKET_TYPE_LORA)) {
986 0 : state = setLoRaPacketParams(this->preambleLengthLoRa, this->headerType,
987 0 : (this->headerType == RADIOLIB_LR2021_LORA_HEADER_IMPLICIT) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeLoRa, this->invertIQEnabled);
988 0 : RADIOLIB_ASSERT(state);
989 : }
990 :
991 : // if max(uint32_t) is used, revert to RxContinuous
992 0 : if(cfg->receive.timeout == 0xFFFFFFFF) {
993 0 : cfg->receive.timeout = 0xFFFFFF;
994 : }
995 0 : this->rxTimeout = cfg->receive.timeout;
996 0 : } break;
997 :
998 1 : case(RADIOLIB_RADIO_MODE_TX): {
999 : // check packet length
1000 1 : if(cfg->transmit.len > RADIOLIB_LR2021_MAX_PACKET_LENGTH) {
1001 1 : return(RADIOLIB_ERR_PACKET_TOO_LONG);
1002 : }
1003 :
1004 : // maximum packet length is decreased by 1 when address filtering is active
1005 : //! \todo [LR2021] implement GFSK address filtering
1006 :
1007 : // set packet Length
1008 1 : uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
1009 1 : state = getPacketType(&modem);
1010 1 : RADIOLIB_ASSERT(state);
1011 0 : if(modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) {
1012 0 : state = setLoRaPacketParams(this->preambleLengthLoRa, this->headerType, cfg->transmit.len, this->crcTypeLoRa, this->invertIQEnabled);
1013 :
1014 0 : } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
1015 0 : state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, cfg->transmit.len, this->crcTypeGFSK, this->whitening);
1016 :
1017 0 : } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_OOK) {
1018 0 : state = setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, cfg->transmit.len, this->crcTypeGFSK, this->whitening);
1019 :
1020 0 : } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
1021 0 : state = setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, cfg->transmit.len);
1022 :
1023 : } else {
1024 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1025 : }
1026 :
1027 0 : RADIOLIB_ASSERT(state);
1028 :
1029 : // set DIO mapping
1030 0 : state = setDioIrqConfig(this->irqDioNum, RADIOLIB_LR2021_IRQ_TX_DONE | RADIOLIB_LR2021_IRQ_TIMEOUT);
1031 0 : RADIOLIB_ASSERT(state);
1032 :
1033 0 : if(modem == RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS) {
1034 : // in LR-FHSS mode, the packet is built by the device
1035 : //! \todo [LR2021] add configurable LR-FHSS device offset
1036 0 : state = LRxxxx::lrFhssBuildFrame(RADIOLIB_LR2021_CMD_LR_FHSS_BUILD_FRAME, this->lrFhssHdrCount, this->lrFhssCr, this->lrFhssGrid, true, this->lrFhssBw, this->lrFhssHopSeq, 0, cfg->transmit.data, cfg->transmit.len);
1037 0 : RADIOLIB_ASSERT(state);
1038 :
1039 : } else {
1040 : // write packet to buffer
1041 0 : state = writeRadioTxFifo(cfg->transmit.data, cfg->transmit.len);
1042 0 : RADIOLIB_ASSERT(state);
1043 :
1044 : }
1045 :
1046 : // clear interrupt flags
1047 0 : state = clearIrqState(RADIOLIB_LR2021_IRQ_ALL);
1048 0 : RADIOLIB_ASSERT(state);
1049 0 : } break;
1050 :
1051 0 : default:
1052 0 : return(RADIOLIB_ERR_UNSUPPORTED);
1053 : }
1054 :
1055 0 : this->stagedMode = mode;
1056 0 : return(state);
1057 : }
1058 :
1059 1 : int16_t LR2021::launchMode() {
1060 : int16_t state;
1061 1 : switch(this->stagedMode) {
1062 1 : case(RADIOLIB_RADIO_MODE_RX): {
1063 1 : this->mod->setRfSwitchState(Module::MODE_RX);
1064 1 : state = setRx(this->rxTimeout);
1065 1 : } break;
1066 :
1067 0 : case(RADIOLIB_RADIO_MODE_TX): {
1068 0 : this->mod->setRfSwitchState(Module::MODE_TX);
1069 0 : state = setTx(RADIOLIB_LR2021_TX_TIMEOUT_NONE);
1070 0 : RADIOLIB_ASSERT(state);
1071 :
1072 : // wait for BUSY to go low (= PA ramp up done)
1073 0 : while(this->mod->hal->digitalRead(this->mod->getGpio())) {
1074 0 : this->mod->hal->yield();
1075 : }
1076 0 : } break;
1077 :
1078 0 : default:
1079 0 : return(RADIOLIB_ERR_UNSUPPORTED);
1080 : }
1081 :
1082 1 : this->stagedMode = RADIOLIB_RADIO_MODE_NONE;
1083 1 : return(state);
1084 : }
1085 :
1086 0 : float LR2021::getVoltage(uint8_t bits) {
1087 0 : if((bits < 8) || (bits > 13)) {
1088 0 : return(0);
1089 : }
1090 :
1091 : uint16_t val;
1092 0 : if(getVbat(bits, &val) != RADIOLIB_ERR_NONE) {
1093 0 : return(0);
1094 : }
1095 :
1096 0 : return((float)val / 1000.0f);
1097 : }
1098 :
1099 0 : float LR2021::getTemperature(uint8_t source, uint8_t bits) {
1100 0 : if((bits < 8) || (bits > 13)) {
1101 0 : return(0);
1102 : }
1103 :
1104 : float val;
1105 0 : if(getTemp(source, bits, &val) != RADIOLIB_ERR_NONE) {
1106 0 : return(0);
1107 : }
1108 :
1109 0 : return(val);
1110 : }
1111 :
1112 1 : float LR2021::getRSSI() {
1113 1 : return(this->getRSSI(true));
1114 : }
1115 :
1116 1 : float LR2021::getRSSI(bool packet, bool skipReceive) {
1117 1 : float rssi = 0;
1118 : int16_t state;
1119 1 : if(!packet) {
1120 : // get instantaneous RSSI value
1121 0 : if(!skipReceive) { (void)startReceive(); }
1122 0 : state = this->getRssiInst(&rssi);
1123 0 : if(!skipReceive) { (void)standby(); }
1124 0 : if(state != RADIOLIB_ERR_NONE) { return(0); }
1125 0 : return(rssi);
1126 : }
1127 :
1128 : // check modem type
1129 1 : uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
1130 1 : state = this->getPacketType(&modem);
1131 1 : if(state != RADIOLIB_ERR_NONE) { return(0); }
1132 0 : if(modem == RADIOLIB_LR2021_PACKET_TYPE_LORA) {
1133 0 : state = this->getLoRaPacketStatus(NULL, NULL, NULL, NULL, &rssi, NULL);
1134 0 : } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
1135 0 : state = this->getGfskPacketStatus(NULL, &rssi, NULL, NULL, NULL, NULL);
1136 0 : } else if(modem == RADIOLIB_LR2021_PACKET_TYPE_OOK) {
1137 0 : state = this->getOokPacketStatus(NULL, NULL, &rssi, NULL, NULL, NULL);
1138 : } else {
1139 0 : return(0);
1140 : }
1141 :
1142 0 : if(state != RADIOLIB_ERR_NONE) { return(0); }
1143 0 : return(rssi);
1144 : }
1145 :
1146 1 : float LR2021::getSNR() {
1147 : float snr;
1148 1 : uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
1149 1 : int16_t state = this->getPacketType(&modem);
1150 1 : if(state != RADIOLIB_ERR_NONE) { return(0); }
1151 0 : if(modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) { return(0); }
1152 0 : state = this->getLoRaPacketStatus(NULL, NULL, NULL, &snr, NULL, NULL);
1153 0 : if(state != RADIOLIB_ERR_NONE) { return(0); }
1154 0 : return(snr);
1155 : }
1156 :
1157 1 : uint8_t LR2021::randomByte() {
1158 1 : uint32_t num = 0;
1159 1 : (void)getRandomNumber(&num);
1160 1 : return((uint8_t)num);
1161 : }
1162 :
1163 0 : int16_t LR2021::getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC){
1164 0 : return(this->getLoRaPacketStatus(cr, hasCRC, NULL, NULL, NULL, NULL));
1165 : }
1166 :
1167 : #endif
|