view spandsp-0.0.3/spandsp-0.0.3/src/v17tx.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 source

/*
 * SpanDSP - a series of DSP components for telephony
 *
 * v17tx.c - ITU V.17 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: v17tx.c,v 1.46 2006/11/28 16:59:57 steveu Exp $
 */

/*! \file */

#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/v17tx.h"

#define CARRIER_NOMINAL_FREQ        1800.0f

/* Segments of the training sequence */
#define V17_TRAINING_SEG_TEP_A      0
#define V17_TRAINING_SEG_TEP_B      (V17_TRAINING_SEG_TEP_A + 480)
#define V17_TRAINING_SEG_1          (V17_TRAINING_SEG_TEP_B + 48)
#define V17_TRAINING_SEG_2          (V17_TRAINING_SEG_1 + 256)
#define V17_TRAINING_SEG_3          (V17_TRAINING_SEG_2 + 2976)
#define V17_TRAINING_SEG_4          (V17_TRAINING_SEG_3 + 64)
#define V17_TRAINING_END            (V17_TRAINING_SEG_4 + 48)
#define V17_TRAINING_SHUTDOWN_A     (V17_TRAINING_END + 32)
#define V17_TRAINING_SHUTDOWN_END   (V17_TRAINING_SHUTDOWN_A + 48)

#define V17_TRAINING_SHORT_SEG_4    (V17_TRAINING_SEG_2 + 38)

#define V17_BRIDGE_WORD             0x8880

const complexf_t v17_14400_constellation[128] =
{
    {-8, -3},       /* 0x00 */
    { 9,  2},       /* 0x01 */
    { 2, -9},       /* 0x02 */
    {-3,  8},       /* 0x03 */
    { 8,  3},       /* 0x04 */
    {-9, -2},       /* 0x05 */
    {-2,  9},       /* 0x06 */
    { 3, -8},       /* 0x07 */
    {-8,  1},       /* 0x08 */
    { 9, -2},       /* 0x09 */
    {-2, -9},       /* 0x0A */
    { 1,  8},       /* 0x0B */
    { 8, -1},       /* 0x0C */
    {-9,  2},       /* 0x0D */
    { 2,  9},       /* 0x0E */
    {-1, -8},       /* 0x0F */
    {-4, -3},       /* 0x10 */
    { 5,  2},       /* 0x11 */
    { 2, -5},       /* 0x12 */
    {-3,  4},       /* 0x13 */
    { 4,  3},       /* 0x14 */
    {-5, -2},       /* 0x15 */
    {-2,  5},       /* 0x16 */
    { 3, -4},       /* 0x17 */
    {-4,  1},       /* 0x18 */
    { 5, -2},       /* 0x19 */
    {-2, -5},       /* 0x1A */
    { 1,  4},       /* 0x1B */
    { 4, -1},       /* 0x1C */
    {-5,  2},       /* 0x1D */
    { 2,  5},       /* 0x1E */
    {-1, -4},       /* 0x1F */
    { 4, -3},       /* 0x20 */
    {-3,  2},       /* 0x21 */
    { 2,  3},       /* 0x22 */
    {-3, -4},       /* 0x23 */
    {-4,  3},       /* 0x24 */
    { 3, -2},       /* 0x25 */
    {-2, -3},       /* 0x26 */
    { 3,  4},       /* 0x27 */
    { 4,  1},       /* 0x28 */
    {-3, -2},       /* 0x29 */
    {-2,  3},       /* 0x2A */
    { 1, -4},       /* 0x2B */
    {-4, -1},       /* 0x2C */
    { 3,  2},       /* 0x2D */
    { 2, -3},       /* 0x2E */
    {-1,  4},       /* 0x2F */
    { 0, -3},       /* 0x30 */
    { 1,  2},       /* 0x31 */
    { 2, -1},       /* 0x32 */
    {-3,  0},       /* 0x33 */
    { 0,  3},       /* 0x34 */
    {-1, -2},       /* 0x35 */
    {-2,  1},       /* 0x36 */
    { 3,  0},       /* 0x37 */
    { 0,  1},       /* 0x38 */
    { 1, -2},       /* 0x39 */
    {-2, -1},       /* 0x3A */
    { 1,  0},       /* 0x3B */
    { 0, -1},       /* 0x3C */
    {-1,  2},       /* 0x3D */
    { 2,  1},       /* 0x3E */
    {-1,  0},       /* 0x3F */
    { 8, -3},       /* 0x40 */
    {-7,  2},       /* 0x41 */
    { 2,  7},       /* 0x42 */
    {-3, -8},       /* 0x43 */
    {-8,  3},       /* 0x44 */
    { 7, -2},       /* 0x45 */
    {-2, -7},       /* 0x46 */
    { 3,  8},       /* 0x47 */
    { 8,  1},       /* 0x48 */
    {-7, -2},       /* 0x49 */
    {-2,  7},       /* 0x4A */
    { 1, -8},       /* 0x4B */
    {-8, -1},       /* 0x4C */
    { 7,  2},       /* 0x4D */
    { 2, -7},       /* 0x4E */
    {-1,  8},       /* 0x4F */
    {-4, -7},       /* 0x50 */
    { 5,  6},       /* 0x51 */
    { 6, -5},       /* 0x52 */
    {-7,  4},       /* 0x53 */
    { 4,  7},       /* 0x54 */
    {-5, -6},       /* 0x55 */
    {-6,  5},       /* 0x56 */
    { 7, -4},       /* 0x57 */
    {-4,  5},       /* 0x58 */
    { 5, -6},       /* 0x59 */
    {-6, -5},       /* 0x5A */
    { 5,  4},       /* 0x5B */
    { 4, -5},       /* 0x5C */
    {-5,  6},       /* 0x5D */
    { 6,  5},       /* 0x5E */
    {-5, -4},       /* 0x5F */
    { 4, -7},       /* 0x60 */
    {-3,  6},       /* 0x61 */
    { 6,  3},       /* 0x62 */
    {-7, -4},       /* 0x63 */
    {-4,  7},       /* 0x64 */
    { 3, -6},       /* 0x65 */
    {-6, -3},       /* 0x66 */
    { 7,  4},       /* 0x67 */
    { 4,  5},       /* 0x68 */
    {-3, -6},       /* 0x69 */
    {-6,  3},       /* 0x6A */
    { 5, -4},       /* 0x6B */
    {-4, -5},       /* 0x6C */
    { 3,  6},       /* 0x6D */
    { 6, -3},       /* 0x6E */
    {-5,  4},       /* 0x6F */
    { 0, -7},       /* 0x70 */
    { 1,  6},       /* 0x71 */
    { 6, -1},       /* 0x72 */
    {-7,  0},       /* 0x73 */
    { 0,  7},       /* 0x74 */
    {-1, -6},       /* 0x75 */
    {-6,  1},       /* 0x76 */
    { 7,  0},       /* 0x77 */
    { 0,  5},       /* 0x78 */
    { 1, -6},       /* 0x79 */
    {-6, -1},       /* 0x7A */
    { 5,  0},       /* 0x7B */
    { 0, -5},       /* 0x7C */
    {-1,  6},       /* 0x7D */
    { 6,  1},       /* 0x7E */
    {-5,  0}        /* 0x7F */
};

const complexf_t v17_12000_constellation[64] =
{
    { 7,  1},       /* 0x00 */
    {-5, -1},       /* 0x01 */
    {-1,  5},       /* 0x02 */
    { 1, -7},       /* 0x03 */
    {-7, -1},       /* 0x04 */
    { 5,  1},       /* 0x05 */
    { 1, -5},       /* 0x06 */
    {-1,  7},       /* 0x07 */
    { 3, -3},       /* 0x08 */
    {-1,  3},       /* 0x09 */
    { 3,  1},       /* 0x0A */
    {-3, -3},       /* 0x0B */
    {-3,  3},       /* 0x0C */
    { 1, -3},       /* 0x0D */
    {-3, -1},       /* 0x0E */
    { 3,  3},       /* 0x0F */
    { 7, -7},       /* 0x10 */
    {-5,  7},       /* 0x11 */
    { 7,  5},       /* 0x12 */
    {-7, -7},       /* 0x13 */
    {-7,  7},       /* 0x14 */
    { 5, -7},       /* 0x15 */
    {-7, -5},       /* 0x16 */
    { 7,  7},       /* 0x17 */
    {-1, -7},       /* 0x18 */
    { 3,  7},       /* 0x19 */
    { 7, -3},       /* 0x1A */
    {-7,  1},       /* 0x1B */
    { 1,  7},       /* 0x1C */
    {-3, -7},       /* 0x1D */
    {-7,  3},       /* 0x1E */
    { 7, -1},       /* 0x1F */
    { 3,  5},       /* 0x20 */
    {-1, -5},       /* 0x21 */
    {-5,  1},       /* 0x22 */
    { 5, -3},       /* 0x23 */
    {-3, -5},       /* 0x24 */
    { 1,  5},       /* 0x25 */
    { 5, -1},       /* 0x26 */
    {-5,  3},       /* 0x27 */
    {-1,  1},       /* 0x28 */
    { 3, -1},       /* 0x29 */
    {-1, -3},       /* 0x2A */
    { 1,  1},       /* 0x2B */
    { 1, -1},       /* 0x2C */
    {-3,  1},       /* 0x2D */
    { 1,  3},       /* 0x2E */
    {-1, -1},       /* 0x2F */
    {-5,  5},       /* 0x30 */
    { 7, -5},       /* 0x31 */
    {-5, -7},       /* 0x32 */
    { 5,  5},       /* 0x33 */
    { 5, -5},       /* 0x34 */
    {-7,  5},       /* 0x35 */
    { 5,  7},       /* 0x36 */
    {-5, -5},       /* 0x37 */
    {-5, -3},       /* 0x38 */
    { 7,  3},       /* 0x39 */
    { 3, -7},       /* 0x3A */
    {-3,  5},       /* 0x3B */
    { 5,  3},       /* 0x3C */
    {-7, -3},       /* 0x3D */
    {-3,  7},       /* 0x3E */
    { 3, -5}        /* 0x3F */
};

const complexf_t v17_9600_constellation[32] =
{
    {-8,  2},       /* 0x00 */
    {-6, -4},       /* 0x01 */
    {-4,  6},       /* 0x02 */
    { 2,  8},       /* 0x03 */
    { 8, -2},       /* 0x04 */
    { 6,  4},       /* 0x05 */
    { 4, -6},       /* 0x06 */
    {-2, -8},       /* 0x07 */
    { 0,  2},       /* 0x08 */
    {-6,  4},       /* 0x09 */
    { 4,  6},       /* 0x0A */
    { 2,  0},       /* 0x0B */
    { 0, -2},       /* 0x0C */
    { 6, -4},       /* 0x0D */
    {-4, -6},       /* 0x0E */
    {-2,  0},       /* 0x0F */
    { 0, -6},       /* 0x10 */
    { 2, -4},       /* 0x11 */
    {-4, -2},       /* 0x12 */
    {-6,  0},       /* 0x13 */
    { 0,  6},       /* 0x14 */
    {-2,  4},       /* 0x15 */
    { 4,  2},       /* 0x16 */
    { 6,  0},       /* 0x17 */
    { 8,  2},       /* 0x18 */
    { 2,  4},       /* 0x19 */
    { 4, -2},       /* 0x1A */
    { 2, -8},       /* 0x1B */
    {-8, -2},       /* 0x1C */
    {-2, -4},       /* 0x1D */
    {-4,  2},       /* 0x1E */
    {-2,  8}        /* 0x1F */
};

const complexf_t v17_7200_constellation[16] =
{
    { 6, -6},       /* 0x00 */
    {-2,  6},       /* 0x01 */
    { 6,  2},       /* 0x02 */
    {-6, -6},       /* 0x03 */
    {-6,  6},       /* 0x04 */
    { 2, -6},       /* 0x05 */
    {-6, -2},       /* 0x06 */
    { 6,  6},       /* 0x07 */
    {-2,  2},       /* 0x08 */
    { 6, -2},       /* 0x09 */
    {-2, -6},       /* 0x0A */
    { 2,  2},       /* 0x0B */
    { 2, -2},       /* 0x0C */
    {-6,  2},       /* 0x0D */
    { 2,  6},       /* 0x0E */
    {-2, -2}        /* 0x0F */
};

/* Raised root cosine pulse shaping; Beta = 0.25; 4 symbols either
   side of the centre. */
/* Created with mkshape -r 0.05 0.25 91 -l and then split up */
#define PULSESHAPER_GAIN            (9.9888356312f/10.0f)
#define PULSESHAPER_COEFF_SETS      10

static const float pulseshaper[PULSESHAPER_COEFF_SETS][V17_TX_FILTER_STEPS] =
{
    {
        -0.0029426223f,         /* Filter 0 */
        -0.0183060118f,
         0.0653192857f,
        -0.1703207714f,
         0.6218069936f,
         0.6218069936f,
        -0.1703207714f,
         0.0653192857f,
        -0.0183060118f
    },
    {
         0.0031876922f,         /* Filter 1 */
        -0.0300884145f,
         0.0832744718f,
        -0.1974255221f,
         0.7664229820f,
         0.4670580725f,
        -0.1291107519f,
         0.0424189243f,
        -0.0059810465f
    },
    {
         0.0097229236f,         /* Filter 2 */
        -0.0394811291f,
         0.0931039664f,
        -0.2043906784f,
         0.8910868760f,
         0.3122713836f,
        -0.0802880559f,
         0.0179050490f,
         0.0052057308f
    },
    {
         0.0156117223f,         /* Filter 3 */
        -0.0447125347f,
         0.0922040267f,
        -0.1862939416f,
         0.9870942864f,
         0.1669790517f,
        -0.0301581072f,
        -0.0051358510f,
         0.0139350286f
    },
    {
         0.0197702545f,         /* Filter 4 */
        -0.0443470335f,
         0.0789538534f,
        -0.1399184160f,
         1.0476130256f,
         0.0393903028f,
         0.0157339854f,
        -0.0241879599f,
         0.0193774571f
    },
    {
         0.0212455717f,         /* Filter 5 */
        -0.0375307894f,
         0.0530516472f,
        -0.0642195521f,
         1.0682849922f,
        -0.0642195521f,
         0.0530516472f,
        -0.0375307894f,
         0.0212455717f
    },
    {
         0.0193774571f,         /* Filter 6 */
        -0.0241879599f,
         0.0157339854f,
         0.0393903028f,
         1.0476130256f,
        -0.1399184160f,
         0.0789538534f,
        -0.0443470335f,
         0.0197702545f
    },
    {
         0.0139350286f,         /* Filter 7 */
        -0.0051358510f,
        -0.0301581072f,
         0.1669790517f,
         0.9870942864f,
        -0.1862939416f,
         0.0922040267f,
        -0.0447125347f,
         0.0156117223f
    },
    {
         0.0052057308f,         /* Filter 8 */
         0.0179050490f,
        -0.0802880559f,
         0.3122713836f,
         0.8910868760f,
        -0.2043906784f,
         0.0931039664f,
        -0.0394811291f,
         0.0097229236f
    },
    {
        -0.0059810465f,         /* Filter 9 */
         0.0424189243f,
        -0.1291107519f,
         0.4670580725f,
         0.7664229820f,
        -0.1974255221f,
         0.0832744718f,
        -0.0300884145f,
         0.0031876922f
    },
};

static __inline__ int scramble(v17_tx_state_t *s, int in_bit)
{
    int out_bit;

    out_bit = (in_bit ^ (s->scramble_reg >> 17) ^ (s->scramble_reg >> 22)) & 1;
    s->scramble_reg = (s->scramble_reg << 1) | out_bit;
    return out_bit;
}
/*- End of function --------------------------------------------------------*/

static __inline__ complexf_t training_get(v17_tx_state_t *s)
{
    static const complexf_t abcd[4] =
    {
        {-6.0f, -2.0f},
        { 2.0f, -6.0f},
        { 6.0f,  2.0f},
        {-2.0f,  6.0f}
    };
    static const int cdba_to_abcd[4] =
    {
        2, 3, 1, 0
    };
    static const int dibit_to_step[4] =
    {
        1, 0, 2, 3
    };
    int bits;
    int shift;

    if (++s->training_step <= V17_TRAINING_SEG_3)
    {
        if (s->training_step <= V17_TRAINING_SEG_2)
        {
            if (s->training_step <= V17_TRAINING_SEG_TEP_B)
            {
                /* Optional segment: Unmodulated carrier (talker echo protection) */
                return abcd[0];
            }
            if (s->training_step <= V17_TRAINING_SEG_1)
            {
                /* Optional segment: silence (talker echo protection) */
                return complex_setf(0.0f, 0.0f);
            }
            /* Segment 1: ABAB... */
            return abcd[(s->training_step & 1) ^ 1];
        }
        /* Segment 2: CDBA... */
        /* Apply the scrambler */
        bits = scramble(s, 1);
        bits = (bits << 1) | scramble(s, 1);
        s->constellation_state = cdba_to_abcd[bits];
        if (s->short_train  &&  s->training_step == V17_TRAINING_SHORT_SEG_4)
        {
            /* Go straight to the ones test. */
            s->training_step = V17_TRAINING_SEG_4;
        }
        return abcd[s->constellation_state];
    }
    /* Segment 3: Bridge... */
    shift = ((s->training_step - V17_TRAINING_SEG_3 - 1) & 0x7) << 1;
    span_log(&s->logging, SPAN_LOG_FLOW, "Seg 3 shift %d\n", shift);
    bits = scramble(s, V17_BRIDGE_WORD >> shift);
    bits = (bits << 1) | scramble(s, V17_BRIDGE_WORD >> (shift + 1));
    s->constellation_state = (s->constellation_state + dibit_to_step[bits]) & 3;
    return abcd[s->constellation_state];
}
/*- End of function --------------------------------------------------------*/

static __inline__ int diff_and_convolutional_encode(v17_tx_state_t *s, int q)
{
    static const int diff_code[16] =
    {
        0, 1, 2, 3, 1, 2, 3, 0, 2, 3, 0, 1, 3, 0, 1, 2
    };
    int y1;
    int y2;
    int this1;
    int this2;

    /* Differentially encode */
    s->diff = diff_code[((q & 0x03) << 2) | s->diff];

    /* Convolutionally encode the redundant bit */
    y2 = s->diff >> 1;
    y1 = s->diff;
    this2 = y2 ^ y1 ^ (s->convolution >> 2) ^ ((y2 ^ (s->convolution >> 1)) & s->convolution);
    this1 = y2 ^ (s->convolution >> 1) ^ (y1 & s->convolution);
    s->convolution = ((s->convolution & 1) << 2) | ((this2 & 1) << 1) | (this1 & 1);
    return ((q << 1) & 0x78) | (s->diff << 1) | ((s->convolution >> 2) & 1);
}
/*- End of function --------------------------------------------------------*/

static int fake_get_bit(void *user_data)
{
    return 1;
}
/*- End of function --------------------------------------------------------*/

static __inline__ complexf_t getbaud(v17_tx_state_t *s)
{
    int i;
    int bit;
    int bits;

    if (s->in_training)
    {
        if (s->training_step <= V17_TRAINING_END)
        {
            /* Send the training sequence */
            if (s->training_step < V17_TRAINING_SEG_4)
                return training_get(s);
            /* The last step in training is to send some 1's */
            if (++s->training_step > V17_TRAINING_END)
            {
                /* Training finished - commence normal operation. */
                s->current_get_bit = s->get_bit;
                s->in_training = FALSE;
            }
        }
        else
        {
            if (++s->training_step > V17_TRAINING_SHUTDOWN_A)
            {
                /* The shutdown sequence is 32 bauds of all 1's, then 48 bauds
                   of silence */
                return complex_setf(0.0f, 0.0f);
            }
        }
    }
    bits = 0;
    for (i = 0;  i < s->bits_per_symbol;  i++)
    {
        if ((bit = s->current_get_bit(s->user_data)) == PUTBIT_END_OF_DATA)
        {
printf("End of real data\n");
            /* End of real data. Switch to the fake get_bit routine, until we
               have shut down completely. */
            s->current_get_bit = fake_get_bit;
            s->in_training = TRUE;
            bit = 1;
        }
        bits |= (scramble(s, bit) << i);
    }
    return s->constellation[diff_and_convolutional_encode(s, bits)];
}
/*- End of function --------------------------------------------------------*/

int v17_tx(v17_tx_state_t *s, int16_t amp[], int len)
{
    complexf_t x;
    complexf_t z;
    int i;
    int sample;

    if (s->training_step >= V17_TRAINING_SHUTDOWN_END)
    {
        /* Once we have sent the shutdown sequence, we stop sending completely. */
        return 0;
    }
    for (sample = 0;  sample < len;  sample++)
    {
        if ((s->baud_phase += 3) >= 10)
        {
            s->baud_phase -= 10;
            s->rrc_filter[s->rrc_filter_step] =
            s->rrc_filter[s->rrc_filter_step + V17_TX_FILTER_STEPS] = getbaud(s);
            if (++s->rrc_filter_step >= V17_TX_FILTER_STEPS)
                s->rrc_filter_step = 0;
        }
        /* Root raised cosine pulse shaping at baseband */
        x.re = 0.0f;
        x.im = 0.0f;
        for (i = 0;  i < V17_TX_FILTER_STEPS;  i++)
        {
            x.re += pulseshaper[9 - s->baud_phase][i]*s->rrc_filter[i + s->rrc_filter_step].re;
            x.im += pulseshaper[9 - s->baud_phase][i]*s->rrc_filter[i + s->rrc_filter_step].im;
        }
        /* Now create and modulate the carrier */
        z = dds_complexf(&(s->carrier_phase), s->carrier_phase_rate);
        /* Don't bother saturating. We should never clip. */
        amp[sample] = (int16_t) lrintf((x.re*z.re - x.im*z.im)*s->gain);
    }
    return sample;
}
/*- End of function --------------------------------------------------------*/

void v17_tx_power(v17_tx_state_t *s, float power)
{
    /* The constellation design seems to keep the average power the same, regardless
       of which bit rate is in use. */
    s->gain = 0.223f*powf(10.0f, (power - DBM0_MAX_POWER)/20.0f)*32768.0f/PULSESHAPER_GAIN;
}
/*- End of function --------------------------------------------------------*/

void v17_tx_set_get_bit(v17_tx_state_t *s, get_bit_func_t get_bit, void *user_data)
{
    if (s->get_bit == s->current_get_bit)
        s->current_get_bit = get_bit;
    s->get_bit = get_bit;
    s->user_data = user_data;
}
/*- End of function --------------------------------------------------------*/

int v17_tx_restart(v17_tx_state_t *s, int rate, int tep, int short_train)
{
    switch (rate)
    {
    case 14400:
        s->bits_per_symbol = 6;
        s->constellation = v17_14400_constellation;
        break;
    case 12000:
        s->bits_per_symbol = 5;
        s->constellation = v17_12000_constellation;
        break;
    case 9600:
        s->bits_per_symbol = 4;
        s->constellation = v17_9600_constellation;
        break;
    case 7200:
        s->bits_per_symbol = 3;
        s->constellation = v17_7200_constellation;
        break;
    default:
        return -1;
    }
    /* NB: some modems seem to use 3 instead of 1 for long training */
    s->diff = (short_train)  ?  0  :  1;
    s->bit_rate = rate;
    cvec_zerof(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
    s->rrc_filter_step = 0;
    s->convolution = 0;
    s->scramble_reg = 0x2ECDD5;
    s->in_training = TRUE;
    s->short_train = short_train;
    s->training_step =  (tep)  ?  V17_TRAINING_SEG_TEP_A  :  V17_TRAINING_SEG_1;
    s->carrier_phase = 0;
    s->baud_phase = 0;
    s->constellation_state = 0;
    s->current_get_bit = fake_get_bit;
    return 0;
}
/*- End of function --------------------------------------------------------*/

v17_tx_state_t *v17_tx_init(v17_tx_state_t *s, int rate, int tep, get_bit_func_t get_bit, void *user_data)
{
    if (s == NULL)
    {
        if ((s = (v17_tx_state_t *) malloc(sizeof(*s))) == NULL)
            return NULL;
    }
    memset(s, 0, sizeof(*s));
    s->get_bit = get_bit;
    s->user_data = user_data;
    s->carrier_phase_rate = dds_phase_ratef(CARRIER_NOMINAL_FREQ);
    v17_tx_power(s, -14.0f);
    v17_tx_restart(s, rate, tep, FALSE);
    return s;
}
/*- End of function --------------------------------------------------------*/

int v17_tx_release(v17_tx_state_t *s)
{
    free(s);
    return 0;
}
/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/

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