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