1 /***********************************************************************
2 * Copyright Henry Minsky (hqm@alum.mit.edu) 1991-2009
4 * This software library is licensed under terms of the GNU GENERAL
8 * RSCODE is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
13 * RSCODE is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with Rscode. If not, see <http://www.gnu.org/licenses/>.
21 * Commercial licensing is available under a separate license, please
22 * contact author for details.
24 * Source code is available at http://rscode.sourceforge.net
25 * Berlekamp-Peterson and Berlekamp-Massey Algorithms for error-location
27 * From Cain, Clark, "Error-Correction Coding For Digital Communications", pp. 205.
29 * This finds the coefficients of the error locator polynomial.
31 * The roots are then found by looking for the values of a^n
32 * where evaluating the polynomial yields zero.
34 * Error correction is done using the error-evaluator equation on pp 207.
41 /* The Error Locator Polynomial, also known as Lambda or Sigma. Lambda[0] == 1 */
42 static int Lambda
[MAXDEG
];
44 /* The Error Evaluator Polynomial */
45 static int Omega
[MAXDEG
];
47 /* local ANSI declarations */
48 static int compute_discrepancy(int lambda
[], int S
[], int L
, int n
);
49 static void init_gamma(int gamma
[]);
50 static void compute_modified_omega (void);
51 static void mul_z_poly (int src
[]);
53 /* error locations found using Chien's search*/
54 static int ErrorLocs
[256];
58 static int ErasureLocs
[256];
61 /* From Cain, Clark, "Error-Correction Coding For Digital Communications", pp. 216. */
63 Modified_Berlekamp_Massey (void)
65 int n
, L
, L2
, k
, d
, i
;
66 int psi
[MAXDEG
], psi2
[MAXDEG
], D
[MAXDEG
];
69 /* initialize Gamma, the erasure locator polynomial */
76 copy_poly(psi
, gamma
);
77 k
= -1; L
= NErasures
;
79 for (n
= NErasures
; n
< RS_ECC_NPARITY
; n
++) {
81 d
= compute_discrepancy(psi
, synBytes
, L
, n
);
85 /* psi2 = psi - d*D */
86 for (i
= 0; i
< MAXDEG
; i
++) psi2
[i
] = psi
[i
] ^ gmult(d
, D
[i
]);
92 /* D = scale_poly(ginv(d), psi); */
93 for (i
= 0; i
< MAXDEG
; i
++) D
[i
] = gmult(psi
[i
], ginv(d
));
98 for (i
= 0; i
< MAXDEG
; i
++) psi
[i
] = psi2
[i
];
104 for(i
= 0; i
< MAXDEG
; i
++) Lambda
[i
] = psi
[i
];
105 compute_modified_omega();
110 /* given Psi (called Lambda in Modified_Berlekamp_Massey) and synBytes,
111 compute the combined erasure/error evaluator polynomial as
115 compute_modified_omega ()
118 int product
[MAXDEG
*2];
120 mult_polys(product
, Lambda
, synBytes
);
122 for(i
= 0; i
< RS_ECC_NPARITY
; i
++) Omega
[i
] = product
[i
];
126 /* polynomial multiplication */
128 mult_polys (int dst
[], int p1
[], int p2
[])
133 for (i
=0; i
< (MAXDEG
*2); i
++) dst
[i
] = 0;
135 for (i
= 0; i
< MAXDEG
; i
++) {
136 for(j
=MAXDEG
; j
<(MAXDEG
*2); j
++) tmp1
[j
]=0;
138 /* scale tmp1 by p1[i] */
139 for(j
=0; j
<MAXDEG
; j
++) tmp1
[j
]=gmult(p2
[j
], p1
[i
]);
140 /* and mult (shift) tmp1 right by i */
141 for (j
= (MAXDEG
*2)-1; j
>= i
; j
--) tmp1
[j
] = tmp1
[j
-i
];
142 for (j
= 0; j
< i
; j
++) tmp1
[j
] = 0;
144 /* add into partial product */
145 for(j
=0; j
< (MAXDEG
*2); j
++) dst
[j
] ^= tmp1
[j
];
151 /* gamma = product (1-z*a^Ij) for erasure locs Ij */
153 init_gamma (int gamma
[])
161 for (e
= 0; e
< NErasures
; e
++) {
162 copy_poly(tmp
, gamma
);
163 scale_poly(gexp
[ErasureLocs
[e
]], tmp
);
165 add_polys(gamma
, tmp
);
172 compute_next_omega (int d
, int A
[], int dst
[], int src
[])
175 for ( i
= 0; i
< MAXDEG
; i
++) {
176 dst
[i
] = src
[i
] ^ gmult(d
, A
[i
]);
183 compute_discrepancy (int lambda
[], int S
[], int L
, int n
)
187 for (i
= 0; i
<= L
; i
++)
188 sum
^= gmult(lambda
[i
], S
[n
-i
]);
192 /********** polynomial arithmetic *******************/
194 void add_polys (int dst
[], int src
[])
197 for (i
= 0; i
< MAXDEG
; i
++) dst
[i
] ^= src
[i
];
200 void copy_poly (int dst
[], int src
[])
203 for (i
= 0; i
< MAXDEG
; i
++) dst
[i
] = src
[i
];
206 void scale_poly (int k
, int poly
[])
209 for (i
= 0; i
< MAXDEG
; i
++) poly
[i
] = gmult(k
, poly
[i
]);
213 void zero_poly (int poly
[])
216 for (i
= 0; i
< MAXDEG
; i
++) poly
[i
] = 0;
220 /* multiply by z, i.e., shift right by 1 */
221 static void mul_z_poly (int src
[])
224 for (i
= MAXDEG
-1; i
> 0; i
--) src
[i
] = src
[i
-1];
229 /* Finds all the roots of an error-locator polynomial with coefficients
230 * Lambda[j] by evaluating Lambda at successive values of alpha.
232 * This can be tested with the decoder's equations case.
242 for (r
= 1; r
< 256; r
++) {
244 /* evaluate lambda at r */
245 for (k
= 0; k
< RS_ECC_NPARITY
+1; k
++) {
246 sum
^= gmult(gexp
[(k
*r
)%255], Lambda
[k
]);
250 ErrorLocs
[NErrors
] = (255-r
); NErrors
++;
251 //if (DEBUG) fprintf(stderr, "Root found at r = %d, (255-r) = %d\n", r, (255-r));
256 /* Combined Erasure And Error Magnitude Computation
258 * Pass in the codeword, its size in bytes, as well as
259 * an array of any known erasure locations, along the number
262 * Evaluate Omega(actually Psi)/Lambda' at the roots
263 * alpha^(-i) for error locs i.
265 * Returns 1 if everything ok, or 0 if an out-of-bounds error is found
270 correct_errors_erasures (unsigned char codeword
[],
277 /* If you want to take advantage of erasure correction, be sure to
278 set NErasures and ErasureLocs[] with the locations of erasures.
280 NErasures
= nerasures
;
281 for (i
= 0; i
< NErasures
; i
++) ErasureLocs
[i
] = erasures
[i
];
283 Modified_Berlekamp_Massey();
287 if ((NErrors
<= RS_ECC_NPARITY
) && NErrors
> 0) {
289 /* first check for illegal error locs */
290 for (r
= 0; r
< NErrors
; r
++) {
291 if (ErrorLocs
[r
] >= csize
) {
292 //if (DEBUG) fprintf(stderr, "Error loc i=%d outside of codeword length %d\n", i, csize);
297 for (r
= 0; r
< NErrors
; r
++) {
300 /* evaluate Omega at alpha^(-i) */
303 for (j
= 0; j
< MAXDEG
; j
++)
304 num
^= gmult(Omega
[j
], gexp
[((255-i
)*j
)%255]);
306 /* evaluate Lambda' (derivative) at alpha^(-i) ; all odd powers disappear */
308 for (j
= 1; j
< MAXDEG
; j
+= 2) {
309 denom
^= gmult(Lambda
[j
], gexp
[((255-i
)*(j
-1)) % 255]);
312 err
= gmult(num
, ginv(denom
));
313 //if (DEBUG) fprintf(stderr, "Error magnitude %#x at loc %d\n", err, csize-i);
315 codeword
[csize
-i
-1] ^= err
;
320 //if (DEBUG && NErrors) fprintf(stderr, "Uncorrectable codeword\n");