Mercurial > hg > audiostuff
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 ------------------------------------------------------------*/ |
