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