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