LCOV - code coverage report
Current view: top level - src/protocols/PhysicalLayer - PhysicalLayer.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 85 326 26.1 %
Date: 2026-11-08 19:43:08 Functions: 9 75 12.0 %

          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(&currentModem);
     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             : }

Generated by: LCOV version 1.14