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,
289 0 : (this->headerType == RADIOLIB_LR2021_LORA_HEADER_IMPLICIT) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled));
290 :
291 0 : } else if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
292 0 : this->preambleLengthGFSK = preambleLength;
293 0 : this->preambleDetLength = (preambleLength / 8) << 3;
294 0 : return(setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType,
295 0 : (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
296 :
297 0 : } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) {
298 0 : this->preambleLengthGFSK = preambleLength;
299 0 : this->preambleDetLength = (preambleLength / 8) << 3;
300 0 : return(setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType,
301 0 : (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
302 :
303 0 : } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
304 0 : if((preambleLength % 4) != 0) {
305 0 : return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH);
306 : }
307 0 : this->preambleLengthGFSK = (preambleLength / 4) - 1;
308 0 : return(setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK,
309 0 : (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH));
310 :
311 : }
312 :
313 0 : return(RADIOLIB_ERR_WRONG_MODEM);
314 : }
315 :
316 0 : int16_t LR2021::setTCXO(float voltage, uint32_t delay) {
317 : // check if TCXO is enabled at all
318 0 : if(this->XTAL) {
319 0 : return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE);
320 : }
321 :
322 : // set mode to standby
323 0 : standby();
324 :
325 : // check oscillator startup error flag and clear it
326 0 : uint16_t errors = 0;
327 0 : int16_t state = getErrors(&errors);
328 0 : RADIOLIB_ASSERT(state);
329 0 : if(errors & RADIOLIB_LR2021_HF_XOSC_START_ERR) {
330 0 : clearErrors();
331 : }
332 :
333 : // check 0 V disable
334 0 : if(fabsf(voltage - 0.0f) <= 0.001f) {
335 0 : setTcxoMode(0, 0);
336 0 : return(reset());
337 : }
338 :
339 : // check allowed voltage values
340 0 : uint8_t tune = 0;
341 0 : if(fabsf(voltage - 1.6f) <= 0.001f) {
342 0 : tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_1_6;
343 0 : } else if(fabsf(voltage - 1.7f) <= 0.001f) {
344 0 : tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_1_7;
345 0 : } else if(fabsf(voltage - 1.8f) <= 0.001f) {
346 0 : tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_1_8;
347 0 : } else if(fabsf(voltage - 2.2f) <= 0.001f) {
348 0 : tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_2_2;
349 0 : } else if(fabsf(voltage - 2.4f) <= 0.001f) {
350 0 : tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_2_4;
351 0 : } else if(fabsf(voltage - 2.7f) <= 0.001f) {
352 0 : tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_2_7;
353 0 : } else if(fabsf(voltage - 3.0f) <= 0.001f) {
354 0 : tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_3_0;
355 0 : } else if(fabsf(voltage - 3.3f) <= 0.001f) {
356 0 : tune = RADIOLIB_LRXXXX_TCXO_VOLTAGE_3_3;
357 : } else {
358 0 : return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE);
359 : }
360 :
361 : // calculate delay value
362 0 : uint32_t delayValue = (uint32_t)((float)delay / 30.52f);
363 0 : if(delayValue == 0) {
364 0 : delayValue = 1;
365 : }
366 :
367 : // enable TCXO control
368 0 : return(setTcxoMode(tune, delayValue));
369 : }
370 :
371 0 : int16_t LR2021::setCRC(uint8_t len, uint32_t initial, uint32_t polynomial, bool inverted) {
372 : // check active modem
373 0 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
374 0 : int16_t state = getPacketType(&type);
375 0 : RADIOLIB_ASSERT(state);
376 0 : if(type == RADIOLIB_LR2021_PACKET_TYPE_LORA) {
377 : // LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion
378 0 : this->crcTypeLoRa = len > 0;
379 0 : return(setLoRaPacketParams(this->preambleLengthLoRa, this->headerType,
380 0 : (this->packetType == RADIOLIB_LR2021_LORA_HEADER_IMPLICIT) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled));
381 :
382 0 : } else if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
383 0 : if(len > 4) {
384 0 : return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
385 : }
386 :
387 0 : this->crcTypeGFSK = len;
388 0 : if((this->crcTypeGFSK != RADIOLIB_LR2021_GFSK_OOK_CRC_OFF) && inverted) {
389 0 : this->crcTypeGFSK += 0x08;
390 : }
391 :
392 0 : state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType,
393 0 : (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
394 0 : RADIOLIB_ASSERT(state);
395 :
396 0 : return(setGfskCrcParams(polynomial, initial));
397 :
398 0 : } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) {
399 0 : if(len > 4) {
400 0 : return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
401 : }
402 :
403 0 : this->crcTypeGFSK = len;
404 0 : if((this->crcTypeGFSK != RADIOLIB_LR2021_GFSK_OOK_CRC_OFF) && inverted) {
405 0 : this->crcTypeGFSK += 0x08;
406 : }
407 :
408 0 : state = setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType,
409 0 : (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
410 0 : RADIOLIB_ASSERT(state);
411 :
412 0 : return(setOokCrcParams(polynomial, initial));
413 :
414 0 : } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
415 0 : if((len == 1) || (len > 4)) {
416 0 : return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
417 : }
418 :
419 0 : this->crcLenGFSK = len ? len - 1 : 0;
420 0 : return(setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK,
421 0 : (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH));
422 :
423 : }
424 :
425 0 : return(RADIOLIB_ERR_WRONG_MODEM);
426 : }
427 :
428 1 : int16_t LR2021::invertIQ(bool enable) {
429 : // check active modem
430 1 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
431 1 : int16_t state = getPacketType(&type);
432 1 : RADIOLIB_ASSERT(state);
433 0 : if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
434 0 : return(RADIOLIB_ERR_WRONG_MODEM);
435 : }
436 :
437 0 : this->invertIQEnabled = enable;
438 0 : return(setLoRaPacketParams(this->preambleLengthLoRa, this->headerType,
439 0 : (this->packetType == RADIOLIB_LR2021_LORA_HEADER_IMPLICIT) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled));
440 : }
441 :
442 1 : int16_t LR2021::setBitRate(float br) {
443 : // check active modem
444 1 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
445 1 : int16_t state = getPacketType(&type);
446 1 : RADIOLIB_ASSERT(state);
447 0 : if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
448 0 : RADIOLIB_CHECK_RANGE(br, 0.5f, 2000.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
449 : //! \TODO: [LR2021] implement fractional bit rate configuration
450 0 : this->bitRate = br * 1000.0f;
451 0 : state = setGfskModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev);
452 0 : return(state);
453 :
454 0 : } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) {
455 0 : RADIOLIB_CHECK_RANGE(br, 0.5f, 2000.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
456 : //! \TODO: [LR2021] implement fractional bit rate configuration
457 0 : this->bitRate = br * 1000.0f;
458 : //! \TODO: [LR2021] implement OOK magnitude depth configuration
459 0 : state = setOokModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, RADIOLIB_LR2021_OOK_DEPTH_FULL);
460 0 : return(state);
461 :
462 0 : } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
463 0 : if((uint16_t)br == 260) {
464 0 : this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_260;
465 0 : } else if((uint16_t)br == 325) {
466 0 : this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_325;
467 0 : } else if((uint16_t)br == 520) {
468 0 : this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_520;
469 0 : } else if((uint16_t)br == 650) {
470 0 : this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_650;
471 0 : } else if((uint16_t)br == 1040) {
472 0 : this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_1040;
473 0 : } else if((uint16_t)br == 1300) {
474 0 : this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_1300;
475 0 : } else if((uint16_t)br == 2080) {
476 0 : this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_2080;
477 0 : } else if((uint16_t)br == 2600) {
478 0 : this->bitRateFlrc = RADIOLIB_LR2021_FLRC_BR_2600;
479 : } else {
480 0 : return(RADIOLIB_ERR_INVALID_BIT_RATE);
481 : }
482 :
483 : // it is slightly weird to reuse the GFSK bitrate variable in this way
484 : // but if GFSK gets enabled it should get reset anyway ... I think
485 0 : this->bitRate = br;
486 :
487 : // update modulation parameters
488 0 : return(setFlrcModulationParams(this->bitRateFlrc, this->codingRateFlrc, this->pulseShape));
489 : }
490 :
491 0 : return(RADIOLIB_ERR_WRONG_MODEM);
492 : }
493 :
494 1 : int16_t LR2021::setFrequencyDeviation(float freqDev) {
495 : // check active modem
496 1 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
497 1 : int16_t state = getPacketType(&type);
498 1 : RADIOLIB_ASSERT(state);
499 0 : if(type != RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
500 0 : return(RADIOLIB_ERR_WRONG_MODEM);
501 : }
502 :
503 : // set frequency deviation to lowest available setting (required for digimodes)
504 0 : float newFreqDev = freqDev;
505 0 : if(freqDev < 0.6f) {
506 0 : newFreqDev = 0.6f;
507 : }
508 :
509 0 : RADIOLIB_CHECK_RANGE(newFreqDev, 0.6f, 500.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
510 0 : this->frequencyDev = newFreqDev * 1000.0f;
511 0 : state = setGfskModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev);
512 0 : return(state);
513 : }
514 :
515 0 : int16_t LR2021::setRxBandwidth(float rxBw) {
516 : // check active modem
517 0 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
518 0 : int16_t state = getPacketType(&type);
519 0 : RADIOLIB_ASSERT(state);
520 0 : if(!((type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) ||
521 0 : (type == RADIOLIB_LR2021_PACKET_TYPE_OOK))) {
522 0 : return(RADIOLIB_ERR_WRONG_MODEM);
523 : }
524 :
525 0 : const uint8_t rxBwLut[] = {
526 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_4_8,
527 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_5_8,
528 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_7_4,
529 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_9_7,
530 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_12_0,
531 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_14_9,
532 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_19_2,
533 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_23_1,
534 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_29_8,
535 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_38_5,
536 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_46_3,
537 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_59_5,
538 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_76_9,
539 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_92_6,
540 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_119_0,
541 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_153_8,
542 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_185_2,
543 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_238_1,
544 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_307_7,
545 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_370_4,
546 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_476_2,
547 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_555_6,
548 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_666_7,
549 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_769_2,
550 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_1111,
551 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_2222,
552 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_2666,
553 : RADIOLIB_LR2021_GFSK_OOK_RX_BW_3076,
554 : };
555 :
556 0 : state = findRxBw(rxBw, rxBwLut, sizeof(rxBwLut)/sizeof(rxBwLut[0]), 3076.0f, &this->rxBandwidth);
557 0 : RADIOLIB_ASSERT(state);
558 :
559 : // update modulation parameters
560 0 : if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
561 0 : state = setGfskModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev);
562 : } else {
563 0 : state = setOokModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, RADIOLIB_LR2021_OOK_DEPTH_FULL);
564 : }
565 0 : return(state);
566 : }
567 :
568 1 : int16_t LR2021::setSyncWord(uint8_t* syncWord, size_t len) {
569 1 : if(len > RADIOLIB_LR2021_GFSK_SYNC_WORD_LEN) {
570 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
571 : }
572 :
573 : // check active modem
574 1 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
575 1 : int16_t state = getPacketType(&type);
576 1 : RADIOLIB_ASSERT(state);
577 :
578 0 : uint32_t sync = 0;
579 0 : switch(type) {
580 0 : case(RADIOLIB_LR2021_PACKET_TYPE_GFSK):
581 : // default to MSB-first
582 0 : return(setGfskSyncword(const_cast<const uint8_t*>(syncWord), len, true));
583 :
584 0 : case(RADIOLIB_LR2021_PACKET_TYPE_OOK):
585 : // default to MSB-first
586 0 : return(setOokSyncword(const_cast<const uint8_t*>(syncWord), len, true));
587 :
588 0 : case(RADIOLIB_LR2021_PACKET_TYPE_LORA):
589 : // with length set to 1 and LoRa modem active, assume it is the LoRa sync word
590 0 : if(len > 1) {
591 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
592 : }
593 0 : return(setSyncWord(syncWord[0]));
594 :
595 0 : case(RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS):
596 : // with length set to 4 and LR-FHSS modem active, assume it is the LR-FHSS sync word
597 0 : if(len != sizeof(uint32_t)) {
598 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
599 : }
600 0 : memcpy(&sync, syncWord, sizeof(uint32_t));
601 0 : return(lrFhssSetSyncword(sync));
602 :
603 0 : case(RADIOLIB_LR2021_PACKET_TYPE_FLRC):
604 : // FLRC requires 16 or 32-bit sync word
605 0 : if(!((len == 0) || (len == 2) || (len == 4))) {
606 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
607 : }
608 :
609 : // update sync word length
610 0 : this->syncWordLength = len;
611 0 : state = setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK,
612 0 : (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH);
613 0 : RADIOLIB_ASSERT(state);
614 :
615 0 : sync |= (uint32_t)syncWord[0] << 24;
616 0 : sync |= (uint32_t)syncWord[1] << 16;
617 0 : sync |= (uint32_t)syncWord[2] << 8;
618 0 : sync |= (uint32_t)syncWord[3];
619 0 : return(setFlrcSyncWord(1, sync));
620 : }
621 :
622 0 : return(RADIOLIB_ERR_WRONG_MODEM);
623 : }
624 :
625 1 : int16_t LR2021::setDataShaping(uint8_t sh) {
626 : // check active modem
627 1 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
628 1 : int16_t state = getPacketType(&type);
629 1 : RADIOLIB_ASSERT(state);
630 :
631 : // set data shaping
632 0 : switch(sh) {
633 0 : case RADIOLIB_SHAPING_NONE:
634 0 : this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_NONE;
635 0 : break;
636 0 : case RADIOLIB_SHAPING_0_3:
637 0 : this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_0_3;
638 0 : break;
639 0 : case RADIOLIB_SHAPING_0_5:
640 0 : this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_0_5;
641 0 : break;
642 0 : case RADIOLIB_SHAPING_0_7:
643 0 : this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_0_7;
644 0 : break;
645 0 : case RADIOLIB_SHAPING_1_0:
646 0 : this->pulseShape = RADIOLIB_LR2021_GFSK_BPSK_FLRC_OOK_SHAPING_GAUSS_BT_1_0;
647 0 : break;
648 0 : default:
649 0 : return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
650 : }
651 :
652 : // update modulation parameters
653 0 : if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
654 0 : return(setFlrcModulationParams(this->bitRateFlrc, this->codingRateFlrc, this->pulseShape));
655 0 : } else if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
656 0 : return(setGfskModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
657 0 : } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) {
658 0 : return(setOokModulationParams(this->bitRate, this->pulseShape, this->rxBandwidth, RADIOLIB_LR2021_OOK_DEPTH_FULL));
659 : }
660 0 : return(RADIOLIB_ERR_WRONG_MODEM);
661 : }
662 :
663 1 : int16_t LR2021::setEncoding(uint8_t encoding) {
664 : // check active modem
665 1 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
666 1 : int16_t state = getPacketType(&type);
667 1 : RADIOLIB_ASSERT(state);
668 :
669 0 : switch(type) {
670 0 : case(RADIOLIB_LR2021_PACKET_TYPE_GFSK):
671 0 : return(setWhitening(encoding == RADIOLIB_ENCODING_WHITENING));
672 :
673 0 : case(RADIOLIB_LR2021_PACKET_TYPE_OOK):
674 0 : switch(encoding) {
675 0 : case(RADIOLIB_ENCODING_NRZ):
676 : case(RADIOLIB_ENCODING_WHITENING):
677 0 : return(setWhitening(encoding == RADIOLIB_ENCODING_WHITENING));
678 :
679 0 : case(RADIOLIB_ENCODING_MANCHESTER):
680 0 : state = setWhitening(false);
681 0 : RADIOLIB_ASSERT(state);
682 0 : this->whitening = RADIOLIB_LR2021_OOK_MANCHESTER_ON;
683 0 : return(setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType,
684 0 : (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
685 :
686 0 : case(RADIOLIB_ENCODING_MANCHESTER_INV):
687 0 : state = setWhitening(false);
688 0 : RADIOLIB_ASSERT(state);
689 0 : this->whitening = RADIOLIB_LR2021_OOK_MANCHESTER_ON_INV;
690 0 : return(setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType,
691 0 : (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
692 :
693 0 : default:
694 0 : return(RADIOLIB_ERR_INVALID_ENCODING);
695 : }
696 :
697 0 : default:
698 0 : return(RADIOLIB_ERR_WRONG_MODEM);
699 : }
700 :
701 : return(state);
702 : }
703 :
704 0 : int16_t LR2021::fixedPacketLengthMode(uint8_t len) {
705 0 : return(setPacketMode(RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, len));
706 : }
707 :
708 0 : int16_t LR2021::variablePacketLengthMode(uint8_t maxLen) {
709 0 : return(setPacketMode(RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_VARIABLE_8BIT, maxLen));
710 : }
711 :
712 0 : int16_t LR2021::setWhitening(bool enabled, uint16_t initial) {
713 : // check active modem
714 0 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
715 0 : int16_t state = getPacketType(&type);
716 0 : RADIOLIB_ASSERT(state);
717 :
718 0 : switch(type) {
719 0 : case(RADIOLIB_LR2021_PACKET_TYPE_GFSK):
720 : //! \TODO: [LR2021] Implement SX128x-compatible whitening
721 0 : if(enabled) {
722 0 : state = setGfskWhiteningParams(RADIOLIB_LR2021_GFSK_WHITENING_TYPE_SX126X_LR11XX, initial);
723 0 : RADIOLIB_ASSERT(state);
724 : }
725 0 : this->whitening = enabled;
726 0 : return(setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType,
727 0 : (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
728 :
729 0 : case(RADIOLIB_LR2021_PACKET_TYPE_OOK):
730 0 : this->whitening = enabled;
731 0 : if(enabled) {
732 : //! \TODO: [LR2021] Implement configurable index and polynomial
733 0 : state = setOokWhiteningParams(12, 0x01FF, initial);
734 : } else {
735 0 : state = setOokWhiteningParams(0, 0, 0);
736 : }
737 0 : RADIOLIB_ASSERT(state);
738 0 : return(setOokPacketParams(this->preambleLengthGFSK, this->addrComp, this->packetType,
739 0 : (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
740 : }
741 :
742 0 : return(RADIOLIB_ERR_WRONG_MODEM);
743 : }
744 :
745 1 : int16_t LR2021::setDataRate(DataRate_t dr, ModemType_t modem ) {
746 : // get the current modem
747 : ModemType_t currentModem;
748 1 : int16_t state = this->getModem(¤tModem);
749 1 : RADIOLIB_ASSERT(state);
750 :
751 : // switch over if the requested modem is different
752 0 : if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) {
753 0 : state = this->standby();
754 0 : RADIOLIB_ASSERT(state);
755 0 : state = this->setModem(modem);
756 0 : RADIOLIB_ASSERT(state);
757 : }
758 :
759 0 : if(modem == RADIOLIB_MODEM_NONE) {
760 0 : modem = currentModem;
761 : }
762 :
763 : // select interpretation based on modem
764 0 : if(modem == RADIOLIB_MODEM_FSK) {
765 : // set the bit rate
766 0 : state = this->setBitRate(dr.fsk.bitRate);
767 0 : RADIOLIB_ASSERT(state);
768 :
769 : // set the frequency deviation
770 0 : state = this->setFrequencyDeviation(dr.fsk.freqDev);
771 :
772 0 : } else if(modem == RADIOLIB_MODEM_LORA) {
773 : // set the spreading factor
774 0 : state = this->setSpreadingFactor(dr.lora.spreadingFactor);
775 0 : RADIOLIB_ASSERT(state);
776 :
777 : // set the bandwidth
778 0 : state = this->setBandwidth(dr.lora.bandwidth);
779 0 : RADIOLIB_ASSERT(state);
780 :
781 : // set the coding rate
782 0 : state = this->setCodingRate(dr.lora.codingRate);
783 :
784 0 : } else if(modem == RADIOLIB_MODEM_LRFHSS) {
785 : // set the basic config
786 0 : state = this->setLrFhssConfig(dr.lrFhss.bw, dr.lrFhss.cr);
787 0 : RADIOLIB_ASSERT(state);
788 :
789 : // set hopping grid
790 0 : this->lrFhssGrid = dr.lrFhss.narrowGrid ? RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_LRXXXX_LR_FHSS_GRID_STEP_FCC;
791 :
792 : }
793 :
794 0 : return(state);
795 : }
796 :
797 1 : int16_t LR2021::checkDataRate(DataRate_t dr, ModemType_t modem) {
798 1 : int16_t state = RADIOLIB_ERR_UNKNOWN;
799 :
800 : // retrieve modem if not supplied
801 1 : if(modem == RADIOLIB_MODEM_NONE) {
802 1 : state = this->getModem(&modem);
803 1 : RADIOLIB_ASSERT(state);
804 : }
805 :
806 : // select interpretation based on modem
807 0 : if(modem == RADIOLIB_MODEM_FSK) {
808 0 : RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5f, 2000.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
809 0 : RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6f, 500.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
810 0 : return(RADIOLIB_ERR_NONE);
811 :
812 0 : } else if(modem == RADIOLIB_MODEM_LORA) {
813 0 : RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
814 0 : RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
815 0 : RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
816 0 : return(RADIOLIB_ERR_NONE);
817 :
818 : }
819 :
820 0 : return(state);
821 : }
822 :
823 0 : int16_t LR2021::setLrFhssConfig(uint8_t bw, uint8_t cr, uint8_t hdrCount, uint16_t hopSeed) {
824 : // check active modem
825 0 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
826 0 : int16_t state = getPacketType(&type);
827 0 : RADIOLIB_ASSERT(state);
828 0 : if(type != RADIOLIB_LR2021_PACKET_TYPE_LR_FHSS) {
829 0 : return(RADIOLIB_ERR_WRONG_MODEM);
830 : }
831 :
832 : // check and cache all parameters
833 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);
834 0 : this->lrFhssCr = cr;
835 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);
836 0 : this->lrFhssBw = bw;
837 0 : RADIOLIB_CHECK_RANGE(hdrCount, 1, 4, RADIOLIB_ERR_INVALID_BIT_RANGE);
838 0 : this->lrFhssHdrCount = hdrCount;
839 0 : RADIOLIB_CHECK_RANGE((int16_t)hopSeed, (int16_t)0x000, (int16_t)0x1FF, RADIOLIB_ERR_INVALID_DATA_SHAPING);
840 0 : this->lrFhssHopSeq = hopSeed;
841 0 : return(RADIOLIB_ERR_NONE);
842 : }
843 :
844 0 : int16_t LR2021::setRxBoostedGainMode(uint8_t level) {
845 0 : if(this->highFreq) {
846 0 : this->gainModeHf = level;
847 : } else {
848 0 : this->gainModeLf = level;
849 : }
850 0 : return(this->setRxPath(this->highFreq ? RADIOLIB_LR2021_RX_PATH_HF : RADIOLIB_LR2021_RX_PATH_LF, this->highFreq ? this->gainModeHf : this->gainModeLf));
851 : }
852 :
853 0 : int16_t LR2021::setPacketMode(uint8_t mode, uint8_t len) {
854 : // check active modem
855 0 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
856 0 : int16_t state = getPacketType(&type);
857 0 : RADIOLIB_ASSERT(state);
858 0 : if(type == RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
859 : // set requested packet mode
860 0 : state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, mode, len, this->crcTypeGFSK, this->whitening);
861 0 : RADIOLIB_ASSERT(state);
862 :
863 : // update cached value
864 0 : this->packetType = mode;
865 0 : this->implicitLen = len;
866 0 : return(state);
867 :
868 0 : } else if(type == RADIOLIB_LR2021_PACKET_TYPE_OOK) {
869 : // set requested packet mode
870 0 : state = setOokPacketParams(this->preambleLengthGFSK, this->addrComp, mode, len, this->crcTypeGFSK, this->whitening);
871 0 : RADIOLIB_ASSERT(state);
872 :
873 : // update cached value
874 0 : this->packetType = mode;
875 0 : this->implicitLen = len;
876 0 : return(state);
877 :
878 0 : } else if(type == RADIOLIB_LR2021_PACKET_TYPE_FLRC) {
879 0 : state = setFlrcPacketParams(this->preambleLengthGFSK, this->syncWordLength, 1, 0x01, mode == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED, this->crcLenGFSK, len);
880 0 : RADIOLIB_ASSERT(state);
881 :
882 0 : this->packetType = mode;
883 0 : this->implicitLen = len;
884 0 : return(state);
885 :
886 : }
887 :
888 0 : return(RADIOLIB_ERR_WRONG_MODEM);
889 : }
890 :
891 0 : int16_t LR2021::setLoRaHeaderType(uint8_t hdrType, size_t len) {
892 0 : uint8_t modem = RADIOLIB_LR2021_PACKET_TYPE_NONE;
893 0 : int16_t state = getPacketType(&modem);
894 0 : RADIOLIB_ASSERT(state);
895 0 : if(modem != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
896 0 : return(RADIOLIB_ERR_WRONG_MODEM);
897 : }
898 :
899 : // set requested packet mode
900 0 : state = setLoRaPacketParams(this->preambleLengthLoRa, hdrType, len, this->crcTypeLoRa, this->invertIQEnabled);
901 0 : RADIOLIB_ASSERT(state);
902 :
903 : // update cached value
904 0 : this->headerType = hdrType;
905 0 : this->implicitLen = len;
906 :
907 0 : return(state);
908 : }
909 :
910 0 : int16_t LR2021::implicitHeader(size_t len) {
911 0 : return(this->setLoRaHeaderType(RADIOLIB_LR2021_LORA_HEADER_IMPLICIT, len));
912 : }
913 :
914 0 : int16_t LR2021::explicitHeader() {
915 0 : return(this->setLoRaHeaderType(RADIOLIB_LR2021_LORA_HEADER_EXPLICIT));
916 : }
917 :
918 0 : int16_t LR2021::setNodeAddress(uint8_t nodeAddr) {
919 : // check active modem
920 0 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
921 0 : int16_t state = getPacketType(&type);
922 0 : RADIOLIB_ASSERT(state);
923 0 : if(type != RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
924 0 : return(RADIOLIB_ERR_WRONG_MODEM);
925 : }
926 :
927 : // enable address filtering (node only)
928 0 : this->addrComp = RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_NODE;
929 0 : state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType,
930 0 : (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
931 0 : RADIOLIB_ASSERT(state);
932 :
933 : // set node address
934 0 : this->node = nodeAddr;
935 0 : return(setGfskAddress(this->node, 0));
936 : }
937 :
938 0 : int16_t LR2021::setBroadcastAddress(uint8_t broadAddr) {
939 : // check active modem
940 0 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
941 0 : int16_t state = getPacketType(&type);
942 0 : RADIOLIB_ASSERT(state);
943 0 : if(type != RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
944 0 : return(RADIOLIB_ERR_WRONG_MODEM);
945 : }
946 :
947 : // enable address filtering (node and broadcast)
948 0 : this->addrComp = RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_NODE_BROADCAST;
949 0 : state = setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType,
950 0 : (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
951 0 : RADIOLIB_ASSERT(state);
952 :
953 : // set node and broadcast address
954 0 : return(setGfskAddress(this->node, broadAddr));
955 : }
956 :
957 0 : int16_t LR2021::disableAddressFiltering() {
958 : // check active modem
959 0 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
960 0 : int16_t state = getPacketType(&type);
961 0 : RADIOLIB_ASSERT(state);
962 0 : if(type != RADIOLIB_LR2021_PACKET_TYPE_GFSK) {
963 0 : return(RADIOLIB_ERR_WRONG_MODEM);
964 : }
965 :
966 : // disable address filtering
967 0 : this->addrComp = RADIOLIB_LR2021_GFSK_OOK_ADDR_FILT_DISABLED;
968 0 : return(setGfskPacketParams(this->preambleLengthGFSK, this->preambleDetLength, false, false, this->addrComp, this->packetType,
969 0 : (this->packetType == RADIOLIB_LR2021_GFSK_OOK_PACKET_FORMAT_FIXED) ? this->implicitLen : RADIOLIB_LR2021_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
970 : }
971 :
972 0 : int16_t LR2021::ookDetector(uint16_t pattern, uint8_t len, uint8_t repeats, bool syncRaw, bool rising, uint8_t sofLen) {
973 : // check active modem
974 0 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
975 0 : int16_t state = getPacketType(&type);
976 0 : RADIOLIB_ASSERT(state);
977 0 : if(type != RADIOLIB_LR2021_PACKET_TYPE_OOK) {
978 0 : return(RADIOLIB_ERR_WRONG_MODEM);
979 : }
980 :
981 0 : return(setOokDetector(pattern, len - 1, repeats, syncRaw, rising, sofLen));
982 : }
983 :
984 0 : int16_t LR2021::setOokDetectionThreshold(int16_t level) {
985 0 : int16_t levelRaw = 64 + level;
986 0 : return(this->writeRegMemMask32(RADIOLIB_LR2021_REG_OOK_DETECTION_THRESHOLD, (0x7FUL << 20), (uint32_t)levelRaw << 20));
987 : }
988 :
989 0 : int16_t LR2021::setSideDetector(const LR2021LoRaSideDetector_t* cfg, size_t numDetectors) {
990 : // some basic sanity checks
991 0 : if((cfg == nullptr) || (numDetectors == 0)) {
992 0 : return(RADIOLIB_ERR_NONE);
993 : }
994 :
995 0 : if(numDetectors > 3) {
996 0 : return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
997 : }
998 :
999 : // if bandwidth is higher than 500 kHz, at most 2 side detectors are allowed
1000 0 : if((this->bandwidthKhz > 500.0f) && (numDetectors > 2)) {
1001 0 : return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
1002 : }
1003 :
1004 : // if the primary spreading factor is 10, 11 or 12, at most 2 side detectors are allowed
1005 0 : if((this->spreadingFactor >= 10) && (numDetectors > 2)) {
1006 0 : return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
1007 : }
1008 :
1009 : // condition of the primary spreading factor being the smallest/largest is not checked
1010 : // this is intentional, because it depends on whether the user wants to start Rx or CAD
1011 :
1012 0 : uint8_t detectors[3] = { 0 };
1013 0 : uint8_t syncWords[3] = { 0 };
1014 0 : uint8_t minSf = this->spreadingFactor;
1015 0 : uint32_t sumDetFactors = 0;
1016 0 : for(size_t i = 0; i < numDetectors; i++) {
1017 : // all side-detector spreading factors must be higher than the primary one
1018 : //! \todo [LR2021] implement multi-SF for CAD (main SF must be smallest!)
1019 0 : if(this->spreadingFactor >= cfg[i].sf) {
1020 0 : return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
1021 : }
1022 :
1023 : // the difference between maximum and minimum spreading factor used must be less than or equal to 4
1024 0 : if(cfg[i].sf - minSf > 4) {
1025 0 : return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
1026 : }
1027 :
1028 0 : if(cfg[i].sf < minSf) { minSf = cfg[i].sf; }
1029 :
1030 0 : detectors[i] = cfg[i].sf << 4 | cfg[i].ldro << 2 | cfg[i].invertIQ;
1031 0 : syncWords[i] = cfg[i].syncWord;
1032 0 : sumDetFactors += 10 + (((cfg[i].sf - 5) >> 1) << 1);
1033 : }
1034 :
1035 : // sum of detection factors multiplied by BW must be smaller than 32E6
1036 0 : if(sumDetFactors*(uint32_t)this->bandwidthKhz >= 32000UL) {
1037 0 : return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
1038 : }
1039 :
1040 : // all spreading factors must be different
1041 0 : if(numDetectors >= 2) {
1042 0 : if(cfg[0].sf == cfg[1].sf) {
1043 0 : return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
1044 : }
1045 : }
1046 :
1047 0 : if(numDetectors == 3) {
1048 0 : if((cfg[1].sf == cfg[2].sf) || (cfg[0].sf == cfg[2].sf)) {
1049 0 : return(RADIOLIB_ERR_INVALID_SIDE_DETECT);
1050 : }
1051 : }
1052 :
1053 : // check active modem
1054 0 : uint8_t type = RADIOLIB_LR2021_PACKET_TYPE_NONE;
1055 0 : int16_t state = getPacketType(&type);
1056 0 : RADIOLIB_ASSERT(state);
1057 0 : if(type != RADIOLIB_LR2021_PACKET_TYPE_LORA) {
1058 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1059 : }
1060 :
1061 0 : state = setLoRaSideDetConfig(detectors, numDetectors);
1062 0 : RADIOLIB_ASSERT(state);
1063 :
1064 0 : return(setLoRaSideDetSyncword(syncWords, numDetectors));
1065 : }
1066 :
1067 0 : int16_t LR2021::setGain(uint8_t gain) {
1068 0 : if(gain > 13) {
1069 0 : return(RADIOLIB_ERR_INVALID_GAIN);
1070 : }
1071 0 : return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_AGC_GAIN_MANUAL, true, &gain, sizeof(gain)));
1072 : }
1073 :
1074 : #endif
|