5 * Reed-Solomon coding and decoding
6 * Phil Karn (karn@ka9q.ampr.org) September 1996
7 * Separate CCSDS version create Dec 1998, merged into this version May 1999
9 * This file is derived from my generic RS encoder/decoder, which is
10 * in turn based on the program "new_rs_erasures.c" by Robert
11 * Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari Thirumoorthy
12 * (harit@spectra.eng.hawaii.edu), Aug 1995
14 * Copyright 1999 Phil Karn, KA9Q
15 * May be used under the terms of the GNU public license
18 #include "reedsolomon.h"
21 /* CCSDS field generator polynomial: 1+x+x^2+x^7+x^8 */
22 int Pp
[MM
+1] = { 1, 1, 1, 0, 0, 0, 0, 1, 1 };
25 /* MM, KK, B0, PRIM are user-defined in rs.h */
27 /* Primitive polynomials - see Lin & Costello, Appendix A,
28 * and Lee & Messerschmitt, p. 453.
30 #if(MM == 2)/* Admittedly silly */
31 int Pp
[MM
+1] = { 1, 1, 1 };
35 int Pp
[MM
+1] = { 1, 1, 0, 1 };
39 int Pp
[MM
+1] = { 1, 1, 0, 0, 1 };
43 int Pp
[MM
+1] = { 1, 0, 1, 0, 0, 1 };
47 int Pp
[MM
+1] = { 1, 1, 0, 0, 0, 0, 1 };
51 int Pp
[MM
+1] = { 1, 0, 0, 1, 0, 0, 0, 1 };
54 /* 1+x^2+x^3+x^4+x^8 */
55 int Pp
[MM
+1] = { 1, 0, 1, 1, 1, 0, 0, 0, 1 };
59 int Pp
[MM
+1] = { 1, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
63 int Pp
[MM
+1] = { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 };
67 int Pp
[MM
+1] = { 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
70 /* 1+x+x^4+x^6+x^12 */
71 int Pp
[MM
+1] = { 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1 };
74 /* 1+x+x^3+x^4+x^13 */
75 int Pp
[MM
+1] = { 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
78 /* 1+x+x^6+x^10+x^14 */
79 int Pp
[MM
+1] = { 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 };
83 int Pp
[MM
+1] = { 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
86 /* 1+x+x^3+x^12+x^16 */
87 int Pp
[MM
+1] = { 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1 };
90 #error "Either CCSDS must be defined, or MM must be set in range 2-16"
95 #ifdef STANDARD_ORDER /* first byte transmitted is index of x**(KK-1) in message poly*/
96 /* definitions used in the encode routine*/
97 #define MESSAGE(i) data[KK-(i)-1]
98 #define REMAINDER(i) bb[NN-KK-(i)-1]
99 /* definitions used in the decode routine*/
100 #define RECEIVED(i) data[NN-1-(i)]
101 #define ERAS_INDEX(i) (NN-1-eras_pos[i])
102 #define INDEX_TO_POS(i) (NN-1-(i))
103 #else /* first byte transmitted is index of x**0 in message polynomial*/
104 /* definitions used in the encode routine*/
105 #define MESSAGE(i) data[i]
106 #define REMAINDER(i) bb[i]
107 /* definitions used in the decode routine*/
108 #define RECEIVED(i) data[i]
109 #define ERAS_INDEX(i) eras_pos[i]
110 #define INDEX_TO_POS(i) i
114 /* This defines the type used to store an element of the Galois Field
115 * used by the code. Make sure this is something larger than a char if
116 * if anything larger than GF(256) is used.
118 * Note: unsigned char will work up to GF(256) but int seems to run
119 * faster on the Pentium.
123 /* index->polynomial form conversion table */
124 static gf Alpha_to
[NN
+ 1];
126 /* Polynomial->index form conversion table */
127 static gf Index_of
[NN
+ 1];
129 /* No legal value in index form represents zero, so
130 * we need a special value for this purpose
134 /* Generator polynomial g(x) in index form */
135 static gf Gg
[NN
- KK
+ 1];
137 static int RS_init
; /* Initialization flag */
139 /* Compute x % NN, where NN is 2**MM - 1,
140 * without a slow divide
142 /* static inline gf*/
148 x
= (x
>> MM
) + (x
& NN
);
153 #define min_(a,b) ((a) < (b) ? (a) : (b))
155 #define CLEAR(a,n) {\
157 for(ci=(n)-1;ci >=0;ci--)\
161 #define COPY(a,b,n) {\
163 for(ci=(n)-1;ci >=0;ci--)\
167 #define COPYDOWN(a,b,n) {\
169 for(ci=(n)-1;ci >=0;ci--)\
173 static void init_rs(void);
176 /* Conversion lookup tables from conventional alpha to Berlekamp's
177 * dual-basis representation. Used in the CCSDS version only.
178 * taltab[] -- convert conventional to dual basis
179 * tal1tab[] -- convert dual basis to conventional
181 * Note: the actual RS encoder/decoder works with the conventional basis.
182 * So data is converted from dual to conventional basis before either
183 * encoding or decoding and then converted back.
185 static unsigned char taltab
[NN
+1],tal1tab
[NN
+1];
187 static unsigned char tal
[] = { 0x8d, 0xef, 0xec, 0x86, 0xfa, 0x99, 0xaf, 0x7b };
189 /* Generate conversion lookup tables between conventional alpha representation
190 * (@**7, @**6, ...@**0)
191 * and Berlekamp's dual basis representation
199 for(i
=0;i
<256;i
++){/* For each value of input */
201 for(j
=0;j
<8;j
++) /* for each column of matrix */
202 for(k
=0;k
<8;k
++){ /* for each row of matrix */
204 taltab
[i
] ^= tal
[7-k
] & (1<<j
);
206 tal1tab
[taltab
[i
]] = i
;
212 static int Ldec
;/* Decrement for aux location variable in Chien search */
217 for(Ldec
=1;(Ldec
% PRIM
) != 0;Ldec
+= NN
)
225 /* generate GF(2**m) from the irreducible polynomial p(X) in Pp[0]..Pp[m]
226 lookup tables: index->polynomial form alpha_to[] contains j=alpha**i;
227 polynomial form -> index form index_of[j=alpha**i] = i
228 alpha=2 is the primitive element of GF(2**m)
229 HARI's COMMENT: (4/13/94) alpha_to[] can be used as follows:
230 Let @ represent the primitive element commonly called "alpha" that
231 is the root of the primitive polynomial p(x). Then in GF(2^m), for any
233 @^i = a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1)
234 where the binary vector (a(0),a(1),a(2),...,a(m-1)) is the representation
235 of the integer "alpha_to[i]" with a(0) being the LSB and a(m-1) the MSB. Thus for
236 example the polynomial representation of @^5 would be given by the binary
237 representation of the integer "alpha_to[5]".
238 Similarily, index_of[] can be used as follows:
239 As above, let @ represent the primitive element of GF(2^m) that is
240 the root of the primitive polynomial p(x). In order to find the power
241 of @ (alpha) that has the polynomial representation
242 a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1)
243 we consider the integer "i" whose binary representation with a(0) being LSB
244 and a(m-1) MSB is (a(0),a(1),...,a(m-1)) and locate the entry
245 "index_of[i]". Now, @^index_of[i] is that element whose polynomial
246 representation is (a(0),a(1),a(2),...,a(m-1)).
248 The element alpha_to[2^m-1] = 0 always signifying that the
249 representation of "@^infinity" = 0 is (0,0,0,...,0).
250 Similarily, the element index_of[0] = A0 always signifying
251 that the power of alpha which has the polynomial representation
252 (0,0,...,0) is "infinity".
259 register int i
, mask
;
263 for (i
= 0; i
< MM
; i
++) {
265 Index_of
[Alpha_to
[i
]] = i
;
266 /* If Pp[i] == 1 then, term @^i occurs in poly-repr of @^MM */
268 Alpha_to
[MM
] ^= mask
; /* Bit-wise EXOR operation */
269 mask
<<= 1; /* single left-shift */
271 Index_of
[Alpha_to
[MM
]] = MM
;
273 * Have obtained poly-repr of @^MM. Poly-repr of @^(i+1) is given by
274 * poly-repr of @^i shifted left one-bit and accounting for any @^MM
275 * term that may occur when poly-repr of @^i is shifted.
278 for (i
= MM
+ 1; i
< NN
; i
++) {
279 if (Alpha_to
[i
- 1] >= mask
)
280 Alpha_to
[i
] = Alpha_to
[MM
] ^ ((Alpha_to
[i
- 1] ^ mask
) << 1);
282 Alpha_to
[i
] = Alpha_to
[i
- 1] << 1;
283 Index_of
[Alpha_to
[i
]] = i
;
290 * Obtain the generator polynomial of the TT-error correcting, length
291 * NN=(2**MM -1) Reed Solomon code from the product of (X+@**(B0+i)), i = 0,
296 * If B0 = 1, TT = 1. deg(g(x)) = 2*TT = 2.
297 * g(x) = (x+@) (x+@**2)
299 * If B0 = 0, TT = 2. deg(g(x)) = 2*TT = 4.
300 * g(x) = (x+1) (x+@) (x+@**2) (x+@**3)
308 for (i
= 0; i
< NN
- KK
; i
++) {
311 * Below multiply (Gg[0]+Gg[1]*x + ... +Gg[i]x^i) by
312 * (@**(B0+i)*PRIM + x)
314 for (j
= i
; j
> 0; j
--)
316 Gg
[j
] = Gg
[j
- 1] ^ Alpha_to
[modnn((Index_of
[Gg
[j
]]) + (B0
+ i
) *PRIM
)];
319 /* Gg[0] can never be zero */
320 Gg
[0] = Alpha_to
[modnn(Index_of
[Gg
[0]] + (B0
+ i
) * PRIM
)];
322 /* convert Gg[] to index form for quicker encoding */
323 for (i
= 0; i
<= NN
- KK
; i
++)
324 Gg
[i
] = Index_of
[Gg
[i
]];
329 * take the string of symbols in data[i], i=0..(k-1) and encode
330 * systematically to produce NN-KK parity symbols in bb[0]..bb[NN-KK-1] data[]
331 * is input and bb[] is output in polynomial form. Encoding is done by using
332 * a feedback shift register with appropriate connections specified by the
333 * elements of Gg[], which was generated above. Codeword is c(X) =
334 * data(X)*X**(NN-KK)+ b(X)
338 encode_rs(dtype data
[KK
], dtype bb
[NN
-KK
])
343 #if DEBUG >= 1 && MM != 8
344 /* Check for illegal input values */
356 /* Convert to conventional basis */
358 MESSAGE(i
) = tal1tab
[MESSAGE(i
)];
361 for(i
= KK
- 1; i
>= 0; i
--) {
362 feedback
= Index_of
[MESSAGE(i
) ^ REMAINDER(NN
- KK
- 1)];
363 if (feedback
!= A0
) { /* feedback term is non-zero */
364 for (j
= NN
- KK
- 1; j
> 0; j
--)
366 REMAINDER(j
) = REMAINDER(j
- 1) ^ Alpha_to
[modnn(Gg
[j
] + feedback
)];
368 REMAINDER(j
) = REMAINDER(j
- 1);
369 REMAINDER(0) = Alpha_to
[modnn(Gg
[0] + feedback
)];
370 } else { /* feedback term is zero. encoder becomes a
371 * single-byte shifter */
372 for (j
= NN
- KK
- 1; j
> 0; j
--)
373 REMAINDER(j
) = REMAINDER(j
- 1);
378 /* Convert to l-basis */
380 MESSAGE(i
) = taltab
[MESSAGE(i
)];
387 * Performs ERRORS+ERASURES decoding of RS codes. If decoding is successful,
388 * writes the codeword into data[] itself. Otherwise data[] is unaltered.
390 * Return number of symbols corrected, or -1 if codeword is illegal
391 * or uncorrectable. If eras_pos is non-null, the detected error locations
392 * are written back. NOTE! This array must be at least NN-KK elements long.
394 * First "no_eras" erasures are declared by the calling program. Then, the
395 * maximum # of errors correctable is t_after_eras = floor((NN-KK-no_eras)/2).
396 * If the number of channel errors is not greater than "t_after_eras" the
397 * transmitted codeword will be recovered. Details of algorithm can be found
398 * in R. Blahut's "Theory ... of Error-Correcting Codes".
400 * Warning: the eras_pos[] array must not contain duplicate entries; decoder failure
401 * will result. The decoder *could* check for this condition, but it would involve
402 * extra time on every decoding operation.
406 eras_dec_rs(dtype data
[NN
], int eras_pos
[NN
-KK
], int no_eras
)
408 int deg_lambda
, el
, deg_omega
;
410 gf u
,q
,tmp
,num1
,num2
,den
,discr_r
;
411 gf lambda
[NN
-KK
+ 1], s
[NN
-KK
+ 1]; /* Err+Eras Locator poly
412 * and syndrome poly */
413 gf b
[NN
-KK
+ 1], t
[NN
-KK
+ 1], omega
[NN
-KK
+ 1];
414 gf root
[NN
-KK
], reg
[NN
-KK
+ 1], loc
[NN
-KK
];
415 int syn_error
, count
;
421 /* Convert to conventional basis */
423 RECEIVED(i
) = tal1tab
[RECEIVED(i
)];
426 #if DEBUG >= 1 && MM != 8
427 /* Check for illegal input values */
432 /* form the syndromes; i.e., evaluate data(x) at roots of g(x)
433 * namely @**(B0+i)*PRIM, i = 0, ... ,(NN-KK-1)
435 for(i
=1;i
<=NN
-KK
;i
++){
441 tmp
= Index_of
[RECEIVED(j
)];
443 /* s[i] ^= Alpha_to[modnn(tmp + (B0+i-1)*j)]; */
444 for(i
=1;i
<=NN
-KK
;i
++)
445 s
[i
] ^= Alpha_to
[modnn(tmp
+ (B0
+i
-1)*PRIM
*j
)];
447 /* Convert syndromes to index form, checking for nonzero condition */
449 for(i
=1;i
<=NN
-KK
;i
++){
451 /*printf("syndrome %d = %x\n",i,s[i]);*/
452 s
[i
] = Index_of
[s
[i
]];
456 /* if syndrome is zero, data[] is a codeword and there are no
457 * errors to correct. So return data[] unmodified
462 CLEAR(&lambda
[1],NN
-KK
);
466 /* Init lambda to be the erasure locator polynomial */
467 lambda
[1] = Alpha_to
[modnn(PRIM
* ERAS_INDEX(0))];
468 for (i
= 1; i
< no_eras
; i
++) {
469 u
= modnn(PRIM
*ERAS_INDEX(i
));
470 for (j
= i
+1; j
> 0; j
--) {
471 tmp
= Index_of
[lambda
[j
- 1]];
473 lambda
[j
] ^= Alpha_to
[modnn(u
+ tmp
)];
477 /* Test code that verifies the erasure locator polynomial just constructed
478 Needed only for decoder debugging. */
480 /* find roots of the erasure location polynomial */
481 for(i
=1;i
<=no_eras
;i
++)
482 reg
[i
] = Index_of
[lambda
[i
]];
484 for (i
= 1,k
=NN
-Ldec
; i
<= NN
; i
++,k
= modnn(NN
+k
-Ldec
)) {
486 for (j
= 1; j
<= no_eras
; j
++)
488 reg
[j
] = modnn(reg
[j
] + j
);
489 q
^= Alpha_to
[reg
[j
]];
493 /* store root and error location number indices */
498 if (count
!= no_eras
) {
499 printf("\n lambda(x) is WRONG\n");
504 printf("\n Erasure positions as determined by roots of Eras Loc Poly:\n");
505 for (i
= 0; i
< count
; i
++)
506 printf("%d ", loc
[i
]);
511 for(i
=0;i
<NN
-KK
+1;i
++)
512 b
[i
] = Index_of
[lambda
[i
]];
515 * Begin Berlekamp-Massey algorithm to determine error+erasure
520 while (++r
<= NN
-KK
) { /* r is the step number */
521 /* Compute discrepancy at the r-th step in poly-form */
523 for (i
= 0; i
< r
; i
++){
524 if ((lambda
[i
] != 0) && (s
[r
- i
] != A0
)) {
525 discr_r
^= Alpha_to
[modnn(Index_of
[lambda
[i
]] + s
[r
- i
])];
528 discr_r
= Index_of
[discr_r
]; /* Index form */
530 /* 2 lines below: B(x) <-- x*B(x) */
531 COPYDOWN(&b
[1],b
,NN
-KK
);
534 /* 7 lines below: T(x) <-- lambda(x) - discr_r*x*b(x) */
536 for (i
= 0 ; i
< NN
-KK
; i
++) {
538 t
[i
+1] = lambda
[i
+1] ^ Alpha_to
[modnn(discr_r
+ b
[i
])];
540 t
[i
+1] = lambda
[i
+1];
542 if (2 * el
<= r
+ no_eras
- 1) {
543 el
= r
+ no_eras
- el
;
545 * 2 lines below: B(x) <-- inv(discr_r) *
548 for (i
= 0; i
<= NN
-KK
; i
++)
549 b
[i
] = (lambda
[i
] == 0) ? A0
: modnn(Index_of
[lambda
[i
]] - discr_r
+ NN
);
551 /* 2 lines below: B(x) <-- x*B(x) */
552 COPYDOWN(&b
[1],b
,NN
-KK
);
555 COPY(lambda
,t
,NN
-KK
+1);
559 /* Convert lambda to index form and compute deg(lambda(x)) */
561 for(i
=0;i
<NN
-KK
+1;i
++){
562 lambda
[i
] = Index_of
[lambda
[i
]];
567 * Find roots of the error+erasure locator polynomial by Chien
570 COPY(®
[1],&lambda
[1],NN
-KK
);
571 count
= 0; /* Number of roots of lambda(x) */
572 for (i
= 1,k
=NN
-Ldec
; i
<= NN
; i
++,k
= modnn(NN
+k
-Ldec
)) {
574 for (j
= deg_lambda
; j
> 0; j
--){
576 reg
[j
] = modnn(reg
[j
] + j
);
577 q
^= Alpha_to
[reg
[j
]];
582 /* store root (index-form) and error location number */
585 /* If we've already found max possible roots,
586 * abort the search to save time
588 if(++count
== deg_lambda
)
591 if (deg_lambda
!= count
) {
593 * deg(lambda) unequal to number of roots => uncorrectable
600 * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
601 * x**(NN-KK)). in index form. Also find deg(omega).
604 for (i
= 0; i
< NN
-KK
;i
++){
606 j
= (deg_lambda
< i
) ? deg_lambda
: i
;
608 if ((s
[i
+ 1 - j
] != A0
) && (lambda
[j
] != A0
))
609 tmp
^= Alpha_to
[modnn(s
[i
+ 1 - j
] + lambda
[j
])];
613 omega
[i
] = Index_of
[tmp
];
618 * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
619 * inv(X(l))**(B0-1) and den = lambda_pr(inv(X(l))) all in poly-form
621 for (j
= count
-1; j
>=0; j
--) {
623 for (i
= deg_omega
; i
>= 0; i
--) {
625 num1
^= Alpha_to
[modnn(omega
[i
] + i
* root
[j
])];
627 num2
= Alpha_to
[modnn(root
[j
] * (B0
- 1) + NN
)];
630 /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
631 for (i
= min_(deg_lambda
,NN
-KK
-1) & ~1; i
>= 0; i
-=2) {
632 if(lambda
[i
+1] != A0
)
633 den
^= Alpha_to
[modnn(lambda
[i
+1] + i
* root
[j
])];
637 printf("\n ERROR: denominator = 0\n");
639 /* Convert to dual- basis */
643 /* Apply error to data */
645 RECEIVED(loc
[j
]) ^= Alpha_to
[modnn(Index_of
[num1
] + Index_of
[num2
] + NN
- Index_of
[den
])];
650 /* Convert to dual- basis */
652 RECEIVED(i
) = taltab
[RECEIVED(i
)];
654 if(eras_pos
!= NULL
){
655 for(i
=0;i
<count
;i
++){
657 eras_pos
[i
] = INDEX_TO_POS(loc
[i
]);
662 /* Encoder/decoder initialization - call this first! */