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 ------------------------------------------------------------*/

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