LCOV - code coverage report
Current view: top level - src/utils - ReedSolomon.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 100 105 95.2 %
Date: 2026-10-11 07:31:10 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /* General purpose Reed-Solomon codec for 8-bit symbols or less
       2             :  * Copyright 2003 Phil Karn, KA9Q
       3             :  * May be used under the terms of the GNU Lesser General Public License (LGPL)
       4             :  *
       5             :  * This version tweaked by Philip Heron <phil@sanslogic.co.uk>
       6             : */
       7             : 
       8             : #include <string.h>
       9             : #include "ReedSolomon.h"
      10             : 
      11             : static const uint8_t ALPHA_TO[] = {
      12             :   0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x87,0x89,0x95,0xAD,0xDD,0x3D,0x7A,0xF4,
      13             :   0x6F,0xDE,0x3B,0x76,0xEC,0x5F,0xBE,0xFB,0x71,0xE2,0x43,0x86,0x8B,0x91,0xA5,0xCD,
      14             :   0x1D,0x3A,0x74,0xE8,0x57,0xAE,0xDB,0x31,0x62,0xC4,0x0F,0x1E,0x3C,0x78,0xF0,0x67,
      15             :   0xCE,0x1B,0x36,0x6C,0xD8,0x37,0x6E,0xDC,0x3F,0x7E,0xFC,0x7F,0xFE,0x7B,0xF6,0x6B,
      16             :   0xD6,0x2B,0x56,0xAC,0xDF,0x39,0x72,0xE4,0x4F,0x9E,0xBB,0xF1,0x65,0xCA,0x13,0x26,
      17             :   0x4C,0x98,0xB7,0xE9,0x55,0xAA,0xD3,0x21,0x42,0x84,0x8F,0x99,0xB5,0xED,0x5D,0xBA,
      18             :   0xF3,0x61,0xC2,0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x07,0x0E,0x1C,0x38,0x70,0xE0,
      19             :   0x47,0x8E,0x9B,0xB1,0xE5,0x4D,0x9A,0xB3,0xE1,0x45,0x8A,0x93,0xA1,0xC5,0x0D,0x1A,
      20             :   0x34,0x68,0xD0,0x27,0x4E,0x9C,0xBF,0xF9,0x75,0xEA,0x53,0xA6,0xCB,0x11,0x22,0x44,
      21             :   0x88,0x97,0xA9,0xD5,0x2D,0x5A,0xB4,0xEF,0x59,0xB2,0xE3,0x41,0x82,0x83,0x81,0x85,
      22             :   0x8D,0x9D,0xBD,0xFD,0x7D,0xFA,0x73,0xE6,0x4B,0x96,0xAB,0xD1,0x25,0x4A,0x94,0xAF,
      23             :   0xD9,0x35,0x6A,0xD4,0x2F,0x5E,0xBC,0xFF,0x79,0xF2,0x63,0xC6,0x0B,0x16,0x2C,0x58,
      24             :   0xB0,0xE7,0x49,0x92,0xA3,0xC1,0x05,0x0A,0x14,0x28,0x50,0xA0,0xC7,0x09,0x12,0x24,
      25             :   0x48,0x90,0xA7,0xC9,0x15,0x2A,0x54,0xA8,0xD7,0x29,0x52,0xA4,0xCF,0x19,0x32,0x64,
      26             :   0xC8,0x17,0x2E,0x5C,0xB8,0xF7,0x69,0xD2,0x23,0x46,0x8C,0x9F,0xB9,0xF5,0x6D,0xDA,
      27             :   0x33,0x66,0xCC,0x1F,0x3E,0x7C,0xF8,0x77,0xEE,0x5B,0xB6,0xEB,0x51,0xA2,0xC3,0x00,
      28             : };
      29             : 
      30             : static const uint8_t INDEX_OF[] = {
      31             :   0xFF,0x00,0x01,0x63,0x02,0xC6,0x64,0x6A,0x03,0xCD,0xC7,0xBC,0x65,0x7E,0x6B,0x2A,
      32             :   0x04,0x8D,0xCE,0x4E,0xC8,0xD4,0xBD,0xE1,0x66,0xDD,0x7F,0x31,0x6C,0x20,0x2B,0xF3,
      33             :   0x05,0x57,0x8E,0xE8,0xCF,0xAC,0x4F,0x83,0xC9,0xD9,0xD5,0x41,0xBE,0x94,0xE2,0xB4,
      34             :   0x67,0x27,0xDE,0xF0,0x80,0xB1,0x32,0x35,0x6D,0x45,0x21,0x12,0x2C,0x0D,0xF4,0x38,
      35             :   0x06,0x9B,0x58,0x1A,0x8F,0x79,0xE9,0x70,0xD0,0xC2,0xAD,0xA8,0x50,0x75,0x84,0x48,
      36             :   0xCA,0xFC,0xDA,0x8A,0xD6,0x54,0x42,0x24,0xBF,0x98,0x95,0xF9,0xE3,0x5E,0xB5,0x15,
      37             :   0x68,0x61,0x28,0xBA,0xDF,0x4C,0xF1,0x2F,0x81,0xE6,0xB2,0x3F,0x33,0xEE,0x36,0x10,
      38             :   0x6E,0x18,0x46,0xA6,0x22,0x88,0x13,0xF7,0x2D,0xB8,0x0E,0x3D,0xF5,0xA4,0x39,0x3B,
      39             :   0x07,0x9E,0x9C,0x9D,0x59,0x9F,0x1B,0x08,0x90,0x09,0x7A,0x1C,0xEA,0xA0,0x71,0x5A,
      40             :   0xD1,0x1D,0xC3,0x7B,0xAE,0x0A,0xA9,0x91,0x51,0x5B,0x76,0x72,0x85,0xA1,0x49,0xEB,
      41             :   0xCB,0x7C,0xFD,0xC4,0xDB,0x1E,0x8B,0xD2,0xD7,0x92,0x55,0xAA,0x43,0x0B,0x25,0xAF,
      42             :   0xC0,0x73,0x99,0x77,0x96,0x5C,0xFA,0x52,0xE4,0xEC,0x5F,0x4A,0xB6,0xA2,0x16,0x86,
      43             :   0x69,0xC5,0x62,0xFE,0x29,0x7D,0xBB,0xCC,0xE0,0xD3,0x4D,0x8C,0xF2,0x1F,0x30,0xDC,
      44             :   0x82,0xAB,0xE7,0x56,0xB3,0x93,0x40,0xD8,0x34,0xB0,0xEF,0x26,0x37,0x0C,0x11,0x44,
      45             :   0x6F,0x78,0x19,0x9A,0x47,0x74,0xA7,0xC1,0x23,0x53,0x89,0xFB,0x14,0x5D,0xF8,0x97,
      46             :   0x2E,0x4B,0xB9,0x60,0x0F,0xED,0x3E,0xE5,0xF6,0x87,0xA5,0x17,0x3A,0xA3,0x3C,0xB7,
      47             : };
      48             : 
      49             : static const uint8_t GENPOLY[] = {
      50             :   0x00,0xF9,0x3B,0x42,0x04,0x2B,0x7E,0xFB,0x61,0x1E,0x03,0xD5,0x32,0x42,0xAA,0x05,
      51             :   0x18,0x05,0xAA,0x42,0x32,0xD5,0x03,0x1E,0x61,0xFB,0x7E,0x2B,0x04,0x42,0x3B,0xF9,
      52             :   0x00,
      53             : };
      54             : 
      55       75103 : static inline int mod255(int x)
      56             : {
      57      132382 :   while(x >= 255)
      58             :   {
      59       57279 :     x -= 255;
      60       57279 :     x = (x >> 8) + (x & 255);
      61             :   }
      62       75103 :   return(x);
      63             : }
      64             : #define MODNN(x) mod255(x)
      65             : 
      66             : #define MM     (8)
      67             : #define NN     (255)
      68             : #define NROOTS (32)
      69             : #define FCR    (112)
      70             : #define PRIM   (11)
      71             : #define IPRIM  (116)
      72             : 
      73             : #define MIN(a,b) ((a) < (b) ? (a) : (b))
      74             : #define A0       (NN) /* Special reserved value encoding zero in index form */
      75             : 
      76             : /* Portable C version */
      77           3 : void rlb_encode_rs_8(const uint8_t *data, uint8_t *parity, int pad)
      78             : {
      79             :   int i, j;
      80             :   
      81           3 :   memset(parity, 0, NROOTS * sizeof(uint8_t));
      82             :   
      83         662 :   for(i = 0; i < NN - NROOTS - pad; i++)
      84             :   {
      85         659 :     uint8_t feedback = INDEX_OF[data[i] ^ parity[0]];
      86         659 :     if(feedback != A0) /* feedback term is non-zero */
      87             :     {
      88       21088 :       for(j = 1; j < NROOTS; j++)
      89       20429 :         parity[j] ^= ALPHA_TO[mod255(feedback + GENPOLY[NROOTS - j])];
      90             :     }
      91             :     
      92             :     /* Shift */
      93         659 :     memmove(&parity[0], &parity[1], sizeof(uint8_t) * (NROOTS - 1));
      94         659 :     if(feedback != A0)
      95         659 :       parity[NROOTS - 1] = ALPHA_TO[mod255(feedback + GENPOLY[0])];
      96             :     else
      97           0 :       parity[NROOTS - 1] = 0;
      98             :   }
      99           3 : }
     100             : 
     101           6 : int rlb_decode_rs_8(uint8_t *data, int *eras_pos, int no_eras, int pad)
     102             : {
     103             :   int deg_lambda, el, deg_omega;
     104             :   int i, j, r, k;
     105             :   uint8_t u, q, tmp, num1, num2, den, discr_r;
     106             :   uint8_t lambda[NROOTS + 1], s[NROOTS]; /* Err+Eras Locator poly
     107             :                                           * and syndrome poly */
     108             :   uint8_t b[NROOTS + 1], t[NROOTS + 1], omega[NROOTS + 1];
     109             :   uint8_t root[NROOTS], reg[NROOTS + 1], loc[NROOTS];
     110             :   int syn_error, count;
     111             :   
     112           6 :   if(pad < 0 || pad > 222) return(-1);
     113             :   
     114             :   /* form the syndromes; i.e., evaluate data(x) at roots of g(x) */
     115         198 :   for(i = 0; i < NROOTS; i++) s[i] = data[0];
     116             :   
     117        1520 :   for(j = 1; j < NN - pad; j++)
     118             :   {
     119       49962 :     for(i = 0; i < NROOTS; i++)
     120             :     {
     121       48448 :       if(s[i] == 0) s[i] = data[j];
     122       48161 :       else s[i] = data[j] ^ ALPHA_TO[MODNN(INDEX_OF[s[i]] + (FCR + i) * PRIM)];
     123             :     }
     124             :   }
     125             :   
     126             :   /* Convert syndromes to index form, checking for nonzero condition */
     127           6 :   syn_error = 0;
     128         198 :   for(i = 0; i < NROOTS; i++)
     129             :   {
     130         192 :     syn_error |= s[i];
     131         192 :     s[i] = INDEX_OF[s[i]];
     132             :   }
     133             :   
     134           6 :   if(!syn_error)
     135             :   {
     136             :     /* if syndrome is zero, data[] is a codeword and there are no
     137             :      * errors to correct. So return data[] unmodified
     138             :      */
     139           2 :     count = 0;
     140           2 :     goto finish;
     141             :   }
     142             :   
     143           4 :   memset(&lambda[1], 0, NROOTS * sizeof(lambda[0]));
     144           4 :   lambda[0] = 1;
     145             :   
     146           4 :   if(no_eras > 0)
     147             :   {
     148             :     /* Init lambda to be the erasure locator polynomial */
     149           1 :     lambda[1] = ALPHA_TO[MODNN(PRIM * (NN - 1 - eras_pos[0]))];
     150           1 :     for(i = 1; i < no_eras; i++)
     151             :     {
     152           0 :       u = MODNN(PRIM * (NN - 1 - eras_pos[i]));
     153           0 :       for(j = i + 1; j > 0; j--)
     154             :       {
     155           0 :         tmp = INDEX_OF[lambda[j - 1]];
     156           0 :         if(tmp != A0) lambda[j] ^= ALPHA_TO[MODNN(u + tmp)];
     157             :       }
     158             :     }
     159             :     
     160             :   }
     161             :   
     162         136 :   for(i = 0; i < NROOTS + 1; i++)
     163         132 :     b[i] = INDEX_OF[lambda[i]];
     164             :   
     165             :   /*
     166             :    * Begin Berlekamp-Massey algorithm to determine error+erasure
     167             :    * locator polynomial
     168             :    */
     169           4 :   r = no_eras;
     170           4 :   el = no_eras;
     171         131 :   while(++r <= NROOTS) /* r is the step number */
     172             :   {
     173             :     /* Compute discrepancy at the r-th step in poly-form */
     174         127 :     discr_r = 0;
     175        2238 :     for(i = 0; i < r; i++)
     176             :     {
     177        2111 :       if((lambda[i] != 0) && (s[r - i - 1] != A0))
     178             :       {
     179         456 :         discr_r ^= ALPHA_TO[MODNN(INDEX_OF[lambda[i]] + s[r - i - 1])];
     180             :       }
     181             :     }
     182         127 :     discr_r = INDEX_OF[discr_r]; /* Index form */
     183         127 :     if(discr_r == A0)
     184             :     {
     185             :       /* 2 lines below: B(x) <-- x*B(x) */
     186          92 :       memmove(&b[1], b, NROOTS * sizeof(b[0]));
     187          92 :       b[0] = A0;
     188             :     }
     189             :     else
     190             :     {
     191             :       /* 7 lines below: T(x) <-- lambda(x) - discr_r*x*b(x) */
     192          35 :       t[0] = lambda[0];
     193        1155 :       for(i = 0; i < NROOTS; i++)
     194             :       {
     195        1120 :         if(b[i] != A0)
     196         248 :           t[i + 1] = lambda[i + 1] ^ ALPHA_TO[MODNN(discr_r + b[i])];
     197             :         else
     198         872 :           t[i + 1] = lambda[i + 1];
     199             :       }
     200             :       
     201          35 :       if(2 * el <= r + no_eras - 1)
     202             :       {
     203          17 :         el = r + no_eras - el;
     204             :         /*
     205             :          * 2 lines below: B(x) <-- inv(discr_r) *
     206             :          * lambda(x)
     207             :          */
     208         578 :         for(i = 0; i <= NROOTS; i++)
     209         561 :           b[i] = (lambda[i] == 0) ? A0 : MODNN(INDEX_OF[lambda[i]] - discr_r + NN);
     210             :       }
     211             :       else
     212             :       {
     213             :         /* 2 lines below: B(x) <-- x*B(x) */
     214          18 :         memmove(&b[1], b, NROOTS * sizeof(b[0]));
     215          18 :         b[0] = A0;
     216             :       }
     217             :       
     218          35 :       memcpy(lambda, t, (NROOTS + 1) * sizeof(t[0]));
     219             :     }
     220             :   }
     221             :   
     222             :   /* Convert lambda to index form and compute deg(lambda(x)) */
     223           4 :   deg_lambda = 0;
     224         136 :   for(i = 0; i < NROOTS + 1; i++)
     225             :   {
     226         132 :     lambda[i] = INDEX_OF[lambda[i]];
     227         132 :     if(lambda[i] != A0) deg_lambda = i;
     228             :   }
     229             :   
     230             :   /* Find roots of the error+erasure locator polynomial by Chien search */
     231           4 :   memcpy(&reg[1], &lambda[1], NROOTS * sizeof(reg[0]));
     232           4 :   count = 0; /* Number of roots of lambda(x) */
     233         594 :   for(i = 1, k = IPRIM - 1; i <= NN; i++, k = MODNN(k + IPRIM))
     234             :   {
     235         593 :     q = 1; /* lambda[0] is always 0 */
     236        5011 :     for(j = deg_lambda; j > 0; j--)
     237             :     {
     238        4418 :       if(reg[j] != A0)
     239             :       {
     240        4418 :         reg[j] = MODNN(reg[j] + j);
     241        4418 :         q ^= ALPHA_TO[reg[j]];
     242             :       }
     243             :     }
     244             :     
     245         593 :     if (q != 0) continue; /* Not a root */
     246             :     
     247             :     /* store root (index-form) and error location number */
     248           5 :     root[count] = i;
     249           5 :     loc[count] = k;
     250             :     /* If we've already found max possible roots,
     251             :      * abort the search to save time
     252             :      */
     253           5 :     if(++count == deg_lambda) break;
     254             :   }
     255             :   
     256           4 :   if(deg_lambda != count)
     257             :   {
     258             :     /*
     259             :      * deg(lambda) unequal to number of roots => uncorrectable
     260             :      * error detected
     261             :      */
     262           1 :     count = -1;
     263           1 :     goto finish;
     264             :   }
     265             :   
     266             :   /*
     267             :    * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
     268             :    * x**NROOTS). in index form. Also find deg(omega).
     269             :    */
     270           3 :   deg_omega = deg_lambda - 1;
     271           6 :   for(i = 0; i <= deg_omega; i++)
     272             :   {
     273           3 :     tmp = 0;
     274           6 :     for(j = i; j >= 0; j--)
     275             :     {
     276           3 :       if((s[i - j] != A0) && (lambda[j] != A0))
     277           3 :         tmp ^= ALPHA_TO[MODNN(s[i - j] + lambda[j])];
     278             :     }
     279           3 :     omega[i] = INDEX_OF[tmp];
     280             :   }
     281             :   
     282             :   /*
     283             :    * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
     284             :    * inv(X(l))**(FCR-1) and den = lambda_pr(inv(X(l))) all in poly-form
     285             :    */
     286           6 :   for(j = count - 1; j >= 0; j--)
     287             :   {
     288           3 :     num1 = 0;
     289           6 :     for(i = deg_omega; i >= 0; i--)
     290             :     {
     291           3 :       if(omega[i] != A0) num1 ^= ALPHA_TO[MODNN(omega[i] + i * root[j])];
     292             :     }
     293           3 :     num2 = ALPHA_TO[MODNN(root[j] * (FCR - 1) + NN)];
     294           3 :     den = 0;
     295             :     
     296             :     /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
     297           6 :     for(i = MIN(deg_lambda, NROOTS - 1) & ~1; i >= 0; i -= 2)
     298             :     {
     299           3 :       if(lambda[i + 1] != A0) den ^= ALPHA_TO[MODNN(lambda[i + 1] + i * root[j])];
     300             :     }
     301             :     
     302             :     /* Apply error to data */
     303           3 :     if(num1 != 0 && loc[j] >= pad)
     304             :     {
     305           3 :       data[loc[j] - pad] ^= ALPHA_TO[MODNN(INDEX_OF[num1] + INDEX_OF[num2] + NN - INDEX_OF[den])];
     306             :     }
     307             :   }
     308             :   
     309           3 : finish:
     310           6 :   if(eras_pos != NULL)
     311             :   {
     312           2 :     for(i = 0; i < count; i++) eras_pos[i] = loc[i];
     313             :   }
     314             :   
     315           6 :   return(count);
     316             : }

Generated by: LCOV version 1.14