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 ? RADIOLIB_SX126X_LR_FHSS_GRID_STEP_NON_FCC : RADIOLIB_SX126X_LR_FHSS_GRID_STEP_FCC;
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::setRxBandwidth(float rxBw) {
335 : // check active modem
336 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
337 0 : return(RADIOLIB_ERR_WRONG_MODEM);
338 : }
339 :
340 : // check modulation parameters
341 : /*if(2 * this->frequencyDev + this->bitRate > rxBw * 1000.0) {
342 : return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS);
343 : }*/
344 0 : this->rxBandwidthKhz = rxBw;
345 :
346 : // check allowed receiver bandwidth values
347 0 : if(fabsf(rxBw - 4.8f) <= 0.001f) {
348 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_4_8;
349 0 : } else if(fabsf(rxBw - 5.8f) <= 0.001f) {
350 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_5_8;
351 0 : } else if(fabsf(rxBw - 7.3f) <= 0.001f) {
352 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_7_3;
353 0 : } else if(fabsf(rxBw - 9.7f) <= 0.001f) {
354 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_9_7;
355 0 : } else if(fabsf(rxBw - 11.7f) <= 0.001f) {
356 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_11_7;
357 0 : } else if(fabsf(rxBw - 14.6f) <= 0.001f) {
358 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_14_6;
359 0 : } else if(fabsf(rxBw - 19.5f) <= 0.001f) {
360 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_19_5;
361 0 : } else if(fabsf(rxBw - 23.4f) <= 0.001f) {
362 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_23_4;
363 0 : } else if(fabsf(rxBw - 29.3f) <= 0.001f) {
364 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_29_3;
365 0 : } else if(fabsf(rxBw - 39.0f) <= 0.001f) {
366 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_39_0;
367 0 : } else if(fabsf(rxBw - 46.9f) <= 0.001f) {
368 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_46_9;
369 0 : } else if(fabsf(rxBw - 58.6f) <= 0.001f) {
370 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_58_6;
371 0 : } else if(fabsf(rxBw - 78.2f) <= 0.001f) {
372 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_78_2;
373 0 : } else if(fabsf(rxBw - 93.8f) <= 0.001f) {
374 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_93_8;
375 0 : } else if(fabsf(rxBw - 117.3f) <= 0.001f) {
376 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_117_3;
377 0 : } else if(fabsf(rxBw - 156.2f) <= 0.001f) {
378 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_156_2;
379 0 : } else if(fabsf(rxBw - 187.2f) <= 0.001f) {
380 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_187_2;
381 0 : } else if(fabsf(rxBw - 234.3f) <= 0.001f) {
382 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_234_3;
383 0 : } else if(fabsf(rxBw - 312.0f) <= 0.001f) {
384 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_312_0;
385 0 : } else if(fabsf(rxBw - 373.6f) <= 0.001f) {
386 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_373_6;
387 0 : } else if(fabsf(rxBw - 467.0f) <= 0.001f) {
388 0 : this->rxBandwidth = RADIOLIB_SX126X_GFSK_RX_BW_467_0;
389 : } else {
390 0 : return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH);
391 : }
392 :
393 : // update modulation parameters
394 0 : return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
395 : }
396 :
397 0 : int16_t SX126x::setRxBoostedGainMode(bool rxbgm, bool persist) {
398 0 : this->rxBoostedGainMode = rxbgm;
399 :
400 : // update RX gain setting register
401 0 : uint8_t rxGain = rxbgm ? RADIOLIB_SX126X_RX_GAIN_BOOSTED : RADIOLIB_SX126X_RX_GAIN_POWER_SAVING;
402 0 : int16_t state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN, &rxGain, 1);
403 0 : RADIOLIB_ASSERT(state);
404 :
405 : // add Rx Gain register to retention memory if requested
406 0 : if(persist) {
407 : // values and registers below are specified in SX126x datasheet v2.1 section 9.6, just below table 9-3
408 0 : const uint8_t data[] = { 0x01, (uint8_t)((RADIOLIB_SX126X_REG_RX_GAIN >> 8) & 0xFF), (uint8_t)(RADIOLIB_SX126X_REG_RX_GAIN & 0xFF) };
409 0 : state = writeRegister(RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_0, data, 3);
410 : }
411 :
412 0 : return(state);
413 : }
414 :
415 3 : int16_t SX126x::setDataShaping(uint8_t sh) {
416 : // check active modem
417 3 : uint8_t modem = getPacketType();
418 3 : if((modem != RADIOLIB_SX126X_PACKET_TYPE_GFSK) && (modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS)) {
419 3 : return(RADIOLIB_ERR_WRONG_MODEM);
420 : }
421 :
422 : // set data shaping
423 0 : switch(sh) {
424 0 : case RADIOLIB_SHAPING_NONE:
425 0 : this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_NONE;
426 0 : break;
427 0 : case RADIOLIB_SHAPING_0_3:
428 0 : this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_3;
429 0 : break;
430 0 : case RADIOLIB_SHAPING_0_5:
431 0 : this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_5;
432 0 : break;
433 0 : case RADIOLIB_SHAPING_0_7:
434 0 : this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_0_7;
435 0 : break;
436 0 : case RADIOLIB_SHAPING_1_0:
437 0 : this->pulseShape = RADIOLIB_SX126X_GFSK_FILTER_GAUSS_1;
438 0 : break;
439 0 : default:
440 0 : return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
441 : }
442 :
443 : // update modulation parameters
444 0 : return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
445 : }
446 :
447 3 : int16_t SX126x::setSyncWord(uint8_t* syncWord, size_t len) {
448 : // check active modem
449 3 : uint8_t modem = getPacketType();
450 3 : if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
451 : // check sync word Length
452 0 : if(len > 8) {
453 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
454 : }
455 :
456 : // write sync word
457 0 : int16_t state = writeRegister(RADIOLIB_SX126X_REG_SYNC_WORD_0, syncWord, len);
458 0 : RADIOLIB_ASSERT(state);
459 :
460 : // update packet parameters
461 0 : this->syncWordLength = len * 8;
462 :
463 : // maximum preamble detector length is limited by sync word length
464 : // for details, see the note in SX1261 datasheet, Rev 2.1, section 6.2.2.1, page 45
465 0 : uint8_t maxDetLen = RADIOLIB_MIN(this->syncWordLength, this->preambleLengthFSK);
466 0 : this->preambleDetLength = maxDetLen >= 32 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_32 :
467 : maxDetLen >= 24 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_24 :
468 : maxDetLen >= 16 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_16 :
469 : maxDetLen > 0 ? RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_8 :
470 : RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF;
471 0 : state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening,
472 0 : this->packetType, (this->packetType == RADIOLIB_SX126X_GFSK_PACKET_FIXED) ? this->implicitLen : RADIOLIB_SX126X_MAX_PACKET_LENGTH);
473 0 : return(state);
474 :
475 3 : } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
476 : // with length set to 1 and LoRa modem active, assume it is the LoRa sync word
477 0 : if(len > 1) {
478 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
479 : }
480 0 : return(setSyncWord(syncWord[0]));
481 :
482 3 : } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
483 : // with length set to 4 and LR-FHSS modem active, assume it is the LR-FHSS sync word
484 0 : if(len != sizeof(uint32_t)) {
485 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
486 : }
487 0 : memcpy(this->lrFhssSyncWord, syncWord, sizeof(uint32_t));
488 :
489 : }
490 :
491 3 : return(RADIOLIB_ERR_WRONG_MODEM);
492 : }
493 :
494 0 : int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool inverted) {
495 : // check active modem
496 0 : uint8_t modem = getPacketType();
497 :
498 0 : if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
499 : // update packet parameters
500 0 : switch(len) {
501 0 : case 0:
502 0 : this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_OFF;
503 0 : break;
504 0 : case 1:
505 0 : if(inverted) {
506 0 : this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE_INV;
507 : } else {
508 0 : this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_1_BYTE;
509 : }
510 0 : break;
511 0 : case 2:
512 0 : if(inverted) {
513 0 : this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE_INV;
514 : } else {
515 0 : this->crcTypeFSK = RADIOLIB_SX126X_GFSK_CRC_2_BYTE;
516 : }
517 0 : break;
518 0 : default:
519 0 : return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
520 : }
521 :
522 0 : int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening,
523 0 : this->packetType, (this->packetType == RADIOLIB_SX126X_GFSK_PACKET_FIXED) ? this->implicitLen : RADIOLIB_SX126X_MAX_PACKET_LENGTH);
524 0 : RADIOLIB_ASSERT(state);
525 :
526 : // write initial CRC value
527 0 : uint8_t data[2] = {(uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF)};
528 0 : state = writeRegister(RADIOLIB_SX126X_REG_CRC_INITIAL_MSB, data, 2);
529 0 : RADIOLIB_ASSERT(state);
530 :
531 : // write CRC polynomial value
532 0 : data[0] = (uint8_t)((polynomial >> 8) & 0xFF);
533 0 : data[1] = (uint8_t)(polynomial & 0xFF);
534 0 : state = writeRegister(RADIOLIB_SX126X_REG_CRC_POLYNOMIAL_MSB, data, 2);
535 :
536 0 : return(state);
537 :
538 0 : } else if(modem == RADIOLIB_SX126X_PACKET_TYPE_LORA) {
539 : // LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion
540 :
541 : // update packet parameters
542 0 : if(len) {
543 0 : this->crcTypeLoRa = RADIOLIB_SX126X_LORA_CRC_ON;
544 : } else {
545 0 : this->crcTypeLoRa = RADIOLIB_SX126X_LORA_CRC_OFF;
546 : }
547 :
548 0 : return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled));
549 : }
550 :
551 0 : return(RADIOLIB_ERR_UNKNOWN);
552 : }
553 :
554 3 : int16_t SX126x::setWhitening(bool enabled, uint16_t initial) {
555 : // check active modem
556 3 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
557 3 : return(RADIOLIB_ERR_WRONG_MODEM);
558 : }
559 :
560 0 : int16_t state = RADIOLIB_ERR_NONE;
561 0 : if(!enabled) {
562 : // disable whitening
563 0 : this->whitening = RADIOLIB_SX126X_GFSK_WHITENING_OFF;
564 :
565 0 : state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening,
566 0 : this->packetType, (this->packetType == RADIOLIB_SX126X_GFSK_PACKET_FIXED) ? this->implicitLen : RADIOLIB_SX126X_MAX_PACKET_LENGTH);
567 0 : RADIOLIB_ASSERT(state);
568 :
569 : } else {
570 : // enable whitening
571 0 : this->whitening = RADIOLIB_SX126X_GFSK_WHITENING_ON;
572 :
573 : // write initial whitening value
574 : // 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"
575 : uint8_t data[2];
576 : // first read the actual value and mask 7 MSB which we can not change
577 : // if different value is written in 7 MSB, the Rx won't even work (tested on HW)
578 0 : state = readRegister(RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB, data, 1);
579 0 : RADIOLIB_ASSERT(state);
580 :
581 0 : data[0] = (data[0] & 0xFE) | (uint8_t)((initial >> 8) & 0x01);
582 0 : data[1] = (uint8_t)(initial & 0xFF);
583 0 : state = writeRegister(RADIOLIB_SX126X_REG_WHITENING_INITIAL_MSB, data, 2);
584 0 : RADIOLIB_ASSERT(state);
585 :
586 0 : state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening,
587 0 : this->packetType, (this->packetType == RADIOLIB_SX126X_GFSK_PACKET_FIXED) ? this->implicitLen : RADIOLIB_SX126X_MAX_PACKET_LENGTH);
588 0 : RADIOLIB_ASSERT(state);
589 : }
590 0 : return(state);
591 : }
592 :
593 0 : int16_t SX126x::fixedPacketLengthMode(uint8_t len) {
594 0 : return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_FIXED, len));
595 : }
596 :
597 0 : int16_t SX126x::variablePacketLengthMode(uint8_t maxLen) {
598 0 : return(setPacketMode(RADIOLIB_SX126X_GFSK_PACKET_VARIABLE, maxLen));
599 : }
600 0 : int16_t SX126x::implicitHeader(size_t len) {
601 0 : return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_IMPLICIT, len));
602 : }
603 :
604 0 : int16_t SX126x::explicitHeader() {
605 0 : return(setHeaderType(RADIOLIB_SX126X_LORA_HEADER_EXPLICIT));
606 : }
607 :
608 0 : int16_t SX126x::setRegulatorLDO() {
609 0 : return(setRegulatorMode(RADIOLIB_SX126X_REGULATOR_LDO));
610 : }
611 :
612 0 : int16_t SX126x::setRegulatorDCDC() {
613 0 : return(setRegulatorMode(RADIOLIB_SX126X_REGULATOR_DC_DC));
614 : }
615 :
616 3 : int16_t SX126x::setEncoding(uint8_t encoding) {
617 3 : return(setWhitening(encoding));
618 : }
619 :
620 0 : void SX126x::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) {
621 0 : this->mod->setRfSwitchPins(rxEn, txEn);
622 0 : }
623 :
624 0 : void SX126x::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) {
625 0 : this->mod->setRfSwitchTable(pins, table);
626 0 : }
627 :
628 0 : int16_t SX126x::forceLDRO(bool enable) {
629 : // check active modem
630 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
631 0 : return(RADIOLIB_ERR_WRONG_MODEM);
632 : }
633 :
634 : // update modulation parameters
635 0 : this->ldroAuto = false;
636 0 : this->ldrOptimize = (uint8_t)enable;
637 0 : return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRate, this->ldrOptimize));
638 : }
639 :
640 0 : int16_t SX126x::autoLDRO() {
641 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
642 0 : return(RADIOLIB_ERR_WRONG_MODEM);
643 : }
644 :
645 0 : this->ldroAuto = true;
646 0 : return(RADIOLIB_ERR_NONE);
647 : }
648 :
649 3 : int16_t SX126x::invertIQ(bool enable) {
650 3 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
651 3 : return(RADIOLIB_ERR_WRONG_MODEM);
652 : }
653 :
654 0 : if(enable) {
655 0 : this->invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_INVERTED;
656 : } else {
657 0 : this->invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_STANDARD;
658 : }
659 :
660 0 : return(setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, this->invertIQEnabled));
661 : }
662 :
663 0 : int16_t SX126x::setTCXO(float voltage, uint32_t delay) {
664 : // check if TCXO is enabled at all
665 0 : if(this->XTAL) {
666 0 : return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE);
667 : }
668 :
669 : // set mode to standby
670 0 : standby();
671 :
672 : // check RADIOLIB_SX126X_XOSC_START_ERR flag and clear it
673 0 : if(getDeviceErrors() & RADIOLIB_SX126X_XOSC_START_ERR) {
674 0 : clearDeviceErrors();
675 : }
676 :
677 : // check 0 V disable
678 0 : if(fabsf(voltage - 0.0f) <= 0.001f) {
679 0 : return(reset(true));
680 : }
681 :
682 : // check alowed voltage values
683 : uint8_t data[4];
684 0 : if(fabsf(voltage - 1.6f) <= 0.001f) {
685 0 : data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_6;
686 0 : } else if(fabsf(voltage - 1.7f) <= 0.001f) {
687 0 : data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_7;
688 0 : } else if(fabsf(voltage - 1.8f) <= 0.001f) {
689 0 : data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_1_8;
690 0 : } else if(fabsf(voltage - 2.2f) <= 0.001f) {
691 0 : data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_2;
692 0 : } else if(fabsf(voltage - 2.4f) <= 0.001f) {
693 0 : data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_4;
694 0 : } else if(fabsf(voltage - 2.7f) <= 0.001f) {
695 0 : data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_2_7;
696 0 : } else if(fabsf(voltage - 3.0f) <= 0.001f) {
697 0 : data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_3_0;
698 0 : } else if(fabsf(voltage - 3.3f) <= 0.001f) {
699 0 : data[0] = RADIOLIB_SX126X_DIO3_OUTPUT_3_3;
700 : } else {
701 0 : return(RADIOLIB_ERR_INVALID_TCXO_VOLTAGE);
702 : }
703 :
704 : // calculate delay
705 0 : uint32_t delayValue = (float)delay / 15.625f;
706 0 : data[1] = (uint8_t)((delayValue >> 16) & 0xFF);
707 0 : data[2] = (uint8_t)((delayValue >> 8) & 0xFF);
708 0 : data[3] = (uint8_t)(delayValue & 0xFF);
709 :
710 0 : this->tcxoDelay = delay;
711 :
712 : // enable TCXO control on DIO3
713 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO3_AS_TCXO_CTRL, data, 4));
714 : }
715 :
716 0 : int16_t SX126x::setDio2AsRfSwitch(bool enable) {
717 0 : this->dio2RfSwitch = enable;
718 0 : uint8_t data = enable ? RADIOLIB_SX126X_DIO2_AS_RF_SWITCH : RADIOLIB_SX126X_DIO2_AS_IRQ;
719 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, &data, 1));
720 : }
721 :
722 0 : int16_t SX126x::setPaRampTime(uint8_t rampTime) {
723 0 : return(this->setTxParams(this->pwr, rampTime));
724 : }
725 :
726 2 : int16_t SX126x::setOutputPower(int8_t power, uint8_t paDutyCycle, uint8_t hpMax, uint8_t deviceSel) {
727 : // get current OCP configuration
728 2 : uint8_t ocp = 0;
729 2 : int16_t state = readRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
730 2 : RADIOLIB_ASSERT(state);
731 :
732 : // set PA config
733 0 : state = SX126x::setPaConfig(paDutyCycle, deviceSel, hpMax);
734 0 : RADIOLIB_ASSERT(state);
735 :
736 : // set output power with default 200us ramp
737 0 : state = SX126x::setTxParams(power, RADIOLIB_SX126X_PA_RAMP_200U);
738 0 : RADIOLIB_ASSERT(state);
739 :
740 : // restore OCP configuration
741 0 : return(writeRegister(RADIOLIB_SX126X_REG_OCP_CONFIGURATION, &ocp, 1));
742 : }
743 :
744 0 : int16_t SX126x::setPacketMode(uint8_t mode, uint8_t len) {
745 : // check active modem
746 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
747 0 : return(RADIOLIB_ERR_WRONG_MODEM);
748 : }
749 :
750 : // set requested packet mode
751 0 : int16_t state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, mode, len);
752 0 : RADIOLIB_ASSERT(state);
753 :
754 : // update cached value
755 0 : this->packetType = mode;
756 0 : this->implicitLen = len;
757 0 : return(state);
758 : }
759 :
760 0 : int16_t SX126x::setHeaderType(uint8_t hdrType, size_t len) {
761 : // check active modem
762 0 : if(getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
763 0 : return(RADIOLIB_ERR_WRONG_MODEM);
764 : }
765 :
766 : // set requested packet mode
767 0 : int16_t state = setPacketParams(this->preambleLengthLoRa, this->crcTypeLoRa, len, hdrType, this->invertIQEnabled);
768 0 : RADIOLIB_ASSERT(state);
769 :
770 : // update cached value
771 0 : this->headerType = hdrType;
772 0 : this->implicitLen = len;
773 :
774 0 : return(state);
775 : }
776 :
777 0 : int16_t SX126x::setFrequencyRaw(float freq) {
778 : // calculate raw value
779 0 : this->freqMHz = freq;
780 0 : uint32_t frf = (this->freqMHz * (uint32_t(1) << RADIOLIB_SX126X_DIV_EXPONENT)) / RADIOLIB_SX126X_CRYSTAL_FREQ;
781 0 : return(setRfFrequency(frf));
782 : }
783 :
784 0 : int16_t SX126x::config(uint8_t modem) {
785 : // reset buffer base address
786 0 : int16_t state = setBufferBaseAddress();
787 0 : RADIOLIB_ASSERT(state);
788 :
789 : // set modem
790 : uint8_t data[7];
791 0 : data[0] = modem;
792 0 : state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_TYPE, data, 1);
793 0 : RADIOLIB_ASSERT(state);
794 :
795 : // set Rx/Tx fallback mode to STDBY_RC
796 0 : data[0] = this->standbyXOSC ? RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_XOSC : RADIOLIB_SX126X_RX_TX_FALLBACK_MODE_STDBY_RC;
797 0 : state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1);
798 0 : RADIOLIB_ASSERT(state);
799 :
800 : // set some CAD parameters - will be overwritten when calling CAD anyway
801 0 : data[0] = RADIOLIB_SX126X_CAD_ON_8_SYMB;
802 0 : data[1] = this->spreadingFactor + 13;
803 0 : data[2] = RADIOLIB_SX126X_CAD_PARAM_DET_MIN;
804 0 : data[3] = RADIOLIB_SX126X_CAD_GOTO_STDBY;
805 0 : data[4] = 0x00;
806 0 : data[5] = 0x00;
807 0 : data[6] = 0x00;
808 0 : state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_CAD_PARAMS, data, 7);
809 0 : RADIOLIB_ASSERT(state);
810 :
811 : // clear IRQ
812 0 : state = clearIrqStatus();
813 0 : state |= setDioIrqParams(RADIOLIB_SX126X_IRQ_NONE, RADIOLIB_SX126X_IRQ_NONE);
814 0 : RADIOLIB_ASSERT(state);
815 :
816 : // calibrate all blocks
817 0 : data[0] = RADIOLIB_SX126X_CALIBRATE_ALL;
818 0 : state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_CALIBRATE, data, 1, true, false);
819 0 : RADIOLIB_ASSERT(state);
820 :
821 : // wait for calibration completion
822 0 : this->mod->hal->delay(5);
823 0 : while(this->mod->hal->digitalRead(this->mod->getGpio())) {
824 0 : this->mod->hal->yield();
825 : }
826 :
827 : // check calibration result
828 0 : return(this->mod->SPIcheckStream());
829 : }
830 :
831 : #endif
|