LCOV - code coverage report
Current view: top level - src/utils - FEC.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 9 180 5.0 %
Date: 2025-10-24 15:14:50 Functions: 3 7 42.9 %

          Line data    Source code
       1             : #include "FEC.h"
       2             : #include <string.h>
       3             : 
       4           1 : RadioLibBCH::RadioLibBCH() {
       5             :   
       6           1 : }
       7             : 
       8           1 : RadioLibBCH::~RadioLibBCH() {
       9             :   #if !RADIOLIB_STATIC_ONLY
      10           1 :     delete[] this->alphaTo;
      11           1 :     delete[] this->indexOf;
      12           1 :     delete[] this->generator;
      13             :   #endif
      14           1 : }
      15             : 
      16             : /*
      17             :   BCH Encoder based on https://www.codeproject.com/articles/13189/pocsag-encoder
      18             : 
      19             :   Significantly cleaned up and slightly fixed.
      20             : */
      21           0 : void RadioLibBCH::begin(uint8_t n, uint8_t k, uint32_t poly) {
      22           0 :   this->n = n;
      23           0 :   this->k = k;
      24           0 :   this->poly = poly;
      25             :   #if !RADIOLIB_STATIC_ONLY
      26           0 :   this->alphaTo = new int32_t[n + 1];
      27           0 :   this->indexOf = new int32_t[n + 1];
      28           0 :   this->generator = new int32_t[n - k + 1];
      29             :   #endif
      30             : 
      31             :   // find the maximum power of the polynomial
      32           0 :   for(this->m = 0; this->m < 31; this->m++) {
      33           0 :     if((poly >> this->m) == 1) {
      34           0 :       break;
      35             :     }
      36             :   }
      37             : 
      38             :   /*
      39             :   * generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m]
      40             :   * lookup tables:  index->polynomial form   this->alphaTo[] contains j=alpha**i;
      41             :   * polynomial form -> index form  this->indexOf[j=alpha**i] = i alpha=2 is the
      42             :   * primitive element of GF(2**m)
      43             :   */
      44             : 
      45           0 :         int32_t mask = 1;
      46           0 :         this->alphaTo[this->m] = 0;
      47             : 
      48           0 :         for(uint8_t i = 0; i < this->m; i++) {
      49           0 :                 this->alphaTo[i] = mask;
      50             : 
      51           0 :                 this->indexOf[this->alphaTo[i]] = i;
      52             : 
      53           0 :     if(this->poly & ((uint32_t)0x01 << i)) {
      54           0 :       this->alphaTo[this->m] ^= mask;
      55             :     }
      56             : 
      57           0 :                 mask <<= 1;
      58             :         }
      59             : 
      60           0 :         this->indexOf[this->alphaTo[this->m]] = this->m;
      61           0 :         mask >>= 1;
      62             : 
      63           0 :         for(uint8_t i = this->m + 1; i < this->n; i++) {
      64           0 :                 if(this->alphaTo[i - 1] >= mask) {
      65           0 :       this->alphaTo[i] = this->alphaTo[this->m] ^ ((this->alphaTo[i - 1] ^ mask) << 1);
      66             :     } else {
      67           0 :       this->alphaTo[i] = this->alphaTo[i - 1] << 1;
      68             :     }
      69             : 
      70           0 :                 this->indexOf[this->alphaTo[i]] = i;
      71             :         }
      72             : 
      73           0 :         this->indexOf[0] = -1;
      74             : 
      75             :   /*
      76             :         * Compute generator polynomial of BCH code of length = 31, redundancy = 10
      77             :         * (OK, this is not very efficient, but we only do it once, right? :)
      78             :         */
      79             : 
      80           0 :         int32_t ii = 0;
      81           0 :   int32_t jj = 1;
      82           0 :   int32_t ll = 0;
      83           0 :   int32_t kaux = 0;
      84           0 :   bool test = false;
      85           0 :         int32_t aux = 0;
      86           0 :         int32_t cycle[15][6] = { { 0 } };
      87           0 :   int32_t size[15] = { 0 };
      88             : 
      89             :         // Generate cycle sets modulo 31
      90           0 :         cycle[0][0] = 0; size[0] = 1;
      91           0 :         cycle[1][0] = 1; size[1] = 1;
      92             : 
      93             :         do {
      94             :                 // Generate the jj-th cycle set
      95           0 :                 ii = 0;
      96             :                 do {
      97           0 :                         ii++;
      98           0 :                         cycle[jj][ii] = (cycle[jj][ii - 1] * 2) % this->n;
      99           0 :                         size[jj]++;
     100           0 :                         aux = (cycle[jj][ii] * 2) % this->n;
     101           0 :                 } while(aux != cycle[jj][0]);
     102             : 
     103             :                 // Next cycle set representative
     104           0 :                 ll = 0;
     105             :                 do {
     106           0 :                         ll++;
     107           0 :                         test = false;
     108           0 :                         for(ii = 1; ((ii <= jj) && !test); ii++) {
     109             :         // Examine previous cycle sets
     110           0 :                           for(kaux = 0; ((kaux < size[ii]) && !test); kaux++) {
     111           0 :           test = (ll == cycle[ii][kaux]);
     112             :         }
     113             :       }
     114           0 :                 } while(test && (ll < (this->n - 1)));
     115             : 
     116           0 :                 if(!test) {
     117           0 :                         jj++;   // next cycle set index
     118           0 :                         cycle[jj][0] = ll;
     119           0 :                         size[jj] = 1;
     120             :                 }
     121             : 
     122           0 :         } while(ll < (this->n - 1));
     123             : 
     124             :         // Search for roots 1, 2, ..., m-1 in cycle sets
     125           0 :         int32_t rdncy = 0;
     126             :   #if RADIOLIB_STATIC_ONLY
     127             :     int32_t min[RADIOLIB_BCH_MAX_N - RADIOLIB_BCH_MAX_K + 1] = { 0 };
     128             :   #else
     129           0 :     int32_t* min = new int32_t[this->n - this->k + 1];
     130             :   #endif
     131           0 :         kaux = 0;
     132             : 
     133             :   // ensure the first element is always initializer
     134           0 :   min[0] = 0;
     135             : 
     136           0 :         for(ii = 1; ii <= jj; ii++) {
     137           0 :                 min[kaux] = 0;
     138           0 :                 for(jj = 0; jj < size[ii]; jj++) {
     139           0 :       for(uint8_t root = 1; root < this->m; root++) {
     140           0 :         if(root == cycle[ii][jj]) {
     141           0 :           min[kaux] = ii;
     142             :         }
     143             :       }
     144             :     }
     145             : 
     146           0 :                 if(min[kaux]) {
     147           0 :                         rdncy += size[min[kaux]];
     148           0 :                         kaux++;
     149             :                 }
     150             :         }
     151             : 
     152           0 :         int32_t noterms = kaux;
     153             :   #if RADIOLIB_STATIC_ONLY
     154             :     int32_t zeros[RADIOLIB_BCH_MAX_N - RADIOLIB_BCH_MAX_K + 1] = { 0 };
     155             :   #else
     156           0 :     int32_t* zeros = new int32_t[this->n - this->k + 1];
     157             :   #endif
     158           0 :         kaux = 1;
     159             : 
     160             :   // ensure the first element is always initializer
     161           0 :   zeros[1] = 0;
     162             : 
     163           0 :         for(ii = 0; ii < noterms; ii++) {
     164           0 :     for(jj = 0; jj < size[min[ii]]; jj++) {
     165           0 :                         zeros[kaux] = cycle[min[ii]][jj];
     166           0 :                         kaux++;
     167             :                 }
     168             :   }
     169             : 
     170             :   #if !RADIOLIB_STATIC_ONLY
     171           0 :   delete[] min;
     172             :   #endif
     173             : 
     174             :         // Compute generator polynomial
     175           0 :         this->generator[0] = this->alphaTo[zeros[1]];
     176           0 :         this->generator[1] = 1;              // g(x) = (X + zeros[1]) initially
     177             : 
     178           0 :         for(ii = 2; ii <= rdncy; ii++) {
     179           0 :           this->generator[ii] = 1;
     180           0 :           for(jj = ii - 1; jj > 0; jj--) {
     181           0 :       if(this->generator[jj] != 0) {
     182           0 :         this->generator[jj] = this->generator[jj - 1] ^ this->alphaTo[(this->indexOf[this->generator[jj]] + zeros[ii]) % this->n];
     183             :       } else {
     184           0 :         this->generator[jj] = this->generator[jj - 1];
     185             :       }
     186             :     }
     187           0 :                 this->generator[0] = this->alphaTo[(this->indexOf[this->generator[0]] + zeros[ii]) % this->n];
     188             :         }
     189             : 
     190             :   #if !RADIOLIB_STATIC_ONLY
     191           0 :   delete[] zeros;
     192             :   #endif
     193           0 : }
     194             : 
     195             : /*
     196             :   BCH Encoder based on https://www.codeproject.com/articles/13189/pocsag-encoder
     197             : 
     198             :   Significantly cleaned up and slightly fixed.
     199             : */
     200           0 : uint32_t RadioLibBCH::encode(uint32_t dataword) {
     201             :   // we only use the "k" most significant bits
     202             :   #if RADIOLIB_STATIC_ONLY
     203             :     int32_t data[RADIOLIB_BCH_MAX_K] = { 0 };
     204             :   #else
     205           0 :     int32_t* data = new int32_t[this->k];
     206           0 :     memset(data, 0, this->k*sizeof(int32_t));
     207             :   #endif
     208           0 :         int32_t j1 = 0;
     209           0 :         for(int32_t i = this->n; i > (this->n - this->k); i--) {
     210           0 :                 if(dataword & ((uint32_t)1<<i)) {
     211           0 :       data[j1++]=1;
     212             :     } else {
     213           0 :       data[j1++]=0;
     214             :     }
     215             :         }
     216             : 
     217             :   // reset the M(x)+r array elements
     218             :   #if RADIOLIB_STATIC_ONLY
     219             :     int32_t Mr[RADIOLIB_BCH_MAX_N] = { 0 };
     220             :   #else
     221           0 :     int32_t* Mr = new int32_t[this->n];
     222           0 :     memset(Mr, 0x00, this->n*sizeof(int32_t));
     223             :   #endif
     224             : 
     225             :   // copy the contents of data into Mr and add the zeros
     226           0 :   memcpy(Mr, data, this->k*sizeof(int32_t));
     227             : 
     228           0 :   int32_t j = 0;
     229           0 :   int32_t start = 0;
     230           0 :   int32_t end = this->n - this->k;
     231           0 :   while(end < this->n) {
     232           0 :     for(int32_t i = end; i > start-2; --i) {
     233           0 :       if(Mr[start]) {
     234           0 :         Mr[i] ^= this->generator[j];
     235           0 :         ++j;
     236             :       } else {
     237           0 :         ++start;
     238           0 :         j = 0;
     239           0 :         end = start + this->n - this->k;
     240           0 :         break;
     241             :       }
     242             :     }
     243             :   }
     244             : 
     245             :   #if RADIOLIB_STATIC_ONLY
     246             :     int32_t bb[RADIOLIB_BCH_MAX_N - RADIOLIB_BCH_MAX_K + 1] = { 0 };
     247             :   #else
     248           0 :     int32_t* bb = new int32_t[this->n - this->k + 1];
     249           0 :     memset(bb, 0, (this->n - this->k + 1)*sizeof(int32_t));
     250             :   #endif
     251           0 :   j = 0;
     252           0 :   for(int32_t i = start; i < end; ++i) {
     253           0 :     bb[j] = Mr[i];
     254           0 :     ++j;
     255             :   }
     256             : 
     257             :   #if !RADIOLIB_STATIC_ONLY
     258           0 :   delete[] Mr;
     259             :   #endif
     260             : 
     261           0 :         int32_t iEvenParity = 0;
     262             :   #if RADIOLIB_STATIC_ONLY
     263             :     int32_t recd[RADIOLIB_BCH_MAX_N + 1];
     264             :   #else
     265           0 :     int32_t* recd = new int32_t[this->n + 1];
     266             :   #endif
     267           0 :         for(uint8_t i = 0; i < this->k; i++) {
     268           0 :                 recd[this->n - i] = data[i];
     269           0 :                 if(data[i] == 1) {
     270           0 :       iEvenParity++;
     271             :     }
     272             :         }
     273             :   
     274             :   #if !RADIOLIB_STATIC_ONLY
     275           0 :   delete[] data;
     276             :   #endif
     277             : 
     278           0 :         for(uint8_t i = 0; i < this->n - this->k + 1; i++) {
     279           0 :                 recd[this->n - this->k - i] = bb[i];
     280           0 :                 if(bb[i] == 1) {
     281           0 :       iEvenParity++;
     282             :     }
     283             :         }
     284             :   
     285             :   #if !RADIOLIB_STATIC_ONLY
     286           0 :   delete[] bb;
     287             :   #endif
     288             : 
     289           0 :         if((iEvenParity % 2) == 0) {
     290           0 :     recd[0] = 0;
     291             :   } else {
     292           0 :     recd[0] = 1;
     293             :   }
     294             : 
     295           0 :   int32_t res = 0;
     296           0 :         for(int32_t i = 0; i < this->n + 1; i++) {
     297           0 :                 if(recd[i]) {
     298           0 :       res |= ((uint32_t)1<<i);
     299             :     }
     300             :         }
     301             : 
     302             :   #if !RADIOLIB_STATIC_ONLY
     303           0 :   delete[] recd;
     304             :   #endif
     305             : 
     306           0 :         return(res);
     307             : }
     308             : 
     309             : RadioLibBCH RadioLibBCHInstance;
     310             : 
     311           1 : RadioLibConvCode::RadioLibConvCode() {
     312             : 
     313           1 : }
     314             : 
     315           0 : void RadioLibConvCode::begin(uint8_t rt) {
     316           0 :   this->enc_state = 0;
     317           0 :   this->rate = rt;
     318           0 : }
     319             : 
     320           0 : int16_t RadioLibConvCode::encode(const uint8_t* in, size_t in_bits, uint8_t* out, size_t* out_bits) {
     321           0 :   if(!in || !out) {
     322           0 :     return(RADIOLIB_ERR_UNKNOWN);
     323             :   }
     324             : 
     325             :   size_t ind_bit;
     326           0 :   uint16_t data_out_bitcount = 0;
     327           0 :   uint32_t bin_out_word = 0;
     328             : 
     329             :   // iterate over the provided bits
     330           0 :   for(ind_bit = 0; ind_bit < in_bits; ind_bit++) {
     331           0 :     uint8_t cur_bit = GET_BIT_IN_ARRAY_LSB(in, ind_bit);
     332           0 :     const uint32_t* lut_ptr = (this->rate == 2) ? ConvCodeTable1_2 : ConvCodeTable1_3;
     333           0 :     uint8_t word_pos = this->enc_state / 4;
     334           0 :     uint8_t byte_pos = (3 - (this->enc_state % 4)) * 8;
     335           0 :     uint8_t nibble_pos = (1 - cur_bit) * 4;
     336           0 :     uint8_t g1g0 = (lut_ptr[word_pos] >> (byte_pos + nibble_pos)) & 0x0F;
     337             : 
     338           0 :     uint8_t mod = this->rate == 2 ? 16 : 64;
     339           0 :     this->enc_state = (this->enc_state * 2 + cur_bit) % mod;
     340           0 :     bin_out_word |= (g1g0 << ((7 - (ind_bit % 8)) * this->rate));
     341           0 :     if(ind_bit % 8 == 7) {
     342           0 :       if(this->rate == 3) {
     343           0 :         *out++ = (uint8_t)(bin_out_word >> 16);
     344             :       }
     345           0 :       *out++ = (uint8_t)(bin_out_word >> 8);
     346           0 :       *out++ = (uint8_t)bin_out_word;
     347           0 :       bin_out_word  = 0;
     348             :     }
     349           0 :     data_out_bitcount += this->rate;
     350             :   }
     351             : 
     352           0 :   if(ind_bit % 8) {
     353           0 :     if(this->rate == 3) {
     354           0 :       *out++ = (uint8_t)(bin_out_word >> 16);
     355             :     }
     356           0 :     *out++ = (uint8_t)(bin_out_word >> 8);
     357           0 :     *out++ = (uint8_t)bin_out_word;
     358             :   }
     359             : 
     360           0 :   if(out_bits) { *out_bits = data_out_bitcount; }
     361             : 
     362           0 :   return(RADIOLIB_ERR_NONE);
     363             : }
     364             : 
     365             : RadioLibConvCode RadioLibConvCodeInstance;

Generated by: LCOV version 1.14