comparison spandsp-0.0.6pre17/src/v27ter_rx.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 * v27ter_rx.c - ITU V.27ter modem receive part
6 *
7 * Written by Steve Underwood <steveu@coppice.org>
8 *
9 * Copyright (C) 2003 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: v27ter_rx.c,v 1.131 2009/07/08 15:11:09 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 #include "spandsp/v27ter_rx.h"
62
63 #include "spandsp/private/logging.h"
64 #include "spandsp/private/v27ter_rx.h"
65
66 #if defined(SPANDSP_USE_FIXED_POINT)
67 #include "v27ter_rx_4800_fixed_rrc.h"
68 #include "v27ter_rx_2400_fixed_rrc.h"
69 #else
70 #include "v27ter_rx_4800_floating_rrc.h"
71 #include "v27ter_rx_2400_floating_rrc.h"
72 #endif
73
74 /* V.27ter is a DPSK modem, but this code treats it like QAM. It nails down the
75 signal to a static constellation, even though dealing with differences is all
76 that is necessary. */
77
78 /*! The nominal frequency of the carrier, in Hertz */
79 #define CARRIER_NOMINAL_FREQ 1800.0f
80 /*! The nominal baud or symbol rate in 2400bps mode */
81 #define BAUD_RATE_2400 1200
82 /*! The nominal baud or symbol rate in 4800bps mode */
83 #define BAUD_RATE_4800 1600
84 /*! The adaption rate coefficient for the equalizer */
85 #define EQUALIZER_DELTA 0.25f
86
87 #if defined(SPANDSP_USE_FIXED_POINT)
88 #define FP_FACTOR 4096
89 #define FP_SHIFT_FACTOR 12
90 #endif
91
92 /* Segments of the training sequence */
93 /* V.27ter defines a long and a short sequence. FAX doesn't use the
94 short sequence, so it is not implemented here. */
95 /*! The length of training segment 3, in symbols */
96 #define V27TER_TRAINING_SEG_3_LEN 50
97 /*! The length of training segment 5, in symbols */
98 #define V27TER_TRAINING_SEG_5_LEN 1074
99 /*! The length of training segment 6, in symbols */
100 #define V27TER_TRAINING_SEG_6_LEN 8
101
102 /*! The length of the equalizer buffer */
103 #define V27TER_EQUALIZER_LEN (V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN)
104
105 enum
106 {
107 TRAINING_STAGE_NORMAL_OPERATION = 0,
108 TRAINING_STAGE_SYMBOL_ACQUISITION,
109 TRAINING_STAGE_LOG_PHASE,
110 TRAINING_STAGE_WAIT_FOR_HOP,
111 TRAINING_STAGE_TRAIN_ON_ABAB,
112 TRAINING_STAGE_TEST_ONES,
113 TRAINING_STAGE_PARKED
114 };
115
116 #if defined(SPANDSP_USE_FIXED_POINTx)
117 static const complexi16_t v27ter_constellation[8] =
118 {
119 {((int)(FP_FACTOR* 1.414f), ((int)(FP_FACTOR* 0.0f)}, /* 0deg */
120 {((int)(FP_FACTOR* 1.0f), ((int)(FP_FACTOR* 1.0f)}, /* 45deg */
121 {((int)(FP_FACTOR* 0.0f), ((int)(FP_FACTOR* 1.414f)}, /* 90deg */
122 {((int)(FP_FACTOR*-1.0f), ((int)(FP_FACTOR* 1.0f)}, /* 135deg */
123 {((int)(FP_FACTOR*-1.414f), ((int)(FP_FACTOR* 0.0f)}, /* 180deg */
124 {((int)(FP_FACTOR*-1.0f), ((int)(FP_FACTOR*-1.0f)}, /* 225deg */
125 {((int)(FP_FACTOR* 0.0f), ((int)(FP_FACTOR*-1.414f)}, /* 270deg */
126 {((int)(FP_FACTOR* 1.0f), ((int)(FP_FACTOR*-1.0f)} /* 315deg */
127 };
128 #else
129 static const complexf_t v27ter_constellation[8] =
130 {
131 { 1.414f, 0.0f}, /* 0deg */
132 { 1.0f, 1.0f}, /* 45deg */
133 { 0.0f, 1.414f}, /* 90deg */
134 {-1.0f, 1.0f}, /* 135deg */
135 {-1.414f, 0.0f}, /* 180deg */
136 {-1.0f, -1.0f}, /* 225deg */
137 { 0.0f, -1.414f}, /* 270deg */
138 { 1.0f, -1.0f} /* 315deg */
139 };
140 #endif
141
142 SPAN_DECLARE(float) v27ter_rx_carrier_frequency(v27ter_rx_state_t *s)
143 {
144 return dds_frequencyf(s->carrier_phase_rate);
145 }
146 /*- End of function --------------------------------------------------------*/
147
148 SPAN_DECLARE(float) v27ter_rx_symbol_timing_correction(v27ter_rx_state_t *s)
149 {
150 int steps_per_symbol;
151
152 steps_per_symbol = (s->bit_rate == 4800) ? RX_PULSESHAPER_4800_COEFF_SETS*5 : RX_PULSESHAPER_2400_COEFF_SETS*20/3;
153 return (float) s->total_baud_timing_correction/(float) steps_per_symbol;
154 }
155 /*- End of function --------------------------------------------------------*/
156
157 SPAN_DECLARE(float) v27ter_rx_signal_power(v27ter_rx_state_t *s)
158 {
159 return power_meter_current_dbm0(&s->power) + 3.98f;
160 }
161 /*- End of function --------------------------------------------------------*/
162
163 SPAN_DECLARE(void) v27ter_rx_signal_cutoff(v27ter_rx_state_t *s, float cutoff)
164 {
165 /* The 0.4 factor allows for the gain of the DC blocker */
166 s->carrier_on_power = (int32_t) (power_meter_level_dbm0(cutoff + 2.5f)*0.4f);
167 s->carrier_off_power = (int32_t) (power_meter_level_dbm0(cutoff - 2.5f)*0.4f);
168 }
169 /*- End of function --------------------------------------------------------*/
170
171 static void report_status_change(v27ter_rx_state_t *s, int status)
172 {
173 if (s->status_handler)
174 s->status_handler(s->status_user_data, status);
175 else if (s->put_bit)
176 s->put_bit(s->put_bit_user_data, status);
177 }
178 /*- End of function --------------------------------------------------------*/
179
180 #if defined(SPANDSP_USE_FIXED_POINTx)
181 SPAN_DECLARE(int) v27ter_rx_equalizer_state(v27ter_rx_state_t *s, complexi16_t **coeffs)
182 #else
183 SPAN_DECLARE(int) v27ter_rx_equalizer_state(v27ter_rx_state_t *s, complexf_t **coeffs)
184 #endif
185 {
186 *coeffs = s->eq_coeff;
187 return V27TER_EQUALIZER_LEN;
188 }
189 /*- End of function --------------------------------------------------------*/
190
191 static void equalizer_save(v27ter_rx_state_t *s)
192 {
193 #if defined(SPANDSP_USE_FIXED_POINTx)
194 cvec_copyi16(s->eq_coeff_save, s->eq_coeff, V27TER_EQUALIZER_LEN);
195 #else
196 cvec_copyf(s->eq_coeff_save, s->eq_coeff, V27TER_EQUALIZER_LEN);
197 #endif
198 }
199 /*- End of function --------------------------------------------------------*/
200
201 static void equalizer_restore(v27ter_rx_state_t *s)
202 {
203 #if defined(SPANDSP_USE_FIXED_POINTx)
204 cvec_copyi16(s->eq_coeff, s->eq_coeff_save, V27TER_EQUALIZER_LEN);
205 cvec_zeroi16(s->eq_buf, V27TER_EQUALIZER_LEN);
206 s->eq_delta = 32768.0f*EQUALIZER_DELTA/V27TER_EQUALIZER_LEN);
207 #else
208 cvec_copyf(s->eq_coeff, s->eq_coeff_save, V27TER_EQUALIZER_LEN);
209 cvec_zerof(s->eq_buf, V27TER_EQUALIZER_LEN);
210 s->eq_delta = EQUALIZER_DELTA/V27TER_EQUALIZER_LEN;
211 #endif
212
213 s->eq_put_step = (s->bit_rate == 4800) ? RX_PULSESHAPER_4800_COEFF_SETS*5/2 : RX_PULSESHAPER_2400_COEFF_SETS*20/(3*2);
214 s->eq_step = 0;
215 }
216 /*- End of function --------------------------------------------------------*/
217
218 static void equalizer_reset(v27ter_rx_state_t *s)
219 {
220 /* Start with an equalizer based on everything being perfect. */
221 #if defined(SPANDSP_USE_FIXED_POINTx)
222 cvec_zeroi16(s->eq_coeff, V27TER_EQUALIZER_LEN);
223 s->eq_coeff[V27TER_EQUALIZER_PRE_LEN] = complex_seti16(1.414f*FP_FACTOR, 0);
224 cvec_zeroi16(s->eq_buf, V27TER_EQUALIZER_LEN);
225 s->eq_delta = 32768.0f*EQUALIZER_DELTA/V27TER_EQUALIZER_LEN);
226 #else
227 cvec_zerof(s->eq_coeff, V27TER_EQUALIZER_LEN);
228 s->eq_coeff[V27TER_EQUALIZER_PRE_LEN] = complex_setf(1.414f, 0.0f);
229 cvec_zerof(s->eq_buf, V27TER_EQUALIZER_LEN);
230 s->eq_delta = EQUALIZER_DELTA/V27TER_EQUALIZER_LEN;
231 #endif
232
233 s->eq_put_step = (s->bit_rate == 4800) ? RX_PULSESHAPER_4800_COEFF_SETS*5/2 : RX_PULSESHAPER_2400_COEFF_SETS*20/(3*2);
234 s->eq_step = 0;
235 }
236 /*- End of function --------------------------------------------------------*/
237
238 #if defined(SPANDSP_USE_FIXED_POINTx)
239 static __inline__ complexi16_t complex_mul_q4_12(const complexi16_t *x, const complexi16_t *y)
240 {
241 complexi16_t z;
242
243 z.re = ((int32_t) x->re*(int32_t) y->re - (int32_t) x->im*(int32_t) y->im) >> 12;
244 z.im = ((int32_t) x->re*(int32_t) y->im + (int32_t) x->im*(int32_t) y->re) >> 12;
245 return z;
246 }
247 /*- End of function --------------------------------------------------------*/
248 #endif
249
250 #if defined(SPANDSP_USE_FIXED_POINTx)
251 static __inline__ complexi16_t equalizer_get(v27ter_rx_state_t *s)
252 #else
253 static __inline__ complexf_t equalizer_get(v27ter_rx_state_t *s)
254 #endif
255 {
256 #if defined(SPANDSP_USE_FIXED_POINTx)
257 complexi32_t zz;
258 complexi16_t z;
259
260 /* Get the next equalized value. */
261 zz = cvec_circular_dot_prodi16(s->eq_buf, s->eq_coeff, V27TER_EQUALIZER_LEN, s->eq_step);
262 z.re = zz.re >> FP_SHIFT_FACTOR;
263 z.im = zz.im >> FP_SHIFT_FACTOR;
264 return z;
265 #else
266 /* Get the next equalized value. */
267 return cvec_circular_dot_prodf(s->eq_buf, s->eq_coeff, V27TER_EQUALIZER_LEN, s->eq_step);
268 #endif
269 }
270 /*- End of function --------------------------------------------------------*/
271
272 #if defined(SPANDSP_USE_FIXED_POINTx)
273 static void tune_equalizer(v27ter_rx_state_t *s, const complexi16_t *z, const complexi16_t *target)
274 {
275 complexi16_t err;
276
277 /* Find the x and y mismatch from the exact constellation position. */
278 err.re = target->re*FP_FACTOR - z->re;
279 err.im = target->im*FP_FACTOR - z->im;
280 err.re = ((int32_t) err.re*(int32_t) s->eq_delta) >> 15;
281 err.im = ((int32_t) err.im*(int32_t) s->eq_delta) >> 15;
282 cvec_circular_lmsi16(s->eq_buf, s->eq_coeff, V27TER_EQUALIZER_LEN, s->eq_step, &err);
283 }
284 #else
285 static void tune_equalizer(v27ter_rx_state_t *s, const complexf_t *z, const complexf_t *target)
286 {
287 complexf_t err;
288
289 /* Find the x and y mismatch from the exact constellation position. */
290 err = complex_subf(target, z);
291 err.re *= s->eq_delta;
292 err.im *= s->eq_delta;
293 cvec_circular_lmsf(s->eq_buf, s->eq_coeff, V27TER_EQUALIZER_LEN, s->eq_step, &err);
294 }
295 #endif
296 /*- End of function --------------------------------------------------------*/
297
298 #if defined(SPANDSP_USE_FIXED_POINTx)
299 static __inline__ int find_quadrant(const complexi16_t *z)
300 #else
301 static __inline__ int find_quadrant(const complexf_t *z)
302 #endif
303 {
304 int b1;
305 int b2;
306
307 /* Split the space along the two diagonals. */
308 b1 = (z->im > z->re);
309 b2 = (z->im < -z->re);
310 return (b2 << 1) | (b1 ^ b2);
311 }
312 /*- End of function --------------------------------------------------------*/
313
314 #if defined(SPANDSP_USE_FIXED_POINTx)
315 static __inline__ int find_octant(complexi16_t *z)
316 #else
317 static __inline__ int find_octant(complexf_t *z)
318 #endif
319 {
320 float abs_re;
321 float abs_im;
322 int b1;
323 int b2;
324 int bits;
325
326 /* Are we near an axis or a diagonal? */
327 abs_re = fabsf(z->re);
328 abs_im = fabsf(z->im);
329 if (abs_im > abs_re*0.4142136f && abs_im < abs_re*2.4142136f)
330 {
331 /* Split the space along the two axes. */
332 b1 = (z->re < 0.0f);
333 b2 = (z->im < 0.0f);
334 bits = (b2 << 2) | ((b1 ^ b2) << 1) | 1;
335 }
336 else
337 {
338 /* Split the space along the two diagonals. */
339 b1 = (z->im > z->re);
340 b2 = (z->im < -z->re);
341 bits = (b2 << 2) | ((b1 ^ b2) << 1);
342 }
343 return bits;
344 }
345 /*- End of function --------------------------------------------------------*/
346
347 #if defined(SPANDSP_USE_FIXED_POINTx)
348 static __inline__ void track_carrier(v27ter_rx_state_t *s, const complexi16_t *z, const complexi16_t *target)
349 #else
350 static __inline__ void track_carrier(v27ter_rx_state_t *s, const complexf_t *z, const complexf_t *target)
351 #endif
352 {
353 #if defined(SPANDSP_USE_FIXED_POINTx)
354 int32_t error;
355 #else
356 float error;
357 #endif
358
359 /* For small errors the imaginary part of the difference between the actual and the target
360 positions is proportional to the phase error, for any particular target. However, the
361 different amplitudes of the various target positions scale things. */
362 error = z->im*target->re - z->re*target->im;
363
364 #if defined(SPANDSP_USE_FIXED_POINTx)
365 error /= (float) FP_FACTOR;
366 s->carrier_phase_rate += (int32_t) (s->carrier_track_i*error);
367 s->carrier_phase += (int32_t) (s->carrier_track_p*error);
368 #else
369 s->carrier_phase_rate += (int32_t) (s->carrier_track_i*error);
370 s->carrier_phase += (int32_t) (s->carrier_track_p*error);
371 //span_log(&s->logging, SPAN_LOG_FLOW, "Im = %15.5f f = %15.5f\n", error, dds_frequencyf(s->carrier_phase_rate));
372 #endif
373 }
374 /*- End of function --------------------------------------------------------*/
375
376 static __inline__ int descramble(v27ter_rx_state_t *s, int in_bit)
377 {
378 int out_bit;
379
380 out_bit = (in_bit ^ (s->scramble_reg >> 5) ^ (s->scramble_reg >> 6)) & 1;
381 if (s->scrambler_pattern_count >= 33)
382 {
383 out_bit ^= 1;
384 s->scrambler_pattern_count = 0;
385 }
386 else
387 {
388 if (s->training_stage > TRAINING_STAGE_NORMAL_OPERATION && s->training_stage < TRAINING_STAGE_TEST_ONES)
389 {
390 s->scrambler_pattern_count = 0;
391 }
392 else
393 {
394 if ((((s->scramble_reg >> 7) ^ in_bit) & ((s->scramble_reg >> 8) ^ in_bit) & ((s->scramble_reg >> 11) ^ in_bit) & 1))
395 s->scrambler_pattern_count = 0;
396 else
397 s->scrambler_pattern_count++;
398 }
399 }
400 s->scramble_reg <<= 1;
401 if (s->training_stage > TRAINING_STAGE_NORMAL_OPERATION && s->training_stage < TRAINING_STAGE_TEST_ONES)
402 s->scramble_reg |= out_bit;
403 else
404 s->scramble_reg |= in_bit;
405 return out_bit;
406 }
407 /*- End of function --------------------------------------------------------*/
408
409 static __inline__ void put_bit(v27ter_rx_state_t *s, int bit)
410 {
411 int out_bit;
412
413 bit &= 1;
414
415 out_bit = descramble(s, bit);
416
417 /* We need to strip the last part of the training before we let data
418 go to the application. */
419 if (s->training_stage == TRAINING_STAGE_NORMAL_OPERATION)
420 {
421 s->put_bit(s->put_bit_user_data, out_bit);
422 }
423 else
424 {
425 //span_log(&s->logging, SPAN_LOG_FLOW, "Test bit %d\n", out_bit);
426 /* The bits during the final stage of training should be all ones. However,
427 buggy modems mean you cannot rely on this. Therefore we don't bother
428 testing for ones, but just rely on a constellation mismatch measurement. */
429 }
430 }
431 /*- End of function --------------------------------------------------------*/
432
433 #if defined(SPANDSP_USE_FIXED_POINTx)
434 static void decode_baud(v27ter_rx_state_t *s, complexi16_t *z)
435 #else
436 static void decode_baud(v27ter_rx_state_t *s, complexf_t *z)
437 #endif
438 {
439 static const uint8_t phase_steps_4800[8] =
440 {
441 4, 0, 2, 6, 7, 3, 1, 5
442 };
443 static const uint8_t phase_steps_2400[4] =
444 {
445 0, 2, 3, 1
446 };
447 int nearest;
448 int raw_bits;
449
450 if (s->bit_rate == 2400)
451 {
452 nearest = find_quadrant(z);
453 raw_bits = phase_steps_2400[(nearest - s->constellation_state) & 3];
454 put_bit(s, raw_bits);
455 put_bit(s, raw_bits >> 1);
456 s->constellation_state = nearest;
457 nearest <<= 1;
458 }
459 else
460 {
461 nearest = find_octant(z);
462 raw_bits = phase_steps_4800[(nearest - s->constellation_state) & 7];
463 put_bit(s, raw_bits);
464 put_bit(s, raw_bits >> 1);
465 put_bit(s, raw_bits >> 2);
466 s->constellation_state = nearest;
467 }
468 track_carrier(s, z, &v27ter_constellation[nearest]);
469 if (--s->eq_skip <= 0)
470 {
471 /* Once we are in the data the equalization should not need updating.
472 However, the line characteristics may slowly drift. We, therefore,
473 tune up on the occassional sample, keeping the compute down. */
474 s->eq_skip = 100;
475 tune_equalizer(s, z, &v27ter_constellation[nearest]);
476 }
477 }
478 /*- End of function --------------------------------------------------------*/
479
480 static __inline__ void symbol_sync(v27ter_rx_state_t *s)
481 {
482 float p;
483 float q;
484
485 /* This routine adapts the position of the half baud samples entering the equalizer. */
486
487 /* Perform a Gardner test for baud alignment */
488 p = s->eq_buf[(s->eq_step - 3) & V27TER_EQUALIZER_LEN].re
489 - s->eq_buf[(s->eq_step - 1) & V27TER_EQUALIZER_LEN].re;
490 p *= s->eq_buf[(s->eq_step - 2) & V27TER_EQUALIZER_LEN].re;
491
492 q = s->eq_buf[(s->eq_step - 3) & V27TER_EQUALIZER_LEN].im
493 - s->eq_buf[(s->eq_step - 1) & V27TER_EQUALIZER_LEN].im;
494 q *= s->eq_buf[(s->eq_step - 2) & V27TER_EQUALIZER_LEN].im;
495
496 s->gardner_integrate += (p + q > 0.0f) ? s->gardner_step : -s->gardner_step;
497
498 if (abs(s->gardner_integrate) >= 256)
499 {
500 /* This integrate and dump approach avoids rapid changes of the equalizer put step.
501 Rapid changes, without hysteresis, are bad. They degrade the equalizer performance
502 when the true symbol boundary is close to a sample boundary. */
503 //span_log(&s->logging, SPAN_LOG_FLOW, "Hop %d\n", s->gardner_integrate);
504 s->eq_put_step += (s->gardner_integrate/256);
505 s->total_baud_timing_correction += (s->gardner_integrate/256);
506 if (s->qam_report)
507 s->qam_report(s->qam_user_data, NULL, NULL, s->gardner_integrate);
508 s->gardner_integrate = 0;
509 }
510 //span_log(&s->logging, SPAN_LOG_FLOW, "Gardner=%10.5f 0x%X\n", p, s->eq_put_step);
511 }
512 /*- End of function --------------------------------------------------------*/
513
514 #if defined(SPANDSP_USE_FIXED_POINT)
515 static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexi16_t *sample)
516 #else
517 static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexf_t *sample)
518 #endif
519 {
520 static const int abab_pos[2] =
521 {
522 0, 4
523 };
524 complexf_t zz;
525 #if defined(SPANDSP_USE_FIXED_POINTx)
526 complexf_t z1;
527 complexi16_t z;
528 const complexi16_t *target;
529 static const complexi16_t zero = {0, 0};
530 #else
531 complexf_t z;
532 const complexf_t *target;
533 static const complexf_t zero = {0.0f, 0.0f};
534 #endif
535 float p;
536 int i;
537 int j;
538 int32_t angle;
539 int32_t ang;
540 int constellation_state;
541
542 /* Add a sample to the equalizer's circular buffer, but don't calculate anything
543 at this time. */
544 #if defined(SPANDSP_USE_FIXED_POINT)
545 s->eq_buf[s->eq_step].re = sample->re/(float) FP_FACTOR;
546 s->eq_buf[s->eq_step].im = sample->im/(float) FP_FACTOR;
547 #else
548 s->eq_buf[s->eq_step] = *sample;
549 #endif
550 if (++s->eq_step >= V27TER_EQUALIZER_LEN)
551 s->eq_step = 0;
552
553 /* On alternate insertions we have a whole baud, and must process it. */
554 if ((s->baud_half ^= 1))
555 return;
556
557 symbol_sync(s);
558
559 z = equalizer_get(s);
560
561 //span_log(&s->logging, SPAN_LOG_FLOW, "Equalized symbol - %15.5f %15.5f\n", z.re, z.im);
562 constellation_state = s->constellation_state;
563 switch (s->training_stage)
564 {
565 case TRAINING_STAGE_NORMAL_OPERATION:
566 decode_baud(s, &z);
567 constellation_state = (s->bit_rate == 4800) ? s->constellation_state : (s->constellation_state << 1);
568 target = &v27ter_constellation[constellation_state];
569 break;
570 case TRAINING_STAGE_SYMBOL_ACQUISITION:
571 /* Allow time for the Gardner algorithm to settle the baud timing */
572 /* Don't start narrowing the bandwidth of the Gardner algorithm too early.
573 Some modems are a bit wobbly when they start sending the signal. Also, we start
574 this analysis before our filter buffers have completely filled. */
575 target = &zero;
576 if (++s->training_count >= 30)
577 {
578 s->gardner_step = 32;
579 s->training_stage = TRAINING_STAGE_LOG_PHASE;
580 s->angles[0] =
581 s->start_angles[0] = arctan2(z.im, z.re);
582 }
583 break;
584 case TRAINING_STAGE_LOG_PHASE:
585 /* Record the current alternate phase angle */
586 target = &zero;
587 angle = arctan2(z.im, z.re);
588 s->angles[1] =
589 s->start_angles[1] = angle;
590 s->training_count = 1;
591 s->training_stage = TRAINING_STAGE_WAIT_FOR_HOP;
592 break;
593 case TRAINING_STAGE_WAIT_FOR_HOP:
594 target = &zero;
595 angle = arctan2(z.im, z.re);
596 /* Look for the initial ABAB sequence to display a phase reversal, which will
597 signal the start of the scrambled ABAB segment */
598 ang = angle - s->angles[(s->training_count - 1) & 0xF];
599 s->angles[(s->training_count + 1) & 0xF] = angle;
600 if ((ang > 0x20000000 || ang < -0x20000000) && s->training_count >= 3)
601 {
602 /* We seem to have a phase reversal */
603 /* Slam the carrier frequency into line, based on the total phase drift over the last
604 section. Use the shift from the odd bits and the shift from the even bits to get
605 better jitter suppression. We need to scale here, or at the maximum specified
606 frequency deviation we could overflow, and get a silly answer. */
607 /* Step back a few symbols so we don't get ISI distorting things. */
608 i = (s->training_count - 8) & ~1;
609 /* Avoid the possibility of a divide by zero */
610 if (i)
611 {
612 j = i & 0xF;
613 ang = (s->angles[j] - s->start_angles[0])/i
614 + (s->angles[j | 0x1] - s->start_angles[1])/i;
615 if (s->bit_rate == 4800)
616 s->carrier_phase_rate += ang/10;
617 else
618 s->carrier_phase_rate += 3*(ang/40);
619 }
620 span_log(&s->logging, SPAN_LOG_FLOW, "Coarse carrier frequency %7.2f (%d)\n", dds_frequencyf(s->carrier_phase_rate), s->training_count);
621 /* Check if the carrier frequency is plausible */
622 if (s->carrier_phase_rate < dds_phase_ratef(CARRIER_NOMINAL_FREQ - 20.0f)
623 ||
624 s->carrier_phase_rate > dds_phase_ratef(CARRIER_NOMINAL_FREQ + 20.0f))
625 {
626 span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n");
627 /* Park this modem */
628 s->training_stage = TRAINING_STAGE_PARKED;
629 report_status_change(s, SIG_STATUS_TRAINING_FAILED);
630 break;
631 }
632
633 /* Make a step shift in the phase, to pull it into line. We need to rotate the equalizer
634 buffer, as well as the carrier phase, for this to play out nicely. */
635 angle += 0x80000000;
636 p = angle*2.0f*3.14159f/(65536.0f*65536.0f);
637 #if defined(SPANDSP_USE_FIXED_POINTx)
638 zz = complex_setf(cosf(p), -sinf(p));
639 for (i = 0; i < V27TER_EQUALIZER_LEN; i++)
640 {
641 z1 = complex_setf(s->eq_buf[i].re, s->eq_buf[i].im);
642 z1 = complex_mulf(&z1, &zz);
643 s->eq_buf[i].re = z1.re;
644 s->eq_buf[i].im = z1.im;
645 }
646 #else
647 zz = complex_setf(cosf(p), -sinf(p));
648 for (i = 0; i < V27TER_EQUALIZER_LEN; i++)
649 s->eq_buf[i] = complex_mulf(&s->eq_buf[i], &zz);
650 #endif
651 s->carrier_phase += angle;
652 s->gardner_step = 2;
653 /* We have just seen the first element of the scrambled sequence so skip it. */
654 s->training_bc = 1;
655 s->training_bc ^= descramble(s, 1);
656 descramble(s, 1);
657 descramble(s, 1);
658 constellation_state =
659 s->constellation_state = abab_pos[s->training_bc];
660 target = &v27ter_constellation[constellation_state];
661 s->training_count = 1;
662 s->training_stage = TRAINING_STAGE_TRAIN_ON_ABAB;
663 report_status_change(s, SIG_STATUS_TRAINING_IN_PROGRESS);
664 }
665 else if (++s->training_count > V27TER_TRAINING_SEG_3_LEN)
666 {
667 /* This is bogus. There are not this many bits in this section
668 of a real training sequence. */
669 span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n");
670 /* Park this modem */
671 s->training_stage = TRAINING_STAGE_PARKED;
672 report_status_change(s, SIG_STATUS_TRAINING_FAILED);
673 }
674 break;
675 case TRAINING_STAGE_TRAIN_ON_ABAB:
676 /* Train on the scrambled ABAB section */
677 s->training_bc ^= descramble(s, 1);
678 descramble(s, 1);
679 descramble(s, 1);
680 constellation_state =
681 s->constellation_state = abab_pos[s->training_bc];
682 target = &v27ter_constellation[constellation_state];
683 track_carrier(s, &z, target);
684 tune_equalizer(s, &z, target);
685
686 #if defined(SPANDSP_USE_FIXED_POINTx)
687 s->carrier_track_i = 400 + (200000 - 400)*(float) (V27TER_TRAINING_SEG_5_LEN - s->training_count)/(float) V27TER_TRAINING_SEG_5_LEN;
688 s->carrier_track_p = 1000000 + (10000000 - 1000000)*(float) (V27TER_TRAINING_SEG_5_LEN - s->training_count)/(float) V27TER_TRAINING_SEG_5_LEN;
689 #else
690 s->carrier_track_i = 400.0f + (200000.0f - 400.0f)*(float) (V27TER_TRAINING_SEG_5_LEN - s->training_count)/(float) V27TER_TRAINING_SEG_5_LEN;
691 s->carrier_track_p = 1000000.0f + (10000000.0f - 1000000.0f)*(float) (V27TER_TRAINING_SEG_5_LEN - s->training_count)/(float) V27TER_TRAINING_SEG_5_LEN;
692 #endif
693 if (++s->training_count >= V27TER_TRAINING_SEG_5_LEN)
694 {
695 constellation_state = 4;
696 s->constellation_state = (s->bit_rate == 4800) ? 4 : 2;
697 s->training_count = 0;
698 s->training_stage = TRAINING_STAGE_TEST_ONES;
699 }
700 break;
701 case TRAINING_STAGE_TEST_ONES:
702 decode_baud(s, &z);
703 constellation_state = (s->bit_rate == 4800) ? s->constellation_state : (s->constellation_state << 1);
704 target = &v27ter_constellation[constellation_state];
705 /* Measure the training error */
706 #if defined(SPANDSP_USE_FIXED_POINTx)
707 z1.re = z.re/(float) FP_FACTOR;
708 z1.im = z.im/(float) FP_FACTOR;
709 zz = complex_subf(&z, target);
710 zz = complex_subf(&z1, &zz);
711 s->training_error += powerf(&zz);
712 #else
713 zz = complex_subf(&z, target);
714 s->training_error += powerf(&zz);
715 #endif
716 if (++s->training_count >= V27TER_TRAINING_SEG_6_LEN)
717 {
718 /* At 4800bps the symbols are 1.08238 (Euclidian) apart.
719 At 2400bps the symbols are 2.0 (Euclidian) apart. */
720 if ((s->bit_rate == 4800 && s->training_error < V27TER_TRAINING_SEG_6_LEN*0.25f)
721 ||
722 (s->bit_rate == 2400 && s->training_error < V27TER_TRAINING_SEG_6_LEN*0.5f))
723 {
724 /* We are up and running */
725 span_log(&s->logging, SPAN_LOG_FLOW, "Training succeeded at %dbps (constellation mismatch %f)\n", s->bit_rate, s->training_error);
726 report_status_change(s, SIG_STATUS_TRAINING_SUCCEEDED);
727 /* Apply some lag to the carrier off condition, to ensure the last few bits get pushed through
728 the processing. */
729 s->signal_present = (s->bit_rate == 4800) ? 90 : 120;
730 s->training_stage = TRAINING_STAGE_NORMAL_OPERATION;
731 equalizer_save(s);
732 s->carrier_phase_rate_save = s->carrier_phase_rate;
733 s->agc_scaling_save = s->agc_scaling;
734 }
735 else
736 {
737 /* Training has failed */
738 span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (constellation mismatch %f)\n", s->training_error);
739 /* Park this modem */
740 s->training_stage = TRAINING_STAGE_PARKED;
741 report_status_change(s, SIG_STATUS_TRAINING_FAILED);
742 }
743 }
744 break;
745 case TRAINING_STAGE_PARKED:
746 default:
747 /* We failed to train! */
748 /* Park here until the carrier drops. */
749 target = &zero;
750 break;
751 }
752 if (s->qam_report)
753 {
754 #if defined(SPANDSP_USE_FIXED_POINTx)
755 z1.re = z.re/(float) FP_FACTOR;
756 z1.im = z.im/(float) FP_FACTOR;
757 zz.re = target->re;
758 zz.im = target->im;
759 s->qam_report(s->qam_user_data, &z1, &zz, s->constellation_state);
760 #else
761 s->qam_report(s->qam_user_data, &z, target, s->constellation_state);
762 #endif
763 }
764 }
765 /*- End of function --------------------------------------------------------*/
766
767 static __inline__ int signal_detect(v27ter_rx_state_t *s, int16_t amp)
768 {
769 int16_t diff;
770 int16_t x;
771 int32_t power;
772
773 /* There should be no DC in the signal, but sometimes there is.
774 We need to measure the power with the DC blocked, but not using
775 a slow to respond DC blocker. Use the most elementary HPF. */
776 x = amp >> 1;
777 /* There could be overflow here, but it isn't a problem in practice */
778 diff = x - s->last_sample;
779 s->last_sample = x;
780 power = power_meter_update(&(s->power), diff);
781 #if defined(IAXMODEM_STUFF)
782 /* Quick power drop fudge */
783 diff = abs(diff);
784 if (10*diff < s->high_sample)
785 {
786 if (++s->low_samples > 120)
787 {
788 power_meter_init(&(s->power), 4);
789 s->high_sample = 0;
790 s->low_samples = 0;
791 }
792 }
793 else
794 {
795 s->low_samples = 0;
796 if (diff > s->high_sample)
797 s->high_sample = diff;
798 }
799 #endif
800 //span_log(&s->logging, SPAN_LOG_FLOW, "Power = %f\n", power_meter_current_dbm0(&(s->power)));
801 if (s->signal_present > 0)
802 {
803 /* Look for power below turn-off threshold to turn the carrier off */
804 #if defined(IAXMODEM_STUFF)
805 if (s->carrier_drop_pending || power < s->carrier_off_power)
806 #else
807 if (power < s->carrier_off_power)
808 #endif
809 {
810 if (--s->signal_present <= 0)
811 {
812 /* Count down a short delay, to ensure we push the last
813 few bits through the filters before stopping. */
814 v27ter_rx_restart(s, s->bit_rate, FALSE);
815 report_status_change(s, SIG_STATUS_CARRIER_DOWN);
816 return 0;
817 }
818 #if defined(IAXMODEM_STUFF)
819 /* Carrier has dropped, but the put_bit is pending the signal_present delay. */
820 s->carrier_drop_pending = TRUE;
821 #endif
822 }
823 }
824 else
825 {
826 /* Look for power exceeding turn-on threshold to turn the carrier on */
827 if (power < s->carrier_on_power)
828 return 0;
829 s->signal_present = 1;
830 #if defined(IAXMODEM_STUFF)
831 s->carrier_drop_pending = FALSE;
832 #endif
833 report_status_change(s, SIG_STATUS_CARRIER_UP);
834 }
835 return power;
836 }
837 /*- End of function --------------------------------------------------------*/
838
839 SPAN_DECLARE_NONSTD(int) v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], int len)
840 {
841 int i;
842 int step;
843 #if defined(SPANDSP_USE_FIXED_POINT)
844 complexi16_t z;
845 complexi16_t zz;
846 complexi16_t sample;
847 int32_t v;
848 #else
849 complexf_t z;
850 complexf_t zz;
851 complexf_t sample;
852 float v;
853 #endif
854 int32_t power;
855
856 if (s->bit_rate == 4800)
857 {
858 for (i = 0; i < len; i++)
859 {
860 s->rrc_filter[s->rrc_filter_step] = amp[i];
861 if (++s->rrc_filter_step >= V27TER_RX_4800_FILTER_STEPS)
862 s->rrc_filter_step = 0;
863
864 if ((power = signal_detect(s, amp[i])) == 0)
865 continue;
866 /* Only spend effort processing this data if the modem is not
867 parked, after training failure. */
868 if (s->training_stage == TRAINING_STAGE_PARKED)
869 continue;
870
871 /* Put things into the equalization buffer at T/2 rate. The Gardner algorithm
872 will fiddle the step to align this with the symbols. */
873 if ((s->eq_put_step -= RX_PULSESHAPER_4800_COEFF_SETS) <= 0)
874 {
875 if (s->training_stage == TRAINING_STAGE_SYMBOL_ACQUISITION)
876 {
877 /* Only AGC during the initial training */
878 #if defined(SPANDSP_USE_FIXED_POINT)
879 s->agc_scaling = (float) FP_FACTOR*32768.0f*(1.0f/RX_PULSESHAPER_4800_GAIN)*1.414f/sqrtf(power);
880 #else
881 s->agc_scaling = (1.0f/RX_PULSESHAPER_4800_GAIN)*1.414f/sqrtf(power);
882 #endif
883 }
884 /* Pulse shape while still at the carrier frequency, using a quadrature
885 pair of filters. This results in a properly bandpass filtered complex
886 signal, which can be brought directly to baseband by complex mixing.
887 No further filtering, to remove mixer harmonics, is needed. */
888 step = -s->eq_put_step;
889 if (step > RX_PULSESHAPER_4800_COEFF_SETS - 1)
890 step = RX_PULSESHAPER_4800_COEFF_SETS - 1;
891 s->eq_put_step += RX_PULSESHAPER_4800_COEFF_SETS*5/2;
892 #if defined(SPANDSP_USE_FIXED_POINT)
893 v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_4800_re[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step);
894 sample.re = (v*(int32_t) s->agc_scaling) >> 15;
895 v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_4800_im[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step);
896 sample.im = (v*(int32_t) s->agc_scaling) >> 15;
897 z = dds_lookup_complexi16(s->carrier_phase);
898 zz.re = ((int32_t) sample.re*(int32_t) z.re - (int32_t) sample.im*(int32_t) z.im) >> 15;
899 zz.im = ((int32_t) -sample.re*(int32_t) z.im - (int32_t) sample.im*(int32_t) z.re) >> 15;
900 #else
901 v = vec_circular_dot_prodf(s->rrc_filter, rx_pulseshaper_4800_re[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step);
902 sample.re = v*s->agc_scaling;
903 v = vec_circular_dot_prodf(s->rrc_filter, rx_pulseshaper_4800_im[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step);
904 sample.im = v*s->agc_scaling;
905 z = dds_lookup_complexf(s->carrier_phase);
906 zz.re = sample.re*z.re - sample.im*z.im;
907 zz.im = -sample.re*z.im - sample.im*z.re;
908 #endif
909 process_half_baud(s, &zz);
910 }
911 #if defined(SPANDSP_USE_FIXED_POINT)
912 dds_advance(&s->carrier_phase, s->carrier_phase_rate);
913 #else
914 dds_advancef(&s->carrier_phase, s->carrier_phase_rate);
915 #endif
916 }
917 }
918 else
919 {
920 for (i = 0; i < len; i++)
921 {
922 s->rrc_filter[s->rrc_filter_step] = amp[i];
923 if (++s->rrc_filter_step >= V27TER_RX_2400_FILTER_STEPS)
924 s->rrc_filter_step = 0;
925
926 if ((power = signal_detect(s, amp[i])) == 0)
927 continue;
928 /* Only spend effort processing this data if the modem is not
929 parked, after training failure. */
930 if (s->training_stage == TRAINING_STAGE_PARKED)
931 continue;
932
933 /* Put things into the equalization buffer at T/2 rate. The Gardner algorithm
934 will fiddle the step to align this with the symbols. */
935 if ((s->eq_put_step -= RX_PULSESHAPER_2400_COEFF_SETS) <= 0)
936 {
937 if (s->training_stage == TRAINING_STAGE_SYMBOL_ACQUISITION)
938 {
939 /* Only AGC during the initial training */
940 #if defined(SPANDSP_USE_FIXED_POINT)
941 s->agc_scaling = (float) FP_FACTOR*32768.0f*(1.0f/RX_PULSESHAPER_2400_GAIN)*1.414f/sqrtf(power);
942 #else
943 s->agc_scaling = (1.0f/RX_PULSESHAPER_2400_GAIN)*1.414f/sqrtf(power);
944 #endif
945 }
946 /* Pulse shape while still at the carrier frequency, using a quadrature
947 pair of filters. This results in a properly bandpass filtered complex
948 signal, which can be brought directly to bandband by complex mixing.
949 No further filtering, to remove mixer harmonics, is needed. */
950 step = -s->eq_put_step;
951 if (step > RX_PULSESHAPER_2400_COEFF_SETS - 1)
952 step = RX_PULSESHAPER_2400_COEFF_SETS - 1;
953 s->eq_put_step += RX_PULSESHAPER_2400_COEFF_SETS*20/(3*2);
954 #if defined(SPANDSP_USE_FIXED_POINT)
955 v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_2400_re[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step);
956 sample.re = (v*(int32_t) s->agc_scaling) >> 15;
957 v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_2400_im[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step);
958 sample.im = (v*(int32_t) s->agc_scaling) >> 15;
959 z = dds_lookup_complexi16(s->carrier_phase);
960 zz.re = ((int32_t) sample.re*(int32_t) z.re - (int32_t) sample.im*(int32_t) z.im) >> 15;
961 zz.im = ((int32_t) -sample.re*(int32_t) z.im - (int32_t) sample.im*(int32_t) z.re) >> 15;
962 #else
963 v = vec_circular_dot_prodf(s->rrc_filter, rx_pulseshaper_2400_re[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step);
964 sample.re = v*s->agc_scaling;
965 v = vec_circular_dot_prodf(s->rrc_filter, rx_pulseshaper_2400_im[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step);
966 sample.im = v*s->agc_scaling;
967 z = dds_lookup_complexf(s->carrier_phase);
968 zz.re = sample.re*z.re - sample.im*z.im;
969 zz.im = -sample.re*z.im - sample.im*z.re;
970 #endif
971 process_half_baud(s, &zz);
972 }
973 #if defined(SPANDSP_USE_FIXED_POINT)
974 dds_advance(&s->carrier_phase, s->carrier_phase_rate);
975 #else
976 dds_advancef(&s->carrier_phase, s->carrier_phase_rate);
977 #endif
978 }
979 }
980 return 0;
981 }
982 /*- End of function --------------------------------------------------------*/
983
984 SPAN_DECLARE(int) v27ter_rx_fillin(v27ter_rx_state_t *s, int len)
985 {
986 int i;
987
988 /* We want to sustain the current state (i.e carrier on<->carrier off), and
989 try to sustain the carrier phase. We should probably push the filters, as well */
990 span_log(&s->logging, SPAN_LOG_FLOW, "Fill-in %d samples\n", len);
991 if (s->signal_present <= 0)
992 return 0;
993 if (s->training_stage == TRAINING_STAGE_PARKED)
994 return 0;
995 for (i = 0; i < len; i++)
996 {
997 #if defined(SPANDSP_USE_FIXED_POINT)
998 dds_advance(&s->carrier_phase, s->carrier_phase_rate);
999 #else
1000 dds_advancef(&s->carrier_phase, s->carrier_phase_rate);
1001 #endif
1002 /* Advance the symbol phase the appropriate amount */
1003 if (s->bit_rate == 4800)
1004 {
1005 if ((s->eq_put_step -= RX_PULSESHAPER_4800_COEFF_SETS) <= 0)
1006 s->eq_put_step += RX_PULSESHAPER_4800_COEFF_SETS*5/2;
1007 }
1008 else
1009 {
1010 if ((s->eq_put_step -= RX_PULSESHAPER_2400_COEFF_SETS) <= 0)
1011 s->eq_put_step += RX_PULSESHAPER_2400_COEFF_SETS*20/(3*2);
1012 }
1013 /* TODO: Should we rotate any buffers */
1014 }
1015 return 0;
1016 }
1017 /*- End of function --------------------------------------------------------*/
1018
1019 SPAN_DECLARE(void) v27ter_rx_set_put_bit(v27ter_rx_state_t *s, put_bit_func_t put_bit, void *user_data)
1020 {
1021 s->put_bit = put_bit;
1022 s->put_bit_user_data = user_data;
1023 }
1024 /*- End of function --------------------------------------------------------*/
1025
1026 SPAN_DECLARE(void) v27ter_rx_set_modem_status_handler(v27ter_rx_state_t *s, modem_tx_status_func_t handler, void *user_data)
1027 {
1028 s->status_handler = handler;
1029 s->status_user_data = user_data;
1030 }
1031 /*- End of function --------------------------------------------------------*/
1032
1033 SPAN_DECLARE(logging_state_t *) v27ter_rx_get_logging_state(v27ter_rx_state_t *s)
1034 {
1035 return &s->logging;
1036 }
1037 /*- End of function --------------------------------------------------------*/
1038
1039 SPAN_DECLARE(int) v27ter_rx_restart(v27ter_rx_state_t *s, int bit_rate, int old_train)
1040 {
1041 span_log(&s->logging, SPAN_LOG_FLOW, "Restarting V.27ter\n");
1042 if (bit_rate != 4800 && bit_rate != 2400)
1043 return -1;
1044 s->bit_rate = bit_rate;
1045
1046 #if defined(SPANDSP_USE_FIXED_POINT)
1047 vec_zeroi16(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
1048 #else
1049 vec_zerof(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
1050 #endif
1051 s->rrc_filter_step = 0;
1052
1053 s->scramble_reg = 0x3C;
1054 s->scrambler_pattern_count = 0;
1055 s->training_stage = TRAINING_STAGE_SYMBOL_ACQUISITION;
1056 s->training_bc = 0;
1057 s->training_count = 0;
1058 s->training_error = 0.0f;
1059 s->signal_present = 0;
1060 #if defined(IAXMODEM_STUFF)
1061 s->high_sample = 0;
1062 s->low_samples = 0;
1063 s->carrier_drop_pending = FALSE;
1064 #endif
1065
1066 s->carrier_phase = 0;
1067 #if defined(SPANDSP_USE_FIXED_POINTx)
1068 s->carrier_track_i = 200000;
1069 s->carrier_track_p = 10000000;
1070 #else
1071 s->carrier_track_i = 200000.0f;
1072 s->carrier_track_p = 10000000.0f;
1073 #endif
1074 power_meter_init(&(s->power), 4);
1075
1076 s->constellation_state = 0;
1077
1078 if (s->old_train)
1079 {
1080 s->carrier_phase_rate = s->carrier_phase_rate_save;
1081 s->agc_scaling = s->agc_scaling_save;
1082 equalizer_restore(s);
1083 }
1084 else
1085 {
1086 s->carrier_phase_rate = dds_phase_ratef(CARRIER_NOMINAL_FREQ);
1087 #if defined(SPANDSP_USE_FIXED_POINTx)
1088 s->agc_scaling = (float) FP_FACTOR*32768.0f*0.005f/RX_PULSESHAPER_4800_GAIN;
1089 #else
1090 s->agc_scaling = 0.005f/RX_PULSESHAPER_4800_GAIN;
1091 #endif
1092 equalizer_reset(s);
1093 }
1094 s->eq_skip = 0;
1095 s->last_sample = 0;
1096
1097 s->gardner_integrate = 0;
1098 s->total_baud_timing_correction = 0;
1099 s->gardner_step = 512;
1100 s->baud_half = 0;
1101
1102 return 0;
1103 }
1104 /*- End of function --------------------------------------------------------*/
1105
1106 SPAN_DECLARE(v27ter_rx_state_t *) v27ter_rx_init(v27ter_rx_state_t *s, int bit_rate, put_bit_func_t put_bit, void *user_data)
1107 {
1108 switch (bit_rate)
1109 {
1110 case 4800:
1111 case 2400:
1112 break;
1113 default:
1114 return NULL;
1115 }
1116 if (s == NULL)
1117 {
1118 if ((s = (v27ter_rx_state_t *) malloc(sizeof(*s))) == NULL)
1119 return NULL;
1120 }
1121 memset(s, 0, sizeof(*s));
1122 span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
1123 span_log_set_protocol(&s->logging, "V.27ter RX");
1124 v27ter_rx_signal_cutoff(s, -45.5f);
1125 s->put_bit = put_bit;
1126 s->put_bit_user_data = user_data;
1127
1128 v27ter_rx_restart(s, bit_rate, FALSE);
1129 return s;
1130 }
1131 /*- End of function --------------------------------------------------------*/
1132
1133 SPAN_DECLARE(int) v27ter_rx_release(v27ter_rx_state_t *s)
1134 {
1135 return 0;
1136 }
1137 /*- End of function --------------------------------------------------------*/
1138
1139 SPAN_DECLARE(int) v27ter_rx_free(v27ter_rx_state_t *s)
1140 {
1141 free(s);
1142 return 0;
1143 }
1144 /*- End of function --------------------------------------------------------*/
1145
1146 SPAN_DECLARE(void) v27ter_rx_set_qam_report_handler(v27ter_rx_state_t *s, qam_report_handler_t handler, void *user_data)
1147 {
1148 s->qam_report = handler;
1149 s->qam_user_data = user_data;
1150 }
1151 /*- End of function --------------------------------------------------------*/
1152 /*- End of file ------------------------------------------------------------*/

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