freeswitch/libs/spandsp/src/v22bis_tx.c

763 lines
30 KiB
C

/*
* 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.
*/
/*! \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
#if defined(HAVE_STDBOOL_H)
#include <stdbool.h>
#else
#include "spandsp/stdbool.h"
#endif
#include "floating_fudge.h"
#include "spandsp/telephony.h"
#include "spandsp/alloc.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/vector_int.h"
#include "spandsp/complex_vector_int.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/power_meter.h"
#include "spandsp/private/v22bis.h"
#if defined(SPANDSP_USE_FIXED_POINT)
#define FP_SCALE(x) FP_Q6_10(x)
#else
#define FP_SCALE(x) (x)
#endif
#include "v22bis_tx_rrc.h"
/* 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
};
#if defined(SPANDSP_USE_FIXED_POINT)
const complexi16_t v22bis_constellation[16] =
#else
const complexf_t v22bis_constellation[16] =
#endif
{
{FP_SCALE( 1.0f), FP_SCALE( 1.0f)},
{FP_SCALE( 3.0f), FP_SCALE( 1.0f)}, /* 1200bps 00 */
{FP_SCALE( 1.0f), FP_SCALE( 3.0f)},
{FP_SCALE( 3.0f), FP_SCALE( 3.0f)},
{FP_SCALE(-1.0f), FP_SCALE( 1.0f)},
{FP_SCALE(-1.0f), FP_SCALE( 3.0f)}, /* 1200bps 01 */
{FP_SCALE(-3.0f), FP_SCALE( 1.0f)},
{FP_SCALE(-3.0f), FP_SCALE( 3.0f)},
{FP_SCALE(-1.0f), FP_SCALE(-1.0f)},
{FP_SCALE(-3.0f), FP_SCALE(-1.0f)}, /* 1200bps 10 */
{FP_SCALE(-1.0f), FP_SCALE(-3.0f)},
{FP_SCALE(-3.0f), FP_SCALE(-3.0f)},
{FP_SCALE( 1.0f), FP_SCALE(-1.0f)},
{FP_SCALE( 1.0f), FP_SCALE(-3.0f)}, /* 1200bps 11 */
{FP_SCALE( 3.0f), FP_SCALE(-1.0f)},
{FP_SCALE( 3.0f), FP_SCALE(-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 --------------------------------------------------------*/
#if defined(SPANDSP_USE_FIXED_POINT)
static complexi16_t training_get(v22bis_state_t *s)
#else
static complexf_t training_get(v22bis_state_t *s)
#endif
{
#if defined(SPANDSP_USE_FIXED_POINT)
static const complexi16_t zero = {0, 0};
#else
static const complexf_t zero = {0.0f, 0.0f};
#endif
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;
return zero;
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;
return v22bis_constellation[(s->tx.constellation_state << 2) | 0x01];
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;
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;
}
}
return v22bis_constellation[(s->tx.constellation_state << 2) | 0x01];
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;
return v22bis_constellation[(s->tx.constellation_state << 2) | 0x01];
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);
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;
}
return v22bis_constellation[(s->tx.constellation_state << 2) | bits];
}
return zero;
}
/*- End of function --------------------------------------------------------*/
#if defined(SPANDSP_USE_FIXED_POINT)
static complexi16_t getbaud(v22bis_state_t *s)
#else
static complexf_t getbaud(v22bis_state_t *s)
#endif
{
#if defined(SPANDSP_USE_FIXED_POINT)
static const complexi16_t zero = {0, 0};
#else
static const complexf_t zero = {0.0f, 0.0f};
#endif
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 zero;
}
/* 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(int) v22bis_tx(v22bis_state_t *s, int16_t amp[], int len)
{
#if defined(SPANDSP_USE_FIXED_POINT)
complexi16_t v;
complexi32_t x;
complexi32_t z;
int16_t iamp;
#else
complexf_t v;
complexf_t x;
complexf_t z;
float famp;
#endif
int sample;
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;
v = getbaud(s);
s->tx.rrc_filter_re[s->tx.rrc_filter_step] = v.re;
s->tx.rrc_filter_im[s->tx.rrc_filter_step] = v.im;
if (++s->tx.rrc_filter_step >= V22BIS_TX_FILTER_STEPS)
s->tx.rrc_filter_step = 0;
}
#if defined(SPANDSP_USE_FIXED_POINT)
/* Root raised cosine pulse shaping at baseband */
x.re = vec_circular_dot_prodi16(s->tx.rrc_filter_re, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->tx.baud_phase], V22BIS_TX_FILTER_STEPS, s->tx.rrc_filter_step) >> 14;
x.im = vec_circular_dot_prodi16(s->tx.rrc_filter_im, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->tx.baud_phase], V22BIS_TX_FILTER_STEPS, s->tx.rrc_filter_step) >> 14;
/* Now create and modulate the carrier */
z = dds_complexi32(&s->tx.carrier_phase, s->tx.carrier_phase_rate);
iamp = (x.re*z.re - x.im*z.im) >> 15;
iamp = (int16_t) (((int32_t) iamp*s->tx.gain) >> 11);
if (s->tx.guard_phase_rate && (s->tx.rrc_filter_re[s->tx.rrc_filter_step] != 0 || s->tx.rrc_filter_im[s->tx.rrc_filter_step] != 0))
{
/* Add the guard tone */
iamp += dds_mod(&s->tx.guard_phase, s->tx.guard_phase_rate, s->tx.guard_tone_gain, 0);
}
/* Don't bother saturating. We should never clip. */
amp[sample] = iamp;
#else
/* Root raised cosine pulse shaping at baseband */
x.re = vec_circular_dot_prodf(s->tx.rrc_filter_re, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->tx.baud_phase], V22BIS_TX_FILTER_STEPS, s->tx.rrc_filter_step);
x.im = vec_circular_dot_prodf(s->tx.rrc_filter_im, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->tx.baud_phase], V22BIS_TX_FILTER_STEPS, s->tx.rrc_filter_step);
/* 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_re[s->tx.rrc_filter_step] != 0.0f || s->tx.rrc_filter_im[s->tx.rrc_filter_step] != 0.0f))
{
/* Add the guard tone */
famp += dds_modf(&s->tx.guard_phase, s->tx.guard_phase_rate, s->tx.guard_tone_gain, 0);
}
/* Don't bother saturating. We should never clip. */
amp[sample] = (int16_t) lfastrintf(famp);
#endif
}
return sample;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(void) v22bis_tx_power(v22bis_state_t *s, float power)
{
float sig_power;
float guard_tone_power;
float sig_gain;
float guard_tone_gain;
/* If is there is a guard tone we need to scale down the signal power a bit, so the aggregate of the signal
and guard tone power is the specified power. */
if (s->tx.guard_phase_rate == dds_phase_ratef(550.0f))
{
sig_power = power - 1.0f;
guard_tone_power = sig_power - 3.0f;
}
else if(s->tx.guard_phase_rate == dds_phase_ratef(1800.0f))
{
sig_power = power - 0.55f;
guard_tone_power = sig_power - 6.0f;
}
else
{
sig_power = power;
guard_tone_power = -9999.0f;
}
sig_gain = 0.4490f*powf(10.0f, (sig_power - DBM0_MAX_POWER)/20.0f)*32768.0f/TX_PULSESHAPER_GAIN;
guard_tone_gain = powf(10.0f, (guard_tone_power - DBM0_MAX_POWER)/20.0f)*32768.0f;
#if defined(SPANDSP_USE_FIXED_POINT)
s->tx.gain = (int16_t) sig_gain;
s->tx.guard_tone_gain = (int16_t) guard_tone_gain;
#else
s->tx.gain = sig_gain;
s->tx.guard_tone_gain = guard_tone_gain;
#endif
}
/*- End of function --------------------------------------------------------*/
static int v22bis_tx_restart(v22bis_state_t *s)
{
#if defined(SPANDSP_USE_FIXED_POINT)
vec_zeroi16(s->tx.rrc_filter_re, sizeof(s->tx.rrc_filter_re)/sizeof(s->tx.rrc_filter_re[0]));
vec_zeroi16(s->tx.rrc_filter_im, sizeof(s->tx.rrc_filter_im)/sizeof(s->tx.rrc_filter_im[0]));
#else
vec_zerof(s->tx.rrc_filter_re, sizeof(s->tx.rrc_filter_re)/sizeof(s->tx.rrc_filter_re[0]));
vec_zerof(s->tx.rrc_filter_im, sizeof(s->tx.rrc_filter_im)/sizeof(s->tx.rrc_filter_im[0]));
#endif
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_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, bool enable)
{
/* TODO: */
return -1;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) v22bis_get_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,
bool 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 *) span_alloc(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)
{
span_free(s);
return 0;
}
/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/