SPAN_DECLARE_NONSTD(int) fax_modems_v17_v21_rx_fillin(void *user_data, int len);
SPAN_DECLARE_NONSTD(int) fax_modems_v27ter_v21_rx_fillin(void *user_data, int len);
SPAN_DECLARE_NONSTD(int) fax_modems_v29_v21_rx_fillin(void *user_data, int len);
+
SPAN_DECLARE(void) fax_modems_start_rx_modem(fax_modems_state_t *s, int which);
SPAN_DECLARE(void) fax_modems_set_tep_mode(fax_modems_state_t *s, int use_tep);
uint16_t crc;
/*! \brief TRUE if non-ECM fill bits are to be stripped when sending image data. */
int fill_bit_removal;
- /*! \brief The number of octets to send in each image packet (non-ECM or ECM) at the current
- rate and the current specified packet interval. */
+ /*! \brief The number of octets to send in each image packet (non-ECM or ECM) at
+ the current rate and the current specified packet interval. */
int octets_per_data_packet;
/*! \brief Bits into the non-ECM buffer */
/* Receive section */
struct
{
-#if defined(SPANDSP_USE_FIXED_POINTx)
- /*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */
- int16_t rrc_filter[V22BIS_RX_FILTER_STEPS];
-#else
- /*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */
- float rrc_filter[V22BIS_RX_FILTER_STEPS];
-#endif
/*! \brief Current offset into the RRC pulse shaping filter buffer. */
int rrc_filter_step;
/*! \brief >0 if a signal above the minimum is present. It may or may not be a V.22bis signal. */
int signal_present;
- /*! \brief A measure of how much mismatch there is between the real constellation,
- and the decoded symbol positions. */
- float training_error;
-
/*! \brief The current phase of the carrier (i.e. the DDS parameter). */
uint32_t carrier_phase;
/*! \brief The update rate for the phase of the carrier (i.e. the DDS increment). */
int32_t carrier_phase_rate;
- /*! \brief The proportional part of the carrier tracking filter. */
- float carrier_track_p;
- /*! \brief The integral part of the carrier tracking filter. */
- float carrier_track_i;
-
/*! \brief A callback function which may be enabled to report every symbol's
constellation position. */
qam_report_handler_t qam_report;
int32_t carrier_on_power;
/*! \brief The power meter level at which carrier off is declared. */
int32_t carrier_off_power;
+
+ int constellation_state;
+
+#if defined(SPANDSP_USE_FIXED_POINTx)
/*! \brief The scaling factor accessed by the AGC algorithm. */
float agc_scaling;
-
- int constellation_state;
+ /*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */
+ int16_t rrc_filter[V22BIS_RX_FILTER_STEPS];
/*! \brief The current delta factor for updating the equalizer coefficients. */
float eq_delta;
-#if defined(SPANDSP_USE_FIXED_POINTx)
/*! \brief The adaptive equalizer coefficients. */
complexi_t eq_coeff[2*V22BIS_EQUALIZER_LEN + 1];
/*! \brief The equalizer signal buffer. */
complexi_t eq_buf[V22BIS_EQUALIZER_MASK + 1];
+
+ /*! \brief A measure of how much mismatch there is between the real constellation,
+ and the decoded symbol positions. */
+ float training_error;
+ /*! \brief The proportional part of the carrier tracking filter. */
+ float carrier_track_p;
+ /*! \brief The integral part of the carrier tracking filter. */
+ float carrier_track_i;
#else
+ /*! \brief The scaling factor accessed by the AGC algorithm. */
+ float agc_scaling;
+ /*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */
+ float rrc_filter[V22BIS_RX_FILTER_STEPS];
+
+ /*! \brief The current delta factor for updating the equalizer coefficients. */
+ float eq_delta;
/*! \brief The adaptive equalizer coefficients. */
complexf_t eq_coeff[2*V22BIS_EQUALIZER_LEN + 1];
/*! \brief The equalizer signal buffer. */
complexf_t eq_buf[V22BIS_EQUALIZER_MASK + 1];
+
+ /*! \brief A measure of how much mismatch there is between the real constellation,
+ and the decoded symbol positions. */
+ float training_error;
+ /*! \brief The proportional part of the carrier tracking filter. */
+ float carrier_track_p;
+ /*! \brief The integral part of the carrier tracking filter. */
+ float carrier_track_i;
#endif
/*! \brief Current offset into the equalizer buffer. */
int eq_step;
/* Transmit section */
struct
{
+#if defined(SPANDSP_USE_FIXED_POINTx)
+ /*! \brief The guard tone level. */
+ int16_t guard_tone_gain;
+ /*! \brief The gain factor needed to achieve the specified output power. */
+ int16_t gain;
+ /*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */
+ int16_t rrc_filter_re[V22BIS_TX_FILTER_STEPS];
+ int16_t rrc_filter_im[V22BIS_TX_FILTER_STEPS];
+#else
+ /*! \brief The guard tone level. */
+ float guard_tone_gain;
/*! \brief The gain factor needed to achieve the specified output power. */
float gain;
-
/*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */
- complexf_t rrc_filter[2*V22BIS_TX_FILTER_STEPS];
+ float rrc_filter_re[V22BIS_TX_FILTER_STEPS];
+ float rrc_filter_im[V22BIS_TX_FILTER_STEPS];
+#endif
+
/*! \brief Current offset into the RRC pulse shaping filter buffer. */
int rrc_filter_step;
uint32_t guard_phase;
/*! \brief The update rate for the phase of the guard tone (i.e. the DDS increment). */
int32_t guard_phase_rate;
- float guard_tone_gain;
/*! \brief The current fractional phase of the baud timing. */
int baud_phase;
/*! \brief The code number for the current position in the constellation. */
/*! \brief The gain factor needed to achieve the specified output power at 4800bps. */
int16_t gain_4800;
/*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */
- complexi16_t rrc_filter[2*V27TER_TX_FILTER_STEPS];
+ int16_t rrc_filter_re[V27TER_TX_FILTER_STEPS];
+ int16_t rrc_filter_im[V27TER_TX_FILTER_STEPS];
#else
/*! \brief The gain factor needed to achieve the specified output power at 2400bps. */
float gain_2400;
/*! \brief The gain factor needed to achieve the specified output power at 4800bps. */
float gain_4800;
/*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */
- complexf_t rrc_filter[2*V27TER_TX_FILTER_STEPS];
+ float rrc_filter_re[V27TER_TX_FILTER_STEPS];
+ float rrc_filter_im[V27TER_TX_FILTER_STEPS];
#endif
+
/*! \brief Current offset into the RRC pulse shaping filter buffer. */
int rrc_filter_step;
#if defined(SPANDSP_USE_FIXED_POINT)
/*! \brief Gain required to achieve the specified output power, not allowing
for the size of the current constellation. */
- float base_gain;
+ int16_t base_gain;
/*! \brief Gain required to achieve the specified output power, allowing
for the size of the current constellation. */
- int32_t gain;
+ int16_t gain;
/*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */
- complexi16_t rrc_filter[2*V29_TX_FILTER_STEPS];
+ int16_t rrc_filter_re[V29_TX_FILTER_STEPS];
+ int16_t rrc_filter_im[V29_TX_FILTER_STEPS];
#else
/*! \brief Gain required to achieve the specified output power, not allowing
for the size of the current constellation. */
for the size of the current constellation. */
float gain;
/*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */
- complexf_t rrc_filter[2*V29_TX_FILTER_STEPS];
+ float rrc_filter_re[V29_TX_FILTER_STEPS];
+ float rrc_filter_im[V29_TX_FILTER_STEPS];
#endif
+
/*! \brief Current offset into the RRC pulse shaping filter buffer. */
int rrc_filter_step;
#include "spandsp/private/v22bis.h"
#if defined(SPANDSP_USE_FIXED_POINTx)
+#define FP_SCALE FP_Q_6_10
#include "v22bis_tx_fixed_rrc.h"
#else
+#define FP_SCALE(x) (x)
#include "v22bis_tx_floating_rrc.h"
#endif
1, 0, 2, 3
};
+#if defined(SPANDSP_USE_FIXED_POINTx)
+const complexi16_t v22bis_constellation[16] =
+#else
const complexf_t v22bis_constellation[16] =
+#endif
{
- { 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}
+ {FP_SCALE( 1.0f), FP_SCALE( 1.0f)},
+ {FP_SCALE( 3.0f), FP_SCALE( 1.0f)}, /* 1200bps 00 */
+ {FP_SCALE( 1.0f), FP_SCALE( 3.0f)},
+ {FP_SCALE( 3.0f), FP_SCALE( 3.0f)},
+ {FP_SCALE(-1.0f), FP_SCALE( 1.0f)},
+ {FP_SCALE(-1.0f), FP_SCALE( 3.0f)}, /* 1200bps 01 */
+ {FP_SCALE(-3.0f), FP_SCALE( 1.0f)},
+ {FP_SCALE(-3.0f), FP_SCALE( 3.0f)},
+ {FP_SCALE(-1.0f), FP_SCALE(-1.0f)},
+ {FP_SCALE(-3.0f), FP_SCALE(-1.0f)}, /* 1200bps 10 */
+ {FP_SCALE(-1.0f), FP_SCALE(-3.0f)},
+ {FP_SCALE(-3.0f), FP_SCALE(-3.0f)},
+ {FP_SCALE( 1.0f), FP_SCALE(-1.0f)},
+ {FP_SCALE( 1.0f), FP_SCALE(-3.0f)}, /* 1200bps 11 */
+ {FP_SCALE( 3.0f), FP_SCALE(-1.0f)},
+ {FP_SCALE( 3.0f), FP_SCALE(-3.0f)}
};
static int fake_get_bit(void *user_data)
}
/*- End of function --------------------------------------------------------*/
+#if defined(SPANDSP_USE_FIXED_POINTx)
+static complexi16_t training_get(v22bis_state_t *s)
+#else
static complexf_t training_get(v22bis_state_t *s)
+#endif
{
- int bits;
+#if defined(SPANDSP_USE_FIXED_POINT)
+ static const complexi16_t zero = {0, 0};
+#else
static const complexf_t zero = {0.0f, 0.0f};
+#endif
+ int bits;
/* V.22bis training sequence */
switch (s->tx.training)
}
/*- End of function --------------------------------------------------------*/
+#if defined(SPANDSP_USE_FIXED_POINTx)
+static complexi16_t getbaud(v22bis_state_t *s)
+#else
static complexf_t getbaud(v22bis_state_t *s)
+#endif
{
+#if defined(SPANDSP_USE_FIXED_POINTx)
+ static const complexi16_t zero = {0, 0};
+#else
+ static const complexf_t zero = {0.0f, 0.0f};
+#endif
int bits;
if (s->tx.training)
if (s->tx.shutdown)
{
if (++s->tx.shutdown > 10)
- return complex_setf(0.0f, 0.0f);
+ return zero;
}
/* The first two bits define the quadrant */
bits = get_scrambled_bit(s);
SPAN_DECLARE_NONSTD(int) v22bis_tx(v22bis_state_t *s, int16_t amp[], int len)
{
+#if defined(SPANDSP_USE_FIXED_POINTx)
+ complexi16_t v;
+ complexi32_t x;
+ complexi32_t z;
+ int16_t iamp;
+#else
+ complexf_t v;
complexf_t x;
complexf_t z;
- int i;
- int sample;
float famp;
+#endif
+ int sample;
if (s->tx.shutdown > 10)
return 0;
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);
+ v = getbaud(s);
+ s->tx.rrc_filter_re[s->tx.rrc_filter_step] = v.re;
+ s->tx.rrc_filter_im[s->tx.rrc_filter_step] = v.im;
if (++s->tx.rrc_filter_step >= V22BIS_TX_FILTER_STEPS)
s->tx.rrc_filter_step = 0;
}
+#if defined(SPANDSP_USE_FIXED_POINTx)
/* 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 = vec_circular_dot_prodi16(s->tx.rrc_filter_re, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->tx.baud_phase], V22BIS_TX_FILTER_STEPS, s->tx.rrc_filter_step) >> 14;
+ x.im = vec_circular_dot_prodi16(s->tx.rrc_filter_im, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->tx.baud_phase], V22BIS_TX_FILTER_STEPS, s->tx.rrc_filter_step) >> 14;
+ /* Now create and modulate the carrier */
+ z = dds_complexi32(&s->tx.carrier_phase, s->tx.carrier_phase_rate);
+ iamp = (x.re*z.re - x.im*z.im) >> 15;
+ iamp = (int16_t) (((int32_t) iamp*s->tx.gain) >> 11);
+ if (s->tx.guard_phase_rate && (s->tx.rrc_filter_re[s->tx.rrc_filter_step] != 0 || s->tx.rrc_filter_im[s->tx.rrc_filter_step] != 0))
{
- 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;
+ /* Add the guard tone */
+ iamp += dds_mod(&s->tx.guard_phase, s->tx.guard_phase_rate, s->tx.guard_tone_gain, 0);
}
+ /* Don't bother saturating. We should never clip. */
+ amp[sample] = iamp;
+#else
+ /* Root raised cosine pulse shaping at baseband */
+ x.re = vec_circular_dot_prodf(s->tx.rrc_filter_re, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->tx.baud_phase], V22BIS_TX_FILTER_STEPS, s->tx.rrc_filter_step);
+ x.im = vec_circular_dot_prodf(s->tx.rrc_filter_im, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->tx.baud_phase], V22BIS_TX_FILTER_STEPS, s->tx.rrc_filter_step);
/* Now create and modulate the carrier */
z = dds_complexf(&s->tx.carrier_phase, s->tx.carrier_phase_rate);
famp = (x.re*z.re - x.im*z.im)*s->tx.gain;
- if (s->tx.guard_phase_rate && (s->tx.rrc_filter[s->tx.rrc_filter_step].re != 0.0f || s->tx.rrc_filter[s->tx.rrc_filter_step].im != 0.0f))
+ if (s->tx.guard_phase_rate && (s->tx.rrc_filter_re[s->tx.rrc_filter_step] != 0.0f || s->tx.rrc_filter_im[s->tx.rrc_filter_step] != 0.0f))
{
/* Add the guard tone */
famp += dds_modf(&s->tx.guard_phase, s->tx.guard_phase_rate, s->tx.guard_tone_gain, 0);
}
/* Don't bother saturating. We should never clip. */
amp[sample] = (int16_t) lfastrintf(famp);
+#endif
}
return sample;
}
SPAN_DECLARE(void) v22bis_tx_power(v22bis_state_t *s, float power)
{
- float l;
+ float sig_power;
+ float guard_tone_power;
+ float sig_gain;
+ float guard_tone_gain;
+ /* If is there is a guard tone we need to scale down the signal power a bit, so the aggregate of the signal
+ and guard tone power is the specified power. */
if (s->tx.guard_phase_rate == dds_phase_ratef(550.0f))
{
- 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_tone_gain = l*32768.0f;
+ sig_power = power - 1.0f;
+ guard_tone_power = sig_power - 3.0f;
}
else if(s->tx.guard_phase_rate == dds_phase_ratef(1800.0f))
{
- 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_tone_gain = l*32768.0f;
+ sig_power = power - 0.55f;
+ guard_tone_power = sig_power - 6.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_tone_gain = 0;
+ sig_power = power;
+ guard_tone_power = -9999.0f;
}
+ sig_gain = 0.4490f*powf(10.0f, (sig_power - DBM0_MAX_POWER)/20.0f)*32768.0f/TX_PULSESHAPER_GAIN;
+ guard_tone_gain = powf(10.0f, (guard_tone_power - DBM0_MAX_POWER)/20.0f)*32768.0f;
+#if defined(SPANDSP_USE_FIXED_POINTx)
+ s->tx.gain = (int16_t) sig_gain;
+ s->tx.guard_tone_gain = (int16_t) guard_tone_gain;
+#else
+ s->tx.gain = sig_gain;
+ s->tx.guard_tone_gain = guard_tone_gain;
+#endif
}
/*- End of function --------------------------------------------------------*/
static int v22bis_tx_restart(v22bis_state_t *s)
{
- cvec_zerof(s->tx.rrc_filter, sizeof(s->tx.rrc_filter)/sizeof(s->tx.rrc_filter[0]));
+#if defined(SPANDSP_USE_FIXED_POINTx)
+ vec_zeroi16(s->tx.rrc_filter_re, sizeof(s->tx.rrc_filter_re)/sizeof(s->tx.rrc_filter_re[0]));
+ vec_zeroi16(s->tx.rrc_filter_im, sizeof(s->tx.rrc_filter_im)/sizeof(s->tx.rrc_filter_im[0]));
+#else
+ vec_zerof(s->tx.rrc_filter_re, sizeof(s->tx.rrc_filter_re)/sizeof(s->tx.rrc_filter_re[0]));
+ vec_zerof(s->tx.rrc_filter_im, sizeof(s->tx.rrc_filter_im)/sizeof(s->tx.rrc_filter_im[0]));
+#endif
s->tx.rrc_filter_step = 0;
s->tx.scramble_reg = 0;
s->tx.scrambler_pattern_count = 0;
SPAN_DECLARE_NONSTD(int) v27ter_tx(v27ter_tx_state_t *s, int16_t amp[], int len)
{
#if defined(SPANDSP_USE_FIXED_POINT)
- complexi_t x;
- complexi_t z;
+ complexi16_t v;
+ complexi32_t x;
+ complexi32_t z;
+ int16_t iamp;
#else
+ complexf_t v;
complexf_t x;
complexf_t z;
+ float famp;
#endif
- int i;
int sample;
if (s->training_step >= V27TER_TRAINING_SHUTDOWN_END)
if (++s->baud_phase >= 5)
{
s->baud_phase -= 5;
- s->rrc_filter[s->rrc_filter_step] =
- s->rrc_filter[s->rrc_filter_step + V27TER_TX_FILTER_STEPS] = getbaud(s);
+ v = getbaud(s);;
+ s->rrc_filter_re[s->rrc_filter_step] = v.re;
+ s->rrc_filter_im[s->rrc_filter_step] = v.im;
if (++s->rrc_filter_step >= V27TER_TX_FILTER_STEPS)
s->rrc_filter_step = 0;
}
- /* Root raised cosine pulse shaping at baseband */
#if defined(SPANDSP_USE_FIXED_POINT)
- x = complex_seti(0, 0);
- for (i = 0; i < V27TER_TX_FILTER_STEPS; i++)
- {
- x.re += (int32_t) tx_pulseshaper_4800[TX_PULSESHAPER_4800_COEFF_SETS - 1 - s->baud_phase][i]*(int32_t) s->rrc_filter[i + s->rrc_filter_step].re;
- x.im += (int32_t) tx_pulseshaper_4800[TX_PULSESHAPER_4800_COEFF_SETS - 1 - s->baud_phase][i]*(int32_t) s->rrc_filter[i + s->rrc_filter_step].im;
- }
+ /* Root raised cosine pulse shaping at baseband */
+ x.re = vec_circular_dot_prodi16(s->rrc_filter_re, tx_pulseshaper_4800[TX_PULSESHAPER_4800_COEFF_SETS - 1 - s->baud_phase], V27TER_TX_FILTER_STEPS, s->rrc_filter_step) >> (10 + 4);
+ x.im = vec_circular_dot_prodi16(s->rrc_filter_im, tx_pulseshaper_4800[TX_PULSESHAPER_4800_COEFF_SETS - 1 - s->baud_phase], V27TER_TX_FILTER_STEPS, s->rrc_filter_step) >> (10 + 4);
/* Now create and modulate the carrier */
- x.re >>= 14;
- x.im >>= 14;
- z = dds_complexi(&(s->carrier_phase), s->carrier_phase_rate);
+ z = dds_complexi32(&s->carrier_phase, s->carrier_phase_rate);
+ iamp = ((int32_t) x.re*z.re - x.im*z.im) >> 15;
/* Don't bother saturating. We should never clip. */
- i = (x.re*z.re - x.im*z.im) >> 15;
- amp[sample] = (int16_t) ((i*s->gain_4800) >> 15);
+ amp[sample] = (int16_t) (((int32_t) iamp*s->gain_4800) >> 11);
#else
- x = complex_setf(0.0f, 0.0f);
- for (i = 0; i < V27TER_TX_FILTER_STEPS; i++)
- {
- x.re += tx_pulseshaper_4800[TX_PULSESHAPER_4800_COEFF_SETS - 1 - s->baud_phase][i]*s->rrc_filter[i + s->rrc_filter_step].re;
- x.im += tx_pulseshaper_4800[TX_PULSESHAPER_4800_COEFF_SETS - 1 - s->baud_phase][i]*s->rrc_filter[i + s->rrc_filter_step].im;
- }
+ /* Root raised cosine pulse shaping at baseband */
+ x.re = vec_circular_dot_prodf(s->rrc_filter_re, tx_pulseshaper_4800[TX_PULSESHAPER_4800_COEFF_SETS - 1 - s->baud_phase], V27TER_TX_FILTER_STEPS, s->rrc_filter_step);
+ x.im = vec_circular_dot_prodf(s->rrc_filter_im, tx_pulseshaper_4800[TX_PULSESHAPER_4800_COEFF_SETS - 1 - s->baud_phase], V27TER_TX_FILTER_STEPS, s->rrc_filter_step);
/* Now create and modulate the carrier */
- z = dds_complexf(&(s->carrier_phase), s->carrier_phase_rate);
+ z = dds_complexf(&s->carrier_phase, s->carrier_phase_rate);
+ famp = x.re*z.re - x.im*z.im;
/* Don't bother saturating. We should never clip. */
- amp[sample] = (int16_t) lfastrintf((x.re*z.re - x.im*z.im)*s->gain_4800);
+ amp[sample] = (int16_t) lfastrintf(famp*s->gain_4800);
#endif
}
}
if ((s->baud_phase += 3) >= 20)
{
s->baud_phase -= 20;
- s->rrc_filter[s->rrc_filter_step] =
- s->rrc_filter[s->rrc_filter_step + V27TER_TX_FILTER_STEPS] = getbaud(s);
+ v = getbaud(s);
+ s->rrc_filter_re[s->rrc_filter_step] = v.re;
+ s->rrc_filter_im[s->rrc_filter_step] = v.im;
if (++s->rrc_filter_step >= V27TER_TX_FILTER_STEPS)
s->rrc_filter_step = 0;
}
- /* Root raised cosine pulse shaping at baseband */
#if defined(SPANDSP_USE_FIXED_POINT)
- x = complex_seti(0, 0);
- for (i = 0; i < V27TER_TX_FILTER_STEPS; i++)
- {
- x.re += (int32_t) tx_pulseshaper_2400[TX_PULSESHAPER_2400_COEFF_SETS - 1 - s->baud_phase][i]*(int32_t) s->rrc_filter[i + s->rrc_filter_step].re;
- x.im += (int32_t) tx_pulseshaper_2400[TX_PULSESHAPER_2400_COEFF_SETS - 1 - s->baud_phase][i]*(int32_t) s->rrc_filter[i + s->rrc_filter_step].im;
- }
+ /* Root raised cosine pulse shaping at baseband */
+ x.re = vec_circular_dot_prodi16(s->rrc_filter_re, tx_pulseshaper_2400[TX_PULSESHAPER_2400_COEFF_SETS - 1 - s->baud_phase], V27TER_TX_FILTER_STEPS, s->rrc_filter_step) >> (10 + 4);
+ x.im = vec_circular_dot_prodi16(s->rrc_filter_im, tx_pulseshaper_2400[TX_PULSESHAPER_2400_COEFF_SETS - 1 - s->baud_phase], V27TER_TX_FILTER_STEPS, s->rrc_filter_step) >> (10 + 4);
/* Now create and modulate the carrier */
- x.re >>= 14;
- x.im >>= 14;
- z = dds_complexi(&(s->carrier_phase), s->carrier_phase_rate);
+ z = dds_complexi32(&s->carrier_phase, s->carrier_phase_rate);
+ iamp = ((int32_t) x.re*z.re - x.im*z.im) >> 15;
/* Don't bother saturating. We should never clip. */
- i = (x.re*z.re - x.im*z.im) >> 15;
- amp[sample] = (int16_t) ((i*s->gain_2400) >> 15);
+ amp[sample] = (int16_t) (((int32_t) iamp*s->gain_2400) >> 11);
#else
- x = complex_setf(0.0f, 0.0f);
- for (i = 0; i < V27TER_TX_FILTER_STEPS; i++)
- {
- x.re += tx_pulseshaper_2400[TX_PULSESHAPER_2400_COEFF_SETS - 1 - s->baud_phase][i]*s->rrc_filter[i + s->rrc_filter_step].re;
- x.im += tx_pulseshaper_2400[TX_PULSESHAPER_2400_COEFF_SETS - 1 - s->baud_phase][i]*s->rrc_filter[i + s->rrc_filter_step].im;
- }
+ /* Root raised cosine pulse shaping at baseband */
+ x.re = vec_circular_dot_prodf(s->rrc_filter_re, tx_pulseshaper_2400[TX_PULSESHAPER_2400_COEFF_SETS - 1 - s->baud_phase], V27TER_TX_FILTER_STEPS, s->rrc_filter_step);
+ x.im = vec_circular_dot_prodf(s->rrc_filter_im, tx_pulseshaper_2400[TX_PULSESHAPER_2400_COEFF_SETS - 1 - s->baud_phase], V27TER_TX_FILTER_STEPS, s->rrc_filter_step);
/* Now create and modulate the carrier */
- z = dds_complexf(&(s->carrier_phase), s->carrier_phase_rate);
+ z = dds_complexf(&s->carrier_phase, s->carrier_phase_rate);
+ famp = x.re*z.re - x.im*z.im;
/* Don't bother saturating. We should never clip. */
- amp[sample] = (int16_t) lfastrintf((x.re*z.re - x.im*z.im)*s->gain_2400);
+ amp[sample] = (int16_t) lfastrintf(famp*s->gain_2400);
#endif
}
}
SPAN_DECLARE(void) v27ter_tx_power(v27ter_tx_state_t *s, float power)
{
- float l;
+ float gain;
- l = powf(10.0f, (power - DBM0_MAX_POWER)/20.0f)*32768.0f;
+ gain = powf(10.0f, (power - DBM0_MAX_POWER)/20.0f)*32768.0f;
#if defined(SPANDSP_USE_FIXED_POINT)
- s->gain_2400 = 16.0f*1.024f*(32767.0f/28828.51f)*l/TX_PULSESHAPER_2400_GAIN;
- s->gain_4800 = 16.0f*1.024f*(32767.0f/28828.46f)*l/TX_PULSESHAPER_4800_GAIN;
+ s->gain_2400 = (int16_t) (gain/TX_PULSESHAPER_2400_GAIN);
+ s->gain_4800 = (int16_t) (gain/TX_PULSESHAPER_4800_GAIN);
#else
- s->gain_2400 = l/TX_PULSESHAPER_2400_GAIN;
- s->gain_4800 = l/TX_PULSESHAPER_4800_GAIN;
+ s->gain_2400 = gain/TX_PULSESHAPER_2400_GAIN;
+ s->gain_4800 = gain/TX_PULSESHAPER_4800_GAIN;
#endif
}
/*- End of function --------------------------------------------------------*/
return -1;
s->bit_rate = bit_rate;
#if defined(SPANDSP_USE_FIXED_POINT)
- cvec_zeroi16(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
+ vec_zeroi16(s->rrc_filter_re, sizeof(s->rrc_filter_re)/sizeof(s->rrc_filter_re[0]));
+ vec_zeroi16(s->rrc_filter_im, sizeof(s->rrc_filter_im)/sizeof(s->rrc_filter_im[0]));
#else
- cvec_zerof(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
+ vec_zerof(s->rrc_filter_re, sizeof(s->rrc_filter_re)/sizeof(s->rrc_filter_re[0]));
+ vec_zerof(s->rrc_filter_im, sizeof(s->rrc_filter_im)/sizeof(s->rrc_filter_im[0]));
#endif
s->rrc_filter_step = 0;
s->scramble_reg = 0x3C;
SPAN_DECLARE_NONSTD(int) v29_tx(v29_tx_state_t *s, int16_t amp[], int len)
{
#if defined(SPANDSP_USE_FIXED_POINT)
- complexi_t x;
- complexi_t z;
+ complexi16_t v;
+ complexi32_t x;
+ complexi32_t z;
+ int16_t iamp;
#else
+ complexf_t v;
complexf_t x;
complexf_t z;
+ float famp;
#endif
- int i;
int sample;
if (s->training_step >= V29_TRAINING_SHUTDOWN_END)
if ((s->baud_phase += 3) >= 10)
{
s->baud_phase -= 10;
- s->rrc_filter[s->rrc_filter_step] =
- s->rrc_filter[s->rrc_filter_step + V29_TX_FILTER_STEPS] = getbaud(s);
+ v = getbaud(s);
+ s->rrc_filter_re[s->rrc_filter_step] = v.re;
+ s->rrc_filter_im[s->rrc_filter_step] = v.im;
if (++s->rrc_filter_step >= V29_TX_FILTER_STEPS)
s->rrc_filter_step = 0;
}
- /* Root raised cosine pulse shaping at baseband */
#if defined(SPANDSP_USE_FIXED_POINT)
- x = complex_seti(0, 0);
- for (i = 0; i < V29_TX_FILTER_STEPS; i++)
- {
- x.re += (int32_t) tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->baud_phase][i]*(int32_t) s->rrc_filter[i + s->rrc_filter_step].re;
- x.im += (int32_t) tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->baud_phase][i]*(int32_t) s->rrc_filter[i + s->rrc_filter_step].im;
- }
+ /* Root raised cosine pulse shaping at baseband */
+ x.re = vec_circular_dot_prodi16(s->rrc_filter_re, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->baud_phase], V29_TX_FILTER_STEPS, s->rrc_filter_step) >> 4;
+ x.im = vec_circular_dot_prodi16(s->rrc_filter_im, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->baud_phase], V29_TX_FILTER_STEPS, s->rrc_filter_step) >> 4;
/* Now create and modulate the carrier */
- x.re >>= 4;
- x.im >>= 4;
- z = dds_complexi(&(s->carrier_phase), s->carrier_phase_rate);
+ z = dds_complexi32(&s->carrier_phase, s->carrier_phase_rate);
+ iamp = ((int32_t) x.re*z.re - x.im*z.im) >> 15;
/* Don't bother saturating. We should never clip. */
- i = (x.re*z.re - x.im*z.im) >> 15;
- amp[sample] = (int16_t) ((i*s->gain) >> 15);
+ amp[sample] = (int16_t) (((int32_t) iamp*s->gain) >> 11);
#else
- x = complex_setf(0.0f, 0.0f);
- for (i = 0; i < V29_TX_FILTER_STEPS; i++)
- {
- x.re += tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->baud_phase][i]*s->rrc_filter[i + s->rrc_filter_step].re;
- x.im += tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->baud_phase][i]*s->rrc_filter[i + s->rrc_filter_step].im;
- }
+ /* Root raised cosine pulse shaping at baseband */
+ x.re = vec_circular_dot_prodf(s->rrc_filter_re, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->baud_phase], V29_TX_FILTER_STEPS, s->rrc_filter_step);
+ x.im = vec_circular_dot_prodf(s->rrc_filter_im, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->baud_phase], V29_TX_FILTER_STEPS, s->rrc_filter_step);
/* Now create and modulate the carrier */
- z = dds_complexf(&(s->carrier_phase), s->carrier_phase_rate);
+ z = dds_complexf(&s->carrier_phase, s->carrier_phase_rate);
+ famp = x.re*z.re - x.im*z.im;
/* Don't bother saturating. We should never clip. */
- amp[sample] = (int16_t) lfastrintf((x.re*z.re - x.im*z.im)*s->gain);
+ amp[sample] = (int16_t) lfastrintf(famp*s->gain);
#endif
}
return sample;
switch (s->bit_rate)
{
case 9600:
- s->gain = 0.387f*s->base_gain*16.0f*32767.0f/30672.52f;
+ s->gain = ((int32_t) FP_Q_4_12(0.387f)*s->base_gain) >> 12;
break;
case 7200:
- s->gain = 0.605f*s->base_gain*16.0f*32767.0f/30672.52f;
+ s->gain = ((int32_t) FP_Q_4_12(0.605f)*s->base_gain) >> 12;
break;
case 4800:
- s->gain = 0.470f*s->base_gain*16.0f*32767.0f/30672.52f;
+ s->gain = ((int32_t) FP_Q_4_12(0.470f)*s->base_gain) >> 12;
break;
default:
break;
SPAN_DECLARE(void) v29_tx_power(v29_tx_state_t *s, float power)
{
+ float gain;
+
/* The constellation does not maintain constant average power as we change bit rates.
We need to scale the gain we get here by a bit rate specific scaling factor each
time we restart the modem. */
- s->base_gain = powf(10.0f, (power - DBM0_MAX_POWER)/20.0f)*32768.0f/TX_PULSESHAPER_GAIN;
+ gain = powf(10.0f, (power - DBM0_MAX_POWER)/20.0f)*32768.0f/TX_PULSESHAPER_GAIN;
+#if defined(SPANDSP_USE_FIXED_POINT)
+ s->base_gain = (int16_t) gain;
+#else
+ s->base_gain = gain;
+#endif
set_working_gain(s);
}
/*- End of function --------------------------------------------------------*/
return -1;
}
#if defined(SPANDSP_USE_FIXED_POINT)
- cvec_zeroi16(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
+ vec_zeroi16(s->rrc_filter_re, sizeof(s->rrc_filter_re)/sizeof(s->rrc_filter_re[0]));
+ vec_zeroi16(s->rrc_filter_im, sizeof(s->rrc_filter_im)/sizeof(s->rrc_filter_im[0]));
#else
- cvec_zerof(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
+ vec_zerof(s->rrc_filter_re, sizeof(s->rrc_filter_re)/sizeof(s->rrc_filter_re[0]));
+ vec_zerof(s->rrc_filter_im, sizeof(s->rrc_filter_im)/sizeof(s->rrc_filter_im[0]));
#endif
s->rrc_filter_step = 0;
s->scramble_reg = 0;