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 : state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3);
224 : } else {
225 0 : state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3);
226 : }
227 : }
228 : }
229 0 : return(state);
230 : }
231 :
232 0 : int16_t SX1278::setCodingRate(uint8_t cr) {
233 : // check active modem
234 0 : if(getActiveModem() != RADIOLIB_SX127X_LORA) {
235 0 : return(RADIOLIB_ERR_WRONG_MODEM);
236 : }
237 :
238 : uint8_t newCodingRate;
239 :
240 : // check allowed coding rate values
241 0 : switch(cr) {
242 0 : case 4:
243 0 : newCodingRate = RADIOLIB_SX1278_CR_4_4;
244 0 : break;
245 0 : case 5:
246 0 : newCodingRate = RADIOLIB_SX1278_CR_4_5;
247 0 : break;
248 0 : case 6:
249 0 : newCodingRate = RADIOLIB_SX1278_CR_4_6;
250 0 : break;
251 0 : case 7:
252 0 : newCodingRate = RADIOLIB_SX1278_CR_4_7;
253 0 : break;
254 0 : case 8:
255 0 : newCodingRate = RADIOLIB_SX1278_CR_4_8;
256 0 : break;
257 0 : default:
258 0 : return(RADIOLIB_ERR_INVALID_CODING_RATE);
259 : }
260 :
261 : // set coding rate and if successful, save the new setting
262 0 : int16_t state = SX1278::setCodingRateRaw(newCodingRate);
263 0 : if(state == RADIOLIB_ERR_NONE) {
264 0 : SX127x::codingRate = cr;
265 : }
266 0 : return(state);
267 : }
268 :
269 3 : int16_t SX1278::setBitRate(float br) {
270 3 : return(SX127x::setBitRateCommon(br, RADIOLIB_SX1278_REG_BIT_RATE_FRAC));
271 : }
272 :
273 2 : int16_t SX1278::setDataRate(DataRate_t dr, ModemType_t modem) {
274 : // get the current modem
275 : ModemType_t currentModem;
276 2 : int16_t state = this->getModem(¤tModem);
277 2 : RADIOLIB_ASSERT(state);
278 :
279 : // switch over if the requested modem is different
280 2 : if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) {
281 0 : state = this->standby();
282 0 : RADIOLIB_ASSERT(state);
283 0 : state = this->setModem(modem);
284 0 : RADIOLIB_ASSERT(state);
285 : }
286 :
287 2 : if(modem == RADIOLIB_MODEM_NONE) {
288 2 : modem = currentModem;
289 : }
290 :
291 : // select interpretation based on modem
292 2 : if(modem == RADIOLIB_MODEM_FSK) {
293 : // set the bit rate
294 0 : state = this->setBitRate(dr.fsk.bitRate);
295 0 : RADIOLIB_ASSERT(state);
296 :
297 : // set the frequency deviation
298 0 : state = this->setFrequencyDeviation(dr.fsk.freqDev);
299 :
300 2 : } else if(modem == RADIOLIB_MODEM_LORA) {
301 : // set the spreading factor
302 2 : state = this->setSpreadingFactor(dr.lora.spreadingFactor);
303 2 : RADIOLIB_ASSERT(state);
304 :
305 : // set the bandwidth
306 0 : state = this->setBandwidth(dr.lora.bandwidth);
307 0 : RADIOLIB_ASSERT(state);
308 :
309 : // set the coding rate
310 0 : state = this->setCodingRate(dr.lora.codingRate);
311 : }
312 :
313 0 : return(state);
314 : }
315 :
316 2 : int16_t SX1278::checkDataRate(DataRate_t dr, ModemType_t modem) {
317 2 : int16_t state = RADIOLIB_ERR_UNKNOWN;
318 :
319 : // retrieve modem if not supplied
320 2 : if(modem == RADIOLIB_MODEM_NONE) {
321 2 : state = this->getModem(&modem);
322 2 : RADIOLIB_ASSERT(state);
323 : }
324 :
325 : // select interpretation based on modem
326 2 : if(modem == RADIOLIB_MODEM_FSK) {
327 0 : RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.5f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
328 0 : if(!((dr.fsk.freqDev + dr.fsk.bitRate/2.0f <= 250.0f) && (dr.fsk.freqDev <= 200.0f))) {
329 0 : return(RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
330 : }
331 0 : return(RADIOLIB_ERR_NONE);
332 :
333 2 : } else if(modem == RADIOLIB_MODEM_LORA) {
334 2 : RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 6, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
335 0 : RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0f, 510.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
336 0 : RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
337 0 : return(RADIOLIB_ERR_NONE);
338 :
339 : }
340 :
341 0 : return(state);
342 : }
343 :
344 3 : int16_t SX1278::setOutputPower(int8_t power) {
345 3 : return(this->setOutputPower(power, false));
346 : }
347 :
348 3 : int16_t SX1278::setOutputPower(int8_t power, bool forceRfo) {
349 : // check if power value is configurable
350 3 : bool useRfo = (power < 2) || forceRfo;
351 3 : int16_t state = checkOutputPower(power, NULL, useRfo);
352 3 : RADIOLIB_ASSERT(state);
353 :
354 : // set mode to standby
355 3 : state = SX127x::standby();
356 3 : Module* mod = this->getMod();
357 :
358 3 : if(useRfo) {
359 3 : uint8_t paCfg = 0;
360 3 : if(power < 0) {
361 : // low power mode RFO output
362 0 : paCfg = RADIOLIB_SX1278_LOW_POWER | (power + 3);
363 : } else {
364 : // high power mode RFO output
365 3 : paCfg = RADIOLIB_SX1278_MAX_POWER | power;
366 : }
367 :
368 3 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_RFO, 7, 7);
369 3 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, paCfg, 6, 0);
370 3 : state |= mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0);
371 :
372 : } else {
373 0 : if(power != 20) {
374 : // power is 2 - 17 dBm, enable PA1 + PA2 on PA_BOOST
375 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7);
376 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX1278_MAX_POWER | (power - 2), 6, 0);
377 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_OFF, 2, 0);
378 :
379 : } else {
380 : // power is 20 dBm, enable PA1 + PA2 on PA_BOOST and enable high power control
381 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX127X_PA_SELECT_BOOST, 7, 7);
382 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_CONFIG, RADIOLIB_SX1278_MAX_POWER | 0x0F, 6, 0);
383 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PA_DAC, RADIOLIB_SX127X_PA_BOOST_ON, 2, 0);
384 :
385 : }
386 : }
387 :
388 3 : return(state);
389 : }
390 :
391 3 : int16_t SX1278::checkOutputPower(int8_t power, int8_t* clipped) {
392 3 : return(checkOutputPower(power, clipped, false));
393 : }
394 :
395 6 : int16_t SX1278::checkOutputPower(int8_t power, int8_t* clipped, bool useRfo) {
396 : // check allowed power range
397 6 : if(useRfo) {
398 : // RFO output
399 3 : if(clipped) {
400 0 : *clipped = RADIOLIB_MAX(-4, RADIOLIB_MIN(15, power));
401 : }
402 3 : RADIOLIB_CHECK_RANGE(power, -4, 15, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
403 : } else {
404 : // PA_BOOST output, check high-power operation
405 3 : if(clipped) {
406 0 : if(power != 20) {
407 0 : *clipped = RADIOLIB_MAX(2, RADIOLIB_MIN(17, power));
408 : } else {
409 0 : *clipped = 20;
410 : }
411 : }
412 3 : if(power != 20) {
413 3 : RADIOLIB_CHECK_RANGE(power, 2, 17, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
414 : }
415 : }
416 3 : return(RADIOLIB_ERR_NONE);
417 : }
418 :
419 0 : int16_t SX1278::setGain(uint8_t gain) {
420 : // check allowed range
421 0 : if(gain > 6) {
422 0 : return(RADIOLIB_ERR_INVALID_GAIN);
423 : }
424 :
425 : // set mode to standby
426 0 : int16_t state = SX127x::standby();
427 0 : Module* mod = this->getMod();
428 :
429 : // get modem
430 0 : int16_t modem = getActiveModem();
431 0 : if(modem == RADIOLIB_SX127X_LORA){
432 : // set gain
433 0 : if(gain == 0) {
434 : // gain set to 0, enable AGC loop
435 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_AGC_AUTO_ON, 2, 2);
436 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, RADIOLIB_SX127X_LNA_BOOST_ON, 1, 0);
437 : } else {
438 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_AGC_AUTO_OFF, 2, 2);
439 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON);
440 : }
441 :
442 0 : } else if(modem == RADIOLIB_SX127X_FSK_OOK) {
443 : // set gain
444 0 : if(gain == 0) {
445 : // gain set to 0, enable AGC loop
446 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX127X_AGC_AUTO_ON, 3, 3);
447 : } else {
448 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_RX_CONFIG, RADIOLIB_SX1278_AGC_AUTO_OFF, 3, 3);
449 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_LNA, (gain << 5) | RADIOLIB_SX127X_LNA_BOOST_ON);
450 : }
451 :
452 : }
453 :
454 0 : return(state);
455 : }
456 :
457 3 : int16_t SX1278::setDataShaping(uint8_t sh) {
458 : // check active modem
459 3 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
460 3 : return(RADIOLIB_ERR_WRONG_MODEM);
461 : }
462 :
463 : // check modulation
464 0 : if(SX127x::ookEnabled) {
465 : // we're in OOK mode, the only thing we can do is disable
466 0 : if(sh == RADIOLIB_SHAPING_NONE) {
467 0 : return(setDataShapingOOK(0));
468 : }
469 :
470 0 : return(RADIOLIB_ERR_INVALID_MODULATION);
471 : }
472 :
473 : // set mode to standby
474 0 : int16_t state = SX127x::standby();
475 0 : RADIOLIB_ASSERT(state);
476 :
477 : // set data shaping
478 0 : Module* mod = this->getMod();
479 0 : switch(sh) {
480 0 : case RADIOLIB_SHAPING_NONE:
481 0 : return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_NO_SHAPING, 6, 5));
482 0 : case RADIOLIB_SHAPING_0_3:
483 0 : return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_0_3, 6, 5));
484 0 : case RADIOLIB_SHAPING_0_5:
485 0 : return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_0_5, 6, 5));
486 0 : case RADIOLIB_SHAPING_1_0:
487 0 : return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_FSK_GAUSSIAN_1_0, 6, 5));
488 0 : default:
489 0 : return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
490 : }
491 : }
492 :
493 0 : int16_t SX1278::setDataShapingOOK(uint8_t sh) {
494 : // check active modem
495 0 : if(getActiveModem() != RADIOLIB_SX127X_FSK_OOK) {
496 0 : return(RADIOLIB_ERR_WRONG_MODEM);
497 : }
498 :
499 : // check modulation
500 0 : if(!SX127x::ookEnabled) {
501 0 : return(RADIOLIB_ERR_INVALID_MODULATION);
502 : }
503 :
504 : // set mode to standby
505 0 : int16_t state = SX127x::standby();
506 :
507 : // set data shaping
508 0 : Module* mod = this->getMod();
509 0 : switch(sh) {
510 0 : case 0:
511 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_NO_SHAPING, 6, 5);
512 0 : break;
513 0 : case 1:
514 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_OOK_FILTER_BR, 6, 5);
515 0 : break;
516 0 : case 2:
517 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PA_RAMP, RADIOLIB_SX1278_OOK_FILTER_2BR, 6, 5);
518 0 : break;
519 0 : default:
520 0 : return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
521 : }
522 :
523 0 : return(state);
524 : }
525 :
526 3 : float SX1278::getRSSI() {
527 3 : return(SX1278::getRSSI(true, false));
528 : }
529 :
530 3 : float SX1278::getRSSI(bool packet, bool skipReceive) {
531 3 : int16_t offset = -157;
532 3 : if(frequency < 868.0f) {
533 3 : offset = -164;
534 : }
535 3 : return(SX127x::getRSSICommon(packet, skipReceive, offset));
536 : }
537 :
538 0 : int16_t SX1278::setCRC(bool enable, bool mode) {
539 0 : Module* mod = this->getMod();
540 0 : if(getActiveModem() == RADIOLIB_SX127X_LORA) {
541 : // set LoRa CRC
542 0 : SX127x::crcEnabled = enable;
543 0 : if(enable) {
544 0 : return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1278_RX_CRC_MODE_ON, 2, 2));
545 : } else {
546 0 : return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX1278_RX_CRC_MODE_OFF, 2, 2));
547 : }
548 : } else {
549 : // set FSK CRC
550 0 : int16_t state = RADIOLIB_ERR_NONE;
551 0 : if(enable) {
552 0 : state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_ON, 4, 4);
553 : } else {
554 0 : state = mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_OFF, 4, 4);
555 : }
556 0 : RADIOLIB_ASSERT(state);
557 :
558 : // set FSK CRC mode
559 0 : if(mode) {
560 0 : return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_IBM, 0, 0));
561 : } else {
562 0 : return(mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PACKET_CONFIG_1, RADIOLIB_SX127X_CRC_WHITENING_TYPE_CCITT, 0, 0));
563 : }
564 : }
565 : }
566 :
567 0 : int16_t SX1278::forceLDRO(bool enable) {
568 0 : if(getActiveModem() != RADIOLIB_SX127X_LORA) {
569 0 : return(RADIOLIB_ERR_WRONG_MODEM);
570 : }
571 :
572 0 : Module* mod = this->getMod();
573 0 : this->ldroAuto = false;
574 0 : this->ldroEnabled = enable;
575 0 : if(enable) {
576 0 : return(mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_ON, 3, 3));
577 : } else {
578 0 : return(mod->SPIsetRegValue(RADIOLIB_SX1278_REG_MODEM_CONFIG_3, RADIOLIB_SX1278_LOW_DATA_RATE_OPT_OFF, 3, 3));
579 : }
580 : }
581 :
582 0 : int16_t SX1278::autoLDRO() {
583 0 : if(getActiveModem() != RADIOLIB_SX127X_LORA) {
584 0 : return(RADIOLIB_ERR_WRONG_MODEM);
585 : }
586 :
587 0 : this->ldroAuto = true;
588 0 : return(RADIOLIB_ERR_NONE);
589 : }
590 :
591 0 : int16_t SX1278::implicitHeader(size_t len) {
592 0 : this->implicitHdr = true;
593 0 : return(setHeaderType(RADIOLIB_SX1278_HEADER_IMPL_MODE, 0, len));
594 : }
595 :
596 0 : int16_t SX1278::explicitHeader() {
597 0 : this->implicitHdr = false;
598 0 : return(setHeaderType(RADIOLIB_SX1278_HEADER_EXPL_MODE, 0));
599 : }
600 :
601 0 : int16_t SX1278::setBandwidthRaw(uint8_t newBandwidth) {
602 : // set mode to standby
603 0 : int16_t state = SX127x::standby();
604 :
605 : // write register
606 0 : Module* mod = this->getMod();
607 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newBandwidth, 7, 4);
608 0 : return(state);
609 : }
610 :
611 0 : int16_t SX1278::setSpreadingFactorRaw(uint8_t newSpreadingFactor) {
612 : // set mode to standby
613 0 : int16_t state = SX127x::standby();
614 :
615 : // write registers
616 0 : Module* mod = this->getMod();
617 0 : if(newSpreadingFactor == RADIOLIB_SX127X_SF_6) {
618 0 : this->implicitHdr = true;
619 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1278_HEADER_IMPL_MODE, 0, 0);
620 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, RADIOLIB_SX127X_SF_6 | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3);
621 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_6, 2, 0);
622 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_6);
623 : } else {
624 0 : this->implicitHdr = false;
625 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, RADIOLIB_SX1278_HEADER_EXPL_MODE, 0, 0);
626 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | RADIOLIB_SX127X_TX_MODE_SINGLE, 7, 3);
627 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECT_OPTIMIZE, RADIOLIB_SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0);
628 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DETECTION_THRESHOLD, RADIOLIB_SX127X_DETECTION_THRESHOLD_SF_7_12);
629 : }
630 0 : return(state);
631 : }
632 :
633 0 : int16_t SX1278::setCodingRateRaw(uint8_t newCodingRate) {
634 : // set mode to standby
635 0 : int16_t state = SX127x::standby();
636 :
637 : // write register
638 0 : Module* mod = this->getMod();
639 0 : state |= mod->SPIsetRegValue(RADIOLIB_SX127X_REG_MODEM_CONFIG_1, newCodingRate, 3, 1);
640 0 : return(state);
641 : }
642 :
643 0 : int16_t SX1278::configFSK() {
644 : // configure common registers
645 0 : int16_t state = SX127x::configFSK();
646 0 : RADIOLIB_ASSERT(state);
647 :
648 : // set fast PLL hop
649 0 : Module* mod = this->getMod();
650 0 : state = mod->SPIsetRegValue(RADIOLIB_SX1278_REG_PLL_HOP, RADIOLIB_SX127X_FAST_HOP_ON, 7, 7);
651 0 : return(state);
652 : }
653 :
654 0 : void SX1278::errataFix(bool rx) {
655 : // only apply in LoRa mode
656 0 : if(getActiveModem() != RADIOLIB_SX127X_LORA) {
657 0 : return;
658 : }
659 :
660 : // sensitivity optimization for 500kHz bandwidth
661 : // see SX1276/77/78 Errata, section 2.1 for details
662 0 : Module* mod = this->getMod();
663 0 : if(fabsf(SX127x::bandwidth - 500.0f) <= 0.001f) {
664 0 : if((frequency >= 862.0f) && (frequency <= 1020.0f)) {
665 0 : mod->SPIwriteRegister(0x36, 0x02);
666 0 : mod->SPIwriteRegister(0x3a, 0x64);
667 0 : } else if((frequency >= 410.0f) && (frequency <= 525.0f)) {
668 0 : mod->SPIwriteRegister(0x36, 0x02);
669 0 : mod->SPIwriteRegister(0x3a, 0x7F);
670 : }
671 : }
672 :
673 : // mitigation of receiver spurious response
674 : // see SX1276/77/78 Errata, section 2.3 for details
675 :
676 : // figure out what we need to set
677 0 : uint8_t fixedRegs[3] = { 0x00, 0x00, 0x00 };
678 0 : float rxFreq = frequency;
679 0 : if(fabsf(SX127x::bandwidth - 7.8f) <= 0.001f) {
680 0 : fixedRegs[0] = 0b00000000;
681 0 : fixedRegs[1] = 0x48;
682 0 : fixedRegs[2] = 0x00;
683 0 : rxFreq += 0.00781f;
684 0 : } else if(fabsf(SX127x::bandwidth - 10.4f) <= 0.001f) {
685 0 : fixedRegs[0] = 0b00000000;
686 0 : fixedRegs[1] = 0x44;
687 0 : fixedRegs[2] = 0x00;
688 0 : rxFreq += 0.01042f;
689 0 : } else if(fabsf(SX127x::bandwidth - 15.6f) <= 0.001f) {
690 0 : fixedRegs[0] = 0b00000000;
691 0 : fixedRegs[1] = 0x44;
692 0 : fixedRegs[2] = 0x00;
693 0 : rxFreq += 0.01562f;
694 0 : } else if(fabsf(SX127x::bandwidth - 20.8f) <= 0.001f) {
695 0 : fixedRegs[0] = 0b00000000;
696 0 : fixedRegs[1] = 0x44;
697 0 : fixedRegs[2] = 0x00;
698 0 : rxFreq += 0.02083f;
699 0 : } else if(fabsf(SX127x::bandwidth - 31.25f) <= 0.001f) {
700 0 : fixedRegs[0] = 0b00000000;
701 0 : fixedRegs[1] = 0x44;
702 0 : fixedRegs[2] = 0x00;
703 0 : rxFreq += 0.03125f;
704 0 : } else if(fabsf(SX127x::bandwidth - 41.7f) <= 0.001f) {
705 0 : fixedRegs[0] = 0b00000000;
706 0 : fixedRegs[1] = 0x44;
707 0 : fixedRegs[2] = 0x00;
708 0 : rxFreq += 0.04167f;
709 0 : } else if(fabsf(SX127x::bandwidth - 62.5f) <= 0.001f) {
710 0 : fixedRegs[0] = 0b00000000;
711 0 : fixedRegs[1] = 0x40;
712 0 : fixedRegs[2] = 0x00;
713 0 : } else if(fabsf(SX127x::bandwidth - 125.0f) <= 0.001f) {
714 0 : fixedRegs[0] = 0b00000000;
715 0 : fixedRegs[1] = 0x40;
716 0 : fixedRegs[2] = 0x00;
717 0 : } else if(fabsf(SX127x::bandwidth - 250.0f) <= 0.001f) {
718 0 : fixedRegs[0] = 0b00000000;
719 0 : fixedRegs[1] = 0x40;
720 0 : fixedRegs[2] = 0x00;
721 0 : } else if(fabsf(SX127x::bandwidth - 500.0f) <= 0.001f) {
722 0 : fixedRegs[0] = 0b10000000;
723 0 : fixedRegs[1] = mod->SPIreadRegister(0x2F);
724 0 : fixedRegs[2] = mod->SPIreadRegister(0x30);
725 : } else {
726 0 : return;
727 : }
728 :
729 : // first, go to standby
730 0 : standby();
731 :
732 : // shift the freqency up when receiving, or restore the original when transmitting
733 0 : if(rx) {
734 0 : SX127x::setFrequencyRaw(rxFreq);
735 : } else {
736 0 : SX127x::setFrequencyRaw(frequency);
737 : }
738 :
739 : // finally, apply errata fixes
740 0 : mod->SPIsetRegValue(0x31, fixedRegs[0], 7, 7);
741 0 : mod->SPIsetRegValue(0x2F, fixedRegs[1]);
742 0 : mod->SPIsetRegValue(0x30, fixedRegs[2]);
743 : }
744 :
745 1 : int16_t SX1278::setModem(ModemType_t modem) {
746 1 : switch(modem) {
747 0 : case(ModemType_t::RADIOLIB_MODEM_LORA): {
748 0 : return(this->begin());
749 : } break;
750 0 : case(ModemType_t::RADIOLIB_MODEM_FSK): {
751 0 : return(this->beginFSK());
752 : } break;
753 1 : default:
754 1 : return(RADIOLIB_ERR_WRONG_MODEM);
755 : }
756 : }
757 :
758 : #endif
|