Line data Source code
1 : #include "SX128x.h"
2 : #include <math.h>
3 : #include <string.h>
4 : #if !RADIOLIB_EXCLUDE_SX128X
5 :
6 10 : SX128x::SX128x(Module* mod) : PhysicalLayer() {
7 10 : this->freqStep = RADIOLIB_SX128X_FREQUENCY_STEP_SIZE;
8 10 : this->maxPacketLength = RADIOLIB_SX128X_MAX_PACKET_LENGTH;
9 10 : this->mod = mod;
10 10 : this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_SX128X_IRQ_TX_DONE;
11 10 : this->irqMap[RADIOLIB_IRQ_RX_DONE] = RADIOLIB_SX128X_IRQ_RX_DONE;
12 10 : this->irqMap[RADIOLIB_IRQ_PREAMBLE_DETECTED] = RADIOLIB_SX128X_IRQ_PREAMBLE_DETECTED;
13 10 : this->irqMap[RADIOLIB_IRQ_SYNC_WORD_VALID] = RADIOLIB_SX128X_IRQ_SYNC_WORD_VALID;
14 10 : this->irqMap[RADIOLIB_IRQ_HEADER_VALID] = RADIOLIB_SX128X_IRQ_HEADER_VALID;
15 10 : this->irqMap[RADIOLIB_IRQ_HEADER_ERR] = RADIOLIB_SX128X_IRQ_HEADER_ERROR;
16 10 : this->irqMap[RADIOLIB_IRQ_CRC_ERR] = RADIOLIB_SX128X_IRQ_CRC_ERROR;
17 10 : this->irqMap[RADIOLIB_IRQ_CAD_DONE] = RADIOLIB_SX128X_IRQ_CAD_DONE;
18 10 : this->irqMap[RADIOLIB_IRQ_CAD_DETECTED] = RADIOLIB_SX128X_IRQ_CAD_DETECTED;
19 10 : this->irqMap[RADIOLIB_IRQ_TIMEOUT] = RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT;
20 10 : }
21 :
22 0 : int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncWord, int8_t pwr, uint16_t preambleLength) {
23 : // initialize LoRa modulation variables
24 0 : this->bandwidthKhz = bw;
25 0 : this->spreadingFactor = RADIOLIB_SX128X_LORA_SF_9;
26 0 : this->codingRateLoRa = RADIOLIB_SX128X_LORA_CR_4_7;
27 :
28 : // initialize LoRa packet variables
29 0 : this->preambleLengthLoRa = preambleLength;
30 0 : this->headerType = RADIOLIB_SX128X_LORA_HEADER_EXPLICIT;
31 0 : this->payloadLen = 0xFF;
32 0 : this->crcLoRa = RADIOLIB_SX128X_LORA_CRC_ON;
33 :
34 : // set module properties and perform initial setup
35 0 : int16_t state = this->modSetup(RADIOLIB_SX128X_PACKET_TYPE_LORA);
36 0 : RADIOLIB_ASSERT(state);
37 :
38 : // configure publicly accessible settings
39 0 : state = setFrequency(freq);
40 0 : RADIOLIB_ASSERT(state);
41 :
42 0 : state = setBandwidth(bw);
43 0 : RADIOLIB_ASSERT(state);
44 :
45 0 : state = setSpreadingFactor(sf);
46 0 : RADIOLIB_ASSERT(state);
47 :
48 0 : state = setCodingRate(cr);
49 0 : RADIOLIB_ASSERT(state);
50 :
51 0 : state = setSyncWord(syncWord);
52 0 : RADIOLIB_ASSERT(state);
53 :
54 0 : state = setPreambleLength(preambleLength);
55 0 : RADIOLIB_ASSERT(state);
56 :
57 0 : state = setOutputPower(pwr);
58 0 : RADIOLIB_ASSERT(state);
59 :
60 0 : return(state);
61 : }
62 :
63 0 : int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t pwr, uint16_t preambleLength) {
64 : // initialize GFSK modulation variables
65 0 : this->bitRateKbps = br;
66 0 : this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4;
67 0 : this->modIndexReal = 1.0;
68 0 : this->modIndex = RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_00;
69 0 : this->shaping = RADIOLIB_SX128X_BLE_GFSK_BT_0_5;
70 :
71 : // initialize GFSK packet variables
72 0 : this->preambleLengthGFSK = preambleLength;
73 0 : this->syncWordLen = 2;
74 0 : this->syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1;
75 0 : this->crcGFSK = RADIOLIB_SX128X_GFSK_FLRC_CRC_2_BYTE;
76 0 : this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON;
77 :
78 : // set module properties and perform initial setup
79 0 : int16_t state = this->modSetup(RADIOLIB_SX128X_PACKET_TYPE_GFSK);
80 0 : RADIOLIB_ASSERT(state);
81 :
82 : // configure publicly accessible settings
83 0 : state = setFrequency(freq);
84 0 : RADIOLIB_ASSERT(state);
85 :
86 0 : state = setBitRate(br);
87 0 : RADIOLIB_ASSERT(state);
88 :
89 0 : state = setFrequencyDeviation(freqDev);
90 0 : RADIOLIB_ASSERT(state);
91 :
92 0 : state = setOutputPower(pwr);
93 0 : RADIOLIB_ASSERT(state);
94 :
95 0 : state = setPreambleLength(preambleLength);
96 0 : RADIOLIB_ASSERT(state);
97 :
98 0 : state = setDataShaping(RADIOLIB_SHAPING_0_5);
99 0 : RADIOLIB_ASSERT(state);
100 :
101 : // set publicly accessible settings that are not a part of begin method
102 0 : uint8_t sync[] = { 0x12, 0xAD };
103 0 : state = setSyncWord(sync, 2);
104 0 : RADIOLIB_ASSERT(state);
105 :
106 0 : state = setEncoding(RADIOLIB_ENCODING_NRZ);
107 0 : RADIOLIB_ASSERT(state);
108 :
109 0 : return(state);
110 : }
111 :
112 0 : int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t pwr, uint8_t dataShaping) {
113 : // initialize BLE modulation variables
114 0 : this->bitRateKbps = br;
115 0 : this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4;
116 0 : this->modIndexReal = 1.0;
117 0 : this->modIndex = RADIOLIB_SX128X_BLE_GFSK_MOD_IND_1_00;
118 0 : this->shaping = RADIOLIB_SX128X_BLE_GFSK_BT_0_5;
119 :
120 : // initialize BLE packet variables
121 0 : this->crcGFSK = RADIOLIB_SX128X_BLE_CRC_3_BYTE;
122 0 : this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON;
123 :
124 : // set module properties and perform initial setup
125 0 : int16_t state = this->modSetup(RADIOLIB_SX128X_PACKET_TYPE_BLE);
126 0 : RADIOLIB_ASSERT(state);
127 :
128 : // configure publicly accessible settings
129 0 : state = setFrequency(freq);
130 0 : RADIOLIB_ASSERT(state);
131 :
132 0 : state = setBitRate(br);
133 0 : RADIOLIB_ASSERT(state);
134 :
135 0 : state = setFrequencyDeviation(freqDev);
136 0 : RADIOLIB_ASSERT(state);
137 :
138 0 : state = setOutputPower(pwr);
139 0 : RADIOLIB_ASSERT(state);
140 :
141 0 : state = setDataShaping(dataShaping);
142 0 : RADIOLIB_ASSERT(state);
143 :
144 0 : return(state);
145 : }
146 :
147 0 : int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t pwr, uint16_t preambleLength, uint8_t dataShaping) {
148 : // initialize FLRC modulation variables
149 0 : this->bitRateKbps = br;
150 0 : this->bitRate = RADIOLIB_SX128X_FLRC_BR_0_650_BW_0_6;
151 0 : this->codingRateFLRC = RADIOLIB_SX128X_FLRC_CR_3_4;
152 0 : this->shaping = RADIOLIB_SX128X_FLRC_BT_0_5;
153 :
154 : // initialize FLRC packet variables
155 0 : this->preambleLengthGFSK = preambleLength;
156 0 : this->syncWordLen = 2;
157 0 : this->syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1;
158 0 : this->crcGFSK = RADIOLIB_SX128X_GFSK_FLRC_CRC_2_BYTE;
159 0 : this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_OFF;
160 :
161 : // set module properties and perform initial setup
162 0 : int16_t state = this->modSetup(RADIOLIB_SX128X_PACKET_TYPE_FLRC);
163 0 : RADIOLIB_ASSERT(state);
164 :
165 : // configure publicly accessible settings
166 0 : state = setFrequency(freq);
167 0 : RADIOLIB_ASSERT(state);
168 :
169 0 : state = setBitRate(br);
170 0 : RADIOLIB_ASSERT(state);
171 :
172 0 : state = setCodingRate(cr);
173 0 : RADIOLIB_ASSERT(state);
174 :
175 0 : state = setOutputPower(pwr);
176 0 : RADIOLIB_ASSERT(state);
177 :
178 0 : state = setPreambleLength(preambleLength);
179 0 : RADIOLIB_ASSERT(state);
180 :
181 0 : state = setDataShaping(dataShaping);
182 0 : RADIOLIB_ASSERT(state);
183 :
184 : // set publicly accessible settings that are not a part of begin method
185 0 : uint8_t sync[] = { 0x2D, 0x01, 0x4B, 0x1D};
186 0 : state = setSyncWord(sync, 4);
187 0 : RADIOLIB_ASSERT(state);
188 :
189 0 : return(state);
190 : }
191 :
192 0 : int16_t SX128x::reset(bool verify) {
193 : // run the reset sequence - same as SX126x, as SX128x docs don't seem to mention this
194 0 : this->mod->hal->pinMode(this->mod->getRst(), this->mod->hal->GpioModeOutput);
195 0 : this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelLow);
196 0 : this->mod->hal->delay(1);
197 0 : this->mod->hal->digitalWrite(this->mod->getRst(), this->mod->hal->GpioLevelHigh);
198 :
199 : // return immediately when verification is disabled
200 0 : if(!verify) {
201 0 : return(RADIOLIB_ERR_NONE);
202 : }
203 :
204 : // set mode to standby
205 0 : RadioLibTime_t start = this->mod->hal->millis();
206 : while(true) {
207 : // try to set mode to standby
208 0 : int16_t state = standby();
209 0 : if(state == RADIOLIB_ERR_NONE) {
210 : // standby command successful
211 0 : return(RADIOLIB_ERR_NONE);
212 : }
213 :
214 : // standby command failed, check timeout and try again
215 0 : if(this->mod->hal->millis() - start >= 3000) {
216 : // timed out, possibly incorrect wiring
217 0 : return(state);
218 : }
219 :
220 : // wait a bit to not spam the module
221 0 : this->mod->hal->delay(10);
222 0 : }
223 : }
224 :
225 0 : int16_t SX128x::transmit(const uint8_t* data, size_t len, uint8_t addr) {
226 : // check packet length
227 0 : if(this->codingRateLoRa == RADIOLIB_SX128X_LORA_CR_4_8_LI && this->crcLoRa == RADIOLIB_SX128X_LORA_CRC_ON) {
228 : // Long Interleaver at CR 4/8 supports up to 253 bytes if CRC is enabled
229 0 : if(len > RADIOLIB_SX128X_MAX_PACKET_LENGTH - 2) {
230 0 : return(RADIOLIB_ERR_PACKET_TOO_LONG);
231 : }
232 0 : } else if(len > RADIOLIB_SX128X_MAX_PACKET_LENGTH) {
233 0 : return(RADIOLIB_ERR_PACKET_TOO_LONG);
234 : }
235 :
236 : // check active modem
237 0 : uint8_t modem = getPacketType();
238 0 : if(modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING) {
239 0 : return(RADIOLIB_ERR_WRONG_MODEM);
240 : }
241 :
242 : // set mode to standby
243 0 : int16_t state = standby();
244 0 : RADIOLIB_ASSERT(state);
245 :
246 : // calculate timeout in ms (5ms + 500 % of expected time-on-air)
247 0 : RadioLibTime_t timeout = 5 + (getTimeOnAir(len) * 5) / 1000;
248 : RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", timeout);
249 :
250 : // start transmission
251 0 : state = startTransmit(data, len, addr);
252 0 : RADIOLIB_ASSERT(state);
253 :
254 : // wait for packet transmission or timeout
255 0 : RadioLibTime_t start = this->mod->hal->millis();
256 0 : while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
257 0 : this->mod->hal->yield();
258 0 : if(this->mod->hal->millis() - start > timeout) {
259 0 : finishTransmit();
260 0 : return(RADIOLIB_ERR_TX_TIMEOUT);
261 : }
262 : }
263 :
264 0 : return(finishTransmit());
265 : }
266 :
267 0 : int16_t SX128x::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) {
268 : // check active modem
269 0 : uint8_t modem = getPacketType();
270 0 : if(modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING) {
271 0 : return(RADIOLIB_ERR_WRONG_MODEM);
272 : }
273 :
274 : // set mode to standby
275 0 : int16_t state = standby();
276 0 : RADIOLIB_ASSERT(state);
277 :
278 : // calculate timeout (1000% of expected time-on-air)
279 : // for most other modules, it is 500%, however, the overall datarates of SX128x are higher
280 : // so we use higher value for the default timeout
281 0 : RadioLibTime_t timeoutInternal = timeout;
282 0 : if(!timeoutInternal) {
283 0 : timeoutInternal = getTimeOnAir(len) * 10;
284 : }
285 : RADIOLIB_DEBUG_BASIC_PRINTLN("Timeout in %lu ms", (uint32_t)((timeout + 999) / 1000));
286 :
287 : // start reception
288 0 : uint32_t timeoutValue = (uint32_t)((float)timeoutInternal / 15.625f);
289 0 : state = startReceive(timeoutValue);
290 0 : RADIOLIB_ASSERT(state);
291 :
292 : // wait for packet reception or timeout
293 0 : bool softTimeout = false;
294 0 : RadioLibTime_t start = this->mod->hal->micros();
295 0 : while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
296 0 : this->mod->hal->yield();
297 : // safety check, the timeout should be done by the radio
298 0 : if(this->mod->hal->micros() - start > timeout) {
299 0 : softTimeout = true;
300 0 : break;
301 : }
302 : }
303 :
304 : // if it was a timeout, this will return an error code
305 0 : state = standby();
306 0 : if((state != RADIOLIB_ERR_NONE) && (state != RADIOLIB_ERR_SPI_CMD_TIMEOUT)) {
307 0 : return(state);
308 : }
309 :
310 : // check whether this was a timeout or not
311 0 : if(softTimeout || (getIrqStatus() & this->irqMap[RADIOLIB_IRQ_TIMEOUT])) {
312 0 : (void)finishReceive();
313 0 : return(RADIOLIB_ERR_RX_TIMEOUT);
314 : }
315 :
316 : // read the received data
317 0 : return(readData(data, len));
318 : }
319 :
320 0 : int16_t SX128x::transmitDirect(uint32_t frf) {
321 : // set RF switch (if present)
322 0 : this->mod->setRfSwitchState(Module::MODE_TX);
323 :
324 : // user requested to start transmitting immediately (required for RTTY)
325 0 : int16_t state = RADIOLIB_ERR_NONE;
326 0 : if(frf != 0) {
327 0 : state = setRfFrequency(frf);
328 : }
329 0 : RADIOLIB_ASSERT(state);
330 :
331 : // start transmitting
332 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_TX_CONTINUOUS_WAVE, NULL, 0));
333 : }
334 :
335 0 : int16_t SX128x::receiveDirect() {
336 : // set RF switch (if present)
337 0 : this->mod->setRfSwitchState(Module::MODE_RX);
338 :
339 : // SX128x is unable to output received data directly
340 0 : return(RADIOLIB_ERR_UNKNOWN);
341 : }
342 :
343 0 : int16_t SX128x::scanChannel() {
344 0 : ChannelScanConfig_t cfg = {
345 : .cad = {
346 : .symNum = RADIOLIB_SX128X_CAD_PARAM_DEFAULT,
347 : .detPeak = 0,
348 : .detMin = 0,
349 : .exitMode = 0,
350 : .timeout = 0,
351 : .irqFlags = RADIOLIB_IRQ_CAD_DEFAULT_FLAGS,
352 : .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK,
353 : },
354 : };
355 0 : return(this->scanChannel(cfg));
356 : }
357 :
358 0 : int16_t SX128x::scanChannel(const ChannelScanConfig_t &config) {
359 : // set mode to CAD
360 0 : int16_t state = startChannelScan(config);
361 0 : RADIOLIB_ASSERT(state);
362 :
363 : // wait for channel activity detected or timeout
364 0 : while(!this->mod->hal->digitalRead(this->mod->getIrq())) {
365 0 : this->mod->hal->yield();
366 : }
367 :
368 : // check CAD result
369 0 : return(getChannelScanResult());
370 : }
371 :
372 0 : int16_t SX128x::sleep() {
373 0 : return(SX128x::sleep(true));
374 : }
375 :
376 0 : int16_t SX128x::sleep(bool retainConfig) {
377 : // set RF switch (if present)
378 0 : this->mod->setRfSwitchState(Module::MODE_IDLE);
379 :
380 0 : uint8_t sleepConfig = RADIOLIB_SX128X_SLEEP_DATA_BUFFER_RETAIN | RADIOLIB_SX128X_SLEEP_DATA_RAM_RETAIN;
381 0 : if(!retainConfig) {
382 0 : sleepConfig = RADIOLIB_SX128X_SLEEP_DATA_BUFFER_FLUSH | RADIOLIB_SX128X_SLEEP_DATA_RAM_FLUSH;
383 : }
384 0 : int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SAVE_CONTEXT, 0, 1, false, false);
385 0 : RADIOLIB_ASSERT(state);
386 0 : state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_SLEEP, &sleepConfig, 1, false, false);
387 :
388 : // wait for SX128x to safely enter sleep mode
389 0 : this->mod->hal->delay(1);
390 :
391 0 : return(state);
392 : }
393 :
394 0 : int16_t SX128x::standby() {
395 0 : return(SX128x::standby(RADIOLIB_SX128X_STANDBY_RC));
396 : }
397 :
398 0 : int16_t SX128x::standby(uint8_t mode, bool wakeup) {
399 : // set RF switch (if present)
400 0 : this->mod->setRfSwitchState(Module::MODE_IDLE);
401 :
402 0 : if(wakeup) {
403 : // send a NOP command - this pulls the NSS low to exit the sleep mode,
404 : // while preventing interference with possible other SPI transactions
405 0 : (void)this->mod->SPIwriteStream((uint16_t)RADIOLIB_SX128X_CMD_NOP, NULL, 0, false, false);
406 : }
407 :
408 0 : const uint8_t data[] = { mode };
409 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_STANDBY, data, 1));
410 : }
411 :
412 0 : void SX128x::setDio1Action(void (*func)(void)) {
413 0 : this->mod->hal->attachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()), func, this->mod->hal->GpioInterruptRising);
414 0 : }
415 :
416 0 : void SX128x::clearDio1Action() {
417 0 : this->mod->hal->detachInterrupt(this->mod->hal->pinToInterrupt(this->mod->getIrq()));
418 0 : }
419 :
420 0 : void SX128x::setPacketReceivedAction(void (*func)(void)) {
421 0 : this->setDio1Action(func);
422 0 : }
423 :
424 0 : void SX128x::clearPacketReceivedAction() {
425 0 : this->clearDio1Action();
426 0 : }
427 :
428 0 : void SX128x::setPacketSentAction(void (*func)(void)) {
429 0 : this->setDio1Action(func);
430 0 : }
431 :
432 0 : void SX128x::clearPacketSentAction() {
433 0 : this->clearDio1Action();
434 0 : }
435 :
436 0 : int16_t SX128x::finishTransmit() {
437 : // clear interrupt flags
438 0 : clearIrqStatus();
439 :
440 : // set mode to standby to disable transmitter/RF switch
441 0 : return(standby());
442 : }
443 :
444 0 : int16_t SX128x::startReceive() {
445 0 : return(this->startReceive(RADIOLIB_SX128X_RX_TIMEOUT_INF, RADIOLIB_IRQ_RX_DEFAULT_FLAGS, RADIOLIB_IRQ_RX_DEFAULT_MASK, 0));
446 : }
447 :
448 0 : int16_t SX128x::readData(uint8_t* data, size_t len) {
449 : // check active modem
450 0 : if(getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_RANGING) {
451 0 : return(RADIOLIB_ERR_WRONG_MODEM);
452 : }
453 :
454 : // set mode to standby
455 0 : int16_t state = standby();
456 0 : RADIOLIB_ASSERT(state);
457 :
458 : // check integrity CRC
459 0 : uint16_t irq = getIrqStatus();
460 0 : int16_t crcState = RADIOLIB_ERR_NONE;
461 : // Report CRC mismatch when there's a payload CRC error, or a header error and no valid header (to avoid false alarm from previous packet)
462 0 : if((irq & RADIOLIB_SX128X_IRQ_CRC_ERROR) || ((irq & RADIOLIB_SX128X_IRQ_HEADER_ERROR) && !(irq & RADIOLIB_SX128X_IRQ_HEADER_VALID))) {
463 0 : crcState = RADIOLIB_ERR_CRC_MISMATCH;
464 : }
465 :
466 : // get packet length and Rx buffer offset
467 0 : uint8_t offset = 0;
468 0 : size_t length = getPacketLength(true, &offset);
469 0 : if((len != 0) && (len < length)) {
470 : // user requested less data than we got, only return what was requested
471 0 : length = len;
472 : }
473 :
474 : // read packet data starting at offset
475 0 : state = readBuffer(data, length, offset);
476 0 : RADIOLIB_ASSERT(state);
477 :
478 : // clear interrupt flags
479 0 : state = clearIrqStatus();
480 :
481 : // check if CRC failed - this is done after reading data to give user the option to keep them
482 0 : RADIOLIB_ASSERT(crcState);
483 :
484 0 : return(state);
485 : }
486 :
487 0 : int16_t SX128x::finishReceive() {
488 : // set mode to standby to disable RF switch
489 0 : int16_t state = standby();
490 0 : RADIOLIB_ASSERT(state);
491 :
492 : // clear interrupt flags
493 0 : return(clearIrqStatus());
494 : }
495 :
496 0 : uint32_t SX128x::getIrqFlags() {
497 0 : return((uint32_t)this->getIrqStatus());
498 : }
499 :
500 0 : int16_t SX128x::setIrqFlags(uint32_t irq) {
501 0 : return(this->setDioIrqParams(irq, irq));
502 : }
503 :
504 0 : int16_t SX128x::clearIrqFlags(uint32_t irq) {
505 0 : return(this->clearIrqStatus(irq));
506 : }
507 :
508 0 : int16_t SX128x::startChannelScan() {
509 0 : ChannelScanConfig_t cfg = {
510 : .cad = {
511 : .symNum = RADIOLIB_SX128X_CAD_PARAM_DEFAULT,
512 : .detPeak = 0,
513 : .detMin = 0,
514 : .exitMode = 0,
515 : .timeout = 0,
516 : .irqFlags = RADIOLIB_IRQ_CAD_DEFAULT_FLAGS,
517 : .irqMask = RADIOLIB_IRQ_CAD_DEFAULT_MASK,
518 : },
519 : };
520 0 : return(this->startChannelScan(cfg));
521 : }
522 :
523 0 : int16_t SX128x::startChannelScan(const ChannelScanConfig_t &config) {
524 : // check active modem
525 0 : if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) {
526 0 : return(RADIOLIB_ERR_WRONG_MODEM);
527 : }
528 :
529 : // set mode to standby
530 0 : int16_t state = standby();
531 0 : RADIOLIB_ASSERT(state);
532 :
533 : // set DIO pin mapping
534 0 : state = setDioIrqParams(getIrqMapped(config.cad.irqFlags), getIrqMapped(config.cad.irqMask));
535 0 : RADIOLIB_ASSERT(state);
536 :
537 : // clear interrupt flags
538 0 : state = clearIrqStatus();
539 0 : RADIOLIB_ASSERT(state);
540 :
541 : // set RF switch (if present)
542 0 : this->mod->setRfSwitchState(Module::MODE_RX);
543 :
544 : // set mode to CAD
545 0 : return(setCad(config.cad.symNum));
546 : }
547 :
548 0 : int16_t SX128x::getChannelScanResult() {
549 : // check active modem
550 0 : if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) {
551 0 : return(RADIOLIB_ERR_WRONG_MODEM);
552 : }
553 :
554 : // check CAD result
555 0 : uint16_t cadResult = getIrqStatus();
556 0 : int16_t state = RADIOLIB_ERR_UNKNOWN;
557 0 : if(cadResult & RADIOLIB_SX128X_IRQ_CAD_DETECTED) {
558 : // detected some LoRa activity
559 0 : state = RADIOLIB_LORA_DETECTED;
560 0 : } else if(cadResult & RADIOLIB_SX128X_IRQ_CAD_DONE) {
561 : // channel is free
562 0 : state = RADIOLIB_CHANNEL_FREE;
563 : }
564 :
565 0 : clearIrqStatus();
566 0 : return(state);
567 : }
568 :
569 0 : int16_t SX128x::setFrequency(float freq) {
570 0 : RADIOLIB_CHECK_RANGE(freq, 2400.0f, 2500.0f, RADIOLIB_ERR_INVALID_FREQUENCY);
571 :
572 : // calculate raw value
573 0 : uint32_t frf = (freq * (uint32_t(1) << RADIOLIB_SX128X_DIV_EXPONENT)) / RADIOLIB_SX128X_CRYSTAL_FREQ;
574 0 : return(setRfFrequency(frf));
575 : }
576 :
577 0 : int16_t SX128x::setBandwidth(float bw) {
578 : // check active modem
579 0 : uint8_t modem = getPacketType();
580 0 : if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) {
581 : // check range for LoRa
582 0 : RADIOLIB_CHECK_RANGE(bw, 203.125f, 1625.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
583 0 : } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING) {
584 : // check range for ranging
585 0 : RADIOLIB_CHECK_RANGE(bw, 406.25f, 1625.0f, RADIOLIB_ERR_INVALID_BANDWIDTH);
586 : } else {
587 0 : return(RADIOLIB_ERR_WRONG_MODEM);
588 : }
589 :
590 0 : if(fabsf(bw - 203.125f) <= 0.001f) {
591 0 : this->bandwidth = RADIOLIB_SX128X_LORA_BW_203_125;
592 0 : } else if(fabsf(bw - 406.25f) <= 0.001f) {
593 0 : this->bandwidth = RADIOLIB_SX128X_LORA_BW_406_25;
594 0 : } else if(fabsf(bw - 812.5f) <= 0.001f) {
595 0 : this->bandwidth = RADIOLIB_SX128X_LORA_BW_812_50;
596 0 : } else if(fabsf(bw - 1625.0f) <= 0.001f) {
597 0 : this->bandwidth = RADIOLIB_SX128X_LORA_BW_1625_00;
598 : } else {
599 0 : return(RADIOLIB_ERR_INVALID_BANDWIDTH);
600 : }
601 :
602 : // update modulation parameters
603 0 : this->bandwidthKhz = bw;
604 0 : return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRateLoRa));
605 : }
606 :
607 0 : int16_t SX128x::setSpreadingFactor(uint8_t sf) {
608 : // check active modem
609 0 : uint8_t modem = getPacketType();
610 0 : if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) {
611 : // check range for LoRa
612 0 : RADIOLIB_CHECK_RANGE(sf, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
613 0 : } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING) {
614 : // check range for ranging
615 0 : RADIOLIB_CHECK_RANGE(sf, 5, 10, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
616 : } else {
617 0 : return(RADIOLIB_ERR_WRONG_MODEM);
618 : }
619 :
620 : // update modulation parameters
621 0 : this->spreadingFactor = sf << 4;
622 0 : int16_t state = setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRateLoRa);
623 0 : RADIOLIB_ASSERT(state);
624 :
625 : // update mystery register in LoRa mode - SX1280 datasheet rev 3.2 section 14.4.1
626 0 : if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) {
627 0 : uint8_t data = 0;
628 0 : if((this->spreadingFactor == RADIOLIB_SX128X_LORA_SF_5) || (this->spreadingFactor == RADIOLIB_SX128X_LORA_SF_6)) {
629 0 : data = 0x1E;
630 0 : } else if((this->spreadingFactor == RADIOLIB_SX128X_LORA_SF_7) || (this->spreadingFactor == RADIOLIB_SX128X_LORA_SF_8)) {
631 0 : data = 0x37;
632 : } else {
633 0 : data = 0x32;
634 : }
635 0 : state = SX128x::writeRegister(RADIOLIB_SX128X_REG_LORA_SF_CONFIG, &data, 1);
636 0 : RADIOLIB_ASSERT(state);
637 :
638 : // this register must also be updated for some reason
639 0 : state = SX128x::readRegister(RADIOLIB_SX128X_REG_FREQ_ERROR_CORRECTION, &data, 1);
640 0 : RADIOLIB_ASSERT(state);
641 :
642 0 : data |= 0x01;
643 0 : state = SX128x::writeRegister(RADIOLIB_SX128X_REG_FREQ_ERROR_CORRECTION, &data, 1);
644 0 : RADIOLIB_ASSERT(state);
645 : }
646 :
647 0 : return(state);
648 : }
649 :
650 0 : int16_t SX128x::setCodingRate(uint8_t cr, bool longInterleaving) {
651 : // check active modem
652 0 : uint8_t modem = getPacketType();
653 :
654 : // LoRa/ranging
655 0 : if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) {
656 0 : RADIOLIB_CHECK_RANGE(cr, 4, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
657 :
658 : // update modulation parameters
659 0 : if(longInterleaving && (modem == RADIOLIB_SX128X_PACKET_TYPE_LORA)) {
660 0 : switch(cr) {
661 0 : case 4:
662 0 : this->codingRateLoRa = 0;
663 0 : break;
664 0 : case 5:
665 : case 6:
666 0 : this->codingRateLoRa = cr;
667 0 : break;
668 0 : case 8:
669 0 : this->codingRateLoRa = cr - 1;
670 0 : break;
671 0 : default:
672 0 : return(RADIOLIB_ERR_INVALID_CODING_RATE);
673 : }
674 : } else {
675 0 : this->codingRateLoRa = cr - 4;
676 : }
677 0 : return(setModulationParams(this->spreadingFactor, this->bandwidth, this->codingRateLoRa));
678 :
679 : // FLRC
680 0 : } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC) {
681 0 : RADIOLIB_CHECK_RANGE(cr, 2, 4, RADIOLIB_ERR_INVALID_CODING_RATE);
682 :
683 : // update modulation parameters
684 0 : this->codingRateFLRC = (cr - 2) * 2;
685 0 : return(setModulationParams(this->bitRate, this->codingRateFLRC, this->shaping));
686 : }
687 :
688 0 : return(RADIOLIB_ERR_WRONG_MODEM);
689 : }
690 :
691 0 : int16_t SX128x::setOutputPower(int8_t pwr) {
692 : // check if power value is configurable
693 0 : int16_t state = checkOutputPower(pwr, NULL);
694 0 : RADIOLIB_ASSERT(state);
695 :
696 0 : this->power = pwr + 18;
697 0 : return(setTxParams(this->power));
698 : }
699 :
700 0 : int16_t SX128x::checkOutputPower(int8_t pwr, int8_t* clipped) {
701 0 : if(clipped) {
702 0 : *clipped = RADIOLIB_MAX(-18, RADIOLIB_MIN(13, pwr));
703 : }
704 0 : RADIOLIB_CHECK_RANGE(pwr, -18, 13, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
705 0 : return(RADIOLIB_ERR_NONE);
706 : }
707 :
708 0 : int16_t SX128x::setModem(ModemType_t modem) {
709 0 : switch(modem) {
710 0 : case(ModemType_t::RADIOLIB_MODEM_LORA): {
711 0 : return(this->begin());
712 : } break;
713 0 : case(ModemType_t::RADIOLIB_MODEM_FSK): {
714 0 : return(this->beginGFSK());
715 : } break;
716 0 : default:
717 0 : return(RADIOLIB_ERR_WRONG_MODEM);
718 : }
719 : }
720 :
721 0 : int16_t SX128x::getModem(ModemType_t* modem) {
722 0 : RADIOLIB_ASSERT_PTR(modem);
723 :
724 0 : switch(getPacketType()) {
725 0 : case(RADIOLIB_SX128X_PACKET_TYPE_LORA):
726 0 : *modem = ModemType_t::RADIOLIB_MODEM_LORA;
727 0 : return(RADIOLIB_ERR_NONE);
728 0 : case(RADIOLIB_SX128X_PACKET_TYPE_GFSK):
729 0 : *modem = ModemType_t::RADIOLIB_MODEM_FSK;
730 0 : return(RADIOLIB_ERR_NONE);
731 : }
732 :
733 0 : return(RADIOLIB_ERR_WRONG_MODEM);
734 : }
735 :
736 0 : int16_t SX128x::setPreambleLength(size_t preambleLength) {
737 0 : uint8_t modem = getPacketType();
738 0 : if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) {
739 : // LoRa or ranging
740 : // the actual limit is 491520, however, some platforms (notably AVR) limit size_t to 16 bits
741 0 : RADIOLIB_CHECK_RANGE(preambleLength, 2, 65534, RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH);
742 :
743 : // check preamble length is even - no point even trying odd numbers
744 0 : if(preambleLength % 2 != 0) {
745 0 : return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH);
746 : }
747 :
748 : // calculate exponent and mantissa values (use the next longer preamble if there's no exact match)
749 0 : uint8_t e = 1;
750 0 : uint8_t m = 1;
751 0 : uint32_t len = 0;
752 0 : for(; e <= 15; e++) {
753 0 : for(m = 1; m <= 15; m++) {
754 0 : len = m * (uint32_t(1) << e);
755 0 : if(len >= preambleLength) {
756 0 : break;
757 : }
758 : }
759 0 : if(len >= preambleLength) {
760 0 : break;
761 : }
762 : }
763 :
764 : // update packet parameters
765 0 : this->preambleLengthLoRa = (e << 4) | m;
766 0 : return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled));
767 :
768 0 : } else if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC)) {
769 : // GFSK or FLRC
770 0 : RADIOLIB_CHECK_RANGE(preambleLength, 4, 32, RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH);
771 :
772 : // check preamble length is multiple of 4
773 0 : if(preambleLength % 4 != 0) {
774 0 : return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH);
775 : }
776 :
777 : // update packet parameters
778 0 : this->preambleLengthGFSK = ((preambleLength / 4) - 1) << 4;
779 0 : return(setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, this->packetType));
780 : }
781 :
782 0 : return(RADIOLIB_ERR_WRONG_MODEM);
783 : }
784 :
785 0 : int16_t SX128x::setDataRate(DataRate_t dr, ModemType_t modem) {
786 : // get the current modem
787 : ModemType_t currentModem;
788 0 : int16_t state = this->getModem(¤tModem);
789 0 : RADIOLIB_ASSERT(state);
790 :
791 : // switch over if the requested modem is different
792 0 : if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) {
793 0 : state = this->standby();
794 0 : RADIOLIB_ASSERT(state);
795 0 : state = this->setModem(modem);
796 0 : RADIOLIB_ASSERT(state);
797 : }
798 :
799 0 : if(modem == RADIOLIB_MODEM_NONE) {
800 0 : modem = currentModem;
801 : }
802 :
803 : // select interpretation based on modem
804 0 : if (modem == RADIOLIB_MODEM_LORA) {
805 0 : state = this->setBandwidth(dr.lora.bandwidth);
806 0 : RADIOLIB_ASSERT(state);
807 0 : state = this->setSpreadingFactor(dr.lora.spreadingFactor);
808 0 : RADIOLIB_ASSERT(state);
809 0 : state = this->setCodingRate(dr.lora.codingRate);
810 : } else {
811 0 : return(RADIOLIB_ERR_WRONG_MODEM);
812 : }
813 0 : return(state);
814 : }
815 :
816 0 : int16_t SX128x::setBitRate(float br) {
817 : // check active modem
818 0 : uint8_t modem = getPacketType();
819 :
820 : // GFSK/BLE
821 0 : if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE)) {
822 0 : if((uint16_t)br == 125) {
823 0 : this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_125_BW_0_3;
824 0 : } else if((uint16_t)br == 250) {
825 0 : this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_250_BW_0_6;
826 0 : } else if((uint16_t)br == 400) {
827 0 : this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_400_BW_1_2;
828 0 : } else if((uint16_t)br == 500) {
829 0 : this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_500_BW_1_2;
830 0 : } else if((uint16_t)br == 800) {
831 0 : this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_800_BW_2_4;
832 0 : } else if((uint16_t)br == 1000) {
833 0 : this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_1_000_BW_2_4;
834 0 : } else if((uint16_t)br == 1600) {
835 0 : this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_1_600_BW_2_4;
836 0 : } else if((uint16_t)br == 2000) {
837 0 : this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_2_000_BW_2_4;
838 : } else {
839 0 : return(RADIOLIB_ERR_INVALID_BIT_RATE);
840 : }
841 :
842 : // update modulation parameters
843 0 : this->bitRateKbps = (uint16_t)br;
844 0 : return(setModulationParams(this->bitRate, this->modIndex, this->shaping));
845 :
846 : // FLRC
847 0 : } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC) {
848 0 : if((uint16_t)br == 260) {
849 0 : this->bitRate = RADIOLIB_SX128X_FLRC_BR_0_260_BW_0_3;
850 0 : } else if((uint16_t)br == 325) {
851 0 : this->bitRate = RADIOLIB_SX128X_FLRC_BR_0_325_BW_0_3;
852 0 : } else if((uint16_t)br == 520) {
853 0 : this->bitRate = RADIOLIB_SX128X_FLRC_BR_0_520_BW_0_6;
854 0 : } else if((uint16_t)br == 650) {
855 0 : this->bitRate = RADIOLIB_SX128X_FLRC_BR_0_650_BW_0_6;
856 0 : } else if((uint16_t)br == 1000) {
857 0 : this->bitRate = RADIOLIB_SX128X_FLRC_BR_1_000_BW_1_2;
858 0 : } else if((uint16_t)br == 1300) {
859 0 : this->bitRate = RADIOLIB_SX128X_FLRC_BR_1_300_BW_1_2;
860 : } else {
861 0 : return(RADIOLIB_ERR_INVALID_BIT_RATE);
862 : }
863 :
864 : // update modulation parameters
865 0 : this->bitRateKbps = (uint16_t)br;
866 0 : return(setModulationParams(this->bitRate, this->codingRateFLRC, this->shaping));
867 :
868 : }
869 :
870 0 : return(RADIOLIB_ERR_WRONG_MODEM);
871 : }
872 :
873 0 : int16_t SX128x::setFrequencyDeviation(float freqDev) {
874 : // check active modem
875 0 : uint8_t modem = getPacketType();
876 0 : if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE))) {
877 0 : return(RADIOLIB_ERR_WRONG_MODEM);
878 : }
879 :
880 : // set frequency deviation to lowest available setting (required for digimodes)
881 0 : float newFreqDev = freqDev;
882 0 : if(freqDev < 0.0f) {
883 0 : newFreqDev = 62.5f;
884 : }
885 :
886 0 : RADIOLIB_CHECK_RANGE(newFreqDev, 62.5f, 1000.0f, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
887 :
888 : // override for the lowest possible frequency deviation - required for some PhysicalLayer protocols
889 0 : if(newFreqDev == 0.0f) {
890 0 : this->modIndex = RADIOLIB_SX128X_BLE_GFSK_MOD_IND_0_35;
891 0 : this->bitRate = RADIOLIB_SX128X_BLE_GFSK_BR_0_125_BW_0_3;
892 0 : return(setModulationParams(this->bitRate, this->modIndex, this->shaping));
893 : }
894 :
895 : // update modulation parameters
896 0 : uint8_t modInd = (uint8_t)((8.0f * (newFreqDev / (float)this->bitRateKbps)) - 1.0f);
897 0 : if(modInd > RADIOLIB_SX128X_BLE_GFSK_MOD_IND_4_00) {
898 0 : return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS);
899 : }
900 :
901 : // update modulation parameters
902 0 : this->frequencyDev = newFreqDev;
903 0 : this->modIndex = modInd;
904 0 : return(setModulationParams(this->bitRate, this->modIndex, this->shaping));
905 : }
906 :
907 0 : int16_t SX128x::setDataShaping(uint8_t sh) {
908 : // check active modem
909 0 : uint8_t modem = getPacketType();
910 0 : if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC))) {
911 0 : return(RADIOLIB_ERR_WRONG_MODEM);
912 : }
913 :
914 : // set data this->shaping
915 0 : switch(sh) {
916 0 : case RADIOLIB_SHAPING_NONE:
917 0 : this->shaping = RADIOLIB_SX128X_BLE_GFSK_BT_OFF;
918 0 : break;
919 0 : case RADIOLIB_SHAPING_0_5:
920 0 : this->shaping = RADIOLIB_SX128X_BLE_GFSK_BT_0_5;
921 0 : break;
922 0 : case RADIOLIB_SHAPING_1_0:
923 0 : this->shaping = RADIOLIB_SX128X_BLE_GFSK_BT_1_0;
924 0 : break;
925 0 : default:
926 0 : return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
927 : }
928 :
929 : // update modulation parameters
930 0 : if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE)) {
931 0 : return(setModulationParams(this->bitRate, this->modIndex, this->shaping));
932 : } else {
933 0 : return(setModulationParams(this->bitRate, this->codingRateFLRC, this->shaping));
934 : }
935 : }
936 :
937 0 : int16_t SX128x::setSyncWord(const uint8_t* syncWord, uint8_t len) {
938 : // check active modem
939 0 : uint8_t modem = getPacketType();
940 0 : if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC))) {
941 0 : return(RADIOLIB_ERR_WRONG_MODEM);
942 : }
943 :
944 0 : if(modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) {
945 : // GFSK can use up to 5 bytes as sync word
946 0 : if(len > 5) {
947 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
948 : }
949 :
950 : // calculate sync word length parameter value
951 0 : if(len > 0) {
952 0 : this->syncWordLen = (len - 1)*2;
953 : }
954 :
955 : } else {
956 : // FLRC requires 32-bit sync word
957 0 : if(!((len == 0) || (len == 4))) {
958 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
959 : }
960 :
961 : // save sync word length parameter value
962 0 : this->syncWordLen = len;
963 : }
964 :
965 : // update sync word
966 0 : int16_t state = SX128x::writeRegister(RADIOLIB_SX128X_REG_SYNC_WORD_1_BYTE_4 + (5 - len), const_cast<uint8_t*>(syncWord), len);
967 0 : RADIOLIB_ASSERT(state);
968 :
969 : // update packet parameters
970 0 : if(this->syncWordLen == 0) {
971 0 : this->syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_OFF;
972 : } else {
973 : /// \todo add support for multiple sync words
974 0 : this->syncWordMatch = RADIOLIB_SX128X_GFSK_FLRC_SYNC_WORD_1;
975 : }
976 0 : return(setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, this->packetType));
977 : }
978 :
979 0 : int16_t SX128x::setSyncWord(uint8_t syncWord, uint8_t controlBits) {
980 : // check active modem
981 0 : if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) {
982 0 : return(RADIOLIB_ERR_WRONG_MODEM);
983 : }
984 :
985 : // update register
986 0 : const uint8_t data[2] = {(uint8_t)((syncWord & 0xF0) | ((controlBits & 0xF0) >> 4)), (uint8_t)(((syncWord & 0x0F) << 4) | (controlBits & 0x0F))};
987 0 : return(writeRegister(RADIOLIB_SX128X_REG_LORA_SYNC_WORD_MSB, data, 2));
988 : }
989 :
990 0 : int16_t SX128x::setCRC(uint8_t len, uint32_t initial, uint16_t polynomial) {
991 : // check active modem
992 0 : uint8_t modem = getPacketType();
993 :
994 : int16_t state;
995 0 : if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC)) {
996 : // update packet parameters
997 0 : if(modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) {
998 0 : if(len > 2) {
999 0 : return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
1000 : }
1001 : } else {
1002 0 : if(len > 3) {
1003 0 : return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
1004 : }
1005 : }
1006 0 : this->crcGFSK = len << 4;
1007 0 : state = setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, this->packetType);
1008 0 : RADIOLIB_ASSERT(state);
1009 :
1010 : // set initial CRC value
1011 0 : uint8_t data[] = { (uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF) };
1012 0 : state = writeRegister(RADIOLIB_SX128X_REG_CRC_INITIAL_MSB, data, 2);
1013 0 : RADIOLIB_ASSERT(state);
1014 :
1015 : // set CRC polynomial
1016 0 : data[0] = (uint8_t)((polynomial >> 8) & 0xFF);
1017 0 : data[1] = (uint8_t)(polynomial & 0xFF);
1018 0 : state = writeRegister(RADIOLIB_SX128X_REG_CRC_POLYNOMIAL_MSB, data, 2);
1019 0 : return(state);
1020 :
1021 0 : } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) {
1022 : // update packet parameters
1023 0 : if(len == 0) {
1024 0 : this->crcBLE = RADIOLIB_SX128X_BLE_CRC_OFF;
1025 0 : } else if(len == 3) {
1026 0 : this->crcBLE = RADIOLIB_SX128X_BLE_CRC_3_BYTE;
1027 : } else {
1028 0 : return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
1029 : }
1030 0 : state = setPacketParamsBLE(this->connectionState, this->crcBLE, this->bleTestPayload, this->whitening);
1031 0 : RADIOLIB_ASSERT(state);
1032 :
1033 : // set initial CRC value
1034 0 : const uint8_t data[] = { (uint8_t)((initial >> 16) & 0xFF), (uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF) };
1035 0 : state = writeRegister(RADIOLIB_SX128X_REG_BLE_CRC_INITIAL_MSB, data, 3);
1036 0 : return(state);
1037 :
1038 0 : } else if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) {
1039 : // update packet parameters
1040 0 : if(len == 0) {
1041 0 : this->crcLoRa = RADIOLIB_SX128X_LORA_CRC_OFF;
1042 0 : } else if(len == 2) {
1043 0 : this->crcLoRa = RADIOLIB_SX128X_LORA_CRC_ON;
1044 : } else {
1045 0 : return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
1046 : }
1047 0 : state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled);
1048 0 : return(state);
1049 : }
1050 :
1051 0 : return(RADIOLIB_ERR_UNKNOWN);
1052 : }
1053 :
1054 0 : int16_t SX128x::setWhitening(bool enabled) {
1055 : // check active modem
1056 0 : uint8_t modem = getPacketType();
1057 0 : if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_BLE))) {
1058 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1059 : }
1060 :
1061 : // update packet parameters
1062 0 : if(enabled) {
1063 0 : this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_ON;
1064 : } else {
1065 0 : this->whitening = RADIOLIB_SX128X_GFSK_BLE_WHITENING_OFF;
1066 : }
1067 :
1068 0 : if(modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) {
1069 0 : return(setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, this->packetType));
1070 : }
1071 0 : return(setPacketParamsBLE(this->connectionState, this->crcBLE, this->bleTestPayload, this->whitening));
1072 : }
1073 :
1074 0 : int16_t SX128x::setAccessAddress(uint32_t addr) {
1075 : // check active modem
1076 0 : if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_BLE) {
1077 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1078 : }
1079 :
1080 : // set the address
1081 0 : const uint8_t addrBuff[] = { (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) };
1082 0 : return(SX128x::writeRegister(RADIOLIB_SX128X_REG_ACCESS_ADDRESS_BYTE_3, addrBuff, 4));
1083 : }
1084 :
1085 0 : int16_t SX128x::setHighSensitivityMode(bool enable) {
1086 : // read the current registers
1087 0 : uint8_t RxGain = 0;
1088 0 : int16_t state = readRegister(RADIOLIB_SX128X_REG_GAIN_MODE, &RxGain, 1);
1089 0 : RADIOLIB_ASSERT(state);
1090 :
1091 0 : if(enable) {
1092 0 : RxGain |= 0xC0; // Set bits 6 and 7
1093 : } else {
1094 0 : RxGain &= ~0xC0; // Unset bits 6 and 7
1095 : }
1096 :
1097 : // update all values
1098 0 : state = writeRegister(RADIOLIB_SX128X_REG_GAIN_MODE, &RxGain, 1);
1099 0 : return(state);
1100 : }
1101 :
1102 0 : int16_t SX128x::setGainControl(uint8_t gain) {
1103 : // read the current registers
1104 0 : uint8_t ManualGainSetting = 0;
1105 0 : int16_t state = readRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_2, &ManualGainSetting, 1);
1106 0 : RADIOLIB_ASSERT(state);
1107 0 : uint8_t LNAGainValue = 0;
1108 0 : state = readRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_SETTING, &LNAGainValue, 1);
1109 0 : RADIOLIB_ASSERT(state);
1110 0 : uint8_t LNAGainControl = 0;
1111 0 : state = readRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_1, &LNAGainControl, 1);
1112 0 : RADIOLIB_ASSERT(state);
1113 :
1114 : // set the gain
1115 0 : if (gain > 0 && gain < 14) {
1116 : // Set manual gain
1117 0 : ManualGainSetting &= ~0x01; // Set bit 0 to 0 (Enable Manual Gain Control)
1118 0 : LNAGainValue &= 0xF0; // Bits 0, 1, 2 and 3 to 0
1119 0 : LNAGainValue |= gain; // Set bits 0, 1, 2 and 3 to Manual Gain Setting (1-13)
1120 0 : LNAGainControl |= 0x80; // Set bit 7 to 1 (Enable Manual Gain Control)
1121 : } else {
1122 : // Set automatic gain if 0 or out of range
1123 0 : ManualGainSetting |= 0x01; // Set bit 0 to 1 (Enable Automatic Gain Control)
1124 0 : LNAGainValue &= 0xF0; // Bits 0, 1, 2 and 3 to 0
1125 0 : LNAGainValue |= 0x0A; // Set bits 0, 1, 2 and 3 to Manual Gain Setting (1-13)
1126 0 : LNAGainControl &= ~0x80; // Set bit 7 to 0 (Enable Automatic Gain Control)
1127 : }
1128 :
1129 : // update all values
1130 0 : state = writeRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_2, &ManualGainSetting, 1);
1131 0 : RADIOLIB_ASSERT(state);
1132 0 : state = writeRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_SETTING, &LNAGainValue, 1);
1133 0 : RADIOLIB_ASSERT(state);
1134 0 : state = writeRegister(RADIOLIB_SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_1, &LNAGainControl, 1);
1135 0 : return(state);
1136 : }
1137 :
1138 0 : float SX128x::getRSSI() {
1139 : // get packet status
1140 : uint8_t packetStatus[5];
1141 0 : this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_PACKET_STATUS, packetStatus, 5);
1142 :
1143 : // check active modem
1144 0 : uint8_t modem = getPacketType();
1145 0 : if((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING)) {
1146 : // LoRa or ranging
1147 0 : uint8_t rssiSync = packetStatus[0];
1148 0 : float rssiMeasured = -1.0 * rssiSync/2.0;
1149 0 : float snr = getSNR();
1150 0 : if(snr <= 0.0f) {
1151 0 : return(rssiMeasured - snr);
1152 : } else {
1153 0 : return(rssiMeasured);
1154 : }
1155 : } else {
1156 : // GFSK, BLE or FLRC
1157 0 : uint8_t rssiSync = packetStatus[1];
1158 0 : return(-1.0 * rssiSync/2.0);
1159 : }
1160 : }
1161 :
1162 0 : float SX128x::getRSSI(bool packet) {
1163 0 : if (!packet) {
1164 : // get instantaneous RSSI value
1165 0 : uint8_t data[3] = {0, 0, 0}; // RssiInst, Status, RFU
1166 0 : this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_RSSI_INST, data, 3);
1167 0 : return ((float)data[0] / (-2.0f));
1168 : } else {
1169 0 : return this->getRSSI();
1170 : }
1171 : }
1172 :
1173 0 : float SX128x::getSNR() {
1174 : // check active modem
1175 0 : uint8_t modem = getPacketType();
1176 0 : if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING))) {
1177 0 : return(0.0);
1178 : }
1179 :
1180 : // get packet status
1181 : uint8_t packetStatus[5];
1182 0 : this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_PACKET_STATUS, packetStatus, 5);
1183 :
1184 : // calculate real SNR
1185 0 : uint8_t snr = packetStatus[1];
1186 0 : if(snr < 128) {
1187 0 : return(snr/4.0);
1188 : } else {
1189 0 : return((snr - 256)/4.0f);
1190 : }
1191 : }
1192 :
1193 0 : float SX128x::getFrequencyError() {
1194 : // check active modem
1195 0 : uint8_t modem = getPacketType();
1196 0 : if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING))) {
1197 0 : return(0.0);
1198 : }
1199 :
1200 : // read the raw frequency error register values
1201 0 : uint8_t efeRaw[3] = {0};
1202 0 : int16_t state = readRegister(RADIOLIB_SX128X_REG_FEI_MSB, &efeRaw[0], 1);
1203 0 : RADIOLIB_ASSERT(state);
1204 0 : state = readRegister(RADIOLIB_SX128X_REG_FEI_MID, &efeRaw[1], 1);
1205 0 : RADIOLIB_ASSERT(state);
1206 0 : state = readRegister(RADIOLIB_SX128X_REG_FEI_LSB, &efeRaw[2], 1);
1207 0 : RADIOLIB_ASSERT(state);
1208 0 : uint32_t efe = ((uint32_t) efeRaw[0] << 16) | ((uint32_t) efeRaw[1] << 8) | efeRaw[2];
1209 0 : efe &= 0x0FFFFF;
1210 :
1211 0 : float error = 0;
1212 :
1213 : // check the first bit
1214 0 : if (efe & 0x80000) {
1215 : // frequency error is negative
1216 0 : efe |= (uint32_t) 0xFFF00000;
1217 0 : efe = ~efe + 1;
1218 0 : error = 1.55f * (float) efe / (1600.0f / this->bandwidthKhz) * -1.0f;
1219 : } else {
1220 0 : error = 1.55f * (float) efe / (1600.0f / this->bandwidthKhz);
1221 : }
1222 :
1223 0 : return(error);
1224 : }
1225 :
1226 0 : size_t SX128x::getPacketLength(bool update) {
1227 0 : return(this->getPacketLength(update, NULL));
1228 : }
1229 :
1230 0 : size_t SX128x::getPacketLength(bool update, uint8_t* offset) {
1231 : (void)update;
1232 :
1233 : // in implicit mode, return the cached value
1234 0 : if((getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_LORA) && (this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT)) {
1235 0 : return(this->payloadLen);
1236 : }
1237 :
1238 0 : uint8_t rxBufStatus[2] = {0, 0};
1239 0 : this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2);
1240 :
1241 0 : if(offset) { *offset = rxBufStatus[1]; }
1242 :
1243 0 : return((size_t)rxBufStatus[0]);
1244 : }
1245 :
1246 0 : int16_t SX128x::getLoRaRxHeaderInfo(uint8_t* cr, bool* hasCRC) {
1247 0 : int16_t state = RADIOLIB_ERR_NONE;
1248 :
1249 : // check if in explicit header mode
1250 0 : if(this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) {
1251 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1252 : }
1253 :
1254 0 : if(cr) { *cr = this->mod->SPIgetRegValue(RADIOLIB_SX128X_REG_LORA_RX_CODING_RATE, 6, 4) >> 4; }
1255 0 : if(hasCRC) { *hasCRC = (this->mod->SPIgetRegValue(RADIOLIB_SX128X_REG_FEI_MSB, 4, 4) != 0); }
1256 :
1257 0 : return(state);
1258 : }
1259 :
1260 0 : int16_t SX128x::fixedPacketLengthMode(uint8_t len) {
1261 0 : return(setPacketMode(RADIOLIB_SX128X_GFSK_FLRC_PACKET_FIXED, len));
1262 : }
1263 :
1264 0 : int16_t SX128x::variablePacketLengthMode(uint8_t maxLen) {
1265 0 : return(setPacketMode(RADIOLIB_SX128X_GFSK_FLRC_PACKET_VARIABLE, maxLen));
1266 : }
1267 :
1268 10 : RadioLibTime_t SX128x::calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) {
1269 10 : switch(modem) {
1270 6 : case (ModemType_t::RADIOLIB_MODEM_LORA): {
1271 : // calculate number of symbols
1272 6 : float N_symbol = 0;
1273 6 : uint8_t sf = dr.lora.spreadingFactor;
1274 6 : float cr = (float)dr.lora.codingRate;
1275 :
1276 : // get SF coefficients
1277 6 : float coeff1 = 0;
1278 6 : int16_t coeff2 = 0;
1279 6 : int16_t coeff3 = 0;
1280 6 : if(sf < 7) {
1281 : // SF5, SF6
1282 3 : coeff1 = 6.25;
1283 3 : coeff2 = 4*sf;
1284 3 : coeff3 = 4*sf;
1285 3 : } else if(sf < 11) {
1286 : // SF7. SF8, SF9, SF10
1287 0 : coeff1 = 4.25;
1288 0 : coeff2 = 4*sf + 8;
1289 0 : coeff3 = 4*sf;
1290 : } else {
1291 : // SF11, SF12
1292 3 : coeff1 = 4.25;
1293 3 : coeff2 = 4*sf + 8;
1294 3 : coeff3 = 4*(sf - 2);
1295 : }
1296 :
1297 : // get CRC length
1298 6 : int16_t N_bitCRC = 16;
1299 6 : if(!pc.lora.crcEnabled) {
1300 0 : N_bitCRC = 0;
1301 : }
1302 :
1303 : // get header length
1304 6 : int16_t N_symbolHeader = 20;
1305 6 : if(pc.lora.implicitHeader) {
1306 0 : N_symbolHeader = 0;
1307 : }
1308 :
1309 : // calculate number of LoRa preamble symbols
1310 6 : uint32_t N_symbolPreamble = pc.lora.preambleLength;
1311 :
1312 : // calculate the number of symbols
1313 6 : N_symbol = (float)N_symbolPreamble + coeff1 + 8.0f + ceilf((float)RADIOLIB_MAX((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * cr;
1314 :
1315 : // get time-on-air in us
1316 6 : return(((uint32_t(1) << sf) / dr.lora.bandwidth) * N_symbol * 1000.0f);
1317 : }
1318 4 : case (ModemType_t::RADIOLIB_MODEM_FSK):
1319 4 : return((((float)(pc.fsk.crcLength * 8) + pc.fsk.syncWordLength + pc.fsk.preambleLength + (uint32_t)len * 8) / (dr.fsk.bitRate / 1000.0f)));
1320 :
1321 0 : default:
1322 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1323 : }
1324 :
1325 : }
1326 :
1327 0 : RadioLibTime_t SX128x::getTimeOnAir(size_t len) {
1328 : // check active modem
1329 0 : uint8_t modem = getPacketType();
1330 0 : DataRate_t dr = {};
1331 0 : PacketConfig_t pc = {};
1332 :
1333 0 : if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) {
1334 0 : uint8_t sf = this->spreadingFactor >> 4;
1335 0 : uint8_t cr = this->codingRateLoRa;
1336 : // We assume same calculation for short and long interleaving, so map CR values 0-4 and 5-7 to the same values
1337 0 : if (cr < 5) {
1338 0 : cr = cr + 4;
1339 0 : } else if (cr == 7) {
1340 0 : cr = cr + 1;
1341 : }
1342 :
1343 0 : dr.lora.spreadingFactor = sf;
1344 0 : dr.lora.codingRate = cr;
1345 0 : dr.lora.bandwidth = this->bandwidthKhz;
1346 :
1347 0 : uint16_t preambleLength = (this->preambleLengthLoRa & 0x0F) * (uint32_t(1) << ((this->preambleLengthLoRa & 0xF0) >> 4));
1348 :
1349 0 : pc.lora.preambleLength = preambleLength;
1350 0 : pc.lora.implicitHeader = this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT;
1351 0 : pc.lora.crcEnabled = this->crcLoRa == RADIOLIB_SX128X_LORA_CRC_ON;
1352 0 : pc.lora.ldrOptimize = false;
1353 :
1354 0 : return(calculateTimeOnAir(ModemType_t::RADIOLIB_MODEM_LORA, dr, pc, len));
1355 0 : } else if (modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) {
1356 0 : dr.fsk.bitRate = (float)this->bitRateKbps;
1357 0 : dr.fsk.freqDev = this->frequencyDev;
1358 :
1359 0 : pc.fsk.preambleLength = ((uint16_t)this->preambleLengthGFSK >> 2) + 4;
1360 0 : pc.fsk.syncWordLength = ((this->syncWordLen >> 1) + 1) * 8;
1361 0 : pc.fsk.crcLength = this->crcGFSK >> 4;
1362 :
1363 0 : return(calculateTimeOnAir(ModemType_t::RADIOLIB_MODEM_FSK, dr, pc, len));
1364 : } else {
1365 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1366 : }
1367 :
1368 : }
1369 :
1370 0 : int16_t SX128x::implicitHeader(size_t len) {
1371 0 : return(setHeaderType(RADIOLIB_SX128X_LORA_HEADER_IMPLICIT, len));
1372 : }
1373 :
1374 0 : int16_t SX128x::explicitHeader() {
1375 0 : return(setHeaderType(RADIOLIB_SX128X_LORA_HEADER_EXPLICIT));
1376 : }
1377 :
1378 0 : int16_t SX128x::setEncoding(uint8_t encoding) {
1379 0 : return(setWhitening(encoding));
1380 : }
1381 :
1382 0 : void SX128x::setRfSwitchPins(uint32_t rxEn, uint32_t txEn) {
1383 0 : this->mod->setRfSwitchPins(rxEn, txEn);
1384 0 : }
1385 :
1386 0 : void SX128x::setRfSwitchTable(const uint32_t (&pins)[Module::RFSWITCH_MAX_PINS], const Module::RfSwitchMode_t table[]) {
1387 0 : this->mod->setRfSwitchTable(pins, table);
1388 0 : }
1389 :
1390 0 : uint8_t SX128x::randomByte() {
1391 : // it's unclear whether SX128x can measure RSSI while not receiving a packet
1392 : // this method is implemented only for PhysicalLayer compatibility
1393 0 : return(0);
1394 : }
1395 :
1396 0 : int16_t SX128x::invertIQ(bool enable) {
1397 0 : if(getPacketType() != RADIOLIB_SX128X_PACKET_TYPE_LORA) {
1398 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1399 : }
1400 :
1401 0 : if(enable) {
1402 0 : this->invertIQEnabled = RADIOLIB_SX128X_LORA_IQ_INVERTED;
1403 : } else {
1404 0 : this->invertIQEnabled = RADIOLIB_SX128X_LORA_IQ_STANDARD;
1405 : }
1406 :
1407 0 : return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled));
1408 : }
1409 :
1410 0 : int16_t SX128x::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) {
1411 : int16_t state;
1412 :
1413 0 : switch(mode) {
1414 0 : case(RADIOLIB_RADIO_MODE_RX): {
1415 : // in implicit header mode, use the provided length if it is nonzero
1416 : // otherwise we trust the user has previously set the payload length manually
1417 0 : if((this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) && (cfg->receive.len != 0)) {
1418 0 : this->payloadLen = cfg->receive.len;
1419 : }
1420 :
1421 : // check active modem
1422 0 : if(getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_RANGING) {
1423 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1424 : }
1425 :
1426 : // set DIO mapping
1427 0 : if(cfg->receive.timeout != RADIOLIB_SX128X_RX_TIMEOUT_INF) {
1428 0 : cfg->receive.irqMask |= (1UL << RADIOLIB_IRQ_TIMEOUT);
1429 : }
1430 :
1431 0 : state = setDioIrqParams(getIrqMapped(cfg->receive.irqFlags), getIrqMapped(cfg->receive.irqMask));
1432 0 : RADIOLIB_ASSERT(state);
1433 :
1434 : // set buffer pointers
1435 0 : state = setBufferBaseAddress();
1436 0 : RADIOLIB_ASSERT(state);
1437 :
1438 : // clear interrupt flags
1439 0 : state = clearIrqStatus();
1440 0 : RADIOLIB_ASSERT(state);
1441 :
1442 : // set implicit mode and expected len if applicable
1443 0 : if((this->headerType == RADIOLIB_SX128X_LORA_HEADER_IMPLICIT) && (getPacketType() == RADIOLIB_SX128X_PACKET_TYPE_LORA)) {
1444 0 : state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled);
1445 0 : RADIOLIB_ASSERT(state);
1446 : }
1447 : // if max(uint32_t) is used, revert to RxContinuous
1448 0 : if(cfg->receive.timeout == 0xFFFFFFFF) {
1449 0 : cfg->receive.timeout = 0xFFFF;
1450 : }
1451 0 : this->rxTimeout = cfg->receive.timeout;
1452 0 : } break;
1453 :
1454 0 : case(RADIOLIB_RADIO_MODE_TX): {
1455 : // check packet length
1456 0 : if(cfg->transmit.len > RADIOLIB_SX128X_MAX_PACKET_LENGTH) {
1457 0 : return(RADIOLIB_ERR_PACKET_TOO_LONG);
1458 : }
1459 :
1460 : // set packet Length
1461 0 : uint8_t modem = getPacketType();
1462 0 : if(modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) {
1463 0 : state = setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, cfg->transmit.len, this->crcLoRa, this->invertIQEnabled);
1464 0 : } else if((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC)) {
1465 0 : state = setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, this->packetType, cfg->transmit.len);
1466 0 : } else if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) {
1467 0 : state = setPacketParamsBLE(this->connectionState, this->crcBLE, this->bleTestPayload, this->whitening);
1468 : } else {
1469 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1470 : }
1471 0 : RADIOLIB_ASSERT(state);
1472 :
1473 : // update output power
1474 0 : state = setTxParams(this->power);
1475 0 : RADIOLIB_ASSERT(state);
1476 :
1477 : // set buffer pointers
1478 0 : state = setBufferBaseAddress();
1479 0 : RADIOLIB_ASSERT(state);
1480 :
1481 : // write packet to buffer
1482 0 : if(modem == RADIOLIB_SX128X_PACKET_TYPE_BLE) {
1483 : // first 2 bytes of BLE payload are PDU header
1484 0 : state = writeBuffer(cfg->transmit.data, cfg->transmit.len, 2);
1485 0 : RADIOLIB_ASSERT(state);
1486 : } else {
1487 0 : state = writeBuffer(cfg->transmit.data, cfg->transmit.len);
1488 0 : RADIOLIB_ASSERT(state);
1489 : }
1490 :
1491 : // set DIO mapping
1492 0 : state = setDioIrqParams(RADIOLIB_SX128X_IRQ_TX_DONE | RADIOLIB_SX128X_IRQ_RX_TX_TIMEOUT, RADIOLIB_SX128X_IRQ_TX_DONE);
1493 0 : RADIOLIB_ASSERT(state);
1494 :
1495 : // clear interrupt flags
1496 0 : state = clearIrqStatus();
1497 0 : RADIOLIB_ASSERT(state);
1498 0 : } break;
1499 :
1500 0 : default:
1501 0 : return(RADIOLIB_ERR_UNSUPPORTED);
1502 : }
1503 :
1504 0 : this->stagedMode = mode;
1505 0 : return(state);
1506 : }
1507 :
1508 0 : int16_t SX128x::launchMode() {
1509 : int16_t state;
1510 0 : switch(this->stagedMode) {
1511 0 : case(RADIOLIB_RADIO_MODE_RX): {
1512 0 : this->mod->setRfSwitchState(Module::MODE_RX);
1513 0 : state = setRx(this->rxTimeout);
1514 0 : RADIOLIB_ASSERT(state);
1515 0 : } break;
1516 :
1517 0 : case(RADIOLIB_RADIO_MODE_TX): {
1518 0 : this->mod->setRfSwitchState(Module::MODE_TX);
1519 0 : state = setTx(RADIOLIB_SX128X_TX_TIMEOUT_NONE);
1520 0 : RADIOLIB_ASSERT(state);
1521 :
1522 : // wait for BUSY to go low (= PA ramp up done)
1523 0 : while(this->mod->hal->digitalRead(this->mod->getGpio())) {
1524 0 : this->mod->hal->yield();
1525 : }
1526 0 : } break;
1527 :
1528 0 : default:
1529 0 : return(RADIOLIB_ERR_UNSUPPORTED);
1530 : }
1531 :
1532 0 : this->stagedMode = RADIOLIB_RADIO_MODE_NONE;
1533 0 : return(state);
1534 : }
1535 :
1536 : #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE
1537 0 : void SX128x::setDirectAction(void (*func)(void)) {
1538 : // SX128x is unable to perform direct mode reception
1539 : // this method is implemented only for PhysicalLayer compatibility
1540 : (void)func;
1541 0 : }
1542 :
1543 0 : void SX128x::readBit(uint32_t pin) {
1544 : // SX128x is unable to perform direct mode reception
1545 : // this method is implemented only for PhysicalLayer compatibility
1546 : (void)pin;
1547 0 : }
1548 : #endif
1549 :
1550 0 : Module* SX128x::getMod() {
1551 0 : return(this->mod);
1552 : }
1553 :
1554 0 : int16_t SX128x::modSetup(uint8_t modem) {
1555 : // set module properties
1556 0 : this->mod->init();
1557 0 : this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput);
1558 0 : this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput);
1559 0 : this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_ADDR] = Module::BITS_16;
1560 0 : this->mod->spiConfig.widths[RADIOLIB_MODULE_SPI_WIDTH_CMD] = Module::BITS_8;
1561 0 : this->mod->spiConfig.statusPos = 1;
1562 0 : this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_READ] = RADIOLIB_SX128X_CMD_READ_REGISTER;
1563 0 : this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_WRITE] = RADIOLIB_SX128X_CMD_WRITE_REGISTER;
1564 0 : this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_NOP] = RADIOLIB_SX128X_CMD_NOP;
1565 0 : this->mod->spiConfig.cmds[RADIOLIB_MODULE_SPI_COMMAND_STATUS] = RADIOLIB_SX128X_CMD_GET_STATUS;
1566 0 : this->mod->spiConfig.stream = true;
1567 0 : this->mod->spiConfig.parseStatusCb = SPIparseStatus;
1568 :
1569 : // find the chip - this will also reset the module and verify the module
1570 0 : if(!SX128x::findChip(this->chipType)) {
1571 : RADIOLIB_DEBUG_BASIC_PRINTLN("No SX128x found!");
1572 0 : this->mod->term();
1573 0 : return(RADIOLIB_ERR_CHIP_NOT_FOUND);
1574 : }
1575 : RADIOLIB_DEBUG_BASIC_PRINTLN("M\tSX128x");
1576 :
1577 : // configure settings not accessible by API
1578 0 : return(config(modem));
1579 : }
1580 :
1581 0 : uint8_t SX128x::getStatus() {
1582 0 : uint8_t data = 0;
1583 0 : this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_STATUS, &data, 0);
1584 0 : return(data);
1585 : }
1586 :
1587 0 : int16_t SX128x::writeRegister(uint16_t addr, const uint8_t* data, uint8_t numBytes) {
1588 0 : this->mod->SPIwriteRegisterBurst(addr, data, numBytes);
1589 0 : return(RADIOLIB_ERR_NONE);
1590 : }
1591 :
1592 0 : int16_t SX128x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) {
1593 : // send the command
1594 0 : this->mod->SPIreadRegisterBurst(addr, numBytes, data);
1595 :
1596 : // check the status
1597 0 : int16_t state = this->mod->SPIcheckStream();
1598 0 : return(state);
1599 : }
1600 :
1601 0 : int16_t SX128x::writeBuffer(const uint8_t* data, uint8_t numBytes, uint8_t offset) {
1602 0 : const uint8_t cmd[] = { RADIOLIB_SX128X_CMD_WRITE_BUFFER, offset };
1603 0 : return(this->mod->SPIwriteStream(cmd, 2, data, numBytes));
1604 : }
1605 :
1606 0 : int16_t SX128x::readBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) {
1607 0 : const uint8_t cmd[] = { RADIOLIB_SX128X_CMD_READ_BUFFER, offset };
1608 0 : return(this->mod->SPIreadStream(cmd, 2, data, numBytes));
1609 : }
1610 :
1611 0 : int16_t SX128x::setTx(uint16_t periodBaseCount, uint8_t periodBase) {
1612 0 : const uint8_t data[] = { periodBase, (uint8_t)((periodBaseCount >> 8) & 0xFF), (uint8_t)(periodBaseCount & 0xFF) };
1613 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_TX, data, 3));
1614 : }
1615 :
1616 0 : int16_t SX128x::setRx(uint16_t periodBaseCount, uint8_t periodBase) {
1617 0 : const uint8_t data[] = { periodBase, (uint8_t)((periodBaseCount >> 8) & 0xFF), (uint8_t)(periodBaseCount & 0xFF) };
1618 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RX, data, 3));
1619 : }
1620 :
1621 0 : int16_t SX128x::setCad(uint8_t symbolNum) {
1622 : // configure parameters
1623 0 : int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_CAD_PARAMS, &symbolNum, 1);
1624 0 : RADIOLIB_ASSERT(state);
1625 :
1626 : // start CAD
1627 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_CAD, NULL, 0));
1628 : }
1629 :
1630 0 : uint8_t SX128x::getPacketType() {
1631 0 : uint8_t data = 0xFF;
1632 0 : this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_PACKET_TYPE, &data, 1);
1633 0 : return(data);
1634 : }
1635 :
1636 0 : int16_t SX128x::setRfFrequency(uint32_t frf) {
1637 0 : const uint8_t data[] = { (uint8_t)((frf >> 16) & 0xFF), (uint8_t)((frf >> 8) & 0xFF), (uint8_t)(frf & 0xFF) };
1638 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RF_FREQUENCY, data, 3));
1639 : }
1640 :
1641 0 : int16_t SX128x::setTxParams(uint8_t pwr, uint8_t rampTime) {
1642 0 : const uint8_t data[] = { pwr, rampTime };
1643 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_TX_PARAMS, data, 2));
1644 : }
1645 :
1646 0 : int16_t SX128x::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) {
1647 0 : const uint8_t data[] = { txBaseAddress, rxBaseAddress };
1648 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2));
1649 : }
1650 :
1651 0 : int16_t SX128x::setModulationParams(uint8_t modParam1, uint8_t modParam2, uint8_t modParam3) {
1652 0 : const uint8_t data[] = { modParam1, modParam2, modParam3 };
1653 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_MODULATION_PARAMS, data, 3));
1654 : }
1655 :
1656 0 : int16_t SX128x::setPacketParamsGFSK(uint8_t preambleLen, uint8_t syncLen, uint8_t syncMatch, uint8_t crcLen, uint8_t whiten, uint8_t hdrType, uint8_t payLen) {
1657 0 : const uint8_t data[] = { preambleLen, syncLen, syncMatch, hdrType, payLen, crcLen, whiten };
1658 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7));
1659 : }
1660 :
1661 0 : int16_t SX128x::setPacketParamsBLE(uint8_t connState, uint8_t crcLen, uint8_t bleTest, uint8_t whiten) {
1662 0 : const uint8_t data[] = { connState, crcLen, bleTest, whiten, 0x00, 0x00, 0x00 };
1663 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7));
1664 : }
1665 :
1666 0 : int16_t SX128x::setPacketParamsLoRa(uint8_t preambleLen, uint8_t hdrType, uint8_t payLen, uint8_t crc, uint8_t invIQ) {
1667 0 : const uint8_t data[] = { preambleLen, hdrType, payLen, crc, invIQ, 0x00, 0x00 };
1668 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_PARAMS, data, 7));
1669 : }
1670 :
1671 0 : int16_t SX128x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) {
1672 0 : const uint8_t data[] = { (uint8_t)((irqMask >> 8) & 0xFF), (uint8_t)(irqMask & 0xFF),
1673 0 : (uint8_t)((dio1Mask >> 8) & 0xFF), (uint8_t)(dio1Mask & 0xFF),
1674 0 : (uint8_t)((dio2Mask >> 8) & 0xFF), (uint8_t)(dio2Mask & 0xFF),
1675 0 : (uint8_t)((dio3Mask >> 8) & 0xFF), (uint8_t)(dio3Mask & 0xFF) };
1676 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_DIO_IRQ_PARAMS, data, 8));
1677 : }
1678 :
1679 0 : uint16_t SX128x::getIrqStatus() {
1680 0 : uint8_t data[] = { 0x00, 0x00 };
1681 0 : this->mod->SPIreadStream(RADIOLIB_SX128X_CMD_GET_IRQ_STATUS, data, 2);
1682 0 : return(((uint16_t)(data[0]) << 8) | data[1]);
1683 : }
1684 :
1685 0 : int16_t SX128x::clearIrqStatus(uint16_t clearIrqParams) {
1686 0 : const uint8_t data[] = { (uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF) };
1687 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_CLEAR_IRQ_STATUS, data, 2));
1688 : }
1689 :
1690 0 : int16_t SX128x::setRangingRole(uint8_t role) {
1691 0 : const uint8_t data[] = { role };
1692 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_RANGING_ROLE, data, 1));
1693 : }
1694 :
1695 0 : int16_t SX128x::setPacketType(uint8_t type) {
1696 0 : const uint8_t data[] = { type };
1697 0 : return(this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_TYPE, data, 1));
1698 : }
1699 :
1700 0 : int16_t SX128x::setPacketMode(uint8_t mode, uint8_t len) {
1701 : // check active modem
1702 0 : uint8_t modem = getPacketType();
1703 0 : if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_GFSK) || (modem == RADIOLIB_SX128X_PACKET_TYPE_FLRC))) {
1704 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1705 : }
1706 :
1707 : // set requested packet mode
1708 0 : int16_t state = setPacketParamsGFSK(this->preambleLengthGFSK, this->syncWordLen, this->syncWordMatch, this->crcGFSK, this->whitening, mode, len);
1709 0 : RADIOLIB_ASSERT(state);
1710 :
1711 : // update cached value
1712 0 : this->packetType = mode;
1713 0 : return(state);
1714 : }
1715 :
1716 0 : int16_t SX128x::setHeaderType(uint8_t hdrType, size_t len) {
1717 : // check active modem
1718 0 : uint8_t modem = getPacketType();
1719 0 : if(!((modem == RADIOLIB_SX128X_PACKET_TYPE_LORA) || (modem == RADIOLIB_SX128X_PACKET_TYPE_RANGING))) {
1720 0 : return(RADIOLIB_ERR_WRONG_MODEM);
1721 : }
1722 :
1723 : // update packet parameters
1724 0 : this->headerType = hdrType;
1725 0 : this->payloadLen = len;
1726 0 : return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->payloadLen, this->crcLoRa, this->invertIQEnabled));
1727 : }
1728 :
1729 0 : int16_t SX128x::config(uint8_t modem) {
1730 : // reset buffer base address
1731 0 : int16_t state = setBufferBaseAddress();
1732 0 : RADIOLIB_ASSERT(state);
1733 :
1734 : // set modem
1735 : uint8_t data[1];
1736 0 : data[0] = modem;
1737 0 : state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_PACKET_TYPE, data, 1);
1738 0 : RADIOLIB_ASSERT(state);
1739 :
1740 : // set CAD parameters
1741 0 : data[0] = RADIOLIB_SX128X_CAD_ON_8_SYMB;
1742 0 : state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_CAD_PARAMS, data, 1);
1743 0 : RADIOLIB_ASSERT(state);
1744 :
1745 : // set regulator mode to DC-DC
1746 0 : data[0] = RADIOLIB_SX128X_REGULATOR_DC_DC;
1747 0 : state = this->mod->SPIwriteStream(RADIOLIB_SX128X_CMD_SET_REGULATOR_MODE, data, 1);
1748 0 : RADIOLIB_ASSERT(state);
1749 :
1750 0 : return(RADIOLIB_ERR_NONE);
1751 : }
1752 :
1753 0 : int16_t SX128x::SPIparseStatus(uint8_t in) {
1754 0 : if((in & 0b00011100) == RADIOLIB_SX128X_STATUS_CMD_TIMEOUT) {
1755 0 : return(RADIOLIB_ERR_SPI_CMD_TIMEOUT);
1756 0 : } else if((in & 0b00011100) == RADIOLIB_SX128X_STATUS_CMD_ERROR) {
1757 0 : return(RADIOLIB_ERR_SPI_CMD_INVALID);
1758 0 : } else if((in & 0b00011100) == RADIOLIB_SX128X_STATUS_CMD_FAILED) {
1759 0 : return(RADIOLIB_ERR_SPI_CMD_FAILED);
1760 0 : } else if((in == 0x00) || (in == 0xFF)) {
1761 0 : return(RADIOLIB_ERR_CHIP_NOT_FOUND);
1762 : }
1763 0 : return(RADIOLIB_ERR_NONE);
1764 : }
1765 :
1766 0 : bool SX128x::findChip(const char* verStr) {
1767 0 : uint8_t i = 0;
1768 0 : bool flagFound = false;
1769 0 : while((i < 10) && !flagFound) {
1770 : // reset the module
1771 0 : reset(true);
1772 :
1773 : // read the version string
1774 0 : char version[16] = { 0 };
1775 0 : this->mod->SPIreadRegisterBurst(RADIOLIB_SX128X_REG_VERSION_STRING, 16, reinterpret_cast<uint8_t*>(version));
1776 :
1777 : // check version register
1778 0 : if(strncmp(verStr, version, 6) == 0) {
1779 : RADIOLIB_DEBUG_BASIC_PRINTLN("Found SX128x: RADIOLIB_SX128X_REG_VERSION_STRING:");
1780 : RADIOLIB_DEBUG_BASIC_HEXDUMP(reinterpret_cast<uint8_t*>(version), 16, RADIOLIB_SX128X_REG_VERSION_STRING);
1781 : RADIOLIB_DEBUG_BASIC_PRINTLN();
1782 0 : flagFound = true;
1783 : } else {
1784 : #if RADIOLIB_DEBUG_BASIC
1785 : RADIOLIB_DEBUG_BASIC_PRINTLN("SX128x not found! (%d of 10 tries) RADIOLIB_SX128X_REG_VERSION_STRING:", i + 1);
1786 : RADIOLIB_DEBUG_BASIC_HEXDUMP(reinterpret_cast<uint8_t*>(version), 16, RADIOLIB_SX128X_REG_VERSION_STRING);
1787 : RADIOLIB_DEBUG_BASIC_PRINTLN("Expected string: %s", verStr);
1788 : #endif
1789 0 : this->mod->hal->delay(10);
1790 0 : i++;
1791 : }
1792 : }
1793 :
1794 0 : return(flagFound);
1795 : }
1796 :
1797 : #endif
|