Line data Source code
1 : #include "LR2021.h"
2 :
3 : #include "../LR11x0/LR_common.h"
4 : #include "LR2021_registers.h"
5 :
6 : #include <math.h>
7 : #include <string.h>
8 :
9 : #if !RADIOLIB_EXCLUDE_LR2021
10 :
11 : // maximum number of allowed frontend calibration attempts
12 : #define RADIOLIB_LR2021_MAX_CAL_ATTEMPTS (10)
13 :
14 1 : int16_t LR2021::setFrequency(float freq) {
15 1 : return(this->setFrequency(freq, false));
16 : }
17 :
18 1 : int16_t LR2021::setFrequency(float freq, bool skipCalibration) {
19 : #if RADIOLIB_CHECK_PARAMS
20 1 : if(!(((freq >= 150.0f) && (freq <= 1090.0f)) ||
21 1 : ((freq >= 1900.0f) && (freq <= 2200.0f)) ||
22 1 : ((freq >= 2400.0f) && (freq <= 2500.0f)))) {
23 1 : return(RADIOLIB_ERR_INVALID_FREQUENCY);
24 : }
25 : #endif
26 :
27 : // check if we need to recalibrate image
28 : int16_t state;
29 0 : if(!skipCalibration && (fabsf(freq - this->freqMHz) >= RADIOLIB_LR2021_CAL_IMG_FREQ_TRIG_MHZ)) {
30 : // calibration can fail if there is a strong interfering source
31 : // run it several times until it passes
32 0 : int i = 0;
33 0 : for(; i < RADIOLIB_LR2021_MAX_CAL_ATTEMPTS; i++) {
34 : // get the nearest multiple of 4 MHz
35 0 : uint16_t frequencies[3] = { (uint16_t)((freq / 4.0f) + 0.5f), 0, 0 };
36 0 : frequencies[0] |= (freq > RADIOLIB_LR2021_LF_CUTOFF_FREQ) ? RADIOLIB_LR2021_CALIBRATE_FE_HF_PATH : RADIOLIB_LR2021_CALIBRATE_FE_LF_PATH;
37 0 : state = calibrateFrontEnd(const_cast<const uint16_t*>(frequencies));
38 :
39 : // if something failed, check the device errors
40 0 : if(state != RADIOLIB_ERR_NONE) {
41 0 : uint16_t errors = 0;
42 0 : getErrors(&errors);
43 : RADIOLIB_DEBUG_BASIC_PRINTLN("Frontend calibration #%d failed, device errors: 0x%X", i, errors);
44 :
45 : // if this is caused by something else than RSSI saturation, repeating will not help
46 0 : if((errors & RADIOLIB_LR2021_SRC_SATURATION_CALIB_ERR) == 0) {
47 0 : return(state);
48 : }
49 :
50 : // wait a little while before the next attempt
51 0 : this->mod->hal->delay(5);
52 :
53 : } else {
54 : // calibration passed
55 0 : break;
56 : }
57 :
58 : }
59 :
60 0 : if(i == RADIOLIB_LR2021_MAX_CAL_ATTEMPTS) {
61 0 : return(RADIOLIB_ERR_FRONTEND_CALIBRATION_FAILED);
62 : }
63 :
64 : }
65 :
66 : // set frequency
67 0 : state = setRfFrequency((uint32_t)(freq*1000000.0f));
68 0 : RADIOLIB_ASSERT(state);
69 0 : this->freqMHz = freq;
70 0 : this->highFreq = (freq > RADIOLIB_LR2021_LF_CUTOFF_FREQ);
71 0 : return(state);
72 : }
73 :
74 1 : int16_t LR2021::setOutputPower(int8_t power) {
75 1 : return(this->setOutputPower(power, 48));
76 : }
77 :
78 1 : int16_t LR2021::setOutputPower(int8_t power, uint32_t rampTimeUs) {
79 : // check if power value is configurable
80 1 : int16_t state = this->checkOutputPower(power, NULL);
81 1 : RADIOLIB_ASSERT(state);
82 :
83 : //! \TODO: [LR2021] how and when to configure OCP?
84 : //! \TODO: [LR2021] Determine the optimal PA configuration
85 : // update PA config
86 1 : state = setPaConfig(this->highFreq,
87 : RADIOLIB_LR2021_PA_LF_MODE_FSM,
88 : RADIOLIB_LR2021_PA_LF_DUTY_CYCLE_UNUSED,
89 : RADIOLIB_LR2021_PA_LF_SLICES_UNUSED,
90 : RADIOLIB_LR2021_PA_HF_DUTY_CYCLE_UNUSED);
91 1 : RADIOLIB_ASSERT(state);
92 :
93 : // set output power
94 0 : state = setTxParams(power, roundRampTime(rampTimeUs));
95 0 : return(state);
96 : }
97 :
98 2 : int16_t LR2021::checkOutputPower(int8_t power, int8_t* clipped) {
99 2 : if(this->highFreq) {
100 0 : if(clipped) {
101 0 : *clipped = RADIOLIB_MAX(-19, RADIOLIB_MIN(12, power));
102 : }
103 0 : RADIOLIB_CHECK_RANGE(power, -19, 12, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
104 :
105 : } else {
106 2 : if(clipped) {
107 0 : *clipped = RADIOLIB_MAX(-9, RADIOLIB_MIN(22, power));
108 : }
109 2 : RADIOLIB_CHECK_RANGE(power, -9, 22, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
110 :
111 : }
112 :
113 2 : return(RADIOLIB_ERR_NONE);
114 : }
115 :
116 0 : void LR2021::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) {
117 : // find which pins are used
118 : // on LR2021, modes are configured per DIO (exact opposite of LR11x0)
119 0 : uint8_t dioConfigs[7] = { 0 };
120 0 : for(size_t i = 0; i < Module::RFSWITCH_MAX_PINS; i++) {
121 : // check if this pin is unused
122 0 : if(pins[i] == RADIOLIB_NC) { continue; }
123 :
124 : // only keep DIO pins, there may be some GPIOs in the switch tabke
125 0 : if((pins[i] & RFSWITCH_PIN_FLAG) == 0) { continue; }
126 :
127 : // find modes in which this pin is used
128 0 : uint32_t dioNum = RADIOLIB_LRXXXX_DIOx_VAL(pins[i]);
129 0 : size_t j = 0;
130 0 : while(table[j].mode != LR2021::MODE_END_OF_TABLE) {
131 0 : dioConfigs[dioNum] |= (table[j].values[i] == this->mod->hal->GpioLevelHigh) ? (1UL << (table[j].mode - 1)) : 0;
132 0 : j++;
133 : }
134 :
135 : // For DIO = 5, only DIO_SLEEP_PULL_UP is accepted. Otherwise the SetDioFunction returns FAIL.
136 0 : uint8_t pull = dioNum == 0 ? RADIOLIB_LR2021_DIO_SLEEP_PULL_UP : RADIOLIB_LR2021_DIO_SLEEP_PULL_AUTO;
137 : // enable RF control for this pin and set the modes in which it is active
138 0 : (void)this->setDioFunction(dioNum + 5, RADIOLIB_LR2021_DIO_FUNCTION_RF_SWITCH, pull);
139 0 : (void)this->setDioRfSwitchConfig(dioNum + 5, dioConfigs[i]);
140 : }
141 0 : }
142 :
143 0 : int16_t LR2021::setBandwidth(float bw) {
144 : // check active modem
145 0 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
146 0 : int16_t state = getPacketType(&type);
147 0 : RADIOLIB_ASSERT(state);
148 0 : if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
149 0 : return(RADIOLIB_ERR_WRONG_MODEM);
150 : }
151 :
152 : // convert to int to avoid bunch of math
153 0 : int bw_div2 = bw / 2 + 0.01f;
154 :
155 : // check allowed bandwidth values
156 0 : switch (bw_div2) {
157 0 : case 15:
158 0 : this->bandwidth = RADIOLIB_LR2021_LORA_BW_31;
159 0 : break;
160 0 : case 20:
161 0 : this->bandwidth = RADIOLIB_LR2021_LORA_BW_41;
162 0 : break;
163 0 : case 31:
164 0 : this->bandwidth = RADIOLIB_LR2021_LORA_BW_62;
165 0 : break;
166 0 : case 41:
167 0 : this->bandwidth = RADIOLIB_LR2021_LORA_BW_83;
168 0 : break;
169 0 : case 50:
170 0 : this->bandwidth = RADIOLIB_LR2021_LORA_BW_101;
171 0 : break;
172 0 : case 101:
173 0 : this->bandwidth = RADIOLIB_LR2021_LORA_BW_203;
174 0 : break;
175 0 : case 62:
176 0 : this->bandwidth = RADIOLIB_LR2021_LORA_BW_125;
177 0 : break;
178 0 : case 125:
179 0 : this->bandwidth = RADIOLIB_LR2021_LORA_BW_250;
180 0 : break;
181 0 : case 203:
182 0 : this->bandwidth = RADIOLIB_LR2021_LORA_BW_406;
183 0 : break;
184 0 : case 250:
185 0 : this->bandwidth = RADIOLIB_LR2021_LORA_BW_500;
186 0 : break;
187 0 : case 406:
188 0 : this->bandwidth = RADIOLIB_LR2021_LORA_BW_812;
189 0 : break;
190 0 : case 500:
191 0 : this->bandwidth = RADIOLIB_LR2021_LORA_BW_1000;
192 0 : break;
193 0 : default:
194 0 : return(RADIOLIB_ERR_INVALID_BANDWIDTH);
195 : }
196 :
197 : // update modulation parameters
198 0 : this->bandwidthKhz = bw;
199 0 : return(setLoRaModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
200 : }
201 :
202 0 : int16_t LR2021::setSpreadingFactor(uint8_t sf, bool legacy) {
203 : // check active modem
204 0 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
205 0 : int16_t state = getPacketType(&type);
206 0 : RADIOLIB_ASSERT(state);
207 0 : if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
208 0 : return(RADIOLIB_ERR_WRONG_MODEM);
209 : }
210 :
211 0 : RADIOLIB_CHECK_RANGE(sf, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
212 :
213 : //! \TODO: [LR2021] enable SF6 legacy mode
214 : if(legacy && (sf == 6)) {
215 : //this->mod->SPIsetRegValue(RADIOLIB_LR11X0_REG_SF6_SX127X_COMPAT, RADIOLIB_LR11X0_SF6_SX127X, 18, 18);
216 : }
217 :
218 : // update modulation parameters
219 0 : this->spreadingFactor = sf;
220 0 : return(setLoRaModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
221 : }
222 :
223 0 : int16_t LR2021::setCodingRate(uint8_t cr, bool longInterleave) {
224 : // check active modem
225 0 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
226 0 : int16_t state = getPacketType(&type);
227 0 : RADIOLIB_ASSERT(state);
228 0 : if(type == RADIOLIB_LR2021_PACKET_TYPE_LORA) {
229 0 : RADIOLIB_CHECK_RANGE(cr, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
230 :
231 0 : if(longInterleave) {
232 0 : switch(cr) {
233 0 : case 4:
234 0 : this->codingRate = 0;
235 0 : break;
236 0 : case 5:
237 : case 6:
238 0 : this->codingRate = cr;
239 0 : break;
240 0 : case 8:
241 0 : this->codingRate = cr - 1;
242 0 : break;
243 0 : default:
244 0 : return(RADIOLIB_ERR_INVALID_CODING_RATE);
245 : }
246 :
247 : } else {
248 0 : this->codingRate = cr - 4;
249 :
250 : }
251 :
252 : // update modulation parameters
253 0 : return(setLoRaModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
254 :
255 0 : } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
256 0 : if(cr > RADIOLIB_LR2021_FLRC_CR_2_3) {
257 0 : return(RADIOLIB_ERR_INVALID_CODING_RATE);
258 : }
259 :
260 : // update modulation parameters
261 0 : this->codingRateFlrc = cr;
262 0 : return(setFlrcModulationParams(this->bitRateFlrc, this->codingRateFlrc, this->pulseShape));
263 :
264 : }
265 :
266 0 : return(RADIOLIB_ERR_WRONG_MODEM);
267 : }
268 :
269 0 : int16_t LR2021::setSyncWord(uint8_t syncWord) {
270 : // check active modem
271 0 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
272 0 : int16_t state = getPacketType(&type);
273 0 : RADIOLIB_ASSERT(state);
274 0 : if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
275 0 : return(RADIOLIB_ERR_WRONG_MODEM);
276 : }
277 :
278 0 : return(setLoRaSyncword(syncWord));
279 : }
280 :
281 1 : int16_t LR2021::setPreambleLength(size_t preambleLength) {
282 : // check active modem
283 1 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
284 1 : int16_t state = getPacketType(&type);
285 1 : RADIOLIB_ASSERT(state);
286 0 : if(type == RADIOLIB_LR2021_PACKET_TYPE_LORA) {
287 0 : this->preambleLengthLoRa = preambleLength;
288 0 : return(setLoRaPacketParams(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled));
289 :
290 0 : } else if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
291 0 : this->preambleLengthGFSK = preambleLength;
292 0 : this->preambleDetLength = (preambleLength / 8) << 3;
293 0 : return(setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
294 :
295 0 : } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) {
296 0 : this->preambleLengthGFSK = preambleLength;
297 0 : this->preambleDetLength = (preambleLength / 8) << 3;
298 0 : return(setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
299 :
300 0 : } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
301 0 : if((preambleLength % 4) != 0) {
302 0 : return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH);
303 : }
304 0 : this->preambleLengthGFSK = (preambleLength / 4) - 1;
305 0 : return(setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, RADIOLIB_LR2021_MAX_PACKET_LENGTH));
306 :
307 : }
308 :
309 0 : return(RADIOLIB_ERR_WRONG_MODEM);
310 : }
311 :
312 0 : int16_t LR2021::setTCXO(float voltage, uint32_t delay) {
313 : // check if TCXO is enabled at all
314 0 : if(this->XTAL) {
315 0 : return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE);
316 : }
317 :
318 : // set mode to standby
319 0 : standby();
320 :
321 : // check oscillator startup error flag and clear it
322 0 : uint16_t errors = 0;
323 0 : int16_t state = getErrors(&errors);
324 0 : RADIOLIB_ASSERT(state);
325 0 : if(errors & RADIOLIB_LR2021_HF_XOSC_START_ERR) {
326 0 : clearErrors();
327 : }
328 :
329 : // check 0 V disable
330 0 : if(fabsf(voltage - 0.0f) <= 0.001f) {
331 0 : setTcxoMode(0, 0);
332 0 : return(reset());
333 : }
334 :
335 : // check allowed voltage values
336 0 : uint8_t tune = 0;
337 0 : if(fabsf(voltage - 1.6f) <= 0.001f) {
338 0 : tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_1_6;
339 0 : } else if(fabsf(voltage - 1.7f) <= 0.001f) {
340 0 : tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_1_7;
341 0 : } else if(fabsf(voltage - 1.8f) <= 0.001f) {
342 0 : tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_1_8;
343 0 : } else if(fabsf(voltage - 2.2f) <= 0.001f) {
344 0 : tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_2_2;
345 0 : } else if(fabsf(voltage - 2.4f) <= 0.001f) {
346 0 : tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_2_4;
347 0 : } else if(fabsf(voltage - 2.7f) <= 0.001f) {
348 0 : tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_2_7;
349 0 : } else if(fabsf(voltage - 3.0f) <= 0.001f) {
350 0 : tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_3_0;
351 0 : } else if(fabsf(voltage - 3.3f) <= 0.001f) {
352 0 : tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_3_3;
353 : } else {
354 0 : return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE);
355 : }
356 :
357 : // calculate delay value
358 0 : uint32_t delayValue = (uint32_t)((float)delay / 30.52f);
359 0 : if(delayValue == 0) {
360 0 : delayValue = 1;
361 : }
362 :
363 : // enable TCXO control
364 0 : return(setTcxoMode(tune, delayValue));
365 : }
366 :
367 0 : int16_t LR2021::setCRC(uint8_t len, uint32_t initial, uint32_t polynomial, bool inverted) {
368 : // check active modem
369 0 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
370 0 : int16_t state = getPacketType(&type);
371 0 : RADIOLIB_ASSERT(state);
372 0 : if(type == RADIOLIB_LR2021_PACKET_TYPE_LORA) {
373 : // LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion
374 0 : this->crcTypeLoRa = len > 0;
375 0 : return(setLoRaPacketParams(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled));
376 :
377 0 : } else if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
378 0 : if(len > 4) {
379 0 : return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
380 : }
381 :
382 0 : this->crcTypeGFSK = len;
383 0 : if((this->crcTypeGFSK != RADIOLIB_LR2021_GFSK_OOK_CRC_OFF) && inverted) {
384 0 : this->crcTypeGFSK += 0x08;
385 : }
386 :
387 0 : state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
388 0 : RADIOLIB_ASSERT(state);
389 :
390 0 : return(setGfskCrcParams(polynomial, initial));
391 :
392 0 : } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) {
393 0 : if(len > 4) {
394 0 : return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
395 : }
396 :
397 0 : this->crcTypeGFSK = len;
398 0 : if((this->crcTypeGFSK != RADIOLIB_LR2021_GFSK_OOK_CRC_OFF) && inverted) {
399 0 : this->crcTypeGFSK += 0x08;
400 : }
401 :
402 0 : state = setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
403 0 : RADIOLIB_ASSERT(state);
404 :
405 0 : return(setOokCrcParams(polynomial, initial));
406 :
407 0 : } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
408 0 : if((len == 1) || (len > 4)) {
409 0 : return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
410 : }
411 :
412 0 : this->crcLenGFSK = len ? len - 1 : 0;
413 0 : return(setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, RADIOLIB_LR2021_MAX_PACKET_LENGTH));
414 :
415 : }
416 :
417 0 : return(RADIOLIB_ERR_WRONG_MODEM);
418 : }
419 :
420 1 : int16_t LR2021::invertIQ(bool enable) {
421 : // check active modem
422 1 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
423 1 : int16_t state = getPacketType(&type);
424 1 : RADIOLIB_ASSERT(state);
425 0 : if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
426 0 : return(RADIOLIB_ERR_WRONG_MODEM);
427 : }
428 :
429 0 : this->invertIQEnabled = enable;
430 0 : return(setLoRaPacketParams(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled));
431 : }
432 :
433 1 : int16_t LR2021::setBitRate(float br) {
434 : // check active modem
435 1 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
436 1 : int16_t state = getPacketType(&type);
437 1 : RADIOLIB_ASSERT(state);
438 0 : if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
439 0 : RADIOLIB_CHECK_RANGE(br, 0.5f, 2000.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
440 : //! \TODO: [LR2021] implement fractional bit rate configuration
441 0 : this->bitRate = br * 1000.0f;
442 0 : state = setGfskModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev);
443 0 : return(state);
444 :
445 0 : } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) {
446 0 : RADIOLIB_CHECK_RANGE(br, 0.5f, 2000.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
447 : //! \TODO: [LR2021] implement fractional bit rate configuration
448 0 : this->bitRate = br * 1000.0f;
449 : //! \TODO: [LR2021] implement OOK magnitude depth configuration
450 0 : state = setOokModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, RADIOLIB_LR2021_OOK_DEPTH_FULL);
451 0 : return(state);
452 :
453 0 : } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
454 0 : if((uint16_t)br == 260) {
455 0 : this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_260;
456 0 : } else if((uint16_t)br == 325) {
457 0 : this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_325;
458 0 : } else if((uint16_t)br == 520) {
459 0 : this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_520;
460 0 : } else if((uint16_t)br == 650) {
461 0 : this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_650;
462 0 : } else if((uint16_t)br == 1040) {
463 0 : this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_1040;
464 0 : } else if((uint16_t)br == 1300) {
465 0 : this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_1300;
466 0 : } else if((uint16_t)br == 2080) {
467 0 : this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_2080;
468 0 : } else if((uint16_t)br == 2600) {
469 0 : this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_2600;
470 : } else {
471 0 : return(RADIOLIB_ERR_INVALID_BIT_RATE);
472 : }
473 :
474 : // it is slightly weird to reuse the GFSK bitrate variable in this way
475 : // but if GFSK gets enabled it should get reset anyway ... I think
476 0 : this->bitRate = br;
477 :
478 : // update modulation parameters
479 0 : return(setFlrcModulationParams(this->bitRateFlrc, this->codingRateFlrc, this->pulseShape));
480 : }
481 :
482 0 : return(RADIOLIB_ERR_WRONG_MODEM);
483 : }
484 :
485 1 : int16_t LR2021::setFrequencyDeviation(float freqDev) {
486 : // check active modem
487 1 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
488 1 : int16_t state = getPacketType(&type);
489 1 : RADIOLIB_ASSERT(state);
490 0 : if(type != RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
491 0 : return(RADIOLIB_ERR_WRONG_MODEM);
492 : }
493 :
494 : // set frequency deviation to lowest available setting (required for digimodes)
495 0 : float newFreqDev = freqDev;
496 0 : if(freqDev < 0.6f) {
497 0 : newFreqDev = 0.6f;
498 : }
499 :
500 0 : RADIOLIB_CHECK_RANGE(newFreqDev, 0.6f, 500.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
501 0 : this->frequencyDev = newFreqDev * 1000.0f;
502 0 : state = setGfskModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev);
503 0 : return(state);
504 : }
505 :
506 0 : int16_t LR2021::setRxBandwidth(float rxBw) {
507 : // check active modem
508 0 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
509 0 : int16_t state = getPacketType(&type);
510 0 : RADIOLIB_ASSERT(state);
511 0 : if(!((type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) ||
512 0 : (type == RADIOLIB_LR2021_PACKET_TYPE_OOK))) {
513 0 : return(RADIOLIB_ERR_WRONG_MODEM);
514 : }
515 :
516 0 : const uint8_t rxBwLut[] = {
517 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_4_8,
518 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_5_8,
519 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_7_4,
520 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_9_7,
521 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_12_0,
522 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_14_9,
523 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_19_2,
524 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_23_1,
525 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_29_8,
526 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_38_5,
527 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_46_3,
528 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_59_5,
529 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_76_9,
530 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_92_6,
531 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_119_0,
532 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_153_8,
533 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_185_2,
534 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_238_1,
535 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_307_7,
536 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_370_4,
537 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_476_2,
538 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_555_6,
539 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_666_7,
540 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_769_2,
541 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_1111,
542 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_2222,
543 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_2666,
544 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_3076,
545 : };
546 :
547 0 : state = findRxBw(rxBw, rxBwLut, sizeof(rxBwLut)/sizeof(rxBwLut[0]), 3076.0f, &this->rxBandwidth);
548 0 : RADIOLIB_ASSERT(state);
549 :
550 : // update modulation parameters
551 0 : if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
552 0 : state = setGfskModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev);
553 : } else {
554 0 : state = setOokModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, RADIOLIB_LR2021_OOK_DEPTH_FULL);
555 : }
556 0 : return(state);
557 : }
558 :
559 1 : int16_t LR2021::setSyncWord(uint8_t* syncWord, size_t len) {
560 1 : if(len > RADIOLIB_LR2021_GFSK_SYNC_WORD_LEN) {
561 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
562 : }
563 :
564 : // check active modem
565 1 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
566 1 : int16_t state = getPacketType(&type);
567 1 : RADIOLIB_ASSERT(state);
568 :
569 0 : uint32_t sync = 0;
570 0 : switch(type) {
571 0 : case(RADIOLIB_LR2021_PACKET_TYPE_GFSK):
572 : // default to MSB-first
573 0 : return(setGfskSyncword(const_cast<const uint8_t*>(syncWord), len, true));
574 :
575 0 : case(RADIOLIB_LR2021_PACKET_TYPE_OOK):
576 : // default to MSB-first
577 0 : return(setOokSyncword(const_cast<const uint8_t*>(syncWord), len, true));
578 :
579 0 : case(RADIOLIB_LR2021_PACKET_TYPE_LORA):
580 : // with length set to 1 and LoRa modem active, assume it is the LoRa sync word
581 0 : if(len > 1) {
582 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
583 : }
584 0 : return(setSyncWord(syncWord[0]));
585 :
586 0 : case(RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS):
587 : // with length set to 4 and LR-FHSS modem active, assume it is the LR-FHSS sync word
588 0 : if(len != sizeof(uint32_t)) {
589 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
590 : }
591 0 : memcpy(&sync, syncWord, sizeof(uint32_t));
592 0 : return(lrFhssSetSyncword(sync));
593 :
594 0 : case(RADIOLIB_LR2021_PACKET_TYPE_FLRC):
595 : // FLRC requires 16 or 32-bit sync word
596 0 : if(!((len == 0) || (len == 2) || (len == 4))) {
597 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
598 : }
599 :
600 : // update sync word length
601 0 : this->syncWordLength = len;
602 0 : state = setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, RADIOLIB_LR2021_MAX_PACKET_LENGTH);
603 0 : RADIOLIB_ASSERT(state);
604 :
605 0 : sync |= (uint32_t)syncWord[0] << 24;
606 0 : sync |= (uint32_t)syncWord[1] << 16;
607 0 : sync |= (uint32_t)syncWord[2] << 8;
608 0 : sync |= (uint32_t)syncWord[3];
609 0 : return(setFlrcSyncWord(1, sync));
610 : }
611 :
612 0 : return(RADIOLIB_ERR_WRONG_MODEM);
613 : }
614 :
615 1 : int16_t LR2021::setDataShaping(uint8_t sh) {
616 : // check active modem
617 1 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
618 1 : int16_t state = getPacketType(&type);
619 1 : RADIOLIB_ASSERT(state);
620 :
621 : // set data shaping
622 0 : switch(sh) {
623 0 : case RADIOLIB_SHAPING_NONE:
624 0 : this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_NONE;
625 0 : break;
626 0 : case RADIOLIB_SHAPING_0_3:
627 0 : this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_0_3;
628 0 : break;
629 0 : case RADIOLIB_SHAPING_0_5:
630 0 : this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_0_5;
631 0 : break;
632 0 : case RADIOLIB_SHAPING_0_7:
633 0 : this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_0_7;
634 0 : break;
635 0 : case RADIOLIB_SHAPING_1_0:
636 0 : this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_1_0;
637 0 : break;
638 0 : default:
639 0 : return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
640 : }
641 :
642 : // update modulation parameters
643 0 : if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
644 0 : return(setFlrcModulationParams(this->bitRateFlrc, this->codingRateFlrc, this->pulseShape));
645 0 : } else if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
646 0 : return(setGfskModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
647 0 : } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) {
648 0 : return(setOokModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, RADIOLIB_LR2021_OOK_DEPTH_FULL));
649 : }
650 0 : return(RADIOLIB_ERR_WRONG_MODEM);
651 : }
652 :
653 1 : int16_t LR2021::setEncoding(uint8_t encoding) {
654 : // check active modem
655 1 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
656 1 : int16_t state = getPacketType(&type);
657 1 : RADIOLIB_ASSERT(state);
658 :
659 0 : switch(type) {
660 0 : case(RADIOLIB_LR2021_PACKET_TYPE_GFSK):
661 0 : return(setWhitening(encoding == RADIOLIB_ENCODING_WHITENING));
662 :
663 0 : case(RADIOLIB_LR2021_PACKET_TYPE_OOK):
664 0 : switch(encoding) {
665 0 : case(RADIOLIB_ENCODING_NRZ):
666 : case(RADIOLIB_ENCODING_WHITENING):
667 0 : return(setWhitening(encoding == RADIOLIB_ENCODING_WHITENING));
668 :
669 0 : case(RADIOLIB_ENCODING_MANCHESTER):
670 0 : state = setWhitening(false);
671 0 : RADIOLIB_ASSERT(state);
672 0 : this->whitening = RADIOLIB_LR2021_OOK_MANCHESTER_ON;
673 0 : return(setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
674 :
675 0 : case(RADIOLIB_ENCODING_MANCHESTER_INV):
676 0 : state = setWhitening(false);
677 0 : RADIOLIB_ASSERT(state);
678 0 : this->whitening = RADIOLIB_LR2021_OOK_MANCHESTER_ON_INV;
679 0 : return(setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
680 :
681 0 : default:
682 0 : return(RADIOLIB_ERR_INVALID_ENCODING);
683 : }
684 :
685 0 : default:
686 0 : return(RADIOLIB_ERR_WRONG_MODEM);
687 : }
688 :
689 : return(state);
690 : }
691 :
692 0 : int16_t LR2021::fixedPacketLengthMode(uint8_t len) {
693 0 : return(setPacketMode(RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, len));
694 : }
695 :
696 0 : int16_t LR2021::variablePacketLengthMode(uint8_t maxLen) {
697 0 : return(setPacketMode(RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_VARIABLE_8BIT, maxLen));
698 : }
699 :
700 0 : int16_t LR2021::setWhitening(bool enabled, uint16_t initial) {
701 : // check active modem
702 0 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
703 0 : int16_t state = getPacketType(&type);
704 0 : RADIOLIB_ASSERT(state);
705 :
706 0 : switch(type) {
707 0 : case(RADIOLIB_LR2021_PACKET_TYPE_GFSK):
708 : //! \TODO: [LR2021] Implement SX128x-compatible whitening
709 0 : if(enabled) {
710 0 : state = setGfskWhiteningParams(RADIOLIB_LR2021_GFSK_WHITENING_TYPE_SX126X_LR11XX, initial);
711 0 : RADIOLIB_ASSERT(state);
712 : }
713 0 : this->whitening = enabled;
714 0 : return(setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
715 :
716 0 : case(RADIOLIB_LR2021_PACKET_TYPE_OOK):
717 0 : this->whitening = enabled;
718 0 : if(enabled) {
719 : //! \TODO: [LR2021] Implement configurable index and polynomial
720 0 : state = setOokWhiteningParams(12, 0x01FF, initial);
721 : } else {
722 0 : state = setOokWhiteningParams(0, 0, 0);
723 : }
724 0 : RADIOLIB_ASSERT(state);
725 0 : return(setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
726 : }
727 :
728 0 : return(RADIOLIB_ERR_WRONG_MODEM);
729 : }
730 :
731 1 : int16_t LR2021::setDataRate(DataRate_t dr, ModemType_t modem ) {
732 : // get the current modem
733 : ModemType_t currentModem;
734 1 : int16_t state = this->getModem(¤tModem);
735 1 : RADIOLIB_ASSERT(state);
736 :
737 : // switch over if the requested modem is different
738 0 : if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) {
739 0 : state = this->standby();
740 0 : RADIOLIB_ASSERT(state);
741 0 : state = this->setModem(modem);
742 0 : RADIOLIB_ASSERT(state);
743 : }
744 :
745 0 : if(modem == RADIOLIB_MODEM_NONE) {
746 0 : modem = currentModem;
747 : }
748 :
749 : // select interpretation based on modem
750 0 : if(modem == RADIOLIB_MODEM_FSK) {
751 : // set the bit rate
752 0 : state = this->setBitRate(dr.fsk.bitRate);
753 0 : RADIOLIB_ASSERT(state);
754 :
755 : // set the frequency deviation
756 0 : state = this->setFrequencyDeviation(dr.fsk.freqDev);
757 :
758 0 : } else if(modem == RADIOLIB_MODEM_LORA) {
759 : // set the spreading factor
760 0 : state = this->setSpreadingFactor(dr.lora.spreadingFactor);
761 0 : RADIOLIB_ASSERT(state);
762 :
763 : // set the bandwidth
764 0 : state = this->setBandwidth(dr.lora.bandwidth);
765 0 : RADIOLIB_ASSERT(state);
766 :
767 : // set the coding rate
768 0 : state = this->setCodingRate(dr.lora.codingRate);
769 :
770 0 : } else if(modem == RADIOLIB_MODEM_LRFHSS) {
771 : // set the basic config
772 0 : state = this->setLrFhssConfig(dr.lrFhss.bw, dr.lrFhss.cr);
773 0 : RADIOLIB_ASSERT(state);
774 :
775 : // set hopping grid
776 0 : this->lrFhssGrid = dr.lrFhss.narrowGrid ? RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_FCC;
777 :
778 : }
779 :
780 0 : return(state);
781 : }
782 :
783 1 : int16_t LR2021::checkDataRate(DataRate_t dr, ModemType_t modem) {
784 1 : int16_t state = RADIOLIB_ERR_UNKNOWN;
785 :
786 : // retrieve modem if not supplied
787 1 : if(modem == RADIOLIB_MODEM_NONE) {
788 1 : state = this->getModem(&modem);
789 1 : RADIOLIB_ASSERT(state);
790 : }
791 :
792 : // select interpretation based on modem
793 0 : if(modem == RADIOLIB_MODEM_FSK) {
794 0 : RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5f, 2000.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
795 0 : RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6f, 500.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
796 0 : return(RADIOLIB_ERR_NONE);
797 :
798 0 : } else if(modem == RADIOLIB_MODEM_LORA) {
799 0 : RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
800 0 : RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
801 0 : RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
802 0 : return(RADIOLIB_ERR_NONE);
803 :
804 : }
805 :
806 0 : return(state);
807 : }
808 :
809 0 : int16_t LR2021::setLrFhssConfig(uint8_t bw, uint8_t cr, uint8_t hdrCount, uint16_t hopSeed) {
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_LR_FHSS) {
815 0 : return(RADIOLIB_ERR_WRONG_MODEM);
816 : }
817 :
818 : // check and cache all parameters
819 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);
820 0 : this->lrFhssCr = cr;
821 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);
822 0 : this->lrFhssBw = bw;
823 0 : RADIOLIB_CHECK_RANGE(hdrCount, 1, 4, RADIOLIB_ERR_INVALID_BIT_RANGE);
824 0 : this->lrFhssHdrCount = hdrCount;
825 0 : RADIOLIB_CHECK_RANGE((int16_t)hopSeed, (int16_t)0x000, (int16_t)0x1FF, RADIOLIB_ERR_INVALID_DATA_SHAPING);
826 0 : this->lrFhssHopSeq = hopSeed;
827 0 : return(RADIOLIB_ERR_NONE);
828 : }
829 :
830 0 : int16_t LR2021::setRxBoostedGainMode(uint8_t level) {
831 0 : int16_t state = this->setRxPath(this->highFreq ? RADIOLIB_LR2021_RX_PATH_HF : RADIOLIB_LR2021_RX_PATH_LF, this->highFreq ? this->gainModeHf : this->gainModeLf);
832 0 : RADIOLIB_ASSERT(state);
833 0 : if(this->highFreq) {
834 0 : this->gainModeHf = level;
835 : } else {
836 0 : this->gainModeLf = level;
837 : }
838 0 : return(state);
839 : }
840 :
841 0 : int16_t LR2021::setPacketMode(uint8_t mode, uint8_t len) {
842 : // check active modem
843 0 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
844 0 : int16_t state = getPacketType(&type);
845 0 : RADIOLIB_ASSERT(state);
846 0 : if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
847 : // set requested packet mode
848 0 : state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, mode, len, this->crcTypeGFSK, this->whitening);
849 0 : RADIOLIB_ASSERT(state);
850 :
851 : // update cached value
852 0 : this->packetType = mode;
853 0 : return(state);
854 :
855 0 : } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) {
856 : // set requested packet mode
857 0 : state = setOokPacketParams(this->preambleLengthGFSK, this->addrComp, mode, len, this->crcTypeGFSK, this->whitening);
858 0 : RADIOLIB_ASSERT(state);
859 :
860 : // update cached value
861 0 : this->packetType = mode;
862 0 : return(state);
863 :
864 0 : } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
865 0 : state = setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, mode == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, len);
866 0 : RADIOLIB_ASSERT(state);
867 :
868 0 : this->packetType = mode;
869 0 : return(state);
870 :
871 : }
872 :
873 0 : return(RADIOLIB_ERR_WRONG_MODEM);
874 : }
875 :
876 0 : int16_t LR2021::setLoRaHeaderType(uint8_t hdrType, size_t len) {
877 0 : uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
878 0 : int16_t state = getPacketType(&modem);
879 0 : RADIOLIB_ASSERT(state);
880 0 : if(modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
881 0 : return(RADIOLIB_ERR_WRONG_MODEM);
882 : }
883 :
884 : // set requested packet mode
885 0 : state = setLoRaPacketParams(this->preambleLengthLoRa, hdrType, len, this->crcTypeLoRa, this->invertIQEnabled);
886 0 : RADIOLIB_ASSERT(state);
887 :
888 : // update cached value
889 0 : this->headerType = hdrType;
890 0 : this->implicitLen = len;
891 :
892 0 : return(state);
893 : }
894 :
895 0 : int16_t LR2021::implicitHeader(size_t len) {
896 0 : return(this->setLoRaHeaderType(RADIOLIB_LR2021_LORA_HEADER_IMPLICIT, len));
897 : }
898 :
899 0 : int16_t LR2021::explicitHeader() {
900 0 : return(this->setLoRaHeaderType(RADIOLIB_LR2021_LORA_HEADER_EXPLICIT));
901 : }
902 :
903 0 : int16_t LR2021::setNodeAddress(uint8_t nodeAddr) {
904 : // check active modem
905 0 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
906 0 : int16_t state = getPacketType(&type);
907 0 : RADIOLIB_ASSERT(state);
908 0 : if(type != RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
909 0 : return(RADIOLIB_ERR_WRONG_MODEM);
910 : }
911 :
912 : // enable address filtering (node only)
913 0 : this->addrComp = RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_NODE;
914 0 : state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
915 0 : RADIOLIB_ASSERT(state);
916 :
917 : // set node address
918 0 : this->node = nodeAddr;
919 0 : return(setGfskAddress(this->node, 0));
920 : }
921 :
922 0 : int16_t LR2021::setBroadcastAddress(uint8_t broadAddr) {
923 : // check active modem
924 0 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
925 0 : int16_t state = getPacketType(&type);
926 0 : RADIOLIB_ASSERT(state);
927 0 : if(type != RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
928 0 : return(RADIOLIB_ERR_WRONG_MODEM);
929 : }
930 :
931 : // enable address filtering (node and broadcast)
932 0 : this->addrComp = RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_NODE_BROADCAST;
933 0 : state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
934 0 : RADIOLIB_ASSERT(state);
935 :
936 : // set node and broadcast address
937 0 : return(setGfskAddress(this->node, broadAddr));
938 : }
939 :
940 0 : int16_t LR2021::disableAddressFiltering() {
941 : // check active modem
942 0 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
943 0 : int16_t state = getPacketType(&type);
944 0 : RADIOLIB_ASSERT(state);
945 0 : if(type != RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
946 0 : return(RADIOLIB_ERR_WRONG_MODEM);
947 : }
948 :
949 : // disable address filtering
950 0 : this->addrComp = RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_DISABLED;
951 0 : return(setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType, RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
952 : }
953 :
954 0 : int16_t LR2021::ookDetector(uint16_t pattern, uint8_t len, uint8_t repeats, bool syncRaw, bool rising, uint8_t sofLen) {
955 : // check active modem
956 0 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
957 0 : int16_t state = getPacketType(&type);
958 0 : RADIOLIB_ASSERT(state);
959 0 : if(type != RADIOLIB_LR2021_PACKET_TYPE_OOK) {
960 0 : return(RADIOLIB_ERR_WRONG_MODEM);
961 : }
962 :
963 0 : return(setOokDetector(pattern, len - 1, repeats, syncRaw, rising, sofLen));
964 : }
965 :
966 0 : int16_t LR2021::setOokDetectionThreshold(int16_t level) {
967 0 : int16_t levelRaw = 64 + level;
968 0 : return(this->writeRegMemMask32(RADIOLIB_LR2021_REG_OOK_DETECTION_THRESHOLD, (0x7FUL << 20), (uint32_t)levelRaw << 20));
969 : }
970 :
971 0 : int16_t LR2021::setSideDetector(const LR2021LoRaSideDetector_t* cfg, size_t numDetectors) {
972 : // some basic sanity checks
973 0 : if((cfg == nullptr) || (numDetectors == 0)) {
974 0 : return(RADIOLIB_ERR_NONE);
975 : }
976 :
977 0 : if(numDetectors > 3) {
978 0 : return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
979 : }
980 :
981 : // if bandwidth is higher than 500 kHz, at most 2 side detectors are allowed
982 0 : if((this->bandwidthKhz > 500.0f) && (numDetectors > 2)) {
983 0 : return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
984 : }
985 :
986 : // if the primary spreading factor is 10, 11 or 12, at most 2 side detectors are allowed
987 0 : if((this->spreadingFactor >= 10) && (numDetectors > 2)) {
988 0 : return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
989 : }
990 :
991 : // condition of the primary spreading factor being the smallest/largest is not checked
992 : // this is intentional, because it depends on whether the user wants to start Rx or CAD
993 :
994 0 : uint8_t detectors[3] = { 0 };
995 0 : uint8_t syncWords[3] = { 0 };
996 0 : uint8_t minSf = this->spreadingFactor;
997 0 : for(size_t i = 0; i < numDetectors; i++) {
998 : // all side-detector spreading factors must be higher than the primary one
999 : //! \todo [LR2021] implement multi-SF for CAD (main SF must be smallest!)
1000 0 : if(this->spreadingFactor >= cfg[i].sf) {
1001 0 : return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
1002 : }
1003 :
1004 : // the difference between maximum and minimum spreading factor used must be less than or equal to 4
1005 0 : if(cfg[i].sf - minSf > 4) {
1006 0 : return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
1007 : }
1008 :
1009 0 : if(cfg[i].sf < minSf) { minSf = cfg[i].sf; }
1010 :
1011 0 : detectors[i] = cfg[i].sf << 4 | cfg[i].ldro << 2 | cfg[i].invertIQ;
1012 0 : syncWords[i] = cfg[i].syncWord;
1013 : }
1014 :
1015 : // all spreading factors must be different
1016 0 : if(numDetectors >= 2) {
1017 0 : if(cfg[0].sf == cfg[1].sf) {
1018 0 : return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
1019 : }
1020 : }
1021 :
1022 0 : if(numDetectors == 3) {
1023 0 : if((cfg[1].sf == cfg[2].sf) || (cfg[0].sf == cfg[2].sf)) {
1024 0 : return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
1025 : }
1026 : }
1027 :
1028 : // check active modem
1029 0 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
1030 0 : int16_t state = getPacketType(&type);
1031 0 : RADIOLIB_ASSERT(state);
1032 0 : if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
1033 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1034 : }
1035 :
1036 0 : state = setLoRaSideDetConfig(detectors, numDetectors);
1037 0 : RADIOLIB_ASSERT(state);
1038 :
1039 0 : return(setLoRaSideDetSyncword(syncWords, numDetectors));
1040 : }
1041 :
1042 0 : int16_t LR2021::setGain(uint8_t gain) {
1043 0 : if(gain > 13) {
1044 0 : return(RADIOLIB_ERR_INVALID_GAIN);
1045 : }
1046 0 : return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_AGC_GAIN_MANUAL, true, &gain, sizeof(gain)));
1047 : }
1048 :
1049 : #endif
|