Line data Source code
1 : #include "SX1278.h"
2 : #include <math.h>
3 : #if !RADIOLIB_EXCLUDE_SX127X
4 :
5 3 : SX1278::SX1278(Module* mod) : SX127x(mod) {
6 :
7 3 : }
8 :
9 0 : int16_t SX1278::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t power, uint16_t preambleLength, uint8_t gain) {
10 : // execute common part
11 0 : const uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X };
12 0 : int16_t state = SX127x::begin(versions, 3, syncWord, preambleLength);
13 0 : RADIOLIB_ASSERT(state);
14 :
15 : // configure publicly accessible settings
16 0 : state = setBandwidth(bw);
17 0 : RADIOLIB_ASSERT(state);
18 :
19 0 : state = setFrequency(freq);
20 0 : RADIOLIB_ASSERT(state);
21 :
22 0 : state = setSpreadingFactor(sf);
23 0 : RADIOLIB_ASSERT(state);
24 :
25 0 : state = setCodingRate(cr);
26 0 : RADIOLIB_ASSERT(state);
27 :
28 0 : state = setOutputPower(power);
29 0 : RADIOLIB_ASSERT(state);
30 :
31 0 : state = setGain(gain);
32 0 : RADIOLIB_ASSERT(state);
33 :
34 : // set publicly accessible settings that are not a part of begin method
35 0 : state = setCRC(true);
36 0 : RADIOLIB_ASSERT(state);
37 :
38 0 : return(state);
39 : }
40 :
41 0 : int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint16_t preambleLength, bool enableOOK) {
42 : // execute common part
43 0 : const uint8_t versions[] = { RADIOLIB_SX1278_CHIP_VERSION, RADIOLIB_SX1278_CHIP_VERSION_ALT, RADIOLIB_SX1278_CHIP_VERSION_RFM9X };
44 0 : int16_t state = SX127x::beginFSK(versions, 3, freqDev, rxBw, preambleLength, enableOOK);
45 0 : RADIOLIB_ASSERT(state);
46 :
47 : // configure settings not accessible by API
48 0 : state = configFSK();
49 0 : RADIOLIB_ASSERT(state);
50 :
51 : // configure publicly accessible settings
52 0 : state = setFrequency(freq);
53 0 : RADIOLIB_ASSERT(state);
54 :
55 0 : state = setBitRate(br);
56 0 : RADIOLIB_ASSERT(state);
57 :
58 0 : state = setOutputPower(power);
59 0 : RADIOLIB_ASSERT(state);
60 :
61 0 : if(enableOOK) {
62 0 : state = setDataShapingOOK(RADIOLIB_SHAPING_NONE);
63 0 : RADIOLIB_ASSERT(state);
64 : } else {
65 0 : state = setDataShaping(RADIOLIB_SHAPING_NONE);
66 0 : RADIOLIB_ASSERT(state);
67 : }
68 :
69 : // set publicly accessible settings that are not a part of begin method
70 0 : state = setCRC(true);
71 0 : RADIOLIB_ASSERT(state);
72 :
73 0 : return(state);
74 : }
75 :
76 0 : void SX1278::reset() {
77 0 : Module* mod = this->getMod();
78 0 : mod->hal->pinMode(mod->getRst(), mod->hal->GpioModeOutput);
79 0 : mod->hal->digitalWrite(mod->getRst(), mod->hal->GpioLevelLow);
80 0 : mod->hal->delay(1);
81 0 : mod->hal->digitalWrite(mod->getRst(), mod->hal->GpioLevelHigh);
82 0 : mod->hal->delay(5);
83 0 : }
84 :
85 1 : int16_t SX1278::setFrequency(float freq) {
86 : // NOTE: The datasheet specifies Band 2 as 410-525 MHz, but the hardware has been
87 : // verified to work down to ~395 MHz. The lower bound is set here to 395 MHz to
88 : // accommodate real-world use cases (e.g. TinyGS satellites, radiosondes) while
89 : // adding a small margin below the 400 MHz practical limit.
90 1 : if(!(((freq >= 137.0f) && (freq <= 175.0f)) ||
91 1 : ((freq >= 395.0f) && (freq <= 525.0f)))) {
92 1 : return(RADIOLIB_ERR_INVALID_FREQUENCY);
93 : }
94 :
95 : // set frequency and if successful, save the new setting
96 0 : int16_t state = SX127x::setFrequencyRaw(freq);
97 0 : if(state == RADIOLIB_ERR_NONE) {
98 0 : SX127x::frequency = freq;
99 : }
100 0 : return(state);
101 : }
102 :
103 0 : int16_t SX1278::setBandwidth(float bw) {
104 : // check active modem
105 0 : if(getActiveModem() != RADIOLIB_SX127X_LORA) {
106 0 : return(RADIOLIB_ERR_WRONG_MODEM);
107 : }
108 :
109 : uint8_t newBandwidth;
110 :
111 : // check allowed bandwidth values
112 0 : if(fabsf(bw - 7.8f) <= 0.001f) {
113 0 : newBandwidth = RADIOLIB_SX1278_BW_7_80_KHZ;
114 0 : } else if(fabsf(bw - 10.4f) <= 0.001f) {
115 0 : newBandwidth = RADIOLIB_SX1278_BW_10_40_KHZ;
116 0 : } else if(fabsf(bw - 15.6f) <= 0.001f) {
117 0 : newBandwidth = RADIOLIB_SX1278_BW_15_60_KHZ;
118 0 : } else if(fabsf(bw - 20.8f) <= 0.001f) {
119 0 : newBandwidth = RADIOLIB_SX1278_BW_20_80_KHZ;
120 0 : } else if(fabsf(bw - 31.25f) <= 0.001f) {
121 0 : newBandwidth = RADIOLIB_SX1278_BW_31_25_KHZ;
122 0 : } else if(fabsf(bw - 41.7f) <= 0.001f) {
123 0 : newBandwidth = RADIOLIB_SX1278_BW_41_70_KHZ;
124 0 : } else if(fabsf(bw - 62.5f) <= 0.001f) {
125 0 : newBandwidth = RADIOLIB_SX1278_BW_62_50_KHZ;
126 0 : } else if(fabsf(bw - 125.0f) <= 0.001f) {
127 0 : newBandwidth = RADIOLIB_SX1278_BW_125_00_KHZ;
128 0 : } else if(fabsf(bw - 250.0f) <= 0.001f) {
129 0 : newBandwidth = RADIOLIB_SX1278_BW_250_00_KHZ;
130 0 : } else if(fabsf(bw - 500.0f) <= 0.001f) {
131 0 : newBandwidth = RADIOLIB_SX1278_BW_500_00_KHZ;
132 : } else {
133 0 : return(RADIOLIB_ERR_INVALID_BANDWIDTH);
134 : }
135 :
136 : // set bandwidth and if successful, save the new setting
137 0 : int16_t state = SX1278::setBandwidthRaw(newBandwidth);
138 0 : if(state == RADIOLIB_ERR_NONE) {
139 0 : SX127x::bandwidth = bw;
140 :
141 : // calculate symbol length and set low data rate optimization, if auto-configuration is enabled
142 0 : if(this->ldroAuto) {
143 0 : float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth;
144 0 : Module* mod = this->getMod();
145 0 : if(symbolLength >= 16.0f) {
146 0 : this->ldroEnabled = true;
147 0 : state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3);
148 : } else {
149 0 : this->ldroEnabled = false;
150 0 : state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3);
151 : }
152 : }
153 : }
154 0 : return(state);
155 : }
156 :
157 2 : int16_t SX1278::setSpreadingFactor(uint8_t sf) {
158 : // check active modem
159 2 : if(getActiveModem() != RADIOLIB_SX127X_LORA) {
160 0 : return(RADIOLIB_ERR_WRONG_MODEM);
161 : }
162 :
163 : uint8_t newSpreadingFactor;
164 :
165 : // check allowed spreading factor values
166 2 : switch(sf) {
167 0 : case 6:
168 0 : newSpreadingFactor = RADIOLIB_SX127X_SF_6;
169 0 : break;
170 0 : case 7:
171 0 : newSpreadingFactor = RADIOLIB_SX127X_SF_7;
172 0 : break;
173 0 : case 8:
174 0 : newSpreadingFactor = RADIOLIB_SX127X_SF_8;
175 0 : break;
176 0 : case 9:
177 0 : newSpreadingFactor = RADIOLIB_SX127X_SF_9;
178 0 : break;
179 0 : case 10:
180 0 : newSpreadingFactor = RADIOLIB_SX127X_SF_10;
181 0 : break;
182 0 : case 11:
183 0 : newSpreadingFactor = RADIOLIB_SX127X_SF_11;
184 0 : break;
185 0 : case 12:
186 0 : newSpreadingFactor = RADIOLIB_SX127X_SF_12;
187 0 : break;
188 2 : default:
189 2 : return(RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
190 : }
191 :
192 : // set spreading factor and if successful, save the new setting
193 0 : int16_t state = SX1278::setSpreadingFactorRaw(newSpreadingFactor);
194 0 : if(state == RADIOLIB_ERR_NONE) {
195 0 : SX127x::spreadingFactor = sf;
196 :
197 : // calculate symbol length and set low data rate optimization, if auto-configuration is enabled
198 0 : if(this->ldroAuto) {
199 0 : float symbolLength = (float)(uint32_t(1) << SX127x::spreadingFactor) / (float)SX127x::bandwidth;
200 0 : Module* mod = this->getMod();
201 0 : if(symbolLength >= 16.0f) {
202 0 : state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3);
203 : } else {
204 0 : state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3);
205 : }
206 : }
207 : }
208 0 : return(state);
209 : }
210 :
211 0 : int16_t SX1278::setCodingRate(uint8_t cr) {
212 : // check active modem
213 0 : if(getActiveModem() != RADIOLIB_SX127X_LORA) {
214 0 : return(RADIOLIB_ERR_WRONG_MODEM);
215 : }
216 :
217 : uint8_t newCodingRate;
218 :
219 : // check allowed coding rate values
220 0 : switch(cr) {
221 0 : case 4:
222 0 : newCodingRate = RADIOLIB_SX1278_CR_4_4;
223 0 : break;
224 0 : case 5:
225 0 : newCodingRate = RADIOLIB_SX1278_CR_4_5;
226 0 : break;
227 0 : case 6:
228 0 : newCodingRate = RADIOLIB_SX1278_CR_4_6;
229 0 : break;
230 0 : case 7:
231 0 : newCodingRate = RADIOLIB_SX1278_CR_4_7;
232 0 : break;
233 0 : case 8:
234 0 : newCodingRate = RADIOLIB_SX1278_CR_4_8;
235 0 : break;
236 0 : default:
237 0 : return(RADIOLIB_ERR_INVALID_CODING_RATE);
238 : }
239 :
240 : // set coding rate and if successful, save the new setting
241 0 : int16_t state = SX1278::setCodingRateRaw(newCodingRate);
242 0 : if(state == RADIOLIB_ERR_NONE) {
243 0 : SX127x::codingRate = cr;
244 : }
245 0 : return(state);
246 : }
247 :
248 3 : int16_t SX1278::setBitRate(float br) {
249 3 : return(SX127x::setBitRateCommon(br, RADIOLIB_SX1278_REG_BIT_RATE_FRAC));
250 : }
251 :
252 2 : int16_t SX1278::setDataRate(DataRate_t dr, ModemType_t modem) {
253 : // get the current modem
254 : ModemType_t currentModem;
255 2 : int16_t state = this->getModem(¤tModem);
256 2 : RADIOLIB_ASSERT(state);
257 :
258 : // switch over if the requested modem is different
259 2 : if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) {
260 0 : state = this->standby();
261 0 : RADIOLIB_ASSERT(state);
262 0 : state = this->setModem(modem);
263 0 : RADIOLIB_ASSERT(state);
264 : }
265 :
266 2 : if(modem == RADIOLIB_MODEM_NONE) {
267 2 : modem = currentModem;
268 : }
269 :
270 : // select interpretation based on modem
271 2 : if(modem == RADIOLIB_MODEM_FSK) {
272 : // set the bit rate
273 0 : state = this->setBitRate(dr.fsk.bitRate);
274 0 : RADIOLIB_ASSERT(state);
275 :
276 : // set the frequency deviation
277 0 : state = this->setFrequencyDeviation(dr.fsk.freqDev);
278 :
279 2 : } else if(modem == RADIOLIB_MODEM_LORA) {
280 : // set the spreading factor
281 2 : state = this->setSpreadingFactor(dr.lora.spreadingFactor);
282 2 : RADIOLIB_ASSERT(state);
283 :
284 : // set the bandwidth
285 0 : state = this->setBandwidth(dr.lora.bandwidth);
286 0 : RADIOLIB_ASSERT(state);
287 :
288 : // set the coding rate
289 0 : state = this->setCodingRate(dr.lora.codingRate);
290 : }
291 :
292 0 : return(state);
293 : }
294 :
295 2 : int16_t SX1278::checkDataRate(DataRate_t dr, ModemType_t modem) {
296 2 : int16_t state = RADIOLIB_ERR_UNKNOWN;
297 :
298 : // retrieve modem if not supplied
299 2 : if(modem == RADIOLIB_MODEM_NONE) {
300 2 : state = this->getModem(&modem);
301 2 : RADIOLIB_ASSERT(state);
302 : }
303 :
304 : // select interpretation based on modem
305 2 : if(modem == RADIOLIB_MODEM_FSK) {
306 0 : RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
307 0 : if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0f <= 250.0f) && (dr.fsk.freqDev <= 200.0f))) {
308 0 : return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
309 : }
310 0 : return(RADIOLIB_ERR_NONE);
311 :
312 2 : } else if(modem == RADIOLIB_MODEM_LORA) {
313 2 : RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
314 0 : RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
315 0 : RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
316 0 : return(RADIOLIB_ERR_NONE);
317 :
318 : }
319 :
320 0 : return(state);
321 : }
322 :
323 3 : int16_t SX1278::setOutputPower(int8_t power) {
324 3 : return(this->setOutputPower(power, false));
325 : }
326 :
327 3 : int16_t SX1278::setOutputPower(int8_t power, bool forceRfo) {
328 : // check if power value is configurable
329 3 : bool useRfo = (power < 2) || forceRfo;
330 3 : int16_t state = checkOutputPower(power, NULL, useRfo);
331 3 : RADIOLIB_ASSERT(state);
332 :
333 : // set mode to standby
334 3 : state = SX127x::standby();
335 3 : Module* mod = this->getMod();
336 :
337 3 : if(useRfo) {
338 3 : uint8_t paCfg = 0;
339 3 : if(power < 0) {
340 : // low power mode RFO output
341 0 : paCfg = RADIOLIB_SX1278_LOW_POWER | (power + 3);
342 : } else {
343 : // high power mode RFO output
344 3 : paCfg = RADIOLIB_SX1278_MAX_POWER | power;
345 : }
346 :
347 3 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_RFO, 7, 7);
348 3 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, paCfg, 6, 0);
349 3 : state |= mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0);
350 :
351 : } else {
352 0 : if(power != 20) {
353 : // power is 2 - 17 dBm, enable PA1 + PA2 on PA_BOOST
354 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7);
355 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX1278_MAX_POWER | (power - 2), 6, 0);
356 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0);
357 :
358 : } else {
359 : // power is 20 dBm, enable PA1 + PA2 on PA_BOOST and enable high power control
360 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7);
361 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX1278_MAX_POWER | 0x0F, 6, 0);
362 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_ON, 2, 0);
363 :
364 : }
365 : }
366 :
367 3 : return(state);
368 : }
369 :
370 3 : int16_t SX1278::checkOutputPower(int8_t power, int8_t* clipped) {
371 3 : return(checkOutputPower(power, clipped, false));
372 : }
373 :
374 6 : int16_t SX1278::checkOutputPower(int8_t power, int8_t* clipped, bool useRfo) {
375 : // check allowed power range
376 6 : if(useRfo) {
377 : // RFO output
378 3 : if(clipped) {
379 0 : *clipped = RADIOLIB_MAX(-4, RADIOLIB_MIN(15, power));
380 : }
381 3 : RADIOLIB_CHECK_RANGE(power, -4, 15, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
382 : } else {
383 : // PA_BOOST output, check high-power operation
384 3 : if(clipped) {
385 0 : if(power != 20) {
386 0 : *clipped = RADIOLIB_MAX(2, RADIOLIB_MIN(17, power));
387 : } else {
388 0 : *clipped = 20;
389 : }
390 : }
391 3 : if(power != 20) {
392 3 : RADIOLIB_CHECK_RANGE(power, 2, 17, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
393 : }
394 : }
395 3 : return(RADIOLIB_ERR_NONE);
396 : }
397 :
398 0 : int16_t SX1278::setGain(uint8_t gain) {
399 : // check allowed range
400 0 : if(gain > 6) {
401 0 : return(RADIOLIB_ERR_INVALID_GAIN);
402 : }
403 :
404 : // set mode to standby
405 0 : int16_t state = SX127x::standby();
406 0 : Module* mod = this->getMod();
407 :
408 : // get modem
409 0 : int16_t modem = getActiveModem();
410 0 : if(modem == RADIOLIB_SX127X_LORA){
411 : // set gain
412 0 : if(gain == 0) {
413 : // gain set to 0, enable AGC loop
414 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_AGC_AUTO_ON, 2, 2);
415 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, RADIOLIB_SX127X_LNA_BOOST_ON, 1, 0);
416 : } else {
417 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_AGC_AUTO_OFF, 2, 2);
418 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON);
419 : }
420 :
421 0 : } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
422 : // set gain
423 0 : if(gain == 0) {
424 : // gain set to 0, enable AGC loop
425 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX127X_AGC_AUTO_ON, 3, 3);
426 : } else {
427 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX1278_AGC_AUTO_OFF, 3, 3);
428 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON);
429 : }
430 :
431 : }
432 :
433 0 : return(state);
434 : }
435 :
436 3 : int16_t SX1278::setDataShaping(uint8_t sh) {
437 : // check active modem
438 3 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
439 3 : return(RADIOLIB_ERR_WRONG_MODEM);
440 : }
441 :
442 : // check modulation
443 0 : if(SX127x::ookEnabled) {
444 : // we're in OOK mode, the only thing we can do is disable
445 0 : if(sh == RADIOLIB_SHAPING_NONE) {
446 0 : return(setDataShapingOOK(0));
447 : }
448 :
449 0 : return(RADIOLIB_ERR_INVALID_MODULATION);
450 : }
451 :
452 : // set mode to standby
453 0 : int16_t state = SX127x::standby();
454 0 : RADIOLIB_ASSERT(state);
455 :
456 : // set data shaping
457 0 : Module* mod = this->getMod();
458 0 : switch(sh) {
459 0 : case RADIOLIB_SHAPING_NONE:
460 0 : return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_NO_SHAPING, 6, 5));
461 0 : case RADIOLIB_SHAPING_0_3:
462 0 : return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_0_3, 6, 5));
463 0 : case RADIOLIB_SHAPING_0_5:
464 0 : return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_0_5, 6, 5));
465 0 : case RADIOLIB_SHAPING_1_0:
466 0 : return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_1_0, 6, 5));
467 0 : default:
468 0 : return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
469 : }
470 : }
471 :
472 0 : int16_t SX1278::setDataShapingOOK(uint8_t sh) {
473 : // check active modem
474 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
475 0 : return(RADIOLIB_ERR_WRONG_MODEM);
476 : }
477 :
478 : // check modulation
479 0 : if(!SX127x::ookEnabled) {
480 0 : return(RADIOLIB_ERR_INVALID_MODULATION);
481 : }
482 :
483 : // set mode to standby
484 0 : int16_t state = SX127x::standby();
485 :
486 : // set data shaping
487 0 : Module* mod = this->getMod();
488 0 : switch(sh) {
489 0 : case 0:
490 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_NO_SHAPING, 6, 5);
491 0 : break;
492 0 : case 1:
493 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_OOK_FILTER_BR, 6, 5);
494 0 : break;
495 0 : case 2:
496 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_OOK_FILTER_2BR, 6, 5);
497 0 : break;
498 0 : default:
499 0 : return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
500 : }
501 :
502 0 : return(state);
503 : }
504 :
505 3 : float SX1278::getRSSI() {
506 3 : return(SX1278::getRSSI(true, false));
507 : }
508 :
509 3 : float SX1278::getRSSI(bool packet, bool skipReceive) {
510 3 : int16_t offset = -157;
511 3 : if(frequency < 868.0f) {
512 3 : offset = -164;
513 : }
514 3 : return(SX127x::getRSSI(packet, skipReceive, offset));
515 : }
516 :
517 0 : int16_t SX1278::setCRC(bool enable, bool mode) {
518 0 : Module* mod = this->getMod();
519 0 : if(getActiveModem() == RADIOLIB_SX127X_LORA) {
520 : // set LoRa CRC
521 0 : SX127x::crcEnabled = enable;
522 0 : if(enable) {
523 0 : return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1278_RX_CRC_MODE_ON, 2, 2));
524 : } else {
525 0 : return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1278_RX_CRC_MODE_OFF, 2, 2));
526 : }
527 : } else {
528 : // set FSK CRC
529 0 : int16_t state = RADIOLIB_ERR_NONE;
530 0 : if(enable) {
531 0 : state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_ON, 4, 4);
532 : } else {
533 0 : state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_OFF, 4, 4);
534 : }
535 0 : RADIOLIB_ASSERT(state);
536 :
537 : // set FSK CRC mode
538 0 : if(mode) {
539 0 : return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_IBM, 0, 0));
540 : } else {
541 0 : return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT, 0, 0));
542 : }
543 : }
544 : }
545 :
546 0 : int16_t SX1278::forceLDRO(bool enable) {
547 0 : if(getActiveModem() != RADIOLIB_SX127X_LORA) {
548 0 : return(RADIOLIB_ERR_WRONG_MODEM);
549 : }
550 :
551 0 : Module* mod = this->getMod();
552 0 : this->ldroAuto = false;
553 0 : this->ldroEnabled = enable;
554 0 : if(enable) {
555 0 : return(mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3));
556 : } else {
557 0 : return(mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3));
558 : }
559 : }
560 :
561 0 : int16_t SX1278::autoLDRO() {
562 0 : if(getActiveModem() != RADIOLIB_SX127X_LORA) {
563 0 : return(RADIOLIB_ERR_WRONG_MODEM);
564 : }
565 :
566 0 : this->ldroAuto = true;
567 0 : return(RADIOLIB_ERR_NONE);
568 : }
569 :
570 0 : int16_t SX1278::implicitHeader(size_t len) {
571 0 : this->implicitHdr = true;
572 0 : return(setHeaderType(RADIOLIB_SX1278_HEADER_IMPL_MODE, 0, len));
573 : }
574 :
575 0 : int16_t SX1278::explicitHeader() {
576 0 : this->implicitHdr = false;
577 0 : return(setHeaderType(RADIOLIB_SX1278_HEADER_EXPL_MODE, 0));
578 : }
579 :
580 0 : int16_t SX1278::setBandwidthRaw(uint8_t newBandwidth) {
581 : // set mode to standby
582 0 : int16_t state = SX127x::standby();
583 :
584 : // write register
585 0 : Module* mod = this->getMod();
586 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newBandwidth, 7, 4);
587 0 : return(state);
588 : }
589 :
590 0 : int16_t SX1278::setSpreadingFactorRaw(uint8_t newSpreadingFactor) {
591 : // set mode to standby
592 0 : int16_t state = SX127x::standby();
593 :
594 : // write registers
595 0 : Module* mod = this->getMod();
596 0 : if(newSpreadingFactor == RADIOLIB_SX127X_SF_6) {
597 0 : this->implicitHdr = true;
598 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1278_HEADER_IMPL_MODE, 0, 0);
599 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX127X_SF_6 | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3);
600 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_6, 2, 0);
601 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_6);
602 : } else {
603 0 : this->implicitHdr = false;
604 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1278_HEADER_EXPL_MODE, 0, 0);
605 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3);
606 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0);
607 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_7_12);
608 : }
609 0 : return(state);
610 : }
611 :
612 0 : int16_t SX1278::setCodingRateRaw(uint8_t newCodingRate) {
613 : // set mode to standby
614 0 : int16_t state = SX127x::standby();
615 :
616 : // write register
617 0 : Module* mod = this->getMod();
618 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newCodingRate, 3, 1);
619 0 : return(state);
620 : }
621 :
622 0 : int16_t SX1278::configFSK() {
623 : // configure common registers
624 0 : int16_t state = SX127x::configFSK();
625 0 : RADIOLIB_ASSERT(state);
626 :
627 : // set fast PLL hop
628 0 : Module* mod = this->getMod();
629 0 : state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PLL_HOP, RADIOLIB_SX127X_FAST_HOP_ON, 7, 7);
630 0 : return(state);
631 : }
632 :
633 0 : void SX1278::errataFix(bool rx) {
634 : // only apply in LoRa mode
635 0 : if(getActiveModem() != RADIOLIB_SX127X_LORA) {
636 0 : return;
637 : }
638 :
639 : // sensitivity optimization for 500kHz bandwidth
640 : // see SX1276/77/78 Errata, section 2.1 for details
641 0 : Module* mod = this->getMod();
642 0 : if(fabsf(SX127x::bandwidth - 500.0f) <= 0.001f) {
643 0 : if((frequency >= 862.0f) && (frequency <= 1020.0f)) {
644 0 : mod->SPIwriteRegister(0x36, 0x02);
645 0 : mod->SPIwriteRegister(0x3a, 0x64);
646 0 : } else if((frequency >= 410.0f) && (frequency <= 525.0f)) {
647 0 : mod->SPIwriteRegister(0x36, 0x02);
648 0 : mod->SPIwriteRegister(0x3a, 0x7F);
649 : }
650 : }
651 :
652 : // mitigation of receiver spurious response
653 : // see SX1276/77/78 Errata, section 2.3 for details
654 :
655 : // figure out what we need to set
656 0 : uint8_t fixedRegs[3] = { 0x00, 0x00, 0x00 };
657 0 : float rxFreq = frequency;
658 0 : if(fabsf(SX127x::bandwidth - 7.8f) <= 0.001f) {
659 0 : fixedRegs[0] = 0b00000000;
660 0 : fixedRegs[1] = 0x48;
661 0 : fixedRegs[2] = 0x00;
662 0 : rxFreq += 0.00781f;
663 0 : } else if(fabsf(SX127x::bandwidth - 10.4f) <= 0.001f) {
664 0 : fixedRegs[0] = 0b00000000;
665 0 : fixedRegs[1] = 0x44;
666 0 : fixedRegs[2] = 0x00;
667 0 : rxFreq += 0.01042f;
668 0 : } else if(fabsf(SX127x::bandwidth - 15.6f) <= 0.001f) {
669 0 : fixedRegs[0] = 0b00000000;
670 0 : fixedRegs[1] = 0x44;
671 0 : fixedRegs[2] = 0x00;
672 0 : rxFreq += 0.01562f;
673 0 : } else if(fabsf(SX127x::bandwidth - 20.8f) <= 0.001f) {
674 0 : fixedRegs[0] = 0b00000000;
675 0 : fixedRegs[1] = 0x44;
676 0 : fixedRegs[2] = 0x00;
677 0 : rxFreq += 0.02083f;
678 0 : } else if(fabsf(SX127x::bandwidth - 31.25f) <= 0.001f) {
679 0 : fixedRegs[0] = 0b00000000;
680 0 : fixedRegs[1] = 0x44;
681 0 : fixedRegs[2] = 0x00;
682 0 : rxFreq += 0.03125f;
683 0 : } else if(fabsf(SX127x::bandwidth - 41.7f) <= 0.001f) {
684 0 : fixedRegs[0] = 0b00000000;
685 0 : fixedRegs[1] = 0x44;
686 0 : fixedRegs[2] = 0x00;
687 0 : rxFreq += 0.04167f;
688 0 : } else if(fabsf(SX127x::bandwidth - 62.5f) <= 0.001f) {
689 0 : fixedRegs[0] = 0b00000000;
690 0 : fixedRegs[1] = 0x40;
691 0 : fixedRegs[2] = 0x00;
692 0 : } else if(fabsf(SX127x::bandwidth - 125.0f) <= 0.001f) {
693 0 : fixedRegs[0] = 0b00000000;
694 0 : fixedRegs[1] = 0x40;
695 0 : fixedRegs[2] = 0x00;
696 0 : } else if(fabsf(SX127x::bandwidth - 250.0f) <= 0.001f) {
697 0 : fixedRegs[0] = 0b00000000;
698 0 : fixedRegs[1] = 0x40;
699 0 : fixedRegs[2] = 0x00;
700 0 : } else if(fabsf(SX127x::bandwidth - 500.0f) <= 0.001f) {
701 0 : fixedRegs[0] = 0b10000000;
702 0 : fixedRegs[1] = mod->SPIreadRegister(0x2F);
703 0 : fixedRegs[2] = mod->SPIreadRegister(0x30);
704 : } else {
705 0 : return;
706 : }
707 :
708 : // first, go to standby
709 0 : standby();
710 :
711 : // shift the freqency up when receiving, or restore the original when transmitting
712 0 : if(rx) {
713 0 : SX127x::setFrequencyRaw(rxFreq);
714 : } else {
715 0 : SX127x::setFrequencyRaw(frequency);
716 : }
717 :
718 : // finally, apply errata fixes
719 0 : mod->SPIsetRegValue(0x31, fixedRegs[0], 7, 7);
720 0 : mod->SPIsetRegValue(0x2F, fixedRegs[1]);
721 0 : mod->SPIsetRegValue(0x30, fixedRegs[2]);
722 : }
723 :
724 1 : int16_t SX1278::setModem(ModemType_t modem) {
725 1 : switch(modem) {
726 0 : case(ModemType_t::RADIOLIB_MODEM_LORA): {
727 0 : return(this->begin());
728 : } break;
729 0 : case(ModemType_t::RADIOLIB_MODEM_FSK): {
730 0 : return(this->beginFSK());
731 : } break;
732 1 : default:
733 1 : return(RADIOLIB_ERR_WRONG_MODEM);
734 : }
735 : }
736 :
737 : #endif
|