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