diff spandsp-0.0.3/spandsp-0.0.3/src/v22bis_tx.c @ 5:f762bf195c4b

import spandsp-0.0.3
author Peter Meerwald <pmeerw@cosy.sbg.ac.at>
date Fri, 25 Jun 2010 16:00:21 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spandsp-0.0.3/spandsp-0.0.3/src/v22bis_tx.c	Fri Jun 25 16:00:21 2010 +0200
@@ -0,0 +1,1107 @@
+/*
+ * 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 General Public License version 2, 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.34 2006/11/28 16:59:57 steveu Exp $
+ */
+
+/*! \file */
+
+/* THIS IS A WORK IN PROGRESS - NOT YET FUNCTIONAL! */
+
+#ifdef 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 "spandsp/telephony.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"
+
+/* 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)
+
+/* Segments of the training sequence */
+enum
+{
+    V22BIS_TRAINING_STAGE_NORMAL_OPERATION = 0,
+    V22BIS_TRAINING_STAGE_INITIAL_SILENCE,
+    V22BIS_TRAINING_STAGE_UNSCRAMBLED_ONES,
+    V22BIS_TRAINING_STAGE_UNSCRAMBLED_0011,
+    V22BIS_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200,
+    V22BIS_TRAINING_STAGE_SCRAMBLED_ONES_AT_2400,
+    V22BIS_TRAINING_STAGE_PARKED
+};
+
+static const int phase_steps[4] =
+{
+    1, 0, 2, 3
+};
+
+const complexf_t v22bis_constellation[16] =
+{
+    { 1.0f,  1.0f},
+    { 3.0f,  1.0f},
+    { 1.0f,  3.0f},
+    { 3.0f,  3.0f},
+    {-1.0f,  1.0f},
+    {-1.0f,  3.0f},
+    {-3.0f,  1.0f},
+    {-3.0f,  3.0f},
+    {-1.0f, -1.0f},
+    {-3.0f, -1.0f},
+    {-1.0f, -3.0f},
+    {-3.0f, -3.0f},
+    { 1.0f, -1.0f},
+    { 1.0f, -3.0f},
+    { 3.0f, -1.0f},
+    { 3.0f, -3.0f}
+};
+
+/* Raised root cosine pulse shaping; Beta = 0.75; 4 symbols either
+   side of the centre. */
+/* Created with mkshape -r 0.0125 0.75 361 -l and then split up */
+#define PULSESHAPER_GAIN            (40.000612087f/40.0f)
+#define PULSESHAPER_COEFF_SETS      40
+
+static const float pulseshaper[PULSESHAPER_COEFF_SETS][V22BIS_TX_FILTER_STEPS] =
+{
+    {
+        -0.0047287346f,         /* Filter 0 */
+        -0.0083947197f,
+        -0.0087380763f,
+         0.0088053673f,
+         0.5108981827f,
+         0.5108981827f,
+         0.0088053673f,
+        -0.0087380763f,
+        -0.0083947197f
+    },
+    {
+        -0.0044638629f,         /* Filter 1 */
+        -0.0089241700f,
+        -0.0111288952f,
+         0.0023412184f,
+         0.5623914901f,
+         0.4599551720f,
+         0.0144817755f,
+        -0.0063186648f,
+        -0.0077293609f
+    },
+    {
+        -0.0041048584f,         /* Filter 2 */
+        -0.0093040596f,
+        -0.0134459768f,
+        -0.0048558766f,
+         0.6141017035f,
+         0.4098822897f,
+         0.0193317049f,
+        -0.0039145680f,
+        -0.0069438567f
+    },
+    {
+        -0.0036565006f,         /* Filter 3 */
+        -0.0095231635f,
+        -0.0156437084f,
+        -0.0127148737f,
+         0.6656848457f,
+         0.3609830295f,
+         0.0233320755f,
+        -0.0015677363f,
+        -0.0060557371f
+    },
+    {
+        -0.0031253709f,         /* Filter 4 */
+        -0.0095729633f,
+        -0.0176768181f,
+        -0.0211485021f,
+         0.7167894869f,
+         0.3135419896f,
+         0.0264748749f,
+         0.0006824956f,
+        -0.0050839319f
+    },
+    {
+        -0.0025197700f,         /* Filter 5 */
+        -0.0094478866f,
+        -0.0195012095f,
+        -0.0300535107f,
+         0.7670600056f,
+         0.2678225635f,
+         0.0287663895f,
+         0.0027999985f,
+        -0.0040483891f
+    },
+    {
+        -0.0018496023f,         /* Filter 6 */
+        -0.0091454978f,
+        -0.0210748106f,
+        -0.0393111426f,
+         0.8161399423f,
+         0.2240649005f,
+         0.0302262769f,
+         0.0047523617f,
+        -0.0029696854f
+    },
+    {
+        -0.0011262266f,         /* Filter 7 */
+        -0.0086666380f,
+        -0.0223584207f,
+        -0.0487878398f,
+         0.8636754069f,
+         0.1824841563f,
+         0.0308864956f,
+         0.0065113237f,
+        -0.0018686358f
+    },
+    {
+        -0.0003622774f,         /* Filter 8 */
+        -0.0080155088f,
+        -0.0233165437f,
+        -0.0583361774f,
+         0.9093185032f,
+         0.1432690480f,
+         0.0307901140f,
+         0.0080531155f,
+        -0.0007659096f
+    },
+    {
+         0.0004285425f,         /* Filter 9 */
+        -0.0071996967f,
+        -0.0239181901f,
+        -0.0677960213f,
+         0.9527307304f,
+         0.1065807242f,
+         0.0299900191f,
+         0.0093587151f,
+         0.0003183408f
+    },
+    {
+         0.0012316933f,         /* Filter 10 */
+        -0.0062301368f,
+        -0.0241376359f,
+        -0.0769959031f,
+         0.9935863233f,
+         0.0725519600f,
+         0.0285475474f,
+         0.0104140102f,
+         0.0013648323f
+    },
+    {
+         0.0020320508f,         /* Filter 11 */
+        -0.0051210137f,
+        -0.0239551212f,
+        -0.0857546018f,
+         1.0315754934f,
+         0.0412866769f,
+         0.0265310587f,
+         0.0112098711f,
+         0.0023554782f
+    },
+    {
+         0.0028141763f,         /* Filter 12 */
+        -0.0038896008f,
+        -0.0233574765f,
+        -0.0938829156f,
+         1.0664075323f,
+         0.0128597894f,
+         0.0240144782f,
+         0.0117421344f,
+         0.0032736852f
+    },
+    {
+         0.0035625973f,         /* Filter 13 */
+        -0.0025560369f,
+        -0.0223386620f,
+        -0.1011856112f,
+         1.0978137424f,
+        -0.0126826277f,
+         0.0210758250f,
+         0.0120115019f,
+         0.0041046165f
+    },
+    {
+         0.0042620971f,         /* Filter 14 */
+        -0.0011430452f,
+        -0.0209002083f,
+        -0.1074635265f,
+         1.1255501596f,
+        -0.0353228594f,
+         0.0177957527f,
+         0.0120233576f,
+         0.0048354157f
+    },
+    {
+         0.0048980053f,         /* Filter 15 */
+         0.0003244045f,
+        -0.0190515462f,
+        -0.1125158080f,
+         1.1494000377f,
+        -0.0550707703f,
+         0.0142561191f,
+         0.0117875105f,
+         0.0054553898f
+    },
+    {
+         0.0054564857f,         /* Filter 16 */
+         0.0018194852f,
+        -0.0168102168f,
+        -0.1161422557f,
+         1.1691760633f,
+        -0.0719627404f,
+         0.0105386068f,
+         0.0113178688f,
+         0.0059561483f
+    },
+    {
+         0.0059248154f,         /* Filter 17 */
+         0.0033139475f,
+        -0.0142019526f,
+        -0.1181457502f,
+         1.1847222770f,
+        -0.0860603350f,
+         0.0067234125f,
+         0.0106320540f,
+         0.0063316975f
+    },
+    {
+         0.0062916504f,         /* Filter 18 */
+         0.0047785946f,
+        -0.0112606234f,
+        -0.1183347329f,
+         1.1959156771f,
+        -0.0974487311f,
+         0.0028880206f,
+         0.0097509621f,
+         0.0065784888f
+    },
+    {
+         0.0065472715f,         /* Filter 19 */
+         0.0061837898f,
+        -0.0080280420f,
+        -0.1165257094f,
+         1.2026674866f,
+        -0.1062349247f,
+        -0.0008939235f,
+         0.0086982833f,
+         0.0066954225f
+    },
+    {
+         0.0066838062f,         /* Filter 20 */
+         0.0074999881f,
+        -0.0045536271f,
+        -0.1125457458f,
+         1.2049240699f,
+        -0.1125457458f,
+        -0.0045536271f,
+         0.0074999881f,
+         0.0066838062f
+    },
+    {
+         0.0066954225f,         /* Filter 21 */
+         0.0086982833f,
+        -0.0008939235f,
+        -0.1062349247f,
+         1.2026674866f,
+        -0.1165257094f,
+        -0.0080280420f,
+         0.0061837898f,
+         0.0065472715f
+    },
+    {
+         0.0065784888f,         /* Filter 22 */
+         0.0097509621f,
+         0.0028880206f,
+        -0.0974487311f,
+         1.1959156771f,
+        -0.1183347329f,
+        -0.0112606234f,
+         0.0047785946f,
+         0.0062916504f
+    },
+    {
+         0.0063316975f,         /* Filter 23 */
+         0.0106320540f,
+         0.0067234125f,
+        -0.0860603350f,
+         1.1847222770f,
+        -0.1181457502f,
+        -0.0142019526f,
+         0.0033139475f,
+         0.0059248154f
+    },
+    {
+         0.0059561483f,         /* Filter 24 */
+         0.0113178688f,
+         0.0105386068f,
+        -0.0719627404f,
+         1.1691760633f,
+        -0.1161422557f,
+        -0.0168102168f,
+         0.0018194852f,
+         0.0054564857f
+    },
+    {
+         0.0054553898f,         /* Filter 25 */
+         0.0117875105f,
+         0.0142561191f,
+        -0.0550707703f,
+         1.1494000377f,
+        -0.1125158080f,
+        -0.0190515462f,
+         0.0003244045f,
+         0.0048980053f
+    },
+    {
+         0.0048354157f,         /* Filter 26 */
+         0.0120233576f,
+         0.0177957527f,
+        -0.0353228594f,
+         1.1255501596f,
+        -0.1074635265f,
+        -0.0209002083f,
+        -0.0011430452f,
+         0.0042620971f
+    },
+    {
+         0.0041046165f,         /* Filter 27 */
+         0.0120115019f,
+         0.0210758250f,
+        -0.0126826277f,
+         1.0978137424f,
+        -0.1011856112f,
+        -0.0223386620f,
+        -0.0025560369f,
+         0.0035625973f
+    },
+    {
+         0.0032736852f,         /* Filter 28 */
+         0.0117421344f,
+         0.0240144782f,
+         0.0128597894f,
+         1.0664075323f,
+        -0.0938829156f,
+        -0.0233574765f,
+        -0.0038896008f,
+         0.0028141763f
+    },
+    {
+         0.0023554782f,         /* Filter 29 */
+         0.0112098711f,
+         0.0265310587f,
+         0.0412866769f,
+         1.0315754934f,
+        -0.0857546018f,
+        -0.0239551212f,
+        -0.0051210137f,
+         0.0020320508f
+    },
+    {
+         0.0013648323f,         /* Filter 30 */
+         0.0104140102f,
+         0.0285475474f,
+         0.0725519600f,
+         0.9935863233f,
+        -0.0769959031f,
+        -0.0241376359f,
+        -0.0062301368f,
+         0.0012316933f
+    },
+    {
+         0.0003183408f,         /* Filter 31 */
+         0.0093587151f,
+         0.0299900191f,
+         0.1065807242f,
+         0.9527307304f,
+        -0.0677960213f,
+        -0.0239181901f,
+        -0.0071996967f,
+         0.0004285425f
+    },
+    {
+        -0.0007659096f,         /* Filter 32 */
+         0.0080531155f,
+         0.0307901140f,
+         0.1432690480f,
+         0.9093185032f,
+        -0.0583361774f,
+        -0.0233165437f,
+        -0.0080155088f,
+        -0.0003622774f
+    },
+    {
+        -0.0018686358f,         /* Filter 33 */
+         0.0065113237f,
+         0.0308864956f,
+         0.1824841563f,
+         0.8636754069f,
+        -0.0487878398f,
+        -0.0223584207f,
+        -0.0086666380f,
+        -0.0011262266f
+    },
+    {
+        -0.0029696854f,         /* Filter 34 */
+         0.0047523617f,
+         0.0302262769f,
+         0.2240649005f,
+         0.8161399423f,
+        -0.0393111426f,
+        -0.0210748106f,
+        -0.0091454978f,
+        -0.0018496023f
+    },
+    {
+        -0.0040483891f,         /* Filter 35 */
+         0.0027999985f,
+         0.0287663895f,
+         0.2678225635f,
+         0.7670600056f,
+        -0.0300535107f,
+        -0.0195012095f,
+        -0.0094478866f,
+        -0.0025197700f
+    },
+    {
+        -0.0050839319f,         /* Filter 36 */
+         0.0006824956f,
+         0.0264748749f,
+         0.3135419896f,
+         0.7167894869f,
+        -0.0211485021f,
+        -0.0176768181f,
+        -0.0095729633f,
+        -0.0031253709f
+    },
+    {
+        -0.0060557371f,         /* Filter 37 */
+        -0.0015677363f,
+         0.0233320755f,
+         0.3609830295f,
+         0.6656848457f,
+        -0.0127148737f,
+        -0.0156437084f,
+        -0.0095231635f,
+        -0.0036565006f
+    },
+    {
+        -0.0069438567f,         /* Filter 38 */
+        -0.0039145680f,
+         0.0193317049f,
+         0.4098822897f,
+         0.6141017035f,
+        -0.0048558766f,
+        -0.0134459768f,
+        -0.0093040596f,
+        -0.0041048584f
+    },
+    {
+        -0.0077293609f,         /* Filter 39 */
+        -0.0063186648f,
+         0.0144817755f,
+         0.4599551720f,
+         0.5623914901f,
+         0.0023412184f,
+        -0.0111288952f,
+        -0.0089241700f,
+        -0.0044638629f
+    },
+};
+
+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;
+
+    out_bit = (bit ^ (s->tx_scramble_reg >> 14) ^ (s->tx_scramble_reg >> 17)) & 1;
+    if (s->tx_scrambler_pattern_count >= 64)
+    {
+        out_bit ^= 1;
+        s->tx_scrambler_pattern_count = 0;
+    }
+    if (out_bit == 1)
+        s->tx_scrambler_pattern_count++;
+    else
+        s->tx_scrambler_pattern_count = 0;
+    s->tx_scramble_reg = (s->tx_scramble_reg << 1) | out_bit;
+    return out_bit;
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ int get_scrambled_bit(v22bis_state_t *s)
+{
+    int bit;
+
+    if ((bit = s->current_get_bit(s->user_data)) == PUTBIT_END_OF_DATA)
+    {
+        /* Fill out this symbol with ones, and prepare to send
+           the rest of the shutdown sequence. */
+        s->current_get_bit = fake_get_bit;
+        s->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_TRAINING_STAGE_INITIAL_SILENCE:
+        /* Segment 1: silence */
+        s->tx_constellation_state = 0;
+        z = complex_setf(0.0f, 0.0f);
+        if (s->caller)
+        {
+            /* The caller just waits for a signal from the far end, which should be unscrambled ones */
+            if (s->detected_unscrambled_ones_or_zeros)
+            {
+                if (s->bit_rate == 2400)
+                {
+                    /* Try to establish at 2400bps */
+                    span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting unscrambled 0011 at 1200 (S1)\n");
+                    s->tx_training = V22BIS_TRAINING_STAGE_UNSCRAMBLED_0011;
+                }
+                else
+                {
+                    /* Only try at 1200bps */
+                    span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting scrambled ones at 1200 (A)\n");
+                    s->tx_training = V22BIS_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200;
+                }
+                s->tx_training_count = 0;
+            }
+        }
+        else
+        {
+            /* The answerer waits 75ms, then sends unscrambled ones */
+            if (++s->tx_training_count >= ms_to_symbols(75))
+            {
+                /* Inital 75ms of silence is over */
+                span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting unscrambled ones at 1200\n");
+                s->tx_training = V22BIS_TRAINING_STAGE_UNSCRAMBLED_ONES;
+                s->tx_training_count = 0;
+            }
+        }
+        break;
+    case V22BIS_TRAINING_STAGE_UNSCRAMBLED_ONES:
+        /* Segment 2: Continuous unscrambled ones at 1200bps (i.e. reversals). */
+        /* 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];
+        if (s->bit_rate == 2400  &&  s->detected_unscrambled_0011_ending)
+        {
+            /* We are allowed to use 2400bps, and the far end is requesting 2400bps. Result: we are going to
+               work at 2400bps */
+            span_log(&s->logging, SPAN_LOG_FLOW, "+++ [2400] starting unscrambled 0011 at 1200 (S1)\n");
+            s->tx_training = V22BIS_TRAINING_STAGE_UNSCRAMBLED_0011;
+            s->tx_training_count = 0;
+            break;
+        }
+        if (s->detected_scrambled_ones_or_zeros_at_1200bps)
+        {
+            /* We are going to work at 1200bps. */
+            span_log(&s->logging, SPAN_LOG_FLOW, "+++ [1200] starting scrambled ones at 1200 (B)\n");
+            s->bit_rate = 1200;
+            s->tx_training = V22BIS_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200;
+            s->tx_training_count = 0;
+            break;
+        }
+        break;
+    case V22BIS_TRAINING_STAGE_UNSCRAMBLED_0011:
+        /* Segment 3: 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[(s->tx_training_count & 1)  ?  3  :  0]) & 3;
+span_log(&s->logging, SPAN_LOG_FLOW, "U0011 Tx 0x%02x\n", s->tx_constellation_state);
+        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 scrambled ones at 1200 (C)\n");
+            s->tx_training = V22BIS_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200;
+            s->tx_training_count = 0;
+        }
+        break;
+    case V22BIS_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200:
+        /* Segment 4: 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];
+        if (s->caller)
+        {
+            if (s->detected_unscrambled_0011_ending)
+            {
+                /* Continue for a further 600+-10ms */
+                if (++s->tx_training_count >= ms_to_symbols(600))
+                {
+                    span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting scrambled ones at 2400 (A)\n");
+                    s->tx_training = V22BIS_TRAINING_STAGE_SCRAMBLED_ONES_AT_2400;
+                    s->tx_training_count = 0;
+                }
+            }
+            else if (s->detected_scrambled_ones_or_zeros_at_1200bps)
+            {
+                if (s->bit_rate == 2400)
+                {
+                    /* Continue for a further 756+-10ms */
+                    if (++s->tx_training_count >= ms_to_symbols(756))
+                    {
+                        span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting scrambled ones at 2400 (B)\n");
+                        s->tx_training = V22BIS_TRAINING_STAGE_SCRAMBLED_ONES_AT_2400;
+                        s->tx_training_count = 0;
+                    }
+                }
+                else
+                {
+                    span_log(&s->logging, SPAN_LOG_FLOW, "+++ finished\n");
+                    s->tx_training = V22BIS_TRAINING_STAGE_NORMAL_OPERATION;
+                    s->tx_training_count = 0;
+                    s->current_get_bit = s->get_bit;
+                }
+            }
+        }
+        else
+        {
+            if (s->bit_rate == 2400)
+            {
+                if (++s->tx_training_count >= ms_to_symbols(500))
+                {
+                    span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting scrambled ones at 2400 (C)\n");
+                    s->tx_training = V22BIS_TRAINING_STAGE_SCRAMBLED_ONES_AT_2400;
+                    s->tx_training_count = 0;
+                }
+            }
+            else
+            {
+                if (++s->tx_training_count >= ms_to_symbols(756))
+                {
+                    span_log(&s->logging, SPAN_LOG_FLOW, "+++ finished\n");
+                    s->tx_training = 0;
+                    s->tx_training_count = 0;
+                }
+            }
+        }
+        break;
+    case V22BIS_TRAINING_STAGE_SCRAMBLED_ONES_AT_2400:
+        /* Segment 4: Scrambled ones 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) | 0x01];
+        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, "+++ finished\n");
+            s->tx_training = 0;
+            s->tx_training_count = 0;
+            s->current_get_bit = s->get_bit;
+        }
+        break;
+    case V22BIS_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->shutdown)
+    {
+        if (++s->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->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 --------------------------------------------------------*/
+
+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->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.re = 0.0f;
+        x.im = 0.0f;
+        for (i = 0;  i < V22BIS_TX_FILTER_STEPS;  i++)
+        {
+            x.re += pulseshaper[39 - s->tx_baud_phase][i]*s->tx_rrc_filter[i + s->tx_rrc_filter_step].re;
+            x.im += 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->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->guard_phase), s->guard_phase_rate, s->guard_level, 0);
+        }
+        /* Don't bother saturating. We should never clip. */
+        amp[sample] = (int16_t) lrintf(famp);
+    }
+    return sample;
+}
+/*- End of function --------------------------------------------------------*/
+
+void v22bis_tx_power(v22bis_state_t *s, float power)
+{
+    float l;
+
+    l = 1.6f*powf(10.0f, (power - DBM0_MAX_POWER)/20.0f);
+    s->tx_gain = l*32768.0f/(PULSESHAPER_GAIN*3.0f);
+}
+/*- End of function --------------------------------------------------------*/
+
+static int v22bis_tx_restart(v22bis_state_t *s, int bit_rate)
+{
+    s->bit_rate = bit_rate;
+    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;
+    s->tx_training = V22BIS_TRAINING_STAGE_INITIAL_SILENCE;
+    s->tx_training_count = 0;
+    s->tx_carrier_phase = 0;
+    s->guard_phase = 0;
+    s->tx_baud_phase = 0;
+    s->tx_constellation_state = 0;
+    s->current_get_bit = fake_get_bit;
+    s->shutdown = 0;
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+void v22bis_set_get_bit(v22bis_state_t *s, get_bit_func_t get_bit, void *user_data)
+{
+    s->get_bit = get_bit;
+    s->user_data = user_data;
+}
+/*- End of function --------------------------------------------------------*/
+
+void v22bis_set_put_bit(v22bis_state_t *s, put_bit_func_t put_bit, void *user_data)
+{
+    s->put_bit = put_bit;
+    s->user_data = user_data;
+}
+/*- End of function --------------------------------------------------------*/
+
+int v22bis_restart(v22bis_state_t *s, int bit_rate)
+{
+    if (v22bis_tx_restart(s, bit_rate))
+        return -1;
+    return v22bis_rx_restart(s, bit_rate);
+}
+/*- End of function --------------------------------------------------------*/
+
+v22bis_state_t *v22bis_init(v22bis_state_t *s,
+                            int bit_rate,
+                            int guard,
+                            int caller,
+                            get_bit_func_t get_bit,
+                            put_bit_func_t put_bit,
+                            void *user_data)
+{
+    if (s == NULL)
+    {
+        if ((s = (v22bis_state_t *) malloc(sizeof(*s))) == NULL)
+            return NULL;
+    }
+    memset(s, 0, sizeof(*s));
+    s->bit_rate = bit_rate;
+    s->caller = caller;
+
+    s->get_bit = get_bit;
+    s->put_bit = put_bit;
+    s->user_data = user_data;
+
+    if (s->caller)
+    {
+        s->tx_carrier_phase_rate = dds_phase_ratef(1200.0f);
+    }
+    else
+    {
+        s->tx_carrier_phase_rate = dds_phase_ratef(2400.0f);
+        if (guard)
+        {
+            if (guard == 1)
+            {
+                s->guard_phase_rate = dds_phase_ratef(550.0f);
+                s->guard_level = 1500.0f;
+            }
+            else
+            {
+                s->guard_phase_rate = dds_phase_ratef(1800.0f);
+                s->guard_level = 1000.0f;
+            }
+        }
+    }
+    v22bis_tx_power(s, -10.0f);
+    span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
+    span_log_set_protocol(&s->logging, "V.22bis");
+    v22bis_restart(s, s->bit_rate);
+    return s;
+}
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/

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