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