1 /*
2  * SpanDSP - a series of DSP components for telephony
3  *
4  * v17rx.c - ITU V.17 modem receive part
5  *
6  * Written by Steve Underwood <steveu@coppice.org>
7  *
8  * Copyright (C) 2004, 2005, 2006, 2007 Steve Underwood
9  *
10  * All rights reserved.
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU Lesser General Public License version 2.1,
14  * as published by the Free Software Foundation.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this program; if not, write to the Free Software
23  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  *
25  * $Id: v17rx.c,v 1.112 2008/07/17 19:12:27 steveu Exp $
26  */
27 
28 /*! \file */
29 
30 #if defined(HAVE_CONFIG_H)
31 #include <config.h>
32 #endif
33 
34 #include <stdlib.h>
35 #include <inttypes.h>
36 #include <string.h>
37 #include <stdio.h>
38 #include "floating_fudge.h"
39 #if defined(HAVE_TGMATH_H)
40 #include <tgmath.h>
41 #endif
42 #if defined(HAVE_MATH_H)
43 #include <math.h>
44 #endif
45 
46 #include "spandsp/telephony.h"
47 #include "spandsp/logging.h"
48 #include "spandsp/complex.h"
49 #include "spandsp/vector_float.h"
50 #include "spandsp/complex_vector_float.h"
51 #include "spandsp/async.h"
52 #include "spandsp/power_meter.h"
53 #include "spandsp/arctan2.h"
54 #include "spandsp/dds.h"
55 #include "spandsp/complex_filters.h"
56 
57 #include "spandsp/v29rx.h"
58 #include "spandsp/v17tx.h"
59 #include "spandsp/v17rx.h"
60 
61 #include "v17tx_constellation_maps.h"
62 #include "v17rx_constellation_maps.h"
63 #if defined(SPANDSP_USE_FIXED_POINT)
64 #include "v17rx_fixed_rrc.h"
65 #else
66 #include "v17rx_floating_rrc.h"
67 #endif
68 
69 #define CARRIER_NOMINAL_FREQ            1800.0f
70 #define BAUD_RATE                       2400
71 #define EQUALIZER_DELTA                 0.21f
72 #define EQUALIZER_SLOW_ADAPT_RATIO      0.1f
73 
74 /* Segments of the training sequence */
75 #define V17_TRAINING_SEG_1_LEN          256
76 #define V17_TRAINING_SEG_2_LEN          2976
77 #define V17_TRAINING_SHORT_SEG_2_LEN    38
78 #define V17_TRAINING_SEG_3_LEN          64
79 #define V17_TRAINING_SEG_4A_LEN         15
80 #define V17_TRAINING_SEG_4_LEN          48
81 
82 #define V17_BRIDGE_WORD                 0x8880
83 
84 enum
85 {
86     TRAINING_STAGE_NORMAL_OPERATION = 0,
87     TRAINING_STAGE_SYMBOL_ACQUISITION,
88     TRAINING_STAGE_LOG_PHASE,
89     TRAINING_STAGE_SHORT_WAIT_FOR_CDBA,
90     TRAINING_STAGE_WAIT_FOR_CDBA,
91     TRAINING_STAGE_COARSE_TRAIN_ON_CDBA,
92     TRAINING_STAGE_FINE_TRAIN_ON_CDBA,
93     TRAINING_STAGE_SHORT_TRAIN_ON_CDBA_AND_TEST,
94     TRAINING_STAGE_TRAIN_ON_CDBA_AND_TEST,
95     TRAINING_STAGE_BRIDGE,
96     TRAINING_STAGE_TCM_WINDUP,
97     TRAINING_STAGE_TEST_ONES,
98     TRAINING_STAGE_PARKED
99 };
100 
101 /* Coefficients for the band edge symbol timing synchroniser (alpha = 0.99) */
102 #define SYNC_LOW_BAND_EDGE_COEFF_0       1.764193f    /* 2*alpha*cos(low_edge) */
103 #define SYNC_LOW_BAND_EDGE_COEFF_1      -0.980100f    /* -alpha^2 */
104 #define SYNC_HIGH_BAND_EDGE_COEFF_0     -1.400072f    /* 2*alpha*cos(high_edge) */
105 #define SYNC_HIGH_BAND_EDGE_COEFF_1     -0.980100f    /* -alpha^2 */
106 #define SYNC_CROSS_CORR_COEFF_A         -0.932131f    /* -alpha^2*sin(freq_diff) */
107 #define SYNC_CROSS_CORR_COEFF_B          0.700036f    /* alpha*sin(high_edge) */
108 #define SYNC_CROSS_CORR_COEFF_C         -0.449451f    /* -alpha*sin(low_edge) */
109 
v17_rx_carrier_frequency(v17_rx_state_t * s)110 float v17_rx_carrier_frequency(v17_rx_state_t *s)
111 {
112     return dds_frequencyf(s->carrier_phase_rate);
113 }
114 /*- End of function --------------------------------------------------------*/
115 
v17_rx_symbol_timing_correction(v17_rx_state_t * s)116 float v17_rx_symbol_timing_correction(v17_rx_state_t *s)
117 {
118     return (float) s->total_baud_timing_correction/((float) RX_PULSESHAPER_COEFF_SETS*10.0f/3.0f);
119 }
120 /*- End of function --------------------------------------------------------*/
121 
v17_rx_signal_power(v17_rx_state_t * s)122 float v17_rx_signal_power(v17_rx_state_t *s)
123 {
124     return power_meter_current_dbm0(&s->power);
125 }
126 /*- End of function --------------------------------------------------------*/
127 
v17_rx_signal_cutoff(v17_rx_state_t * s,float cutoff)128 void v17_rx_signal_cutoff(v17_rx_state_t *s, float cutoff)
129 {
130     /* The 0.4 factor allows for the gain of the DC blocker */
131     s->carrier_on_power = (int32_t) (power_meter_level_dbm0(cutoff + 2.5f)*0.4f);
132     s->carrier_off_power = (int32_t) (power_meter_level_dbm0(cutoff - 2.5f)*0.4f);
133 }
134 /*- End of function --------------------------------------------------------*/
135 
v17_rx_equalizer_state(v17_rx_state_t * s,complexf_t ** coeffs)136 int v17_rx_equalizer_state(v17_rx_state_t *s, complexf_t **coeffs)
137 {
138     *coeffs = s->eq_coeff;
139     return V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN;
140 }
141 /*- End of function --------------------------------------------------------*/
142 
report_status_change(v17_rx_state_t * s,int status)143 static void report_status_change(v17_rx_state_t *s, int status)
144 {
145     if (s->status_handler)
146         s->status_handler(s->status_user_data, status);
147     else if (s->put_bit)
148         s->put_bit(s->put_bit_user_data, status);
149 }
150 /*- End of function --------------------------------------------------------*/
151 
equalizer_save(v17_rx_state_t * s)152 static void equalizer_save(v17_rx_state_t *s)
153 {
154     cvec_copyf(s->eq_coeff_save, s->eq_coeff, V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN);
155 }
156 /*- End of function --------------------------------------------------------*/
157 
equalizer_restore(v17_rx_state_t * s)158 static void equalizer_restore(v17_rx_state_t *s)
159 {
160     cvec_copyf(s->eq_coeff, s->eq_coeff_save, V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN);
161     cvec_zerof(s->eq_buf, V17_EQUALIZER_MASK);
162 
163     s->eq_put_step = RX_PULSESHAPER_COEFF_SETS*10/(3*2) - 1;
164     s->eq_step = 0;
165     s->eq_delta = EQUALIZER_SLOW_ADAPT_RATIO*EQUALIZER_DELTA/(V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN);
166 }
167 /*- End of function --------------------------------------------------------*/
168 
equalizer_reset(v17_rx_state_t * s)169 static void equalizer_reset(v17_rx_state_t *s)
170 {
171     /* Start with an equalizer based on everything being perfect */
172     cvec_zerof(s->eq_coeff, V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN);
173     s->eq_coeff[V17_EQUALIZER_PRE_LEN] = complex_setf(3.0f, 0.0f);
174     cvec_zerof(s->eq_buf, V17_EQUALIZER_MASK);
175 
176     s->eq_put_step = RX_PULSESHAPER_COEFF_SETS*10/(3*2) - 1;
177     s->eq_step = 0;
178     s->eq_delta = EQUALIZER_DELTA/(V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN);
179 }
180 /*- End of function --------------------------------------------------------*/
181 
equalizer_get(v17_rx_state_t * s)182 static __inline__ complexf_t equalizer_get(v17_rx_state_t *s)
183 {
184     int i;
185     int p;
186     complexf_t z;
187     complexf_t z1;
188 
189     /* Get the next equalized value. */
190     z = complex_setf(0.0f, 0.0f);
191     p = s->eq_step - 1;
192     for (i = 0;  i < V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN;  i++)
193     {
194         p = (p - 1) & V17_EQUALIZER_MASK;
195         z1 = complex_mulf(&s->eq_coeff[i], &s->eq_buf[p]);
196         z = complex_addf(&z, &z1);
197     }
198     return z;
199 }
200 /*- End of function --------------------------------------------------------*/
201 
tune_equalizer(v17_rx_state_t * s,const complexf_t * z,const complexf_t * target)202 static void tune_equalizer(v17_rx_state_t *s, const complexf_t *z, const complexf_t *target)
203 {
204     int i;
205     int p;
206     complexf_t ez;
207     complexf_t z1;
208 
209     /* Find the x and y mismatch from the exact constellation position. */
210     ez = complex_subf(target, z);
211     //span_log(&s->logging, SPAN_LOG_FLOW, "Equalizer error %f\n", sqrt(ez.re*ez.re + ez.im*ez.im));
212     ez.re *= s->eq_delta;
213     ez.im *= s->eq_delta;
214 
215     p = s->eq_step - 1;
216     for (i = 0;  i < V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN;  i++)
217     {
218         p = (p - 1) & V17_EQUALIZER_MASK;
219         z1 = complex_conjf(&s->eq_buf[p]);
220         z1 = complex_mulf(&ez, &z1);
221         s->eq_coeff[i] = complex_addf(&s->eq_coeff[i], &z1);
222         /* Leak a little to tame uncontrolled wandering */
223         s->eq_coeff[i].re *= 0.9999f;
224         s->eq_coeff[i].im *= 0.9999f;
225     }
226 }
227 /*- End of function --------------------------------------------------------*/
228 
descramble(v17_rx_state_t * s,int in_bit)229 static int descramble(v17_rx_state_t *s, int in_bit)
230 {
231     int out_bit;
232 
233     out_bit = (in_bit ^ (s->scramble_reg >> 17) ^ (s->scramble_reg >> 22)) & 1;
234     s->scramble_reg <<= 1;
235     if (s->training_stage > TRAINING_STAGE_NORMAL_OPERATION  &&  s->training_stage < TRAINING_STAGE_TCM_WINDUP)
236         s->scramble_reg |= out_bit;
237     else
238         s->scramble_reg |= (in_bit & 1);
239     return out_bit;
240 }
241 /*- End of function --------------------------------------------------------*/
242 
find_quadrant(complexf_t * z)243 static __inline__ int find_quadrant(complexf_t *z)
244 {
245     int b1;
246     int b2;
247 
248     /* Split the space along the two diagonals. */
249     b1 = (z->im > z->re);
250     b2 = (z->im < -z->re);
251     return (b2 << 1) | (b1 ^ b2);
252 }
253 /*- End of function --------------------------------------------------------*/
254 
track_carrier(v17_rx_state_t * s,const complexf_t * z,const complexf_t * target)255 static void track_carrier(v17_rx_state_t *s, const complexf_t *z, const complexf_t *target)
256 {
257     float error;
258 
259     /* For small errors the imaginary part of the difference between the actual and the target
260        positions is proportional to the phase error, for any particular target. However, the
261        different amplitudes of the various target positions scale things. */
262     error = z->im*target->re - z->re*target->im;
263 
264     s->carrier_phase_rate += (int32_t) (s->carrier_track_i*error);
265     s->carrier_phase += (int32_t) (s->carrier_track_p*error);
266     //span_log(&s->logging, SPAN_LOG_FLOW, "Im = %15.5f   f = %15.5f\n", error, dds_frequencyf(s->carrier_phase_rate));
267     //printf("XXX Im = %15.5f   f = %15.5f   %f %f %f %f (%f %f)\n", error, dds_frequencyf(s->carrier_phase_rate), target->re, target->im, z->re, z->im, s->carrier_track_i, s->carrier_track_p);
268 }
269 /*- End of function --------------------------------------------------------*/
270 
put_bit(v17_rx_state_t * s,int bit)271 static __inline__ void put_bit(v17_rx_state_t *s, int bit)
272 {
273     int out_bit;
274 
275     /* We need to strip the last part of the training - the test period of all 1s -
276        before we let data go to the application. */
277     if (s->training_stage == TRAINING_STAGE_NORMAL_OPERATION)
278     {
279         out_bit = descramble(s, bit);
280         s->put_bit(s->put_bit_user_data, out_bit);
281     }
282     else if (s->training_stage == TRAINING_STAGE_TEST_ONES)
283     {
284         /* The bits during the final stage of training should be all ones. However,
285            buggy modems mean you cannot rely on this. Therefore we don't bother
286            testing for ones, but just rely on a constellation mismatch measurement. */
287         out_bit = descramble(s, bit);
288         //span_log(&s->logging, SPAN_LOG_FLOW, "A 1 is really %d\n", out_bit);
289     }
290 }
291 /*- End of function --------------------------------------------------------*/
292 
293 #if defined(SPANDSP_USE_FIXED_POINTx)
dist_sq(const complexi_t * x,const complexi_t * y)294 static __inline__ uint32_t dist_sq(const complexi_t *x, const complexi_t *y)
295 {
296     return (x->re - y->re)*(x->re - y->re) + (x->im - y->im)*(x->im - y->im);
297 }
298 /*- End of function --------------------------------------------------------*/
299 #else
dist_sq(const complexf_t * x,const complexf_t * y)300 static __inline__ float dist_sq(const complexf_t *x, const complexf_t *y)
301 {
302     return (x->re - y->re)*(x->re - y->re) + (x->im - y->im)*(x->im - y->im);
303 }
304 /*- End of function --------------------------------------------------------*/
305 #endif
306 
decode_baud(v17_rx_state_t * s,complexf_t * z)307 static int decode_baud(v17_rx_state_t *s, complexf_t *z)
308 {
309     static const int diff_code[16] =
310     {
311         0, 3, 2, 1, 1, 0, 3, 2, 2, 1, 0, 3, 3, 2, 1, 0
312     };
313     static const int tcm_paths[8][4] =
314     {
315         {0, 6, 2, 4},
316         {6, 0, 4, 2},
317         {2, 4, 0, 6},
318         {4, 2, 6, 0},
319         {1, 3, 7, 5},
320         {5, 7, 3, 1},
321         {7, 5, 1, 3},
322         {3, 1, 5, 7}
323     };
324     int nearest;
325     int i;
326     int j;
327     int k;
328     int re;
329     int im;
330     int raw;
331     int constellation_state;
332 #if defined(SPANDSP_USE_FIXED_POINTx)
333 #define DIST_FACTOR 2048       /* Something less than sqrt(0xFFFFFFFF/10)/10 */
334     complexi_t zi;
335     uint32_t distances[8];
336     uint32_t new_distances[8];
337     uint32_t min;
338     complexi_t ci;
339 #else
340     float distances[8];
341     float new_distances[8];
342     float min;
343 #endif
344 
345     re = (int) ((z->re + 9.0f)*2.0f);
346     if (re > 35)
347         re = 35;
348     else if (re < 0)
349         re = 0;
350     im = (int) ((z->im + 9.0f)*2.0f);
351     if (im > 35)
352         im = 35;
353     else if (im < 0)
354         im = 0;
355 
356     /* Find a set of 8 candidate constellation positions, that are the closest
357        to the target, with different patterns in the last 3 bits. */
358 #if defined(SPANDSP_USE_FIXED_POINTx)
359     min = 0xFFFFFFFF;
360     zi = complex_seti(z->re*DIST_FACTOR, z->im*DIST_FACTOR);
361 #else
362     min = 9999999.0f;
363 #endif
364     j = 0;
365     for (i = 0;  i < 8;  i++)
366     {
367         nearest = constel_maps[s->space_map][re][im][i];
368 #if defined(SPANDSP_USE_FIXED_POINTx)
369         ci = complex_seti(s->constellation[nearest].re*DIST_FACTOR,
370                           s->constellation[nearest].im*DIST_FACTOR);
371         distances[i] = dist_sq(&ci, &zi);
372 #else
373         distances[i] = dist_sq(&s->constellation[nearest], z);
374 #endif
375         if (min > distances[i])
376         {
377             min = distances[i];
378             j = i;
379         }
380     }
381     /* Use the nearest of these soft-decisions as the basis for DFE */
382     constellation_state = constel_maps[s->space_map][re][im][j];
383     /* Control the equalizer, carrier tracking, etc. based on the non-trellis
384        corrected information. The trellis correct stuff comes out a bit late. */
385     track_carrier(s, z, &s->constellation[constellation_state]);
386     //tune_equalizer(s, z, &s->constellation[constellation_state]);
387 
388     /* Now do the trellis decoding */
389 
390     /* TODO: change to processing blocks of stored symbols here, instead of processing
391              one symbol at a time, to speed up the processing. */
392 
393     /* Update the minimum accumulated distance to each of the 8 states */
394     if (++s->trellis_ptr >= V17_TRELLIS_STORAGE_DEPTH)
395         s->trellis_ptr = 0;
396     for (i = 0;  i < 4;  i++)
397     {
398         min = distances[tcm_paths[i][0]] + s->distances[0];
399         k = 0;
400         for (j = 1;  j < 4;  j++)
401         {
402             if (min > distances[tcm_paths[i][j]] + s->distances[j << 1])
403             {
404                 min = distances[tcm_paths[i][j]] + s->distances[j << 1];
405                 k = j;
406             }
407         }
408         /* Use an elementary IIR filter to track the distance to date. */
409 #if defined(SPANDSP_USE_FIXED_POINTx)
410         new_distances[i] = s->distances[k << 1]*9/10 + distances[tcm_paths[i][k]]*1/10;
411 #else
412         new_distances[i] = s->distances[k << 1]*0.9f + distances[tcm_paths[i][k]]*0.1f;
413 #endif
414         s->full_path_to_past_state_locations[s->trellis_ptr][i] = constel_maps[s->space_map][re][im][tcm_paths[i][k]];
415         s->past_state_locations[s->trellis_ptr][i] = k << 1;
416     }
417     for (i = 4;  i < 8;  i++)
418     {
419         min = distances[tcm_paths[i][0]] + s->distances[1];
420         k = 0;
421         for (j = 1;  j < 4;  j++)
422         {
423             if (min > distances[tcm_paths[i][j]] + s->distances[(j << 1) + 1])
424             {
425                 min = distances[tcm_paths[i][j]] + s->distances[(j << 1) + 1];
426                 k = j;
427             }
428         }
429 #if defined(SPANDSP_USE_FIXED_POINTx)
430         new_distances[i] = s->distances[(k << 1) + 1]*9/10 + distances[tcm_paths[i][k]]*1/10;
431 #else
432         new_distances[i] = s->distances[(k << 1) + 1]*0.9f + distances[tcm_paths[i][k]]*0.1f;
433 #endif
434         s->full_path_to_past_state_locations[s->trellis_ptr][i] = constel_maps[s->space_map][re][im][tcm_paths[i][k]];
435         s->past_state_locations[s->trellis_ptr][i] = (k << 1) + 1;
436     }
437     memcpy(s->distances, new_distances, sizeof(s->distances));
438 
439     /* Find the minimum distance to date. This is the start of the path back to the result. */
440     min = s->distances[0];
441     k = 0;
442     for (i = 1;  i < 8;  i++)
443     {
444         if (min > s->distances[i])
445         {
446             min = s->distances[i];
447             k = i;
448         }
449     }
450     /* Trace back through every time step, starting with the current one, and find the
451        state from which the path came one step before. At the end of this search, the
452        last state found also points to the constellation point at that state. This is the
453        output of the trellis. */
454     for (i = 0, j = s->trellis_ptr;  i < V17_TRELLIS_LOOKBACK_DEPTH - 1;  i++)
455     {
456         k = s->past_state_locations[j][k];
457         if (--j < 0)
458             j = V17_TRELLIS_STORAGE_DEPTH - 1;
459     }
460     nearest = s->full_path_to_past_state_locations[j][k] >> 1;
461 
462     /* Differentially decode */
463     raw = (nearest & 0x3C) | diff_code[((nearest & 0x03) << 2) | s->diff];
464     s->diff = nearest & 0x03;
465     for (i = 0;  i < s->bits_per_symbol;  i++)
466     {
467         put_bit(s, raw);
468         raw >>= 1;
469     }
470     return constellation_state;
471 }
472 /*- End of function --------------------------------------------------------*/
473 
process_half_baud(v17_rx_state_t * s,const complexf_t * sample)474 static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
475 {
476     static const complexf_t cdba[4] =
477     {
478         { 6.0f,  2.0f},
479         {-2.0f,  6.0f},
480         { 2.0f, -6.0f},
481         {-6.0f, -2.0f}
482     };
483     complexf_t z;
484     complexf_t zz;
485 #if defined(SPANDSP_USE_FIXED_POINTx)
486     const complexi_t *target;
487 #else
488     const complexf_t *target;
489 #endif
490     float v;
491     float p;
492     int bit;
493     int i;
494     int j;
495     int32_t angle;
496     int32_t ang;
497     int constellation_state;
498 
499     /* This routine processes every half a baud, as we put things into the equalizer at the T/2 rate.
500        This routine adapts the position of the half baud samples, which the caller takes. */
501 
502     /* Add a sample to the equalizer's circular buffer, but don't calculate anything
503        at this time. */
504     s->eq_buf[s->eq_step] = *sample;
505     s->eq_step = (s->eq_step + 1) & V17_EQUALIZER_MASK;
506 
507     /* On alternate insertions we have a whole baud and must process it. */
508     if ((s->baud_half ^= 1))
509         return;
510 
511     /* Symbol timing synchronisation */
512     /* Cross correlate */
513     v = s->symbol_sync_low[1]*s->symbol_sync_high[1]*SYNC_CROSS_CORR_COEFF_A
514       + s->symbol_sync_low[0]*s->symbol_sync_high[1]*SYNC_CROSS_CORR_COEFF_B
515       + s->symbol_sync_low[1]*s->symbol_sync_high[0]*SYNC_CROSS_CORR_COEFF_C;
516 
517     /* Filter away any DC component  */
518     p = v - s->symbol_sync_dc_filter[1];
519     s->symbol_sync_dc_filter[1] = s->symbol_sync_dc_filter[0];
520     s->symbol_sync_dc_filter[0] = v;
521     /* A little integration will now filter away much of the HF noise */
522     s->baud_phase -= p;
523 
524     if (fabsf(s->baud_phase) > 100.0f)
525     {
526         if (s->baud_phase > 0.0f)
527             i = (s->baud_phase > 1000.0f)  ?  15  :  1;
528         else
529             i = (s->baud_phase < -1000.0f)  ?  -15  :  -1;
530         //printf("v = %10.5f %5d - %f %f %d\n", v, i, p, s->baud_phase, s->total_baud_timing_correction);
531 
532         s->eq_put_step += i;
533         s->total_baud_timing_correction += i;
534     }
535 
536     z = equalizer_get(s);
537 
538     constellation_state = 0;
539     switch (s->training_stage)
540     {
541     case TRAINING_STAGE_NORMAL_OPERATION:
542         /* Normal operation. */
543         constellation_state = decode_baud(s, &z);
544         target = &s->constellation[constellation_state];
545         break;
546     case TRAINING_STAGE_SYMBOL_ACQUISITION:
547         /* Allow time for the symbol synchronisation to settle the symbol timing. */
548         target = &z;
549 #if defined(IAXMODEM_STUFF)
550         if (++s->training_count >= 100)
551 #else
552         if (++s->training_count >= 50)
553 #endif
554         {
555             /* Record the current phase angle */
556             s->angles[0] =
557             s->start_angles[0] = arctan2(z.im, z.re);
558             s->training_stage = TRAINING_STAGE_LOG_PHASE;
559             if (s->agc_scaling_save == 0.0f)
560                 s->agc_scaling_save = s->agc_scaling;
561         }
562         break;
563     case TRAINING_STAGE_LOG_PHASE:
564         /* Record the current alternate phase angle */
565         target = &z;
566         angle = arctan2(z.im, z.re);
567         s->training_count = 1;
568         if (s->short_train)
569         {
570             /* We should already know the accurate carrier frequency. All we need to sort
571                out is the phase. */
572             /* Check if we just saw A or B */
573             if ((uint32_t) (angle - s->start_angles[0]) < 0x80000000U)
574             {
575                 angle = s->start_angles[0];
576                 s->angles[0] = 0xC0000000 + 219937506;
577                 s->angles[1] = 0x80000000 + 219937506;
578             }
579             else
580             {
581                 s->angles[0] = 0x80000000 + 219937506;
582                 s->angles[1] = 0xC0000000 + 219937506;
583             }
584             /* Make a step shift in the phase, to pull it into line. We need to rotate the equalizer
585                buffer, as well as the carrier phase, for this to play out nicely. */
586             /* angle is now the difference between where A is, and where it should be */
587             p = 3.14159f + angle*2.0f*3.14159f/(65536.0f*65536.0f) - 0.321751f;
588             span_log(&s->logging, SPAN_LOG_FLOW, "Spin (short) by %.5f rads\n", p);
589             zz = complex_setf(cosf(p), -sinf(p));
590             for (i = 0;  i <= V17_EQUALIZER_MASK;  i++)
591                 s->eq_buf[i] = complex_mulf(&s->eq_buf[i], &zz);
592             s->carrier_phase += (0x80000000 + angle - 219937506);
593 
594             s->carrier_track_p = 500000.0f;
595 
596             s->training_stage = TRAINING_STAGE_SHORT_WAIT_FOR_CDBA;
597         }
598         else
599         {
600             s->angles[1] =
601             s->start_angles[1] = angle;
602             s->training_stage = TRAINING_STAGE_WAIT_FOR_CDBA;
603         }
604         break;
605     case TRAINING_STAGE_WAIT_FOR_CDBA:
606         target = &z;
607         angle = arctan2(z.im, z.re);
608         /* Look for the initial ABAB sequence to display a phase reversal, which will
609            signal the start of the scrambled CDBA segment */
610         ang = angle - s->angles[(s->training_count - 1) & 0xF];
611         s->angles[(s->training_count + 1) & 0xF] = angle;
612 
613         /* Do a coarse frequency adjustment about half way through the reversals, as if we wait until
614            the end, we might have rotated too far to correct properly. */
615         if (s->training_count == 100)
616         {
617             i = s->training_count;
618             /* Avoid the possibility of a divide by zero */
619             if (i)
620             {
621                 j = i & 0xF;
622                 ang = (s->angles[j] - s->start_angles[0])/i
623                     + (s->angles[j | 0x1] - s->start_angles[1])/i;
624                 s->carrier_phase_rate += 3*(ang/20);
625                 //span_log(&s->logging, SPAN_LOG_FLOW, "Angles %x, %x, %x, %x, dist %d\n", s->angles[j], s->start_angles[0], s->angles[j | 0x1], s->start_angles[1], i);
626 
627                 s->start_angles[0] = s->angles[j];
628                 s->start_angles[1] = s->angles[j | 0x1];
629             }
630             //span_log(&s->logging, SPAN_LOG_FLOW, "%d %d %d %d %d\n", s->angles[s->training_count & 0xF], s->start_angles[0], s->angles[(s->training_count | 0x1) & 0xF], s->start_angles[1], s->training_count);
631             span_log(&s->logging, SPAN_LOG_FLOW, "First coarse carrier frequency %7.2f (%d)\n", dds_frequencyf(s->carrier_phase_rate), s->training_count);
632 
633         }
634         if ((ang > 0x40000000  ||  ang < -0x40000000)  &&  s->training_count >= 13)
635         {
636             span_log(&s->logging, SPAN_LOG_FLOW, "We seem to have a reversal at symbol %d\n", s->training_count);
637             /* We seem to have a phase reversal */
638             /* Slam the carrier frequency into line, based on the total phase drift over the last
639                section. Use the shift from the odd bits and the shift from the even bits to get
640                better jitter suppression. */
641             /* TODO: We are supposed to deal with frequancy errors up to +-8Hz. Over 200+
642                      symbols that is more than half a cycle. We get confused an do crazy things.
643                      We can only cope with errors up to 5Hz right now. We need to implement
644                      greater tolerance to be compliant, although it doesn't really matter much
645                      these days. */
646             /* Step back a few symbols so we don't get ISI distorting things. */
647             i = (s->training_count - 8) & ~1;
648             /* Avoid the possibility of a divide by zero */
649             if (i - 100 + 8)
650             {
651                 j = i & 0xF;
652                 ang = (s->angles[j] - s->start_angles[0])/(i - 100 + 8)
653                     + (s->angles[j | 0x1] - s->start_angles[1])/(i - 100 + 8);
654                 s->carrier_phase_rate += 3*(ang/20);
655                 span_log(&s->logging, SPAN_LOG_FLOW, "Angles %x, %x, %x, %x, dist %d\n", s->angles[j], s->start_angles[0], s->angles[j | 0x1], s->start_angles[1], i);
656             }
657             //span_log(&s->logging, SPAN_LOG_FLOW, "%d %d %d %d %d\n", s->angles[s->training_count & 0xF], s->start_angles[0], s->angles[(s->training_count | 0x1) & 0xF], s->start_angles[1], s->training_count);
658             span_log(&s->logging, SPAN_LOG_FLOW, "Second coarse carrier frequency %7.2f (%d)\n", dds_frequencyf(s->carrier_phase_rate), s->training_count);
659             /* Check if the carrier frequency is plausible */
660             if (s->carrier_phase_rate < dds_phase_ratef(CARRIER_NOMINAL_FREQ - 20.0f)
661                 ||
662                 s->carrier_phase_rate > dds_phase_ratef(CARRIER_NOMINAL_FREQ + 20.0f))
663             {
664                 span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n");
665                 /* Park this modem */
666                 s->agc_scaling_save = 0.0f;
667                 s->training_stage = TRAINING_STAGE_PARKED;
668                 report_status_change(s, PUTBIT_TRAINING_FAILED);
669                 break;
670             }
671 
672             /* Make a step shift in the phase, to pull it into line. We need to rotate the equalizer buffer,
673                as well as the carrier phase, for this to play out nicely. */
674             /* angle is now the difference between where C is, and where it should be */
675             p = angle*2.0f*3.14159f/(65536.0f*65536.0f) - 0.321751f;
676             span_log(&s->logging, SPAN_LOG_FLOW, "Spin (long) by %.5f rads\n", p);
677             zz = complex_setf(cosf(p), -sinf(p));
678             for (i = 0;  i <= V17_EQUALIZER_MASK;  i++)
679                 s->eq_buf[i] = complex_mulf(&s->eq_buf[i], &zz);
680             s->carrier_phase += (angle - 219937506);
681 
682             /* We have just seen the first symbol of the scrambled sequence, so skip it. */
683             descramble(s, 1);
684             descramble(s, 1);
685             s->training_count = 1;
686             s->training_stage = TRAINING_STAGE_COARSE_TRAIN_ON_CDBA;
687             report_status_change(s, PUTBIT_TRAINING_IN_PROGRESS);
688             break;
689         }
690         if (++s->training_count > V17_TRAINING_SEG_1_LEN)
691         {
692             /* This is bogus. There are not this many bits in this section
693                of a real training sequence. Note that this might be TEP. */
694             span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n");
695             /* Park this modem */
696             s->agc_scaling_save = 0.0f;
697             s->training_stage = TRAINING_STAGE_PARKED;
698             report_status_change(s, PUTBIT_TRAINING_FAILED);
699         }
700         break;
701     case TRAINING_STAGE_COARSE_TRAIN_ON_CDBA:
702         /* Train on the scrambled CDBA section. */
703         bit = descramble(s, 1);
704         bit = (bit << 1) | descramble(s, 1);
705         target = &cdba[bit];
706         track_carrier(s, &z, target);
707         tune_equalizer(s, &z, target);
708 #if defined(IAXMODEM_STUFF)
709         zz = complex_subf(&z, target);
710         s->training_error = powerf(&zz);
711         if (++s->training_count == V17_TRAINING_SEG_2_LEN - 2000  ||  s->training_error < 1.0f  ||  s->training_error > 200.0f)
712 #else
713         if (++s->training_count == V17_TRAINING_SEG_2_LEN - 2000)
714 #endif
715         {
716             /* Now the equaliser adaption should be getting somewhere, slow it down, or it will never
717                tune very well on a noisy signal. */
718             s->eq_delta *= EQUALIZER_SLOW_ADAPT_RATIO;
719             s->carrier_track_i = 1000.0f;
720             s->training_stage = TRAINING_STAGE_FINE_TRAIN_ON_CDBA;
721         }
722         break;
723     case TRAINING_STAGE_FINE_TRAIN_ON_CDBA:
724         /* Train on the scrambled CDBA section. */
725         bit = descramble(s, 1);
726         bit = (bit << 1) | descramble(s, 1);
727         target = &cdba[bit];
728         /* By this point the training should be comming into focus. */
729         track_carrier(s, &z, target);
730         tune_equalizer(s, &z, target);
731         if (++s->training_count >= V17_TRAINING_SEG_2_LEN - 48)
732         {
733             s->training_error = 0.0f;
734             s->carrier_track_i = 100.0f;
735             s->carrier_track_p = 500000.0f;
736             s->training_stage = TRAINING_STAGE_TRAIN_ON_CDBA_AND_TEST;
737         }
738         break;
739     case TRAINING_STAGE_TRAIN_ON_CDBA_AND_TEST:
740         /* Continue training on the scrambled CDBA section, but measure the quality of training too. */
741         bit = descramble(s, 1);
742         bit = (bit << 1) | descramble(s, 1);
743         target = &cdba[bit];
744         //span_log(&s->logging, SPAN_LOG_FLOW, "%5d [%15.5f, %15.5f]     [%15.5f, %15.5f]\n", s->training_count, z.re, z.im, cdba[bit].re, cdba[bit].im);
745         /* We ignore the last few symbols because it seems some modems do not end this
746            part properly, and it throws things off. */
747         if (++s->training_count < V17_TRAINING_SEG_2_LEN - 20)
748         {
749             track_carrier(s, &z, target);
750             tune_equalizer(s, &z, target);
751             /* Measure the training error */
752             zz = complex_subf(&z, &cdba[bit]);
753             s->training_error += powerf(&zz);
754         }
755         else if (s->training_count >= V17_TRAINING_SEG_2_LEN)
756         {
757             span_log(&s->logging, SPAN_LOG_FLOW, "Long training error %f\n", s->training_error);
758             if (s->training_error < 40.0f)
759             {
760                 s->training_count = 0;
761                 s->training_error = 0.0f;
762                 s->training_stage = TRAINING_STAGE_BRIDGE;
763             }
764             else
765             {
766                 span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (convergence failed)\n");
767                 /* Park this modem */
768                 s->agc_scaling_save = 0.0f;
769                 s->training_stage = TRAINING_STAGE_PARKED;
770                 report_status_change(s, PUTBIT_TRAINING_FAILED);
771             }
772         }
773         break;
774     case TRAINING_STAGE_BRIDGE:
775         descramble(s, V17_BRIDGE_WORD >> ((s->training_count & 0x7) << 1));
776         descramble(s, V17_BRIDGE_WORD >> (((s->training_count & 0x7) << 1) + 1));
777         target = &z;
778         if (++s->training_count >= V17_TRAINING_SEG_3_LEN)
779         {
780             s->training_count = 0;
781             s->training_error = 0.0f;
782             s->training_stage = TRAINING_STAGE_TCM_WINDUP;
783         }
784         break;
785     case TRAINING_STAGE_SHORT_WAIT_FOR_CDBA:
786         target = &cdba[(s->training_count & 1) + 2];
787         /* Look for the initial ABAB sequence to display a phase reversal, which will
788            signal the start of the scrambled CDBA segment */
789         angle = arctan2(z.im, z.re);
790         ang = angle - s->angles[s->training_count & 1];
791         if (ang > 0x40000000  ||  ang < -0x40000000)
792         {
793             /* We seem to have a phase reversal */
794             /* We have just seen the first symbol of the scrambled sequence, so skip it. */
795             descramble(s, 1);
796             descramble(s, 1);
797             s->training_count = 1;
798             s->training_error = 0.0f;
799             s->training_stage = TRAINING_STAGE_SHORT_TRAIN_ON_CDBA_AND_TEST;
800             break;
801         }
802         track_carrier(s, &z, target);
803         if (++s->training_count > V17_TRAINING_SEG_1_LEN)
804         {
805             /* This is bogus. There are not this many bits in this section
806                of a real training sequence. Note that this might be TEP. */
807             span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n");
808             /* Park this modem */
809             report_status_change(s, PUTBIT_TRAINING_FAILED);
810             s->training_stage = TRAINING_STAGE_PARKED;
811         }
812         break;
813     case TRAINING_STAGE_SHORT_TRAIN_ON_CDBA_AND_TEST:
814         /* Short retrain on the scrambled CDBA section, but measure the quality of training too. */
815         bit = descramble(s, 1);
816         bit = (bit << 1) | descramble(s, 1);
817         //span_log(&s->logging, SPAN_LOG_FLOW, "%5d [%15.5f, %15.5f]     [%15.5f, %15.5f] %d\n", s->training_count, z.re, z.im, cdba[bit].re, cdba[bit].im, arctan2(z.im, z.re));
818         target = &cdba[bit];
819         track_carrier(s, &z, target);
820         //tune_equalizer(s, &z, target);
821         /* Measure the training error */
822         if (s->training_count > 8)
823         {
824             zz = complex_subf(&z, &cdba[bit]);
825             s->training_error += powerf(&zz);
826         }
827         if (++s->training_count >= V17_TRAINING_SHORT_SEG_2_LEN)
828         {
829             span_log(&s->logging, SPAN_LOG_FLOW, "Short training error %f\n", s->training_error);
830             s->carrier_track_i = 100.0f;
831             s->carrier_track_p = 500000.0f;
832             /* TODO: This was changed from 20.0 to 200.0 after studying real world failures.
833                      However, it is not clear why this is an improvement, If something gives
834                      a training error way over 20, surely it shouldn't decode too well? */
835             if (s->training_error < 200.0f)
836             {
837                 s->training_count = 0;
838                 s->training_stage = TRAINING_STAGE_TCM_WINDUP;
839                 report_status_change(s, PUTBIT_TRAINING_IN_PROGRESS);
840             }
841             else
842             {
843                 span_log(&s->logging, SPAN_LOG_FLOW, "Short training failed (convergence failed)\n");
844                 /* Park this modem */
845                 report_status_change(s, PUTBIT_TRAINING_FAILED);
846                 s->training_stage = TRAINING_STAGE_PARKED;
847             }
848         }
849         break;
850     case TRAINING_STAGE_TCM_WINDUP:
851         /* We need to wait 15 bauds while the trellis fills up. */
852         //span_log(&s->logging, SPAN_LOG_FLOW, "%5d %15.5f, %15.5f\n", s->training_count, z.re, z.im);
853         constellation_state = decode_baud(s, &z);
854         target = &s->constellation[constellation_state];
855         /* Measure the training error */
856         zz = complex_subf(&z, target);
857         s->training_error += powerf(&zz);
858         if (++s->training_count >= V17_TRAINING_SEG_4A_LEN)
859         {
860             s->training_count = 0;
861             s->training_error = 0.0f;
862             /* Restart the differential decoder */
863             s->diff = (s->short_train)  ?  0  :  1;
864             s->training_stage = TRAINING_STAGE_TEST_ONES;
865         }
866         break;
867     case TRAINING_STAGE_TEST_ONES:
868         /* We are in the test phase, where we check that we can receive reliably.
869            We should get a run of 1's, 48 symbols long. */
870         //span_log(&s->logging, SPAN_LOG_FLOW, "%5d %15.5f, %15.5f\n", s->training_count, z.re, z.im);
871         constellation_state = decode_baud(s, &z);
872         target = &s->constellation[constellation_state];
873         /* Measure the training error */
874         zz = complex_subf(&z, target);
875         s->training_error += powerf(&zz);
876         if (++s->training_count >= V17_TRAINING_SEG_4_LEN)
877         {
878 #if defined(IAXMODEM_STUFF)
879             if (s->training_error < 80.0f)
880 #else
881             if (s->training_error < 30.0f)
882 #endif
883             {
884                 /* We are up and running */
885                 span_log(&s->logging, SPAN_LOG_FLOW, "Training succeeded (constellation mismatch %f)\n", s->training_error);
886                 report_status_change(s, PUTBIT_TRAINING_SUCCEEDED);
887                 /* Apply some lag to the carrier off condition, to ensure the last few bits get pushed through
888                    the processing. */
889                 s->signal_present = 60;
890                 equalizer_save(s);
891                 s->carrier_phase_rate_save = s->carrier_phase_rate;
892                 s->short_train = TRUE;
893                 s->training_stage = TRAINING_STAGE_NORMAL_OPERATION;
894             }
895             else
896             {
897                 /* Training has failed */
898                 span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (constellation mismatch %f)\n", s->training_error);
899                 /* Park this modem */
900                 if (!s->short_train)
901                     s->agc_scaling_save = 0.0f;
902                 report_status_change(s, PUTBIT_TRAINING_FAILED);
903                 s->training_stage = TRAINING_STAGE_PARKED;
904             }
905         }
906         break;
907     case TRAINING_STAGE_PARKED:
908     default:
909         /* We failed to train! */
910         /* Park here until the carrier drops. */
911         target = &z;
912         break;
913     }
914     if (s->qam_report)
915         s->qam_report(s->qam_user_data, &z, target, constellation_state);
916 }
917 /*- End of function --------------------------------------------------------*/
918 
v17_rx(v17_rx_state_t * s,const int16_t amp[],int len)919 int v17_rx(v17_rx_state_t *s, const int16_t amp[], int len)
920 {
921     int i;
922     int j;
923     int step;
924     int16_t x;
925     int32_t diff;
926     complexf_t z;
927     complexf_t zz;
928     complexf_t sample;
929 #if defined(SPANDSP_USE_FIXED_POINT)
930     complexi_t zi;
931 #endif
932     int32_t power;
933     float v;
934 
935     for (i = 0;  i < len;  i++)
936     {
937         s->rrc_filter[s->rrc_filter_step] =
938         s->rrc_filter[s->rrc_filter_step + V17_RX_FILTER_STEPS] = amp[i];
939         if (++s->rrc_filter_step >= V17_RX_FILTER_STEPS)
940             s->rrc_filter_step = 0;
941 
942         /* There should be no DC in the signal, but sometimes there is.
943            We need to measure the power with the DC blocked, but not using
944            a slow to respond DC blocker. Use the most elementary HPF. */
945         x = amp[i] >> 1;
946         diff = x - s->last_sample;
947         power = power_meter_update(&(s->power), diff);
948 #if defined(IAXMODEM_STUFF)
949         /* Quick power drop fudge */
950         diff = abs(diff);
951         if (10*diff < s->high_sample)
952         {
953             if (++s->low_samples > 120)
954             {
955                 power_meter_init(&(s->power), 4);
956                 s->high_sample = 0;
957                 s->low_samples = 0;
958             }
959         }
960         else
961         {
962             s->low_samples = 0;
963             if (diff > s->high_sample)
964                s->high_sample = diff;
965         }
966 #endif
967         s->last_sample = x;
968         if (s->signal_present)
969         {
970             /* Look for power below turnoff threshold to turn the carrier off */
971 #if defined(IAXMODEM_STUFF)
972             if (s->carrier_drop_pending  ||  power < s->carrier_off_power)
973 #else
974             if (power < s->carrier_off_power)
975 #endif
976             {
977                 if (--s->signal_present <= 0)
978                 {
979                     /* Count down a short delay, to ensure we push the last
980                        few bits through the filters before stopping. */
981                     v17_rx_restart(s, s->bit_rate, s->short_train);
982                     report_status_change(s, PUTBIT_CARRIER_DOWN);
983                     continue;
984                 }
985 #if defined(IAXMODEM_STUFF)
986                 /* Carrier has dropped, but the put_bit is
987                    pending the signal_present delay. */
988                 s->carrier_drop_pending = TRUE;
989 #endif
990             }
991         }
992         else
993         {
994             /* Look for power exceeding turnon threshold to turn the carrier on */
995             if (power < s->carrier_on_power)
996                 continue;
997             s->signal_present = 1;
998 #if defined(IAXMODEM_STUFF)
999             s->carrier_drop_pending = FALSE;
1000 #endif
1001             report_status_change(s, PUTBIT_CARRIER_UP);
1002         }
1003         if (s->training_stage == TRAINING_STAGE_PARKED)
1004             continue;
1005         /* Only spend effort processing this data if the modem is not
1006            parked, after training failure. */
1007         s->eq_put_step -= RX_PULSESHAPER_COEFF_SETS;
1008         step = -s->eq_put_step;
1009         if (step > RX_PULSESHAPER_COEFF_SETS - 1)
1010             step = RX_PULSESHAPER_COEFF_SETS - 1;
1011         if (step < 0)
1012             step += RX_PULSESHAPER_COEFF_SETS;
1013 #if defined(SPANDSP_USE_FIXED_POINT)
1014         zi.re = (int32_t) rx_pulseshaper[step][0].re*(int32_t) s->rrc_filter[s->rrc_filter_step];
1015         for (j = 1;  j < V17_RX_FILTER_STEPS;  j++)
1016             zi.re += (int32_t) rx_pulseshaper[step][j].re*(int32_t) s->rrc_filter[j + s->rrc_filter_step];
1017         sample.re = zi.re*s->agc_scaling;
1018 #else
1019         zz.re = rx_pulseshaper[step][0].re*s->rrc_filter[s->rrc_filter_step];
1020         for (j = 1;  j < V17_RX_FILTER_STEPS;  j++)
1021             zz.re += rx_pulseshaper[step][j].re*s->rrc_filter[j + s->rrc_filter_step];
1022         sample.re = zz.re*s->agc_scaling;
1023 #endif
1024 
1025         /* Symbol timing synchronisation band edge filters */
1026         /* Low Nyquist band edge filter */
1027         v = s->symbol_sync_low[0]*SYNC_LOW_BAND_EDGE_COEFF_0 + s->symbol_sync_low[1]*SYNC_LOW_BAND_EDGE_COEFF_1 + sample.re;
1028         s->symbol_sync_low[1] = s->symbol_sync_low[0];
1029         s->symbol_sync_low[0] = v;
1030         /* High Nyquist band edge filter */
1031         v = s->symbol_sync_high[0]*SYNC_HIGH_BAND_EDGE_COEFF_0 + s->symbol_sync_high[1]*SYNC_HIGH_BAND_EDGE_COEFF_1 + sample.re;
1032         s->symbol_sync_high[1] = s->symbol_sync_high[0];
1033         s->symbol_sync_high[0] = v;
1034 
1035         /* Put things into the equalization buffer at T/2 rate. The symbol sync.
1036            will fiddle the step to align this with the symbols. */
1037         if (s->eq_put_step <= 0)
1038         {
1039             /* Only AGC until we have locked down the setting. */
1040             if (s->agc_scaling_save == 0.0f)
1041                 s->agc_scaling = (1.0f/RX_PULSESHAPER_GAIN)*2.17f/sqrtf(power);
1042             /* Pulse shape while still at the carrier frequency, using a quadrature
1043                pair of filters. This results in a properly bandpass filtered complex
1044                signal, which can be brought directly to baseband by complex mixing.
1045                No further filtering, to remove mixer harmonics, is needed. */
1046             step = -s->eq_put_step;
1047             if (step > RX_PULSESHAPER_COEFF_SETS - 1)
1048                 step = RX_PULSESHAPER_COEFF_SETS - 1;
1049 #if defined(SPANDSP_USE_FIXED_POINT)
1050             zi.im = (int32_t) rx_pulseshaper[step][0].im*(int32_t) s->rrc_filter[s->rrc_filter_step];
1051             for (j = 1;  j < V17_RX_FILTER_STEPS;  j++)
1052                 zi.im += (int32_t) rx_pulseshaper[step][j].im*(int32_t) s->rrc_filter[j + s->rrc_filter_step];
1053             sample.im = zi.im*s->agc_scaling;
1054 #else
1055             zz.im = rx_pulseshaper[step][0].im*s->rrc_filter[s->rrc_filter_step];
1056             for (j = 1;  j < V17_RX_FILTER_STEPS;  j++)
1057                 zz.im += rx_pulseshaper[step][j].im*s->rrc_filter[j + s->rrc_filter_step];
1058             sample.im = zz.im*s->agc_scaling;
1059 #endif
1060             s->eq_put_step += RX_PULSESHAPER_COEFF_SETS*10/(3*2);
1061             /* Shift to baseband - since this is done in a full complex form, the
1062                result is clean, and requires no further filtering, apart from the
1063                equalizer. */
1064             z = dds_lookup_complexf(s->carrier_phase);
1065             zz.re = sample.re*z.re - sample.im*z.im;
1066             zz.im = -sample.re*z.im - sample.im*z.re;
1067             process_half_baud(s, &zz);
1068         }
1069         dds_advancef(&(s->carrier_phase), s->carrier_phase_rate);
1070     }
1071     return 0;
1072 }
1073 /*- End of function --------------------------------------------------------*/
1074 
v17_rx_set_put_bit(v17_rx_state_t * s,put_bit_func_t put_bit,void * user_data)1075 void v17_rx_set_put_bit(v17_rx_state_t *s, put_bit_func_t put_bit, void *user_data)
1076 {
1077     s->put_bit = put_bit;
1078     s->put_bit_user_data = user_data;
1079 }
1080 /*- End of function --------------------------------------------------------*/
1081 
v17_rx_set_modem_status_handler(v17_rx_state_t * s,modem_tx_status_func_t handler,void * user_data)1082 void v17_rx_set_modem_status_handler(v17_rx_state_t *s, modem_tx_status_func_t handler, void *user_data)
1083 {
1084     s->status_handler = handler;
1085     s->status_user_data = user_data;
1086 }
1087 /*- End of function --------------------------------------------------------*/
1088 
v17_rx_restart(v17_rx_state_t * s,int bit_rate,int short_train)1089 int v17_rx_restart(v17_rx_state_t *s, int bit_rate, int short_train)
1090 {
1091     int i;
1092 
1093     span_log(&s->logging, SPAN_LOG_FLOW, "Restarting V.17, %dbps, %s training\n", bit_rate, (short_train)  ?  "short"  :  "long");
1094     switch (bit_rate)
1095     {
1096     case 14400:
1097         s->constellation = v17_14400_constellation;
1098         s->space_map = 0;
1099         s->bits_per_symbol = 6;
1100         break;
1101     case 12000:
1102         s->constellation = v17_12000_constellation;
1103         s->space_map = 1;
1104         s->bits_per_symbol = 5;
1105         break;
1106     case 9600:
1107         s->constellation = v17_9600_constellation;
1108         s->space_map = 2;
1109         s->bits_per_symbol = 4;
1110         break;
1111     case 7200:
1112         s->constellation = v17_7200_constellation;
1113         s->space_map = 3;
1114         s->bits_per_symbol = 3;
1115         break;
1116     default:
1117         return -1;
1118     }
1119     s->bit_rate = bit_rate;
1120 #if defined(SPANDSP_USE_FIXED_POINT)
1121     memset(s->rrc_filter, 0, sizeof(s->rrc_filter));
1122 #else
1123     vec_zerof(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
1124 #endif
1125     s->rrc_filter_step = 0;
1126 
1127     s->diff = 1;
1128     s->scramble_reg = 0x2ECDD5;
1129     s->training_stage = TRAINING_STAGE_SYMBOL_ACQUISITION;
1130     s->training_count = 0;
1131     s->training_error = 0.0f;
1132     s->signal_present = 0;
1133 #if defined(IAXMODEM_STUFF)
1134     s->high_sample = 0;
1135     s->low_samples = 0;
1136     s->carrier_drop_pending = FALSE;
1137 #endif
1138     if (short_train != 2)
1139         s->short_train = short_train;
1140     memset(s->start_angles, 0, sizeof(s->start_angles));
1141     memset(s->angles, 0, sizeof(s->angles));
1142 
1143     /* Initialise the TCM decoder parameters. */
1144     /* The accumulated distance vectors are set so state zero starts
1145        at a value of zero, and all others start larger. This forces the
1146        initial paths to merge at the zero states. */
1147     for (i = 0;  i < 8;  i++)
1148 #if defined(SPANDSP_USE_FIXED_POINTx)
1149         s->distances[i] = 99*DIST_FACTOR*DIST_FACTOR;
1150 #else
1151         s->distances[i] = 99.0f;
1152 #endif
1153     memset(s->full_path_to_past_state_locations, 0, sizeof(s->full_path_to_past_state_locations));
1154     memset(s->past_state_locations, 0, sizeof(s->past_state_locations));
1155     s->distances[0] = 0;
1156     s->trellis_ptr = 14;
1157 
1158     span_log(&s->logging, SPAN_LOG_FLOW, "Phase rates %f %f\n", dds_frequencyf(s->carrier_phase_rate), dds_frequencyf(s->carrier_phase_rate_save));
1159     s->carrier_phase = 0;
1160     power_meter_init(&(s->power), 4);
1161 
1162     if (s->short_train)
1163     {
1164         s->carrier_phase_rate = s->carrier_phase_rate_save;
1165         s->agc_scaling = s->agc_scaling_save;
1166         equalizer_restore(s);
1167         /* Don't allow any frequency correction at all, until we start to pull the phase in. */
1168         s->carrier_track_i = 0.0f;
1169         s->carrier_track_p = 40000.0f;
1170     }
1171     else
1172     {
1173         s->carrier_phase_rate = dds_phase_ratef(CARRIER_NOMINAL_FREQ);
1174         s->agc_scaling_save = 0.0f;
1175         s->agc_scaling = 0.0017f/RX_PULSESHAPER_GAIN;
1176         equalizer_reset(s);
1177         s->carrier_track_i = 5000.0f;
1178         s->carrier_track_p = 40000.0f;
1179     }
1180     s->last_sample = 0;
1181 
1182     /* Initialise the working data for symbol timing synchronisation */
1183     s->symbol_sync_low[0] = 0.0f;
1184     s->symbol_sync_low[1] = 0.0f;
1185     s->symbol_sync_high[0] = 0.0f;
1186     s->symbol_sync_high[1] = 0.0f;
1187     s->symbol_sync_dc_filter[0] = 0.0f;
1188     s->symbol_sync_dc_filter[1] = 0.0f;
1189     s->baud_phase = 0.0f;
1190     s->baud_half = 0;
1191 
1192     s->total_baud_timing_correction = 0;
1193 
1194     return 0;
1195 }
1196 /*- End of function --------------------------------------------------------*/
1197 
v17_rx_init(v17_rx_state_t * s,int bit_rate,put_bit_func_t put_bit,void * user_data)1198 v17_rx_state_t *v17_rx_init(v17_rx_state_t *s, int bit_rate, put_bit_func_t put_bit, void *user_data)
1199 {
1200     if (s == NULL)
1201     {
1202         if ((s = (v17_rx_state_t *) malloc(sizeof(*s))) == NULL)
1203             return NULL;
1204     }
1205     memset(s, 0, sizeof(*s));
1206     span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
1207     span_log_set_protocol(&s->logging, "V.17 RX");
1208     s->put_bit = put_bit;
1209     s->put_bit_user_data = user_data;
1210     s->short_train = FALSE;
1211     v17_rx_signal_cutoff(s, -45.5f);
1212     s->agc_scaling = 0.0017f/RX_PULSESHAPER_GAIN;
1213     s->agc_scaling_save = 0.0f;
1214     s->carrier_phase_rate_save = dds_phase_ratef(CARRIER_NOMINAL_FREQ);
1215 
1216     v17_rx_restart(s, bit_rate, s->short_train);
1217     return s;
1218 }
1219 /*- End of function --------------------------------------------------------*/
1220 
v17_rx_free(v17_rx_state_t * s)1221 int v17_rx_free(v17_rx_state_t *s)
1222 {
1223     free(s);
1224     return 0;
1225 }
1226 /*- End of function --------------------------------------------------------*/
1227 
v17_rx_set_qam_report_handler(v17_rx_state_t * s,qam_report_handler_t handler,void * user_data)1228 void v17_rx_set_qam_report_handler(v17_rx_state_t *s, qam_report_handler_t handler, void *user_data)
1229 {
1230     s->qam_report = handler;
1231     s->qam_user_data = user_data;
1232 }
1233 /*- End of function --------------------------------------------------------*/
1234 /*- End of file ------------------------------------------------------------*/
1235