Line data Source code
1 : #include "SX126x.h"
2 :
3 : #include <math.h>
4 : #include <string.h>
5 :
6 : // this file contains all configuration methods
7 : // of the SX126x, which let user control the
8 : // modulation properties, packet configuration etc.
9 :
10 : #if !RADIOLIB_EXCLUDE_SX126X
11 :
12 0 : void SX126x::setDio1Action(void (*func)(void)) {
13 0 : this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptRising);
14 0 : }
15 :
16 0 : void SX126x::clearDio1Action() {
17 0 : this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()));
18 0 : }
19 :
20 0 : void SX126x::setPacketReceivedAction(void (*func)(void)) {
21 0 : this->setDio1Action(func);
22 0 : }
23 :
24 0 : void SX126x::clearPacketReceivedAction() {
25 0 : this->clearDio1Action();
26 0 : }
27 :
28 0 : void SX126x::setPacketSentAction(void (*func)(void)) {
29 0 : this->setDio1Action(func);
30 0 : }
31 :
32 0 : void SX126x::clearPacketSentAction() {
33 0 : this->clearDio1Action();
34 0 : }
35 :
36 0 : void SX126x::setChannelScanAction(void (*func)(void)) {
37 0 : this->setDio1Action(func);
38 0 : }
39 :
40 0 : void SX126x::clearChannelScanAction() {
41 0 : this->clearDio1Action();
42 0 : }
43 :
44 0 : int16_t SX126x::setBandwidth(float bw) {
45 : // check active modem
46 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
47 0 : return(RADIOLIB_ERR_WRONG_MODEM);
48 : }
49 :
50 : // ensure byte conversion doesn't overflow
51 0 : RADIOLIB_CHECK_RANGE(bw, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
52 :
53 : // check allowed bandwidth values
54 0 : uint8_t bw_div2 = bw / 2 + 0.01f;
55 0 : switch (bw_div2) {
56 0 : case 3: // 7.8:
57 0 : this->bandwidth = RADIOLIB_SX126X_LORA_BW_7_8;
58 0 : break;
59 0 : case 5: // 10.4:
60 0 : this->bandwidth = RADIOLIB_SX126X_LORA_BW_10_4;
61 0 : break;
62 0 : case 7: // 15.6:
63 0 : this->bandwidth = RADIOLIB_SX126X_LORA_BW_15_6;
64 0 : break;
65 0 : case 10: // 20.8:
66 0 : this->bandwidth = RADIOLIB_SX126X_LORA_BW_20_8;
67 0 : break;
68 0 : case 15: // 31.25:
69 0 : this->bandwidth = RADIOLIB_SX126X_LORA_BW_31_25;
70 0 : break;
71 0 : case 20: // 41.7:
72 0 : this->bandwidth = RADIOLIB_SX126X_LORA_BW_41_7;
73 0 : break;
74 0 : case 31: // 62.5:
75 0 : this->bandwidth = RADIOLIB_SX126X_LORA_BW_62_5;
76 0 : break;
77 0 : case 62: // 125.0:
78 0 : this->bandwidth = RADIOLIB_SX126X_LORA_BW_125_0;
79 0 : break;
80 0 : case 125: // 250.0
81 0 : this->bandwidth = RADIOLIB_SX126X_LORA_BW_250_0;
82 0 : break;
83 0 : case 250: // 500.0
84 0 : this->bandwidth = RADIOLIB_SX126X_LORA_BW_500_0;
85 0 : break;
86 0 : default:
87 0 : return(RADIOLIB_ERR_INVALID_BANDWIDTH);
88 : }
89 :
90 : // update modulation parameters
91 0 : this->bandwidthKhz = bw;
92 0 : return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
93 : }
94 :
95 0 : int16_t SX126x::setSpreadingFactor(uint8_t sf) {
96 : // check active modem
97 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
98 0 : return(RADIOLIB_ERR_WRONG_MODEM);
99 : }
100 :
101 0 : RADIOLIB_CHECK_RANGE(sf, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
102 :
103 : // update modulation parameters
104 0 : this->spreadingFactor = sf;
105 0 : return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
106 : }
107 :
108 0 : int16_t SX126x::setCodingRate(uint8_t cr, bool longInterleave) {
109 : // check active modem
110 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
111 0 : return(RADIOLIB_ERR_WRONG_MODEM);
112 : }
113 :
114 0 : RADIOLIB_CHECK_RANGE(cr, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
115 :
116 0 : if(longInterleave) {
117 0 : switch(cr) {
118 0 : case 4:
119 0 : this->codingRate = 0;
120 0 : break;
121 0 : case 5:
122 : case 6:
123 0 : this->codingRate = cr;
124 0 : break;
125 0 : case 8:
126 0 : this->codingRate = cr - 1;
127 0 : break;
128 0 : default:
129 0 : return(RADIOLIB_ERR_INVALID_CODING_RATE);
130 : }
131 : } else {
132 0 : this->codingRate = cr - 4;
133 : }
134 :
135 : // update modulation parameters
136 0 : return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
137 : }
138 :
139 0 : int16_t SX126x::setSyncWord(uint8_t syncWord, uint8_t controlBits) {
140 : // check active modem
141 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
142 0 : return(RADIOLIB_ERR_WRONG_MODEM);
143 : }
144 :
145 : // update register
146 0 : const uint8_t data[2] = {(uint8_t)((syncWord & 0xF0) | ((controlBits & 0xF0) >> 4)), (uint8_t)(((syncWord & 0x0F) << 4) | (controlBits & 0x0F))};
147 0 : return(writeRegister(RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB, data, 2));
148 : }
149 :
150 0 : int16_t SX126x::setCurrentLimit(float currentLimit) {
151 : // check allowed range
152 0 : if(!((currentLimit >= 0) && (currentLimit <= 140))) {
153 0 : return(RADIOLIB_ERR_INVALID_CURRENT_LIMIT);
154 : }
155 :
156 : // calculate raw value
157 0 : uint8_t rawLimit = (uint8_t)(currentLimit / 2.5f);
158 :
159 : // update register
160 0 : return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &rawLimit, 1));
161 : }
162 :
163 0 : float SX126x::getCurrentLimit() {
164 : // get the raw value
165 0 : uint8_t ocp = 0;
166 0 : readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
167 :
168 : // return the actual value
169 0 : return((float)ocp * 2.5f);
170 : }
171 :
172 3 : int16_t SX126x::setPreambleLength(size_t preambleLength) {
173 3 : uint8_t modem = getPacketType();
174 3 : if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
175 0 : this->preambleLengthLoRa = preambleLength;
176 0 : return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled));
177 3 : } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
178 0 : this->preambleLengthFSK = preambleLength;
179 : // maximum preamble detector length is limited by sync word length
180 : // for details, see the note in SX1261 datasheet, Rev 2.1, section 6.2.2.1, page 45
181 0 : uint8_t maxDetLen = RADIOLIB_MIN(this->syncWordLength, this->preambleLengthFSK);
182 0 : this->preambleDetLength = maxDetLen >= 32 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 :
183 : maxDetLen >= 24 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 :
184 : maxDetLen >= 16 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 :
185 : maxDetLen > 0 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 :
186 : RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF;
187 0 : return(setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening,
188 0 : this->packetType, (this->packetType == RADIOLIB_SX126X_GFSK_PACKET_FIXED) ? this->implicitLen : RADIOLIB_SX126X_MAX_PACKET_LENGTH));
189 : }
190 :
191 3 : return(RADIOLIB_ERR_UNKNOWN);
192 : }
193 :
194 3 : int16_t SX126x::setFrequencyDeviation(float freqDev) {
195 : // check active modem
196 3 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
197 3 : return(RADIOLIB_ERR_WRONG_MODEM);
198 : }
199 :
200 : // set frequency deviation to lowest available setting (required for digimodes)
201 0 : float newFreqDev = freqDev;
202 0 : if(freqDev < 0.0f) {
203 0 : newFreqDev = 0.6f;
204 : }
205 :
206 0 : RADIOLIB_CHECK_RANGE(newFreqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
207 :
208 : // calculate raw frequency deviation value
209 0 : uint32_t freqDevRaw = (uint32_t)(((newFreqDev * 1000.0f) * (float)((uint32_t)(1) << 25)) / (RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0f));
210 :
211 : // check modulation parameters
212 0 : this->frequencyDev = freqDevRaw;
213 :
214 : // update modulation parameters
215 0 : return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
216 : }
217 :
218 3 : int16_t SX126x::setBitRate(float br) {
219 : // check active modem
220 3 : uint8_t modem = getPacketType();
221 3 : if((modem != RADIOLIB_SX126X_PACKET_TYPE_GFSK) &&
222 3 : (modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) &&
223 : (modem != RADIOLIB_SX126X_PACKET_TYPE_BPSK)) {
224 3 : return(RADIOLIB_ERR_WRONG_MODEM);
225 : }
226 :
227 0 : if(modem == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
228 : // at the moment only the very specific 488.28125 bps rate is supported
229 0 : RADIOLIB_CHECK_RANGE(br, 0.488f, 0.489f, RADIOLIB_ERR_INVALID_BIT_RATE);
230 0 : } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_BPSK) {
231 : // this should be just either 100 or 600 bps, not the range
232 : // but the BPSK support is so experimental it probably does not matter
233 0 : RADIOLIB_CHECK_RANGE(br, 0.1f, 0.6f, RADIOLIB_ERR_INVALID_BIT_RATE);
234 : }
235 :
236 : // calculate raw bit rate value
237 0 : uint32_t brRaw = (uint32_t)((RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0f * 32.0f) / (br * 1000.0f));
238 :
239 : // check modulation parameters
240 0 : this->bitRate = brRaw;
241 :
242 : // update modulation parameters
243 0 : int16_t state = RADIOLIB_ERR_UNKNOWN;
244 0 : if(modem == RADIOLIB_SX126X_PACKET_TYPE_BPSK) {
245 0 : state = setModulationParamsBPSK(this->bitRate);
246 : } else {
247 0 : state = setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev);
248 : }
249 0 : RADIOLIB_ASSERT(state);
250 :
251 : // apply workaround or reset it, as needed
252 0 : return(fixGFSK());
253 : }
254 :
255 3 : int16_t SX126x::setDataRate(DataRate_t dr, ModemType_t modem) {
256 : // get the current modem
257 : ModemType_t currentModem;
258 3 : int16_t state = this->getModem(¤tModem);
259 3 : RADIOLIB_ASSERT(state);
260 :
261 : // switch over if the requested modem is different
262 0 : if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) {
263 0 : state = this->standby();
264 0 : RADIOLIB_ASSERT(state);
265 0 : state = this->setModem(modem);
266 0 : RADIOLIB_ASSERT(state);
267 : }
268 :
269 0 : if(modem == RADIOLIB_MODEM_NONE) {
270 0 : modem = currentModem;
271 : }
272 :
273 : // select interpretation based on modem
274 0 : if(modem == RADIOLIB_MODEM_FSK) {
275 : // set the bit rate
276 0 : state = this->setBitRate(dr.fsk.bitRate);
277 0 : RADIOLIB_ASSERT(state);
278 :
279 : // set the frequency deviation
280 0 : state = this->setFrequencyDeviation(dr.fsk.freqDev);
281 :
282 0 : } else if(modem == RADIOLIB_MODEM_LORA) {
283 : // set the spreading factor
284 0 : state = this->setSpreadingFactor(dr.lora.spreadingFactor);
285 0 : RADIOLIB_ASSERT(state);
286 :
287 : // set the bandwidth
288 0 : state = this->setBandwidth(dr.lora.bandwidth);
289 0 : RADIOLIB_ASSERT(state);
290 :
291 : // set the coding rate
292 0 : state = this->setCodingRate(dr.lora.codingRate);
293 :
294 0 : } else if(modem == RADIOLIB_MODEM_LRFHSS) {
295 : // set the basic config
296 0 : state = this->setLrFhssConfig(dr.lrFhss.bw, dr.lrFhss.cr);
297 0 : RADIOLIB_ASSERT(state);
298 :
299 : // set hopping grid
300 0 : this->lrFhssGridNonFcc = dr.lrFhss.narrowGrid;
301 :
302 : }
303 :
304 0 : return(state);
305 : }
306 :
307 :
308 3 : int16_t SX126x::checkDataRate(DataRate_t dr, ModemType_t modem) {
309 3 : int16_t state = RADIOLIB_ERR_UNKNOWN;
310 :
311 : // retrieve modem if not supplied
312 3 : if(modem == RADIOLIB_MODEM_NONE) {
313 3 : state = this->getModem(&modem);
314 3 : RADIOLIB_ASSERT(state);
315 : }
316 :
317 : // select interpretation based on modem
318 0 : if(modem == RADIOLIB_MODEM_FSK) {
319 0 : RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
320 0 : RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
321 0 : return(RADIOLIB_ERR_NONE);
322 :
323 0 : } else if(modem == RADIOLIB_MODEM_LORA) {
324 0 : RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
325 0 : RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
326 0 : RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
327 0 : return(RADIOLIB_ERR_NONE);
328 :
329 : }
330 :
331 0 : return(state);
332 : }
333 :
334 0 : int16_t SX126x::findRxBw(float rxBw, const uint8_t* lut, size_t lutSize, float rxBwMax, uint8_t* val) {
335 : // lookup tables to avoid comparing a whole bunch of floats
336 0 : const uint16_t rxBwAvg[] = {
337 : 53, 66, 85, 107, 132, 171, 215, 264,
338 : 342, 430, 528, 684, 860, 1056, 1368,
339 : 1717, 2108, 2732, 3428, 4203,
340 : };
341 :
342 : // iterate through the table and find whether the user-provided value
343 : // is lower than the pre-computed average of the adjacent bandwidth values
344 : // if it is, we consider that to be a match even though the actual value is not precise
345 0 : uint16_t rxBwInt = rxBw*10.0f;
346 0 : for(size_t i = 0; i < (lutSize - 1); i++) {
347 0 : if(rxBwInt < rxBwAvg[i]) {
348 0 : *val = lut[i];
349 0 : return(RADIOLIB_ERR_NONE);
350 : }
351 : }
352 :
353 : // if nothing matched up to here, match with the last value
354 0 : if(rxBwInt <= rxBwMax*10) {
355 0 : *val = lut[lutSize - 1];
356 0 : return(RADIOLIB_ERR_NONE);
357 : }
358 :
359 0 : return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH);
360 : }
361 :
362 0 : int16_t SX126x::setRxBandwidth(float rxBw) {
363 : // check active modem
364 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
365 0 : return(RADIOLIB_ERR_WRONG_MODEM);
366 : }
367 :
368 0 : const uint8_t rxBwLut[] = {
369 : RADIOLIB_SX126X_GFSK_RX_BW_4_8,
370 : RADIOLIB_SX126X_GFSK_RX_BW_5_8,
371 : RADIOLIB_SX126X_GFSK_RX_BW_7_3,
372 : RADIOLIB_SX126X_GFSK_RX_BW_9_7,
373 : RADIOLIB_SX126X_GFSK_RX_BW_11_7,
374 : RADIOLIB_SX126X_GFSK_RX_BW_14_6,
375 : RADIOLIB_SX126X_GFSK_RX_BW_19_5,
376 : RADIOLIB_SX126X_GFSK_RX_BW_23_4,
377 : RADIOLIB_SX126X_GFSK_RX_BW_29_3,
378 : RADIOLIB_SX126X_GFSK_RX_BW_39_0,
379 : RADIOLIB_SX126X_GFSK_RX_BW_46_9,
380 : RADIOLIB_SX126X_GFSK_RX_BW_58_6,
381 : RADIOLIB_SX126X_GFSK_RX_BW_78_2,
382 : RADIOLIB_SX126X_GFSK_RX_BW_93_8,
383 : RADIOLIB_SX126X_GFSK_RX_BW_117_3,
384 : RADIOLIB_SX126X_GFSK_RX_BW_156_2,
385 : RADIOLIB_SX126X_GFSK_RX_BW_187_2,
386 : RADIOLIB_SX126X_GFSK_RX_BW_234_3,
387 : RADIOLIB_SX126X_GFSK_RX_BW_312_0,
388 : RADIOLIB_SX126X_GFSK_RX_BW_373_6,
389 : RADIOLIB_SX126X_GFSK_RX_BW_467_0,
390 : };
391 :
392 0 : int16_t state = findRxBw(rxBw, rxBwLut, sizeof(rxBwLut)/sizeof(rxBwLut[0]), 467.0f, &this->rxBandwidth);
393 0 : RADIOLIB_ASSERT(state);
394 :
395 : // update modulation parameters
396 0 : return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
397 : }
398 :
399 0 : int16_t SX126x::setRxBoostedGainMode(bool rxbgm, bool persist) {
400 0 : this->rxBoostedGainMode = rxbgm;
401 :
402 : // update RX gain setting register
403 0 : uint8_t rxGain = rxbgm ? RADIOLIB_SX126X_RX_GAIN_BOOSTED : RADIOLIB_SX126X_RX_GAIN_POWER_SAVING;
404 0 : int16_t state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN, &rxGain, 1);
405 0 : RADIOLIB_ASSERT(state);
406 :
407 : // add Rx Gain register to retention memory if requested
408 0 : if(persist) {
409 : // values and registers below are specified in SX126x datasheet v2.1 section 9.6, just below table 9-3
410 0 : const uint8_t data[] = { 0x01, (uint8_t)((RADIOLIB_SX126X_REG_RX_GAIN >> 8) & 0xFF), (uint8_t)(RADIOLIB_SX126X_REG_RX_GAIN & 0xFF) };
411 0 : state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_0, data, 3);
412 : }
413 :
414 0 : return(state);
415 : }
416 :
417 3 : int16_t SX126x::setDataShaping(uint8_t sh) {
418 : // check active modem
419 3 : uint8_t modem = getPacketType();
420 3 : if((modem != RADIOLIB_SX126X_PACKET_TYPE_GFSK) && (modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS)) {
421 3 : return(RADIOLIB_ERR_WRONG_MODEM);
422 : }
423 :
424 : // set data shaping
425 0 : switch(sh) {
426 0 : case RADIOLIB_SHAPING_NONE:
427 0 : this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_NONE;
428 0 : break;
429 0 : case RADIOLIB_SHAPING_0_3:
430 0 : this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_3;
431 0 : break;
432 0 : case RADIOLIB_SHAPING_0_5:
433 0 : this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5;
434 0 : break;
435 0 : case RADIOLIB_SHAPING_0_7:
436 0 : this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_7;
437 0 : break;
438 0 : case RADIOLIB_SHAPING_1_0:
439 0 : this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_1;
440 0 : break;
441 0 : default:
442 0 : return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
443 : }
444 :
445 : // update modulation parameters
446 0 : return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
447 : }
448 :
449 3 : int16_t SX126x::setSyncWord(uint8_t* syncWord, size_t len) {
450 : // check active modem
451 3 : uint8_t modem = getPacketType();
452 3 : if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
453 : // check sync word Length
454 0 : if(len > 8) {
455 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
456 : }
457 :
458 : // write sync word
459 0 : int16_t state = writeRegister(RADIOLIB_SX126X_REG_SYNC_WORD_0, syncWord, len);
460 0 : RADIOLIB_ASSERT(state);
461 :
462 : // update packet parameters
463 0 : this->syncWordLength = len * 8;
464 :
465 : // maximum preamble detector length is limited by sync word length
466 : // for details, see the note in SX1261 datasheet, Rev 2.1, section 6.2.2.1, page 45
467 0 : uint8_t maxDetLen = RADIOLIB_MIN(this->syncWordLength, this->preambleLengthFSK);
468 0 : this->preambleDetLength = maxDetLen >= 32 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 :
469 : maxDetLen >= 24 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 :
470 : maxDetLen >= 16 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 :
471 : maxDetLen > 0 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 :
472 : RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF;
473 0 : state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening,
474 0 : this->packetType, (this->packetType == RADIOLIB_SX126X_GFSK_PACKET_FIXED) ? this->implicitLen : RADIOLIB_SX126X_MAX_PACKET_LENGTH);
475 0 : return(state);
476 :
477 3 : } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
478 : // with length set to 1 and LoRa modem active, assume it is the LoRa sync word
479 0 : if(len > 1) {
480 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
481 : }
482 0 : return(setSyncWord(syncWord[0]));
483 :
484 3 : } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
485 : // with length set to 4 and LR-FHSS modem active, assume it is the LR-FHSS sync word
486 0 : if(len != sizeof(uint32_t)) {
487 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
488 : }
489 0 : memcpy(this->lrFhssSyncWord, syncWord, sizeof(uint32_t));
490 :
491 : }
492 :
493 3 : return(RADIOLIB_ERR_WRONG_MODEM);
494 : }
495 :
496 0 : int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool inverted) {
497 : // check active modem
498 0 : uint8_t modem = getPacketType();
499 :
500 0 : if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
501 : // update packet parameters
502 0 : switch(len) {
503 0 : case 0:
504 0 : this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_OFF;
505 0 : break;
506 0 : case 1:
507 0 : if(inverted) {
508 0 : this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE_INV;
509 : } else {
510 0 : this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE;
511 : }
512 0 : break;
513 0 : case 2:
514 0 : if(inverted) {
515 0 : this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV;
516 : } else {
517 0 : this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE;
518 : }
519 0 : break;
520 0 : default:
521 0 : return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
522 : }
523 :
524 0 : int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening,
525 0 : this->packetType, (this->packetType == RADIOLIB_SX126X_GFSK_PACKET_FIXED) ? this->implicitLen : RADIOLIB_SX126X_MAX_PACKET_LENGTH);
526 0 : RADIOLIB_ASSERT(state);
527 :
528 : // write initial CRC value
529 0 : uint8_t data[2] = {(uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF)};
530 0 : state = writeRegister(RADIOLIB_SX126X_REG_CRC_INITIAL_MSB, data, 2);
531 0 : RADIOLIB_ASSERT(state);
532 :
533 : // write CRC polynomial value
534 0 : data[0] = (uint8_t)((polynomial >> 8) & 0xFF);
535 0 : data[1] = (uint8_t)(polynomial & 0xFF);
536 0 : state = writeRegister(RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_MSB, data, 2);
537 :
538 0 : return(state);
539 :
540 0 : } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
541 : // LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion
542 :
543 : // update packet parameters
544 0 : if(len) {
545 0 : this->crcTypeLoRa = RADIOLIB_SX126X_LORA_CRC_ON;
546 : } else {
547 0 : this->crcTypeLoRa = RADIOLIB_SX126X_LORA_CRC_OFF;
548 : }
549 :
550 0 : return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled));
551 : }
552 :
553 0 : return(RADIOLIB_ERR_UNKNOWN);
554 : }
555 :
556 3 : int16_t SX126x::setWhitening(bool enabled, uint16_t initial) {
557 : // check active modem
558 3 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
559 3 : return(RADIOLIB_ERR_WRONG_MODEM);
560 : }
561 :
562 0 : int16_t state = RADIOLIB_ERR_NONE;
563 0 : if(!enabled) {
564 : // disable whitening
565 0 : this->whitening = RADIOLIB_SX126X_GFSK_WHITENING_OFF;
566 :
567 0 : state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening,
568 0 : this->packetType, (this->packetType == RADIOLIB_SX126X_GFSK_PACKET_FIXED) ? this->implicitLen : RADIOLIB_SX126X_MAX_PACKET_LENGTH);
569 0 : RADIOLIB_ASSERT(state);
570 :
571 : } else {
572 : // enable whitening
573 0 : this->whitening = RADIOLIB_SX126X_GFSK_WHITENING_ON;
574 :
575 : // write initial whitening value
576 : // as per note on pg. 65 of datasheet v1.2: "The user should not change the value of the 7 MSB's of this register"
577 : uint8_t data[2];
578 : // first read the actual value and mask 7 MSB which we can not change
579 : // if different value is written in 7 MSB, the Rx won't even work (tested on HW)
580 0 : state = readRegister(RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB, data, 1);
581 0 : RADIOLIB_ASSERT(state);
582 :
583 0 : data[0] = (data[0] & 0xFE) | (uint8_t)((initial >> 8) & 0x01);
584 0 : data[1] = (uint8_t)(initial & 0xFF);
585 0 : state = writeRegister(RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB, data, 2);
586 0 : RADIOLIB_ASSERT(state);
587 :
588 0 : state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening,
589 0 : this->packetType, (this->packetType == RADIOLIB_SX126X_GFSK_PACKET_FIXED) ? this->implicitLen : RADIOLIB_SX126X_MAX_PACKET_LENGTH);
590 0 : RADIOLIB_ASSERT(state);
591 : }
592 0 : return(state);
593 : }
594 :
595 0 : int16_t SX126x::fixedPacketLengthMode(uint8_t len) {
596 0 : return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_FIXED, len));
597 : }
598 :
599 0 : int16_t SX126x::variablePacketLengthMode(uint8_t maxLen) {
600 0 : return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_VARIABLE, maxLen));
601 : }
602 0 : int16_t SX126x::implicitHeader(size_t len) {
603 0 : return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_IMPLICIT, len));
604 : }
605 :
606 0 : int16_t SX126x::explicitHeader() {
607 0 : return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_EXPLICIT));
608 : }
609 :
610 0 : int16_t SX126x::setRegulatorLDO() {
611 0 : return(setRegulatorMode(RADIOLIB_SX126X_REGULATOR_LDO));
612 : }
613 :
614 0 : int16_t SX126x::setRegulatorDCDC() {
615 0 : return(setRegulatorMode(RADIOLIB_SX126X_REGULATOR_DC_DC));
616 : }
617 :
618 3 : int16_t SX126x::setEncoding(uint8_t encoding) {
619 3 : return(setWhitening(encoding));
620 : }
621 :
622 0 : void SX126x::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) {
623 0 : this->mod->setRfSwitchPins(rxEn, txEn);
624 0 : }
625 :
626 0 : void SX126x::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) {
627 0 : this->mod->setRfSwitchTable(pins, table);
628 0 : }
629 :
630 0 : int16_t SX126x::forceLDRO(bool enable) {
631 : // check active modem
632 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
633 0 : return(RADIOLIB_ERR_WRONG_MODEM);
634 : }
635 :
636 : // update modulation parameters
637 0 : this->ldroAuto = false;
638 0 : this->ldrOptimize = (uint8_t)enable;
639 0 : return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
640 : }
641 :
642 0 : int16_t SX126x::autoLDRO() {
643 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
644 0 : return(RADIOLIB_ERR_WRONG_MODEM);
645 : }
646 :
647 0 : this->ldroAuto = true;
648 0 : return(RADIOLIB_ERR_NONE);
649 : }
650 :
651 3 : int16_t SX126x::invertIQ(bool enable) {
652 3 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
653 3 : return(RADIOLIB_ERR_WRONG_MODEM);
654 : }
655 :
656 0 : if(enable) {
657 0 : this->invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_INVERTED;
658 : } else {
659 0 : this->invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_STANDARD;
660 : }
661 :
662 0 : return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled));
663 : }
664 :
665 0 : int16_t SX126x::setTCXO(float voltage, uint32_t delay) {
666 : // set mode to standby
667 0 : standby();
668 :
669 : // check RADIOLIB_SX126X_XOSC_START_ERR flag and clear it
670 0 : if(getDeviceErrors() & RADIOLIB_SX126X_XOSC_START_ERR) {
671 0 : clearDeviceErrors();
672 : }
673 :
674 : // check 0 V disable
675 0 : if(fabsf(voltage - 0.0f) <= 0.001f) {
676 0 : return(reset(true));
677 : }
678 :
679 : // check allowed voltage values
680 : uint8_t data[4];
681 0 : if(fabsf(voltage - 1.6f) <= 0.001f) {
682 0 : data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_6;
683 0 : } else if(fabsf(voltage - 1.7f) <= 0.001f) {
684 0 : data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_7;
685 0 : } else if(fabsf(voltage - 1.8f) <= 0.001f) {
686 0 : data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_8;
687 0 : } else if(fabsf(voltage - 2.2f) <= 0.001f) {
688 0 : data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_2;
689 0 : } else if(fabsf(voltage - 2.4f) <= 0.001f) {
690 0 : data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_4;
691 0 : } else if(fabsf(voltage - 2.7f) <= 0.001f) {
692 0 : data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_7;
693 0 : } else if(fabsf(voltage - 3.0f) <= 0.001f) {
694 0 : data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_3_0;
695 0 : } else if(fabsf(voltage - 3.3f) <= 0.001f) {
696 0 : data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_3_3;
697 : } else {
698 0 : return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE);
699 : }
700 :
701 : // calculate delay
702 0 : uint32_t delayValue = (float)delay / 15.625f;
703 0 : data[1] = (uint8_t)((delayValue >> 16) & 0xFF);
704 0 : data[2] = (uint8_t)((delayValue >> 8) & 0xFF);
705 0 : data[3] = (uint8_t)(delayValue & 0xFF);
706 :
707 0 : this->tcxoDelay = delay;
708 :
709 : // enable TCXO control on DIO3
710 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL, data, 4));
711 : }
712 :
713 0 : int16_t SX126x::setDio2AsRfSwitch(bool enable) {
714 0 : this->dio2RfSwitch = enable;
715 0 : uint8_t data = enable ? RADIOLIB_SX126X_DIO2_AS_RF_SWITCH : RADIOLIB_SX126X_DIO2_AS_IRQ;
716 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1));
717 : }
718 :
719 0 : int16_t SX126x::setPaRampTime(uint8_t rampTime) {
720 0 : return(this->setTxParams(this->pwr, rampTime));
721 : }
722 :
723 2 : int16_t SX126x::setOutputPower(int8_t power, uint8_t paDutyCycle, uint8_t hpMax, uint8_t deviceSel) {
724 : // get current OCP configuration
725 2 : uint8_t ocp = 0;
726 2 : int16_t state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
727 2 : RADIOLIB_ASSERT(state);
728 :
729 : // set PA config
730 0 : state = SX126x::setPaConfig(paDutyCycle, deviceSel, hpMax);
731 0 : RADIOLIB_ASSERT(state);
732 :
733 : // set output power with default 200us ramp
734 0 : state = SX126x::setTxParams(power, RADIOLIB_SX126X_PA_RAMP_200U);
735 0 : RADIOLIB_ASSERT(state);
736 :
737 : // restore OCP configuration
738 0 : return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1));
739 : }
740 :
741 0 : void SX126x::setPaTable(SX126x::paTableEntry_t* table) {
742 0 : this->paOptTable = table;
743 0 : }
744 :
745 0 : int16_t SX126x::setPacketMode(uint8_t mode, uint8_t len) {
746 : // check active modem
747 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
748 0 : return(RADIOLIB_ERR_WRONG_MODEM);
749 : }
750 :
751 : // set requested packet mode
752 0 : int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, mode, len);
753 0 : RADIOLIB_ASSERT(state);
754 :
755 : // update cached value
756 0 : this->packetType = mode;
757 0 : this->implicitLen = len;
758 0 : return(state);
759 : }
760 :
761 0 : int16_t SX126x::setHeaderType(uint8_t hdrType, size_t len) {
762 : // check active modem
763 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
764 0 : return(RADIOLIB_ERR_WRONG_MODEM);
765 : }
766 :
767 : // set requested packet mode
768 0 : int16_t state = setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, len, hdrType, this->invertIQEnabled);
769 0 : RADIOLIB_ASSERT(state);
770 :
771 : // update cached value
772 0 : this->headerType = hdrType;
773 0 : this->implicitLen = len;
774 :
775 0 : return(state);
776 : }
777 :
778 0 : int16_t SX126x::setFrequencyRaw(float freq) {
779 : // calculate raw value
780 0 : this->freqMHz = freq;
781 0 : uint32_t frf = (this->freqMHz * (uint32_t(1) << RADIOLIB_SX126X_DIV_EXPONENT)) / RADIOLIB_SX126X_CRYSTAL_FREQ;
782 0 : return(setRfFrequency(frf));
783 : }
784 :
785 0 : int16_t SX126x::config(uint8_t modem) {
786 : // reset buffer base address
787 : int16_t state;
788 0 : if(this->resetOnStartup) {
789 0 : state = setBufferBaseAddress();
790 0 : RADIOLIB_ASSERT(state);
791 : }
792 :
793 : // set modem
794 : uint8_t data[7];
795 0 : data[0] = modem;
796 0 : state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_TYPE, data, 1);
797 0 : RADIOLIB_ASSERT(state);
798 :
799 : // set Rx/Tx fallback mode to STDBY_RC
800 0 : data[0] = this->standbyXOSC ? RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC : RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC;
801 0 : state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1);
802 0 : RADIOLIB_ASSERT(state);
803 :
804 : // set some CAD parameters - will be overwritten when calling CAD anyway
805 0 : data[0] = RADIOLIB_SX126X_CAD_ON_8_SYMB;
806 0 : data[1] = this->spreadingFactor + 13;
807 0 : data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN;
808 0 : data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY;
809 0 : data[4] = 0x00;
810 0 : data[5] = 0x00;
811 0 : data[6] = 0x00;
812 0 : state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7);
813 0 : RADIOLIB_ASSERT(state);
814 :
815 : // clear IRQ
816 0 : state = clearIrqStatus();
817 0 : state |= setDioIrqParams(RADIOLIB_SX126X_IRQ_NONE, RADIOLIB_SX126X_IRQ_NONE);
818 0 : RADIOLIB_ASSERT(state);
819 :
820 : // calibrate all blocks
821 0 : data[0] = RADIOLIB_SX126X_CALIBRATE_ALL;
822 0 : state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE, data, 1, true, false);
823 0 : RADIOLIB_ASSERT(state);
824 :
825 : // wait for calibration completion
826 0 : this->mod->hal->delay(5);
827 0 : while(this->mod->hal->digitalRead(this->mod->getGpio())) {
828 0 : this->mod->hal->yield();
829 : }
830 :
831 : // check calibration result
832 0 : return(this->mod->SPIcheckStream());
833 : }
834 :
835 : #endif
|