Line data Source code
1 : #include "PhysicalLayer.h"
2 :
3 : #include <string.h>
4 :
5 71 : PhysicalLayer::PhysicalLayer() {
6 71 : this->freqStep = 1;
7 71 : this->maxPacketLength = 1;
8 : #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE
9 71 : this->bufferBitPos = 0;
10 71 : this->bufferWritePos = 0;
11 : #endif
12 71 : }
13 :
14 : #if defined(RADIOLIB_BUILD_ARDUINO)
15 : int16_t PhysicalLayer::transmit(__FlashStringHelper* fstr, uint8_t addr) {
16 : // read flash string length
17 : size_t len = 0;
18 : PGM_P p = reinterpret_cast<PGM_P>(fstr);
19 : while(true) {
20 : char c = RADIOLIB_NONVOLATILE_READ_BYTE(p++);
21 : len++;
22 : if(c == '\0') {
23 : break;
24 : }
25 : }
26 :
27 : // dynamically allocate memory
28 : #if RADIOLIB_STATIC_ONLY
29 : char str[RADIOLIB_STATIC_ARRAY_SIZE];
30 : #else
31 : char* str = new char[len];
32 : #endif
33 :
34 : // copy string from flash
35 : p = reinterpret_cast<PGM_P>(fstr);
36 : for(size_t i = 0; i < len; i++) {
37 : str[i] = RADIOLIB_NONVOLATILE_READ_BYTE(p + i);
38 : }
39 :
40 : // transmit string
41 : int16_t state = transmit(str, addr);
42 : #if !RADIOLIB_STATIC_ONLY
43 : delete[] str;
44 : #endif
45 : return(state);
46 : }
47 :
48 : int16_t PhysicalLayer::transmit(String& str, uint8_t addr) {
49 : return(transmit(str.c_str(), addr));
50 : }
51 : #endif
52 :
53 0 : int16_t PhysicalLayer::transmit(const char* str, uint8_t addr) {
54 0 : return(transmit(reinterpret_cast<uint8_t*>(const_cast<char*>(str)), strlen(str), addr));
55 : }
56 :
57 0 : int16_t PhysicalLayer::transmit(const uint8_t* data, size_t len, uint8_t addr) {
58 : (void)data;
59 : (void)len;
60 : (void)addr;
61 0 : return(RADIOLIB_ERR_UNSUPPORTED);
62 : }
63 :
64 : #if defined(RADIOLIB_BUILD_ARDUINO)
65 : int16_t PhysicalLayer::receive(String& str, size_t len, RadioLibTime_t timeout) {
66 : int16_t state = RADIOLIB_ERR_NONE;
67 :
68 : // user can override the length of data to read
69 : size_t length = len;
70 :
71 : // build a temporary buffer
72 : #if RADIOLIB_STATIC_ONLY
73 : uint8_t data[RADIOLIB_STATIC_ARRAY_SIZE + 1];
74 : #else
75 : uint8_t* data = NULL;
76 : if(length == 0) {
77 : data = new uint8_t[this->maxPacketLength + 1];
78 : } else {
79 : data = new uint8_t[length + 1];
80 : }
81 : RADIOLIB_ASSERT_PTR(data);
82 : #endif
83 :
84 : // attempt packet reception
85 : state = receive(data, length, timeout);
86 :
87 : // any of the following leads to at least some data being available
88 : // let's leave the decision of whether to keep it or not up to the user
89 : if((state == RADIOLIB_ERR_NONE) || (state == RADIOLIB_ERR_CRC_MISMATCH) || (state == RADIOLIB_ERR_LORA_HEADER_DAMAGED)) {
90 : // read the number of actually received bytes (for unknown packets)
91 : if(len == 0) {
92 : length = getPacketLength(false);
93 : }
94 :
95 : // add null terminator
96 : data[length] = 0;
97 :
98 : // initialize Arduino String class
99 : str = String(reinterpret_cast<char*>(data));
100 : }
101 :
102 : // deallocate temporary buffer
103 : #if !RADIOLIB_STATIC_ONLY
104 : delete[] data;
105 : #endif
106 :
107 : return(state);
108 : }
109 : #endif
110 :
111 0 : int16_t PhysicalLayer::receive(uint8_t* data, size_t len, RadioLibTime_t timeout) {
112 : (void)data;
113 : (void)len;
114 : (void)timeout;
115 0 : return(RADIOLIB_ERR_UNSUPPORTED);
116 : }
117 :
118 0 : int16_t PhysicalLayer::sleep() {
119 0 : return(RADIOLIB_ERR_UNSUPPORTED);
120 : }
121 :
122 0 : int16_t PhysicalLayer::standby() {
123 0 : return(standby(RADIOLIB_STANDBY_DEFAULT));
124 : }
125 :
126 0 : int16_t PhysicalLayer::standby(uint8_t mode) {
127 : (void)mode;
128 0 : return(RADIOLIB_ERR_UNSUPPORTED);
129 : }
130 :
131 0 : int16_t PhysicalLayer::startReceive() {
132 0 : return(RADIOLIB_ERR_UNSUPPORTED);
133 : }
134 :
135 34 : int16_t PhysicalLayer::startReceive(uint32_t timeout, RadioLibIrqFlags_t irqFlags, RadioLibIrqFlags_t irqMask, size_t len) {
136 34 : RadioModeConfig_t cfg = {
137 : .receive = {
138 : .timeout = timeout,
139 : .syncSymbols = 0,
140 : .irqFlags = irqFlags,
141 : .irqMask = irqMask,
142 : .len = len,
143 : }
144 34 : };
145 :
146 34 : int16_t state = this->stageMode(RADIOLIB_RADIO_MODE_RX, &cfg);
147 34 : RADIOLIB_ASSERT(state);
148 0 : return(this->launchMode());
149 : }
150 :
151 : #if defined(RADIOLIB_BUILD_ARDUINO)
152 : int16_t PhysicalLayer::startTransmit(String& str, uint8_t addr) {
153 : return(startTransmit(str.c_str(), addr));
154 : }
155 : #endif
156 :
157 0 : int16_t PhysicalLayer::startTransmit(const char* str, uint8_t addr) {
158 0 : return(startTransmit(reinterpret_cast<uint8_t*>(const_cast<char*>(str)), strlen(str), addr));
159 : }
160 :
161 17 : int16_t PhysicalLayer::startTransmit(const uint8_t* data, size_t len, uint8_t addr) {
162 17 : RadioModeConfig_t cfg = {
163 : .transmit = {
164 : .data = data,
165 : .len = len,
166 : .addr = addr,
167 : }
168 17 : };
169 :
170 17 : int16_t state = this->stageMode(RADIOLIB_RADIO_MODE_TX, &cfg);
171 17 : RADIOLIB_ASSERT(state);
172 0 : return(this->launchMode());
173 : }
174 :
175 11 : int16_t PhysicalLayer::finishTransmit() {
176 : // clear all interrupt flags
177 11 : int16_t state = clearIrqFlags(0xFFFFFFFFUL);
178 11 : RADIOLIB_ASSERT(state);
179 :
180 : // clear the Tx buffer
181 0 : state = clearTxBuffer();
182 0 : RADIOLIB_ASSERT(state);
183 :
184 : // set mode to standby to disable transmitter/RF switch
185 0 : return(standby());
186 : }
187 :
188 0 : int16_t PhysicalLayer::finishReceive() {
189 0 : return(RADIOLIB_ERR_UNSUPPORTED);
190 : }
191 :
192 : #if defined(RADIOLIB_BUILD_ARDUINO)
193 : int16_t PhysicalLayer::readData(String& str, size_t len) {
194 : int16_t state = RADIOLIB_ERR_NONE;
195 :
196 : // read the number of actually received bytes
197 : size_t length = getPacketLength();
198 :
199 : if((len < length) && (len != 0)) {
200 : // user requested less bytes than were received, this is allowed (but frowned upon)
201 : // requests for more data than were received will only return the number of actually received bytes (unlike PhysicalLayer::receive())
202 : length = len;
203 : }
204 :
205 : // build a temporary buffer
206 : #if RADIOLIB_STATIC_ONLY
207 : uint8_t data[RADIOLIB_STATIC_ARRAY_SIZE + 1];
208 : #else
209 : uint8_t* data = new uint8_t[length + 1];
210 : RADIOLIB_ASSERT_PTR(data);
211 : #endif
212 :
213 : // read the received data
214 : state = readData(data, length);
215 :
216 : // any of the following leads to at least some data being available
217 : // let's leave the decision of whether to keep it or not up to the user
218 : if((state == RADIOLIB_ERR_NONE) || (state == RADIOLIB_ERR_CRC_MISMATCH) || (state == RADIOLIB_ERR_LORA_HEADER_DAMAGED)) {
219 : // add null terminator
220 : data[length] = 0;
221 :
222 : // initialize Arduino String class
223 : str = String(reinterpret_cast<char*>(data));
224 : }
225 :
226 : // deallocate temporary buffer
227 : #if !RADIOLIB_STATIC_ONLY
228 : delete[] data;
229 : #endif
230 :
231 : return(state);
232 : }
233 : #endif
234 :
235 0 : int16_t PhysicalLayer::readData(uint8_t* data, size_t len) {
236 : (void)data;
237 : (void)len;
238 0 : return(RADIOLIB_ERR_UNSUPPORTED);
239 : }
240 :
241 0 : int16_t PhysicalLayer::transmitDirect(uint32_t frf) {
242 : (void)frf;
243 0 : return(RADIOLIB_ERR_UNSUPPORTED);
244 : }
245 :
246 0 : int16_t PhysicalLayer::receiveDirect() {
247 0 : return(RADIOLIB_ERR_UNSUPPORTED);
248 : }
249 :
250 0 : int16_t PhysicalLayer::setFrequency(uint32_t freq) {
251 : (void)freq;
252 0 : return(RADIOLIB_ERR_UNSUPPORTED);
253 : }
254 :
255 0 : int16_t PhysicalLayer::setBitRate(uint32_t br) {
256 : (void)br;
257 0 : return(RADIOLIB_ERR_UNSUPPORTED);
258 : }
259 :
260 0 : int16_t PhysicalLayer::setFrequencyDeviation(uint32_t freqDev) {
261 : (void)freqDev;
262 0 : return(RADIOLIB_ERR_UNSUPPORTED);
263 : }
264 :
265 0 : int16_t PhysicalLayer::setSpreadingFactor(uint8_t sf) {
266 : (void)sf;
267 0 : return(RADIOLIB_ERR_UNSUPPORTED);
268 : }
269 :
270 0 : int16_t PhysicalLayer::setBandwidth(uint32_t bw) {
271 : (void)bw;
272 0 : return(RADIOLIB_ERR_UNSUPPORTED);
273 : }
274 :
275 0 : int16_t PhysicalLayer::setCodingRate(uint8_t cr, bool longInterleave) {
276 : (void)cr;
277 : (void)longInterleave;
278 0 : return(RADIOLIB_ERR_UNSUPPORTED);
279 : }
280 :
281 0 : int16_t PhysicalLayer::setLrFhssConfig(uint8_t bw, uint8_t cr, bool narrowGrid, uint8_t hdrCount, uint16_t hopSeed) {
282 : (void)bw;
283 : (void)cr;
284 : (void)narrowGrid;
285 : (void)hdrCount;
286 : (void)hopSeed;
287 0 : return(RADIOLIB_ERR_UNSUPPORTED);
288 : }
289 :
290 0 : int16_t PhysicalLayer::setDataShaping(uint8_t sh) {
291 : (void)sh;
292 0 : return(RADIOLIB_ERR_UNSUPPORTED);
293 : }
294 :
295 0 : int16_t PhysicalLayer::setEncoding(uint8_t encoding) {
296 : (void)encoding;
297 0 : return(RADIOLIB_ERR_UNSUPPORTED);
298 : }
299 :
300 0 : int16_t PhysicalLayer::invertIQ(bool enable) {
301 : (void)enable;
302 0 : return(RADIOLIB_ERR_UNSUPPORTED);
303 : }
304 :
305 0 : int16_t PhysicalLayer::setOutputPower(int8_t power) {
306 : (void)power;
307 0 : return(RADIOLIB_ERR_UNSUPPORTED);
308 : }
309 :
310 0 : int16_t PhysicalLayer::setSyncWord(uint8_t* sync, size_t len) {
311 : (void)sync;
312 : (void)len;
313 0 : return(RADIOLIB_ERR_UNSUPPORTED);
314 : }
315 :
316 0 : int16_t PhysicalLayer::setPreambleLength(size_t len, size_t detLen) {
317 : (void)len;
318 : (void)detLen;
319 0 : return(RADIOLIB_ERR_UNSUPPORTED);
320 : }
321 :
322 17 : int16_t PhysicalLayer::setDataRate(DataRate_t dr, ModemType_t modem) {
323 : // get the current modem
324 : ModemType_t currentModem;
325 17 : int16_t state = this->getModem(¤tModem);
326 17 : RADIOLIB_ASSERT(state);
327 :
328 : // switch over if the requested modem is different
329 6 : if(modem != RADIOLIB_MODEM_NONE && modem != currentModem) {
330 0 : state = this->standby();
331 0 : RADIOLIB_ASSERT(state);
332 0 : state = this->setModem(modem);
333 0 : RADIOLIB_ASSERT(state);
334 : }
335 :
336 6 : if(modem == RADIOLIB_MODEM_NONE) {
337 6 : modem = currentModem;
338 : }
339 :
340 : // select interpretation based on modem
341 6 : if(modem == RADIOLIB_MODEM_FSK) {
342 : // set the bit rate
343 0 : state = this->setBitRate(dr.fsk.bitRate);
344 0 : RADIOLIB_ASSERT(state);
345 :
346 : // set the frequency deviation
347 0 : state = this->setFrequencyDeviation(dr.fsk.freqDev);
348 :
349 6 : } else if(modem == RADIOLIB_MODEM_LORA) {
350 : // set the spreading factor
351 6 : state = this->setSpreadingFactor(dr.lora.spreadingFactor);
352 6 : RADIOLIB_ASSERT(state);
353 :
354 : // set the bandwidth
355 0 : state = this->setBandwidth(dr.lora.bandwidth);
356 0 : RADIOLIB_ASSERT(state);
357 :
358 : // set the coding rate
359 0 : state = this->setCodingRate(dr.lora.codingRate);
360 :
361 0 : } else if(modem == RADIOLIB_MODEM_LRFHSS) {
362 : // set the basic config
363 0 : state = this->setLrFhssConfig(dr.lrFhss.bw, dr.lrFhss.cr, dr.lrFhss.narrowGrid);
364 : }
365 :
366 0 : return(state);
367 : }
368 :
369 0 : int16_t PhysicalLayer::checkDataRate(DataRate_t dr, ModemType_t modem) {
370 : (void)dr;
371 : (void)modem;
372 0 : return(RADIOLIB_ERR_UNSUPPORTED);
373 : }
374 :
375 0 : size_t PhysicalLayer::getPacketLength(bool update) {
376 : (void)update;
377 : // technically this should be returning some unsigned value, not a negative status code
378 : // however, 0 could be misinterpreted in this case
379 : // the value of RADIOLIB_ERR_UNSUPPORTED (-25) when converted to 32-bit unsigned int is 4294967271
380 : // that is conmfortably out of range for any possible packet length
381 0 : return((size_t)RADIOLIB_ERR_UNSUPPORTED);
382 : }
383 :
384 0 : float PhysicalLayer::getRSSI() {
385 0 : return(RADIOLIB_ERR_UNSUPPORTED);
386 : }
387 :
388 0 : float PhysicalLayer::getSNR() {
389 0 : return(RADIOLIB_ERR_UNSUPPORTED);
390 : }
391 :
392 38 : float PhysicalLayer::getNumSymbols(DataRate_t dr, PacketConfig_t pc, size_t len) {
393 38 : uint8_t sfCoeff1_x4 = 17; // (4.25 * 4)
394 38 : uint8_t sfCoeff2 = 8;
395 38 : if(dr.lora.spreadingFactor == 5 || dr.lora.spreadingFactor == 6) {
396 7 : sfCoeff1_x4 = 25; // 6.25 * 4
397 7 : sfCoeff2 = 0;
398 : }
399 38 : uint8_t sfDivisor = 4*dr.lora.spreadingFactor;
400 38 : if(pc.lora.ldrOptimize) {
401 14 : sfDivisor = 4*(dr.lora.spreadingFactor - 2);
402 : }
403 38 : const int8_t bitsPerCrc = 16;
404 38 : const int8_t N_symbol_header = pc.lora.implicitHeader ? 0 : 20;
405 :
406 : // numerator of equation in section 6.1.4 of SX1268 datasheet v1.1 (might not actually be bitcount, but it has len * 8)
407 38 : int16_t bitCount = (int16_t) 8 * len + pc.lora.crcEnabled * bitsPerCrc - 4 * dr.lora.spreadingFactor + sfCoeff2 + N_symbol_header;
408 38 : if(bitCount < 0) {
409 0 : bitCount = 0;
410 : }
411 :
412 : // add (sfDivisor) - 1 to the numerator to give integer CEIL(...)
413 38 : uint16_t nPreCodedSymbols = (bitCount + (sfDivisor - 1)) / (sfDivisor);
414 :
415 : // preamble can be 65k, therefore nSymbol_x4 needs to be 32 bit
416 38 : uint32_t nSymbol_x4 = (pc.lora.preambleLength + 8) * 4 + sfCoeff1_x4 + nPreCodedSymbols * dr.lora.codingRate * 4;
417 38 : return((float)nSymbol_x4 / 4.0f);
418 : }
419 :
420 62 : RadioLibTime_t PhysicalLayer::calculateTimeOnAir(ModemType_t modem, DataRate_t dr, PacketConfig_t pc, size_t len) {
421 : // check active modem
422 62 : if(modem == ModemType_t::RADIOLIB_MODEM_LORA) {
423 : // everything is in microseconds to allow integer arithmetic
424 : // some constants have .25, these are multiplied by 4, and have _x4 postfix to indicate that fact
425 32 : uint32_t symbolLength_us = (RADIOLIB_UNIT_MEGA(1) << dr.lora.spreadingFactor) / dr.lora.bandwidth;
426 32 : size_t nSymbol_x4 = PhysicalLayer::getNumSymbols(dr, pc, len) * 4;
427 32 : return((symbolLength_us * nSymbol_x4) / 4);
428 :
429 30 : } else if(modem == ModemType_t::RADIOLIB_MODEM_FSK) {
430 16 : size_t num_bits = ((uint32_t)pc.fsk.crcLength * 8UL) + (uint32_t)pc.fsk.syncWordLength + (uint32_t)pc.fsk.preambleLength + ((uint32_t)len * 8UL);
431 16 : return((num_bits * RADIOLIB_UNIT_MEGA(1)) / dr.fsk.bitRate);
432 :
433 14 : } else if(modem == ModemType_t::RADIOLIB_MODEM_LRFHSS) {
434 : // calculate the number of bits based on coding rate
435 : uint16_t N_bits;
436 6 : switch(dr.lrFhss.cr) {
437 0 : case RADIOLIB_LR_FHSS_CR_5_6:
438 0 : N_bits = ((len * 6) + 4) / 5; // this is from the official LR11xx driver, but why the extra +4?
439 0 : break;
440 3 : case RADIOLIB_LR_FHSS_CR_2_3:
441 3 : N_bits = (len * 3) / 2;
442 3 : break;
443 0 : case RADIOLIB_LR_FHSS_CR_1_2:
444 0 : N_bits = len * 2;
445 0 : break;
446 3 : case RADIOLIB_LR_FHSS_CR_1_3:
447 3 : N_bits = len * 3;
448 3 : break;
449 0 : default:
450 0 : return(RADIOLIB_ERR_INVALID_CODING_RATE);
451 : }
452 :
453 : // calculate number of bits when accounting for unaligned last block
454 6 : uint16_t N_payBits = (N_bits / RADIOLIB_LR_FHSS_FRAG_BITS) * RADIOLIB_LR_FHSS_BLOCK_BITS;
455 6 : uint16_t N_lastBlockBits = N_bits % RADIOLIB_LR_FHSS_FRAG_BITS;
456 6 : if(N_lastBlockBits) {
457 6 : N_payBits += N_lastBlockBits + 2;
458 : }
459 :
460 : // add header bits
461 6 : uint16_t N_totalBits = (RADIOLIB_LR_FHSS_HEADER_BITS * pc.lrFhss.hdrCount) + N_payBits;
462 6 : return(((uint32_t)N_totalBits * 8 * 1000000UL) * (1.0f / RADIOLIB_LR_FHSS_BIT_RATE));
463 :
464 : } else {
465 8 : return(RADIOLIB_ERR_WRONG_MODEM);
466 : }
467 :
468 : return(0);
469 : }
470 :
471 0 : RadioLibTime_t PhysicalLayer::getTimeOnAir(size_t len) {
472 : (void)len;
473 0 : return(0);
474 : }
475 :
476 0 : RadioLibTime_t PhysicalLayer::calculateRxTimeout(RadioLibTime_t timeoutUs) {
477 : (void)timeoutUs;
478 0 : return(0);
479 : }
480 :
481 18 : uint32_t PhysicalLayer::getIrqMapped(RadioLibIrqFlags_t irq) {
482 : // iterate over all set bits and build the module-specific flags
483 18 : uint32_t irqRaw = 0;
484 594 : for(uint8_t i = 0; i < 8*(sizeof(RadioLibIrqFlags_t)); i++) {
485 576 : if((irq & (uint32_t)(1UL << i)) && (this->irqMap[i] != RADIOLIB_IRQ_NOT_SUPPORTED)) {
486 60 : irqRaw |= this->irqMap[i];
487 : }
488 : }
489 :
490 18 : return(irqRaw);
491 : }
492 :
493 0 : int16_t PhysicalLayer::checkIrq(RadioLibIrqType_t irq) {
494 0 : if((irq > RADIOLIB_IRQ_TIMEOUT) || (this->irqMap[irq] == RADIOLIB_IRQ_NOT_SUPPORTED)) {
495 0 : return(RADIOLIB_ERR_UNSUPPORTED);
496 : }
497 :
498 0 : return((getIrqFlags() & this->irqMap[irq]) != 0);
499 : }
500 :
501 0 : int16_t PhysicalLayer::setIrq(RadioLibIrqFlags_t irq) {
502 0 : return(setIrqFlags(getIrqMapped(irq)));
503 : }
504 :
505 0 : int16_t PhysicalLayer::clearIrq(RadioLibIrqFlags_t irq) {
506 0 : return(clearIrqFlags(getIrqMapped(irq)));
507 : }
508 :
509 0 : uint32_t PhysicalLayer::getIrqFlags() {
510 0 : return(RADIOLIB_ERR_UNSUPPORTED);
511 : }
512 :
513 0 : int16_t PhysicalLayer::setIrqFlags(uint32_t irq) {
514 : (void)irq;
515 0 : return(RADIOLIB_ERR_UNSUPPORTED);
516 : }
517 :
518 0 : int16_t PhysicalLayer::clearIrqFlags(uint32_t irq) {
519 : (void)irq;
520 0 : return(RADIOLIB_ERR_UNSUPPORTED);
521 : }
522 :
523 0 : int16_t PhysicalLayer::startChannelScan() {
524 0 : return(RADIOLIB_ERR_UNSUPPORTED);
525 : }
526 :
527 0 : int16_t PhysicalLayer::startChannelScan(const ChannelScanConfig_t &config) {
528 : (void)config;
529 0 : return(RADIOLIB_ERR_UNSUPPORTED);
530 : }
531 :
532 0 : int16_t PhysicalLayer::getChannelScanResult() {
533 0 : return(RADIOLIB_ERR_UNSUPPORTED);
534 : }
535 :
536 0 : int16_t PhysicalLayer::scanChannel() {
537 0 : return(RADIOLIB_ERR_UNSUPPORTED);
538 : }
539 :
540 0 : int16_t PhysicalLayer::scanChannel(const ChannelScanConfig_t &config) {
541 : (void)config;
542 0 : return(RADIOLIB_ERR_UNSUPPORTED);
543 : }
544 :
545 0 : int32_t PhysicalLayer::random(int32_t max) {
546 0 : if(max == 0) {
547 0 : return(0);
548 : }
549 :
550 : // get random bytes from the radio
551 : uint8_t randBuff[4];
552 0 : for(uint8_t i = 0; i < 4; i++) {
553 0 : randBuff[i] = randomByte();
554 : }
555 :
556 : // create 32-bit TRNG number
557 0 : int32_t randNum = ((int32_t)randBuff[0] << 24) | ((int32_t)randBuff[1] << 16) | ((int32_t)randBuff[2] << 8) | ((int32_t)randBuff[3]);
558 0 : if(randNum < 0) {
559 0 : randNum *= -1;
560 : }
561 0 : return(randNum % max);
562 : }
563 :
564 0 : int32_t PhysicalLayer::random(int32_t min, int32_t max) {
565 0 : if(min >= max) {
566 0 : return(min);
567 : }
568 :
569 0 : return(PhysicalLayer::random(max - min) + min);
570 : }
571 :
572 0 : uint8_t PhysicalLayer::randomByte() {
573 0 : return(0);
574 : }
575 :
576 0 : int16_t PhysicalLayer::startDirect() {
577 : // disable encodings
578 0 : int16_t state = setEncoding(RADIOLIB_ENCODING_NRZ);
579 0 : RADIOLIB_ASSERT(state);
580 :
581 : // disable shaping
582 0 : state = setDataShaping(RADIOLIB_SHAPING_NONE);
583 0 : RADIOLIB_ASSERT(state);
584 :
585 : // set frequency deviation to the lowest possible value
586 0 : state = setFrequencyDeviation(0);
587 0 : return(state);
588 : }
589 :
590 : #if !RADIOLIB_EXCLUDE_DIRECT_RECEIVE
591 0 : int16_t PhysicalLayer::available() {
592 0 : return(this->bufferWritePos);
593 : }
594 :
595 0 : void PhysicalLayer::dropSync() {
596 0 : if(this->directSyncWordLen > 0) {
597 0 : this->gotSync = false;
598 0 : this->syncBuffer = 0;
599 : }
600 0 : }
601 :
602 0 : uint8_t PhysicalLayer::read(bool drop) {
603 0 : if(drop) {
604 0 : dropSync();
605 : }
606 0 : this->bufferWritePos--;
607 0 : return(this->buffer[this->bufferReadPos++]);
608 : }
609 :
610 0 : int16_t PhysicalLayer::setDirectSyncWord(uint32_t syncWord, uint8_t len) {
611 0 : if(len > 32) {
612 0 : return(RADIOLIB_ERR_INVALID_SYNC_WORD);
613 : }
614 0 : this->directSyncWordMask = 0xFFFFFFFF >> (32 - len);
615 0 : this->directSyncWordLen = len;
616 0 : this->directSyncWord = syncWord;
617 :
618 : // override sync word matching when length is set to 0
619 0 : if(this->directSyncWordLen == 0) {
620 0 : this->gotSync = true;
621 : }
622 :
623 0 : return(RADIOLIB_ERR_NONE);
624 : }
625 :
626 0 : void PhysicalLayer::updateDirectBuffer(uint8_t bit) {
627 : // check sync word
628 0 : if(!this->gotSync) {
629 0 : this->syncBuffer <<= 1;
630 0 : this->syncBuffer |= bit;
631 :
632 : RADIOLIB_DEBUG_PROTOCOL_PRINTLN("S\t%lu", (long unsigned int)this->syncBuffer);
633 :
634 0 : if((this->syncBuffer & this->directSyncWordMask) == this->directSyncWord) {
635 0 : this->gotSync = true;
636 0 : this->bufferWritePos = 0;
637 0 : this->bufferReadPos = 0;
638 0 : this->bufferBitPos = 0;
639 : }
640 :
641 : } else {
642 : // save the bit
643 0 : if(bit) {
644 0 : this->buffer[this->bufferWritePos] |= 0x01 << this->bufferBitPos;
645 : } else {
646 0 : this->buffer[this->bufferWritePos] &= ~(0x01 << this->bufferBitPos);
647 : }
648 0 : this->bufferBitPos++;
649 :
650 : // check complete byte
651 0 : if(this->bufferBitPos == 8) {
652 0 : this->buffer[this->bufferWritePos] = rlb_reflect(this->buffer[this->bufferWritePos], 8);
653 : RADIOLIB_DEBUG_PROTOCOL_PRINTLN("R\t%X", this->buffer[this->bufferWritePos]);
654 :
655 0 : this->bufferWritePos++;
656 0 : this->bufferBitPos = 0;
657 : }
658 : }
659 0 : }
660 :
661 0 : void PhysicalLayer::setDirectAction(void (*func)(void)) {
662 : (void)func;
663 0 : }
664 :
665 0 : void PhysicalLayer::readBit(uint32_t pin) {
666 : (void)pin;
667 0 : }
668 :
669 : #endif
670 :
671 0 : void PhysicalLayer::setIrqAction(void (*func)(void), bool rising) {
672 0 : Module* mod = getMod();
673 0 : mod->hal->attachInterrupt(mod->hal->pinToInterrupt(mod->getIrq()), func,
674 0 : rising ? mod->hal->GpioInterruptRising : mod->hal->GpioInterruptFalling);
675 0 : }
676 :
677 0 : void PhysicalLayer::clearIrqAction() {
678 0 : Module* mod = getMod();
679 0 : mod->hal->detachInterrupt(mod->hal->pinToInterrupt(mod->getIrq()));
680 0 : }
681 :
682 0 : int16_t PhysicalLayer::setModem(ModemType_t modem) {
683 : (void)modem;
684 0 : return(RADIOLIB_ERR_UNSUPPORTED);
685 : }
686 :
687 0 : int16_t PhysicalLayer::getModem(ModemType_t* modem) {
688 : (void)modem;
689 0 : return(RADIOLIB_ERR_UNSUPPORTED);
690 : }
691 :
692 0 : int16_t PhysicalLayer::getMode(RadioModeType_t* mode) {
693 : (void)mode;
694 0 : return(RADIOLIB_ERR_UNSUPPORTED);
695 : }
696 :
697 0 : int16_t PhysicalLayer::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) {
698 : (void)mode;
699 : (void)cfg;
700 0 : return(RADIOLIB_ERR_UNSUPPORTED);
701 : }
702 :
703 0 : int16_t PhysicalLayer::launchMode() {
704 0 : return(RADIOLIB_ERR_UNSUPPORTED);
705 : }
706 :
707 0 : int16_t PhysicalLayer::writeTxBuffer(const uint8_t* data, size_t len) {
708 : (void)data;
709 : (void)len;
710 0 : return(RADIOLIB_ERR_UNSUPPORTED);
711 : }
712 :
713 0 : int16_t PhysicalLayer::clearTxBuffer() {
714 0 : return(RADIOLIB_ERR_UNSUPPORTED);
715 : }
716 :
717 : #if RADIOLIB_INTERRUPT_TIMING
718 : void PhysicalLayer::setInterruptSetup(void (*func)(uint32_t)) {
719 : Module* mod = getMod();
720 : mod->TimerSetupCb = func;
721 : }
722 :
723 : void PhysicalLayer::setTimerFlag() {
724 : Module* mod = getMod();
725 : mod->TimerFlag = true;
726 : }
727 : #endif
728 :
729 0 : int16_t PhysicalLayer::calculateRxDutyCycle(size_t txPreLen, size_t rxPreLen, uint16_t minSymbols, DataRate_t* dr, uint32_t* wakePeriod, uint32_t* sleepPeriod) {
730 0 : RADIOLIB_ASSERT_PTR(dr);
731 0 : RADIOLIB_ASSERT_PTR(wakePeriod);
732 0 : RADIOLIB_ASSERT_PTR(sleepPeriod);
733 :
734 0 : uint16_t senderPreambleLength = txPreLen;
735 0 : if(senderPreambleLength == 0) {
736 0 : senderPreambleLength = rxPreLen;
737 0 : } else if(senderPreambleLength > rxPreLen) {
738 : // the unit must be configured to expect a preamble length at least as long as the sender is using
739 0 : return(RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH);
740 : }
741 0 : if(minSymbols == 0) {
742 0 : if(dr->lora.spreadingFactor <= 6) {
743 0 : minSymbols = 12;
744 : } else {
745 0 : minSymbols = 8;
746 : }
747 : }
748 :
749 : // if we're not to sleep at all, just use the standard startReceive
750 0 : if(2 * minSymbols > senderPreambleLength) {
751 0 : *sleepPeriod = 0;
752 : RADIOLIB_DEBUG_BASIC_PRINTLN("Auto sleep period too short");
753 0 : return(RADIOLIB_ERR_NONE);
754 : }
755 :
756 : // worst case is that the sender starts transmitting when we're just less than minSymbols from going back to sleep.
757 : // in this case, we don't catch minSymbols before going to sleep,
758 : // so we must be awake for at least that long before the sender stops transmitting.
759 0 : uint16_t sleepSymbols = senderPreambleLength - 2 * minSymbols;
760 :
761 0 : uint32_t symbolLength = ((uint32_t)(10 * 1000) << dr->lora.spreadingFactor) / (10 * dr->lora.bandwidth);
762 0 : *sleepPeriod = symbolLength * sleepSymbols;
763 : RADIOLIB_DEBUG_BASIC_PRINTLN("Auto sleep period: %lu", (long unsigned int)*sleepPeriod);
764 :
765 : // when the unit detects a preamble, it starts a timer that will timeout if it doesn't receive a header in time.
766 : // the duration is sleepPeriod + 2 * wakePeriod.
767 : // The sleepPeriod doesn't take into account shutdown and startup time for the unit (~1ms)
768 : // We need to ensure that the timeout is longer than senderPreambleLength.
769 : // So we must satisfy: wakePeriod > (preamblePeriod - (sleepPeriod - 1000)) / 2. (A)
770 : // we also need to ensure the unit is awake to see at least minSymbols. (B)
771 0 : *wakePeriod = RADIOLIB_MAX(
772 : (symbolLength * (senderPreambleLength + 1) - (*sleepPeriod - 1000)) / 2, // (A)
773 : symbolLength * (minSymbols + 1)); //(B)
774 : RADIOLIB_DEBUG_BASIC_PRINTLN("Auto wake period: %lu", (long unsigned int)*wakePeriod);
775 :
776 0 : return(RADIOLIB_ERR_NONE);
777 : }
778 :
779 0 : int16_t PhysicalLayer::setOutputPowerOffset(int8_t offset) {
780 0 : memset(this->paOffsetLut, offset, sizeof(this->paOffsetLut));
781 0 : return(RADIOLIB_ERR_NONE);
782 : }
783 :
784 0 : int16_t PhysicalLayer::setOutputPowerOffset(const int8_t* lut, size_t steps) {
785 0 : RADIOLIB_ASSERT_PTR(lut);
786 0 : if(steps > sizeof(this->paOffsetLut)) {
787 0 : return(RADIOLIB_ERR_INVALID_OUTPUT_POWER);
788 : }
789 0 : memcpy(this->paOffsetLut, lut, steps);
790 0 : return(RADIOLIB_ERR_NONE);
791 : }
792 :
793 17 : int16_t PhysicalLayer::applyOutputPowerOffset(int8_t base, const int8_t* pwrReq, int8_t* pwrRadio) {
794 17 : RADIOLIB_ASSERT_PTR(pwrReq);
795 17 : RADIOLIB_ASSERT_PTR(pwrRadio);
796 :
797 : // update the minimum and maximum supported power
798 17 : this->powerMin = base + this->paOffsetLut[0];
799 17 : this->powerMax = base + this->paSteps - 1 + this->paOffsetLut[this->paSteps - 1];
800 :
801 : // check the range
802 17 : RADIOLIB_CHECK_RANGE(*pwrReq, this->powerMin, this->powerMax, RADIOLIB_ERR_INVALID_OUTPUT_POWER);
803 :
804 : // base is the minimum value that the radio can output on its own, pwrReq is the request from user
805 : // find first entry in the LUT that achieves the target output
806 17 : uint8_t idx = 0;
807 190 : for(; idx < this->paSteps; idx++) {
808 190 : if(base + idx + this->paOffsetLut[idx] >= *pwrReq) {
809 : // output is the base of the table and the index we found
810 17 : *pwrRadio = base + idx;
811 17 : return(RADIOLIB_ERR_NONE);
812 : }
813 : }
814 :
815 : RADIOLIB_DEBUG_BASIC_PRINTLN("Found no setting for PA offset to reach %d dBm!", *pwrReq);
816 0 : return(RADIOLIB_ERR_INVALID_OUTPUT_POWER);
817 : }
818 :
819 0 : int16_t PhysicalLayer::findRxBw(uint32_t rxBw, const uint32_t* rxBwAvg, const uint8_t* lut, size_t lutSize, uint32_t rxBwMax, uint8_t* val) {
820 : // iterate through the table and find whether the user-provided value
821 : // is lower than the pre-computed average of the adjacent bandwidth values
822 : // if it is, we consider that to be a match even though the actual value is not precise
823 0 : for(size_t i = 0; i < (lutSize - 1); i++) {
824 0 : if(rxBw < rxBwAvg[i]) {
825 0 : *val = lut[i];
826 0 : return(RADIOLIB_ERR_NONE);
827 : }
828 : }
829 :
830 : // if nothing matched up to here, match with the last value
831 0 : if(rxBw <= rxBwMax) {
832 0 : *val = lut[lutSize - 1];
833 0 : return(RADIOLIB_ERR_NONE);
834 : }
835 :
836 0 : return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH);
837 : }
|