1 /*---------------------------------------------------------------------------*\
2 
3   FILE........: fdmdv_demod.c
4   AUTHOR......: David Rowe
5   DATE CREATED: April 30 2012
6 
7   Given an input raw file (8kHz, 16 bit shorts) of FDMDV modem samples
8   outputs a file of bits.  The output file is assumed to be arranged
9   as codec frames of 56 bits (7 bytes) which are received as two 28
10   bit modem frames.
11 
12   Demod states can be optionally logged to an Octave file for display
13   using the Octave script fdmdv_demod_c.m.  This is useful for
14   checking demod performance.
15 
16 \*---------------------------------------------------------------------------*/
17 
18 
19 /*
20   Copyright (C) 2012 David Rowe
21 
22   All rights reserved.
23 
24   This program is free software; you can redistribute it and/or modify
25   it under the terms of the GNU Lesser General Public License version 2.1, as
26   published by the Free Software Foundation.  This program is
27   distributed in the hope that it will be useful, but WITHOUT ANY
28   WARRANTY; without even the implied warranty of MERCHANTABILITY or
29   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
30   License for more details.
31 
32   You should have received a copy of the GNU Lesser General Public License
33   along with this program; if not, see <http://www.gnu.org/licenses/>.
34 */
35 
36 #include <assert.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <math.h>
41 #include <errno.h>
42 
43 #include "codec2_fdmdv.h"
44 #include "octave.h"
45 #include "freedv_api.h"
46 
47 #include "debug_alloc.h"
48 
49 /* lof of information we want to dump to Octave */
50 
51 #define MAX_FRAMES 50*60 /* 1 minute at 50 symbols/s */
52 
main(int argc,char * argv[])53 int main(int argc, char *argv[])
54 {
55     FILE         *fin, *fout;
56     struct FDMDV *fdmdv;
57     char         *packed_bits;
58     int          *rx_bits;
59     int          *codec_bits;
60     COMP          rx_fdm[FDMDV_MAX_SAMPLES_PER_FRAME];
61     short         rx_fdm_scaled[FDMDV_MAX_SAMPLES_PER_FRAME];
62     int           i, bit, byte, c;
63     int           nin, nin_prev;
64     int           sync_bit = 0, reliable_sync_bit;
65     int           sync = 0;
66     int           f;
67     FILE         *foct = NULL;
68     struct MODEM_STATS stats;
69     COMP         *rx_fdm_log;
70     int           rx_fdm_log_col_index;
71     COMP         *rx_symbols_log;
72     int           sync_log[MAX_FRAMES];
73     float         rx_timing_log[MAX_FRAMES];
74     float         foff_log[MAX_FRAMES];
75     int           sync_bit_log[MAX_FRAMES];
76     int           rx_bits_log[FDMDV_BITS_PER_FRAME*MAX_FRAMES];
77     float         snr_est_log[MAX_FRAMES];
78     float        *rx_spec_log;
79     int           max_frames_reached;
80     int           bits_per_fdmdv_frame;
81     int           bits_per_codec_frame;
82     int           bytes_per_codec_frame;
83     int           Nc;
84 
85     if (argc < 2) {
86 	printf("usage: %s InputModemRawFile OutputBitFile [Nc [OctaveDumpFile]]\n", argv[0]);
87 	printf("e.g    %s hts1a_fdmdv.raw hts1a.c2\n", argv[0]);
88 	exit(1);
89     }
90 
91     if (strcmp(argv[1], "-")  == 0) fin = stdin;
92     else if ( (fin = fopen(argv[1],"rb")) == NULL ) {
93 	fprintf(stderr, "Error opening input modem sample file: %s: %s.\n",
94          argv[1], strerror(errno));
95 	exit(1);
96     }
97 
98     if (strcmp(argv[2], "-") == 0) fout = stdout;
99     else if ( (fout = fopen(argv[2],"wb")) == NULL ) {
100 	fprintf(stderr, "Error opening output bit file: %s: %s.\n",
101          argv[2], strerror(errno));
102 	exit(1);
103     }
104 
105     if (argc >= 4) {
106         Nc = atoi(argv[3]);
107 
108         if ((Nc < 2) || (Nc > FDMDV_NC_MAX) ) {
109             fprintf(stderr, "Error number of carriers must be between 2 and %d\n",  FDMDV_NC_MAX);
110             exit(1);
111         }
112     }
113     else
114         Nc = FDMDV_NC;
115 
116     fdmdv = fdmdv_create(Nc);
117     modem_stats_open(&stats);
118 
119     bits_per_fdmdv_frame = fdmdv_bits_per_frame(fdmdv);
120     bits_per_codec_frame = 2*fdmdv_bits_per_frame(fdmdv);
121     bytes_per_codec_frame = (bits_per_codec_frame+7)/8;
122 
123     /* malloc some buffers that are dependant on Nc */
124 
125     packed_bits = (char*)MALLOC(bytes_per_codec_frame); assert(packed_bits != NULL);
126     rx_bits = (int*)MALLOC(sizeof(int)*bits_per_codec_frame); assert(rx_bits != NULL);
127     codec_bits = (int*)MALLOC(2*sizeof(int)*bits_per_fdmdv_frame); assert(codec_bits != NULL);
128 
129     /* malloc some of the larger variables to prevent out of stack problems */
130 
131     rx_fdm_log = (COMP*)MALLOC(sizeof(COMP)*FDMDV_MAX_SAMPLES_PER_FRAME*MAX_FRAMES);
132     assert(rx_fdm_log != NULL);
133     rx_spec_log = (float*)MALLOC(sizeof(float)*MODEM_STATS_NSPEC*MAX_FRAMES);
134     assert(rx_spec_log != NULL);
135     rx_symbols_log = (COMP*)MALLOC(sizeof(COMP)*(Nc+1)*MAX_FRAMES);
136     assert(rx_fdm_log != NULL);
137 
138     f = 0;
139     nin = FDMDV_NOM_SAMPLES_PER_FRAME;
140     rx_fdm_log_col_index = 0;
141     max_frames_reached = 0;
142 
143     while(fread(rx_fdm_scaled, sizeof(short), nin, fin) == nin)
144     {
145 	for(i=0; i<nin; i++) {
146 	    rx_fdm[i].real = (float)rx_fdm_scaled[i]/FDMDV_SCALE;
147             rx_fdm[i].imag = 0;
148         }
149 	nin_prev = nin;
150 	fdmdv_demod(fdmdv, rx_bits, &reliable_sync_bit, rx_fdm, &nin);
151 
152 	/* log data for optional Octave dump */
153 
154 	if (f < MAX_FRAMES) {
155 	    fdmdv_get_demod_stats(fdmdv, &stats);
156 
157 	    /* log modem states for later dumping to Octave log file */
158 
159 	    memcpy(&rx_fdm_log[rx_fdm_log_col_index], rx_fdm, sizeof(COMP)*nin_prev);
160 	    rx_fdm_log_col_index += nin_prev;
161 
162 	    for(c=0; c<Nc+1; c++)
163 		rx_symbols_log[f*(Nc+1)+c] = stats.rx_symbols[0][c];
164 	    foff_log[f] = stats.foff;
165 	    rx_timing_log[f] = stats.rx_timing;
166 	    sync_log[f] = stats.sync;
167 	    sync_bit_log[f] = sync_bit;
168 	    memcpy(&rx_bits_log[bits_per_fdmdv_frame*f], rx_bits, sizeof(int)*bits_per_fdmdv_frame);
169 	    snr_est_log[f] = stats.snr_est;
170 
171 	    modem_stats_get_rx_spectrum(&stats, &rx_spec_log[f*MODEM_STATS_NSPEC], rx_fdm, nin_prev);
172 
173 	    f++;
174 	}
175 
176 	if ((f == MAX_FRAMES) && !max_frames_reached) {
177 	    fprintf(stderr,"MAX_FRAMES exceed in Octave log, log truncated\n");
178 	    max_frames_reached = 1;
179 	}
180 
181         if (reliable_sync_bit)
182             sync = 1;
183         //printf("sync_bit: %d reliable_sync_bit: %d sync: %d\n", sync_bit, reliable_sync_bit, sync);
184 
185         if (sync == 0) {
186             memcpy(codec_bits, rx_bits, bits_per_fdmdv_frame*sizeof(int));
187             sync = 1;
188         }
189         else {
190             memcpy(&codec_bits[bits_per_fdmdv_frame], rx_bits, bits_per_fdmdv_frame*sizeof(int));
191 
192             /* pack bits, MSB received first  */
193 
194             bit = 7; byte = 0;
195             memset(packed_bits, 0, bytes_per_codec_frame);
196             for(i=0; i<bits_per_codec_frame; i++) {
197                 packed_bits[byte] |= (codec_bits[i] << bit);
198                 bit--;
199                 if (bit < 0) {
200                     bit = 7;
201                     byte++;
202                 }
203             }
204 
205             fwrite(packed_bits, sizeof(char), bytes_per_codec_frame, fout);
206             sync = 0;
207         }
208 
209 
210 	/* if this is in a pipeline, we probably don't want the usual
211 	   buffering to occur */
212 
213         if (fout == stdout) fflush(stdout);
214     }
215 
216     /* Optional dump to Octave log file */
217 
218     if (argc == 5) {
219 
220 	if ((foct = fopen(argv[4],"wt")) == NULL ) {
221 	    fprintf(stderr, "Error opening Octave dump file: %s: %s.\n",
222 		argv[4], strerror(errno));
223 	    exit(1);
224 	}
225 	octave_save_complex(foct, "rx_fdm_log_c", rx_fdm_log, 1, rx_fdm_log_col_index, FDMDV_MAX_SAMPLES_PER_FRAME);
226 	octave_save_complex(foct, "rx_symbols_log_c", (COMP*)rx_symbols_log, Nc+1, f, MAX_FRAMES);
227 	octave_save_float(foct, "foff_log_c", foff_log, 1, f, MAX_FRAMES);
228 	octave_save_float(foct, "rx_timing_log_c", rx_timing_log, 1, f, MAX_FRAMES);
229 	octave_save_int(foct, "sync_log_c", sync_log, 1, f);
230 	octave_save_int(foct, "rx_bits_log_c", rx_bits_log, 1, bits_per_fdmdv_frame*f);
231 	octave_save_int(foct, "sync_bit_log_c", sync_bit_log, 1, f);
232 	octave_save_float(foct, "snr_est_log_c", snr_est_log, 1, f, MAX_FRAMES);
233 	octave_save_float(foct, "rx_spec_log_c", rx_spec_log, f, MODEM_STATS_NSPEC, MODEM_STATS_NSPEC);
234 	fclose(foct);
235     }
236 
237     //fdmdv_dump_osc_mags(fdmdv);
238 
239     fclose(fin);
240     fclose(fout);
241     FREE(rx_fdm_log);
242     FREE(rx_spec_log);
243     fdmdv_destroy(fdmdv);
244 
245     if (packed_bits != NULL) FREE(packed_bits);
246 
247     return 0;
248 }
249 
250