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