1 /*
2   FILE...: ldpc_dec.c
3   AUTHOR.: Matthew C. Valenti, Rohit Iyer Seshadri, David Rowe, Don Reid
4   CREATED: Sep 2016
5 
6   Command line C LDPC decoder derived from MpDecode.c in the CML
7   library.  Allows us to run the same decoder in Octave and C.  The
8   code is defined by the parameters and array stored in the include
9   file below, which can be machine generated from the Octave function
10   ldpc_fsk_lib.m:ldpc_decode()
11 
12   The include file also contains test input/output vectors for the LDPC
13   decoder for testing this program.  If no input file "stm_in.raw" is found
14   then the built in test mode will run.
15 
16   If there is an input is should be encoded data from the x86 ldpc_enc
17   program.  Here is the suggested way to run:
18 
19     ldpc_enc /dev/zero stm_in.raw --sd --code HRA_112_112 --testframes 6
20 
21     ldpc_dec stm_in.raw ref_out.raw --sd --code HRA_112_112 --testframes
22 
23     <Load stm32 and run>
24 
25     cmp -l ref_out.raw stm_out.raw
26     << Check BER values in logs >>
27 */
28 
29 #include <assert.h>
30 #include <errno.h>
31 #include <math.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <stdio.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 
38 #include "mpdecode_core.h"
39 #include "ofdm_internal.h"
40 
41 #include "semihosting.h"
42 #include "stm32f4xx_conf.h"
43 #include "stm32f4xx.h"
44 #include "machdep.h"
45 
46 /* generated by ldpc_fsk_lib.m:ldpc_decode() */
47 /* Machine generated consts, H_rows, H_cols, test input/output data to
48    change LDPC code regenerate this file. */
49 
50 #include "HRA_112_112.h"
51 
52 int testframes = 1;
53 
54 static char fin_buffer[1024];
55 static __attribute__ ((section (".ccm"))) char fout_buffer[8*8192];
56 
main(int argc,char * argv[])57 int main(int argc, char *argv[]) {
58     int         CodeLength, NumberParityBits;
59     int         i, parityCheckCount;
60     uint8_t     out_data[HRA_112_112_CODELENGTH];
61     struct LDPC ldpc;
62     int         data_bits_per_frame;
63     FILE        *fout;
64     int         iter, total_iters;
65     int         Tbits, Terrs, Tbits_raw, Terrs_raw;
66 
67     int   nread, frame;
68 
69     semihosting_init();
70 
71     fprintf(stderr, "LDPC decode test and profile\n");
72 
73     PROFILE_VAR(ldpc_decode);
74     machdep_profile_init();
75 
76     ldpc.max_iter = HRA_112_112_MAX_ITER;
77     ldpc.dec_type = 0;
78     ldpc.q_scale_factor = 1;
79     ldpc.r_scale_factor = 1;
80     ldpc.CodeLength = HRA_112_112_CODELENGTH;
81     ldpc.NumberParityBits = HRA_112_112_NUMBERPARITYBITS;
82     ldpc.NumberRowsHcols = HRA_112_112_NUMBERROWSHCOLS;
83     ldpc.max_row_weight = HRA_112_112_MAX_ROW_WEIGHT;
84     ldpc.max_col_weight = HRA_112_112_MAX_COL_WEIGHT;
85     ldpc.H_rows = (uint16_t *)HRA_112_112_H_rows;
86     ldpc.H_cols = (uint16_t *)HRA_112_112_H_cols;
87 
88     CodeLength = ldpc.CodeLength;
89     NumberParityBits = ldpc.NumberParityBits;
90     data_bits_per_frame = ldpc.NumberRowsHcols;
91     unsigned char ibits[data_bits_per_frame];
92     unsigned char pbits[NumberParityBits];
93 
94 //    // Allocate common space which can be shared with other functions.
95 //    int         size_common;
96 //    uint8_t     *common_array;
97 
98 //    ldpc_init(&ldpc, &size_common);
99 //    fprintf(stderr, "ldpc needs %d bytes of shared memory\n", size_common);
100 //    common_array = malloc(size_common);
101 
102     testframes = 1;
103     total_iters = 0;
104 
105     if (testframes) {
106         uint16_t r[data_bits_per_frame];
107         ofdm_rand(r, data_bits_per_frame);
108 
109         for(i=0; i<data_bits_per_frame; i++) {
110             ibits[i] = r[i] > 16384;
111         }
112         encode(&ldpc, ibits, pbits);
113         Tbits = Terrs = Tbits_raw = Terrs_raw = 0;
114     }
115 
116     FILE* fin = fopen("stm_in.raw", "rb");
117     if (fin == NULL) {
118         fprintf(stderr, "Error opening input file\n");
119         fflush(stderr);
120         exit(1);
121     }
122     setvbuf(fin, fin_buffer,_IOFBF,sizeof(fin_buffer));
123 
124     fout = fopen("stm_out.raw", "wb");
125     if (fout == NULL) {
126         fprintf(stderr, "Error opening output file\n");
127         fflush(stderr);
128         exit(1);
129     }
130     setvbuf(fout, fout_buffer,_IOFBF,sizeof(fout_buffer));
131 
132     float  *input_float  = calloc(CodeLength, sizeof(float));
133 
134     nread = CodeLength;
135     fprintf(stderr, "CodeLength: %d\n", CodeLength);
136 
137     frame = 0;
138     while(fread(input_float, sizeof(float) , nread, fin) == nread) {
139        fprintf(stderr, "frame %d\n", frame);
140 
141        if (testframes) {
142             char in_char;
143             for (i=0; i<data_bits_per_frame; i++) {
144                 in_char = input_float[i] < 0;
145                 if (in_char != ibits[i]) {
146                     Terrs_raw++;
147                 }
148                 Tbits_raw++;
149             }
150             for (i=0; i<NumberParityBits; i++) {
151                 in_char = input_float[i+data_bits_per_frame] < 0;
152                 if (in_char != pbits[i]) {
153                     Terrs_raw++;
154                 }
155                 Tbits_raw++;
156             }
157         }
158         float llr[CodeLength];
159         sd_to_llr(llr, input_float, CodeLength);
160 
161         PROFILE_SAMPLE(ldpc_decode);
162         iter = run_ldpc_decoder(&ldpc, out_data, llr, &parityCheckCount);
163         PROFILE_SAMPLE_AND_LOG2(ldpc_decode, "ldpc_decode");
164         //fprintf(stderr, "iter: %d\n", iter);
165         total_iters += iter;
166 
167         fwrite(out_data, sizeof(char), data_bits_per_frame, fout);
168 
169         if (testframes) {
170             for (i=0; i<data_bits_per_frame; i++) {
171                 if (out_data[i] != ibits[i]) {
172                     Terrs++;
173                     //fprintf(stderr, "%d %d %d\n", i, out_data[i], ibits[i]);
174                 }
175                 Tbits++;
176             }
177         }
178 
179         frame++;
180     }
181 
182     fclose(fin);
183     fclose(fout);
184 
185     fprintf(stderr, "total iters %d\n", total_iters);
186 
187     if (testframes) {
188         fprintf(stderr, "Raw Tbits..: %d Terr: %d BER: %4.3f\n",
189                 Tbits_raw, Terrs_raw, (double)(Terrs_raw/(Tbits_raw+1E-12)));
190         fprintf(stderr, "Coded Tbits: %d Terr: %d BER: %4.3f\n",
191                 Tbits, Terrs, (double)(Terrs/(Tbits+1E-12)));
192     }
193 
194     printf("\nStart Profile Data\n");
195     machdep_profile_print_logged_samples();
196     printf("End Profile Data\n");
197 
198     fclose(stdout);
199     fclose(stderr);
200 
201     return 0;
202 }
203 
204 /* vi:set ts=4 et sts=4: */
205