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