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