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(®[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