1 /*
2 * Copyright (c) 2007 - 2015 Joseph Gaeddert
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23 //
24 // Reed-Solomon (macros)
25 //
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <assert.h>
31
32 #include "liquid.internal.h"
33
34 #define VERBOSE_FEC_RS 0
35
36 #if LIBFEC_ENABLED
37 #include "fec.h"
38
fec_rs_create(fec_scheme _fs)39 fec fec_rs_create(fec_scheme _fs)
40 {
41 fec q = (fec) malloc(sizeof(struct fec_s));
42
43 q->scheme = _fs;
44 q->rate = fec_get_rate(q->scheme);
45
46 q->encode_func = &fec_rs_encode;
47 q->decode_func = &fec_rs_decode;
48 q->decode_soft_func = NULL;
49
50 switch (q->scheme) {
51 case LIQUID_FEC_RS_M8: fec_rs_init_p8(q); break;
52 default:
53 fprintf(stderr,"error: fec_rs_create(), invalid type\n");
54 exit(1);
55 }
56
57 // initialize basic parameters
58 q->nn = (1 << q->symsize) - 1;
59 q->kk = q->nn - q->nroots;
60
61 // lengths
62 q->num_dec_bytes = 0;
63 q->rs = NULL;
64
65 // allocate memory for arrays
66 q->tblock = (unsigned char*) malloc(q->nn*sizeof(unsigned char));
67 q->errlocs = (int *) malloc(q->nn*sizeof(int));
68 q->derrlocs = (int *) malloc(q->nn*sizeof(int));
69
70 return q;
71 }
72
fec_rs_destroy(fec _q)73 void fec_rs_destroy(fec _q)
74 {
75 // delete internal Reed-Solomon decoder object
76 if (_q->rs != NULL) {
77 free_rs_char(_q->rs);
78 }
79
80 // delete internal memory arrays
81 free(_q->tblock);
82 free(_q->errlocs);
83 free(_q->derrlocs);
84
85 // delete fec object
86 free(_q);
87 }
88
fec_rs_encode(fec _q,unsigned int _dec_msg_len,unsigned char * _msg_dec,unsigned char * _msg_enc)89 void fec_rs_encode(fec _q,
90 unsigned int _dec_msg_len,
91 unsigned char *_msg_dec,
92 unsigned char *_msg_enc)
93 {
94 // validate input
95 if (_dec_msg_len == 0) {
96 fprintf(stderr,"error: fec_rs_encode(), input lenght must be > 0\n");
97 exit(1);
98 }
99
100 // re-allocate resources if necessary
101 fec_rs_setlength(_q, _dec_msg_len);
102
103 unsigned int i;
104 unsigned int n0=0; // input index
105 unsigned int n1=0; // output index
106 unsigned int block_size = _q->dec_block_len;
107 for (i=0; i<_q->num_blocks; i++) {
108
109 // the last block is smaller by the residual block length
110 if (i == _q->num_blocks-1)
111 block_size -= _q->res_block_len;
112
113 // copy sequence
114 memmove(_q->tblock, &_msg_dec[n0], block_size*sizeof(unsigned char));
115
116 // last block: we could pad end with zeros, but it's not really
117 // necessary as these bits are going to be thrown away anyway
118
119 // encode data, appending parity bits to end of sequence
120 encode_rs_char(_q->rs, _q->tblock, &_q->tblock[_q->dec_block_len]);
121
122 // copy result to output
123 memmove(&_msg_enc[n1], _q->tblock, _q->enc_block_len*sizeof(unsigned char));
124
125 // increment counters
126 n0 += block_size;
127 n1 += _q->enc_block_len;
128 }
129
130 // sanity check
131 assert( n0 == _q->num_dec_bytes );
132 assert( n1 == _q->num_enc_bytes );
133 }
134
135 //unsigned int
fec_rs_decode(fec _q,unsigned int _dec_msg_len,unsigned char * _msg_enc,unsigned char * _msg_dec)136 void fec_rs_decode(fec _q,
137 unsigned int _dec_msg_len,
138 unsigned char *_msg_enc,
139 unsigned char *_msg_dec)
140 {
141 // validate input
142 if (_dec_msg_len == 0) {
143 fprintf(stderr,"error: fec_rs_encode(), input lenght must be > 0\n");
144 exit(1);
145 }
146
147 // re-allocate resources if necessary
148 fec_rs_setlength(_q, _dec_msg_len);
149
150 // set erasures, error locations to zero
151 memset(_q->errlocs, 0x00, _q->nn*sizeof(unsigned char));
152 memset(_q->derrlocs, 0x00, _q->nn*sizeof(unsigned char));
153 _q->erasures = 0;
154
155 unsigned int i;
156 unsigned int n0=0;
157 unsigned int n1=0;
158 unsigned int block_size = _q->dec_block_len;
159 //int derrors; // number of decoder errors
160 for (i=0; i<_q->num_blocks; i++) {
161
162 // the last block is smaller by the residual block length
163 if (i == _q->num_blocks-1)
164 block_size -= _q->res_block_len;
165
166 // copy sequence
167 memmove(_q->tblock, &_msg_enc[n0], _q->enc_block_len*sizeof(unsigned char));
168
169 // decode block
170 //derrors =
171 decode_rs_char(_q->rs,
172 _q->tblock,
173 _q->derrlocs,
174 _q->erasures);
175
176 // copy result
177 memmove(&_msg_dec[n1], _q->tblock, block_size*sizeof(unsigned char));
178
179 // increment counters
180 n0 += _q->enc_block_len;
181 n1 += block_size;
182 }
183
184 // sanity check
185 assert( n0 == _q->num_enc_bytes );
186 assert( n1 == _q->num_dec_bytes );
187 }
188
189 // Set dec_msg_len, re-allocating resources as necessary. Effectively, it
190 // divides the input message into several blocks and allows the decoder to
191 // pad each block appropraitely.
192 //
193 // For example : if we are using the 8-bit code,
194 // nroots = 32
195 // nn = 255
196 // kk = 223
197 // Let _dec_msg_len = 1024, then
198 // num_blocks = ceil(1024/223)
199 // = ceil(4.5919)
200 // = 5
201 // dec_block_len = ceil(1024/num_blocks)
202 // = ceil(204.8)
203 // = 205
204 // enc_block_len = dec_block_len + nroots
205 // = 237
206 // res_block_len = mod(num_blocks*dec_block_len,_dec_msg_len)
207 // = mod(5*205,1024)
208 // = mod(1025,1024)
209 // = 1 (cannot evenly divide input sequence)
210 // pad = kk - dec_block_len
211 // = 223 - 205
212 // = 18
213 //
214 // Thus, the 1024-byte input message is broken into 5 blocks, the first
215 // four have a length 205, and the last block has a length 204 (which is
216 // externally padded to 205, e.g. res_block_len = 1). This code adds 32
217 // parity symbols, so each block is extended to 237 bytes. libfec auto-
218 // matically extends the internal data to 255 bytes by padding with 18
219 // symbols. Therefore, the final output length is 237 * 5 = 1185 symbols.
fec_rs_setlength(fec _q,unsigned int _dec_msg_len)220 void fec_rs_setlength(fec _q,
221 unsigned int _dec_msg_len)
222 {
223 // return if length has not changed
224 if (_dec_msg_len == _q->num_dec_bytes)
225 return;
226
227 // reset lengths
228 _q->num_dec_bytes = _dec_msg_len;
229
230 div_t d;
231
232 // compute the total number of blocks necessary: ceil(num_dec_bytes / kk)
233 d = div(_q->num_dec_bytes, _q->kk);
234 _q->num_blocks = d.quot + (d.rem==0 ? 0 : 1);
235
236 // compute the decoded block length: ceil(num_dec_bytes / num_blocks)
237 d = div(_dec_msg_len, _q->num_blocks);
238 _q->dec_block_len = d.quot + (d.rem == 0 ? 0 : 1);
239
240 // compute the encoded block length: dec_block_len + nroots
241 _q->enc_block_len = _q->dec_block_len + _q->nroots;
242
243 // compute the residual padding symbols in the last block:
244 // mod(num_blocks*dec_block_len, num_dec_bytes)
245 _q->res_block_len = (_q->num_blocks*_q->dec_block_len) % _q->num_dec_bytes;
246
247 // compute the internal libfec padding factor: kk - dec_block_len
248 _q->pad = _q->kk - _q->dec_block_len;
249
250 // compute the final encoded block length: enc_block_len * num_blocks
251 _q->num_enc_bytes = _q->enc_block_len * _q->num_blocks;
252
253 #if VERBOSE_FEC_RS
254 printf("dec_msg_len : %u\n", _q->num_dec_bytes);
255 printf("num_blocks : %u\n", _q->num_blocks);
256 printf("dec_block_len : %u\n", _q->dec_block_len);
257 printf("enc_block_len : %u\n", _q->enc_block_len);
258 printf("res_block_len : %u\n", _q->res_block_len);
259 printf("pad : %u\n", _q->pad);
260 printf("enc_msg_len : %u\n", _q->num_enc_bytes);
261 #endif
262
263 // delete old decoder if necessary
264 if (_q->rs != NULL)
265 free_rs_char(_q->rs);
266
267 // Reed-Solomon specific decoding
268 _q->rs = init_rs_char(_q->symsize,
269 _q->genpoly,
270 _q->fcs,
271 _q->prim,
272 _q->nroots,
273 _q->pad);
274 }
275
276 //
277 // internal
278 //
279
fec_rs_init_p8(fec _q)280 void fec_rs_init_p8(fec _q)
281 {
282 _q->symsize = 8;
283 _q->genpoly = 0x11d;
284 _q->fcs = 1;
285 _q->prim = 1;
286 _q->nroots = 32;
287 }
288
289 #else // LIBFEC_ENABLED
290
fec_rs_create(fec_scheme _fs)291 fec fec_rs_create(fec_scheme _fs)
292 {
293 return NULL;
294 }
295
fec_rs_destroy(fec _q)296 void fec_rs_destroy(fec _q)
297 {
298 }
299
fec_rs_encode(fec _q,unsigned int _dec_msg_len,unsigned char * _msg_dec,unsigned char * _msg_enc)300 void fec_rs_encode(fec _q,
301 unsigned int _dec_msg_len,
302 unsigned char *_msg_dec,
303 unsigned char *_msg_enc)
304 {
305 }
306
307 //unsigned int
fec_rs_decode(fec _q,unsigned int _dec_msg_len,unsigned char * _msg_enc,unsigned char * _msg_dec)308 void fec_rs_decode(fec _q,
309 unsigned int _dec_msg_len,
310 unsigned char *_msg_enc,
311 unsigned char *_msg_dec)
312 {
313 }
314
315 #endif // LIBFEC_ENABLED
316
317