xref: /aosp_15_r20/external/fec/decode_rs.c (revision 638691a093b4f9473cd6ee8f3e0139deef159a86)
1*638691a0SAndroid Build Coastguard Worker /* Reed-Solomon decoder
2*638691a0SAndroid Build Coastguard Worker  * Copyright 2002 Phil Karn, KA9Q
3*638691a0SAndroid Build Coastguard Worker  * May be used under the terms of the GNU Lesser General Public License (LGPL)
4*638691a0SAndroid Build Coastguard Worker  */
5*638691a0SAndroid Build Coastguard Worker 
6*638691a0SAndroid Build Coastguard Worker #ifdef DEBUG
7*638691a0SAndroid Build Coastguard Worker #include <stdio.h>
8*638691a0SAndroid Build Coastguard Worker #endif
9*638691a0SAndroid Build Coastguard Worker 
10*638691a0SAndroid Build Coastguard Worker #include <string.h>
11*638691a0SAndroid Build Coastguard Worker 
12*638691a0SAndroid Build Coastguard Worker #define NULL ((void *)0)
13*638691a0SAndroid Build Coastguard Worker #define	min(a,b)	((a) < (b) ? (a) : (b))
14*638691a0SAndroid Build Coastguard Worker 
15*638691a0SAndroid Build Coastguard Worker #ifdef FIXED
16*638691a0SAndroid Build Coastguard Worker #include "fixed.h"
17*638691a0SAndroid Build Coastguard Worker #elif defined(BIGSYM)
18*638691a0SAndroid Build Coastguard Worker #include "int.h"
19*638691a0SAndroid Build Coastguard Worker #else
20*638691a0SAndroid Build Coastguard Worker #include "char.h"
21*638691a0SAndroid Build Coastguard Worker #endif
22*638691a0SAndroid Build Coastguard Worker 
DECODE_RS(data_t * data,int * eras_pos,int no_eras,int pad)23*638691a0SAndroid Build Coastguard Worker int DECODE_RS(
24*638691a0SAndroid Build Coastguard Worker #ifdef FIXED
25*638691a0SAndroid Build Coastguard Worker data_t *data, int *eras_pos, int no_eras,int pad){
26*638691a0SAndroid Build Coastguard Worker #else
27*638691a0SAndroid Build Coastguard Worker void *p,data_t *data, int *eras_pos, int no_eras){
28*638691a0SAndroid Build Coastguard Worker   struct rs *rs = (struct rs *)p;
29*638691a0SAndroid Build Coastguard Worker #endif
30*638691a0SAndroid Build Coastguard Worker   int deg_lambda, el, deg_omega;
31*638691a0SAndroid Build Coastguard Worker   int i, j, r,k;
32*638691a0SAndroid Build Coastguard Worker   data_t u,q,tmp,num1,num2,den,discr_r;
33*638691a0SAndroid Build Coastguard Worker   data_t lambda[NROOTS+1], s[NROOTS];	/* Err+Eras Locator poly
34*638691a0SAndroid Build Coastguard Worker 					 * and syndrome poly */
35*638691a0SAndroid Build Coastguard Worker   data_t b[NROOTS+1], t[NROOTS+1], omega[NROOTS+1];
36*638691a0SAndroid Build Coastguard Worker   data_t root[NROOTS], reg[NROOTS+1], loc[NROOTS];
37*638691a0SAndroid Build Coastguard Worker   int syn_error, count;
38*638691a0SAndroid Build Coastguard Worker 
39*638691a0SAndroid Build Coastguard Worker #ifdef FIXED
40*638691a0SAndroid Build Coastguard Worker   /* Check pad parameter for validity */
41*638691a0SAndroid Build Coastguard Worker   if(pad < 0 || pad >= NN)
42*638691a0SAndroid Build Coastguard Worker     return -1;
43*638691a0SAndroid Build Coastguard Worker #endif
44*638691a0SAndroid Build Coastguard Worker 
45*638691a0SAndroid Build Coastguard Worker   /* form the syndromes; i.e., evaluate data(x) at roots of g(x) */
46*638691a0SAndroid Build Coastguard Worker   for(i=0;i<NROOTS;i++)
47*638691a0SAndroid Build Coastguard Worker     s[i] = data[0];
48*638691a0SAndroid Build Coastguard Worker 
49*638691a0SAndroid Build Coastguard Worker   for(j=1;j<NN-PAD;j++){
50*638691a0SAndroid Build Coastguard Worker     for(i=0;i<NROOTS;i++){
51*638691a0SAndroid Build Coastguard Worker       if(s[i] == 0){
52*638691a0SAndroid Build Coastguard Worker 	s[i] = data[j];
53*638691a0SAndroid Build Coastguard Worker       } else {
54*638691a0SAndroid Build Coastguard Worker 	s[i] = data[j] ^ ALPHA_TO[MODNN(INDEX_OF[s[i]] + (FCR+i)*PRIM)];
55*638691a0SAndroid Build Coastguard Worker       }
56*638691a0SAndroid Build Coastguard Worker     }
57*638691a0SAndroid Build Coastguard Worker   }
58*638691a0SAndroid Build Coastguard Worker 
59*638691a0SAndroid Build Coastguard Worker   /* Convert syndromes to index form, checking for nonzero condition */
60*638691a0SAndroid Build Coastguard Worker   syn_error = 0;
61*638691a0SAndroid Build Coastguard Worker   for(i=0;i<NROOTS;i++){
62*638691a0SAndroid Build Coastguard Worker     syn_error |= s[i];
63*638691a0SAndroid Build Coastguard Worker     s[i] = INDEX_OF[s[i]];
64*638691a0SAndroid Build Coastguard Worker   }
65*638691a0SAndroid Build Coastguard Worker 
66*638691a0SAndroid Build Coastguard Worker   if (!syn_error) {
67*638691a0SAndroid Build Coastguard Worker     /* if syndrome is zero, data[] is a codeword and there are no
68*638691a0SAndroid Build Coastguard Worker      * errors to correct. So return data[] unmodified
69*638691a0SAndroid Build Coastguard Worker      */
70*638691a0SAndroid Build Coastguard Worker     count = 0;
71*638691a0SAndroid Build Coastguard Worker     goto finish;
72*638691a0SAndroid Build Coastguard Worker   }
73*638691a0SAndroid Build Coastguard Worker   memset(&lambda[1],0,NROOTS*sizeof(lambda[0]));
74*638691a0SAndroid Build Coastguard Worker   lambda[0] = 1;
75*638691a0SAndroid Build Coastguard Worker 
76*638691a0SAndroid Build Coastguard Worker   if (no_eras > 0) {
77*638691a0SAndroid Build Coastguard Worker     /* Init lambda to be the erasure locator polynomial */
78*638691a0SAndroid Build Coastguard Worker     lambda[1] = ALPHA_TO[MODNN(PRIM*(NN-1-eras_pos[0]))];
79*638691a0SAndroid Build Coastguard Worker     for (i = 1; i < no_eras; i++) {
80*638691a0SAndroid Build Coastguard Worker       u = MODNN(PRIM*(NN-1-eras_pos[i]));
81*638691a0SAndroid Build Coastguard Worker       for (j = i+1; j > 0; j--) {
82*638691a0SAndroid Build Coastguard Worker 	tmp = INDEX_OF[lambda[j - 1]];
83*638691a0SAndroid Build Coastguard Worker 	if(tmp != A0)
84*638691a0SAndroid Build Coastguard Worker 	  lambda[j] ^= ALPHA_TO[MODNN(u + tmp)];
85*638691a0SAndroid Build Coastguard Worker       }
86*638691a0SAndroid Build Coastguard Worker     }
87*638691a0SAndroid Build Coastguard Worker 
88*638691a0SAndroid Build Coastguard Worker #if DEBUG >= 1
89*638691a0SAndroid Build Coastguard Worker     /* Test code that verifies the erasure locator polynomial just constructed
90*638691a0SAndroid Build Coastguard Worker        Needed only for decoder debugging. */
91*638691a0SAndroid Build Coastguard Worker 
92*638691a0SAndroid Build Coastguard Worker     /* find roots of the erasure location polynomial */
93*638691a0SAndroid Build Coastguard Worker     for(i=1;i<=no_eras;i++)
94*638691a0SAndroid Build Coastguard Worker       reg[i] = INDEX_OF[lambda[i]];
95*638691a0SAndroid Build Coastguard Worker 
96*638691a0SAndroid Build Coastguard Worker     count = 0;
97*638691a0SAndroid Build Coastguard Worker     for (i = 1,k=IPRIM-1; i <= NN; i++,k = MODNN(k+IPRIM)) {
98*638691a0SAndroid Build Coastguard Worker       q = 1;
99*638691a0SAndroid Build Coastguard Worker       for (j = 1; j <= no_eras; j++)
100*638691a0SAndroid Build Coastguard Worker 	if (reg[j] != A0) {
101*638691a0SAndroid Build Coastguard Worker 	  reg[j] = MODNN(reg[j] + j);
102*638691a0SAndroid Build Coastguard Worker 	  q ^= ALPHA_TO[reg[j]];
103*638691a0SAndroid Build Coastguard Worker 	}
104*638691a0SAndroid Build Coastguard Worker       if (q != 0)
105*638691a0SAndroid Build Coastguard Worker 	continue;
106*638691a0SAndroid Build Coastguard Worker       /* store root and error location number indices */
107*638691a0SAndroid Build Coastguard Worker       root[count] = i;
108*638691a0SAndroid Build Coastguard Worker       loc[count] = k;
109*638691a0SAndroid Build Coastguard Worker       count++;
110*638691a0SAndroid Build Coastguard Worker     }
111*638691a0SAndroid Build Coastguard Worker     if (count != no_eras) {
112*638691a0SAndroid Build Coastguard Worker       printf("count = %d no_eras = %d\n lambda(x) is WRONG\n",count,no_eras);
113*638691a0SAndroid Build Coastguard Worker       count = -1;
114*638691a0SAndroid Build Coastguard Worker       goto finish;
115*638691a0SAndroid Build Coastguard Worker     }
116*638691a0SAndroid Build Coastguard Worker #if DEBUG >= 2
117*638691a0SAndroid Build Coastguard Worker     printf("\n Erasure positions as determined by roots of Eras Loc Poly:\n");
118*638691a0SAndroid Build Coastguard Worker     for (i = 0; i < count; i++)
119*638691a0SAndroid Build Coastguard Worker       printf("%d ", loc[i]);
120*638691a0SAndroid Build Coastguard Worker     printf("\n");
121*638691a0SAndroid Build Coastguard Worker #endif
122*638691a0SAndroid Build Coastguard Worker #endif
123*638691a0SAndroid Build Coastguard Worker   }
124*638691a0SAndroid Build Coastguard Worker   for(i=0;i<NROOTS+1;i++)
125*638691a0SAndroid Build Coastguard Worker     b[i] = INDEX_OF[lambda[i]];
126*638691a0SAndroid Build Coastguard Worker 
127*638691a0SAndroid Build Coastguard Worker   /*
128*638691a0SAndroid Build Coastguard Worker    * Begin Berlekamp-Massey algorithm to determine error+erasure
129*638691a0SAndroid Build Coastguard Worker    * locator polynomial
130*638691a0SAndroid Build Coastguard Worker    */
131*638691a0SAndroid Build Coastguard Worker   r = no_eras;
132*638691a0SAndroid Build Coastguard Worker   el = no_eras;
133*638691a0SAndroid Build Coastguard Worker   while (++r <= NROOTS) {	/* r is the step number */
134*638691a0SAndroid Build Coastguard Worker     /* Compute discrepancy at the r-th step in poly-form */
135*638691a0SAndroid Build Coastguard Worker     discr_r = 0;
136*638691a0SAndroid Build Coastguard Worker     for (i = 0; i < r; i++){
137*638691a0SAndroid Build Coastguard Worker       if ((lambda[i] != 0) && (s[r-i-1] != A0)) {
138*638691a0SAndroid Build Coastguard Worker 	discr_r ^= ALPHA_TO[MODNN(INDEX_OF[lambda[i]] + s[r-i-1])];
139*638691a0SAndroid Build Coastguard Worker       }
140*638691a0SAndroid Build Coastguard Worker     }
141*638691a0SAndroid Build Coastguard Worker     discr_r = INDEX_OF[discr_r];	/* Index form */
142*638691a0SAndroid Build Coastguard Worker     if (discr_r == A0) {
143*638691a0SAndroid Build Coastguard Worker       /* 2 lines below: B(x) <-- x*B(x) */
144*638691a0SAndroid Build Coastguard Worker       memmove(&b[1],b,NROOTS*sizeof(b[0]));
145*638691a0SAndroid Build Coastguard Worker       b[0] = A0;
146*638691a0SAndroid Build Coastguard Worker     } else {
147*638691a0SAndroid Build Coastguard Worker       /* 7 lines below: T(x) <-- lambda(x) - discr_r*x*b(x) */
148*638691a0SAndroid Build Coastguard Worker       t[0] = lambda[0];
149*638691a0SAndroid Build Coastguard Worker       for (i = 0 ; i < NROOTS; i++) {
150*638691a0SAndroid Build Coastguard Worker 	if(b[i] != A0)
151*638691a0SAndroid Build Coastguard Worker 	  t[i+1] = lambda[i+1] ^ ALPHA_TO[MODNN(discr_r + b[i])];
152*638691a0SAndroid Build Coastguard Worker 	else
153*638691a0SAndroid Build Coastguard Worker 	  t[i+1] = lambda[i+1];
154*638691a0SAndroid Build Coastguard Worker       }
155*638691a0SAndroid Build Coastguard Worker       if (2 * el <= r + no_eras - 1) {
156*638691a0SAndroid Build Coastguard Worker 	el = r + no_eras - el;
157*638691a0SAndroid Build Coastguard Worker 	/*
158*638691a0SAndroid Build Coastguard Worker 	 * 2 lines below: B(x) <-- inv(discr_r) *
159*638691a0SAndroid Build Coastguard Worker 	 * lambda(x)
160*638691a0SAndroid Build Coastguard Worker 	 */
161*638691a0SAndroid Build Coastguard Worker 	for (i = 0; i <= NROOTS; i++)
162*638691a0SAndroid Build Coastguard Worker 	  b[i] = (lambda[i] == 0) ? A0 : MODNN(INDEX_OF[lambda[i]] - discr_r + NN);
163*638691a0SAndroid Build Coastguard Worker       } else {
164*638691a0SAndroid Build Coastguard Worker 	/* 2 lines below: B(x) <-- x*B(x) */
165*638691a0SAndroid Build Coastguard Worker 	memmove(&b[1],b,NROOTS*sizeof(b[0]));
166*638691a0SAndroid Build Coastguard Worker 	b[0] = A0;
167*638691a0SAndroid Build Coastguard Worker       }
168*638691a0SAndroid Build Coastguard Worker       memcpy(lambda,t,(NROOTS+1)*sizeof(t[0]));
169*638691a0SAndroid Build Coastguard Worker     }
170*638691a0SAndroid Build Coastguard Worker   }
171*638691a0SAndroid Build Coastguard Worker 
172*638691a0SAndroid Build Coastguard Worker   /* Convert lambda to index form and compute deg(lambda(x)) */
173*638691a0SAndroid Build Coastguard Worker   deg_lambda = 0;
174*638691a0SAndroid Build Coastguard Worker   for(i=0;i<NROOTS+1;i++){
175*638691a0SAndroid Build Coastguard Worker     lambda[i] = INDEX_OF[lambda[i]];
176*638691a0SAndroid Build Coastguard Worker     if(lambda[i] != A0)
177*638691a0SAndroid Build Coastguard Worker       deg_lambda = i;
178*638691a0SAndroid Build Coastguard Worker   }
179*638691a0SAndroid Build Coastguard Worker   /* Find roots of the error+erasure locator polynomial by Chien search */
180*638691a0SAndroid Build Coastguard Worker   memcpy(&reg[1],&lambda[1],NROOTS*sizeof(reg[0]));
181*638691a0SAndroid Build Coastguard Worker   count = 0;		/* Number of roots of lambda(x) */
182*638691a0SAndroid Build Coastguard Worker   for (i = 1,k=IPRIM-1; i <= NN; i++,k = MODNN(k+IPRIM)) {
183*638691a0SAndroid Build Coastguard Worker     q = 1; /* lambda[0] is always 0 */
184*638691a0SAndroid Build Coastguard Worker     for (j = deg_lambda; j > 0; j--){
185*638691a0SAndroid Build Coastguard Worker       if (reg[j] != A0) {
186*638691a0SAndroid Build Coastguard Worker 	reg[j] = MODNN(reg[j] + j);
187*638691a0SAndroid Build Coastguard Worker 	q ^= ALPHA_TO[reg[j]];
188*638691a0SAndroid Build Coastguard Worker       }
189*638691a0SAndroid Build Coastguard Worker     }
190*638691a0SAndroid Build Coastguard Worker     if (q != 0)
191*638691a0SAndroid Build Coastguard Worker       continue; /* Not a root */
192*638691a0SAndroid Build Coastguard Worker     /* store root (index-form) and error location number */
193*638691a0SAndroid Build Coastguard Worker #if DEBUG>=2
194*638691a0SAndroid Build Coastguard Worker     printf("count %d root %d loc %d\n",count,i,k);
195*638691a0SAndroid Build Coastguard Worker #endif
196*638691a0SAndroid Build Coastguard Worker     root[count] = i;
197*638691a0SAndroid Build Coastguard Worker     loc[count] = k;
198*638691a0SAndroid Build Coastguard Worker     /* If we've already found max possible roots,
199*638691a0SAndroid Build Coastguard Worker      * abort the search to save time
200*638691a0SAndroid Build Coastguard Worker      */
201*638691a0SAndroid Build Coastguard Worker     if(++count == deg_lambda)
202*638691a0SAndroid Build Coastguard Worker       break;
203*638691a0SAndroid Build Coastguard Worker   }
204*638691a0SAndroid Build Coastguard Worker   if (deg_lambda != count) {
205*638691a0SAndroid Build Coastguard Worker     /*
206*638691a0SAndroid Build Coastguard Worker      * deg(lambda) unequal to number of roots => uncorrectable
207*638691a0SAndroid Build Coastguard Worker      * error detected
208*638691a0SAndroid Build Coastguard Worker      */
209*638691a0SAndroid Build Coastguard Worker     count = -1;
210*638691a0SAndroid Build Coastguard Worker     goto finish;
211*638691a0SAndroid Build Coastguard Worker   }
212*638691a0SAndroid Build Coastguard Worker   /*
213*638691a0SAndroid Build Coastguard Worker    * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
214*638691a0SAndroid Build Coastguard Worker    * x**NROOTS). in index form. Also find deg(omega).
215*638691a0SAndroid Build Coastguard Worker    */
216*638691a0SAndroid Build Coastguard Worker   deg_omega = deg_lambda-1;
217*638691a0SAndroid Build Coastguard Worker   for (i = 0; i <= deg_omega;i++){
218*638691a0SAndroid Build Coastguard Worker     tmp = 0;
219*638691a0SAndroid Build Coastguard Worker     for(j=i;j >= 0; j--){
220*638691a0SAndroid Build Coastguard Worker       if ((s[i - j] != A0) && (lambda[j] != A0))
221*638691a0SAndroid Build Coastguard Worker 	tmp ^= ALPHA_TO[MODNN(s[i - j] + lambda[j])];
222*638691a0SAndroid Build Coastguard Worker     }
223*638691a0SAndroid Build Coastguard Worker     omega[i] = INDEX_OF[tmp];
224*638691a0SAndroid Build Coastguard Worker   }
225*638691a0SAndroid Build Coastguard Worker 
226*638691a0SAndroid Build Coastguard Worker   /*
227*638691a0SAndroid Build Coastguard Worker    * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
228*638691a0SAndroid Build Coastguard Worker    * inv(X(l))**(FCR-1) and den = lambda_pr(inv(X(l))) all in poly-form
229*638691a0SAndroid Build Coastguard Worker    */
230*638691a0SAndroid Build Coastguard Worker   for (j = count-1; j >=0; j--) {
231*638691a0SAndroid Build Coastguard Worker     num1 = 0;
232*638691a0SAndroid Build Coastguard Worker     for (i = deg_omega; i >= 0; i--) {
233*638691a0SAndroid Build Coastguard Worker       if (omega[i] != A0)
234*638691a0SAndroid Build Coastguard Worker 	num1  ^= ALPHA_TO[MODNN(omega[i] + i * root[j])];
235*638691a0SAndroid Build Coastguard Worker     }
236*638691a0SAndroid Build Coastguard Worker     num2 = ALPHA_TO[MODNN(root[j] * (FCR - 1) + NN)];
237*638691a0SAndroid Build Coastguard Worker     den = 0;
238*638691a0SAndroid Build Coastguard Worker 
239*638691a0SAndroid Build Coastguard Worker     /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
240*638691a0SAndroid Build Coastguard Worker     for (i = min(deg_lambda,NROOTS-1) & ~1; i >= 0; i -=2) {
241*638691a0SAndroid Build Coastguard Worker       if(lambda[i+1] != A0)
242*638691a0SAndroid Build Coastguard Worker 	den ^= ALPHA_TO[MODNN(lambda[i+1] + i * root[j])];
243*638691a0SAndroid Build Coastguard Worker     }
244*638691a0SAndroid Build Coastguard Worker #if DEBUG >= 1
245*638691a0SAndroid Build Coastguard Worker     if (den == 0) {
246*638691a0SAndroid Build Coastguard Worker       printf("\n ERROR: denominator = 0\n");
247*638691a0SAndroid Build Coastguard Worker       count = -1;
248*638691a0SAndroid Build Coastguard Worker       goto finish;
249*638691a0SAndroid Build Coastguard Worker     }
250*638691a0SAndroid Build Coastguard Worker #endif
251*638691a0SAndroid Build Coastguard Worker     /* Apply error to data */
252*638691a0SAndroid Build Coastguard Worker     if (num1 != 0 && loc[j] >= PAD) {
253*638691a0SAndroid Build Coastguard Worker       data[loc[j]-PAD] ^= ALPHA_TO[MODNN(INDEX_OF[num1] + INDEX_OF[num2] + NN - INDEX_OF[den])];
254*638691a0SAndroid Build Coastguard Worker     }
255*638691a0SAndroid Build Coastguard Worker   }
256*638691a0SAndroid Build Coastguard Worker  finish:
257*638691a0SAndroid Build Coastguard Worker   if(eras_pos != NULL){
258*638691a0SAndroid Build Coastguard Worker     for(i=0;i<count;i++)
259*638691a0SAndroid Build Coastguard Worker       eras_pos[i] = loc[i];
260*638691a0SAndroid Build Coastguard Worker   }
261*638691a0SAndroid Build Coastguard Worker   return count;
262*638691a0SAndroid Build Coastguard Worker }
263