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

import spandsp-0.0.6pre17
author Peter Meerwald <pmeerw@cosy.sbg.ac.at>
date Fri, 25 Jun 2010 15:50:58 +0200
parents
children
comparison
equal deleted inserted replaced
3:c6c5a16ce2f2 4:26cd8f1ef0b1
1 /*
2 * SpanDSP - a series of DSP components for telephony
3 *
4 * v22bis_rx.c - ITU V.22bis modem receive part
5 *
6 * Written by Steve Underwood <steveu@coppice.org>
7 *
8 * Copyright (C) 2004 Steve Underwood
9 *
10 * All rights reserved.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 2.1,
14 * as published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 * $Id: v22bis_rx.c,v 1.69 2009/11/04 15:52:06 steveu Exp $
26 */
27
28 /*! \file */
29
30 /* THIS IS A WORK IN PROGRESS - It is basically functional, but it is not feature
31 complete, and doesn't reliably sync over the signal and noise level ranges it
32 should. There are some nasty inefficiencies too!
33 TODO:
34 Better noise performance
35 Retrain is incomplete
36 Rate change is not implemented
37 Remote loopback is not implemented */
38
39 #if defined(HAVE_CONFIG_H)
40 #include "config.h"
41 #endif
42
43 #include <inttypes.h>
44 #include <string.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #if defined(HAVE_TGMATH_H)
48 #include <tgmath.h>
49 #endif
50 #if defined(HAVE_MATH_H)
51 #include <math.h>
52 #endif
53 #include "floating_fudge.h"
54
55 #include "spandsp/telephony.h"
56 #include "spandsp/logging.h"
57 #include "spandsp/complex.h"
58 #include "spandsp/vector_float.h"
59 #include "spandsp/complex_vector_float.h"
60 #include "spandsp/async.h"
61 #include "spandsp/power_meter.h"
62 #include "spandsp/arctan2.h"
63 #include "spandsp/dds.h"
64 #include "spandsp/complex_filters.h"
65
66 #include "spandsp/v29rx.h"
67 #include "spandsp/v22bis.h"
68
69 #include "spandsp/private/logging.h"
70 #include "spandsp/private/v22bis.h"
71
72 #if defined(SPANDSP_USE_FIXED_POINTx)
73 #include "v22bis_rx_1200_floating_rrc.h"
74 #include "v22bis_rx_2400_floating_rrc.h"
75 #else
76 #include "v22bis_rx_1200_floating_rrc.h"
77 #include "v22bis_rx_2400_floating_rrc.h"
78 #endif
79
80 #define ms_to_symbols(t) (((t)*600)/1000)
81
82 /*! The adaption rate coefficient for the equalizer */
83 #define EQUALIZER_DELTA 0.25f
84 /*! The number of phase shifted coefficient set for the pulse shaping/bandpass filter */
85 #define PULSESHAPER_COEFF_SETS 12
86
87 /*
88 The basic method used by the V.22bis receiver is:
89
90 Put each sample into the pulse-shaping and phase shift filter buffer
91
92 At T/2 rate:
93 Filter and demodulate the contents of the input filter buffer, producing a sample
94 in the equalizer filter buffer.
95
96 Tune the symbol timing based on the latest 3 samples in the equalizer buffer. This
97 updates the decision points for taking the T/2 samples.
98
99 Equalize the contents of the equalizer buffer, producing a demodulated constellation
100 point.
101
102 Find the nearest constellation point to the received position. This is our received
103 symbol.
104
105 Tune the local carrier, based on the angular mismatch between the actual signal and
106 the decision.
107
108 Tune the equalizer, based on the mismatch between the actual signal and the decision.
109
110 Descramble and output the bits represented by the decision.
111 */
112
113 static const uint8_t space_map_v22bis[6][6] =
114 {
115 {11, 9, 9, 6, 6, 7},
116 {10, 8, 8, 4, 4, 5},
117 {10, 8, 8, 4, 4, 5},
118 {13, 12, 12, 0, 0, 2},
119 {13, 12, 12, 0, 0, 2},
120 {15, 14, 14, 1, 1, 3}
121 };
122
123 static const uint8_t phase_steps[4] =
124 {
125 1, 0, 2, 3
126 };
127
128 static const uint8_t ones[] =
129 {
130 0, 1, 1, 2,
131 1, 2, 2, 3,
132 1, 2, 2, 3,
133 2, 3, 3, 4
134 };
135
136 SPAN_DECLARE(float) v22bis_rx_carrier_frequency(v22bis_state_t *s)
137 {
138 return dds_frequencyf(s->rx.carrier_phase_rate);
139 }
140 /*- End of function --------------------------------------------------------*/
141
142 SPAN_DECLARE(float) v22bis_rx_symbol_timing_correction(v22bis_state_t *s)
143 {
144 return (float) s->rx.total_baud_timing_correction/((float) PULSESHAPER_COEFF_SETS*40.0f/(3.0f*2.0f));
145 }
146 /*- End of function --------------------------------------------------------*/
147
148 SPAN_DECLARE(float) v22bis_rx_signal_power(v22bis_state_t *s)
149 {
150 return power_meter_current_dbm0(&s->rx.rx_power) + 6.34f;
151 }
152 /*- End of function --------------------------------------------------------*/
153
154 SPAN_DECLARE(void) v22bis_rx_signal_cutoff(v22bis_state_t *s, float cutoff)
155 {
156 s->rx.carrier_on_power = (int32_t) (power_meter_level_dbm0(cutoff + 2.5f)*0.232f);
157 s->rx.carrier_off_power = (int32_t) (power_meter_level_dbm0(cutoff - 2.5f)*0.232f);
158 }
159 /*- End of function --------------------------------------------------------*/
160
161 void v22bis_report_status_change(v22bis_state_t *s, int status)
162 {
163 if (s->status_handler)
164 s->status_handler(s->status_user_data, status);
165 else if (s->put_bit)
166 s->put_bit(s->put_bit_user_data, status);
167 }
168 /*- End of function --------------------------------------------------------*/
169
170 SPAN_DECLARE(int) v22bis_rx_equalizer_state(v22bis_state_t *s, complexf_t **coeffs)
171 {
172 *coeffs = s->rx.eq_coeff;
173 return 2*V22BIS_EQUALIZER_LEN + 1;
174 }
175 /*- End of function --------------------------------------------------------*/
176
177 void v22bis_equalizer_coefficient_reset(v22bis_state_t *s)
178 {
179 /* Start with an equalizer based on everything being perfect */
180 #if defined(SPANDSP_USE_FIXED_POINTx)
181 cvec_zeroi16(s->rx.eq_coeff, 2*V22BIS_EQUALIZER_LEN + 1);
182 s->rx.eq_coeff[V22BIS_EQUALIZER_LEN] = complex_seti16(3*FP_FACTOR, 0*FP_FACTOR);
183 s->rx.eq_delta = 32768.0f*EQUALIZER_DELTA/(2*V22BIS_EQUALIZER_LEN + 1);
184 #else
185 cvec_zerof(s->rx.eq_coeff, 2*V22BIS_EQUALIZER_LEN + 1);
186 s->rx.eq_coeff[V22BIS_EQUALIZER_LEN] = complex_setf(3.0f, 0.0f);
187 s->rx.eq_delta = EQUALIZER_DELTA/(2*V22BIS_EQUALIZER_LEN + 1);
188 #endif
189 }
190 /*- End of function --------------------------------------------------------*/
191
192 static void equalizer_reset(v22bis_state_t *s)
193 {
194 v22bis_equalizer_coefficient_reset(s);
195 #if defined(SPANDSP_USE_FIXED_POINTx)
196 cvec_zeroi16(s->rx.eq_buf, V22BIS_EQUALIZER_MASK + 1);
197 #else
198 cvec_zerof(s->rx.eq_buf, V22BIS_EQUALIZER_MASK + 1);
199 #endif
200 s->rx.eq_put_step = 20 - 1;
201 s->rx.eq_step = 0;
202 }
203 /*- End of function --------------------------------------------------------*/
204
205 static complexf_t equalizer_get(v22bis_state_t *s)
206 {
207 int i;
208 int p;
209 complexf_t z;
210 complexf_t z1;
211
212 /* Get the next equalized value. */
213 z = complex_setf(0.0f, 0.0f);
214 p = s->rx.eq_step - 1;
215 for (i = 0; i < 2*V22BIS_EQUALIZER_LEN + 1; i++)
216 {
217 p = (p - 1) & V22BIS_EQUALIZER_MASK;
218 z1 = complex_mulf(&s->rx.eq_coeff[i], &s->rx.eq_buf[p]);
219 z = complex_addf(&z, &z1);
220 }
221 return z;
222 }
223 /*- End of function --------------------------------------------------------*/
224
225 static void tune_equalizer(v22bis_state_t *s, const complexf_t *z, const complexf_t *target)
226 {
227 int i;
228 int p;
229 complexf_t ez;
230 complexf_t z1;
231
232 /* Find the x and y mismatch from the exact constellation position. */
233 ez = complex_subf(target, z);
234 ez.re *= s->rx.eq_delta;
235 ez.im *= s->rx.eq_delta;
236
237 p = s->rx.eq_step - 1;
238 for (i = 0; i < 2*V22BIS_EQUALIZER_LEN + 1; i++)
239 {
240 p = (p - 1) & V22BIS_EQUALIZER_MASK;
241 z1 = complex_conjf(&s->rx.eq_buf[p]);
242 z1 = complex_mulf(&ez, &z1);
243 s->rx.eq_coeff[i] = complex_addf(&s->rx.eq_coeff[i], &z1);
244 /* If we don't leak a little bit we seem to get some wandering adaption */
245 s->rx.eq_coeff[i].re *= 0.9999f;
246 s->rx.eq_coeff[i].im *= 0.9999f;
247 }
248 }
249 /*- End of function --------------------------------------------------------*/
250
251 static __inline__ void track_carrier(v22bis_state_t *s, const complexf_t *z, const complexf_t *target)
252 {
253 float error;
254
255 /* For small errors the imaginary part of the difference between the actual and the target
256 positions is proportional to the phase error, for any particular target. However, the
257 different amplitudes of the various target positions scale things. */
258 error = z->im*target->re - z->re*target->im;
259
260 s->rx.carrier_phase_rate += (int32_t) (s->rx.carrier_track_i*error);
261 s->rx.carrier_phase += (int32_t) (s->rx.carrier_track_p*error);
262 //span_log(&s->logging, SPAN_LOG_FLOW, "Im = %15.5f f = %15.5f\n", error, dds_frequencyf(s->rx.carrier_phase_rate));
263 }
264 /*- End of function --------------------------------------------------------*/
265
266 static __inline__ int descramble(v22bis_state_t *s, int bit)
267 {
268 int out_bit;
269
270 bit &= 1;
271
272 /* Descramble the bit */
273 out_bit = (bit ^ (s->rx.scramble_reg >> 13) ^ (s->rx.scramble_reg >> 16)) & 1;
274 s->rx.scramble_reg = (s->rx.scramble_reg << 1) | bit;
275
276 if (s->rx.scrambler_pattern_count >= 64)
277 {
278 out_bit ^= 1;
279 s->rx.scrambler_pattern_count = 0;
280 }
281 if (bit)
282 s->rx.scrambler_pattern_count++;
283 else
284 s->rx.scrambler_pattern_count = 0;
285 return out_bit;
286 }
287 /*- End of function --------------------------------------------------------*/
288
289 static __inline__ void put_bit(v22bis_state_t *s, int bit)
290 {
291 int out_bit;
292
293 /* Descramble the bit */
294 out_bit = descramble(s, bit);
295 s->put_bit(s->put_bit_user_data, out_bit);
296 }
297 /*- End of function --------------------------------------------------------*/
298
299 static void decode_baud(v22bis_state_t *s, int nearest)
300 {
301 int raw_bits;
302
303 raw_bits = phase_steps[((nearest >> 2) - (s->rx.constellation_state >> 2)) & 3];
304 s->rx.constellation_state = nearest;
305 /* The first two bits are the quadrant */
306 put_bit(s, raw_bits >> 1);
307 put_bit(s, raw_bits);
308 if (s->rx.sixteen_way_decisions)
309 {
310 /* The other two bits are the position within the quadrant */
311 put_bit(s, nearest >> 1);
312 put_bit(s, nearest);
313 }
314 }
315 /*- End of function --------------------------------------------------------*/
316
317 static int decode_baudx(v22bis_state_t *s, int nearest)
318 {
319 int raw_bits;
320 int out_bits;
321
322 raw_bits = phase_steps[((nearest >> 2) - (s->rx.constellation_state >> 2)) & 3];
323 s->rx.constellation_state = nearest;
324 /* The first two bits are the quadrant */
325 out_bits = descramble(s, raw_bits >> 1);
326 out_bits = (out_bits << 1) | descramble(s, raw_bits);
327 if (s->rx.sixteen_way_decisions)
328 {
329 /* The other two bits are the position within the quadrant */
330 out_bits = (out_bits << 1) | descramble(s, nearest >> 1);
331 out_bits = (out_bits << 1) | descramble(s, nearest);
332 }
333 return out_bits;
334 }
335 /*- End of function --------------------------------------------------------*/
336
337 static __inline__ void symbol_sync(v22bis_state_t *s)
338 {
339 float p;
340 float q;
341 complexf_t zz;
342 complexf_t a;
343 complexf_t b;
344 complexf_t c;
345
346 /* This routine adapts the position of the half baud samples entering the equalizer. */
347
348 /* Perform a Gardner test for baud alignment on the three most recent samples. */
349 if (s->rx.sixteen_way_decisions)
350 {
351 p = s->rx.eq_buf[(s->rx.eq_step - 3) & V22BIS_EQUALIZER_MASK].re
352 - s->rx.eq_buf[(s->rx.eq_step - 1) & V22BIS_EQUALIZER_MASK].re;
353 p *= s->rx.eq_buf[(s->rx.eq_step - 2) & V22BIS_EQUALIZER_MASK].re;
354
355 q = s->rx.eq_buf[(s->rx.eq_step - 3) & V22BIS_EQUALIZER_MASK].im
356 - s->rx.eq_buf[(s->rx.eq_step - 1) & V22BIS_EQUALIZER_MASK].im;
357 q *= s->rx.eq_buf[(s->rx.eq_step - 2) & V22BIS_EQUALIZER_MASK].im;
358 }
359 else
360 {
361 /* Rotate the points to the 45 degree positions, to maximise the effectiveness of
362 the Gardner algorithm. This is particularly significant at the start of operation
363 to pull things in quickly. */
364 zz = complex_setf(0.894427, 0.44721f);
365 a = complex_mulf(&s->rx.eq_buf[(s->rx.eq_step - 3) & V22BIS_EQUALIZER_MASK], &zz);
366 b = complex_mulf(&s->rx.eq_buf[(s->rx.eq_step - 2) & V22BIS_EQUALIZER_MASK], &zz);
367 c = complex_mulf(&s->rx.eq_buf[(s->rx.eq_step - 1) & V22BIS_EQUALIZER_MASK], &zz);
368 p = (a.re - c.re)*b.re;
369 q = (a.im - c.im)*b.im;
370 }
371
372 s->rx.gardner_integrate += (p + q > 0.0f) ? s->rx.gardner_step : -s->rx.gardner_step;
373
374 if (abs(s->rx.gardner_integrate) >= 16)
375 {
376 /* This integrate and dump approach avoids rapid changes of the equalizer put step.
377 Rapid changes, without hysteresis, are bad. They degrade the equalizer performance
378 when the true symbol boundary is close to a sample boundary. */
379 s->rx.eq_put_step += (s->rx.gardner_integrate/16);
380 s->rx.total_baud_timing_correction += (s->rx.gardner_integrate/16);
381 //span_log(&s->logging, SPAN_LOG_FLOW, "Gardner kick %d [total %d]\n", s->rx.gardner_integrate, s->rx.total_baud_timing_correction);
382 if (s->rx.qam_report)
383 s->rx.qam_report(s->rx.qam_user_data, NULL, NULL, s->rx.gardner_integrate);
384 s->rx.gardner_integrate = 0;
385 }
386 }
387 /*- End of function --------------------------------------------------------*/
388
389 static void process_half_baud(v22bis_state_t *s, const complexf_t *sample)
390 {
391 complexf_t z;
392 complexf_t zz;
393 const complexf_t *target;
394 int re;
395 int im;
396 int nearest;
397 int bitstream;
398 int raw_bits;
399
400 z.re = sample->re;
401 z.im = sample->im;
402
403 /* Add a sample to the equalizer's circular buffer, but don't calculate anything
404 at this time. */
405 s->rx.eq_buf[s->rx.eq_step] = z;
406 s->rx.eq_step = (s->rx.eq_step + 1) & V22BIS_EQUALIZER_MASK;
407
408 /* On alternate insertions we have a whole baud and must process it. */
409 if ((s->rx.baud_phase ^= 1))
410 return;
411
412 symbol_sync(s);
413
414 z = equalizer_get(s);
415
416 /* Find the constellation point */
417 if (s->rx.sixteen_way_decisions)
418 {
419 re = (int) (z.re + 3.0f);
420 if (re > 5)
421 re = 5;
422 else if (re < 0)
423 re = 0;
424 im = (int) (z.im + 3.0f);
425 if (im > 5)
426 im = 5;
427 else if (im < 0)
428 im = 0;
429 nearest = space_map_v22bis[re][im];
430 }
431 else
432 {
433 /* Rotate to 45 degrees, to make the slicing trivial */
434 zz = complex_setf(0.894427, 0.44721f);
435 zz = complex_mulf(&z, &zz);
436 nearest = 0x01;
437 if (zz.re < 0.0f)
438 nearest |= 0x04;
439 if (zz.im < 0.0f)
440 {
441 nearest ^= 0x04;
442 nearest |= 0x08;
443 }
444 }
445 raw_bits = 0;
446
447 switch (s->rx.training)
448 {
449 case V22BIS_RX_TRAINING_STAGE_NORMAL_OPERATION:
450 /* Normal operation. */
451 target = &v22bis_constellation[nearest];
452 track_carrier(s, &z, target);
453 tune_equalizer(s, &z, target);
454 raw_bits = phase_steps[((nearest >> 2) - (s->rx.constellation_state >> 2)) & 3];
455 /* TODO: detect unscrambled ones indicating a loopback request */
456
457 /* Search for the S1 signal that might be requesting a retrain */
458 if ((s->rx.last_raw_bits ^ raw_bits) == 0x3)
459 {
460 s->rx.pattern_repeats++;
461 }
462 else
463 {
464 if (s->rx.pattern_repeats >= 50 && (s->rx.last_raw_bits == 0x3 || s->rx.last_raw_bits == 0x0))
465 {
466 /* We should get a full run of 00 11 (about 60 bauds) at either modem. */
467 span_log(&s->logging, SPAN_LOG_FLOW, "+++ S1 detected (%d long)\n", s->rx.pattern_repeats);
468 span_log(&s->logging, SPAN_LOG_FLOW, "+++ Accepting a retrain request\n");
469 s->rx.pattern_repeats = 0;
470 s->rx.training_count = 0;
471 s->rx.training = V22BIS_RX_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200;
472 s->tx.training_count = 0;
473 s->tx.training = V22BIS_TX_TRAINING_STAGE_U0011;
474 v22bis_equalizer_coefficient_reset(s);
475 v22bis_report_status_change(s, SIG_STATUS_MODEM_RETRAIN_OCCURRED);
476 }
477 s->rx.pattern_repeats = 0;
478 }
479 decode_baud(s, nearest);
480 break;
481 case V22BIS_RX_TRAINING_STAGE_SYMBOL_ACQUISITION:
482 /* Allow time for the Gardner algorithm to settle the symbol timing. */
483 target = &z;
484 if (++s->rx.training_count >= 40)
485 {
486 /* QAM and Gardner only play nicely with heavy damping, so we need to change to
487 a slow rate of symbol timing adaption. However, it must not be so slow that it
488 cannot track the worst case timing error specified in V.22bis. This should be 0.01%,
489 but since we might be off in the opposite direction from the source, the total
490 error could be higher. */
491 s->rx.gardner_step = 4;
492 s->rx.pattern_repeats = 0;
493 if (s->calling_party)
494 s->rx.training = V22BIS_RX_TRAINING_STAGE_UNSCRAMBLED_ONES;
495 else
496 s->rx.training = V22BIS_RX_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200;
497 /* Be pessimistic and see what the handshake brings */
498 s->negotiated_bit_rate = 1200;
499 break;
500 }
501 /* Once we have pulled in the symbol timing in a coarse way, use finer
502 steps to fine tune the timing. */
503 if (s->rx.training_count == 30)
504 s->rx.gardner_step = 32;
505 break;
506 case V22BIS_RX_TRAINING_STAGE_UNSCRAMBLED_ONES:
507 /* Calling modem only */
508 /* The calling modem should initially receive unscrambled ones at 1200bps */
509 target = &v22bis_constellation[nearest];
510 track_carrier(s, &z, target);
511 raw_bits = phase_steps[((nearest >> 2) - (s->rx.constellation_state >> 2)) & 3];
512 s->rx.constellation_state = nearest;
513 if (raw_bits != s->rx.last_raw_bits)
514 s->rx.pattern_repeats = 0;
515 else
516 s->rx.pattern_repeats++;
517 if (++s->rx.training_count == ms_to_symbols(155 + 456))
518 {
519 /* After the first 155ms things should have been steady, so check if the last 456ms was
520 steady at 11 or 00. */
521 if (raw_bits == s->rx.last_raw_bits
522 &&
523 (raw_bits == 0x3 || raw_bits == 0x0)
524 &&
525 s->rx.pattern_repeats >= ms_to_symbols(456))
526 {
527 /* It looks like the answering machine is sending us a clean unscrambled 11 or 00 */
528 if (s->bit_rate == 2400)
529 {
530 /* Try to establish at 2400bps */
531 span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting U0011 (S1) (Caller)\n");
532 s->tx.training = V22BIS_TX_TRAINING_STAGE_U0011;
533 s->tx.training_count = 0;
534 }
535 else
536 {
537 /* Only try to establish at 1200bps */
538 span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting S11 (1200) (Caller)\n");
539 s->tx.training = V22BIS_TX_TRAINING_STAGE_S11;
540 s->tx.training_count = 0;
541 }
542 }
543 s->rx.pattern_repeats = 0;
544 s->rx.training_count = 0;
545 s->rx.training = V22BIS_RX_TRAINING_STAGE_UNSCRAMBLED_ONES_SUSTAINING;
546 }
547 break;
548 case V22BIS_RX_TRAINING_STAGE_UNSCRAMBLED_ONES_SUSTAINING:
549 /* Calling modem only */
550 /* Wait for the end of the unscrambled ones at 1200bps */
551 target = &v22bis_constellation[nearest];
552 track_carrier(s, &z, target);
553 raw_bits = phase_steps[((nearest >> 2) - (s->rx.constellation_state >> 2)) & 3];
554 s->rx.constellation_state = nearest;
555 if (raw_bits != s->rx.last_raw_bits)
556 {
557 /* This looks like the end of the sustained initial unscrambled 11 or 00 */
558 s->tx.training_count = 0;
559 s->tx.training = V22BIS_TX_TRAINING_STAGE_TIMED_S11;
560 s->rx.training_count = 0;
561 s->rx.training = V22BIS_RX_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200;
562 s->rx.pattern_repeats = 0;
563 }
564 break;
565 case V22BIS_RX_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200:
566 target = &v22bis_constellation[nearest];
567 track_carrier(s, &z, target);
568 tune_equalizer(s, &z, target);
569 raw_bits = phase_steps[((nearest >> 2) - (s->rx.constellation_state >> 2)) & 3];
570 bitstream = decode_baudx(s, nearest);
571 s->rx.training_count++;
572 //span_log(&s->logging, SPAN_LOG_FLOW, "S11 0x%02x 0x%02x 0x%X %d %d %d %d %d\n", raw_bits, nearest, bitstream, s->rx.scrambled_ones_to_date, 0, 0, 0, s->rx.training_count);
573 if (s->negotiated_bit_rate == 1200)
574 {
575 /* Search for the S1 signal */
576 if ((s->rx.last_raw_bits ^ raw_bits) == 0x3)
577 {
578 s->rx.pattern_repeats++;
579 }
580 else
581 {
582 if (s->rx.pattern_repeats >= 15 && (s->rx.last_raw_bits == 0x3 || s->rx.last_raw_bits == 0x0))
583 {
584 /* We should get a full run of 00 11 (about 60 bauds) at the calling modem, but only about 20
585 at the answering modem, as the first 40 are TED settling time. */
586 span_log(&s->logging, SPAN_LOG_FLOW, "+++ S1 detected (%d long)\n", s->rx.pattern_repeats);
587 if (s->bit_rate == 2400)
588 {
589 if (!s->calling_party)
590 {
591 /* Accept establishment at 2400bps */
592 span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting U0011 (S1) (Answerer)\n");
593 s->tx.training = V22BIS_TX_TRAINING_STAGE_U0011;
594 s->tx.training_count = 0;
595 }
596 s->negotiated_bit_rate = 2400;
597 }
598 }
599 s->rx.pattern_repeats = 0;
600 }
601 if (s->rx.training_count >= ms_to_symbols(270))
602 {
603 /* If we haven't seen the S1 signal by now, we are committed to be in 1200bps mode */
604 if (s->calling_party)
605 {
606 span_log(&s->logging, SPAN_LOG_FLOW, "+++ Rx normal operation (1200)\n");
607 /* The transmit side needs to sustain the scrambled ones for a timed period */
608 s->tx.training_count = 0;
609 s->tx.training = V22BIS_TX_TRAINING_STAGE_TIMED_S11;
610 /* Normal reception starts immediately */
611 s->rx.training = V22BIS_RX_TRAINING_STAGE_NORMAL_OPERATION;
612 s->rx.carrier_track_i = 8000.0f;
613 }
614 else
615 {
616 span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting S11 (1200) (Answerer)\n");
617 /* The transmit side needs to sustain the scrambled ones for a timed period */
618 s->tx.training_count = 0;
619 s->tx.training = V22BIS_TX_TRAINING_STAGE_TIMED_S11;
620 /* The receive side needs to wait a timed period, receiving scrambled ones,
621 before entering normal operation. */
622 s->rx.training = V22BIS_RX_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200_SUSTAINING;
623 }
624 }
625 }
626 else
627 {
628 if (s->calling_party)
629 {
630 if (s->rx.training_count >= ms_to_symbols(100 + 450))
631 {
632 span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting 16 way decisions (caller)\n");
633 s->rx.sixteen_way_decisions = TRUE;
634 s->rx.training = V22BIS_RX_TRAINING_STAGE_WAIT_FOR_SCRAMBLED_ONES_AT_2400;
635 s->rx.pattern_repeats = 0;
636 s->rx.carrier_track_i = 8000.0f;
637 }
638 }
639 else
640 {
641 if (s->rx.training_count >= ms_to_symbols(450))
642 {
643 span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting 16 way decisions (answerer)\n");
644 s->rx.sixteen_way_decisions = TRUE;
645 s->rx.training = V22BIS_RX_TRAINING_STAGE_WAIT_FOR_SCRAMBLED_ONES_AT_2400;
646 s->rx.pattern_repeats = 0;
647 }
648 }
649 }
650 break;
651 case V22BIS_RX_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200_SUSTAINING:
652 target = &v22bis_constellation[nearest];
653 track_carrier(s, &z, target);
654 tune_equalizer(s, &z, target);
655 bitstream = decode_baudx(s, nearest);
656 if (++s->rx.training_count > ms_to_symbols(270 + 765))
657 {
658 span_log(&s->logging, SPAN_LOG_FLOW, "+++ Rx normal operation (1200)\n");
659 s->rx.training = V22BIS_RX_TRAINING_STAGE_NORMAL_OPERATION;
660 }
661 break;
662 case V22BIS_RX_TRAINING_STAGE_WAIT_FOR_SCRAMBLED_ONES_AT_2400:
663 target = &v22bis_constellation[nearest];
664 track_carrier(s, &z, target);
665 tune_equalizer(s, &z, target);
666 bitstream = decode_baudx(s, nearest);
667 /* We need 32 sustained 1's to switch into normal operation. */
668 if (bitstream == 0xF)
669 {
670 if (++s->rx.pattern_repeats >= 9)
671 {
672 span_log(&s->logging, SPAN_LOG_FLOW, "+++ Rx normal operation (2400)\n");
673 s->rx.training = V22BIS_RX_TRAINING_STAGE_NORMAL_OPERATION;
674 }
675 }
676 else
677 {
678 s->rx.pattern_repeats = 0;
679 }
680 break;
681 case V22BIS_RX_TRAINING_STAGE_PARKED:
682 default:
683 /* We failed to train! */
684 /* Park here until the carrier drops. */
685 target = &z;
686 break;
687 }
688 s->rx.last_raw_bits = raw_bits;
689 if (s->rx.qam_report)
690 s->rx.qam_report(s->rx.qam_user_data, &z, target, s->rx.constellation_state);
691 }
692 /*- End of function --------------------------------------------------------*/
693
694 SPAN_DECLARE_NONSTD(int) v22bis_rx(v22bis_state_t *s, const int16_t amp[], int len)
695 {
696 int i;
697 int j;
698 int step;
699 complexf_t z;
700 complexf_t zz;
701 int32_t power;
702 complexf_t sample;
703 float ii;
704 float qq;
705
706 for (i = 0; i < len; i++)
707 {
708 /* Complex bandpass filter the signal, using a pair of FIRs, and RRC coeffs shifted
709 to centre at 1200Hz or 2400Hz. The filters support 12 fractional phase shifts, to
710 permit signal extraction very close to the middle of a symbol. */
711 s->rx.rrc_filter[s->rx.rrc_filter_step] =
712 s->rx.rrc_filter[s->rx.rrc_filter_step + V22BIS_RX_FILTER_STEPS] = amp[i];
713 if (++s->rx.rrc_filter_step >= V22BIS_RX_FILTER_STEPS)
714 s->rx.rrc_filter_step = 0;
715
716 /* Calculate the I filter, with an arbitrary phase step, just so we can calculate
717 the signal power of the required carrier, with any guard tone or spillback of our
718 own transmitted signal suppressed. */
719 if (s->calling_party)
720 {
721 ii = rx_pulseshaper_2400_re[6][0]*s->rx.rrc_filter[s->rx.rrc_filter_step];
722 for (j = 1; j < V22BIS_RX_FILTER_STEPS; j++)
723 ii += rx_pulseshaper_2400_re[6][j]*s->rx.rrc_filter[j + s->rx.rrc_filter_step];
724 }
725 else
726 {
727 ii = rx_pulseshaper_1200_re[6][0]*s->rx.rrc_filter[s->rx.rrc_filter_step];
728 for (j = 1; j < V22BIS_RX_FILTER_STEPS; j++)
729 ii += rx_pulseshaper_1200_re[6][j]*s->rx.rrc_filter[j + s->rx.rrc_filter_step];
730 }
731 power = power_meter_update(&(s->rx.rx_power), (int16_t) ii);
732 if (s->rx.signal_present)
733 {
734 /* Look for power below the carrier off point */
735 if (power < s->rx.carrier_off_power)
736 {
737 v22bis_restart(s, s->bit_rate);
738 v22bis_report_status_change(s, SIG_STATUS_CARRIER_DOWN);
739 continue;
740 }
741 }
742 else
743 {
744 /* Look for power exceeding the carrier on point */
745 if (power < s->rx.carrier_on_power)
746 continue;
747 s->rx.signal_present = TRUE;
748 v22bis_report_status_change(s, SIG_STATUS_CARRIER_UP);
749 }
750 if (s->rx.training != V22BIS_RX_TRAINING_STAGE_PARKED)
751 {
752 /* Only spend effort processing this data if the modem is not
753 parked, after a training failure. */
754 z = dds_complexf(&s->rx.carrier_phase, s->rx.carrier_phase_rate);
755 if (s->rx.training == V22BIS_RX_TRAINING_STAGE_SYMBOL_ACQUISITION)
756 {
757 /* Only AGC during the initial symbol acquisition, and then lock the gain. */
758 s->rx.agc_scaling = 0.18f*3.60f/sqrtf(power);
759 }
760 /* Put things into the equalization buffer at T/2 rate. The Gardner algorithm
761 will fiddle the step to align this with the symbols. */
762 if ((s->rx.eq_put_step -= PULSESHAPER_COEFF_SETS) <= 0)
763 {
764 /* Pulse shape while still at the carrier frequency, using a quadrature
765 pair of filters. This results in a properly bandpass filtered complex
766 signal, which can be brought directly to bandband by complex mixing.
767 No further filtering, to remove mixer harmonics, is needed. */
768 step = -s->rx.eq_put_step;
769 if (step > PULSESHAPER_COEFF_SETS - 1)
770 step = PULSESHAPER_COEFF_SETS - 1;
771 s->rx.eq_put_step += PULSESHAPER_COEFF_SETS*40/(3*2);
772 if (s->calling_party)
773 {
774 ii = rx_pulseshaper_2400_re[step][0]*s->rx.rrc_filter[s->rx.rrc_filter_step];
775 qq = rx_pulseshaper_2400_im[step][0]*s->rx.rrc_filter[s->rx.rrc_filter_step];
776 for (j = 1; j < V22BIS_RX_FILTER_STEPS; j++)
777 {
778 ii += rx_pulseshaper_2400_re[step][j]*s->rx.rrc_filter[j + s->rx.rrc_filter_step];
779 qq += rx_pulseshaper_2400_im[step][j]*s->rx.rrc_filter[j + s->rx.rrc_filter_step];
780 }
781 }
782 else
783 {
784 ii = rx_pulseshaper_1200_re[step][0]*s->rx.rrc_filter[s->rx.rrc_filter_step];
785 qq = rx_pulseshaper_1200_im[step][0]*s->rx.rrc_filter[s->rx.rrc_filter_step];
786 for (j = 1; j < V22BIS_RX_FILTER_STEPS; j++)
787 {
788 ii += rx_pulseshaper_1200_re[step][j]*s->rx.rrc_filter[j + s->rx.rrc_filter_step];
789 qq += rx_pulseshaper_1200_im[step][j]*s->rx.rrc_filter[j + s->rx.rrc_filter_step];
790 }
791 }
792 sample.re = ii*s->rx.agc_scaling;
793 sample.im = qq*s->rx.agc_scaling;
794 /* Shift to baseband - since this is done in a full complex form, the
795 result is clean, and requires no further filtering apart from the
796 equalizer. */
797 zz.re = sample.re*z.re - sample.im*z.im;
798 zz.im = -sample.re*z.im - sample.im*z.re;
799 process_half_baud(s, &zz);
800 }
801 }
802 }
803 return 0;
804 }
805 /*- End of function --------------------------------------------------------*/
806
807 SPAN_DECLARE(int) v22bis_rx_fillin(v22bis_state_t *s, int len)
808 {
809 int i;
810
811 /* We want to sustain the current state (i.e carrier on<->carrier off), and
812 try to sustain the carrier phase. We should probably push the filters, as well */
813 span_log(&s->logging, SPAN_LOG_FLOW, "Fill-in %d samples\n", len);
814 if (!s->rx.signal_present)
815 return 0;
816 for (i = 0; i < len; i++)
817 {
818 #if defined(SPANDSP_USE_FIXED_POINTx)
819 dds_advance(&s->rx.carrier_phase, s->rx.carrier_phase_rate);
820 #else
821 dds_advancef(&s->rx.carrier_phase, s->rx.carrier_phase_rate);
822 #endif
823 }
824 /* TODO: Advance the symbol phase the appropriate amount */
825 return 0;
826 }
827 /*- End of function --------------------------------------------------------*/
828
829 int v22bis_rx_restart(v22bis_state_t *s)
830 {
831 vec_zerof(s->rx.rrc_filter, sizeof(s->rx.rrc_filter)/sizeof(s->rx.rrc_filter[0]));
832 s->rx.rrc_filter_step = 0;
833 s->rx.scramble_reg = 0;
834 s->rx.scrambler_pattern_count = 0;
835 s->rx.training = V22BIS_RX_TRAINING_STAGE_SYMBOL_ACQUISITION;
836 s->rx.training_count = 0;
837 s->rx.signal_present = FALSE;
838
839 s->rx.carrier_phase_rate = dds_phase_ratef((s->calling_party) ? 2400.0f : 1200.0f);
840 s->rx.carrier_phase = 0;
841 power_meter_init(&(s->rx.rx_power), 5);
842 v22bis_rx_signal_cutoff(s, -45.5f);
843 s->rx.agc_scaling = 0.0005f*0.025f;
844
845 s->rx.constellation_state = 0;
846 s->rx.sixteen_way_decisions = FALSE;
847
848 equalizer_reset(s);
849
850 s->rx.pattern_repeats = 0;
851 s->rx.last_raw_bits = 0;
852 s->rx.gardner_integrate = 0;
853 s->rx.gardner_step = 256;
854 s->rx.baud_phase = 0;
855 s->rx.training_error = 0.0f;
856 s->rx.total_baud_timing_correction = 0;
857 /* We want the carrier to pull in faster on the answerer side, as it has very little time to adapt. */
858 s->rx.carrier_track_i = (s->calling_party) ? 8000.0f : 40000.0f;
859 s->rx.carrier_track_p = 8000000.0f;
860
861 s->negotiated_bit_rate = 1200;
862
863 return 0;
864 }
865 /*- End of function --------------------------------------------------------*/
866
867 SPAN_DECLARE(void) v22bis_rx_set_qam_report_handler(v22bis_state_t *s, qam_report_handler_t handler, void *user_data)
868 {
869 s->rx.qam_report = handler;
870 s->rx.qam_user_data = user_data;
871 }
872 /*- End of function --------------------------------------------------------*/
873 /*- End of file ------------------------------------------------------------*/

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