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 0 : int16_t SX126x::setPreambleLength(size_t preambleLength) {
173 0 : uint8_t modem = getPacketType();
174 0 : 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 0 : } 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, this->packetType));
188 : }
189 :
190 0 : return(RADIOLIB_ERR_UNKNOWN);
191 : }
192 :
193 0 : int16_t SX126x::setFrequencyDeviation(float freqDev) {
194 : // check active modem
195 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
196 0 : return(RADIOLIB_ERR_WRONG_MODEM);
197 : }
198 :
199 : // set frequency deviation to lowest available setting (required for digimodes)
200 0 : float newFreqDev = freqDev;
201 0 : if(freqDev < 0.0f) {
202 0 : newFreqDev = 0.6f;
203 : }
204 :
205 0 : RADIOLIB_CHECK_RANGE(newFreqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
206 :
207 : // calculate raw frequency deviation value
208 0 : uint32_t freqDevRaw = (uint32_t)(((newFreqDev * 1000.0f) * (float)((uint32_t)(1) << 25)) / (RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0f));
209 :
210 : // check modulation parameters
211 0 : this->frequencyDev = freqDevRaw;
212 :
213 : // update modulation parameters
214 0 : return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
215 : }
216 :
217 0 : int16_t SX126x::setBitRate(float br) {
218 : // check active modem
219 0 : uint8_t modem = getPacketType();
220 0 : if((modem != RADIOLIB_SX126X_PACKET_TYPE_GFSK) &&
221 0 : (modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) &&
222 : (modem != RADIOLIB_SX126X_PACKET_TYPE_BPSK)) {
223 0 : return(RADIOLIB_ERR_WRONG_MODEM);
224 : }
225 :
226 0 : if(modem == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
227 0 : RADIOLIB_CHECK_RANGE(br, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
228 0 : } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_BPSK) {
229 : // this should be just either 100 or 600 bps, not the range
230 : // but the BPSK support is so experimental it probably does not matter
231 0 : RADIOLIB_CHECK_RANGE(br, 0.1f, 0.6f, RADIOLIB_ERR_INVALID_BIT_RATE);
232 : }
233 :
234 : // calculate raw bit rate value
235 0 : uint32_t brRaw = (uint32_t)((RADIOLIB_SX126X_CRYSTAL_FREQ * 1000000.0f * 32.0f) / (br * 1000.0f));
236 :
237 : // check modulation parameters
238 0 : this->bitRate = brRaw;
239 :
240 : // update modulation parameters
241 0 : int16_t state = RADIOLIB_ERR_UNKNOWN;
242 0 : if(modem == RADIOLIB_SX126X_PACKET_TYPE_BPSK) {
243 0 : state = setModulationParamsBPSK(this->bitRate);
244 : } else {
245 0 : state = setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev);
246 : }
247 0 : RADIOLIB_ASSERT(state);
248 :
249 : // apply workaround or reset it, as needed
250 0 : return(fixGFSK());
251 : }
252 :
253 0 : int16_t SX126x::setDataRate(DataRate_t dr, ModemType_t modem) {
254 : // get the current modem
255 : ModemType_t currentModem;
256 0 : int16_t state = this->getModem(¤tModem);
257 0 : RADIOLIB_ASSERT(state);
258 :
259 : // switch over if the requested modem is different
260 0 : if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) {
261 0 : state = this->standby();
262 0 : RADIOLIB_ASSERT(state);
263 0 : state = this->setModem(modem);
264 0 : RADIOLIB_ASSERT(state);
265 : }
266 :
267 0 : if(modem == RADIOLIB_MODEM_NONE) {
268 0 : modem = currentModem;
269 : }
270 :
271 : // select interpretation based on modem
272 0 : if(modem == RADIOLIB_MODEM_FSK) {
273 : // set the bit rate
274 0 : state = this->setBitRate(dr.fsk.bitRate);
275 0 : RADIOLIB_ASSERT(state);
276 :
277 : // set the frequency deviation
278 0 : state = this->setFrequencyDeviation(dr.fsk.freqDev);
279 :
280 0 : } else if(modem == RADIOLIB_MODEM_LORA) {
281 : // set the spreading factor
282 0 : state = this->setSpreadingFactor(dr.lora.spreadingFactor);
283 0 : RADIOLIB_ASSERT(state);
284 :
285 : // set the bandwidth
286 0 : state = this->setBandwidth(dr.lora.bandwidth);
287 0 : RADIOLIB_ASSERT(state);
288 :
289 : // set the coding rate
290 0 : state = this->setCodingRate(dr.lora.codingRate);
291 :
292 0 : } else if(modem == RADIOLIB_MODEM_LRFHSS) {
293 : // set the basic config
294 0 : state = this->setLrFhssConfig(dr.lrFhss.bw, dr.lrFhss.cr);
295 0 : RADIOLIB_ASSERT(state);
296 :
297 : // set hopping grid
298 0 : this->lrFhssGridNonFcc = dr.lrFhss.narrowGrid ? RADIOLIB_SX126X_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_SX126X_LR_FHSS_GRID_STEP_FCC;
299 :
300 : }
301 :
302 0 : return(state);
303 : }
304 :
305 :
306 0 : int16_t SX126x::checkDataRate(DataRate_t dr, ModemType_t modem) {
307 0 : int16_t state = RADIOLIB_ERR_UNKNOWN;
308 :
309 : // retrieve modem if not supplied
310 0 : if(modem == RADIOLIB_MODEM_NONE) {
311 0 : state = this->getModem(&modem);
312 0 : RADIOLIB_ASSERT(state);
313 : }
314 :
315 : // select interpretation based on modem
316 0 : if(modem == RADIOLIB_MODEM_FSK) {
317 0 : RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
318 0 : RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6f, 200.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
319 0 : return(RADIOLIB_ERR_NONE);
320 :
321 0 : } else if(modem == RADIOLIB_MODEM_LORA) {
322 0 : RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
323 0 : RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
324 0 : RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
325 0 : return(RADIOLIB_ERR_NONE);
326 :
327 : }
328 :
329 0 : return(state);
330 : }
331 :
332 0 : int16_t SX126x::setRxBandwidth(float rxBw) {
333 : // check active modem
334 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
335 0 : return(RADIOLIB_ERR_WRONG_MODEM);
336 : }
337 :
338 : // check modulation parameters
339 : /*if(2 * this->frequencyDev + this->bitRate > rxBw * 1000.0) {
340 : return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS);
341 : }*/
342 0 : this->rxBandwidthKhz = rxBw;
343 :
344 : // check allowed receiver bandwidth values
345 0 : if(fabsf(rxBw - 4.8f) <= 0.001f) {
346 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_4_8;
347 0 : } else if(fabsf(rxBw - 5.8f) <= 0.001f) {
348 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_5_8;
349 0 : } else if(fabsf(rxBw - 7.3f) <= 0.001f) {
350 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_7_3;
351 0 : } else if(fabsf(rxBw - 9.7f) <= 0.001f) {
352 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_9_7;
353 0 : } else if(fabsf(rxBw - 11.7f) <= 0.001f) {
354 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_11_7;
355 0 : } else if(fabsf(rxBw - 14.6f) <= 0.001f) {
356 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_14_6;
357 0 : } else if(fabsf(rxBw - 19.5f) <= 0.001f) {
358 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_19_5;
359 0 : } else if(fabsf(rxBw - 23.4f) <= 0.001f) {
360 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_23_4;
361 0 : } else if(fabsf(rxBw - 29.3f) <= 0.001f) {
362 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_29_3;
363 0 : } else if(fabsf(rxBw - 39.0f) <= 0.001f) {
364 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_39_0;
365 0 : } else if(fabsf(rxBw - 46.9f) <= 0.001f) {
366 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_46_9;
367 0 : } else if(fabsf(rxBw - 58.6f) <= 0.001f) {
368 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_58_6;
369 0 : } else if(fabsf(rxBw - 78.2f) <= 0.001f) {
370 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_78_2;
371 0 : } else if(fabsf(rxBw - 93.8f) <= 0.001f) {
372 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_93_8;
373 0 : } else if(fabsf(rxBw - 117.3f) <= 0.001f) {
374 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_117_3;
375 0 : } else if(fabsf(rxBw - 156.2f) <= 0.001f) {
376 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_156_2;
377 0 : } else if(fabsf(rxBw - 187.2f) <= 0.001f) {
378 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_187_2;
379 0 : } else if(fabsf(rxBw - 234.3f) <= 0.001f) {
380 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_234_3;
381 0 : } else if(fabsf(rxBw - 312.0f) <= 0.001f) {
382 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_312_0;
383 0 : } else if(fabsf(rxBw - 373.6f) <= 0.001f) {
384 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_373_6;
385 0 : } else if(fabsf(rxBw - 467.0f) <= 0.001f) {
386 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_467_0;
387 : } else {
388 0 : return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH);
389 : }
390 :
391 : // update modulation parameters
392 0 : return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
393 : }
394 :
395 0 : int16_t SX126x::setRxBoostedGainMode(bool rxbgm, bool persist) {
396 : // update RX gain setting register
397 0 : uint8_t rxGain = rxbgm ? RADIOLIB_SX126X_RX_GAIN_BOOSTED : RADIOLIB_SX126X_RX_GAIN_POWER_SAVING;
398 0 : int16_t state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN, &rxGain, 1);
399 0 : RADIOLIB_ASSERT(state);
400 :
401 : // add Rx Gain register to retention memory if requested
402 0 : if(persist) {
403 : // values and registers below are specified in SX126x datasheet v2.1 section 9.6, just below table 9-3
404 0 : const uint8_t data[] = { 0x01, (uint8_t)((RADIOLIB_SX126X_REG_RX_GAIN >> 8) & 0xFF), (uint8_t)(RADIOLIB_SX126X_REG_RX_GAIN & 0xFF) };
405 0 : state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_0, data, 3);
406 : }
407 :
408 0 : return(state);
409 : }
410 :
411 0 : int16_t SX126x::setDataShaping(uint8_t sh) {
412 : // check active modem
413 0 : uint8_t modem = getPacketType();
414 0 : if((modem != RADIOLIB_SX126X_PACKET_TYPE_GFSK) && (modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS)) {
415 0 : return(RADIOLIB_ERR_WRONG_MODEM);
416 : }
417 :
418 : // set data shaping
419 0 : switch(sh) {
420 0 : case RADIOLIB_SHAPING_NONE:
421 0 : this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_NONE;
422 0 : break;
423 0 : case RADIOLIB_SHAPING_0_3:
424 0 : this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_3;
425 0 : break;
426 0 : case RADIOLIB_SHAPING_0_5:
427 0 : this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5;
428 0 : break;
429 0 : case RADIOLIB_SHAPING_0_7:
430 0 : this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_7;
431 0 : break;
432 0 : case RADIOLIB_SHAPING_1_0:
433 0 : this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_1;
434 0 : break;
435 0 : default:
436 0 : return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
437 : }
438 :
439 : // update modulation parameters
440 0 : return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
441 : }
442 :
443 0 : int16_t SX126x::setSyncWord(uint8_t* syncWord, size_t len) {
444 : // check active modem
445 0 : uint8_t modem = getPacketType();
446 0 : if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
447 : // check sync word Length
448 0 : if(len > 8) {
449 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
450 : }
451 :
452 : // write sync word
453 0 : int16_t state = writeRegister(RADIOLIB_SX126X_REG_SYNC_WORD_0, syncWord, len);
454 0 : RADIOLIB_ASSERT(state);
455 :
456 : // update packet parameters
457 0 : this->syncWordLength = len * 8;
458 :
459 : // maximum preamble detector length is limited by sync word length
460 : // for details, see the note in SX1261 datasheet, Rev 2.1, section 6.2.2.1, page 45
461 0 : uint8_t maxDetLen = RADIOLIB_MIN(this->syncWordLength, this->preambleLengthFSK);
462 0 : this->preambleDetLength = maxDetLen >= 32 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 :
463 : maxDetLen >= 24 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 :
464 : maxDetLen >= 16 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 :
465 : maxDetLen > 0 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 :
466 : RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF;
467 0 : state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType);
468 :
469 0 : return(state);
470 :
471 0 : } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
472 : // with length set to 1 and LoRa modem active, assume it is the LoRa sync word
473 0 : if(len > 1) {
474 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
475 : }
476 0 : return(setSyncWord(syncWord[0]));
477 :
478 0 : } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
479 : // with length set to 4 and LR-FHSS modem active, assume it is the LR-FHSS sync word
480 0 : if(len != sizeof(uint32_t)) {
481 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
482 : }
483 0 : memcpy(this->lrFhssSyncWord, syncWord, sizeof(uint32_t));
484 :
485 : }
486 :
487 0 : return(RADIOLIB_ERR_WRONG_MODEM);
488 : }
489 :
490 0 : int16_t SX126x::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) {
491 : // check active modem
492 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
493 0 : return(RADIOLIB_ERR_WRONG_MODEM);
494 : }
495 :
496 : // check sync word Length
497 0 : if(bitsLen > 0x40) {
498 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
499 : }
500 :
501 0 : uint8_t bytesLen = bitsLen / 8;
502 0 : if ((bitsLen % 8) != 0) {
503 0 : bytesLen++;
504 : }
505 :
506 0 : return(setSyncWord(syncWord, bytesLen));
507 : }
508 :
509 0 : int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool inverted) {
510 : // check active modem
511 0 : uint8_t modem = getPacketType();
512 :
513 0 : if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
514 : // update packet parameters
515 0 : switch(len) {
516 0 : case 0:
517 0 : this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_OFF;
518 0 : break;
519 0 : case 1:
520 0 : if(inverted) {
521 0 : this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE_INV;
522 : } else {
523 0 : this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE;
524 : }
525 0 : break;
526 0 : case 2:
527 0 : if(inverted) {
528 0 : this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV;
529 : } else {
530 0 : this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE;
531 : }
532 0 : break;
533 0 : default:
534 0 : return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
535 : }
536 :
537 0 : int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType);
538 0 : RADIOLIB_ASSERT(state);
539 :
540 : // write initial CRC value
541 0 : uint8_t data[2] = {(uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF)};
542 0 : state = writeRegister(RADIOLIB_SX126X_REG_CRC_INITIAL_MSB, data, 2);
543 0 : RADIOLIB_ASSERT(state);
544 :
545 : // write CRC polynomial value
546 0 : data[0] = (uint8_t)((polynomial >> 8) & 0xFF);
547 0 : data[1] = (uint8_t)(polynomial & 0xFF);
548 0 : state = writeRegister(RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_MSB, data, 2);
549 :
550 0 : return(state);
551 :
552 0 : } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
553 : // LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion
554 :
555 : // update packet parameters
556 0 : if(len) {
557 0 : this->crcTypeLoRa = RADIOLIB_SX126X_LORA_CRC_ON;
558 : } else {
559 0 : this->crcTypeLoRa = RADIOLIB_SX126X_LORA_CRC_OFF;
560 : }
561 :
562 0 : return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled));
563 : }
564 :
565 0 : return(RADIOLIB_ERR_UNKNOWN);
566 : }
567 :
568 0 : int16_t SX126x::setWhitening(bool enabled, uint16_t initial) {
569 : // check active modem
570 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
571 0 : return(RADIOLIB_ERR_WRONG_MODEM);
572 : }
573 :
574 0 : int16_t state = RADIOLIB_ERR_NONE;
575 0 : if(!enabled) {
576 : // disable whitening
577 0 : this->whitening = RADIOLIB_SX126X_GFSK_WHITENING_OFF;
578 :
579 0 : state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType);
580 0 : RADIOLIB_ASSERT(state);
581 :
582 : } else {
583 : // enable whitening
584 0 : this->whitening = RADIOLIB_SX126X_GFSK_WHITENING_ON;
585 :
586 : // write initial whitening value
587 : // 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"
588 : uint8_t data[2];
589 : // first read the actual value and mask 7 MSB which we can not change
590 : // if different value is written in 7 MSB, the Rx won't even work (tested on HW)
591 0 : state = readRegister(RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB, data, 1);
592 0 : RADIOLIB_ASSERT(state);
593 :
594 0 : data[0] = (data[0] & 0xFE) | (uint8_t)((initial >> 8) & 0x01);
595 0 : data[1] = (uint8_t)(initial & 0xFF);
596 0 : state = writeRegister(RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB, data, 2);
597 0 : RADIOLIB_ASSERT(state);
598 :
599 0 : state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType);
600 0 : RADIOLIB_ASSERT(state);
601 : }
602 0 : return(state);
603 : }
604 :
605 0 : int16_t SX126x::fixedPacketLengthMode(uint8_t len) {
606 0 : return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_FIXED, len));
607 : }
608 :
609 0 : int16_t SX126x::variablePacketLengthMode(uint8_t maxLen) {
610 0 : return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_VARIABLE, maxLen));
611 : }
612 0 : int16_t SX126x::implicitHeader(size_t len) {
613 0 : return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_IMPLICIT, len));
614 : }
615 :
616 0 : int16_t SX126x::explicitHeader() {
617 0 : return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_EXPLICIT));
618 : }
619 :
620 0 : int16_t SX126x::setRegulatorLDO() {
621 0 : return(setRegulatorMode(RADIOLIB_SX126X_REGULATOR_LDO));
622 : }
623 :
624 0 : int16_t SX126x::setRegulatorDCDC() {
625 0 : return(setRegulatorMode(RADIOLIB_SX126X_REGULATOR_DC_DC));
626 : }
627 :
628 0 : int16_t SX126x::setEncoding(uint8_t encoding) {
629 0 : return(setWhitening(encoding));
630 : }
631 :
632 0 : void SX126x::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) {
633 0 : this->mod->setRfSwitchPins(rxEn, txEn);
634 0 : }
635 :
636 0 : void SX126x::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) {
637 0 : this->mod->setRfSwitchTable(pins, table);
638 0 : }
639 :
640 0 : int16_t SX126x::forceLDRO(bool enable) {
641 : // check active modem
642 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
643 0 : return(RADIOLIB_ERR_WRONG_MODEM);
644 : }
645 :
646 : // update modulation parameters
647 0 : this->ldroAuto = false;
648 0 : this->ldrOptimize = (uint8_t)enable;
649 0 : return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
650 : }
651 :
652 0 : int16_t SX126x::autoLDRO() {
653 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
654 0 : return(RADIOLIB_ERR_WRONG_MODEM);
655 : }
656 :
657 0 : this->ldroAuto = true;
658 0 : return(RADIOLIB_ERR_NONE);
659 : }
660 :
661 0 : int16_t SX126x::invertIQ(bool enable) {
662 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
663 0 : return(RADIOLIB_ERR_WRONG_MODEM);
664 : }
665 :
666 0 : if(enable) {
667 0 : this->invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_INVERTED;
668 : } else {
669 0 : this->invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_STANDARD;
670 : }
671 :
672 0 : return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled));
673 : }
674 :
675 0 : int16_t SX126x::setTCXO(float voltage, uint32_t delay) {
676 : // check if TCXO is enabled at all
677 0 : if(this->XTAL) {
678 0 : return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE);
679 : }
680 :
681 : // set mode to standby
682 0 : standby();
683 :
684 : // check RADIOLIB_SX126X_XOSC_START_ERR flag and clear it
685 0 : if(getDeviceErrors() & RADIOLIB_SX126X_XOSC_START_ERR) {
686 0 : clearDeviceErrors();
687 : }
688 :
689 : // check 0 V disable
690 0 : if(fabsf(voltage - 0.0f) <= 0.001f) {
691 0 : return(reset(true));
692 : }
693 :
694 : // check alowed voltage values
695 : uint8_t data[4];
696 0 : if(fabsf(voltage - 1.6f) <= 0.001f) {
697 0 : data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_6;
698 0 : } else if(fabsf(voltage - 1.7f) <= 0.001f) {
699 0 : data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_7;
700 0 : } else if(fabsf(voltage - 1.8f) <= 0.001f) {
701 0 : data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_8;
702 0 : } else if(fabsf(voltage - 2.2f) <= 0.001f) {
703 0 : data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_2;
704 0 : } else if(fabsf(voltage - 2.4f) <= 0.001f) {
705 0 : data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_4;
706 0 : } else if(fabsf(voltage - 2.7f) <= 0.001f) {
707 0 : data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_7;
708 0 : } else if(fabsf(voltage - 3.0f) <= 0.001f) {
709 0 : data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_3_0;
710 0 : } else if(fabsf(voltage - 3.3f) <= 0.001f) {
711 0 : data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_3_3;
712 : } else {
713 0 : return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE);
714 : }
715 :
716 : // calculate delay
717 0 : uint32_t delayValue = (float)delay / 15.625f;
718 0 : data[1] = (uint8_t)((delayValue >> 16) & 0xFF);
719 0 : data[2] = (uint8_t)((delayValue >> 8) & 0xFF);
720 0 : data[3] = (uint8_t)(delayValue & 0xFF);
721 :
722 0 : this->tcxoDelay = delay;
723 :
724 : // enable TCXO control on DIO3
725 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL, data, 4));
726 : }
727 :
728 0 : int16_t SX126x::setDio2AsRfSwitch(bool enable) {
729 0 : uint8_t data = enable ? RADIOLIB_SX126X_DIO2_AS_RF_SWITCH : RADIOLIB_SX126X_DIO2_AS_IRQ;
730 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1));
731 : }
732 0 : int16_t SX126x::setPaRampTime(uint8_t rampTime) {
733 0 : return(this->setTxParams(this->pwr, rampTime));
734 : }
735 :
736 0 : int16_t SX126x::setPacketMode(uint8_t mode, uint8_t len) {
737 : // check active modem
738 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
739 0 : return(RADIOLIB_ERR_WRONG_MODEM);
740 : }
741 :
742 : // set requested packet mode
743 0 : int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, mode, len);
744 0 : RADIOLIB_ASSERT(state);
745 :
746 : // update cached value
747 0 : this->packetType = mode;
748 0 : return(state);
749 : }
750 :
751 0 : int16_t SX126x::setHeaderType(uint8_t hdrType, size_t len) {
752 : // check active modem
753 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
754 0 : return(RADIOLIB_ERR_WRONG_MODEM);
755 : }
756 :
757 : // set requested packet mode
758 0 : int16_t state = setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, len, hdrType, this->invertIQEnabled);
759 0 : RADIOLIB_ASSERT(state);
760 :
761 : // update cached value
762 0 : this->headerType = hdrType;
763 0 : this->implicitLen = len;
764 :
765 0 : return(state);
766 : }
767 :
768 0 : int16_t SX126x::setFrequencyRaw(float freq) {
769 : // calculate raw value
770 0 : this->freqMHz = freq;
771 0 : uint32_t frf = (this->freqMHz * (uint32_t(1) << RADIOLIB_SX126X_DIV_EXPONENT)) / RADIOLIB_SX126X_CRYSTAL_FREQ;
772 0 : return(setRfFrequency(frf));
773 : }
774 :
775 0 : int16_t SX126x::config(uint8_t modem) {
776 : // reset buffer base address
777 0 : int16_t state = setBufferBaseAddress();
778 0 : RADIOLIB_ASSERT(state);
779 :
780 : // set modem
781 : uint8_t data[7];
782 0 : data[0] = modem;
783 0 : state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_TYPE, data, 1);
784 0 : RADIOLIB_ASSERT(state);
785 :
786 : // set Rx/Tx fallback mode to STDBY_RC
787 0 : data[0] = this->standbyXOSC ? RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC : RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC;
788 0 : state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1);
789 0 : RADIOLIB_ASSERT(state);
790 :
791 : // set some CAD parameters - will be overwritten when calling CAD anyway
792 0 : data[0] = RADIOLIB_SX126X_CAD_ON_8_SYMB;
793 0 : data[1] = this->spreadingFactor + 13;
794 0 : data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN;
795 0 : data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY;
796 0 : data[4] = 0x00;
797 0 : data[5] = 0x00;
798 0 : data[6] = 0x00;
799 0 : state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7);
800 0 : RADIOLIB_ASSERT(state);
801 :
802 : // clear IRQ
803 0 : state = clearIrqStatus();
804 0 : state |= setDioIrqParams(RADIOLIB_SX126X_IRQ_NONE, RADIOLIB_SX126X_IRQ_NONE);
805 0 : RADIOLIB_ASSERT(state);
806 :
807 : // calibrate all blocks
808 0 : data[0] = RADIOLIB_SX126X_CALIBRATE_ALL;
809 0 : state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE, data, 1, true, false);
810 0 : RADIOLIB_ASSERT(state);
811 :
812 : // wait for calibration completion
813 0 : this->mod->hal->delay(5);
814 0 : while(this->mod->hal->digitalRead(this->mod->getGpio())) {
815 0 : this->mod->hal->yield();
816 : }
817 :
818 : // check calibration result
819 0 : state = this->mod->SPIcheckStream();
820 :
821 : // if something failed, show the device errors
822 : #if RADIOLIB_DEBUG_BASIC
823 : if(state != RADIOLIB_ERR_NONE) {
824 : // unless mode is forced to standby, device errors will be 0
825 : standby();
826 : uint16_t errors = getDeviceErrors();
827 : RADIOLIB_DEBUG_BASIC_PRINTLN("Calibration failed, device errors: 0x%X", errors);
828 : }
829 : #endif
830 :
831 0 : return(state);
832 : }
833 :
834 : #endif
|