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: 2026-06-03 18:53:41 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             : // create a static instance of the convolutional encoder
      43             : // this way it will only get built when Pager is built
      44             : static RadioLibConvCode RadioLibConvCodeInstance;
      45             : 
      46             : // header interleaver
      47             : static const uint8_t LrFhssHeaderInterleaver[80] = {
      48             :   0,  18, 36, 54, 72, 4,  22, 40,
      49             :   58, 76, 8,  26, 44, 62, 12, 30,
      50             :   48, 66, 16, 34, 52, 70, 1,  19,
      51             :   37, 55, 73, 5,  23, 41, 59, 77,
      52             :   9,  27, 45, 63, 13, 31, 49, 67,
      53             :   17, 35, 53, 71, 2,  20, 38, 56,
      54             :   74, 6,  24, 42, 60, 78, 10, 28,
      55             :   46, 64, 14, 32, 50, 68, 3,  21,
      56             :   39, 57, 75, 7,  25, 43, 61, 79,
      57             :   11, 29, 47, 65, 15, 33, 51, 69,
      58             : };
      59             : 
      60           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) {
      61             :   // perform payload whitening
      62           0 :   uint8_t lfsr = 0xFF;
      63           0 :   for(size_t i = 0; i < in_len; i++) {
      64           0 :     uint8_t u = in[i] ^ lfsr;
      65             : 
      66             :     // we really shouldn't reuse the caller's memory in this way ...
      67             :     // but since this is a private method it should be at least controlled, if not safe
      68           0 :     out[i] = ((u & 0x0F) << 4 ) | ((u & 0xF0) >> 4);
      69           0 :     lfsr = (lfsr << 1) | (((lfsr & 0x80) >> 7) ^ (((lfsr & 0x20) >> 5) ^ (((lfsr & 0x10) >> 4) ^ ((lfsr & 0x08) >> 3))));
      70             :   }
      71             : 
      72             :   // calculate the CRC-16 over the whitened data, looks like something custom
      73           0 :   RadioLibCRCInstance.size = 16;
      74           0 :   RadioLibCRCInstance.poly = 0x755B;
      75           0 :   RadioLibCRCInstance.init = 0xFFFF;
      76           0 :   RadioLibCRCInstance.out = 0x0000;
      77           0 :   uint16_t crc16 = RadioLibCRCInstance.checksum(out, in_len);
      78             : 
      79             :   // add payload CRC
      80           0 :   out[in_len] = (crc16 >> 8) & 0xFF;
      81           0 :   out[in_len + 1] = crc16 & 0xFF;
      82           0 :   out[in_len + 2] = 0;
      83             : 
      84             :   // encode the payload with CRC using convolutional coding with 1/3 rate into a temporary buffer
      85           0 :   uint8_t tmp[RADIOLIB_SX126X_LR_FHSS_MAX_ENC_SIZE] = { 0 };
      86           0 :   size_t nb_bits = 0;
      87           0 :   RadioLibConvCodeInstance.begin(3);
      88           0 :   RadioLibConvCodeInstance.encode(out, 8 * (in_len + 2) + 6, tmp, &nb_bits);
      89           0 :   memset(out, 0, RADIOLIB_SX126X_MAX_PACKET_LENGTH);
      90             : 
      91             :   // for rates other than the 1/3 base, puncture the code
      92           0 :   if(this->lrFhssCr != RADIOLIB_SX126X_LR_FHSS_CR_1_3) {
      93           0 :     uint32_t matrix_index = 0;
      94           0 :     const uint8_t matrix[15]   = { 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0 };
      95           0 :     uint8_t  matrix_len   = 0;
      96           0 :     switch(this->lrFhssCr) {
      97           0 :       case RADIOLIB_SX126X_LR_FHSS_CR_5_6:
      98           0 :         matrix_len = 15;
      99           0 :         break;
     100           0 :       case RADIOLIB_SX126X_LR_FHSS_CR_2_3:
     101           0 :         matrix_len = 6;
     102           0 :         break;
     103           0 :       case RADIOLIB_SX126X_LR_FHSS_CR_1_2:
     104           0 :         matrix_len = 3;
     105           0 :         break;
     106             :     }
     107             : 
     108           0 :     uint32_t j = 0;
     109           0 :     for(uint32_t i = 0; i < nb_bits; i++) {
     110           0 :       if(matrix[matrix_index]) {
     111           0 :         if(TEST_BIT_IN_ARRAY_LSB(tmp, i)) {
     112           0 :           SET_BIT_IN_ARRAY_LSB(out, j);
     113             :         } else {
     114           0 :           CLEAR_BIT_IN_ARRAY_LSB(out, j);
     115             :         }
     116           0 :         j++;
     117             :       }
     118             : 
     119           0 :       if(++matrix_index == matrix_len) {
     120           0 :         matrix_index = 0;
     121             :       }
     122             :     }
     123             : 
     124           0 :     nb_bits = j;
     125           0 :     memcpy(tmp, out, (nb_bits + 7) / 8);
     126             :   }
     127             : 
     128             :   // interleave the payload into output buffer
     129           0 :   uint16_t step = 0;
     130           0 :   while((size_t)(step * step) < nb_bits) {
     131             :     // probably the silliest sqrt() I ever saw
     132           0 :     step++;
     133             :   }
     134             : 
     135           0 :   const uint16_t step_v = step >> 1;
     136           0 :   step <<= 1;
     137             : 
     138           0 :   uint16_t pos           = 0;
     139           0 :   uint16_t st_idx        = 0;
     140           0 :   uint16_t st_idx_init   = 0;
     141           0 :   int16_t  bits_left     = nb_bits;
     142           0 :   uint16_t out_row_index = RADIOLIB_SX126X_LR_FHSS_HEADER_BITS * this->lrFhssHdrCount;
     143             : 
     144           0 :   while(bits_left > 0) {
     145           0 :     int16_t in_row_width = bits_left;
     146           0 :     if(in_row_width > RADIOLIB_SX126X_LR_FHSS_FRAG_BITS) {
     147           0 :       in_row_width = RADIOLIB_SX126X_LR_FHSS_FRAG_BITS;
     148             :     }
     149             : 
     150             :     // guard bits
     151           0 :     CLEAR_BIT_IN_ARRAY_LSB(out, out_row_index);
     152           0 :     CLEAR_BIT_IN_ARRAY_LSB(out, out_row_index + 1);
     153             :         
     154           0 :     for(int16_t j = 0; j < in_row_width; j++) {
     155             :       // guard bit
     156           0 :       if(TEST_BIT_IN_ARRAY_LSB(tmp, pos)) {
     157           0 :         SET_BIT_IN_ARRAY_LSB(out, j + 2 + out_row_index);
     158             :       } else {
     159           0 :         CLEAR_BIT_IN_ARRAY_LSB(out, j + 2 + out_row_index);
     160             :       }
     161             : 
     162           0 :       pos += step;
     163           0 :       if(pos >= nb_bits) {
     164           0 :         st_idx += step_v;
     165           0 :         if(st_idx >= step) {
     166           0 :           st_idx_init++;
     167           0 :           st_idx = st_idx_init;
     168             :         }
     169           0 :         pos = st_idx;
     170             :       }
     171             :     }
     172             : 
     173           0 :     bits_left -= RADIOLIB_SX126X_LR_FHSS_FRAG_BITS;
     174           0 :     out_row_index += 2 + in_row_width;
     175             :   }
     176             : 
     177           0 :   nb_bits = out_row_index - RADIOLIB_SX126X_LR_FHSS_HEADER_BITS * this->lrFhssHdrCount;
     178             : 
     179             :   // build the header
     180             :   uint8_t raw_header[RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2];
     181           0 :   raw_header[0] = in_len;
     182           0 :   raw_header[1] = (this->lrFhssCr << 3) | ((uint8_t)this->lrFhssGridNonFcc << 2) |
     183           0 :     (RADIOLIB_SX126X_LR_FHSS_HOPPING_ENABLED << 1) | (this->lrFhssBw >> 3);
     184           0 :   raw_header[2] = ((this->lrFhssBw & 0x07) << 5) | (this->lrFhssHopSeqId >> 4);
     185           0 :   raw_header[3] = ((this->lrFhssHopSeqId & 0x000F) << 4);
     186             : 
     187             :   // CRC-8 used seems to based on 8H2F, but without final XOR
     188           0 :   RadioLibCRCInstance.size = 8;
     189           0 :   RadioLibCRCInstance.poly = 0x2F;
     190           0 :   RadioLibCRCInstance.init = 0xFF;
     191           0 :   RadioLibCRCInstance.out = 0x00;
     192             : 
     193           0 :   uint16_t header_offset = 0;
     194           0 :   for(size_t i = 0; i < this->lrFhssHdrCount; i++) {
     195             :     // insert index and calculate the header CRC
     196           0 :     raw_header[3] = (raw_header[3] & ~0x0C) | ((this->lrFhssHdrCount - i - 1) << 2);
     197           0 :     raw_header[4] = RadioLibCRCInstance.checksum(raw_header, (RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2 - 1));
     198             : 
     199             :     // convolutional encode
     200           0 :     uint8_t coded_header[RADIOLIB_SX126X_LR_FHSS_HDR_BYTES] = { 0 };
     201           0 :     RadioLibConvCodeInstance.begin(2);
     202           0 :     RadioLibConvCodeInstance.encode(raw_header, 8*RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2, coded_header);
     203             :     // tail-biting seems to just do this twice ...?
     204           0 :     RadioLibConvCodeInstance.encode(raw_header, 8*RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2, coded_header);
     205             : 
     206             :     // clear guard bits
     207           0 :     CLEAR_BIT_IN_ARRAY_LSB(out, header_offset);
     208           0 :     CLEAR_BIT_IN_ARRAY_LSB(out, header_offset + 1);
     209             : 
     210             :     // interleave the header directly to the physical payload buffer
     211           0 :     for(size_t j = 0; j < (8*RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2); j++) {
     212           0 :       if(TEST_BIT_IN_ARRAY_LSB(coded_header, LrFhssHeaderInterleaver[j])) {
     213           0 :         SET_BIT_IN_ARRAY_LSB(out, header_offset + 2 + j);
     214             :       } else {
     215           0 :         CLEAR_BIT_IN_ARRAY_LSB(out, header_offset + 2 + j);
     216             :       }
     217             :     }
     218           0 :     for(size_t j = 0; j < (8*RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2); j++) {
     219           0 :       if(TEST_BIT_IN_ARRAY_LSB(coded_header, LrFhssHeaderInterleaver[(8*RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2) + j])) {
     220           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);
     221             :       } else {
     222           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);
     223             :       }
     224             :     }
     225             : 
     226             :     // copy the sync word to the physical payload buffer
     227           0 :     for(size_t j = 0; j < (8*RADIOLIB_SX126X_LR_FHSS_SYNC_WORD_BYTES); j++) {
     228           0 :       if(TEST_BIT_IN_ARRAY_LSB(this->lrFhssSyncWord, j)) {
     229           0 :         SET_BIT_IN_ARRAY_LSB(out, header_offset + 2 + (8*RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2) + j);
     230             :       } else {
     231           0 :         CLEAR_BIT_IN_ARRAY_LSB(out, header_offset + 2 + (8*RADIOLIB_SX126X_LR_FHSS_HDR_BYTES/2) + j);
     232             :       }
     233             :     }
     234             : 
     235           0 :     header_offset += RADIOLIB_SX126X_LR_FHSS_HEADER_BITS;
     236             :   }
     237             : 
     238             :   // calculate the number of hops and total number of bits
     239           0 :   uint16_t length_bits = (in_len + 2) * 8 + 6;
     240           0 :   switch(this->lrFhssCr) {
     241           0 :     case RADIOLIB_SX126X_LR_FHSS_CR_5_6:
     242           0 :       length_bits = ( ( length_bits * 6 ) + 4 ) / 5;
     243           0 :       break;
     244           0 :     case RADIOLIB_SX126X_LR_FHSS_CR_2_3:
     245           0 :       length_bits = length_bits * 3 / 2;
     246           0 :       break;
     247           0 :     case RADIOLIB_SX126X_LR_FHSS_CR_1_2:
     248           0 :       length_bits = length_bits * 2;
     249           0 :       break;
     250           0 :     case RADIOLIB_SX126X_LR_FHSS_CR_1_3:
     251           0 :       length_bits = length_bits * 3;
     252           0 :       break;
     253             :   }
     254             : 
     255           0 :   *out_hops = (length_bits + 47) / 48 + this->lrFhssHdrCount;
     256             : 
     257             :   // calculate total number of payload bits, after breaking into blocks
     258           0 :   uint16_t payload_bits = length_bits / RADIOLIB_SX126X_LR_FHSS_FRAG_BITS * RADIOLIB_SX126X_LR_FHSS_BLOCK_BITS;
     259           0 :   uint16_t last_block_bits = length_bits % RADIOLIB_SX126X_LR_FHSS_FRAG_BITS;
     260           0 :   if(last_block_bits > 0) {
     261             :     // add the 2 guard bits for the last block + the actual remaining payload bits
     262           0 :     payload_bits += last_block_bits + 2;
     263             :   }
     264             : 
     265           0 :   *out_bits = (RADIOLIB_SX126X_LR_FHSS_HEADER_BITS * this->lrFhssHdrCount) + payload_bits;
     266           0 :   *out_len = (*out_bits + 7) / 8;
     267             : 
     268           0 :   return(RADIOLIB_ERR_NONE);
     269             : }
     270             : 
     271           0 : int16_t SX126x::resetLRFHSS() {
     272             :   // initialize hopping configuration
     273           0 :   const uint16_t numChan[] = { 80, 176, 280, 376, 688, 792, 1480, 1584, 3120, 3224 };
     274             :   
     275             :   // LFSR polynomials for different ranges of lrFhssNgrid
     276           0 :   const uint8_t lfsrPoly1[] = { 33, 45, 48, 51, 54, 57 };
     277           0 :   const uint8_t lfsrPoly2[] = { 65, 68, 71, 72 };
     278           0 :   const uint8_t lfsrPoly3[] = { 142, 149 };
     279             : 
     280           0 :   uint32_t nb_channel_in_grid = this->lrFhssGridNonFcc ? 8 : 52;
     281           0 :   this->lrFhssNgrid = numChan[this->lrFhssBw] / nb_channel_in_grid;
     282           0 :   this->lrFhssLfsrState = 6;
     283           0 :   switch(this->lrFhssNgrid) {
     284           0 :     case 10:
     285             :     case 22:
     286             :     case 28:
     287             :     case 30:
     288             :     case 35:
     289             :     case 47:
     290           0 :       this->lrFhssPoly = lfsrPoly1[this->lrFhssHopSeqId >> 6];
     291           0 :       this->lrFhssSeed = this->lrFhssHopSeqId & 0x3F;
     292           0 :       if(this->lrFhssHopSeqId >= 384) {
     293           0 :         return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
     294             :       }
     295           0 :       break;
     296             :     
     297           0 :     case 60:
     298             :     case 62:
     299           0 :       this->lrFhssLfsrState = 56;
     300           0 :       this->lrFhssPoly = lfsrPoly1[this->lrFhssHopSeqId >> 6];
     301           0 :       this->lrFhssSeed = this->lrFhssHopSeqId & 0x3F;
     302           0 :       if(this->lrFhssHopSeqId >= 384) {
     303           0 :         return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
     304             :       }
     305           0 :       break;
     306             :     
     307           0 :     case 86:
     308             :     case 99:
     309           0 :       this->lrFhssPoly = lfsrPoly2[this->lrFhssHopSeqId >> 7];
     310           0 :       this->lrFhssSeed = this->lrFhssHopSeqId & 0x7F;
     311           0 :       break;
     312             :     
     313           0 :     case 185:
     314             :     case 198:
     315           0 :       this->lrFhssPoly = lfsrPoly3[this->lrFhssHopSeqId >> 8];
     316           0 :       this->lrFhssSeed = this->lrFhssHopSeqId & 0xFF;
     317           0 :       break;
     318             :     
     319           0 :     case 390:
     320             :     case 403:
     321           0 :       this->lrFhssPoly = 264;
     322           0 :       this->lrFhssSeed = this->lrFhssHopSeqId;
     323           0 :       break;
     324             :     
     325           0 :     default:
     326           0 :       return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
     327             :   }
     328             : 
     329           0 :   return(RADIOLIB_ERR_NONE);
     330             : }
     331             : 
     332           0 : uint16_t SX126x::stepLRFHSS() {
     333             :   uint16_t hop;
     334             :   do {
     335           0 :     uint16_t lsb = this->lrFhssLfsrState & 1;
     336           0 :     this->lrFhssLfsrState >>= 1;
     337           0 :     if(lsb) {
     338           0 :      this->lrFhssLfsrState ^= this->lrFhssPoly;
     339             :     }
     340           0 :     hop = this->lrFhssSeed;
     341           0 :     if(hop != this->lrFhssLfsrState) {
     342           0 :       hop ^= this->lrFhssLfsrState;
     343             :     }
     344           0 :   } while(hop > this->lrFhssNgrid);
     345           0 :   return(hop);
     346             : }
     347             : 
     348           0 : int16_t SX126x::setLRFHSSHop(uint8_t index) {
     349           0 :   if(!this->lrFhssFrameHopsRem) {
     350           0 :     return(RADIOLIB_ERR_NONE);
     351             :   }
     352             : 
     353           0 :   uint16_t hop = stepLRFHSS();
     354           0 :   int16_t freq_table = hop - 1;
     355           0 :   if(freq_table >= (int16_t)(this->lrFhssNgrid >> 1)) {
     356           0 :     freq_table -= this->lrFhssNgrid;
     357             :   }
     358             : 
     359           0 :   uint32_t nb_channel_in_grid = this->lrFhssGridNonFcc ? 8 : 52;
     360           0 :   uint32_t grid_offset = (1 + (this->lrFhssNgrid % 2)) * (nb_channel_in_grid / 2);
     361           0 :   uint32_t grid_in_pll_steps = this->lrFhssGridNonFcc ? 4096 : 26624;
     362           0 :   uint32_t frf = (this->freqMHz * (uint32_t(1) << RADIOLIB_SX126X_DIV_EXPONENT)) / RADIOLIB_SX126X_CRYSTAL_FREQ;
     363           0 :   uint32_t freq_raw = frf - freq_table * grid_in_pll_steps - grid_offset * 512;
     364             : 
     365           0 :   if((this->lrFhssHopNum < this->lrFhssHdrCount)) {
     366           0 :     if((((this->lrFhssHdrCount - this->lrFhssHopNum) % 2) == 0)) {
     367           0 :       freq_raw += 256;
     368             :     }
     369             :   }
     370             : 
     371           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) };
     372           0 :   int16_t state = writeRegister(RADIOLIB_SX126X_REG_LR_FHSS_FREQX_0(index), frq, sizeof(freq_raw));
     373           0 :   RADIOLIB_ASSERT(state);
     374             : 
     375             :   // (LR_FHSS_HEADER_BITS + pulse_shape_compensation) symbols on first sync_word, LR_FHSS_HEADER_BITS on
     376             :   // next sync_words, LR_FHSS_BLOCK_BITS on payload
     377           0 :   uint16_t numSymbols = RADIOLIB_SX126X_LR_FHSS_BLOCK_BITS;
     378           0 :   if(index == 0) {
     379           0 :     numSymbols = RADIOLIB_SX126X_LR_FHSS_HEADER_BITS + 1; // the +1 is "pulse_shape_compensation", but it's constant in the demo
     380           0 :   } else if(index < this->lrFhssHdrCount) {
     381           0 :     numSymbols = RADIOLIB_SX126X_LR_FHSS_HEADER_BITS;
     382           0 :   } else if(this->lrFhssFrameBitsRem < RADIOLIB_SX126X_LR_FHSS_BLOCK_BITS) {
     383           0 :     numSymbols = this->lrFhssFrameBitsRem;
     384             :   }
     385             : 
     386             :   // write hop length in symbols
     387           0 :   const uint8_t sym[2] = { (uint8_t)((numSymbols >> 8) & 0xFF), (uint8_t)(numSymbols & 0xFF) };
     388           0 :   state = writeRegister(RADIOLIB_SX126X_REG_LR_FHSS_NUM_SYMBOLS_FREQX_MSB(index), sym, sizeof(uint16_t));
     389           0 :   RADIOLIB_ASSERT(state);
     390             : 
     391           0 :   this->lrFhssFrameBitsRem -= numSymbols;
     392           0 :   this->lrFhssFrameHopsRem--;
     393           0 :   this->lrFhssHopNum++;
     394           0 :   return(RADIOLIB_ERR_NONE);
     395             : }
     396             : 
     397             : #endif

Generated by: LCOV version 1.14