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 3 : int16_t SX126x::setBandwidth(uint32_t bw) {
21 3 : RADIOLIB_CHECK_RANGE(bw, 7800, RADIOLIB_UNIT_KILO(500), RADIOLIB_ERR_INVALID_BANDWIDTH);
22 :
23 : // check active modem
24 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
25 0 : return(RADIOLIB_ERR_WRONG_MODEM);
26 : }
27 :
28 0 : switch(bw) {
29 0 : case(7800):
30 0 : this->bandwidth = RADIOLIB_SX126X_LORA_BW_7_8;
31 0 : break;
32 0 : case(10400):
33 0 : this->bandwidth = RADIOLIB_SX126X_LORA_BW_10_4;
34 0 : break;
35 0 : case(15600):
36 0 : this->bandwidth = RADIOLIB_SX126X_LORA_BW_15_6;
37 0 : break;
38 0 : case(20800):
39 0 : this->bandwidth = RADIOLIB_SX126X_LORA_BW_20_8;
40 0 : break;
41 0 : case(31250):
42 0 : this->bandwidth = RADIOLIB_SX126X_LORA_BW_31_25;
43 0 : break;
44 0 : case(41700):
45 0 : this->bandwidth = RADIOLIB_SX126X_LORA_BW_41_7;
46 0 : break;
47 0 : case(62500):
48 0 : this->bandwidth = RADIOLIB_SX126X_LORA_BW_62_5;
49 0 : break;
50 0 : case(RADIOLIB_UNIT_KILO(125)):
51 0 : this->bandwidth = RADIOLIB_SX126X_LORA_BW_125_0;
52 0 : break;
53 0 : case(RADIOLIB_UNIT_KILO(250)):
54 0 : this->bandwidth = RADIOLIB_SX126X_LORA_BW_250_0;
55 0 : break;
56 0 : case(RADIOLIB_UNIT_KILO(500)):
57 0 : this->bandwidth = RADIOLIB_SX126X_LORA_BW_500_0;
58 0 : break;
59 0 : default:
60 0 : return(RADIOLIB_ERR_INVALID_BANDWIDTH);
61 : }
62 :
63 : // update modulation parameters
64 0 : this->bandwidthHz = bw;
65 0 : return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
66 : }
67 :
68 3 : int16_t SX126x::setSpreadingFactor(uint8_t sf) {
69 3 : RADIOLIB_CHECK_RANGE(sf, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
70 :
71 : // check active modem
72 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
73 0 : return(RADIOLIB_ERR_WRONG_MODEM);
74 : }
75 :
76 : // update modulation parameters
77 0 : this->spreadingFactor = sf;
78 0 : return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
79 : }
80 :
81 3 : int16_t SX126x::setCodingRate(uint8_t cr, bool longInterleave) {
82 3 : RADIOLIB_CHECK_RANGE(cr, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
83 :
84 : // check active modem
85 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
86 0 : return(RADIOLIB_ERR_WRONG_MODEM);
87 : }
88 :
89 0 : if(longInterleave) {
90 0 : switch(cr) {
91 0 : case 4:
92 0 : this->codingRate = 0;
93 0 : break;
94 0 : case 5:
95 : case 6:
96 0 : this->codingRate = cr;
97 0 : break;
98 0 : case 8:
99 0 : this->codingRate = cr - 1;
100 0 : break;
101 0 : default:
102 0 : return(RADIOLIB_ERR_INVALID_CODING_RATE);
103 : }
104 : } else {
105 0 : this->codingRate = cr - 4;
106 : }
107 :
108 : // update modulation parameters
109 0 : return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
110 : }
111 :
112 0 : int16_t SX126x::setSyncWord(uint8_t syncWord, uint8_t controlBits) {
113 : // check active modem
114 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
115 0 : return(RADIOLIB_ERR_WRONG_MODEM);
116 : }
117 :
118 : // update register
119 0 : const uint8_t data[2] = {(uint8_t)((syncWord & 0xF0) | ((controlBits & 0xF0) >> 4)), (uint8_t)(((syncWord & 0x0F) << 4) | (controlBits & 0x0F))};
120 0 : return(writeRegister(RADIOLIB_SX126X_REG_LORA_SYNC_WORD_MSB, data, 2));
121 : }
122 :
123 0 : int16_t SX126x::setCurrentLimit(float currentLimit) {
124 : // check allowed range
125 0 : if(!((currentLimit >= 0) && (currentLimit <= 140))) {
126 0 : return(RADIOLIB_ERR_INVALID_CURRENT_LIMIT);
127 : }
128 :
129 : // calculate raw value
130 0 : uint8_t rawLimit = (uint8_t)(currentLimit / 2.5f);
131 :
132 : // update register
133 0 : return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &rawLimit, 1));
134 : }
135 :
136 0 : float SX126x::getCurrentLimit() {
137 : // get the raw value
138 0 : uint8_t ocp = 0;
139 0 : readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
140 :
141 : // return the actual value
142 0 : return((float)ocp * 2.5f);
143 : }
144 :
145 3 : int16_t SX126x::setPreambleLength(size_t preambleLength, size_t preambleDetLength) {
146 3 : uint8_t modem = getPacketType();
147 3 : if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
148 0 : this->preambleLengthLoRa = preambleLength;
149 0 : return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled));
150 3 : } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
151 0 : this->preambleLengthFSK = preambleLength;
152 : // maximum preamble detector length is limited by sync word length
153 : // for details, see the note in SX1261 datasheet, Rev 2.1, section 6.2.2.1, page 45
154 0 : uint8_t maxDetLen = RADIOLIB_MIN(this->syncWordLength, this->preambleLengthFSK);
155 0 : this->preambleDetLength = RADIOLIB_MIN(maxDetLen, preambleDetLength);
156 :
157 : // if no value is specified for preambleDetLength, use the value best corresponding to preambleLength
158 0 : if(preambleDetLength == 0xFFFFFFFF) {
159 0 : this->preambleDetLength = maxDetLen >= 32 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 :
160 : maxDetLen >= 24 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 :
161 : maxDetLen >= 16 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 :
162 : maxDetLen > 0 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 :
163 : RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF;
164 : }
165 0 : return(setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening,
166 0 : this->packetType, (this->packetType == RADIOLIB_SX126X_GFSK_PACKET_FIXED) ? this->implicitLen : RADIOLIB_SX126X_MAX_PACKET_LENGTH));
167 : }
168 :
169 3 : return(RADIOLIB_ERR_UNKNOWN);
170 : }
171 :
172 3 : int16_t SX126x::setFrequencyDeviation(uint32_t freqDev) {
173 : // check active modem
174 3 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
175 3 : return(RADIOLIB_ERR_WRONG_MODEM);
176 : }
177 :
178 : // set frequency deviation to lowest available setting (required for digimodes)
179 0 : uint32_t newFreqDev = freqDev ? freqDev : 600;
180 0 : RADIOLIB_CHECK_RANGE(newFreqDev, 600, RADIOLIB_UNIT_KILO(500), RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
181 :
182 : // calculate raw frequency deviation value
183 0 : uint32_t freqDevRaw = (uint32_t)(((uint64_t)newFreqDev * (1UL << 25)) / (RADIOLIB_UNIT_MEGA(RADIOLIB_SX126X_CRYSTAL_FREQ)));
184 :
185 : // check modulation parameters
186 0 : this->frequencyDev = freqDevRaw;
187 :
188 : // update modulation parameters
189 0 : return(setModulationParamsFSK(this->bitRateRaw, this->pulseShape, this->rxBandwidth, this->frequencyDev));
190 : }
191 :
192 3 : int16_t SX126x::setBitRate(uint32_t br) {
193 : // check active modem and valid range
194 : uint32_t brRaw;
195 3 : uint8_t modem = getPacketType();
196 3 : if(modem == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
197 : // at the moment only the very specific 488.28125 bps rate is supported
198 0 : if(br != 488) { return(RADIOLIB_ERR_INVALID_BIT_RATE); }
199 0 : brRaw = RADIOLIB_SX126X_LR_FHSS_BIT_RATE_RAW;
200 3 : } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_BPSK) {
201 : // this should be just either 100 or 600 bps, not the range
202 : // but the BPSK support is so experimental it probably does not matter
203 0 : RADIOLIB_CHECK_RANGE(br, 100, 600, RADIOLIB_ERR_INVALID_BIT_RATE);
204 0 : brRaw = RADIOLIB_SX126X_BIT_RATE_RAW(br);
205 3 : } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
206 0 : RADIOLIB_CHECK_RANGE(br, 600, RADIOLIB_UNIT_KILO(300), RADIOLIB_ERR_INVALID_BIT_RATE);
207 0 : brRaw = RADIOLIB_SX126X_BIT_RATE_RAW(br);
208 : } else {
209 3 : return(RADIOLIB_ERR_WRONG_MODEM);
210 : }
211 :
212 : // check modulation parameters
213 0 : this->bitRateRaw = brRaw;
214 :
215 : // update modulation parameters
216 0 : int16_t state = RADIOLIB_ERR_UNKNOWN;
217 0 : if(modem == RADIOLIB_SX126X_PACKET_TYPE_BPSK) {
218 0 : state = setModulationParamsBPSK(this->bitRateRaw);
219 : } else {
220 0 : state = setModulationParamsFSK(this->bitRateRaw, this->pulseShape, this->rxBandwidth, this->frequencyDev);
221 : }
222 0 : RADIOLIB_ASSERT(state);
223 :
224 : // apply workaround or reset it, as needed
225 0 : return(fixGFSK());
226 : }
227 :
228 3 : int16_t SX126x::checkDataRate(DataRate_t dr, ModemType_t modem) {
229 3 : int16_t state = RADIOLIB_ERR_UNKNOWN;
230 :
231 : // retrieve modem if not supplied
232 3 : if(modem == RADIOLIB_MODEM_NONE) {
233 3 : state = this->getModem(&modem);
234 3 : RADIOLIB_ASSERT(state);
235 : }
236 :
237 : // select interpretation based on modem
238 0 : if(modem == RADIOLIB_MODEM_FSK) {
239 0 : RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 600, RADIOLIB_UNIT_KILO(300), RADIOLIB_ERR_INVALID_BIT_RATE);
240 0 : RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 600, RADIOLIB_UNIT_KILO(200), RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
241 0 : return(RADIOLIB_ERR_NONE);
242 :
243 0 : } else if(modem == RADIOLIB_MODEM_LORA) {
244 0 : RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
245 0 : RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 7800, RADIOLIB_UNIT_KILO(500), RADIOLIB_ERR_INVALID_BANDWIDTH);
246 0 : RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
247 0 : return(RADIOLIB_ERR_NONE);
248 :
249 : }
250 :
251 0 : return(state);
252 : }
253 :
254 0 : int16_t SX126x::setRxBandwidth(uint32_t rxBw) {
255 : // check active modem
256 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
257 0 : return(RADIOLIB_ERR_WRONG_MODEM);
258 : }
259 :
260 0 : const uint32_t rxBwAvg[] = {
261 : 5300, 6600, 8500, 10700, 13200, 17100, 21500, 26400,
262 : 34200, 43000, 52800, 68400, 86000, 105600, 136800,
263 : 171700, 210800, 273200, 342800, 420300,
264 : };
265 :
266 0 : const uint8_t rxBwLut[] = {
267 : RADIOLIB_SX126X_GFSK_RX_BW_4_8,
268 : RADIOLIB_SX126X_GFSK_RX_BW_5_8,
269 : RADIOLIB_SX126X_GFSK_RX_BW_7_3,
270 : RADIOLIB_SX126X_GFSK_RX_BW_9_7,
271 : RADIOLIB_SX126X_GFSK_RX_BW_11_7,
272 : RADIOLIB_SX126X_GFSK_RX_BW_14_6,
273 : RADIOLIB_SX126X_GFSK_RX_BW_19_5,
274 : RADIOLIB_SX126X_GFSK_RX_BW_23_4,
275 : RADIOLIB_SX126X_GFSK_RX_BW_29_3,
276 : RADIOLIB_SX126X_GFSK_RX_BW_39_0,
277 : RADIOLIB_SX126X_GFSK_RX_BW_46_9,
278 : RADIOLIB_SX126X_GFSK_RX_BW_58_6,
279 : RADIOLIB_SX126X_GFSK_RX_BW_78_2,
280 : RADIOLIB_SX126X_GFSK_RX_BW_93_8,
281 : RADIOLIB_SX126X_GFSK_RX_BW_117_3,
282 : RADIOLIB_SX126X_GFSK_RX_BW_156_2,
283 : RADIOLIB_SX126X_GFSK_RX_BW_187_2,
284 : RADIOLIB_SX126X_GFSK_RX_BW_234_3,
285 : RADIOLIB_SX126X_GFSK_RX_BW_312_0,
286 : RADIOLIB_SX126X_GFSK_RX_BW_373_6,
287 : RADIOLIB_SX126X_GFSK_RX_BW_467_0,
288 : };
289 :
290 0 : int16_t state = findRxBw(rxBw, rxBwAvg, rxBwLut, sizeof(rxBwLut)/sizeof(rxBwLut[0]), RADIOLIB_UNIT_KILO(467), &this->rxBandwidth);
291 0 : RADIOLIB_ASSERT(state);
292 :
293 : // update modulation parameters
294 0 : return(setModulationParamsFSK(this->bitRateRaw, this->pulseShape, this->rxBandwidth, this->frequencyDev));
295 : }
296 :
297 0 : int16_t SX126x::setRxBoostedGainMode(bool rxbgm, bool persist) {
298 0 : this->rxBoostedGainMode = rxbgm;
299 :
300 : // update RX gain setting register
301 0 : uint8_t rxGain = rxbgm ? RADIOLIB_SX126X_RX_GAIN_BOOSTED : RADIOLIB_SX126X_RX_GAIN_POWER_SAVING;
302 0 : int16_t state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN, &rxGain, 1);
303 0 : RADIOLIB_ASSERT(state);
304 :
305 : // add Rx Gain register to retention memory if requested
306 0 : if(persist) {
307 : // values and registers below are specified in SX126x datasheet v2.1 section 9.6, just below table 9-3
308 0 : const uint8_t data[] = { 0x01, (uint8_t)((RADIOLIB_SX126X_REG_RX_GAIN >> 8) & 0xFF), (uint8_t)(RADIOLIB_SX126X_REG_RX_GAIN & 0xFF) };
309 0 : state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_0, data, 3);
310 : }
311 :
312 0 : return(state);
313 : }
314 :
315 3 : int16_t SX126x::setDataShaping(uint8_t sh) {
316 : // check active modem
317 3 : uint8_t modem = getPacketType();
318 3 : if((modem != RADIOLIB_SX126X_PACKET_TYPE_GFSK) && (modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS)) {
319 3 : return(RADIOLIB_ERR_WRONG_MODEM);
320 : }
321 :
322 : // set data shaping
323 0 : switch(sh) {
324 0 : case RADIOLIB_SHAPING_NONE:
325 0 : this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_NONE;
326 0 : break;
327 0 : case RADIOLIB_SHAPING_0_3:
328 0 : this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_3;
329 0 : break;
330 0 : case RADIOLIB_SHAPING_0_5:
331 0 : this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5;
332 0 : break;
333 0 : case RADIOLIB_SHAPING_0_7:
334 0 : this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_7;
335 0 : break;
336 0 : case RADIOLIB_SHAPING_1_0:
337 0 : this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_1;
338 0 : break;
339 0 : default:
340 0 : return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
341 : }
342 :
343 : // update modulation parameters
344 0 : return(setModulationParamsFSK(this->bitRateRaw, this->pulseShape, this->rxBandwidth, this->frequencyDev));
345 : }
346 :
347 3 : int16_t SX126x::setSyncWord(uint8_t* syncWord, size_t len) {
348 : // check active modem
349 3 : uint8_t modem = getPacketType();
350 3 : if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
351 : // check sync word Length
352 0 : if(len > 8) {
353 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
354 : }
355 :
356 : // write sync word
357 0 : int16_t state = writeRegister(RADIOLIB_SX126X_REG_SYNC_WORD_0, syncWord, len);
358 0 : RADIOLIB_ASSERT(state);
359 :
360 : // update packet parameters
361 0 : this->syncWordLength = len * 8;
362 :
363 : // maximum preamble detector length is limited by sync word length
364 : // for details, see the note in SX1261 datasheet, Rev 2.1, section 6.2.2.1, page 45
365 0 : uint8_t maxDetLen = RADIOLIB_MIN(this->syncWordLength, this->preambleLengthFSK);
366 0 : this->preambleDetLength = maxDetLen >= 32 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 :
367 : maxDetLen >= 24 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 :
368 : maxDetLen >= 16 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 :
369 : maxDetLen > 0 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 :
370 : RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF;
371 0 : state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening,
372 0 : this->packetType, (this->packetType == RADIOLIB_SX126X_GFSK_PACKET_FIXED) ? this->implicitLen : RADIOLIB_SX126X_MAX_PACKET_LENGTH);
373 0 : return(state);
374 :
375 3 : } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
376 : // with length set to 1 and LoRa modem active, assume it is the LoRa sync word
377 0 : if(len > 1) {
378 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
379 : }
380 0 : return(setSyncWord(syncWord[0]));
381 :
382 3 : } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
383 : // with length set to 4 and LR-FHSS modem active, assume it is the LR-FHSS sync word
384 0 : if(len != sizeof(uint32_t)) {
385 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
386 : }
387 0 : memcpy(this->lrFhssSyncWord, syncWord, sizeof(uint32_t));
388 :
389 : }
390 :
391 3 : return(RADIOLIB_ERR_WRONG_MODEM);
392 : }
393 :
394 0 : int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool inverted) {
395 : // check active modem
396 0 : uint8_t modem = getPacketType();
397 :
398 0 : if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
399 : // update packet parameters
400 0 : switch(len) {
401 0 : case 0:
402 0 : this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_OFF;
403 0 : break;
404 0 : case 1:
405 0 : if(inverted) {
406 0 : this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE_INV;
407 : } else {
408 0 : this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE;
409 : }
410 0 : break;
411 0 : case 2:
412 0 : if(inverted) {
413 0 : this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV;
414 : } else {
415 0 : this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE;
416 : }
417 0 : break;
418 0 : default:
419 0 : return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
420 : }
421 :
422 0 : int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening,
423 0 : this->packetType, (this->packetType == RADIOLIB_SX126X_GFSK_PACKET_FIXED) ? this->implicitLen : RADIOLIB_SX126X_MAX_PACKET_LENGTH);
424 0 : RADIOLIB_ASSERT(state);
425 :
426 : // write initial CRC value
427 0 : uint8_t data[2] = {(uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF)};
428 0 : state = writeRegister(RADIOLIB_SX126X_REG_CRC_INITIAL_MSB, data, 2);
429 0 : RADIOLIB_ASSERT(state);
430 :
431 : // write CRC polynomial value
432 0 : data[0] = (uint8_t)((polynomial >> 8) & 0xFF);
433 0 : data[1] = (uint8_t)(polynomial & 0xFF);
434 0 : state = writeRegister(RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_MSB, data, 2);
435 :
436 0 : return(state);
437 :
438 0 : } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
439 : // LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion
440 :
441 : // update packet parameters
442 0 : if(len) {
443 0 : this->crcTypeLoRa = RADIOLIB_SX126X_LORA_CRC_ON;
444 : } else {
445 0 : this->crcTypeLoRa = RADIOLIB_SX126X_LORA_CRC_OFF;
446 : }
447 :
448 0 : return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled));
449 : }
450 :
451 0 : return(RADIOLIB_ERR_UNKNOWN);
452 : }
453 :
454 3 : int16_t SX126x::setWhitening(bool enabled, uint16_t initial) {
455 : // check active modem
456 3 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
457 3 : return(RADIOLIB_ERR_WRONG_MODEM);
458 : }
459 :
460 0 : int16_t state = RADIOLIB_ERR_NONE;
461 0 : if(!enabled) {
462 : // disable whitening
463 0 : this->whitening = RADIOLIB_SX126X_GFSK_WHITENING_OFF;
464 :
465 0 : state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening,
466 0 : this->packetType, (this->packetType == RADIOLIB_SX126X_GFSK_PACKET_FIXED) ? this->implicitLen : RADIOLIB_SX126X_MAX_PACKET_LENGTH);
467 0 : RADIOLIB_ASSERT(state);
468 :
469 : } else {
470 : // enable whitening
471 0 : this->whitening = RADIOLIB_SX126X_GFSK_WHITENING_ON;
472 :
473 : // write initial whitening value
474 : // 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"
475 : uint8_t data[2];
476 : // first read the actual value and mask 7 MSB which we can not change
477 : // if different value is written in 7 MSB, the Rx won't even work (tested on HW)
478 0 : state = readRegister(RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB, data, 1);
479 0 : RADIOLIB_ASSERT(state);
480 :
481 0 : data[0] = (data[0] & 0xFE) | (uint8_t)((initial >> 8) & 0x01);
482 0 : data[1] = (uint8_t)(initial & 0xFF);
483 0 : state = writeRegister(RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB, data, 2);
484 0 : RADIOLIB_ASSERT(state);
485 :
486 0 : state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening,
487 0 : this->packetType, (this->packetType == RADIOLIB_SX126X_GFSK_PACKET_FIXED) ? this->implicitLen : RADIOLIB_SX126X_MAX_PACKET_LENGTH);
488 0 : RADIOLIB_ASSERT(state);
489 : }
490 0 : return(state);
491 : }
492 :
493 0 : int16_t SX126x::fixedPacketLengthMode(uint8_t len) {
494 0 : return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_FIXED, len));
495 : }
496 :
497 0 : int16_t SX126x::variablePacketLengthMode(uint8_t maxLen) {
498 0 : return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_VARIABLE, maxLen));
499 : }
500 0 : int16_t SX126x::implicitHeader(size_t len) {
501 0 : return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_IMPLICIT, len));
502 : }
503 :
504 0 : int16_t SX126x::explicitHeader() {
505 0 : return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_EXPLICIT));
506 : }
507 :
508 0 : int16_t SX126x::setRegulatorLDO() {
509 0 : return(setRegulatorMode(RADIOLIB_SX126X_REGULATOR_LDO));
510 : }
511 :
512 0 : int16_t SX126x::setRegulatorDCDC() {
513 0 : return(setRegulatorMode(RADIOLIB_SX126X_REGULATOR_DC_DC));
514 : }
515 :
516 3 : int16_t SX126x::setEncoding(uint8_t encoding) {
517 3 : return(setWhitening(encoding));
518 : }
519 :
520 0 : void SX126x::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) {
521 0 : this->mod->setRfSwitchPins(rxEn, txEn);
522 0 : }
523 :
524 0 : void SX126x::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) {
525 0 : this->mod->setRfSwitchTable(pins, table);
526 0 : }
527 :
528 0 : int16_t SX126x::forceLDRO(bool enable) {
529 : // check active modem
530 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
531 0 : return(RADIOLIB_ERR_WRONG_MODEM);
532 : }
533 :
534 : // update modulation parameters
535 0 : this->ldroAuto = false;
536 0 : this->ldrOptimize = (uint8_t)enable;
537 0 : return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
538 : }
539 :
540 0 : int16_t SX126x::autoLDRO() {
541 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
542 0 : return(RADIOLIB_ERR_WRONG_MODEM);
543 : }
544 :
545 0 : this->ldroAuto = true;
546 0 : return(RADIOLIB_ERR_NONE);
547 : }
548 :
549 3 : int16_t SX126x::invertIQ(bool enable) {
550 3 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
551 3 : return(RADIOLIB_ERR_WRONG_MODEM);
552 : }
553 :
554 0 : if(enable) {
555 0 : this->invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_INVERTED;
556 : } else {
557 0 : this->invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_STANDARD;
558 : }
559 :
560 0 : return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled));
561 : }
562 :
563 0 : int16_t SX126x::setTCXO(RadioLibTCXOVoltage_t voltage, uint32_t delay) {
564 : // set mode to standby
565 : // force RC oscillator - typically this is called on startup,
566 : // so we cannot rely on what the user may have provided
567 0 : (void)standby(RADIOLIB_SX126X_STANDBY_RC);
568 :
569 : // check RADIOLIB_SX126X_XOSC_START_ERR flag and clear it
570 0 : if(getDeviceErrors() & RADIOLIB_SX126X_XOSC_START_ERR) {
571 0 : clearDeviceErrors();
572 : }
573 :
574 : // check disable
575 0 : if(voltage == RadioLibTCXOVoltage_t::VoltageNone) {
576 0 : return(reset(true));
577 : }
578 :
579 : // check allowed voltage values
580 0 : if(voltage > RadioLibTCXOVoltage_t::Voltage3V3) {
581 0 : return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE);
582 : }
583 :
584 : // calculate delay
585 0 : this->tcxoDelay = delay;
586 0 : uint32_t delayValue = (this->tcxoDelay * 8) / 125; // divide by 15.625
587 : const uint8_t data[] = {
588 0 : (uint8_t)voltage, (uint8_t)((delayValue >> 16) & 0xFF),
589 0 : (uint8_t)((delayValue >> 8) & 0xFF), (uint8_t)(delayValue & 0xFF),
590 0 : };
591 :
592 : // enable TCXO control on DIO3
593 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL, data, 4));
594 : }
595 :
596 0 : int16_t SX126x::setDio2AsRfSwitch(bool enable) {
597 0 : this->dio2RfSwitch = enable;
598 0 : uint8_t data = enable ? RADIOLIB_SX126X_DIO2_AS_RF_SWITCH : RADIOLIB_SX126X_DIO2_AS_IRQ;
599 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1));
600 : }
601 :
602 0 : int16_t SX126x::setPaRampTime(uint8_t rampTime) {
603 0 : return(this->setTxParams(this->pwr, rampTime));
604 : }
605 :
606 2 : int16_t SX126x::setOutputPower(int8_t power, uint8_t paDutyCycle, uint8_t hpMax, uint8_t deviceSel) {
607 : // get current OCP configuration
608 2 : uint8_t ocp = 0;
609 2 : int16_t state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
610 2 : RADIOLIB_ASSERT(state);
611 :
612 : // set PA config
613 0 : state = SX126x::setPaConfig(paDutyCycle, deviceSel, hpMax);
614 0 : RADIOLIB_ASSERT(state);
615 :
616 : // set output power with default 200us ramp
617 0 : state = SX126x::setTxParams(power, RADIOLIB_SX126X_PA_RAMP_200U);
618 0 : RADIOLIB_ASSERT(state);
619 :
620 : // restore OCP configuration
621 0 : return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1));
622 : }
623 :
624 0 : void SX126x::setPaTable(SX126x::paTableEntry_t* table) {
625 0 : this->paOptTable = table;
626 0 : }
627 :
628 0 : int16_t SX126x::setStandbyXOSC(bool enable) {
629 : // set the internal variable
630 0 : this->standbyXOSC = enable;
631 :
632 : // call standby to start the oscillator
633 0 : int16_t state = standby();
634 0 : RADIOLIB_ASSERT(state);
635 :
636 : // update Rx/Tx fallback mode
637 0 : uint8_t mode = this->standbyXOSC ? RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC : RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC;
638 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE, &mode, 1));
639 : }
640 :
641 0 : int16_t SX126x::setPacketMode(uint8_t mode, uint8_t len) {
642 : // check active modem
643 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
644 0 : return(RADIOLIB_ERR_WRONG_MODEM);
645 : }
646 :
647 : // set requested packet mode
648 0 : int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, mode, len);
649 0 : RADIOLIB_ASSERT(state);
650 :
651 : // update cached value
652 0 : this->packetType = mode;
653 0 : this->implicitLen = len;
654 0 : return(state);
655 : }
656 :
657 0 : int16_t SX126x::setHeaderType(uint8_t hdrType, size_t len) {
658 : // check active modem
659 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
660 0 : return(RADIOLIB_ERR_WRONG_MODEM);
661 : }
662 :
663 : // set requested packet mode
664 0 : int16_t state = setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, len, hdrType, this->invertIQEnabled);
665 0 : RADIOLIB_ASSERT(state);
666 :
667 : // update cached value
668 0 : this->headerType = hdrType;
669 0 : this->implicitLen = len;
670 :
671 0 : return(state);
672 : }
673 :
674 0 : int16_t SX126x::setFrequencyRaw(uint32_t freq) {
675 : // calculate raw value
676 0 : this->freqHz = freq;
677 0 : uint32_t frf = ((uint64_t)this->freqHz * (uint64_t)((uint64_t)1 << RADIOLIB_SX126X_DIV_EXPONENT)) / RADIOLIB_UNIT_MEGA(RADIOLIB_SX126X_CRYSTAL_FREQ);
678 0 : return(setRfFrequency(frf));
679 : }
680 :
681 0 : int16_t SX126x::config(uint8_t modem) {
682 : // reset buffer base address
683 : int16_t state;
684 0 : if(this->resetOnStartup) {
685 0 : state = setBufferBaseAddress();
686 0 : RADIOLIB_ASSERT(state);
687 : }
688 :
689 : // set modem
690 : uint8_t data[7];
691 0 : data[0] = modem;
692 0 : state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_TYPE, data, 1);
693 0 : RADIOLIB_ASSERT(state);
694 :
695 : // set Rx/Tx fallback mode to STDBY_RC
696 0 : data[0] = this->standbyXOSC ? RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC : RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC;
697 0 : state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1);
698 0 : RADIOLIB_ASSERT(state);
699 :
700 : // set some CAD parameters - will be overwritten when calling CAD anyway
701 0 : data[0] = RADIOLIB_SX126X_CAD_ON_8_SYMB;
702 0 : data[1] = this->spreadingFactor + 13;
703 0 : data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN;
704 0 : data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY;
705 0 : data[4] = 0x00;
706 0 : data[5] = 0x00;
707 0 : data[6] = 0x00;
708 0 : state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7);
709 0 : RADIOLIB_ASSERT(state);
710 :
711 : // clear IRQ
712 0 : state = clearIrqStatus();
713 0 : state |= setDioIrqParams(RADIOLIB_SX126X_IRQ_NONE, RADIOLIB_SX126X_IRQ_NONE);
714 0 : RADIOLIB_ASSERT(state);
715 :
716 : // calibrate all blocks
717 0 : data[0] = RADIOLIB_SX126X_CALIBRATE_ALL;
718 0 : state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE, data, 1, true, false);
719 0 : RADIOLIB_ASSERT(state);
720 :
721 : // wait for calibration completion
722 0 : this->mod->hal->delay(5);
723 0 : while(this->mod->hal->digitalRead(this->mod->getGpio())) {
724 0 : this->mod->hal->yield();
725 : }
726 :
727 : // check calibration result
728 0 : return(this->mod->SPIcheckStream());
729 : }
730 :
731 : #endif
|