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