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