1 //
2 //    This file is part of Dire Wolf, an amateur radio packet TNC.
3 //
4 //    Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2019  John Langner, WB2OSZ
5 //
6 //    This program is free software: you can redistribute it and/or modify
7 //    it under the terms of the GNU General Public License as published by
8 //    the Free Software Foundation, either version 2 of the License, or
9 //    (at your option) any later version.
10 //
11 //    This program is distributed in the hope that it will be useful,
12 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //    GNU General Public License for more details.
15 //
16 //    You should have received a copy of the GNU General Public License
17 //    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 //
19 
20 
21 
22 /*------------------------------------------------------------------
23  *
24  * Module:      demod.c
25  *
26  * Purpose:   	Common entry point for multiple types of demodulators.
27  *
28  * Input:	Audio samples from either a file or the "sound card."
29  *
30  * Outputs:	Calls hdlc_rec_bit() for each bit demodulated.
31  *
32  *---------------------------------------------------------------*/
33 
34 #include "direwolf.h"
35 
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <math.h>
39 #include <unistd.h>
40 #include <sys/stat.h>
41 #include <string.h>
42 #include <assert.h>
43 #include <ctype.h>
44 
45 #include "audio.h"
46 #include "demod.h"
47 #include "tune.h"
48 #include "fsk_demod_state.h"
49 #include "fsk_gen_filter.h"
50 #include "hdlc_rec.h"
51 #include "textcolor.h"
52 #include "demod_9600.h"
53 #include "demod_afsk.h"
54 #include "demod_psk.h"
55 
56 
57 
58 // Properties of the radio channels.
59 
60 static struct audio_s          *save_audio_config_p;
61 
62 
63 // TODO: temp experiment.
64 
65 
66 static int zerostuff = 1;	// temp experiment.
67 
68 // Current state of all the decoders.
69 
70 static struct demodulator_state_s demodulator_state[MAX_CHANS][MAX_SUBCHANS];
71 
72 
73 static int sample_sum[MAX_CHANS][MAX_SUBCHANS];
74 static int sample_count[MAX_CHANS][MAX_SUBCHANS];
75 
76 
77 /*------------------------------------------------------------------
78  *
79  * Name:        demod_init
80  *
81  * Purpose:     Initialize the demodulator(s) used for reception.
82  *
83  * Inputs:      pa		- Pointer to audio_s structure with
84  *				  various parameters for the modem(s).
85  *
86  * Returns:     0 for success, -1 for failure.
87  *
88  *
89  * Bugs:	This doesn't do much error checking so don't give it
90  *		anything crazy.
91  *
92  *----------------------------------------------------------------*/
93 
demod_init(struct audio_s * pa)94 int demod_init (struct audio_s *pa)
95 {
96 	int chan;		/* Loop index over number of radio channels. */
97 	char profile;
98 
99 
100 
101 /*
102  * Save audio configuration for later use.
103  */
104 
105 	save_audio_config_p = pa;
106 
107 	for (chan = 0; chan < MAX_CHANS; chan++) {
108 
109 	 if (save_audio_config_p->achan[chan].medium == MEDIUM_RADIO) {
110 
111 	  char *p;
112 	  char just_letters[16];
113 	  int num_letters;
114 	  int have_plus;
115 
116 	  /*
117 	   * These are derived from config file parameters.
118 	   *
119 	   * num_subchan is number of demodulators.
120 	   * This can be increased by:
121 	   *	Multiple frequencies.
122 	   *	Multiple letters (not sure if I will continue this).
123 	   *
124 	   * num_slicers is set to max by the "+" option.
125 	   */
126 
127 	  save_audio_config_p->achan[chan].num_subchan = 1;
128 	  save_audio_config_p->achan[chan].num_slicers = 1;
129 
130 	  switch (save_audio_config_p->achan[chan].modem_type) {
131 
132 	    case MODEM_OFF:
133 	      break;
134 
135 	    case MODEM_AFSK:
136 	    case MODEM_EAS:
137 
138 	      if (save_audio_config_p->achan[chan].modem_type == MODEM_EAS) {
139 		if (save_audio_config_p->achan[chan].fix_bits != RETRY_NONE) {
140 	          text_color_set(DW_COLOR_INFO);
141 		  dw_printf ("Channel %d: FIX_BITS option has been turned off for EAS.\n", chan);
142 	          save_audio_config_p->achan[chan].fix_bits = RETRY_NONE;
143 	        }
144 		if (save_audio_config_p->achan[chan].passall != 0) {
145 	          text_color_set(DW_COLOR_INFO);
146 		  dw_printf ("Channel %d: PASSALL option has been turned off for EAS.\n", chan);
147 	          save_audio_config_p->achan[chan].passall = 0;
148 	        }
149 	      }
150 
151 /*
152  * Tear apart the profile and put it back together in a normalized form:
153  *	- At least one letter, supply suitable default if necessary.
154  *	- Upper case only.
155  *	- Any plus will be at the end.
156  */
157 	      num_letters = 0;
158 	      just_letters[num_letters] = '\0';
159 	      have_plus = 0;
160 	      for (p = save_audio_config_p->achan[chan].profiles; *p != '\0'; p++) {
161 
162 	        if (islower(*p)) {
163 	          just_letters[num_letters] = toupper(*p);
164 	          num_letters++;
165 	          just_letters[num_letters] = '\0';
166 	        }
167 
168 	        else if (isupper(*p)) {
169 	          just_letters[num_letters] = *p;
170 	          num_letters++;
171 	          just_letters[num_letters] = '\0';
172 	        }
173 
174 	        else if (*p == '+') {
175 	          have_plus = 1;
176 	          if (p[1] != '\0') {
177 		    text_color_set(DW_COLOR_ERROR);
178 		    dw_printf ("Channel %d: + option must appear at end of demodulator types \"%s\" \n",
179 					chan, save_audio_config_p->achan[chan].profiles);
180 		  }
181 	        }
182 
183 	        else if (*p == '-') {
184 	          have_plus = -1;
185 	          if (p[1] != '\0') {
186 		    text_color_set(DW_COLOR_ERROR);
187 		    dw_printf ("Channel %d: - option must appear at end of demodulator types \"%s\" \n",
188 					chan, save_audio_config_p->achan[chan].profiles);
189 		  }
190 
191 	        } else {
192 		  text_color_set(DW_COLOR_ERROR);
193 		  dw_printf ("Channel %d: Demodulator types \"%s\" can contain only letters and + - characters.\n",
194 					chan, save_audio_config_p->achan[chan].profiles);
195 	        }
196 	      }
197 
198 	      assert (num_letters == (int)(strlen(just_letters)));
199 
200 /*
201  * Pick a good default demodulator if none specified.
202  */
203 	      if (num_letters == 0) {
204 
205 	        if (save_audio_config_p->achan[chan].baud < 600) {
206 
207 	          /* This has been optimized for 300 baud. */
208 
209 	          strlcpy (just_letters, "D", sizeof(just_letters));
210 
211 	        }
212 	        else {
213 #if __arm__
214 	          /* We probably don't have a lot of CPU power available. */
215 	          /* Previously we would use F if possible otherwise fall back to A. */
216 
217 	          /* In version 1.2, new default is E+ /3. */
218 	          strlcpy (just_letters, "E", sizeof(just_letters));			// version 1.2 now E.
219 	          if (have_plus != -1) have_plus = 1;		// Add as default for version 1.2
220 								// If not explicitly turned off.
221 	          if (save_audio_config_p->achan[chan].decimate == 0) {
222 	            if (save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec > 40000) {
223 	              save_audio_config_p->achan[chan].decimate = 3;
224 	            }
225 	          }
226 #else
227 	          strlcpy (just_letters, "E", sizeof(just_letters));			// version 1.2 changed C to E.
228 	          if (have_plus != -1) have_plus = 1;		// Add as default for version 1.2
229 								// If not explicitly turned off.
230 #endif
231 	        }
232 	        num_letters = 1;
233 	      }
234 
235 
236 	      assert (num_letters == (int)(strlen(just_letters)));
237 
238 /*
239  * Put it back together again.
240  */
241 
242 		/* At this point, have_plus can have 3 values: */
243 		/* 	1 = turned on, either explicitly or by applied default */
244 		/*	-1 = explicitly turned off.  change to 0 here so it is false. */
245 		/* 	0 = off by default. */
246 
247 	      if (have_plus == -1) have_plus = 0;
248 
249 	      strlcpy (save_audio_config_p->achan[chan].profiles, just_letters, sizeof(save_audio_config_p->achan[chan].profiles));
250 
251 	      assert (strlen(save_audio_config_p->achan[chan].profiles) >= 1);
252 
253 	      if (have_plus) {
254 	        strlcat (save_audio_config_p->achan[chan].profiles, "+", sizeof(save_audio_config_p->achan[chan].profiles));
255 	      }
256 
257 	      /* These can be increased later for the multi-frequency case. */
258 
259 	      save_audio_config_p->achan[chan].num_subchan = num_letters;
260 	      save_audio_config_p->achan[chan].num_slicers = 1;
261 
262 /*
263  * Some error checking - Can use only one of these:
264  *
265  *	- Multiple letters.
266  *	- New + multi-slicer.
267  *	- Multiple frequencies.
268  */
269 
270 	      if (have_plus && save_audio_config_p->achan[chan].num_freq > 1) {
271 
272 		  text_color_set(DW_COLOR_ERROR);
273 		  dw_printf ("Channel %d: Demodulator + option can't be combined with multiple frequencies.\n", chan);
274 	          save_audio_config_p->achan[chan].num_subchan = 1;	// Will be set higher later.
275 	          save_audio_config_p->achan[chan].num_freq = 1;
276 	      }
277 
278 	      if (num_letters > 1 && save_audio_config_p->achan[chan].num_freq > 1) {
279 
280 		  text_color_set(DW_COLOR_ERROR);
281 		  dw_printf ("Channel %d: Multiple demodulator types can't be combined with multiple frequencies.\n", chan);
282 
283 	          save_audio_config_p->achan[chan].profiles[1] = '\0';
284 		  num_letters = 1;
285 	      }
286 
287 	      if (save_audio_config_p->achan[chan].decimate == 0) {
288 	        save_audio_config_p->achan[chan].decimate = 1;
289 		if (strchr (just_letters, 'D') != NULL && save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec > 40000) {
290 		  save_audio_config_p->achan[chan].decimate = 3;
291 		}
292 	      }
293 
294 	      text_color_set(DW_COLOR_DEBUG);
295 	      dw_printf ("Channel %d: %d baud, AFSK %d & %d Hz, %s, %d sample rate",
296 		    chan, save_audio_config_p->achan[chan].baud,
297 		    save_audio_config_p->achan[chan].mark_freq, save_audio_config_p->achan[chan].space_freq,
298 		    save_audio_config_p->achan[chan].profiles,
299 		    save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec);
300 	      if (save_audio_config_p->achan[chan].decimate != 1)
301 	        dw_printf (" / %d", save_audio_config_p->achan[chan].decimate);
302 	      if (save_audio_config_p->achan[chan].dtmf_decode != DTMF_DECODE_OFF)
303 	        dw_printf (", DTMF decoder enabled");
304 	      dw_printf (".\n");
305 
306 
307 /*
308  * Initialize the demodulator(s).
309  *
310  * We have 3 cases to consider.
311  */
312 
313 // TODO1.3: revisit this logic now that it is less restrictive.
314 
315 	      if (num_letters > 1) {
316 	        int d;
317 
318 /*
319  * Multiple letters, usually for 1200 baud.
320  * Each one corresponds to a demodulator and subchannel.
321  *
322  * An interesting experiment but probably not too useful.
323  * Can't have multiple frequency pairs.
324  * In version 1.3 this can be combined with the + option.
325  */
326 
327 	        save_audio_config_p->achan[chan].num_subchan = num_letters;
328 
329 		if (save_audio_config_p->achan[chan].num_subchan != num_letters) {
330 		  text_color_set(DW_COLOR_ERROR);
331 		  dw_printf ("INTERNAL ERROR, %s:%d, chan=%d, num_subchan(%d) != strlen(\"%s\")\n",
332 				__FILE__, __LINE__, chan, save_audio_config_p->achan[chan].num_subchan, save_audio_config_p->achan[chan].profiles);
333 		}
334 
335 	        if (save_audio_config_p->achan[chan].num_freq != 1) {
336 		  text_color_set(DW_COLOR_ERROR);
337 		  dw_printf ("INTERNAL ERROR, %s:%d, chan=%d, num_freq(%d) != 1\n",
338 				__FILE__, __LINE__, chan, save_audio_config_p->achan[chan].num_freq);
339 		}
340 
341 	        for (d = 0; d < save_audio_config_p->achan[chan].num_subchan; d++) {
342 	          int mark, space;
343 	          assert (d >= 0 && d < MAX_SUBCHANS);
344 
345 	          struct demodulator_state_s *D;
346 	          D = &demodulator_state[chan][d];
347 
348 	          profile = save_audio_config_p->achan[chan].profiles[d];
349 	          mark = save_audio_config_p->achan[chan].mark_freq;
350 	          space = save_audio_config_p->achan[chan].space_freq;
351 
352 	          if (save_audio_config_p->achan[chan].num_subchan != 1) {
353 	            text_color_set(DW_COLOR_DEBUG);
354 	            dw_printf ("        %d.%d: %c %d & %d\n", chan, d, profile, mark, space);
355 	          }
356 
357 	          demod_afsk_init (save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec / save_audio_config_p->achan[chan].decimate,
358 			    save_audio_config_p->achan[chan].baud,
359 		            mark,
360 	                    space,
361 			    profile,
362 			    D);
363 
364 	          if (have_plus) {
365 		    /* I'm not happy about putting this hack here. */
366 		    /* should pass in as a parameter rather than adding on later. */
367 
368 	            save_audio_config_p->achan[chan].num_slicers = MAX_SLICERS;
369 		    D->num_slicers = MAX_SLICERS;
370 	          }
371 
372 	          /* For signal level reporting, we want a longer term view. */
373 		  // TODO: Should probably move this into the init functions.
374 
375 	          D->quick_attack = D->agc_fast_attack * 0.2f;
376 	          D->sluggish_decay = D->agc_slow_decay * 0.2f;
377 	        }
378 	      }
379 	      else if (have_plus) {
380 
381 /*
382  * PLUS - which (formerly) implies we have only one letter and one frequency pair.
383  *
384  * One demodulator feeds multiple slicers, each a subchannel.
385  */
386 
387 	        if (num_letters != 1) {
388 		  text_color_set(DW_COLOR_ERROR);
389 		  dw_printf ("INTERNAL ERROR, %s:%d, chan=%d, strlen(\"%s\") != 1\n",
390 				__FILE__, __LINE__, chan, just_letters);
391 		}
392 
393 	        if (save_audio_config_p->achan[chan].num_freq != 1) {
394 		  text_color_set(DW_COLOR_ERROR);
395 		  dw_printf ("INTERNAL ERROR, %s:%d, chan=%d, num_freq(%d) != 1\n",
396 				__FILE__, __LINE__, chan, save_audio_config_p->achan[chan].num_freq);
397 		}
398 
399 	        if (save_audio_config_p->achan[chan].num_freq != save_audio_config_p->achan[chan].num_subchan) {
400 		  text_color_set(DW_COLOR_ERROR);
401 		  dw_printf ("INTERNAL ERROR, %s:%d, chan=%d, num_freq(%d) != num_subchan(%d)\n",
402 				__FILE__, __LINE__, chan, save_audio_config_p->achan[chan].num_freq, save_audio_config_p->achan[chan].num_subchan);
403 		}
404 
405 	        struct demodulator_state_s *D;
406 	        D = &demodulator_state[chan][0];
407 
408 		/* I'm not happy about putting this hack here. */
409 		/* This belongs in demod_afsk_init but it doesn't have access to the audio config. */
410 
411 	        save_audio_config_p->achan[chan].num_slicers = MAX_SLICERS;
412 
413 	        demod_afsk_init (save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec / save_audio_config_p->achan[chan].decimate,
414 			save_audio_config_p->achan[chan].baud,
415 			save_audio_config_p->achan[chan].mark_freq,
416 	                save_audio_config_p->achan[chan].space_freq,
417 			save_audio_config_p->achan[chan].profiles[0],
418 			D);
419 
420 	        if (have_plus) {
421 		  /* I'm not happy about putting this hack here. */
422 		  /* should pass in as a parameter rather than adding on later. */
423 
424 	          save_audio_config_p->achan[chan].num_slicers = MAX_SLICERS;
425 		  D->num_slicers = MAX_SLICERS;
426 	        }
427 
428 	        /* For signal level reporting, we want a longer term view. */
429 
430 	        D->quick_attack = D->agc_fast_attack * 0.2f;
431 	        D->sluggish_decay = D->agc_slow_decay * 0.2f;
432 	      }
433 	      else {
434 	        int d;
435 /*
436  * One letter.
437  * Can be combined with multiple frequencies.
438  */
439 
440 	        if (num_letters != 1) {
441 		  text_color_set(DW_COLOR_ERROR);
442 		  dw_printf ("INTERNAL ERROR, %s:%d, chan=%d, strlen(\"%s\") != 1\n",
443 				__FILE__, __LINE__, chan, save_audio_config_p->achan[chan].profiles);
444 		}
445 
446 	        save_audio_config_p->achan[chan].num_subchan = save_audio_config_p->achan[chan].num_freq;
447 
448 	        for (d = 0; d < save_audio_config_p->achan[chan].num_freq; d++) {
449 
450 	          int mark, space, k;
451 	          assert (d >= 0 && d < MAX_SUBCHANS);
452 
453 	          struct demodulator_state_s *D;
454 	          D = &demodulator_state[chan][d];
455 
456 	          profile = save_audio_config_p->achan[chan].profiles[0];
457 
458 	          k = d * save_audio_config_p->achan[chan].offset - ((save_audio_config_p->achan[chan].num_freq - 1) * save_audio_config_p->achan[chan].offset) / 2;
459 	          mark = save_audio_config_p->achan[chan].mark_freq + k;
460 	          space = save_audio_config_p->achan[chan].space_freq + k;
461 
462 	          if (save_audio_config_p->achan[chan].num_freq != 1) {
463 	            text_color_set(DW_COLOR_DEBUG);
464 	            dw_printf ("        %d.%d: %c %d & %d\n", chan, d, profile, mark, space);
465 	          }
466 
467 	          demod_afsk_init (save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec / save_audio_config_p->achan[chan].decimate,
468 			save_audio_config_p->achan[chan].baud,
469 			mark, space,
470 			profile,
471 			D);
472 
473 	          if (have_plus) {
474 		    /* I'm not happy about putting this hack here. */
475 		    /* should pass in as a parameter rather than adding on later. */
476 
477 	            save_audio_config_p->achan[chan].num_slicers = MAX_SLICERS;
478 		    D->num_slicers = MAX_SLICERS;
479 	          }
480 
481 	          /* For signal level reporting, we want a longer term view. */
482 
483 	          D->quick_attack = D->agc_fast_attack * 0.2f;
484 	          D->sluggish_decay = D->agc_slow_decay * 0.2f;
485 
486 	        } 	  /* for each freq pair */
487 	      }
488 	      break;
489 
490 	    case MODEM_QPSK:		// New for 1.4
491 
492 	      // In versions 1.4 and 1.5, V.26 "Alternative A" was used.
493 	      // years later, I discover that the MFJ-2400 used "Alternative B."
494 	      // It looks like the other two manufacturers use the same but we
495               // can't be sure until we find one for compatbility testing.
496 
497 	      // In version 1.6 we add a choice for the user.
498 	      // If neither one was explicitly specified, print a message and take
499 	      // a default.  My current thinking is that we default to direwolf <= 1.5
500 	      // compatible for version 1.6 and MFJ compatible after that.
501 
502 	      if (save_audio_config_p->achan[chan].v26_alternative == V26_UNSPECIFIED) {
503 
504 	        text_color_set(DW_COLOR_ERROR);
505 	        dw_printf ("Two incompatible versions of 2400 bps QPSK are now available.\n");
506 	        dw_printf ("For compatbility with direwolf <= 1.5, use 'V26A' modem option in config file.\n");
507 	        dw_printf ("For compatbility MFJ-2400 use 'V26B' modem option in config file.\n");
508 	        dw_printf ("Command line options -j and -J can be used for channel 0.\n");
509 	        dw_printf ("For more information, read the Dire Wolf User Guide and\n");
510 	        dw_printf ("2400-4800-PSK-for-APRS-Packet-Radio.pdf.\n");
511 	        dw_printf ("The default is now MFJ-2400 compatibility mode.\n");
512 
513 	        save_audio_config_p->achan[chan].v26_alternative = V26_DEFAULT;
514 	      }
515 
516 
517 // TODO: See how much CPU this takes on ARM and decide if we should have different defaults.
518 
519 	      if (strlen(save_audio_config_p->achan[chan].profiles) == 0) {
520 //#if __arm__
521 //	        strlcpy (save_audio_config_p->achan[chan].profiles, "R", sizeof(save_audio_config_p->achan[chan].profiles));
522 //#else
523 	        strlcpy (save_audio_config_p->achan[chan].profiles, "PQRS", sizeof(save_audio_config_p->achan[chan].profiles));
524 //#endif
525 	      }
526 	      save_audio_config_p->achan[chan].num_subchan = strlen(save_audio_config_p->achan[chan].profiles);
527 
528 	      save_audio_config_p->achan[chan].decimate = 1;	// think about this later.
529 	      text_color_set(DW_COLOR_DEBUG);
530 	      dw_printf ("Channel %d: %d bps, QPSK, %s, %d sample rate",
531 		    chan, save_audio_config_p->achan[chan].baud,
532 		    save_audio_config_p->achan[chan].profiles,
533 		    save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec);
534 	      if (save_audio_config_p->achan[chan].decimate != 1)
535 	        dw_printf (" / %d", save_audio_config_p->achan[chan].decimate);
536 
537 	      if (save_audio_config_p->achan[chan].v26_alternative == V26_B)
538 	        dw_printf (", compatible with MFJ-2400");
539 	      else
540 	        dw_printf (", compatible with earlier direwolf");
541 
542 	      if (save_audio_config_p->achan[chan].dtmf_decode != DTMF_DECODE_OFF)
543 	        dw_printf (", DTMF decoder enabled");
544 	      dw_printf (".\n");
545 
546 	      int d;
547 	      for (d = 0; d < save_audio_config_p->achan[chan].num_subchan; d++) {
548 
549 	        assert (d >= 0 && d < MAX_SUBCHANS);
550 	        struct demodulator_state_s *D;
551 	        D = &demodulator_state[chan][d];
552 	        profile = save_audio_config_p->achan[chan].profiles[d];
553 
554 	        //text_color_set(DW_COLOR_DEBUG);
555 	        //dw_printf ("About to call demod_psk_init for Q-PSK case, modem_type=%d, profile='%c'\n",
556 		//	save_audio_config_p->achan[chan].modem_type, profile);
557 
558 	        demod_psk_init (save_audio_config_p->achan[chan].modem_type,
559 			save_audio_config_p->achan[chan].v26_alternative,
560 			save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec / save_audio_config_p->achan[chan].decimate,
561 			save_audio_config_p->achan[chan].baud,
562 			profile,
563 			D);
564 
565 	        //text_color_set(DW_COLOR_DEBUG);
566 	        //dw_printf ("Returned from demod_psk_init\n");
567 
568 	        /* For signal level reporting, we want a longer term view. */
569 		/* Guesses based on 9600.  Maybe revisit someday. */
570 
571 	        D->quick_attack = 0.080 * 0.2;
572 	        D->sluggish_decay = 0.00012 * 0.2;
573 	      }
574 	      break;
575 
576 	    case MODEM_8PSK:		// New for 1.4
577 
578 // TODO: See how much CPU this takes on ARM and decide if we should have different defaults.
579 
580 	      if (strlen(save_audio_config_p->achan[chan].profiles) == 0) {
581 //#if __arm__
582 //	        strlcpy (save_audio_config_p->achan[chan].profiles, "V", sizeof(save_audio_config_p->achan[chan].profiles));
583 //#else
584 	        strlcpy (save_audio_config_p->achan[chan].profiles, "TUVW", sizeof(save_audio_config_p->achan[chan].profiles));
585 //#endif
586 	      }
587 	      save_audio_config_p->achan[chan].num_subchan = strlen(save_audio_config_p->achan[chan].profiles);
588 
589 	      save_audio_config_p->achan[chan].decimate = 1;	// think about this later
590 	      text_color_set(DW_COLOR_DEBUG);
591 	      dw_printf ("Channel %d: %d bps, 8PSK, %s, %d sample rate",
592 		    chan, save_audio_config_p->achan[chan].baud,
593 		    save_audio_config_p->achan[chan].profiles,
594 		    save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec);
595 	      if (save_audio_config_p->achan[chan].decimate != 1)
596 	        dw_printf (" / %d", save_audio_config_p->achan[chan].decimate);
597 	      if (save_audio_config_p->achan[chan].dtmf_decode != DTMF_DECODE_OFF)
598 	        dw_printf (", DTMF decoder enabled");
599 	      dw_printf (".\n");
600 
601 	      //int d;
602 	      for (d = 0; d < save_audio_config_p->achan[chan].num_subchan; d++) {
603 
604 	        assert (d >= 0 && d < MAX_SUBCHANS);
605 	        struct demodulator_state_s *D;
606 	        D = &demodulator_state[chan][d];
607 	        profile = save_audio_config_p->achan[chan].profiles[d];
608 
609 	        //text_color_set(DW_COLOR_DEBUG);
610 	        //dw_printf ("About to call demod_psk_init for 8-PSK case, modem_type=%d, profile='%c'\n",
611 		//	save_audio_config_p->achan[chan].modem_type, profile);
612 
613 	        demod_psk_init (save_audio_config_p->achan[chan].modem_type,
614 			save_audio_config_p->achan[chan].v26_alternative,
615 			save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec / save_audio_config_p->achan[chan].decimate,
616 			save_audio_config_p->achan[chan].baud,
617 			profile,
618 			D);
619 
620 	        //text_color_set(DW_COLOR_DEBUG);
621 	        //dw_printf ("Returned from demod_psk_init\n");
622 
623 	        /* For signal level reporting, we want a longer term view. */
624 		/* Guesses based on 9600.  Maybe revisit someday. */
625 
626 	        D->quick_attack = 0.080 * 0.2;
627 	        D->sluggish_decay = 0.00012 * 0.2;
628 	      }
629 	      break;
630 
631 //TODO: how about MODEM_OFF case?
632 
633 	    case MODEM_BASEBAND:
634 	    case MODEM_SCRAMBLE:
635 	    case MODEM_AIS:
636 	    default:	/* Not AFSK */
637 	      {
638 
639 	      // For AIS we will accept only a good CRC without any fixup attempts.
640 	      // Even with that, there are still a lot of CRC false matches with random noise.
641 
642 	      if (save_audio_config_p->achan[chan].modem_type == MODEM_AIS) {
643 		if (save_audio_config_p->achan[chan].fix_bits != RETRY_NONE) {
644 	          text_color_set(DW_COLOR_INFO);
645 		  dw_printf ("Channel %d: FIX_BITS option has been turned off for AIS.\n", chan);
646 	          save_audio_config_p->achan[chan].fix_bits = RETRY_NONE;
647 	        }
648 		if (save_audio_config_p->achan[chan].passall != 0) {
649 	          text_color_set(DW_COLOR_INFO);
650 		  dw_printf ("Channel %d: PASSALL option has been turned off for AIS.\n", chan);
651 	          save_audio_config_p->achan[chan].passall = 0;
652 	        }
653 	      }
654 
655 	      if (strcmp(save_audio_config_p->achan[chan].profiles, "") == 0) {
656 
657 		/* Apply default if not set earlier. */
658 		/* Not sure if it should be on for ARM too. */
659 		/* Need to take a look at CPU usage and performance difference. */
660 
661 		/* Version 1.5:  Remove special case for ARM. */
662 		/* We want higher performance to be the default. */
663 		/* "MODEM 9600 -" can be used on very slow CPU if necessary. */
664 
665 	        strlcpy (save_audio_config_p->achan[chan].profiles, "+", sizeof(save_audio_config_p->achan[chan].profiles));
666 	      }
667 
668 
669 #ifdef TUNE_ZEROSTUFF
670 	      zerostuff = TUNE_ZEROSTUFF;
671 #endif
672 
673 
674 /*
675  * We need a minimum number of audio samples per bit time for good performance.
676  * Easier to check here because demod_9600_init might have an adjusted sample rate.
677  */
678 
679 	      float ratio = (float)(save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec)
680 							/ (float)(save_audio_config_p->achan[chan].baud);
681 
682 /*
683  * Set reasonable upsample ratio if user did not override.
684  */
685 
686 	      if (save_audio_config_p->achan[chan].upsample == 0) {
687 
688 	        if (ratio < 5) {
689 
690 	          // example: 44100 / 9600 is 4.59
691 	          // Big improvement with x2.
692 	          // x4 seems to work the best.
693 	          // The other parameters are not as touchy.
694 	          // Might reduce on ARM if it takes too much CPU power.
695 
696 	          save_audio_config_p->achan[chan].upsample = 4;
697 	        }
698 	        else if (ratio < 10) {
699 
700 	          // 48000 / 9600 is 5.00
701 	          // Need more reasearch.  Treat like above for now.
702 
703 	          save_audio_config_p->achan[chan].upsample = 4;
704 	        }
705 	        else if (ratio < 15) {
706 
707 	          // ...
708 
709 	          save_audio_config_p->achan[chan].upsample = 2;
710 	        }
711 	        else {	// >= 15
712 	          //
713 	          // An example of this might be .....
714 	          // Probably no benefit.
715 
716 	          save_audio_config_p->achan[chan].upsample = 1;
717 	        }
718 	      }
719 
720 #ifdef TUNE_UPSAMPLE
721 	      save_audio_config_p->achan[chan].upsample = TUNE_UPSAMPLE;
722 #endif
723 
724 	      text_color_set(DW_COLOR_DEBUG);
725 	      dw_printf ("Channel %d: %d baud, %s, %s, %d sample rate x %d",
726 		    chan,
727 	            save_audio_config_p->achan[chan].baud,
728 	            save_audio_config_p->achan[chan].modem_type == MODEM_AIS ? "AIS" : "K9NG/G3RUH",
729 		    save_audio_config_p->achan[chan].profiles,
730 		    save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec,
731 	            save_audio_config_p->achan[chan].upsample);
732 	      if (save_audio_config_p->achan[chan].dtmf_decode != DTMF_DECODE_OFF)
733 	        dw_printf (", DTMF decoder enabled");
734 	      dw_printf (".\n");
735 
736 	      struct demodulator_state_s *D;
737 	      D = &demodulator_state[chan][0];	// first subchannel
738 
739 
740 	      save_audio_config_p->achan[chan].num_subchan = 1;
741               save_audio_config_p->achan[chan].num_slicers = 1;
742 
743 	      if (strchr(save_audio_config_p->achan[chan].profiles, '+') != NULL) {
744 
745 		/* I'm not happy about putting this hack here. */
746 		/* This belongs in demod_9600_init but it doesn't have access to the audio config. */
747 
748 	        save_audio_config_p->achan[chan].num_slicers = MAX_SLICERS;
749      	      }
750 
751 
752 	      text_color_set(DW_COLOR_INFO);
753 	      dw_printf ("The ratio of audio samples per sec (%d) to data rate in baud (%d) is %.1f\n",
754 				save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec,
755 				save_audio_config_p->achan[chan].baud,
756 				(double)ratio);
757 	      if (ratio < 3) {
758 	        text_color_set(DW_COLOR_ERROR);
759 	        dw_printf ("There is little hope of success with such a low ratio.  Use a higher sample rate.\n");
760 	      }
761 	      else if (ratio < 5) {
762 	        dw_printf ("This is on the low side for best performance.  Can you use a higher sample rate?\n");
763 	        if (save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec == 44100) {
764 	          dw_printf ("For example, can you use 48000 rather than 44100?\n");
765 	        }
766 	      }
767 	      else if (ratio < 6) {
768 	        dw_printf ("Increasing the sample rate should improve decoder performance.\n");
769 	      }
770 	      else if (ratio > 15) {
771 	        dw_printf ("Sample rate is more than adequate.  You might lower it if CPU load is a concern.\n");
772 	      }
773 	      else {
774 	        dw_printf ("This is a suitable ratio for good performance.\n");
775 	      }
776 
777 	      demod_9600_init (save_audio_config_p->achan[chan].modem_type,
778 			save_audio_config_p->achan[chan].upsample * save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec,
779 			save_audio_config_p->achan[chan].baud, D);
780 
781 	      if (strchr(save_audio_config_p->achan[chan].profiles, '+') != NULL) {
782 
783 		/* I'm not happy about putting this hack here. */
784 		/* should pass in as a parameter rather than adding on later. */
785 
786 	        save_audio_config_p->achan[chan].num_slicers = MAX_SLICERS;
787 		D->num_slicers = MAX_SLICERS;
788 	      }
789 
790 	      /* For signal level reporting, we want a longer term view. */
791 
792 	      D->quick_attack = D->agc_fast_attack * 0.2f;
793 	      D->sluggish_decay = D->agc_slow_decay * 0.2f;
794 	      }
795 	      break;
796 
797 	  }  /* switch on modulation type. */
798 
799 	 }  /* if channel number is valid */
800 
801 	}  /* for chan ... */
802 
803 
804         return (0);
805 
806 } /* end demod_init */
807 
808 
809 
810 /*------------------------------------------------------------------
811  *
812  * Name:        demod_get_sample
813  *
814  * Purpose:     Get one audio sample fromt the specified sound input source.
815  *
816  * Inputs:	a	- Index for audio device.  0 = first.
817  *
818  * Returns:     -32768 .. 32767 for a valid audio sample.
819  *              256*256 for end of file or other error.
820  *
821  * Global In:	save_audio_config_p->adev[ACHAN2ADEV(chan)].bits_per_sample - So we know whether to
822  *			read 1 or 2 bytes from audio stream.
823  *
824  * Description:	Grab 1 or two btyes depending on data source.
825  *
826  *		When processing stereo, the caller will call this
827  *		at twice the normal rate to obtain alternating left
828  *		and right samples.
829  *
830  *----------------------------------------------------------------*/
831 
832 #define FSK_READ_ERR (256*256)
833 
834 
835 __attribute__((hot))
demod_get_sample(int a)836 int demod_get_sample (int a)
837 {
838 	int x1, x2;
839 	signed short sam;	/* short to force sign extention. */
840 
841 
842 	assert (save_audio_config_p->adev[a].bits_per_sample == 8 || save_audio_config_p->adev[a].bits_per_sample == 16);
843 
844 
845 	if (save_audio_config_p->adev[a].bits_per_sample == 8) {
846 
847 	  x1 = audio_get(a);
848 	  if (x1 < 0) return(FSK_READ_ERR);
849 
850 	  assert (x1 >= 0 && x1 <= 255);
851 
852 	  /* Scale 0..255 into -32k..+32k */
853 
854 	  sam = (x1 - 128) * 256;
855 
856 	}
857 	else {
858 	  x1 = audio_get(a);	/* lower byte first */
859 	  if (x1 < 0) return(FSK_READ_ERR);
860 
861 	  x2 = audio_get(a);
862 	  if (x2 < 0) return(FSK_READ_ERR);
863 
864 	  assert (x1 >= 0 && x1 <= 255);
865 	  assert (x2 >= 0 && x2 <= 255);
866 
867           sam = ( x2 << 8 ) | x1;
868 	}
869 
870 	return (sam);
871 }
872 
873 
874 /*-------------------------------------------------------------------
875  *
876  * Name:        demod_process_sample
877  *
878  * Purpose:     (1) Demodulate the AFSK signal.
879  *		(2) Recover clock and data.
880  *
881  * Inputs:	chan	- Audio channel.  0 for left, 1 for right.
882  *		subchan - modem of the channel.
883  *		sam	- One sample of audio.
884  *			  Should be in range of -32768 .. 32767.
885  *
886  * Returns:	None
887  *
888  * Descripion:	We start off with two bandpass filters tuned to
889  *		the given frequencies.  In the case of VHF packet
890  *		radio, this would be 1200 and 2200 Hz.
891  *
892  *		The bandpass filter amplitudes are compared to
893  *		obtain the demodulated signal.
894  *
895  *		We also have a digital phase locked loop (PLL)
896  *		to recover the clock and pick out data bits at
897  *		the proper rate.
898  *
899  *		For each recovered data bit, we call:
900  *
901  *			  hdlc_rec (channel, demodulated_bit);
902  *
903  *		to decode HDLC frames from the stream of bits.
904  *
905  * Future:	This could be generalized by passing in the name
906  *		of the function to be called for each bit recovered
907  *		from the demodulator.  For now, it's simply hard-coded.
908  *
909  *--------------------------------------------------------------------*/
910 
911 
912 __attribute__((hot))
demod_process_sample(int chan,int subchan,int sam)913 void demod_process_sample (int chan, int subchan, int sam)
914 {
915 	float fsam;
916 	int k;
917 
918 
919 	struct demodulator_state_s *D;
920 
921 	assert (chan >= 0 && chan < MAX_CHANS);
922 	assert (subchan >= 0 && subchan < MAX_SUBCHANS);
923 
924 	D = &demodulator_state[chan][subchan];
925 
926 
927 	/* Scale to nice number, actually -2.0 to +2.0 for extra headroom */
928 
929 	fsam = sam / 16384.0f;
930 
931 /*
932  * Accumulate measure of the input signal level.
933  */
934 
935 
936 /*
937  * Version 1.2: Try new approach to capturing the amplitude.
938  * This is same as the later AGC without the normalization step.
939  * We want decay to be substantially slower to get a longer
940  * range idea of the received audio.
941  */
942 
943 	if (fsam >= D->alevel_rec_peak) {
944 	  D->alevel_rec_peak = fsam * D->quick_attack + D->alevel_rec_peak * (1.0f - D->quick_attack);
945 	}
946 	else {
947 	  D->alevel_rec_peak = fsam * D->sluggish_decay + D->alevel_rec_peak * (1.0f - D->sluggish_decay);
948 	}
949 
950 	if (fsam <= D->alevel_rec_valley) {
951 	  D->alevel_rec_valley = fsam * D->quick_attack + D->alevel_rec_valley * (1.0f - D->quick_attack);
952 	}
953 	else  {
954 	  D->alevel_rec_valley = fsam * D->sluggish_decay + D->alevel_rec_valley * (1.0f - D->sluggish_decay);
955 	}
956 
957 
958 /*
959  * Select decoder based on modulation type.
960  */
961 
962 	switch (save_audio_config_p->achan[chan].modem_type) {
963 
964 	  case MODEM_OFF:
965 
966 	    // Might have channel only listening to DTMF for APRStt gateway.
967 	    // Don't waste CPU time running a demodulator here.
968 	    break;
969 
970 	  case MODEM_AFSK:
971 	  case MODEM_EAS:
972 
973 	    if (save_audio_config_p->achan[chan].decimate > 1) {
974 
975 	      sample_sum[chan][subchan] += sam;
976 	      sample_count[chan][subchan]++;
977 	      if (sample_count[chan][subchan] >= save_audio_config_p->achan[chan].decimate) {
978   	        demod_afsk_process_sample (chan, subchan, sample_sum[chan][subchan] / save_audio_config_p->achan[chan].decimate, D);
979 	        sample_sum[chan][subchan] = 0;
980 	        sample_count[chan][subchan] = 0;
981 	      }
982 	    }
983 	    else {
984 	      demod_afsk_process_sample (chan, subchan, sam, D);
985 	    }
986 	    break;
987 
988 	  case MODEM_QPSK:
989 	  case MODEM_8PSK:
990 
991 	    if (save_audio_config_p->achan[chan].decimate > 1) {
992 
993 	      text_color_set(DW_COLOR_ERROR);
994 	      dw_printf ("Invalid combination of options.  Exiting.\n");
995 	      // Would probably work but haven't thought about it or tested yet.
996 	      exit (1);
997 	    }
998 	    else {
999 	      demod_psk_process_sample (chan, subchan, sam, D);
1000 	    }
1001 	    break;
1002 
1003 	  case MODEM_BASEBAND:
1004 	  case MODEM_SCRAMBLE:
1005 	  case MODEM_AIS:
1006 	  default:
1007 
1008 	    if (zerostuff) {
1009 	      /* Literature says this is better if followed */
1010 	      /* by appropriate low pass filter. */
1011 	      /* So far, both are same in tests with different */
1012 	      /* optimal low pass filter parameters. */
1013 
1014 	      for (k=1; k<save_audio_config_p->achan[chan].upsample; k++) {
1015 	        demod_9600_process_sample (chan, 0, D);
1016 	      }
1017 	      demod_9600_process_sample (chan, sam * save_audio_config_p->achan[chan].upsample, D);
1018 	    }
1019 	    else {
1020 
1021 	      /* Linear interpolation. */
1022 	      static int prev_sam;
1023 
1024 	      switch (save_audio_config_p->achan[chan].upsample) {
1025 	        case 1:
1026 	          demod_9600_process_sample (chan, sam, D);
1027 	          break;
1028 	        case 2:
1029 	          demod_9600_process_sample (chan, (prev_sam + sam) / 2, D);
1030 	          demod_9600_process_sample (chan, sam, D);
1031 	          break;
1032                 case 3:
1033                   demod_9600_process_sample (chan, (2 * prev_sam + sam) / 3, D);
1034                   demod_9600_process_sample (chan, (prev_sam + 2 * sam) / 3, D);
1035                   demod_9600_process_sample (chan, sam, D);
1036                   break;
1037                 case 4:
1038                   demod_9600_process_sample (chan, (3 * prev_sam + sam) / 4, D);
1039                   demod_9600_process_sample (chan, (prev_sam + sam) / 2, D);
1040                   demod_9600_process_sample (chan, (prev_sam + 3 * sam) / 4, D);
1041                   demod_9600_process_sample (chan, sam, D);
1042                   break;
1043                 default:
1044                   assert (0);
1045                   break;
1046 	      }
1047 	      prev_sam = sam;
1048 	    }
1049 	    break;
1050 
1051 	}  /* switch modem_type */
1052 	return;
1053 
1054 } /* end demod_process_sample */
1055 
1056 
1057 
1058 
1059 
1060 
1061 /* Doesn't seem right.  Need to revisit this. */
1062 /* Resulting scale is 0 to almost 100. */
1063 /* Cranking up the input level produces no more than 97 or 98. */
1064 /* We currently produce a message when this goes over 90. */
1065 
demod_get_audio_level(int chan,int subchan)1066 alevel_t demod_get_audio_level (int chan, int subchan)
1067 {
1068 	struct demodulator_state_s *D;
1069 	alevel_t alevel;
1070 
1071 	assert (chan >= 0 && chan < MAX_CHANS);
1072 	assert (subchan >= 0 && subchan < MAX_SUBCHANS);
1073 
1074 	/* We have to consider two different cases here. */
1075 	/* N demodulators, each with own slicer and HDLC decoder. */
1076 	/* Single demodulator, multiple slicers each with own HDLC decoder. */
1077 
1078 	if (demodulator_state[chan][0].num_slicers > 1) {
1079 	  subchan = 0;
1080 	}
1081 
1082 	D = &demodulator_state[chan][subchan];
1083 
1084 	// Take half of peak-to-peak for received audio level.
1085 
1086 	alevel.rec = (int) (( D->alevel_rec_peak - D->alevel_rec_valley ) * 50.0f + 0.5f);
1087 
1088 	if (save_audio_config_p->achan[chan].modem_type == MODEM_AFSK ||
1089 	    save_audio_config_p->achan[chan].modem_type == MODEM_EAS) {
1090 
1091 	  /* For AFSK, we have mark and space amplitudes. */
1092 
1093 	  alevel.mark = (int) ((D->alevel_mark_peak ) * 100.0f + 0.5f);
1094 	  alevel.space = (int) ((D->alevel_space_peak ) * 100.0f + 0.5f);
1095 	}
1096 	else if (save_audio_config_p->achan[chan].modem_type == MODEM_QPSK ||
1097 	         save_audio_config_p->achan[chan].modem_type == MODEM_8PSK) {
1098 	  alevel.mark = -1;
1099 	  alevel.space = -1;
1100 	}
1101 	else {
1102 
1103 #if 1
1104 	  /* Display the + and - peaks.  */
1105 	  /* Normally we'd expect them to be about the same. */
1106 	  /* However, with SDR, or other DC coupling, we could have an offset. */
1107 
1108 	  alevel.mark = (int) ((D->alevel_mark_peak) * 200.0f  + 0.5f);
1109 	  alevel.space = (int) ((D->alevel_space_peak) * 200.0f - 0.5f);
1110 
1111 
1112 #else
1113 	  /* Here we have + and - peaks after filtering. */
1114 	  /* Take half of the peak to peak. */
1115 	  /* The "5/6" factor worked out right for the current low pass filter. */
1116 	  /* Will it need to be different if the filter is tweaked? */
1117 
1118 	  alevel.mark = (int) ((D->alevel_mark_peak - D->alevel_space_peak) * 100.0f * 5.0f/6.0f + 0.5f);
1119 	  alevel.space = -1;		/* to print one number inside of ( ) */
1120 #endif
1121 	}
1122 	return (alevel);
1123 }
1124 
1125 
1126 /* end demod.c */
1127