Mercurial > hg > audiostuff
diff spandsp-0.0.6pre17/src/v22bis_tx.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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/spandsp-0.0.6pre17/src/v22bis_tx.c Fri Jun 25 15:50:58 2010 +0200 @@ -0,0 +1,705 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * v22bis_tx.c - ITU V.22bis modem transmit part + * + * Written by Steve Underwood <steveu@coppice.org> + * + * Copyright (C) 2004 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: v22bis_tx.c,v 1.64 2009/11/04 15:52:06 steveu Exp $ + */ + +/*! \file */ + +/* THIS IS A WORK IN PROGRESS - It is basically functional, but it is not feature + complete, and doesn't reliably sync over the signal and noise level ranges it should! */ + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#include <stdio.h> +#include <inttypes.h> +#include <stdlib.h> +#include <string.h> +#if defined(HAVE_TGMATH_H) +#include <tgmath.h> +#endif +#if defined(HAVE_MATH_H) +#include <math.h> +#endif +#include "floating_fudge.h" + +#include "spandsp/telephony.h" +#include "spandsp/fast_convert.h" +#include "spandsp/logging.h" +#include "spandsp/complex.h" +#include "spandsp/vector_float.h" +#include "spandsp/complex_vector_float.h" +#include "spandsp/async.h" +#include "spandsp/dds.h" +#include "spandsp/power_meter.h" + +#include "spandsp/v29rx.h" +#include "spandsp/v22bis.h" + +#include "spandsp/private/logging.h" +#include "spandsp/private/v22bis.h" + +#if defined(SPANDSP_USE_FIXED_POINTx) +#include "v22bis_tx_fixed_rrc.h" +#else +#include "v22bis_tx_floating_rrc.h" +#endif + +/* Quoting from the V.22bis spec. + +6.3.1.1 Interworking at 2400 bit/s + +6.3.1.1.1 Calling modem + +a) On connection to line the calling modem shall be conditioned to receive signals + in the high channel at 1200 bit/s and transmit signals in the low channel at 1200 bit/s + in accordance with section 2.5.2.2. It shall apply an ON condition to circuit 107 in accordance + with Recommendation V.25. The modem shall initially remain silent. + +b) After 155 +-10 ms of unscrambled binary 1 has been detected, the modem shall remain silent + for a further 456 +-10 ms then transmit an unscrambled repetitive double dibit pattern of 00 + and 11 at 1200 bit/s for 100 +-3 ms. Following this signal the modem shall transmit scrambled + binary 1 at 1200 bit/s. + +c) If the modem detects scrambled binary 1 in the high channel at 1200 bit/s for 270 +-40 ms, + the handshake shall continue in accordance with section 6.3.1.2.1 c) and d). However, if unscrambled + repetitive double dibit 00 and 11 at 1200 bit/s is detected in the high channel, then at the + end of receipt of this signal the modem shall apply an ON condition to circuit 112. + +d) 600 +-10 ms after circuit 112 has been turned ON the modem shall begin transmitting scrambled + binary 1 at 2400 bit/s, and 450 +-10 ms after circuit 112 has been turned ON the receiver may + begin making 16-way decisions. + +e) Following transmission of scrambled binary 1 at 2400 bit/s for 200 +-10 ms, circuit 106 shall + be conditioned to respond to circuit 105 and the modem shall be ready to transmit data at + 2400 bit/s. + +f) When 32 consecutive bits of scrambled binary 1 at 2400 bit/s have been detected in the high + channel the modem shall be ready to receive data at 2400 bit/s and shall apply an ON condition + to circuit 109. + +6.3.1.1.2 Answering modem + +a) On connection to line the answering modem shall be conditioned to transmit signals in the high + channel at 1200 bit/s in accordance with section 2.5.2.2 and receive signals in the low channel at + 1200 bit/s. Following transmission of the answer sequence in accordance with Recommendation + V.25, the modem shall apply an ON condition to circuit 107 and then transmit unscrambled + binary 1 at 1200 bit/s. + +b) If the modem detects scrambled binary 1 or 0 in the low channel at 1200 bit/s for 270 +-40 ms, + the handshake shall continue in accordance with section 6.3.1.2.2 b) and c). However, if unscrambled + repetitive double dibit 00 and 11 at 1200 bit/s is detected in the low channel, at the end of + receipt of this signal the modem shall apply an ON condition to circuit 112 and then transmit + an unscrambled repetitive double dibit pattern of 00 and 11 at 1200 bit/s for 100 +-3 ms. + Following these signals the modem shall transmit scrambled binary 1 at 1200 bit/s. + +c) 600 +-10 ms after circuit 112 has been turned ON the modem shall begin transmitting scrambled + binary 1 at 2400 bit/s, and 450 +-10 ms after circuit 112 has been turned ON the receiver may + begin making 16-way decisions. + +d) Following transmission of scrambled binary 1 at 2400 bit/s for 200 +-10 ms, circuit 106 shall + be conditioned to respond to circuit 105 and the modem shall be ready to transmit data at + 2400 bit/s. + +e) When 32 consecutive bits of scrambled binary 1 at 2400 bit/s have been detected in the low + channel the modem shall be ready to receive data at 2400 bit/s and shall apply an ON + condition to circuit 109. + +6.3.1.2 Interworking at 1200 bit/s + +The following handshake is identical to the Recommendation V.22 alternative A and B handshake. + +6.3.1.2.1 Calling modem + +a) On connection to line the calling modem shall be conditioned to receive signals in the high + channel at 1200 bit/s and transmit signals in the low channel at 1200 bit/s in accordance + with section 2.5.2.2. It shall apply an ON condition to circuit 107 in accordance with + Recommendation V.25. The modem shall initially remain silent. + +b) After 155 +-10 ms of unscrambled binary 1 has been detected, the modem shall remain silent + for a further 456 +-10 ms then transmit scrambled binary 1 at 1200 bit/s (a preceding V.22 bis + signal, as shown in Figure 7/V.22 bis, would not affect the operation of a V.22 answer modem). + +c) On detection of scrambled binary 1 in the high channel at 1200 bit/s for 270 +-40 ms the modem + shall be ready to receive data at 1200 bit/s and shall apply an ON condition to circuit 109 and + an OFF condition to circuit 112. + +d) 765 +-10 ms after circuit 109 has been turned ON, circuit 106 shall be conditioned to respond + to circuit 105 and the modem shall be ready to transmit data at 1200 bit/s. + +6.3.1.2.2 Answering modem + +a) On connection to line the answering modem shall be conditioned to transmit signals in the high + channel at 1200 bit/s in accordance with section 2.5.2.2 and receive signals in the low channel at + 1200 bit/s. + + Following transmission of the answer sequence in accordance with V.25 the modem shall apply + an ON condition to circuit 107 and then transmit unscrambled binary 1 at 1200 bit/s. + +b) On detection of scrambled binary 1 or 0 in the low channel at 1200 bit/s for 270 +-40 ms the + modem shall apply an OFF condition to circuit 112 and shall then transmit scrambled binary 1 + at 1200 bit/s. + +c) After scrambled binary 1 has been transmitted at 1200 bit/s for 765 +-10 ms the modem shall be + ready to transmit and receive data at 1200 bit/s, shall condition circuit 106 to respond to + circuit 105 and shall apply an ON condition to circuit 109. + +Note - Manufacturers may wish to note that in certain countries, for national purposes, modems are + in service which emit an answering tone of 2225 Hz instead of unscrambled binary 1. + + +V.22bis to V.22bis +------------------ +Calling party + S1 scrambled 1's scrambled 1's data + at 1200bps at 2400bps +|---------------------------------------------------------|XXXXXXXX|XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|XXXXXXXXXXXXXX|XXXXXXXXXXXXX + |<155+-10>|<456+-10>|<100+-3>| |<------600+-10------>|<---200+-10-->| + ^ | ^<----450+-100---->|[16 way decisions begin] + | | | + | v | + | |<------450+-100----->|[16 way decisions begin] + | |<----------600+-10-------->| + |<2150+-350>|<--3300+-700->|<75+-20>| |<100+-3>| |<---200+-10--> + |-----------|XXXXXXXXXXXXXX|--------|XXXXXXXXXXXXXXXXXXXXXXXXXXXX|XXXXXXXX|XXXXXXXXXXXXXXXXXX|XXXXXXXXXXXXXX|XXXXXXXXXXXXX + silence 2100Hz unscrambled 1's S1 scrambled 1's scrambled 1's data + at 1200bps at 1200bps at 2400bps +Answering party + +S1 = Unscrambled double dibit 00 and 11 at 1200bps +When the 2400bps section starts, both sides should look for 32 bits of continuous ones, as a test of integrity. + + + + +V.22 to V.22bis +--------------- +Calling party + scrambled 1's data + at 1200bps +|---------------------------------------------------------|XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|XXXXXXXXXXXXX + |<155+-10>|<456+-10>| |<270+-40>|<--------765+-10-------->| + ^ | ^ + | | | + | | | + | | | + | v | + |<2150+-350>|<--3300+-700->|<75+-20>| |<270+-40>|<---------765+-10-------->| + |-----------|XXXXXXXXXXXXXX|--------|XXXXXXXXXXXXXXXXXXXXXXXXXXXXX|XXXXXXXXXXXXXXXXXXXXXXXXXX|XXXXXXXXXXXXX + silence 2100Hz unscrambled 1's scrambled 1's data + at 1200bps at 1200bps +Answering party + +Both ends should accept unscrambled binary 1 or binary 0 as the preamble. + + + + +V.22bis to V.22 +--------------- +Calling party + S1 scrambled 1's data + at 1200bps +|---------------------------------------------------------|XXXXXXXX|XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|XXXXXXXXXXXXX + |<155+-10>|<456+-10>|<100+-3>| |<-270+-40-><------765+-10------>| + ^ | ^ + | | | + | v | + | | + | | + |<2150+-350>|<--3300+-700->|<75+-20>| |<-270+-40->|<------765+-10----->| + |-----------|XXXXXXXXXXXXXX|--------|XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|XXXXXXXXXXXXXXXXXXXX|XXXXXXXXXXXXX + silence 2100Hz unscrambled 1's scrambled 1's data + at 1200bps at 1200bps +Answering party + +Both ends should accept unscrambled binary 1 or binary 0 as the preamble. +*/ + +#define ms_to_symbols(t) (((t)*600)/1000) + +static const int phase_steps[4] = +{ + 1, 0, 2, 3 +}; + +const complexf_t v22bis_constellation[16] = +{ + { 1.0f, 1.0f}, + { 3.0f, 1.0f}, /* 1200bps 00 */ + { 1.0f, 3.0f}, + { 3.0f, 3.0f}, + {-1.0f, 1.0f}, + {-1.0f, 3.0f}, /* 1200bps 01 */ + {-3.0f, 1.0f}, + {-3.0f, 3.0f}, + {-1.0f, -1.0f}, + {-3.0f, -1.0f}, /* 1200bps 10 */ + {-1.0f, -3.0f}, + {-3.0f, -3.0f}, + { 1.0f, -1.0f}, + { 1.0f, -3.0f}, /* 1200bps 11 */ + { 3.0f, -1.0f}, + { 3.0f, -3.0f} +}; + +static int fake_get_bit(void *user_data) +{ + return 1; +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ int scramble(v22bis_state_t *s, int bit) +{ + int out_bit; + + if (s->tx.scrambler_pattern_count >= 64) + { + bit ^= 1; + s->tx.scrambler_pattern_count = 0; + } + out_bit = (bit ^ (s->tx.scramble_reg >> 13) ^ (s->tx.scramble_reg >> 16)) & 1; + s->tx.scramble_reg = (s->tx.scramble_reg << 1) | out_bit; + + if (out_bit == 1) + s->tx.scrambler_pattern_count++; + else + s->tx.scrambler_pattern_count = 0; + return out_bit; +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ int get_scrambled_bit(v22bis_state_t *s) +{ + int bit; + + if ((bit = s->tx.current_get_bit(s->get_bit_user_data)) == SIG_STATUS_END_OF_DATA) + { + /* Fill out this symbol with ones, and prepare to send + the rest of the shutdown sequence. */ + s->tx.current_get_bit = fake_get_bit; + s->tx.shutdown = 1; + bit = 1; + } + return scramble(s, bit); +} +/*- End of function --------------------------------------------------------*/ + +static complexf_t training_get(v22bis_state_t *s) +{ + complexf_t z; + int bits; + + /* V.22bis training sequence */ + switch (s->tx.training) + { + case V22BIS_TX_TRAINING_STAGE_INITIAL_TIMED_SILENCE: + /* The answerer waits 75ms, then sends unscrambled ones */ + if (++s->tx.training_count >= ms_to_symbols(75)) + { + /* Initial 75ms of silence is over */ + span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting U11 1200\n"); + s->tx.training_count = 0; + s->tx.training = V22BIS_TX_TRAINING_STAGE_U11; + } + /* Fall through */ + case V22BIS_TX_TRAINING_STAGE_INITIAL_SILENCE: + /* Silence */ + s->tx.constellation_state = 0; + z = complex_setf(0.0f, 0.0f); + break; + case V22BIS_TX_TRAINING_STAGE_U11: + /* Send continuous unscrambled ones at 1200bps (i.e. 270 degree phase steps). */ + /* Only the answering modem sends unscrambled ones. It is the first thing exchanged between the modems. */ + s->tx.constellation_state = (s->tx.constellation_state + phase_steps[3]) & 3; + z = v22bis_constellation[(s->tx.constellation_state << 2) | 0x01]; + break; + case V22BIS_TX_TRAINING_STAGE_U0011: + /* Continuous unscrambled double dibit 00 11 at 1200bps. This is termed the S1 segment in + the V.22bis spec. It is only sent to request or accept 2400bps mode, and lasts 100+-3ms. After this + timed burst, we unconditionally change to sending scrambled ones at 1200bps. */ + s->tx.constellation_state = (s->tx.constellation_state + phase_steps[3*(s->tx.training_count & 1)]) & 3; + z = v22bis_constellation[(s->tx.constellation_state << 2) | 0x01]; + if (++s->tx.training_count >= ms_to_symbols(100)) + { + span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting S11 after U0011\n"); + if (s->calling_party) + { + s->tx.training_count = 0; + s->tx.training = V22BIS_TX_TRAINING_STAGE_S11; + } + else + { + s->tx.training_count = ms_to_symbols(756 - (600 - 100)); + s->tx.training = V22BIS_TX_TRAINING_STAGE_TIMED_S11; + } + } + break; + case V22BIS_TX_TRAINING_STAGE_TIMED_S11: + /* A timed period of scrambled ones at 1200bps. */ + if (++s->tx.training_count >= ms_to_symbols(756)) + { + if (s->negotiated_bit_rate == 2400) + { + span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting S1111 (C)\n"); + s->tx.training_count = 0; + s->tx.training = V22BIS_TX_TRAINING_STAGE_S1111; + } + else + { + span_log(&s->logging, SPAN_LOG_FLOW, "+++ Tx normal operation (1200)\n"); + s->tx.training_count = 0; + s->tx.training = V22BIS_TX_TRAINING_STAGE_NORMAL_OPERATION; + v22bis_report_status_change(s, SIG_STATUS_TRAINING_SUCCEEDED); + s->tx.current_get_bit = s->get_bit; + } + } + /* Fall through */ + case V22BIS_TX_TRAINING_STAGE_S11: + /* Scrambled ones at 1200bps. */ + bits = scramble(s, 1); + bits = (bits << 1) | scramble(s, 1); + s->tx.constellation_state = (s->tx.constellation_state + phase_steps[bits]) & 3; + z = v22bis_constellation[(s->tx.constellation_state << 2) | 0x01]; + break; + case V22BIS_TX_TRAINING_STAGE_S1111: + /* Scrambled ones at 2400bps. We send a timed 200ms burst, and switch to normal operation at 2400bps */ + bits = scramble(s, 1); + bits = (bits << 1) | scramble(s, 1); + s->tx.constellation_state = (s->tx.constellation_state + phase_steps[bits]) & 3; + bits = scramble(s, 1); + bits = (bits << 1) | scramble(s, 1); + z = v22bis_constellation[(s->tx.constellation_state << 2) | bits]; + if (++s->tx.training_count >= ms_to_symbols(200)) + { + /* We have completed training. Now handle some real work. */ + span_log(&s->logging, SPAN_LOG_FLOW, "+++ Tx normal operation (2400)\n"); + s->tx.training_count = 0; + s->tx.training = V22BIS_TX_TRAINING_STAGE_NORMAL_OPERATION; + v22bis_report_status_change(s, SIG_STATUS_TRAINING_SUCCEEDED); + s->tx.current_get_bit = s->get_bit; + } + break; + case V22BIS_TX_TRAINING_STAGE_PARKED: + default: + z = complex_setf(0.0f, 0.0f); + break; + } + return z; +} +/*- End of function --------------------------------------------------------*/ + +static complexf_t getbaud(v22bis_state_t *s) +{ + int bits; + + if (s->tx.training) + { + /* Send the training sequence */ + return training_get(s); + } + + /* There is no graceful shutdown procedure defined for V.22bis. Just + send some ones, to ensure we get the real data bits through, even + with bad ISI. */ + if (s->tx.shutdown) + { + if (++s->tx.shutdown > 10) + return complex_setf(0.0f, 0.0f); + } + /* The first two bits define the quadrant */ + bits = get_scrambled_bit(s); + bits = (bits << 1) | get_scrambled_bit(s); + s->tx.constellation_state = (s->tx.constellation_state + phase_steps[bits]) & 3; + if (s->negotiated_bit_rate == 1200) + { + bits = 0x01; + } + else + { + /* The other two bits define the position within the quadrant */ + bits = get_scrambled_bit(s); + bits = (bits << 1) | get_scrambled_bit(s); + } + return v22bis_constellation[(s->tx.constellation_state << 2) | bits]; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE_NONSTD(int) v22bis_tx(v22bis_state_t *s, int16_t amp[], int len) +{ + complexf_t x; + complexf_t z; + int i; + int sample; + float famp; + + if (s->tx.shutdown > 10) + return 0; + for (sample = 0; sample < len; sample++) + { + if ((s->tx.baud_phase += 3) >= 40) + { + s->tx.baud_phase -= 40; + s->tx.rrc_filter[s->tx.rrc_filter_step] = + s->tx.rrc_filter[s->tx.rrc_filter_step + V22BIS_TX_FILTER_STEPS] = getbaud(s); + if (++s->tx.rrc_filter_step >= V22BIS_TX_FILTER_STEPS) + s->tx.rrc_filter_step = 0; + } + /* Root raised cosine pulse shaping at baseband */ + x = complex_setf(0.0f, 0.0f); + for (i = 0; i < V22BIS_TX_FILTER_STEPS; i++) + { + x.re += tx_pulseshaper[39 - s->tx.baud_phase][i]*s->tx.rrc_filter[i + s->tx.rrc_filter_step].re; + x.im += tx_pulseshaper[39 - s->tx.baud_phase][i]*s->tx.rrc_filter[i + s->tx.rrc_filter_step].im; + } + /* Now create and modulate the carrier */ + z = dds_complexf(&(s->tx.carrier_phase), s->tx.carrier_phase_rate); + famp = (x.re*z.re - x.im*z.im)*s->tx.gain; + if (s->tx.guard_phase_rate && (s->tx.rrc_filter[s->tx.rrc_filter_step].re != 0.0f || s->tx.rrc_filter[i + s->tx.rrc_filter_step].im != 0.0f)) + { + /* Add the guard tone */ + famp += dds_modf(&(s->tx.guard_phase), s->tx.guard_phase_rate, s->tx.guard_level, 0); + } + /* Don't bother saturating. We should never clip. */ + amp[sample] = (int16_t) lfastrintf(famp); + } + return sample; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(void) v22bis_tx_power(v22bis_state_t *s, float power) +{ + float l; + + if (s->tx.guard_phase_rate == dds_phase_ratef(550.0f)) + { + l = 1.6f*powf(10.0f, (power - 1.0f - DBM0_MAX_POWER)/20.0f); + s->tx.gain = l*32768.0f/(TX_PULSESHAPER_GAIN*3.0f); + l = powf(10.0f, (power - 1.0f - 3.0f - DBM0_MAX_POWER)/20.0f); + s->tx.guard_level = l*32768.0f; + } + else if(s->tx.guard_phase_rate == dds_phase_ratef(1800.0f)) + { + l = 1.6f*powf(10.0f, (power - 1.0f - 1.0f - DBM0_MAX_POWER)/20.0f); + s->tx.gain = l*32768.0f/(TX_PULSESHAPER_GAIN*3.0f); + l = powf(10.0f, (power - 1.0f - 6.0f - DBM0_MAX_POWER)/20.0f); + s->tx.guard_level = l*32768.0f; + } + else + { + l = 1.6f*powf(10.0f, (power - DBM0_MAX_POWER)/20.0f); + s->tx.gain = l*32768.0f/(TX_PULSESHAPER_GAIN*3.0f); + s->tx.guard_level = 0; + } +} +/*- End of function --------------------------------------------------------*/ + +static int v22bis_tx_restart(v22bis_state_t *s) +{ + cvec_zerof(s->tx.rrc_filter, sizeof(s->tx.rrc_filter)/sizeof(s->tx.rrc_filter[0])); + s->tx.rrc_filter_step = 0; + s->tx.scramble_reg = 0; + s->tx.scrambler_pattern_count = 0; + if (s->calling_party) + s->tx.training = V22BIS_TX_TRAINING_STAGE_INITIAL_SILENCE; + else + s->tx.training = V22BIS_TX_TRAINING_STAGE_INITIAL_TIMED_SILENCE; + s->tx.training_count = 0; + s->tx.carrier_phase = 0; + s->tx.guard_phase = 0; + s->tx.baud_phase = 0; + s->tx.constellation_state = 0; + s->tx.current_get_bit = fake_get_bit; + s->tx.shutdown = 0; + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(void) v22bis_set_get_bit(v22bis_state_t *s, get_bit_func_t get_bit, void *user_data) +{ + s->get_bit = get_bit; + s->get_bit_user_data = user_data; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(void) v22bis_set_put_bit(v22bis_state_t *s, put_bit_func_t put_bit, void *user_data) +{ + s->put_bit = put_bit; + s->put_bit_user_data = user_data; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(void) v22bis_set_modem_status_handler(v22bis_state_t *s, modem_tx_status_func_t handler, void *user_data) +{ + s->status_handler = handler; + s->status_user_data = user_data; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(logging_state_t *) v22bis_get_logging_state(v22bis_state_t *s) +{ + return &s->logging; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v22bis_restart(v22bis_state_t *s, int bit_rate) +{ + switch (bit_rate) + { + case 2400: + case 1200: + break; + default: + return -1; + } + s->bit_rate = bit_rate; + s->negotiated_bit_rate = 1200; + if (v22bis_tx_restart(s)) + return -1; + return v22bis_rx_restart(s); +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v22bis_request_retrain(v22bis_state_t *s, int bit_rate) +{ + /* TODO: support bit rate switching */ + switch (bit_rate) + { + case 2400: + case 1200: + break; + default: + return -1; + } + /* TODO: support bit rate changes */ + /* Retrain is only valid when we are normal operation at 2400bps */ + if (s->rx.training != V22BIS_RX_TRAINING_STAGE_NORMAL_OPERATION + || + s->tx.training != V22BIS_TX_TRAINING_STAGE_NORMAL_OPERATION + || + s->negotiated_bit_rate != 2400) + { + return -1; + } + /* Send things back into the training process at the appropriate point. + The far end should detect the S1 signal, and reciprocate. */ + span_log(&s->logging, SPAN_LOG_FLOW, "+++ Initiating a retrain\n"); + s->rx.pattern_repeats = 0; + s->rx.training_count = 0; + s->rx.training = V22BIS_RX_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200; + s->tx.training_count = 0; + s->tx.training = V22BIS_TX_TRAINING_STAGE_U0011; + v22bis_equalizer_coefficient_reset(s); + v22bis_report_status_change(s, SIG_STATUS_MODEM_RETRAIN_OCCURRED); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v22bis_remote_loopback(v22bis_state_t *s, int enable) +{ + /* TODO: */ + return -1; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v22bis_current_bit_rate(v22bis_state_t *s) +{ + return s->negotiated_bit_rate; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(v22bis_state_t *) v22bis_init(v22bis_state_t *s, + int bit_rate, + int guard, + int calling_party, + get_bit_func_t get_bit, + void *get_bit_user_data, + put_bit_func_t put_bit, + void *put_bit_user_data) +{ + switch (bit_rate) + { + case 2400: + case 1200: + break; + default: + return NULL; + } + if (s == NULL) + { + if ((s = (v22bis_state_t *) malloc(sizeof(*s))) == NULL) + return NULL; + } + memset(s, 0, sizeof(*s)); + span_log_init(&s->logging, SPAN_LOG_NONE, NULL); + span_log_set_protocol(&s->logging, "V.22bis"); + s->bit_rate = bit_rate; + s->calling_party = calling_party; + + s->get_bit = get_bit; + s->get_bit_user_data = get_bit_user_data; + s->put_bit = put_bit; + s->put_bit_user_data = put_bit_user_data; + + if (s->calling_party) + { + s->tx.carrier_phase_rate = dds_phase_ratef(1200.0f); + } + else + { + s->tx.carrier_phase_rate = dds_phase_ratef(2400.0f); + switch (guard) + { + case V22BIS_GUARD_TONE_550HZ: + s->tx.guard_phase_rate = dds_phase_ratef(550.0f); + break; + case V22BIS_GUARD_TONE_1800HZ: + s->tx.guard_phase_rate = dds_phase_ratef(1800.0f); + break; + default: + s->tx.guard_phase_rate = 0; + break; + } + } + v22bis_tx_power(s, -14.0f); + v22bis_restart(s, s->bit_rate); + return s; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v22bis_release(v22bis_state_t *s) +{ + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) v22bis_free(v22bis_state_t *s) +{ + free(s); + return 0; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/