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