LCOV - code coverage report
Current view: top level - src/modules/SX126x - SX126x_LR_FHSS.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 207 0.0 %
Date: 2025-10-24 15:14:50 Functions: 0 4 0.0 %

          Line data    Source code
       1             : #include "SX126x.h"
       2             : #include <string.h>
       3             : #include <math.h>
       4             : #if !RADIOLIB_EXCLUDE_SX126X
       5             : 
       6             : /*
       7             :   LR-FHSS implementation in this file is adapted from Setmech's LR-FHSS demo:
       8             :   https://github.com/Lora-net/SWDM001/tree/master/lib/sx126x_driver
       9             : 
      10             :   Its SX126x driver is distributed under the Clear BSD License,
      11             :   and to comply with its terms, it is reproduced below.
      12             : 
      13             :   The Clear BSD License
      14             :   Copyright Semtech Corporation 2021. All rights reserved.
      15             : 
      16             :   Redistribution and use in source and binary forms, with or without
      17             :   modification, are permitted (subject to the limitations in the disclaimer
      18             :   below) provided that the following conditions are met:
      19             :       * Redistributions of source code must retain the above copyright
      20             :         notice, this list of conditions and the following disclaimer.
      21             :       * Redistributions in binary form must reproduce the above copyright
      22             :         notice, this list of conditions and the following disclaimer in the
      23             :         documentation and/or other materials provided with the distribution.
      24             :       * Neither the name of the Semtech corporation nor the
      25             :         names of its contributors may be used to endorse or promote products
      26             :         derived from this software without specific prior written permission.
      27             : 
      28             :   NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
      29             :   THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
      30             :   CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
      31             :   NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
      32             :   PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SEMTECH CORPORATION BE
      33             :   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      34             :   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
      35             :   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      36             :   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
      37             :   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      38             :   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      39             :   POSSIBILITY OF SUCH DAMAGE.
      40             : */
      41             : 
      42             : // header interleaver
      43             : static const uint8_t LrFhssHeaderInterleaver[80] = {
      44             :   0,  18, 36, 54, 72, 4,  22, 40,
      45             :   58, 76, 8,  26, 44, 62, 12, 30,
      46             :   48, 66, 16, 34, 52, 70, 1,  19,
      47             :   37, 55, 73, 5,  23, 41, 59, 77,
      48             :   9,  27, 45, 63, 13, 31, 49, 67,
      49             :   17, 35, 53, 71, 2,  20, 38, 56,
      50             :   74, 6,  24, 42, 60, 78, 10, 28,
      51             :   46, 64, 14, 32, 50, 68, 3,  21,
      52             :   39, 57, 75, 7,  25, 43, 61, 79,
      53             :   11, 29, 47, 65, 15, 33, 51, 69,
      54             : };
      55             : 
      56           0 : int16_t SX126x::buildLRFHSSPacket(const uint8_t* in, size_t in_len, uint8_t* out, size_t* out_len, size_t* out_bits, size_t* out_hops) {
      57             :   // perform payload whitening
      58           0 :   uint8_t lfsr = 0xFF;
      59           0 :   for(size_t i = 0; i < in_len; i++) {
      60           0 :     uint8_t u = in[i] ^ lfsr;
      61             : 
      62             :     // we really shouldn't reuse the caller's memory in this way ...
      63             :     // but since this is a private method it should be at least controlled, if not safe
      64           0 :     out[i] = ((u & 0x0F) << 4 ) | ((u & 0xF0) >> 4);
      65           0 :     lfsr = (lfsr << 1) | (((lfsr & 0x80) >> 7) ^ (((lfsr & 0x20) >> 5) ^ (((lfsr & 0x10) >> 4) ^ ((lfsr & 0x08) >> 3))));
      66             :   }
      67             : 
      68             :   // calculate the CRC-16 over the whitened data, looks like something custom
      69           0 :   RadioLibCRCInstance.size = 16;
      70           0 :   RadioLibCRCInstance.poly = 0x755B;
      71           0 :   RadioLibCRCInstance.init = 0xFFFF;
      72           0 :   RadioLibCRCInstance.out = 0x0000;
      73           0 :   uint16_t crc16 = RadioLibCRCInstance.checksum(out, in_len);
      74             : 
      75             :   // add payload CRC
      76           0 :   out[in_len] = (crc16 >> 8) & 0xFF;
      77           0 :   out[in_len + 1] = crc16 & 0xFF;
      78           0 :   out[in_len + 2] = 0;
      79             : 
      80             :   // encode the payload with CRC using convolutional coding with 1/3 rate into a temporary buffer
      81           0 :   uint8_t tmp[RADIOLIB_SX126X_LR_FHSS_MAX_ENC_SIZE] = { 0 };
      82           0 :   size_t nb_bits = 0;
      83           0 :   RadioLibConvCodeInstance.begin(3);
      84           0 :   RadioLibConvCodeInstance.encode(out, 8 * (in_len + 2) + 6, tmp, &nb_bits);
      85           0 :   memset(out, 0, RADIOLIB_SX126X_MAX_PACKET_LENGTH);
      86             : 
      87             :   // for rates other than the 1/3 base, puncture the code
      88           0 :   if(this->lrFhssCr != RADIOLIB_SX126X_LR_FHSS_CR_1_3) {
      89           0 :     uint32_t matrix_index = 0;
      90           0 :     const uint8_t matrix[15]   = { 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0 };
      91           0 :     uint8_t  matrix_len   = 0;
      92           0 :     switch(this->lrFhssCr) {
      93           0 :       case RADIOLIB_SX126X_LR_FHSS_CR_5_6:
      94           0 :         matrix_len = 15;
      95           0 :         break;
      96           0 :       case RADIOLIB_SX126X_LR_FHSS_CR_2_3:
      97           0 :         matrix_len = 6;
      98           0 :         break;
      99           0 :       case RADIOLIB_SX126X_LR_FHSS_CR_1_2:
     100           0 :         matrix_len = 3;
     101           0 :         break;
     102             :     }
     103             : 
     104           0 :     uint32_t j = 0;
     105           0 :     for(uint32_t i = 0; i < nb_bits; i++) {
     106           0 :       if(matrix[matrix_index]) {
     107           0 :         if(TEST_BIT_IN_ARRAY_LSB(tmp, i)) {
     108           0 :           SET_BIT_IN_ARRAY_LSB(out, j);
     109             :         } else {
     110           0 :           CLEAR_BIT_IN_ARRAY_LSB(out, j);
     111             :         }
     112           0 :         j++;
     113             :       }
     114             : 
     115           0 :       if(++matrix_index == matrix_len) {
     116           0 :         matrix_index = 0;
     117             :       }
     118             :     }
     119             : 
     120           0 :     nb_bits = j;
     121           0 :     memcpy(tmp, out, (nb_bits + 7) / 8);
     122             :   }
     123             : 
     124             :   // interleave the payload into output buffer
     125           0 :   uint16_t step = 0;
     126           0 :   while((size_t)(step * step) < nb_bits) {
     127             :     // probably the silliest sqrt() I ever saw
     128           0 :     step++;
     129             :   }
     130             : 
     131           0 :   const uint16_t step_v = step >> 1;
     132           0 :   step <<= 1;
     133             : 
     134           0 :   uint16_t pos           = 0;
     135           0 :   uint16_t st_idx        = 0;
     136           0 :   uint16_t st_idx_init   = 0;
     137           0 :   int16_t  bits_left     = nb_bits;
     138           0 :   uint16_t out_row_index = RADIOLIB_SX126X_LR_FHSS_HEADER_BITS * this->lrFhssHdrCount;
     139             : 
     140           0 :   while(bits_left > 0) {
     141           0 :     int16_t in_row_width = bits_left;
     142           0 :     if(in_row_width > RADIOLIB_SX126X_LR_FHSS_FRAG_BITS) {
     143           0 :       in_row_width = RADIOLIB_SX126X_LR_FHSS_FRAG_BITS;
     144             :     }
     145             : 
     146             :     // guard bits
     147           0 :     CLEAR_BIT_IN_ARRAY_LSB(out, out_row_index);
     148           0 :     CLEAR_BIT_IN_ARRAY_LSB(out, out_row_index + 1);
     149             :         
     150           0 :     for(int16_t j = 0; j < in_row_width; j++) {
     151             :       // guard bit
     152           0 :       if(TEST_BIT_IN_ARRAY_LSB(tmp, pos)) {
     153           0 :         SET_BIT_IN_ARRAY_LSB(out, j + 2 + out_row_index);
     154             :       } else {
     155           0 :         CLEAR_BIT_IN_ARRAY_LSB(out, j + 2 + out_row_index);
     156             :       }
     157             : 
     158           0 :       pos += step;
     159           0 :       if(pos >= nb_bits) {
     160           0 :         st_idx += step_v;
     161           0 :         if(st_idx >= step) {
     162           0 :           st_idx_init++;
     163           0 :           st_idx = st_idx_init;
     164             :         }
     165           0 :         pos = st_idx;
     166             :       }
     167             :     }
     168             : 
     169           0 :     bits_left -= RADIOLIB_SX126X_LR_FHSS_FRAG_BITS;
     170           0 :     out_row_index += 2 + in_row_width;
     171             :   }
     172             : 
     173           0 :   nb_bits = out_row_index - RADIOLIB_SX126X_LR_FHSS_HEADER_BITS * this->lrFhssHdrCount;
     174             : 
     175             :   // build the header
     176             :   uint8_t raw_header[RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2];
     177           0 :   raw_header[0] = in_len;
     178           0 :   raw_header[1] = (this->lrFhssCr << 3) | ((uint8_t)this->lrFhssGridNonFcc << 2) |
     179           0 :     (RADIOLIB_SX126X_LR_FHSS_HOPPING_ENABLED << 1) | (this->lrFhssBw >> 3);
     180           0 :   raw_header[2] = ((this->lrFhssBw & 0x07) << 5) | (this->lrFhssHopSeqId >> 4);
     181           0 :   raw_header[3] = ((this->lrFhssHopSeqId & 0x000F) << 4);
     182             : 
     183             :   // CRC-8 used seems to based on 8H2F, but without final XOR
     184           0 :   RadioLibCRCInstance.size = 8;
     185           0 :   RadioLibCRCInstance.poly = 0x2F;
     186           0 :   RadioLibCRCInstance.init = 0xFF;
     187           0 :   RadioLibCRCInstance.out = 0x00;
     188             : 
     189           0 :   uint16_t header_offset = 0;
     190           0 :   for(size_t i = 0; i < this->lrFhssHdrCount; i++) {
     191             :     // insert index and calculate the header CRC
     192           0 :     raw_header[3] = (raw_header[3] & ~0x0C) | ((this->lrFhssHdrCount - i - 1) << 2);
     193           0 :     raw_header[4] = RadioLibCRCInstance.checksum(raw_header, (RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2 - 1));
     194             : 
     195             :     // convolutional encode
     196           0 :     uint8_t coded_header[RADIOLIB_SX126X_LR_FHSS_HDR_BYTES] = { 0 };
     197           0 :     RadioLibConvCodeInstance.begin(2);
     198           0 :     RadioLibConvCodeInstance.encode(raw_header, 8*RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2, coded_header);
     199             :     // tail-biting seems to just do this twice ...?
     200           0 :     RadioLibConvCodeInstance.encode(raw_header, 8*RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2, coded_header);
     201             : 
     202             :     // clear guard bits
     203           0 :     CLEAR_BIT_IN_ARRAY_LSB(out, header_offset);
     204           0 :     CLEAR_BIT_IN_ARRAY_LSB(out, header_offset + 1);
     205             : 
     206             :     // interleave the header directly to the physical payload buffer
     207           0 :     for(size_t j = 0; j < (8*RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2); j++) {
     208           0 :       if(TEST_BIT_IN_ARRAY_LSB(coded_header, LrFhssHeaderInterleaver[j])) {
     209           0 :         SET_BIT_IN_ARRAY_LSB(out, header_offset + 2 + j);
     210             :       } else {
     211           0 :         CLEAR_BIT_IN_ARRAY_LSB(out, header_offset + 2 + j);
     212             :       }
     213             :     }
     214           0 :     for(size_t j = 0; j < (8*RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2); j++) {
     215           0 :       if(TEST_BIT_IN_ARRAY_LSB(coded_header, LrFhssHeaderInterleaver[(8*RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2) + j])) {
     216           0 :         SET_BIT_IN_ARRAY_LSB(out, header_offset + 2 + (8*RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2) + (8*RADIOLIB_SX126X_LR_FHSS_SYNC_WORD_BYTES) + j);
     217             :       } else {
     218           0 :         CLEAR_BIT_IN_ARRAY_LSB(out, header_offset + 2 + (8*RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2) + (8*RADIOLIB_SX126X_LR_FHSS_SYNC_WORD_BYTES) + j);
     219             :       }
     220             :     }
     221             : 
     222             :     // copy the sync word to the physical payload buffer
     223           0 :     for(size_t j = 0; j < (8*RADIOLIB_SX126X_LR_FHSS_SYNC_WORD_BYTES); j++) {
     224           0 :       if(TEST_BIT_IN_ARRAY_LSB(this->lrFhssSyncWord, j)) {
     225           0 :         SET_BIT_IN_ARRAY_LSB(out, header_offset + 2 + (8*RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2) + j);
     226             :       } else {
     227           0 :         CLEAR_BIT_IN_ARRAY_LSB(out, header_offset + 2 + (8*RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2) + j);
     228             :       }
     229             :     }
     230             : 
     231           0 :     header_offset += RADIOLIB_SX126X_LR_FHSS_HEADER_BITS;
     232             :   }
     233             : 
     234             :   // calculate the number of hops and total number of bits
     235           0 :   uint16_t length_bits = (in_len + 2) * 8 + 6;
     236           0 :   switch(this->lrFhssCr) {
     237           0 :     case RADIOLIB_SX126X_LR_FHSS_CR_5_6:
     238           0 :       length_bits = ( ( length_bits * 6 ) + 4 ) / 5;
     239           0 :       break;
     240           0 :     case RADIOLIB_SX126X_LR_FHSS_CR_2_3:
     241           0 :       length_bits = length_bits * 3 / 2;
     242           0 :       break;
     243           0 :     case RADIOLIB_SX126X_LR_FHSS_CR_1_2:
     244           0 :       length_bits = length_bits * 2;
     245           0 :       break;
     246           0 :     case RADIOLIB_SX126X_LR_FHSS_CR_1_3:
     247           0 :       length_bits = length_bits * 3;
     248           0 :       break;
     249             :   }
     250             : 
     251           0 :   *out_hops = (length_bits + 47) / 48 + this->lrFhssHdrCount;
     252             : 
     253             :   // calculate total number of payload bits, after breaking into blocks
     254           0 :   uint16_t payload_bits = length_bits / RADIOLIB_SX126X_LR_FHSS_FRAG_BITS * RADIOLIB_SX126X_LR_FHSS_BLOCK_BITS;
     255           0 :   uint16_t last_block_bits = length_bits % RADIOLIB_SX126X_LR_FHSS_FRAG_BITS;
     256           0 :   if(last_block_bits > 0) {
     257             :     // add the 2 guard bits for the last block + the actual remaining payload bits
     258           0 :     payload_bits += last_block_bits + 2;
     259             :   }
     260             : 
     261           0 :   *out_bits = (RADIOLIB_SX126X_LR_FHSS_HEADER_BITS * this->lrFhssHdrCount) + payload_bits;
     262           0 :   *out_len = (*out_bits + 7) / 8;
     263             : 
     264           0 :   return(RADIOLIB_ERR_NONE);
     265             : }
     266             : 
     267           0 : int16_t SX126x::resetLRFHSS() {
     268             :   // initialize hopping configuration
     269           0 :   const uint16_t numChan[] = { 80, 176, 280, 376, 688, 792, 1480, 1584, 3120, 3224 };
     270             :   
     271             :   // LFSR polynomials for different ranges of lrFhssNgrid
     272           0 :   const uint8_t lfsrPoly1[] = { 33, 45, 48, 51, 54, 57 };
     273           0 :   const uint8_t lfsrPoly2[] = { 65, 68, 71, 72 };
     274           0 :   const uint8_t lfsrPoly3[] = { 142, 149 };
     275             : 
     276           0 :   uint32_t nb_channel_in_grid = this->lrFhssGridNonFcc ? 8 : 52;
     277           0 :   this->lrFhssNgrid = numChan[this->lrFhssBw] / nb_channel_in_grid;
     278           0 :   this->lrFhssLfsrState = 6;
     279           0 :   switch(this->lrFhssNgrid) {
     280           0 :     case 10:
     281             :     case 22:
     282             :     case 28:
     283             :     case 30:
     284             :     case 35:
     285             :     case 47:
     286           0 :       this->lrFhssPoly = lfsrPoly1[this->lrFhssHopSeqId >> 6];
     287           0 :       this->lrFhssSeed = this->lrFhssHopSeqId & 0x3F;
     288           0 :       if(this->lrFhssHopSeqId >= 384) {
     289           0 :         return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
     290             :       }
     291           0 :       break;
     292             :     
     293           0 :     case 60:
     294             :     case 62:
     295           0 :       this->lrFhssLfsrState = 56;
     296           0 :       this->lrFhssPoly = lfsrPoly1[this->lrFhssHopSeqId >> 6];
     297           0 :       this->lrFhssSeed = this->lrFhssHopSeqId & 0x3F;
     298           0 :       if(this->lrFhssHopSeqId >= 384) {
     299           0 :         return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
     300             :       }
     301           0 :       break;
     302             :     
     303           0 :     case 86:
     304             :     case 99:
     305           0 :       this->lrFhssPoly = lfsrPoly2[this->lrFhssHopSeqId >> 7];
     306           0 :       this->lrFhssSeed = this->lrFhssHopSeqId & 0x7F;
     307           0 :       break;
     308             :     
     309           0 :     case 185:
     310             :     case 198:
     311           0 :       this->lrFhssPoly = lfsrPoly3[this->lrFhssHopSeqId >> 8];
     312           0 :       this->lrFhssSeed = this->lrFhssHopSeqId & 0xFF;
     313           0 :       break;
     314             :     
     315           0 :     case 390:
     316             :     case 403:
     317           0 :       this->lrFhssPoly = 264;
     318           0 :       this->lrFhssSeed = this->lrFhssHopSeqId;
     319           0 :       break;
     320             :     
     321           0 :     default:
     322           0 :       return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
     323             :   }
     324             : 
     325           0 :   return(RADIOLIB_ERR_NONE);
     326             : }
     327             : 
     328           0 : uint16_t SX126x::stepLRFHSS() {
     329             :   uint16_t hop;
     330             :   do {
     331           0 :     uint16_t lsb = this->lrFhssLfsrState & 1;
     332           0 :     this->lrFhssLfsrState >>= 1;
     333           0 :     if(lsb) {
     334           0 :      this->lrFhssLfsrState ^= this->lrFhssPoly;
     335             :     }
     336           0 :     hop = this->lrFhssSeed;
     337           0 :     if(hop != this->lrFhssLfsrState) {
     338           0 :       hop ^= this->lrFhssLfsrState;
     339             :     }
     340           0 :   } while(hop > this->lrFhssNgrid);
     341           0 :   return(hop);
     342             : }
     343             : 
     344           0 : int16_t SX126x::setLRFHSSHop(uint8_t index) {
     345           0 :   if(!this->lrFhssFrameHopsRem) {
     346           0 :     return(RADIOLIB_ERR_NONE);
     347             :   }
     348             : 
     349           0 :   uint16_t hop = stepLRFHSS();
     350           0 :   int16_t freq_table = hop - 1;
     351           0 :   if(freq_table >= (int16_t)(this->lrFhssNgrid >> 1)) {
     352           0 :     freq_table -= this->lrFhssNgrid;
     353             :   }
     354             : 
     355           0 :   uint32_t nb_channel_in_grid = this->lrFhssGridNonFcc ? 8 : 52;
     356           0 :   uint32_t grid_offset = (1 + (this->lrFhssNgrid % 2)) * (nb_channel_in_grid / 2);
     357           0 :   uint32_t grid_in_pll_steps = this->lrFhssGridNonFcc ? 4096 : 26624;
     358           0 :   uint32_t frf = (this->freqMHz * (uint32_t(1) << RADIOLIB_SX126X_DIV_EXPONENT)) / RADIOLIB_SX126X_CRYSTAL_FREQ;
     359           0 :   uint32_t freq_raw = frf - freq_table * grid_in_pll_steps - grid_offset * 512;
     360             : 
     361           0 :   if((this->lrFhssHopNum < this->lrFhssHdrCount)) {
     362           0 :     if((((this->lrFhssHdrCount - this->lrFhssHopNum) % 2) == 0)) {
     363           0 :       freq_raw += 256;
     364             :     }
     365             :   }
     366             : 
     367           0 :   const uint8_t frq[4] = { (uint8_t)((freq_raw >> 24) & 0xFF), (uint8_t)((freq_raw >> 16) & 0xFF), (uint8_t)((freq_raw >> 8) & 0xFF), (uint8_t)(freq_raw & 0xFF) };
     368           0 :   int16_t state = writeRegister(RADIOLIB_SX126X_REG_LR_FHSS_FREQX_0(index), frq, sizeof(freq_raw));
     369           0 :   RADIOLIB_ASSERT(state);
     370             : 
     371             :   // (LR_FHSS_HEADER_BITS + pulse_shape_compensation) symbols on first sync_word, LR_FHSS_HEADER_BITS on
     372             :   // next sync_words, LR_FHSS_BLOCK_BITS on payload
     373           0 :   uint16_t numSymbols = RADIOLIB_SX126X_LR_FHSS_BLOCK_BITS;
     374           0 :   if(index == 0) {
     375           0 :     numSymbols = RADIOLIB_SX126X_LR_FHSS_HEADER_BITS + 1; // the +1 is "pulse_shape_compensation", but it's constant in the demo
     376           0 :   } else if(index < this->lrFhssHdrCount) {
     377           0 :     numSymbols = RADIOLIB_SX126X_LR_FHSS_HEADER_BITS;
     378           0 :   } else if(this->lrFhssFrameBitsRem < RADIOLIB_SX126X_LR_FHSS_BLOCK_BITS) {
     379           0 :     numSymbols = this->lrFhssFrameBitsRem;
     380             :   }
     381             : 
     382             :   // write hop length in symbols
     383           0 :   const uint8_t sym[2] = { (uint8_t)((numSymbols >> 8) & 0xFF), (uint8_t)(numSymbols & 0xFF) };
     384           0 :   state = writeRegister(RADIOLIB_SX126X_REG_LR_FHSS_NUM_SYMBOLS_FREQX_MSB(index), sym, sizeof(uint16_t));
     385           0 :   RADIOLIB_ASSERT(state);
     386             : 
     387           0 :   this->lrFhssFrameBitsRem -= numSymbols;
     388           0 :   this->lrFhssFrameHopsRem--;
     389           0 :   this->lrFhssHopNum++;
     390           0 :   return(RADIOLIB_ERR_NONE);
     391             : }
     392             : 
     393             : #endif

Generated by: LCOV version 1.14