Mercurial > hg > audiostuff
diff 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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/spandsp-0.0.3/spandsp-0.0.3/src/v17tx.c Fri Jun 25 16:00:21 2010 +0200 @@ -0,0 +1,717 @@ +/* + * 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 ------------------------------------------------------------*/