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