comparison spandsp-0.0.6pre17/src/v29rx.c @ 4:26cd8f1ef0b1

import spandsp-0.0.6pre17
author Peter Meerwald <pmeerw@cosy.sbg.ac.at>
date Fri, 25 Jun 2010 15:50:58 +0200
parents
children
comparison
equal deleted inserted replaced
3:c6c5a16ce2f2 4:26cd8f1ef0b1
1 #define IAXMODEM_STUFF
2 /*
3 * SpanDSP - a series of DSP components for telephony
4 *
5 * v29rx.c - ITU V.29 modem receive part
6 *
7 * Written by Steve Underwood <steveu@coppice.org>
8 *
9 * Copyright (C) 2003, 2004, 2005, 2006, 2007 Steve Underwood
10 *
11 * All rights reserved.
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU Lesser General Public License version 2.1,
15 * as published by the Free Software Foundation.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Lesser General Public License for more details.
21 *
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 * $Id: v29rx.c,v 1.167.4.5 2009/12/28 12:20:47 steveu Exp $
27 */
28
29 /*! \file */
30
31 #if defined(HAVE_CONFIG_H)
32 #include "config.h"
33 #endif
34
35 #include <stdlib.h>
36 #include <inttypes.h>
37 #include <string.h>
38 #include <stdio.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 #include "floating_fudge.h"
46
47 #include "spandsp/telephony.h"
48 #include "spandsp/logging.h"
49 #include "spandsp/complex.h"
50 #include "spandsp/vector_float.h"
51 #include "spandsp/complex_vector_float.h"
52 #include "spandsp/vector_int.h"
53 #include "spandsp/complex_vector_int.h"
54 #include "spandsp/async.h"
55 #include "spandsp/power_meter.h"
56 #include "spandsp/arctan2.h"
57 #include "spandsp/dds.h"
58 #include "spandsp/complex_filters.h"
59
60 #include "spandsp/v29rx.h"
61
62 #include "spandsp/private/logging.h"
63 #include "spandsp/private/v29rx.h"
64
65 #include "v29tx_constellation_maps.h"
66 #if defined(SPANDSP_USE_FIXED_POINT)
67 #include "v29rx_fixed_rrc.h"
68 #else
69 #include "v29rx_floating_rrc.h"
70 #endif
71
72 /*! The nominal frequency of the carrier, in Hertz */
73 #define CARRIER_NOMINAL_FREQ 1700.0f
74 /*! The nominal baud or symbol rate */
75 #define BAUD_RATE 2400
76 /*! The adaption rate coefficient for the equalizer */
77 #define EQUALIZER_DELTA 0.21f
78
79 #if defined(SPANDSP_USE_FIXED_POINT)
80 #define FP_FACTOR 4096
81 #define FP_SHIFT_FACTOR 12
82 #endif
83
84 /* Segments of the training sequence */
85 /*! The length of training segment 2, in symbols */
86 #define V29_TRAINING_SEG_2_LEN 128
87 /*! The length of training segment 3, in symbols */
88 #define V29_TRAINING_SEG_3_LEN 384
89 /*! The length of training segment 4, in symbols */
90 #define V29_TRAINING_SEG_4_LEN 48
91
92 /*! The length of the equalizer buffer */
93 #define V29_EQUALIZER_LEN (V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN)
94
95 enum
96 {
97 TRAINING_STAGE_NORMAL_OPERATION = 0,
98 TRAINING_STAGE_SYMBOL_ACQUISITION,
99 TRAINING_STAGE_LOG_PHASE,
100 TRAINING_STAGE_WAIT_FOR_CDCD,
101 TRAINING_STAGE_TRAIN_ON_CDCD,
102 TRAINING_STAGE_TRAIN_ON_CDCD_AND_TEST,
103 TRAINING_STAGE_TEST_ONES,
104 TRAINING_STAGE_PARKED
105 };
106
107 static const uint8_t space_map_9600[20][20] =
108 {
109 {13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11},
110 {13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11},
111 {13, 13, 13, 13, 13, 13, 13, 4, 4, 4, 4, 4, 4, 11, 11, 11, 11, 11, 11, 11},
112 {13, 13, 13, 13, 13, 13, 13, 4, 4, 4, 4, 4, 4, 11, 11, 11, 11, 11, 11, 11},
113 {13, 13, 13, 13, 13, 13, 13, 4, 4, 4, 4, 4, 4, 11, 11, 11, 11, 11, 11, 11},
114 {13, 13, 13, 13, 13, 13, 13, 5, 4, 4, 4, 4, 3, 11, 11, 11, 11, 11, 11, 11},
115 {14, 13, 13, 13, 13, 13, 5, 5, 5, 5, 3, 3, 3, 3, 11, 11, 11, 11, 11, 10},
116 {14, 14, 6, 6, 6, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 2, 2, 2, 10, 10},
117 {14, 14, 6, 6, 6, 6, 5, 5, 5, 5, 3, 3, 3, 3, 2, 2, 2, 2, 10, 10},
118 {14, 14, 6, 6, 6, 6, 5, 5, 5, 5, 3, 3, 3, 3, 2, 2, 2, 2, 10, 10},
119 {14, 14, 6, 6, 6, 6, 7, 7, 7, 7, 1, 1, 1, 1, 2, 2, 2, 2, 10, 10},
120 {14, 14, 6, 6, 6, 6, 7, 7, 7, 7, 1, 1, 1, 1, 2, 2, 2, 2, 10, 10},
121 {14, 14, 6, 6, 6, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 2, 2, 2, 10, 10},
122 {14, 15, 15, 15, 15, 15, 7, 7, 7, 7, 1, 1, 1, 1, 9, 9, 9, 9, 9, 10},
123 {15, 15, 15, 15, 15, 15, 15, 7, 0, 0, 0, 0, 1, 9, 9, 9, 9, 9, 9, 9},
124 {15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9},
125 {15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9},
126 {15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9},
127 {15, 15, 15, 15, 15, 15, 15, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9},
128 {15, 15, 15, 15, 15, 15, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9}
129 };
130
131 /* Coefficients for the band edge symbol timing synchroniser (alpha = 0.99) */
132 /* low_edge = 2.0f*M_PI*(CARRIER_NOMINAL_FREQ - BAUD_RATE/2.0f)/SAMPLE_RATE; */
133 /* high_edge = 2.0f*M_PI*(CARRIER_NOMINAL_FREQ + BAUD_RATE/2.0f)/SAMPLE_RATE; */
134 #define SIN_LOW_BAND_EDGE 0.382683432f
135 #define COS_LOW_BAND_EDGE 0.923879533f
136 #define SIN_HIGH_BAND_EDGE 0.760405966f
137 #define COS_HIGH_BAND_EDGE -0.649448048f
138 #define ALPHA 0.99f
139
140 #if defined(SPANDSP_USE_FIXED_POINT)
141 #define SYNC_LOW_BAND_EDGE_COEFF_0 ((int)(FP_FACTOR*(2.0f*ALPHA*COS_LOW_BAND_EDGE)))
142 #define SYNC_LOW_BAND_EDGE_COEFF_1 ((int)(FP_FACTOR*(-ALPHA*ALPHA)))
143 #define SYNC_LOW_BAND_EDGE_COEFF_2 ((int)(FP_FACTOR*(-ALPHA*SIN_LOW_BAND_EDGE)))
144 #define SYNC_HIGH_BAND_EDGE_COEFF_0 ((int)(FP_FACTOR*(2.0f*ALPHA*COS_HIGH_BAND_EDGE)))
145 #define SYNC_HIGH_BAND_EDGE_COEFF_1 ((int)(FP_FACTOR*(-ALPHA*ALPHA)))
146 #define SYNC_HIGH_BAND_EDGE_COEFF_2 ((int)(FP_FACTOR*(-ALPHA*SIN_HIGH_BAND_EDGE)))
147 #define SYNC_MIXED_EDGES_COEFF_3 ((int)(FP_FACTOR*(-ALPHA*ALPHA*(SIN_HIGH_BAND_EDGE*COS_LOW_BAND_EDGE - SIN_LOW_BAND_EDGE*COS_HIGH_BAND_EDGE))))
148 #else
149 #define SYNC_LOW_BAND_EDGE_COEFF_0 (2.0f*ALPHA*COS_LOW_BAND_EDGE)
150 #define SYNC_LOW_BAND_EDGE_COEFF_1 (-ALPHA*ALPHA)
151 #define SYNC_LOW_BAND_EDGE_COEFF_2 (-ALPHA*SIN_LOW_BAND_EDGE)
152 #define SYNC_HIGH_BAND_EDGE_COEFF_0 (2.0f*ALPHA*COS_HIGH_BAND_EDGE)
153 #define SYNC_HIGH_BAND_EDGE_COEFF_1 (-ALPHA*ALPHA)
154 #define SYNC_HIGH_BAND_EDGE_COEFF_2 (-ALPHA*SIN_HIGH_BAND_EDGE)
155 #define SYNC_MIXED_EDGES_COEFF_3 (-ALPHA*ALPHA*(SIN_HIGH_BAND_EDGE*COS_LOW_BAND_EDGE - SIN_LOW_BAND_EDGE*COS_HIGH_BAND_EDGE))
156 #endif
157
158 SPAN_DECLARE(float) v29_rx_carrier_frequency(v29_rx_state_t *s)
159 {
160 return dds_frequencyf(s->carrier_phase_rate);
161 }
162 /*- End of function --------------------------------------------------------*/
163
164 SPAN_DECLARE(float) v29_rx_symbol_timing_correction(v29_rx_state_t *s)
165 {
166 return (float) s->total_baud_timing_correction/((float) RX_PULSESHAPER_COEFF_SETS*10.0f/3.0f);
167 }
168 /*- End of function --------------------------------------------------------*/
169
170 SPAN_DECLARE(float) v29_rx_signal_power(v29_rx_state_t *s)
171 {
172 return power_meter_current_dbm0(&s->power) + 3.98f;
173 }
174 /*- End of function --------------------------------------------------------*/
175
176 SPAN_DECLARE(void) v29_rx_signal_cutoff(v29_rx_state_t *s, float cutoff)
177 {
178 /* The 0.4 factor allows for the gain of the DC blocker */
179 s->carrier_on_power = (int32_t) (power_meter_level_dbm0(cutoff + 2.5f)*0.4f);
180 s->carrier_off_power = (int32_t) (power_meter_level_dbm0(cutoff - 2.5f)*0.4f);
181 }
182 /*- End of function --------------------------------------------------------*/
183
184 static void report_status_change(v29_rx_state_t *s, int status)
185 {
186 if (s->status_handler)
187 s->status_handler(s->status_user_data, status);
188 else if (s->put_bit)
189 s->put_bit(s->put_bit_user_data, status);
190 }
191 /*- End of function --------------------------------------------------------*/
192
193 #if defined(SPANDSP_USE_FIXED_POINT)
194 SPAN_DECLARE(int) v29_rx_equalizer_state(v29_rx_state_t *s, complexi16_t **coeffs)
195 #else
196 SPAN_DECLARE(int) v29_rx_equalizer_state(v29_rx_state_t *s, complexf_t **coeffs)
197 #endif
198 {
199 *coeffs = s->eq_coeff;
200 return V29_EQUALIZER_LEN;
201 }
202 /*- End of function --------------------------------------------------------*/
203
204 static void equalizer_save(v29_rx_state_t *s)
205 {
206 #if defined(SPANDSP_USE_FIXED_POINT)
207 cvec_copyi16(s->eq_coeff_save, s->eq_coeff, V29_EQUALIZER_LEN);
208 #else
209 cvec_copyf(s->eq_coeff_save, s->eq_coeff, V29_EQUALIZER_LEN);
210 #endif
211 }
212 /*- End of function --------------------------------------------------------*/
213
214 static void equalizer_restore(v29_rx_state_t *s)
215 {
216 #if defined(SPANDSP_USE_FIXED_POINT)
217 cvec_copyi16(s->eq_coeff, s->eq_coeff_save, V29_EQUALIZER_LEN);
218 cvec_zeroi16(s->eq_buf, V29_EQUALIZER_LEN);
219 s->eq_delta = 32768.0f*EQUALIZER_DELTA/V29_EQUALIZER_LEN;
220 #else
221 cvec_copyf(s->eq_coeff, s->eq_coeff_save, V29_EQUALIZER_LEN);
222 cvec_zerof(s->eq_buf, V29_EQUALIZER_LEN);
223 s->eq_delta = EQUALIZER_DELTA/V29_EQUALIZER_LEN;
224 #endif
225
226 s->eq_put_step = RX_PULSESHAPER_COEFF_SETS*10/(3*2) - 1;
227 s->eq_step = 0;
228 }
229 /*- End of function --------------------------------------------------------*/
230
231 static void equalizer_reset(v29_rx_state_t *s)
232 {
233 /* Start with an equalizer based on everything being perfect */
234 #if defined(SPANDSP_USE_FIXED_POINT)
235 cvec_zeroi16(s->eq_coeff, V29_EQUALIZER_LEN);
236 s->eq_coeff[V29_EQUALIZER_POST_LEN] = complex_seti16(3*FP_FACTOR, 0*FP_FACTOR);
237 cvec_zeroi16(s->eq_buf, V29_EQUALIZER_LEN);
238 s->eq_delta = 32768.0f*EQUALIZER_DELTA/V29_EQUALIZER_LEN;
239 #else
240 cvec_zerof(s->eq_coeff, V29_EQUALIZER_LEN);
241 s->eq_coeff[V29_EQUALIZER_POST_LEN] = complex_setf(3.0f, 0.0f);
242 cvec_zerof(s->eq_buf, V29_EQUALIZER_LEN);
243 s->eq_delta = EQUALIZER_DELTA/V29_EQUALIZER_LEN;
244 #endif
245
246 s->eq_put_step = RX_PULSESHAPER_COEFF_SETS*10/(3*2) - 1;
247 s->eq_step = 0;
248 }
249 /*- End of function --------------------------------------------------------*/
250
251 #if defined(SPANDSP_USE_FIXED_POINT)
252 static __inline__ complexi16_t complex_mul_q4_12(const complexi16_t *x, const complexi16_t *y)
253 {
254 complexi16_t z;
255
256 z.re = ((int32_t) x->re*(int32_t) y->re - (int32_t) x->im*(int32_t) y->im) >> FP_SHIFT_FACTOR;
257 z.im = ((int32_t) x->re*(int32_t) y->im + (int32_t) x->im*(int32_t) y->re) >> FP_SHIFT_FACTOR;
258 return z;
259 }
260 /*- End of function --------------------------------------------------------*/
261 #endif
262
263 #if defined(SPANDSP_USE_FIXED_POINT)
264 static __inline__ complexi16_t equalizer_get(v29_rx_state_t *s)
265 #else
266 static __inline__ complexf_t equalizer_get(v29_rx_state_t *s)
267 #endif
268 {
269 #if defined(SPANDSP_USE_FIXED_POINT)
270 complexi32_t zz;
271 complexi16_t z;
272
273 /* Get the next equalized value. */
274 zz = cvec_circular_dot_prodi16(s->eq_buf, s->eq_coeff, V29_EQUALIZER_LEN, s->eq_step);
275 z.re = zz.re >> FP_SHIFT_FACTOR;
276 z.im = zz.im >> FP_SHIFT_FACTOR;
277 return z;
278 #else
279 /* Get the next equalized value. */
280 return cvec_circular_dot_prodf(s->eq_buf, s->eq_coeff, V29_EQUALIZER_LEN, s->eq_step);
281 #endif
282 }
283 /*- End of function --------------------------------------------------------*/
284
285 #if defined(SPANDSP_USE_FIXED_POINT)
286 static void tune_equalizer(v29_rx_state_t *s, const complexi16_t *z, const complexi16_t *target)
287 {
288 complexi16_t err;
289
290 /* Find the x and y mismatch from the exact constellation position. */
291 err.re = target->re*FP_FACTOR - z->re;
292 err.im = target->im*FP_FACTOR - z->im;
293 err.re = ((int32_t) err.re*(int32_t) s->eq_delta) >> 15;
294 err.im = ((int32_t) err.im*(int32_t) s->eq_delta) >> 15;
295 cvec_circular_lmsi16(s->eq_buf, s->eq_coeff, V29_EQUALIZER_LEN, s->eq_step, &err);
296 }
297 #else
298 static void tune_equalizer(v29_rx_state_t *s, const complexf_t *z, const complexf_t *target)
299 {
300 complexf_t err;
301
302 /* Find the x and y mismatch from the exact constellation position. */
303 err = complex_subf(target, z);
304 err.re *= s->eq_delta;
305 err.im *= s->eq_delta;
306 cvec_circular_lmsf(s->eq_buf, s->eq_coeff, V29_EQUALIZER_LEN, s->eq_step, &err);
307 }
308 #endif
309 /*- End of function --------------------------------------------------------*/
310
311 static int scrambled_training_bit(v29_rx_state_t *s)
312 {
313 int bit;
314
315 /* Segment 3 of the training sequence - the scrambled CDCD part. */
316 /* Apply the 1 + x^-6 + x^-7 scrambler */
317 bit = s->training_scramble_reg & 1;
318 s->training_scramble_reg >>= 1;
319 if (bit ^ (s->training_scramble_reg & 1))
320 s->training_scramble_reg |= 0x40;
321 return bit;
322 }
323 /*- End of function --------------------------------------------------------*/
324
325 #if defined(SPANDSP_USE_FIXED_POINT)
326 static __inline__ int find_quadrant(const complexi16_t *z)
327 #else
328 static __inline__ int find_quadrant(const complexf_t *z)
329 #endif
330 {
331 int b1;
332 int b2;
333
334 /* Split the space along the two diagonals. */
335 b1 = (z->im > z->re);
336 b2 = (z->im < -z->re);
337 return (b2 << 1) | (b1 ^ b2);
338 }
339 /*- End of function --------------------------------------------------------*/
340
341 #if defined(SPANDSP_USE_FIXED_POINT)
342 static __inline__ void track_carrier(v29_rx_state_t *s, const complexi16_t *z, const complexi16_t *target)
343 #else
344 static __inline__ void track_carrier(v29_rx_state_t *s, const complexf_t *z, const complexf_t *target)
345 #endif
346 {
347 #if defined(SPANDSP_USE_FIXED_POINT)
348 int32_t error;
349 #else
350 float error;
351 #endif
352
353 /* The initial coarse carrier frequency and phase estimation should have
354 got us in the right ballpark. Now we need to fine tune fairly quickly,
355 to get the receovered carrier more precisely on target. Then we need to
356 fine tune in a more damped way to keep us on target. The goal is to have
357 things running really well by the time the training is complete.
358 We assume the frequency of the oscillators at the two ends drift only
359 very slowly. The PSTN has rather limited doppler problems. :-) Any
360 remaining FDM in the network should also drift slowly. */
361 /* For small errors the imaginary part of the difference between the actual and the target
362 positions is proportional to the phase error, for any particular target. However, the
363 different amplitudes of the various target positions scale things. This isn't all bad,
364 as the angular error for the larger amplitude constellation points is probably
365 a more reliable indicator, and we are weighting it as such. */
366 error = z->im*target->re - z->re*target->im;
367
368 /* Use a proportional-integral approach to tracking the carrier. The PI
369 parameters are coarser at first, until we get precisely on target. Then,
370 the filter will be damped more to keep us on target. */
371 #if defined(SPANDSP_USE_FIXED_POINT)
372 s->carrier_phase_rate += ((s->carrier_track_i*error) >> FP_SHIFT_FACTOR);
373 s->carrier_phase += ((s->carrier_track_p*error) >> FP_SHIFT_FACTOR);
374 #else
375 s->carrier_phase_rate += (int32_t) (s->carrier_track_i*error);
376 s->carrier_phase += (int32_t) (s->carrier_track_p*error);
377 //span_log(&s->logging, SPAN_LOG_FLOW, "Im = %15.5f f = %15.5f\n", error, dds_frequencyf(s->carrier_phase_rate));
378 #endif
379 }
380 /*- End of function --------------------------------------------------------*/
381
382 static __inline__ void put_bit(v29_rx_state_t *s, int bit)
383 {
384 int out_bit;
385
386 bit &= 1;
387
388 /* Descramble the bit */
389 out_bit = (bit ^ (s->scramble_reg >> 17) ^ (s->scramble_reg >> 22)) & 1;
390 s->scramble_reg = (s->scramble_reg << 1) | bit;
391
392 /* We need to strip the last part of the training - the test period of all 1s -
393 before we let data go to the application. */
394 if (s->training_stage == TRAINING_STAGE_NORMAL_OPERATION)
395 {
396 s->put_bit(s->put_bit_user_data, out_bit);
397 }
398 else
399 {
400 /* The bits during the final stage of training should be all ones. However,
401 buggy modems mean you cannot rely on this. Therefore we don't bother
402 testing for ones, but just rely on a constellation mismatch measurement. */
403 }
404 }
405 /*- End of function --------------------------------------------------------*/
406
407 #if defined(SPANDSP_USE_FIXED_POINT)
408 static void decode_baud(v29_rx_state_t *s, complexi16_t *z)
409 #else
410 static void decode_baud(v29_rx_state_t *s, complexf_t *z)
411 #endif
412 {
413 static const uint8_t phase_steps_9600[8] =
414 {
415 4, 0, 2, 6, 7, 3, 1, 5
416 };
417 static const uint8_t phase_steps_4800[4] =
418 {
419 0, 2, 3, 1
420 };
421 int nearest;
422 int raw_bits;
423 int i;
424 int re;
425 int im;
426
427 if (s->bit_rate == 4800)
428 {
429 /* 4800 is a special case. */
430 nearest = find_quadrant(z) << 1;
431 raw_bits = phase_steps_4800[((nearest - s->constellation_state) >> 1) & 3];
432 put_bit(s, raw_bits);
433 put_bit(s, raw_bits >> 1);
434 }
435 else
436 {
437 /* 9600 and 7200 are quite similar. */
438 #if defined(SPANDSP_USE_FIXED_POINT)
439 re = (z->re + 5*FP_FACTOR) >> (FP_SHIFT_FACTOR - 1);
440 im = (z->im + 5*FP_FACTOR) >> (FP_SHIFT_FACTOR - 1);
441 #else
442 re = (int) ((z->re + 5.0f)*2.0f);
443 im = (int) ((z->im + 5.0f)*2.0f);
444 #endif
445 if (re > 19)
446 re = 19;
447 else if (re < 0)
448 re = 0;
449 if (im > 19)
450 im = 19;
451 else if (im < 0)
452 im = 0;
453 nearest = space_map_9600[re][im];
454 if (s->bit_rate == 9600)
455 {
456 /* Send out the top (amplitude) bit. */
457 put_bit(s, nearest >> 3);
458 }
459 else
460 {
461 /* We can reuse the space map for 9600, but drop the top bit. */
462 nearest &= 7;
463 }
464 raw_bits = phase_steps_9600[(nearest - s->constellation_state) & 7];
465 for (i = 0; i < 3; i++)
466 {
467 put_bit(s, raw_bits);
468 raw_bits >>= 1;
469 }
470 }
471
472 track_carrier(s, z, &v29_9600_constellation[nearest]);
473 if (--s->eq_skip <= 0)
474 {
475 /* Once we are in the data the equalization should not need updating.
476 However, the line characteristics may slowly drift. We, therefore,
477 tune up on the occassional sample, keeping the compute down. */
478 s->eq_skip = 10;
479 tune_equalizer(s, z, &v29_9600_constellation[nearest]);
480 }
481 s->constellation_state = nearest;
482 }
483 /*- End of function --------------------------------------------------------*/
484
485 static __inline__ void symbol_sync(v29_rx_state_t *s)
486 {
487 int i;
488 #if defined(SPANDSP_USE_FIXED_POINT)
489 int32_t v;
490 int32_t p;
491 #else
492 float v;
493 float p;
494 #endif
495
496 /* This routine adapts the position of the half baud samples entering the equalizer. */
497
498 /* This symbol sync scheme is based on the technique first described by Dominique Godard in
499 Passband Timing Recovery in an All-Digital Modem Receiver
500 IEEE TRANSACTIONS ON COMMUNICATIONS, VOL. COM-26, NO. 5, MAY 1978 */
501
502 /* This is slightly rearranged for figure 3b of the Godard paper, as this saves a couple of
503 maths operations */
504 #if defined(SPANDSP_USE_FIXED_POINT)
505 /* TODO: The scalings used here need more thorough evaluation, to see if overflows are possible. */
506 /* Cross correlate */
507 v = (((s->symbol_sync_low[1] >> 5)*(s->symbol_sync_high[0] >> 4)) >> 15)*SYNC_LOW_BAND_EDGE_COEFF_2
508 - (((s->symbol_sync_low[0] >> 5)*(s->symbol_sync_high[1] >> 4)) >> 15)*SYNC_HIGH_BAND_EDGE_COEFF_2
509 + (((s->symbol_sync_low[1] >> 5)*(s->symbol_sync_high[1] >> 4)) >> 15)*SYNC_MIXED_EDGES_COEFF_3;
510 /* Filter away any DC component */
511 p = v - s->symbol_sync_dc_filter[1];
512 s->symbol_sync_dc_filter[1] = s->symbol_sync_dc_filter[0];
513 s->symbol_sync_dc_filter[0] = v;
514 /* A little integration will now filter away much of the HF noise */
515 s->baud_phase -= p;
516 if (abs(s->baud_phase) > 30*FP_FACTOR)
517 {
518 if (s->baud_phase > 0)
519 i = (s->baud_phase > 1000*FP_FACTOR) ? 5 : 1;
520 else
521 i = (s->baud_phase < -1000*FP_FACTOR) ? -5 : -1;
522 //printf("v = %10.5f %5d - %f %f %d %d\n", v, i, p, s->baud_phase, s->total_baud_timing_correction);
523 s->eq_put_step += i;
524 s->total_baud_timing_correction += i;
525 }
526 #else
527 /* Cross correlate */
528 v = s->symbol_sync_low[1]*s->symbol_sync_high[0]*SYNC_LOW_BAND_EDGE_COEFF_2
529 - s->symbol_sync_low[0]*s->symbol_sync_high[1]*SYNC_HIGH_BAND_EDGE_COEFF_2
530 + s->symbol_sync_low[1]*s->symbol_sync_high[1]*SYNC_MIXED_EDGES_COEFF_3;
531 /* Filter away any DC component */
532 p = v - s->symbol_sync_dc_filter[1];
533 s->symbol_sync_dc_filter[1] = s->symbol_sync_dc_filter[0];
534 s->symbol_sync_dc_filter[0] = v;
535 /* A little integration will now filter away much of the HF noise */
536 s->baud_phase -= p;
537 if (fabsf(s->baud_phase) > 30.0f)
538 {
539 if (s->baud_phase > 0.0f)
540 i = (s->baud_phase > 1000.0f) ? 5 : 1;
541 else
542 i = (s->baud_phase < -1000.0f) ? -5 : -1;
543 //printf("v = %10.5f %5d - %f %f %d %d\n", v, i, p, s->baud_phase, s->total_baud_timing_correction);
544 s->eq_put_step += i;
545 s->total_baud_timing_correction += i;
546 }
547 #endif
548 }
549 /*- End of function --------------------------------------------------------*/
550
551 #if defined(SPANDSP_USE_FIXED_POINT)
552 static void process_half_baud(v29_rx_state_t *s, complexi16_t *sample)
553 #else
554 static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
555 #endif
556 {
557 static const int cdcd_pos[6] =
558 {
559 0, 11,
560 0, 3,
561 0, 2
562 };
563 complexf_t zz;
564 #if defined(SPANDSP_USE_FIXED_POINT)
565 complexf_t z1;
566 complexi16_t z;
567 const complexi16_t *target;
568 static const complexi16_t zero = {0, 0};
569 #else
570 complexf_t z;
571 const complexf_t *target;
572 static const complexf_t zero = {0.0f, 0.0f};
573 #endif
574 float p;
575 int bit;
576 int i;
577 int j;
578 int32_t angle;
579 int32_t ang;
580
581 /* This routine processes every half a baud, as we put things into the equalizer at the T/2 rate. */
582
583 /* Add a sample to the equalizer's circular buffer, but don't calculate anything at this time. */
584 s->eq_buf[s->eq_step] = *sample;
585 if (++s->eq_step >= V29_EQUALIZER_LEN)
586 s->eq_step = 0;
587
588 /* On alternate insertions we have a whole baud, and must process it. */
589 if ((s->baud_half ^= 1))
590 return;
591
592 /* Symbol timing synchronisation */
593 symbol_sync(s);
594
595 z = equalizer_get(s);
596
597 switch (s->training_stage)
598 {
599 case TRAINING_STAGE_NORMAL_OPERATION:
600 /* Normal operation. */
601 decode_baud(s, &z);
602 target = &v29_9600_constellation[s->constellation_state];
603 break;
604 case TRAINING_STAGE_SYMBOL_ACQUISITION:
605 /* Allow time for symbol synchronisation to settle the symbol timing. */
606 target = &zero;
607 if (++s->training_count >= 60)
608 {
609 /* Record the current phase angle */
610 s->training_stage = TRAINING_STAGE_LOG_PHASE;
611 s->angles[0] =
612 s->start_angles[0] = arctan2(z.im, z.re);
613 #if defined(SPANDSP_USE_FIXED_POINT)
614 if (s->agc_scaling_save == 0)
615 s->agc_scaling_save = s->agc_scaling;
616 #else
617 if (s->agc_scaling_save == 0.0f)
618 s->agc_scaling_save = s->agc_scaling;
619 #endif
620 }
621 break;
622 case TRAINING_STAGE_LOG_PHASE:
623 /* Record the current alternate phase angle */
624 target = &zero;
625 s->angles[1] =
626 s->start_angles[1] = arctan2(z.im, z.re);
627 s->training_count = 1;
628 s->training_stage = TRAINING_STAGE_WAIT_FOR_CDCD;
629 break;
630 case TRAINING_STAGE_WAIT_FOR_CDCD:
631 target = &zero;
632 angle = arctan2(z.im, z.re);
633 /* Look for the initial ABAB sequence to display a phase reversal, which will
634 signal the start of the scrambled CDCD segment */
635 ang = angle - s->angles[(s->training_count - 1) & 0xF];
636 s->angles[(s->training_count + 1) & 0xF] = angle;
637 if ((ang > 0x20000000 || ang < -0x20000000) && s->training_count >= 13)
638 {
639 /* We seem to have a phase reversal */
640 /* Slam the carrier frequency into line, based on the total phase drift over the last
641 section. Use the shift from the odd bits and the shift from the even bits to get
642 better jitter suppression. We need to scale here, or at the maximum specified
643 frequency deviation we could overflow, and get a silly answer. */
644 /* Step back a few symbols so we don't get ISI distorting things. */
645 i = (s->training_count - 8) & ~1;
646 /* Avoid the possibility of a divide by zero */
647 if (i)
648 {
649 j = i & 0xF;
650 ang = (s->angles[j] - s->start_angles[0])/i
651 + (s->angles[j | 0x1] - s->start_angles[1])/i;
652 s->carrier_phase_rate += 3*(ang/20);
653 }
654 span_log(&s->logging, SPAN_LOG_FLOW, "Coarse carrier frequency %7.2f\n", dds_frequencyf(s->carrier_phase_rate));
655 /* Check if the carrier frequency is plausible */
656 if (s->carrier_phase_rate < dds_phase_ratef(CARRIER_NOMINAL_FREQ - 20.0f)
657 ||
658 s->carrier_phase_rate > dds_phase_ratef(CARRIER_NOMINAL_FREQ + 20.0f))
659 {
660 span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n");
661 /* Park this modem */
662 #if defined(SPANDSP_USE_FIXED_POINT)
663 s->agc_scaling_save = 0;
664 #else
665 s->agc_scaling_save = 0.0f;
666 #endif
667 s->training_stage = TRAINING_STAGE_PARKED;
668 report_status_change(s, SIG_STATUS_TRAINING_FAILED);
669 break;
670 }
671 /* Make a step shift in the phase, to pull it into line. We need to rotate the equalizer
672 buffer, as well as the carrier phase, for this to play out nicely. */
673 p = angle*2.0f*3.14159f/(65536.0f*65536.0f);
674 #if defined(SPANDSP_USE_FIXED_POINT)
675 zz = complex_setf(cosf(p), -sinf(p));
676 for (i = 0; i < V29_EQUALIZER_LEN; i++)
677 {
678 z1 = complex_setf(s->eq_buf[i].re, s->eq_buf[i].im);
679 z1 = complex_mulf(&z1, &zz);
680 s->eq_buf[i].re = z1.re;
681 s->eq_buf[i].im = z1.im;
682 }
683 #else
684 zz = complex_setf(cosf(p), -sinf(p));
685 for (i = 0; i < V29_EQUALIZER_LEN; i++)
686 s->eq_buf[i] = complex_mulf(&s->eq_buf[i], &zz);
687 #endif
688 s->carrier_phase += angle;
689 /* We have just seen the first bit of the scrambled sequence, so skip it. */
690 bit = scrambled_training_bit(s);
691 s->constellation_state = cdcd_pos[s->training_cd + bit];
692 target = &v29_9600_constellation[s->constellation_state];
693 s->training_count = 1;
694 s->training_stage = TRAINING_STAGE_TRAIN_ON_CDCD;
695 report_status_change(s, SIG_STATUS_TRAINING_IN_PROGRESS);
696 break;
697 }
698 if (++s->training_count > V29_TRAINING_SEG_2_LEN)
699 {
700 /* This is bogus. There are not this many bauds in this section
701 of a real training sequence. */
702 span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n");
703 /* Park this modem */
704 #if defined(SPANDSP_USE_FIXED_POINT)
705 s->agc_scaling_save = 0;
706 #else
707 s->agc_scaling_save = 0.0f;
708 #endif
709 s->training_stage = TRAINING_STAGE_PARKED;
710 report_status_change(s, SIG_STATUS_TRAINING_FAILED);
711 }
712 break;
713 case TRAINING_STAGE_TRAIN_ON_CDCD:
714 /* Train on the scrambled CDCD section. */
715 bit = scrambled_training_bit(s);
716 //span_log(&s->logging, SPAN_LOG_FLOW, "%5d %15.5f, %15.5f %15.5f, %15.5f\n", s->training_count, z.re, z.im, v29_9600_constellation[cdcd_pos[s->training_cd + bit]].re, v29_9600_constellation[cdcd_pos[s->training_cd + bit]].im);
717 s->constellation_state = cdcd_pos[s->training_cd + bit];
718 target = &v29_9600_constellation[s->constellation_state];
719 track_carrier(s, &z, target);
720 tune_equalizer(s, &z, target);
721 if (++s->training_count >= V29_TRAINING_SEG_3_LEN - 48)
722 {
723 s->training_stage = TRAINING_STAGE_TRAIN_ON_CDCD_AND_TEST;
724 s->training_error = 0.0f;
725 #if defined(SPANDSP_USE_FIXED_POINT)
726 s->carrier_track_i = 200;
727 s->carrier_track_p = 1000000;
728 #else
729 s->carrier_track_i = 200.0f;
730 s->carrier_track_p = 1000000.0f;
731 #endif
732 }
733 break;
734 case TRAINING_STAGE_TRAIN_ON_CDCD_AND_TEST:
735 /* Continue training on the scrambled CDCD section, but measure the quality of training too. */
736 bit = scrambled_training_bit(s);
737 //span_log(&s->logging, SPAN_LOG_FLOW, "%5d %15.5f, %15.5f %15.5f, %15.5f\n", s->training_count, z.re, z.im, v29_9600_constellation[cdcd_pos[s->training_cd + bit]].re, v29_9600_constellation[cdcd_pos[s->training_cd + bit]].im);
738 s->constellation_state = cdcd_pos[s->training_cd + bit];
739 target = &v29_9600_constellation[s->constellation_state];
740 track_carrier(s, &z, target);
741 tune_equalizer(s, &z, target);
742 /* Measure the training error */
743 #if defined(SPANDSP_USE_FIXED_POINT)
744 z1.re = z.re/(float) FP_FACTOR;
745 z1.im = z.im/(float) FP_FACTOR;
746 zz.re = target->re;
747 zz.im = target->im;
748 zz = complex_subf(&z1, &zz);
749 s->training_error += powerf(&zz);
750 #else
751 zz = complex_subf(&z, target);
752 s->training_error += powerf(&zz);
753 #endif
754 if (++s->training_count >= V29_TRAINING_SEG_3_LEN)
755 {
756 span_log(&s->logging, SPAN_LOG_FLOW, "Constellation mismatch %f\n", s->training_error);
757 if (s->training_error < 48.0f*2.0f)
758 {
759 s->training_count = 0;
760 s->training_error = 0.0f;
761 s->constellation_state = 0;
762 s->training_stage = TRAINING_STAGE_TEST_ONES;
763 }
764 else
765 {
766 span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (convergence failed)\n");
767 /* Park this modem */
768 #if defined(SPANDSP_USE_FIXED_POINT)
769 s->agc_scaling_save = 0;
770 #else
771 s->agc_scaling_save = 0.0f;
772 #endif
773 s->training_stage = TRAINING_STAGE_PARKED;
774 report_status_change(s, SIG_STATUS_TRAINING_FAILED);
775 }
776 }
777 break;
778 case TRAINING_STAGE_TEST_ONES:
779 /* We are in the test phase, where we check that we can receive reliably.
780 We should get a run of 1's, 48 symbols (192 bits at 9600bps) long. */
781 //span_log(&s->logging, SPAN_LOG_FLOW, "%5d %15.5f, %15.5f\n", s->training_count, z.re, z.im);
782 decode_baud(s, &z);
783 target = &v29_9600_constellation[s->constellation_state];
784 /* Measure the training error */
785 #if defined(SPANDSP_USE_FIXED_POINT)
786 z1.re = z.re/(float) FP_FACTOR;
787 z1.im = z.im/(float) FP_FACTOR;
788 zz.re = target->re;
789 zz.im = target->im;
790 zz = complex_subf(&z1, &zz);
791 s->training_error += powerf(&zz);
792 #else
793 zz = complex_subf(&z, target);
794 s->training_error += powerf(&zz);
795 #endif
796 if (++s->training_count >= V29_TRAINING_SEG_4_LEN)
797 {
798 if (s->training_error < 48.0f)
799 {
800 /* We are up and running */
801 span_log(&s->logging, SPAN_LOG_FLOW, "Training succeeded at %dbps (constellation mismatch %f)\n", s->bit_rate, s->training_error);
802 report_status_change(s, SIG_STATUS_TRAINING_SUCCEEDED);
803 /* Apply some lag to the carrier off condition, to ensure the last few bits get pushed through
804 the processing. */
805 s->signal_present = 60;
806 s->training_stage = TRAINING_STAGE_NORMAL_OPERATION;
807 equalizer_save(s);
808 s->carrier_phase_rate_save = s->carrier_phase_rate;
809 s->agc_scaling_save = s->agc_scaling;
810 }
811 else
812 {
813 /* Training has failed */
814 span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (constellation mismatch %f)\n", s->training_error);
815 /* Park this modem */
816 #if defined(SPANDSP_USE_FIXED_POINT)
817 s->agc_scaling_save = 0;
818 #else
819 s->agc_scaling_save = 0.0f;
820 #endif
821 s->training_stage = TRAINING_STAGE_PARKED;
822 report_status_change(s, SIG_STATUS_TRAINING_FAILED);
823 }
824 }
825 break;
826 case TRAINING_STAGE_PARKED:
827 default:
828 /* We failed to train! */
829 /* Park here until the carrier drops. */
830 target = &zero;
831 break;
832 }
833 if (s->qam_report)
834 {
835 #if defined(SPANDSP_USE_FIXED_POINT)
836 z1.re = z.re/(float) FP_FACTOR;
837 z1.im = z.im/(float) FP_FACTOR;
838 zz.re = target->re;
839 zz.im = target->im;
840 s->qam_report(s->qam_user_data, &z1, &zz, s->constellation_state);
841 #else
842 s->qam_report(s->qam_user_data, &z, target, s->constellation_state);
843 #endif
844 }
845 }
846 /*- End of function --------------------------------------------------------*/
847
848 static __inline__ int signal_detect(v29_rx_state_t *s, int16_t amp)
849 {
850 int16_t diff;
851 int16_t x;
852 int32_t power;
853
854 /* There should be no DC in the signal, but sometimes there is.
855 We need to measure the power with the DC blocked, but not using
856 a slow to respond DC blocker. Use the most elementary HPF. */
857 x = amp >> 1;
858 /* There could be overflow here, but it isn't a problem in practice */
859 diff = x - s->last_sample;
860 s->last_sample = x;
861 power = power_meter_update(&(s->power), diff);
862 #if defined(IAXMODEM_STUFF)
863 /* Quick power drop fudge */
864 diff = abs(diff);
865 if (10*diff < s->high_sample)
866 {
867 if (++s->low_samples > 120)
868 {
869 power_meter_init(&(s->power), 4);
870 s->high_sample = 0;
871 s->low_samples = 0;
872 }
873 }
874 else
875 {
876 s->low_samples = 0;
877 if (diff > s->high_sample)
878 s->high_sample = diff;
879 }
880 #endif
881 if (s->signal_present > 0)
882 {
883 /* Look for power below turn-off threshold to turn the carrier off */
884 #if defined(IAXMODEM_STUFF)
885 if (s->carrier_drop_pending || power < s->carrier_off_power)
886 #else
887 if (power < s->carrier_off_power)
888 #endif
889 {
890 if (--s->signal_present <= 0)
891 {
892 /* Count down a short delay, to ensure we push the last
893 few bits through the filters before stopping. */
894 v29_rx_restart(s, s->bit_rate, FALSE);
895 report_status_change(s, SIG_STATUS_CARRIER_DOWN);
896 return 0;
897 }
898 #if defined(IAXMODEM_STUFF)
899 /* Carrier has dropped, but the put_bit is
900 pending the signal_present delay. */
901 s->carrier_drop_pending = TRUE;
902 #endif
903 }
904 }
905 else
906 {
907 /* Look for power exceeding turn-on threshold to turn the carrier on */
908 if (power < s->carrier_on_power)
909 return 0;
910 s->signal_present = 1;
911 #if defined(IAXMODEM_STUFF)
912 s->carrier_drop_pending = FALSE;
913 #endif
914 report_status_change(s, SIG_STATUS_CARRIER_UP);
915 }
916 return power;
917 }
918 /*- End of function --------------------------------------------------------*/
919
920 SPAN_DECLARE_NONSTD(int) v29_rx(v29_rx_state_t *s, const int16_t amp[], int len)
921 {
922 int i;
923 int step;
924 #if defined(SPANDSP_USE_FIXED_POINT)
925 complexi16_t z;
926 complexi16_t zz;
927 complexi16_t sample;
928 int32_t v;
929 #else
930 complexf_t z;
931 complexf_t zz;
932 complexf_t sample;
933 float v;
934 #endif
935 int32_t power;
936
937 for (i = 0; i < len; i++)
938 {
939 s->rrc_filter[s->rrc_filter_step] = amp[i];
940 if (++s->rrc_filter_step >= V29_RX_FILTER_STEPS)
941 s->rrc_filter_step = 0;
942
943 if ((power = signal_detect(s, amp[i])) == 0)
944 continue;
945 if (s->training_stage == TRAINING_STAGE_PARKED)
946 continue;
947 /* Only spend effort processing this data if the modem is not
948 parked, after training failure. */
949 s->eq_put_step -= RX_PULSESHAPER_COEFF_SETS;
950 step = -s->eq_put_step;
951 if (step > RX_PULSESHAPER_COEFF_SETS - 1)
952 step = RX_PULSESHAPER_COEFF_SETS - 1;
953 if (step < 0)
954 step += RX_PULSESHAPER_COEFF_SETS;
955 #if defined(SPANDSP_USE_FIXED_POINT)
956 v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_re[step], V29_RX_FILTER_STEPS, s->rrc_filter_step);
957 sample.re = (v*s->agc_scaling) >> 15;
958 #else
959 v = vec_circular_dot_prodf(s->rrc_filter, rx_pulseshaper_re[step], V29_RX_FILTER_STEPS, s->rrc_filter_step);
960 sample.re = v*s->agc_scaling;
961 #endif
962
963 /* Symbol timing synchronisation band edge filters */
964 #if defined(SPANDSP_USE_FIXED_POINT)
965 /* Low Nyquist band edge filter */
966 v = ((s->symbol_sync_low[0]*SYNC_LOW_BAND_EDGE_COEFF_0) >> FP_SHIFT_FACTOR) + ((s->symbol_sync_low[1]*SYNC_LOW_BAND_EDGE_COEFF_1) >> FP_SHIFT_FACTOR) + sample.re;
967 s->symbol_sync_low[1] = s->symbol_sync_low[0];
968 s->symbol_sync_low[0] = v;
969 /* High Nyquist band edge filter */
970 v = ((s->symbol_sync_high[0]*SYNC_HIGH_BAND_EDGE_COEFF_0) >> FP_SHIFT_FACTOR) + ((s->symbol_sync_high[1]*SYNC_HIGH_BAND_EDGE_COEFF_1) >> FP_SHIFT_FACTOR) + sample.re;
971 s->symbol_sync_high[1] = s->symbol_sync_high[0];
972 s->symbol_sync_high[0] = v;
973 #else
974 /* Low Nyquist band edge filter */
975 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;
976 s->symbol_sync_low[1] = s->symbol_sync_low[0];
977 s->symbol_sync_low[0] = v;
978 /* High Nyquist band edge filter */
979 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;
980 s->symbol_sync_high[1] = s->symbol_sync_high[0];
981 s->symbol_sync_high[0] = v;
982 #endif
983 /* Put things into the equalization buffer at T/2 rate. The symbol synchronisation
984 will fiddle the step to align this with the symbols. */
985 if (s->eq_put_step <= 0)
986 {
987 /* Only AGC until we have locked down the setting. */
988 #if defined(SPANDSP_USE_FIXED_POINT)
989 if (s->agc_scaling_save == 0)
990 s->agc_scaling = (float) FP_FACTOR*32768.0f*(1.0f/RX_PULSESHAPER_GAIN)*5.0f*0.25f/sqrtf(power);
991 #else
992 if (s->agc_scaling_save == 0.0f)
993 s->agc_scaling = (1.0f/RX_PULSESHAPER_GAIN)*5.0f*0.25f/sqrtf(power);
994 #endif
995 /* Pulse shape while still at the carrier frequency, using a quadrature
996 pair of filters. This results in a properly bandpass filtered complex
997 signal, which can be brought directly to baseband by complex mixing.
998 No further filtering, to remove mixer harmonics, is needed. */
999 step = -s->eq_put_step;
1000 if (step > RX_PULSESHAPER_COEFF_SETS - 1)
1001 step = RX_PULSESHAPER_COEFF_SETS - 1;
1002 s->eq_put_step += RX_PULSESHAPER_COEFF_SETS*10/(3*2);
1003 #if defined(SPANDSP_USE_FIXED_POINT)
1004 v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_im[step], V29_RX_FILTER_STEPS, s->rrc_filter_step);
1005 sample.im = (v*s->agc_scaling) >> 15;
1006 z = dds_lookup_complexi16(s->carrier_phase);
1007 zz.re = ((int32_t) sample.re*(int32_t) z.re - (int32_t) sample.im*(int32_t) z.im) >> 15;
1008 zz.im = ((int32_t) -sample.re*(int32_t) z.im - (int32_t) sample.im*(int32_t) z.re) >> 15;
1009 #else
1010 v = vec_circular_dot_prodf(s->rrc_filter, rx_pulseshaper_im[step], V29_RX_FILTER_STEPS, s->rrc_filter_step);
1011 sample.im = v*s->agc_scaling;
1012 z = dds_lookup_complexf(s->carrier_phase);
1013 zz.re = sample.re*z.re - sample.im*z.im;
1014 zz.im = -sample.re*z.im - sample.im*z.re;
1015 #endif
1016 process_half_baud(s, &zz);
1017 }
1018 #if defined(SPANDSP_USE_FIXED_POINT)
1019 dds_advance(&s->carrier_phase, s->carrier_phase_rate);
1020 #else
1021 dds_advancef(&s->carrier_phase, s->carrier_phase_rate);
1022 #endif
1023 }
1024 return 0;
1025 }
1026 /*- End of function --------------------------------------------------------*/
1027
1028 SPAN_DECLARE(int) v29_rx_fillin(v29_rx_state_t *s, int len)
1029 {
1030 int i;
1031
1032 /* We want to sustain the current state (i.e carrier on<->carrier off), and
1033 try to sustain the carrier phase. We should probably push the filters, as well */
1034 span_log(&s->logging, SPAN_LOG_FLOW, "Fill-in %d samples\n", len);
1035 if (s->signal_present <= 0)
1036 return 0;
1037 if (s->training_stage == TRAINING_STAGE_PARKED)
1038 return 0;
1039 for (i = 0; i < len; i++)
1040 {
1041 #if defined(SPANDSP_USE_FIXED_POINT)
1042 dds_advance(&s->carrier_phase, s->carrier_phase_rate);
1043 #else
1044 dds_advancef(&s->carrier_phase, s->carrier_phase_rate);
1045 #endif
1046 /* Advance the symbol phase the appropriate amount */
1047 s->eq_put_step -= RX_PULSESHAPER_COEFF_SETS;
1048 if (s->eq_put_step <= 0)
1049 s->eq_put_step += RX_PULSESHAPER_COEFF_SETS*10/(3*2);
1050 /* TODO: Should we rotate any buffers */
1051 }
1052 return 0;
1053 }
1054 /*- End of function --------------------------------------------------------*/
1055
1056 SPAN_DECLARE(void) v29_rx_set_put_bit(v29_rx_state_t *s, put_bit_func_t put_bit, void *user_data)
1057 {
1058 s->put_bit = put_bit;
1059 s->put_bit_user_data = user_data;
1060 }
1061 /*- End of function --------------------------------------------------------*/
1062
1063 SPAN_DECLARE(void) v29_rx_set_modem_status_handler(v29_rx_state_t *s, modem_tx_status_func_t handler, void *user_data)
1064 {
1065 s->status_handler = handler;
1066 s->status_user_data = user_data;
1067 }
1068 /*- End of function --------------------------------------------------------*/
1069
1070 SPAN_DECLARE(logging_state_t *) v29_rx_get_logging_state(v29_rx_state_t *s)
1071 {
1072 return &s->logging;
1073 }
1074 /*- End of function --------------------------------------------------------*/
1075
1076 SPAN_DECLARE(int) v29_rx_restart(v29_rx_state_t *s, int bit_rate, int old_train)
1077 {
1078 int i;
1079
1080 switch (bit_rate)
1081 {
1082 case 9600:
1083 s->training_cd = 0;
1084 break;
1085 case 7200:
1086 s->training_cd = 2;
1087 break;
1088 case 4800:
1089 s->training_cd = 4;
1090 break;
1091 default:
1092 return -1;
1093 }
1094 s->bit_rate = bit_rate;
1095
1096 #if defined(SPANDSP_USE_FIXED_POINT)
1097 vec_zeroi16(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
1098 #else
1099 vec_zerof(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
1100 #endif
1101 s->rrc_filter_step = 0;
1102
1103 s->scramble_reg = 0;
1104 s->training_scramble_reg = 0x2A;
1105 s->training_stage = TRAINING_STAGE_SYMBOL_ACQUISITION;
1106 s->training_count = 0;
1107 s->signal_present = 0;
1108 #if defined(IAXMODEM_STUFF)
1109 s->high_sample = 0;
1110 s->low_samples = 0;
1111 s->carrier_drop_pending = FALSE;
1112 #endif
1113 s->old_train = old_train;
1114
1115 s->carrier_phase = 0;
1116
1117 power_meter_init(&(s->power), 4);
1118
1119 s->constellation_state = 0;
1120
1121 if (s->old_train)
1122 {
1123 s->carrier_phase_rate = s->carrier_phase_rate_save;
1124 s->agc_scaling = s->agc_scaling_save;
1125 equalizer_restore(s);
1126 }
1127 else
1128 {
1129 s->carrier_phase_rate = dds_phase_ratef(CARRIER_NOMINAL_FREQ);
1130 #if defined(SPANDSP_USE_FIXED_POINT)
1131 s->agc_scaling_save = 0;
1132 s->agc_scaling = (float) FP_FACTOR*32768.0f*0.0017f/RX_PULSESHAPER_GAIN;
1133 #else
1134 s->agc_scaling_save = 0.0f;
1135 s->agc_scaling = 0.0017f/RX_PULSESHAPER_GAIN;
1136 #endif
1137 equalizer_reset(s);
1138 }
1139 #if defined(SPANDSP_USE_FIXED_POINT)
1140 s->carrier_track_i = 8000;
1141 s->carrier_track_p = 8000000;
1142 #else
1143 s->carrier_track_i = 8000.0f;
1144 s->carrier_track_p = 8000000.0f;
1145 #endif
1146 s->last_sample = 0;
1147 s->eq_skip = 0;
1148
1149 /* Initialise the working data for symbol timing synchronisation */
1150 #if defined(SPANDSP_USE_FIXED_POINT)
1151 for (i = 0; i < 2; i++)
1152 {
1153 s->symbol_sync_low[i] = 0;
1154 s->symbol_sync_high[i] = 0;
1155 s->symbol_sync_dc_filter[i] = 0;
1156 }
1157 s->baud_phase = 0;
1158 #else
1159 for (i = 0; i < 2; i++)
1160 {
1161 s->symbol_sync_low[i] = 0.0f;
1162 s->symbol_sync_high[i] = 0.0f;
1163 s->symbol_sync_dc_filter[i] = 0.0f;
1164 }
1165 s->baud_phase = 0.0f;
1166 #endif
1167 s->baud_half = 0;
1168
1169 s->total_baud_timing_correction = 0;
1170
1171 return 0;
1172 }
1173 /*- End of function --------------------------------------------------------*/
1174
1175 SPAN_DECLARE(v29_rx_state_t *) v29_rx_init(v29_rx_state_t *s, int bit_rate, put_bit_func_t put_bit, void *user_data)
1176 {
1177 switch (bit_rate)
1178 {
1179 case 9600:
1180 case 7200:
1181 case 4800:
1182 break;
1183 default:
1184 return NULL;
1185 }
1186 if (s == NULL)
1187 {
1188 if ((s = (v29_rx_state_t *) malloc(sizeof(*s))) == NULL)
1189 return NULL;
1190 }
1191 memset(s, 0, sizeof(*s));
1192 span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
1193 span_log_set_protocol(&s->logging, "V.29 RX");
1194 s->put_bit = put_bit;
1195 s->put_bit_user_data = user_data;
1196 /* The V.29 spec says the thresholds should be -31dBm and -26dBm, but that makes little
1197 sense. V.17 uses -48dBm and -43dBm, and there seems no good reason to cut off at a
1198 higher level (though at 9600bps and 7200bps, TCM should put V.17 sensitivity several
1199 dB ahead of V.29). */
1200 /* The thresholds should be on at -26dBm0 and off at -31dBm0 */
1201 v29_rx_signal_cutoff(s, -28.5f);
1202
1203 v29_rx_restart(s, bit_rate, FALSE);
1204 return s;
1205 }
1206 /*- End of function --------------------------------------------------------*/
1207
1208 SPAN_DECLARE(int) v29_rx_release(v29_rx_state_t *s)
1209 {
1210 return 0;
1211 }
1212 /*- End of function --------------------------------------------------------*/
1213
1214 SPAN_DECLARE(int) v29_rx_free(v29_rx_state_t *s)
1215 {
1216 free(s);
1217 return 0;
1218 }
1219 /*- End of function --------------------------------------------------------*/
1220
1221 SPAN_DECLARE(void) v29_rx_set_qam_report_handler(v29_rx_state_t *s, qam_report_handler_t handler, void *user_data)
1222 {
1223 s->qam_report = handler;
1224 s->qam_user_data = user_data;
1225 }
1226 /*- End of function --------------------------------------------------------*/
1227 /*- End of file ------------------------------------------------------------*/

Repositories maintained by Peter Meerwald, pmeerw@pmeerw.net.