spandsp DSP tweaks to avoid problems with the LPC10 code compiled with the latest GCC 6.2 series compilers. Various other additional tweaks to spandsp.

This commit is contained in:
Steve Underwood 2017-07-14 00:29:20 +01:00
parent 62fe767e65
commit 9732d32503
33 changed files with 726 additions and 298 deletions

View File

@ -37,7 +37,7 @@ m4_include(m4/ax_c99_features.m4)
m4_include(m4/ax_check_export_capability.m4)
m4_include(m4/ax_check_arm_neon.m4)
m4_include(m4/ax_func_aligned_alloc.m4)
m4_include(m4/memmove.m4)
m4_include(m4/ac_func_memmove.m4)
AC_CONFIG_SRCDIR([src/tone_generate.c])
AC_CONFIG_AUX_DIR([config])

View File

@ -5594,6 +5594,15 @@ SPAN_DECLARE(void) at_set_modem_control_handler(at_state_t *s,
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(void) at_set_at_tx_handler(at_state_t *s,
at_tx_handler_t at_tx_handler,
void *at_tx_user_data)
{
s->at_tx_handler = at_tx_handler;
s->at_tx_user_data = at_tx_user_data;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(logging_state_t *) at_get_logging_state(at_state_t *s)
{
return &s->logging;

View File

@ -52,6 +52,11 @@
#if defined(HAVE_MATH_H)
#include <math.h>
#endif
#if defined(HAVE_STDBOOL_H)
#include <stdbool.h>
#else
#include "spandsp/stdbool.h"
#endif
#include "floating_fudge.h"
#include "spandsp/telephony.h"
@ -62,67 +67,76 @@
#include "spandsp/private/awgn.h"
/* Gaussian noise generator constants */
/* Random number generator constants */
#define M1 259200
#define IA1 7141
#define IC1 54773
#define RM1 (1.0/M1)
#define RM1 (1.0/(double) M1)
#define M2 134456
#define IA2 8121
#define IC2 28411
#define RM2 (1.0/M2)
#define RM2 (1.0/(double) M2)
#define M3 243000
#define IA3 4561
#define IC3 51349
static double ran1(awgn_state_t *s)
static void ran_init(awgn_state_t *s, int idum)
{
int j;
if (idum < 0)
idum = -idum;
s->ix1 = (IC1 + (int32_t) idum)%M1;
s->ix1 = (IA1*s->ix1 + IC1)%M1;
s->ix2 = s->ix1%M2;
s->ix1 = (IA1*s->ix1 + IC1)%M1;
s->ix3 = s->ix1%M3;
for (j = 0; j < 97; j++)
{
s->ix1 = (IA1*s->ix1 + IC1)%M1;
s->ix2 = (IA2*s->ix2 + IC2)%M2;
s->r[j] = (s->ix1 + s->ix2*RM2)*RM1;
}
}
/*- End of function --------------------------------------------------------*/
static double ran(awgn_state_t *s)
{
double temp;
int j;
/* This produces evenly spread random numbers between 0.0 and 1.0 */
s->ix1 = (IA1*s->ix1 + IC1)%M1;
s->ix2 = (IA2*s->ix2 + IC2)%M2;
s->ix3 = (IA3*s->ix3 + IC3)%M3;
j = 1 + ((97*s->ix3)/M3);
if (j > 97 || j < 1)
j = (97*s->ix3)/M3;
if (j > 96 || j < 0)
{
/* Error */
return -1;
temp = -1.0;
}
else
{
temp = s->r[j];
s->r[j] = (s->ix1 + s->ix2*RM2)*RM1;
}
temp = s->r[j];
s->r[j] = (s->ix1 + s->ix2*RM2)*RM1;
return temp;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(awgn_state_t *) awgn_init_dbov(awgn_state_t *s, int idum, float level)
{
int j;
if (s == NULL)
{
if ((s = (awgn_state_t *) span_alloc(sizeof(*s))) == NULL)
return NULL;
}
if (idum < 0)
idum = -idum;
ran_init(s, idum);
s->rms = pow(10.0, level/20.0)*32768.0;
s->ix1 = (IC1 + idum)%M1;
s->ix1 = (IA1*s->ix1 + IC1)%M1;
s->ix2 = s->ix1%M2;
s->ix1 = (IA1*s->ix1 + IC1)%M1;
s->ix3 = s->ix1%M3;
s->r[0] = 0.0;
for (j = 1; j <= 97; j++)
{
s->ix1 = (IA1*s->ix1 + IC1)%M1;
s->ix2 = (IA2*s->ix2 + IC2)%M2;
s->r[j] = (s->ix1 + s->ix2*RM2)*RM1;
}
s->gset = 0.0;
s->iset = 0;
s->amp2 = 0.0;
s->odd = true;
return s;
}
/*- End of function --------------------------------------------------------*/
@ -148,31 +162,30 @@ SPAN_DECLARE(int) awgn_free(awgn_state_t *s)
SPAN_DECLARE(int16_t) awgn(awgn_state_t *s)
{
double fac;
double r;
double v1;
double v2;
double amp;
if (s->iset == 0)
/* The polar method of generating a Gaussian distribution */
if ((s->odd = !s->odd))
{
do
{
v1 = 2.0*ran1(s) - 1.0;
v2 = 2.0*ran1(s) - 1.0;
r = v1*v1 + v2*v2;
}
while (r >= 1.0);
fac = sqrt(-2.0*log(r)/r);
s->gset = v1*fac;
s->iset = 1;
amp = v2*fac*s->rms;
amp = s->amp2;
}
else
{
s->iset = 0;
amp = s->gset*s->rms;
do
{
v1 = 2.0*ran(s) - 1.0;
v2 = 2.0*ran(s) - 1.0;
r = v1*v1 + v2*v2;
}
while (r >= 1.0);
r = sqrt(-2.0*log(r)/r);
s->amp2 = v1*r;
amp = v2*r;
}
amp *= s->rms;
return fsaturate(amp);
}
/*- End of function --------------------------------------------------------*/

View File

@ -63,6 +63,7 @@
#include "spandsp/tone_detect.h"
#include "spandsp/tone_generate.h"
#include "spandsp/async.h"
#include "spandsp/at_interpreter.h"
#include "spandsp/silence_gen.h"
#include "spandsp/fsk.h"
#include "spandsp/v29rx.h"
@ -86,6 +87,7 @@
#include "spandsp/data_modems.h"
#include "spandsp/private/logging.h"
#include "spandsp/private/at_interpreter.h"
#include "spandsp/private/silence_gen.h"
#include "spandsp/private/power_meter.h"
#include "spandsp/private/fsk.h"
@ -139,6 +141,7 @@ SPAN_DECLARE(const char *) data_modems_modulation_to_str(int modulation_scheme)
case DATA_MODEM_V34:
return "V.34 duplex";
}
/*endswitch*/
return "???";
}
/*- End of function --------------------------------------------------------*/
@ -149,6 +152,13 @@ SPAN_DECLARE(logging_state_t *) data_modems_get_logging_state(data_modems_state_
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(void) data_modems_call_event(data_modems_state_t *s, int event)
{
span_log(&s->logging, SPAN_LOG_FLOW, "Call event %s (%d) received\n", at_call_state_to_str(event), event);
at_call_event(&s->at_state, event);
}
/*- End of function --------------------------------------------------------*/
static int async_get_byte(void *user_data)
{
data_modems_state_t *s;
@ -169,6 +179,7 @@ static void async_put_byte(void *user_data, int byte)
msg[0] = byte;
if (byte < 0)
s->put_msg(s->user_data, msg, byte);
/*endif*/
s->put_msg(s->user_data, msg, 1);
}
/*- End of function --------------------------------------------------------*/
@ -193,7 +204,9 @@ static void log_supported_modulations(data_modems_state_t *s, int modulation_sch
span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, "%s%s", comma, v8_modulation_to_str(modulation_schemes & (1 << i)));
comma = ", ";
}
/*endif*/
}
/*endfor*/
span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, " supported\n");
}
/*- End of function --------------------------------------------------------*/
@ -385,6 +398,7 @@ SPAN_DECLARE(void) data_modems_set_modem_type(data_modems_state_t *s, int which,
v8_parms.modem_connect_tone = MODEM_CONNECT_TONES_NONE;
else
v8_parms.modem_connect_tone = MODEM_CONNECT_TONES_ANSAM_PR;
/*endif*/
v8_parms.send_ci = false;
v8_parms.v92 = -1;
v8_parms.call_function = V8_CALL_V_SERIES;
@ -396,6 +410,9 @@ SPAN_DECLARE(void) data_modems_set_modem_type(data_modems_state_t *s, int which,
| V8_MOD_V23
| V8_MOD_V27TER
| V8_MOD_V29
#if defined(SPANDSP_SUPPORT_V34)
| V8_MOD_V34HDX
#endif
| 0;
v8_parms.protocol = V8_PROTOCOL_LAPM_V42;
#elif 1
@ -417,10 +434,10 @@ SPAN_DECLARE(void) data_modems_set_modem_type(data_modems_state_t *s, int which,
v8_parms.nsf = -1;
v8_parms.t66 = -1;
v8_init(&s->modems.v8, s->calling_party, &v8_parms, v8_handler, (void *) s);
logging = v8_get_logging_state(&s->modems.v8);
level = span_log_get_level(&s->logging);
span_log_set_level(logging, level);
span_log_set_tag(logging, "V.8");
logging = v8_get_logging_state(&s->modems.v8);
level = span_log_get_level(&s->logging);
span_log_set_level(logging, level);
span_log_set_tag(logging, "V.8");
break;
case DATA_MODEM_BELL103:
s->rx_handler = (span_rx_handler_t) &fsk_rx;
@ -438,6 +455,7 @@ SPAN_DECLARE(void) data_modems_set_modem_type(data_modems_state_t *s, int which,
fsk_rx_spec = &preset_fsk_specs[FSK_BELL103CH1];
fsk_tx_spec = &preset_fsk_specs[FSK_BELL103CH2];
}
/*endif*/
fsk_rx_init(&s->modems.fsk.rx, fsk_rx_spec, FSK_FRAME_MODE_SYNC, s->put_bit, s->put_user_data);
fsk_tx_init(&s->modems.fsk.tx, fsk_tx_spec, s->get_bit, s->get_user_data);
break;
@ -457,6 +475,7 @@ SPAN_DECLARE(void) data_modems_set_modem_type(data_modems_state_t *s, int which,
fsk_rx_spec = &preset_fsk_specs[FSK_V21CH1];
fsk_tx_spec = &preset_fsk_specs[FSK_V21CH2];
}
/*endif*/
fsk_rx_init(&s->modems.fsk.rx, fsk_rx_spec, FSK_FRAME_MODE_SYNC, s->put_bit, s->put_user_data);
fsk_tx_init(&s->modems.fsk.tx, fsk_tx_spec, s->get_bit, s->get_user_data);
break;
@ -487,6 +506,7 @@ SPAN_DECLARE(void) data_modems_set_modem_type(data_modems_state_t *s, int which,
fsk_rx_spec = &preset_fsk_specs[FSK_V23CH1];
fsk_tx_spec = &preset_fsk_specs[FSK_V23CH2];
}
/*endif*/
fsk_rx_init(&s->modems.fsk.rx, fsk_rx_spec, FSK_FRAME_MODE_SYNC, s->put_bit, s->put_user_data);
fsk_tx_init(&s->modems.fsk.tx, fsk_tx_spec, s->get_bit, s->get_user_data);
break;
@ -497,10 +517,10 @@ SPAN_DECLARE(void) data_modems_set_modem_type(data_modems_state_t *s, int which,
s->tx_handler = (span_tx_handler_t) &v22bis_tx;
s->tx_user_data = &s->modems.v22bis;
v22bis_init(&s->modems.v22bis, bit_rate, 0, s->calling_party, s->get_bit, s->get_user_data, s->put_bit, s->put_user_data);
logging = v22bis_get_logging_state(&s->modems.v22bis);
level = span_log_get_level(&s->logging);
span_log_set_level(logging, level);
span_log_set_tag(logging, "V.22bis");
logging = v22bis_get_logging_state(&s->modems.v22bis);
level = span_log_get_level(&s->logging);
span_log_set_level(logging, level);
span_log_set_tag(logging, "V.22bis");
break;
#if defined(SPANDSP_SUPPORT_V32BIS)
case DATA_MODEM_V32BIS:
@ -510,10 +530,10 @@ SPAN_DECLARE(void) data_modems_set_modem_type(data_modems_state_t *s, int which,
s->tx_handler = (span_tx_handler_t) &v32bis_tx;
s->tx_user_data = &s->modems.v32bis;
v32bis_init(&s->modems.v32bis, bit_rate, s->calling_party, s->get_bit, s->get_user_data, s->put_bit, s->put_user_data);
logging = v32bis_get_logging_state(&s->modems.v32bis);
level = span_log_get_level(&s->logging);
span_log_set_level(logging, level);
span_log_set_tag(logging, "V.32bis");
logging = v32bis_get_logging_state(&s->modems.v32bis);
level = span_log_get_level(&s->logging);
span_log_set_level(logging, level);
span_log_set_tag(logging, "V.32bis");
break;
#endif
#if defined(SPANDSP_SUPPORT_V34)
@ -524,13 +544,14 @@ SPAN_DECLARE(void) data_modems_set_modem_type(data_modems_state_t *s, int which,
s->tx_handler = (span_tx_handler_t) &v34_tx;
s->tx_user_data = &s->modems.v34;
v34_init(&s->modems.v34, baud_rate, bit_rate, s->calling_party, true, s->get_bit, s->get_user_data, s->put_bit, s->put_user_data);
logging = v34_get_logging_state(&s->modems.v34);
level = span_log_get_level(&s->logging);
span_log_set_level(logging, level);
span_log_set_tag(logging, "V.34");
logging = v34_get_logging_state(&s->modems.v34);
level = span_log_get_level(&s->logging);
span_log_set_level(logging, level);
span_log_set_tag(logging, "V.34");
break;
#endif
}
/*endswitch*/
s->current_modem = which;
}
/*- End of function --------------------------------------------------------*/
@ -541,9 +562,11 @@ SPAN_DECLARE(int) data_modems_rx(data_modems_state_t *s, const int16_t amp[], in
if (s->rx_handler == NULL)
return len;
/*endif*/
res = s->rx_handler(s->rx_user_data, amp, len);
if (s->current_modem != s->queued_modem)
data_modems_set_modem_type(s, s->queued_modem, s->queued_baud_rate, s->queued_bit_rate);
/*endif*/
return res;
}
/*- End of function --------------------------------------------------------*/
@ -552,6 +575,7 @@ SPAN_DECLARE(int) data_modems_rx_fillin(data_modems_state_t *s, int len)
{
if (s->rx_fillin_handler == NULL)
return len;
/*endif*/
return s->rx_fillin_handler(s->rx_user_data, len);
}
/*- End of function --------------------------------------------------------*/
@ -564,12 +588,52 @@ SPAN_DECLARE(int) data_modems_tx(data_modems_state_t *s, int16_t amp[], int max_
{
if (s->tx_handler == NULL)
break;
/*endif*/
len += s->tx_handler(s->tx_user_data, &amp[len], max_len - len);
}
/*endfor*/
return len;
}
/*- End of function --------------------------------------------------------*/
static int data_modems_control_handler(void *user_data, int op, const char *num)
{
data_modems_state_t *s;
s = (data_modems_state_t *) user_data;
switch (op)
{
case AT_MODEM_CONTROL_CALL:
s->call_samples = 0;
break;
case AT_MODEM_CONTROL_ANSWER:
s->call_samples = 0;
break;
case AT_MODEM_CONTROL_ONHOOK:
if (s->at_state.rx_signal_present)
{
s->at_state.rx_data_bytes = 0;
}
/*endif*/
break;
case AT_MODEM_CONTROL_RESTART:
return 0;
case AT_MODEM_CONTROL_DTE_TIMEOUT:
return 0;
}
/*endswitch*/
return s->modem_control_handler(s, s->modem_control_user_data, op, num);
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(void) data_modems_set_at_tx_handler(data_modems_state_t *s,
at_tx_handler_t at_tx_handler,
void *at_tx_user_data)
{
at_set_at_tx_handler(&s->at_state, at_tx_handler, at_tx_user_data);
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) data_modems_restart(data_modems_state_t *s)
{
return 0;
@ -578,21 +642,34 @@ SPAN_DECLARE(int) data_modems_restart(data_modems_state_t *s)
SPAN_DECLARE(data_modems_state_t *) data_modems_init(data_modems_state_t *s,
bool calling_party,
at_tx_handler_t at_tx_handler,
void *at_tx_user_data,
data_modems_control_handler_t modem_control_handler,
void *modem_control_user_data,
put_msg_func_t put_msg,
get_msg_func_t get_msg,
void *user_data)
{
if (at_tx_handler == NULL || modem_control_handler == NULL)
return NULL;
/*endif*/
if (s == NULL)
{
if ((s = (data_modems_state_t *) span_alloc(sizeof(*s))) == NULL)
return NULL;
/*endif*/
}
/*endif*/
memset(s, 0, sizeof(*s));
span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
span_log_set_protocol(&s->logging, "Modem");
dc_restore_init(&s->dc_restore);
s->modem_control_handler = modem_control_handler;
s->modem_control_user_data = modem_control_user_data;
s->put_msg = put_msg;
s->get_msg = get_msg;
s->user_data = user_data;
@ -602,6 +679,8 @@ SPAN_DECLARE(data_modems_state_t *) data_modems_init(data_modems_state_t *s,
data_modems_set_async_mode(s, 8, 1, 1);
at_init(&s->at_state, at_tx_handler, at_tx_user_data, data_modems_control_handler, s);
s->get_bit = async_tx_get_bit;
s->get_user_data = &s->async_tx;
s->put_bit = async_rx_put_bit;
@ -627,6 +706,7 @@ SPAN_DECLARE(int) data_modems_free(data_modems_state_t *s)
{
if (s)
span_free(s);
/*endif*/
return 0;
}
/*- End of function --------------------------------------------------------*/

View File

@ -89,6 +89,7 @@ static __inline__ void octet_set_and_count(hdlc_rx_state_t *s)
{
if (s->octet_count_report_interval == 0)
return;
/*endif*/
/* If we are not in octet counting mode, we start it.
If we are in octet counting mode, we update it. */
@ -625,6 +626,7 @@ SPAN_DECLARE(int) hdlc_tx_get_byte(hdlc_tx_state_t *s)
/* An input byte will generate between 8 and 10 output bits */
return (s->octets_in_progress >> s->num_bits) & 0xFF;
}
/*endif*/
/* Untimed idling on flags */
if (s->tx_end)
{
@ -644,8 +646,10 @@ SPAN_DECLARE(int) hdlc_tx_get_bit(hdlc_tx_state_t *s)
{
if ((s->byte = hdlc_tx_get_byte(s)) < 0)
return s->byte;
/*endif*/
s->bits = 8;
}
/*endif*/
s->bits--;
txbit = (s->byte >> s->bits) & 0x01;
return txbit;
@ -661,8 +665,10 @@ SPAN_DECLARE(int) hdlc_tx_get(hdlc_tx_state_t *s, uint8_t buf[], size_t max_len)
{
if ((x = hdlc_tx_get_byte(s)) == SIG_STATUS_END_OF_DATA)
return i;
/*endif*/
buf[i] = (uint8_t) x;
}
/*endfor*/
return (int) i;
}
/*- End of function --------------------------------------------------------*/

View File

@ -532,7 +532,7 @@ static int floyd_steinberg_dither_row(image_translate_state_t *s, uint8_t buf[])
s->output_row = -1;
}
}
/* Apply Floyd-Steinberg dithering to the 8 bit pixels, using a bustrophodontic
/* Apply Floyd-Steinberg dithering to the 8 bit pixels, using a bustrophedontic
scan, to reduce the grayscale image to pure black and white */
/* The first and last pixels in each row need special treatment, so we do not
step outside the row. */

View File

@ -564,7 +564,7 @@ void lpc10_analyse(lpc10_encode_state_t *s, float speech[], int32_t voice[], int
static const float precoef = 0.9375f;
float amdf[60];
float abuf[156];
float abuf[LPC10_MIN_PITCH];
float ivrc[2];
float temp;
float phi[100] /* was [10][10] */;
@ -634,7 +634,7 @@ void lpc10_analyse(lpc10_encode_state_t *s, float speech[], int32_t voice[], int
s->zpre = preemp(&s->inbuf[i - 181], &s->pebuf[i - 181], LPC10_SAMPLES_PER_FRAME, precoef, s->zpre);
onset(s, s->pebuf, s->osbuf, &s->osptr, 10, 181, 720, LPC10_SAMPLES_PER_FRAME);
lpc10_placev(s->osbuf, &s->osptr, 10, &s->obound[2], s->vwin, 3, LPC10_SAMPLES_PER_FRAME, 90, 156, 307, 462);
lpc10_placev(s->osbuf, &s->osptr, 10, &s->obound[2], s->vwin, 3, LPC10_SAMPLES_PER_FRAME, 90, LPC10_MIN_PITCH, 307, 462);
/* The Pitch Extraction algorithm estimates the pitch for a frame
of speech by locating the minimum of the average magnitude difference
function (AMDF). The AMDF operates on low-pass, inverse filtered
@ -655,7 +655,7 @@ void lpc10_analyse(lpc10_encode_state_t *s, float speech[], int32_t voice[], int
/* eval_highres_amdf reads indices PWINL = 229 through
(PWINL-1)+MAXWIN+(TAU(LTAU)-TAU(1))/2 = 452 of IVBUF, and writes
indices 1 through LTAU = 60 of AMDF. */
eval_highres_amdf(s->ivbuf, 156, tau, 60, amdf, &minptr, &maxptr, &mintau);
eval_highres_amdf(s->ivbuf, LPC10_MIN_PITCH, tau, 60, amdf, &minptr, &maxptr, &mintau);
/* Voicing decisions are made for each half frame of input speech.
An initial voicing classification is made for each half of the
analysis frame, and the voicing decisions for the present frame
@ -688,7 +688,7 @@ void lpc10_analyse(lpc10_encode_state_t *s, float speech[], int32_t voice[], int
dynamic_pitch_tracking(s, amdf, 60, &minptr, s->voibuf[3][1], pitch, &midx);
ipitch = tau[midx - 1];
/* Place spectrum analysis and energy windows */
lpc10_placea(&ipitch, s->voibuf, &s->obound[2], 3, s->vwin, s->awin, ewin, LPC10_SAMPLES_PER_FRAME, 156);
lpc10_placea(&ipitch, s->voibuf, &s->obound[2], 3, s->vwin, s->awin, ewin, LPC10_SAMPLES_PER_FRAME, LPC10_MIN_PITCH);
/* Remove short term DC bias over the analysis window. */
lanal = s->awin[2][1] + 1 - s->awin[2][0];
remove_dc_bias(&s->pebuf[s->awin[2][0] - 181], lanal, abuf);

View File

@ -54,7 +54,7 @@
#include "spandsp/lpc10.h"
#include "spandsp/private/lpc10.h"
#define LPC10_ORDER 10
#include "lpc10_encdecs.h"
#if !defined(min)
#define min(a,b) ((a) <= (b) ? (a) : (b))
@ -81,32 +81,6 @@ static int32_t lpc10_random(lpc10_decode_state_t *s)
}
/*- End of function --------------------------------------------------------*/
static __inline__ int32_t pow_ii(int32_t x, int32_t n)
{
int32_t pow;
uint32_t u;
if (n <= 0)
{
if (n == 0 || x == 1)
return 1;
if (x != -1)
return (x != 0) ? 1/x : 0;
n = -n;
}
u = n;
for (pow = 1; ; )
{
if ((u & 1))
pow *= x;
if ((u >>= 1) == 0)
break;
x *= x;
}
return pow;
}
/*- End of function --------------------------------------------------------*/
/* Synthesize one pitch epoch */
static void bsynz(lpc10_decode_state_t *s,
float coef[],
@ -127,7 +101,7 @@ static void bsynz(lpc10_decode_state_t *s,
int32_t j;
int32_t k;
int32_t px;
float noise[166];
float noise[LPC10_MIN_PITCH];
float pulse;
float r1;
float gain;
@ -177,14 +151,13 @@ static void bsynz(lpc10_decode_state_t *s,
}
for (i = 0; i < ip; i++)
{
noise[LPC10_ORDER + i] = lpc10_random(s)/64.0f;
hpi0 = noise[LPC10_ORDER + i];
noise[LPC10_ORDER + i] = noise[LPC10_ORDER + i]*-0.125f + s->hpi[0]*0.25f + s->hpi[1]*-0.125f;
hpi0 = lpc10_random(s)/64.0f;
noise[i] = hpi0*-0.125f + s->hpi[0]*0.25f + s->hpi[1]*-0.125f;
s->hpi[1] = s->hpi[0];
s->hpi[0] = hpi0;
}
for (i = 0; i < ip; i++)
s->exc[LPC10_ORDER + i] += noise[LPC10_ORDER + i];
s->exc[LPC10_ORDER + i] += noise[i];
}
/* Synthesis filters: */
/* Modify the excitation with all-zero filter 1 + G*SUM */
@ -224,20 +197,17 @@ static void bsynz(lpc10_decode_state_t *s,
/* Synthesize a single pitch epoch */
static int pitsyn(lpc10_decode_state_t *s,
int voice[],
int voice[2],
int32_t *pitch,
float *rms,
float *rc,
int32_t ivuv[],
int32_t ipiti[],
float *rmsi,
float *rci,
float rms,
float rc[LPC10_ORDER],
int32_t ivuv[16],
int32_t ipiti[16],
float rmsi[16],
float rci[16*LPC10_ORDER],
int32_t *nout,
float *ratio)
{
int32_t rci_dim1;
int32_t rci_offset;
int32_t i1;
int32_t i;
int32_t j;
int32_t vflag;
@ -257,16 +227,12 @@ static int pitsyn(lpc10_decode_state_t *s,
float xxy;
float msix;
rci_dim1 = LPC10_ORDER;
rci_offset = rci_dim1 + 1;
rci -= rci_offset;
if (*rms < 1.0f)
*rms = 1.0f;
if (rms < 1.0f)
rms = 1.0f;
if (s->rmso < 1.0f)
s->rmso = 1.0f;
uvpit = 0.0f;
*ratio = *rms/(s->rmso + 8.0f);
*ratio = rms/(s->rmso + 8.0f);
if (s->first_pitsyn)
{
ivoice = voice[1];
@ -275,14 +241,13 @@ static int pitsyn(lpc10_decode_state_t *s,
*nout = LPC10_SAMPLES_PER_FRAME / *pitch;
s->jsamp = LPC10_SAMPLES_PER_FRAME - *nout * *pitch;
i1 = *nout;
for (i = 0; i < i1; i++)
for (i = 0; i < *nout; i++)
{
for (j = 0; j < LPC10_ORDER; j++)
rci[j + (i + 1)*rci_dim1 + 1] = rc[j];
rci[j + i*LPC10_ORDER] = rc[j];
ivuv[i] = ivoice;
ipiti[i] = *pitch;
rmsi[i] = *rms;
rmsi[i] = rms;
}
s->first_pitsyn = false;
}
@ -301,7 +266,7 @@ static int pitsyn(lpc10_decode_state_t *s,
*pitch = LPC10_SAMPLES_PER_FRAME/4;
s->ipito = *pitch;
if (*ratio > 8.0f)
s->rmso = *rms;
s->rmso = rms;
}
/* SSVC - - 1 , 1 , 1 */
slope = (*pitch - s->ipito)/(float) lsamp;
@ -329,8 +294,8 @@ static int pitsyn(lpc10_decode_state_t *s,
rmsi[1] = s->rmso;
for (i = 0; i < LPC10_ORDER; i++)
{
rci[i + rci_dim1 + 1] = s->rco[i];
rci[i + (rci_dim1 << 1) + 1] = s->rco[i];
rci[i] = s->rco[i];
rci[i + LPC10_ORDER] = s->rco[i];
s->rco[i] = rc[i];
}
*nout = 2;
@ -434,10 +399,9 @@ static int pitsyn(lpc10_decode_state_t *s,
ip = (int32_t) uvpit;
if (ip <= i - jused)
{
++(*nout);
ipiti[*nout - 1] = ip;
ipiti[*nout] = ip;
*pitch = ip;
ivuv[*nout - 1] = ivoice;
ivuv[*nout] = ivoice;
jused += ip;
prop = (jused - ip/2)/(float) lsamp;
for (j = 0; j < LPC10_ORDER; j++)
@ -446,12 +410,13 @@ static int pitsyn(lpc10_decode_state_t *s,
alrn = logf((rc[j] + 1)/(1 - rc[j]));
xxy = alro + prop*(alrn - alro);
xxy = expf(xxy);
rci[j + *nout*rci_dim1 + 1] = (xxy - 1.0f)/(xxy + 1.0f);
rci[j + *nout*LPC10_ORDER] = (xxy - 1.0f)/(xxy + 1.0f);
}
msix = logf(*rms) - logf(s->rmso);
msix = logf(rms) - logf(s->rmso);
msix = prop*msix;
msix = logf(s->rmso) + msix;
rmsi[*nout - 1] = expf(msix);
rmsi[*nout] = expf(msix);
(*nout)++;
}
}
if (vflag != 1)
@ -465,7 +430,7 @@ static int pitsyn(lpc10_decode_state_t *s,
uvpit = (float) ((lsamp - istart)/2);
if (uvpit > 90.0f)
uvpit /= 2;
s->rmso = *rms;
s->rmso = rms;
for (i = 0; i < LPC10_ORDER; i++)
{
rc[i] = yarc[i];
@ -478,7 +443,7 @@ static int pitsyn(lpc10_decode_state_t *s,
{
s->ivoico = voice[1];
s->ipito = *pitch;
s->rmso = *rms;
s->rmso = rms;
for (i = 0; i < LPC10_ORDER; i++)
s->rco[i] = rc[i];
}
@ -532,13 +497,12 @@ static float reflection_coeffs_to_predictor_coeffs(float rc[], float pc[], float
/*- End of function --------------------------------------------------------*/
static int synths(lpc10_decode_state_t *s,
int voice[],
int voice[2],
int32_t *pitch,
float *rms,
float *rc,
float rms,
float rc[LPC10_ORDER],
float speech[])
{
int32_t i1;
int32_t ivuv[16];
int32_t ipiti[16];
int32_t nout;
@ -547,11 +511,10 @@ static int synths(lpc10_decode_state_t *s,
float rmsi[16];
float ratio;
float g2pass;
float pc[10];
float rci[160];
float pc[LPC10_ORDER];
float rci[16*LPC10_ORDER];
i1 = min(*pitch, 156);
*pitch = max(i1, 20);
*pitch = max(min(*pitch, LPC10_MIN_PITCH), LPC10_MAX_PITCH);
for (i = 0; i < LPC10_ORDER; i++)
rc[i] = max(min(rc[i], 0.99f), -0.99f);
pitsyn(s, voice, pitch, rms, rc, ivuv, ipiti, rmsi, rci, &nout, &ratio);
@ -560,14 +523,13 @@ static int synths(lpc10_decode_state_t *s,
for (j = 0; j < nout; j++)
{
/* Add synthesized speech for pitch period J to the end of s->buf. */
g2pass = reflection_coeffs_to_predictor_coeffs(&rci[j*10], pc, 0.7f);
g2pass = reflection_coeffs_to_predictor_coeffs(&rci[j*LPC10_ORDER], pc, 0.7f);
bsynz(s, pc, ipiti[j], &ivuv[j], &s->buf[s->buflen], rmsi[j], ratio, g2pass);
deemp(s, &s->buf[s->buflen], ipiti[j]);
s->buflen += ipiti[j];
}
/* Copy first MAXFRM samples from BUF to output array speech (scaling them),
and then remove them from the beginning of s->buf. */
for (i = 0; i < LPC10_SAMPLES_PER_FRAME; i++)
speech[i] = s->buf[i]/4096.0f;
s->buflen -= LPC10_SAMPLES_PER_FRAME;
@ -709,7 +671,7 @@ static int32_t median(int32_t d1, int32_t d2, int32_t d3)
static void decode(lpc10_decode_state_t *s,
lpc10_frame_t *t,
int voice[],
int voice[2],
int32_t *pitch,
float *rms,
float rc[])
@ -1110,7 +1072,7 @@ SPAN_DECLARE(int) lpc10_decode(lpc10_decode_state_t *s, int16_t amp[], const uin
{
lpc10_unpack(&frame, &code[i*7]);
decode(s, &frame, voice, &pitch, &rms, rc);
synths(s, voice, &pitch, &rms, rc, speech);
synths(s, voice, &pitch, rms, rc, speech);
base = i*LPC10_SAMPLES_PER_FRAME;
for (j = 0; j < LPC10_SAMPLES_PER_FRAME; j++)
amp[base + j] = (int16_t) lfastrintf(32768.0f*speech[j]);

View File

@ -23,7 +23,9 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define LPC10_ORDER 10
#define LPC10_ORDER 10
#define LPC10_MAX_PITCH 20
#define LPC10_MIN_PITCH 156
#if !defined(min)
#define min(a,b) ((a) <= (b) ? (a) : (b))

View File

@ -353,10 +353,6 @@ void lpc10_voicing(lpc10_encode_state_t *s,
/* Voicing decision for current half-frame: 1 = Voiced; 0 = Unvoiced */
s->voibuf[3][half] = (s->voice[2][half] > 0.0f) ? 1 : 0;
/* Skip voicing decision smoothing in first half-frame: */
/* Give a value to VSTATE, so that trace statements below will print */
/* a consistent value from one call to the next when HALF .EQ. 1. */
/* The value of VSTATE is not used for any other purpose when this is */
/* true. */
if (half != 0)
{
/* Voicing decision smoothing rules (override of linear combination): */

View File

@ -646,7 +646,7 @@ int main(int argc, char *argv[])
exit(2);
/*endif*/
printf("/* THIS FILE WAS AUTOMATICALLY GENERATED - ANY MODIFICATIONS MADE TO THIS");
printf("/* THIS FILE WAS AUTOMATICALLY GENERATED - ANY MODIFICATIONS MADE TO THIS\n");
printf(" FILE MAY BE OVERWRITTEN DURING FUTURE BUILDS OF THE SOFTWARE */\n");
printf("\n");
@ -661,7 +661,7 @@ int main(int argc, char *argv[])
trie_recursive_build_packed_trie(s->root);
dump_trie();
trie_free(s);
return 0;

View File

@ -46,7 +46,7 @@ int main(int argc, char *argv[])
uint8_t srgb;
int i;
printf("/* THIS FILE WAS AUTOMATICALLY GENERATED - ANY MODIFICATIONS MADE TO THIS");
printf("/* THIS FILE WAS AUTOMATICALLY GENERATED - ANY MODIFICATIONS MADE TO THIS\n");
printf(" FILE MAY BE OVERWRITTEN DURING FUTURE BUILDS OF THE SOFTWARE */\n");
printf("\n");

View File

@ -37,7 +37,7 @@ int main(int argc, char *argv[])
double val;
int ival;
printf("/* THIS FILE WAS AUTOMATICALLY GENERATED - ANY MODIFICATIONS MADE TO THIS");
printf("/* THIS FILE WAS AUTOMATICALLY GENERATED - ANY MODIFICATIONS MADE TO THIS\n");
printf(" FILE MAY BE OVERWRITTEN DURING FUTURE BUILDS OF THE SOFTWARE */\n");
printf("\n");

View File

@ -32,11 +32,7 @@
#include <time.h>
#include <fcntl.h>
#include <math.h>
#if defined(HAVE_STDBOOL_H)
#include <stdbool.h>
#else
#include "spandsp/stdbool.h"
#endif
#if defined(__sunos) || defined(__solaris) || defined(__sun)
#include <getopt.h>
#endif
@ -103,7 +99,7 @@ static void make_tx_filter(int coeff_sets,
/* Churn out the data as a C source code header file, which can be directly included by the
modem code. */
printf("/* THIS FILE WAS AUTOMATICALLY GENERATED - ANY MODIFICATIONS MADE TO THIS");
printf("/* THIS FILE WAS AUTOMATICALLY GENERATED - ANY MODIFICATIONS MADE TO THIS\n");
printf(" FILE MAY BE OVERWRITTEN DURING FUTURE BUILDS OF THE SOFTWARE */\n");
printf("\n");
printf("#if defined(SPANDSP_USE_FIXED_POINT)\n");

View File

@ -39,7 +39,7 @@ int main(int argc, char *argv[])
int new_gray;
int restore;
printf("/* THIS FILE WAS AUTOMATICALLY GENERATED - ANY MODIFICATIONS MADE TO THIS");
printf("/* THIS FILE WAS AUTOMATICALLY GENERATED - ANY MODIFICATIONS MADE TO THIS\n");
printf(" FILE MAY BE OVERWRITTEN DURING FUTURE BUILDS OF THE SOFTWARE */\n");
printf("\n");

View File

@ -177,6 +177,10 @@ SPAN_DECLARE(void) at_set_modem_control_handler(at_state_t *s,
at_modem_control_handler_t modem_control_handler,
void *modem_control_user_data);
SPAN_DECLARE(void) at_set_at_tx_handler(at_state_t *s,
at_tx_handler_t at_tx_handler,
void *at_tx_user_data);
/*! Initialise an AT interpreter context.
\brief Initialise an AT interpreter context.
\param s The AT context.

View File

@ -50,6 +50,8 @@ enum
*/
typedef struct data_modems_state_s data_modems_state_t;
typedef int (*data_modems_control_handler_t)(data_modems_state_t *s, void *user_data, int op, const char *num);
#if defined(__cplusplus)
extern "C"
{
@ -62,6 +64,8 @@ SPAN_DECLARE(void) data_modems_set_tep_mode(data_modems_state_t *s, int use_tep)
SPAN_DECLARE(logging_state_t *) data_modems_get_logging_state(data_modems_state_t *s);
SPAN_DECLARE(void) data_modems_call_event(data_modems_state_t *s, int event);
SPAN_DECLARE(int) data_modems_restart(data_modems_state_t *s);
SPAN_DECLARE(void) data_modems_set_async_mode(data_modems_state_t *s,
@ -77,8 +81,16 @@ SPAN_DECLARE(int) data_modems_rx_fillin(data_modems_state_t *s, int len);
SPAN_DECLARE(int) data_modems_tx(data_modems_state_t *s, int16_t amp[], int max_len);
SPAN_DECLARE(void) data_modems_set_at_tx_handler(data_modems_state_t *s,
at_tx_handler_t at_tx_handler,
void *at_tx_user_data);
SPAN_DECLARE(data_modems_state_t *) data_modems_init(data_modems_state_t *s,
bool calling_party,
at_tx_handler_t at_tx_handler,
void *at_tx_user_data,
data_modems_control_handler_t modem_control_handler,
void *modem_control_user_data,
put_msg_func_t put_msg,
get_msg_func_t get_msg,
void *user_data);

View File

@ -115,7 +115,7 @@ extern "C"
/* Enable the trap as per the MIL-STD */
//#define G711_ULAW_ZEROTRAP
/*! Bias for u-law encoding from linear. */
#define G711_ULAW_BIAS 0x84
#define G711_ULAW_BIAS 0x84
/*! \brief Encode a linear sample to u-law
\param linear The sample to encode.

View File

@ -31,13 +31,16 @@
*/
struct awgn_state_s
{
/* Scaling factor */
double rms;
long int ix1;
long int ix2;
long int ix3;
double r[98];
double gset;
int iset;
/* Working data for the Gaussian generator */
bool odd;
double amp2;
/* Working data for the random number generator */
int32_t ix1;
int32_t ix2;
int32_t ix3;
double r[97];
};
#endif

View File

@ -43,6 +43,9 @@ struct data_modems_state_s
silent audio. */
bool transmit_on_idle;
at_state_t at_state;
data_modems_control_handler_t modem_control_handler;
void *modem_control_user_data;
get_bit_func_t get_bit;
void *get_user_data;
put_bit_func_t put_bit;
@ -60,6 +63,9 @@ struct data_modems_state_s
async_tx_state_t async_tx;
async_rx_state_t async_rx;
/*! \brief Samples elapsed in the current call */
int64_t call_samples;
union
{
v8_state_t v8;

View File

@ -31,10 +31,13 @@ struct v18_state_s
/*! \brief True if we are the calling modem */
bool calling_party;
int mode;
int initial_mode;
int current_mode;
int nation;
put_msg_func_t put_msg;
void *user_data;
int repeat_shifts;
bool repeat_shifts;
bool autobauding;
union
{
@ -48,10 +51,38 @@ struct v18_state_s
async_tx_state_t async_tx;
int baudot_tx_shift;
int tx_signal_on;
bool tx_draining;
uint8_t next_byte;
fsk_rx_state_t fsk_rx;
dtmf_rx_state_t dtmf_rx;
#if defined(SPANDSP_USE_FIXED_POINTx)
/*! Minimum acceptable tone level for detection. */
int32_t threshold;
/*! The accumlating total energy on the same period over which the Goertzels work. */
int32_t energy;
#else
/*! Minimum acceptable tone level for detection. */
float threshold;
/*! The accumlating total energy on the same period over which the Goertzels work. */
float energy;
#endif
goertzel_state_t tone_390;
goertzel_state_t tone_980;
goertzel_state_t tone_1180;
goertzel_state_t tone_1270;
goertzel_state_t tone_1300;
goertzel_state_t tone_1400;
goertzel_state_t tone_1650;
goertzel_state_t tone_1800;
/*! The current sample number within a processing block. */
int current_sample;
/*! Tone state duration */
int duration;
int target_duration;
int in_tone;
int baudot_rx_shift;
int consecutive_ones;
uint8_t rx_msg[256 + 1];
@ -59,6 +90,7 @@ struct v18_state_s
int bit_pos;
int in_progress;
int rx_suppression;
int tx_suppression;
/*! \brief Error and flow logging control */
logging_state_t logging;

View File

@ -39,15 +39,14 @@
#if !defined(__cplusplus)
#define _Bool int
#define bool int
typedef int _Bool;
typedef int bool;
#define false 0
#define true (!false)
#else
#define _Bool bool
#define bool bool
typedef bool _Bool;
#define false false
#define true true

View File

@ -67,60 +67,64 @@ typedef int (*span_rx_fillin_handler_t)(void *s, int len);
/*! \brief A handler for transmit, where the buffer will be filled. */
typedef int (*span_tx_handler_t)(void *s, int16_t amp[], int max_len);
#define seconds_to_samples(t) ((t)*SAMPLE_RATE)
#define milliseconds_to_samples(t) ((t)*(SAMPLE_RATE/1000))
#define microseconds_to_samples(t) ((t)/(1000000/SAMPLE_RATE))
#define ms_to_samples(t) ((t)*(SAMPLE_RATE/1000))
#define us_to_samples(t) ((t)/(1000000/SAMPLE_RATE))
/* Fixed point constant macros for 16 bit values */
#define FP_Q16_0(x) ((int16_t) (1.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q15_1(x) ((int16_t) (2.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q14_2(x) ((int16_t) (4.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q13_3(x) ((int16_t) (8.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q12_4(x) ((int16_t) (16.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q11_5(x) ((int16_t) (32.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q10_6(x) ((int16_t) (64.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q9_7(x) ((int16_t) (128.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q8_8(x) ((int16_t) (256.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q7_9(x) ((int16_t) (512.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q6_10(x) ((int16_t) (1024.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q5_11(x) ((int16_t) (2048.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q4_12(x) ((int16_t) (4096.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q3_13(x) ((int16_t) (8192.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q2_14(x) ((int16_t) (16384.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q1_15(x) ((int16_t) (32768.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q16_0(x) ((int16_t) (1.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q15_1(x) ((int16_t) (2.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q14_2(x) ((int16_t) (4.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q13_3(x) ((int16_t) (8.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q12_4(x) ((int16_t) (16.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q11_5(x) ((int16_t) (32.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q10_6(x) ((int16_t) (64.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q9_7(x) ((int16_t) (128.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q8_8(x) ((int16_t) (256.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q7_9(x) ((int16_t) (512.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q6_10(x) ((int16_t) (1024.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q5_11(x) ((int16_t) (2048.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q4_12(x) ((int16_t) (4096.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q3_13(x) ((int16_t) (8192.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q2_14(x) ((int16_t) (16384.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q1_15(x) ((int16_t) (32768.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
/* Fixed point constant macros for 32 bit values */
#define FP_Q32_0(x) ((int32_t) (1.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q31_1(x) ((int32_t) (2.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q30_2(x) ((int32_t) (4.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q29_3(x) ((int32_t) (8.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q28_4(x) ((int32_t) (16.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q27_5(x) ((int32_t) (32.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q26_6(x) ((int32_t) (64.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q25_7(x) ((int32_t) (128.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q24_8(x) ((int32_t) (256.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q23_9(x) ((int32_t) (512.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q22_10(x) ((int32_t) (1024.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q21_11(x) ((int32_t) (2048.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q20_12(x) ((int32_t) (4096.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q19_13(x) ((int32_t) (8192.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q18_14(x) ((int32_t) (16384.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q17_15(x) ((int32_t) (32768.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q16_16(x) ((int32_t) (65536.0*1.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q15_17(x) ((int32_t) (65536.0*2.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q14_18(x) ((int32_t) (65536.0*4.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q13_19(x) ((int32_t) (65536.0*8.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q12_20(x) ((int32_t) (65536.0*16.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q11_21(x) ((int32_t) (65536.0*32.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q10_22(x) ((int32_t) (65536.0*64.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q9_23(x) ((int32_t) (65536.0*128.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q8_24(x) ((int32_t) (65536.0*256.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q7_25(x) ((int32_t) (65536.0*512.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q6_26(x) ((int32_t) (65536.0*1024.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q5_27(x) ((int32_t) (65536.0*2048.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q4_28(x) ((int32_t) (65536.0*4096.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q3_29(x) ((int32_t) (65536.0*8192.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q2_30(x) ((int32_t) (65536.0*16384.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q1_31(x) ((int32_t) (65536.0*32768.0*x + ((x >= 0.0) ? 0.5 : -0.5)))
#define FP_Q32_0(x) ((int32_t) (1.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q31_1(x) ((int32_t) (2.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q30_2(x) ((int32_t) (4.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q29_3(x) ((int32_t) (8.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q28_4(x) ((int32_t) (16.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q27_5(x) ((int32_t) (32.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q26_6(x) ((int32_t) (64.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q25_7(x) ((int32_t) (128.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q24_8(x) ((int32_t) (256.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q23_9(x) ((int32_t) (512.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q22_10(x) ((int32_t) (1024.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q21_11(x) ((int32_t) (2048.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q20_12(x) ((int32_t) (4096.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q19_13(x) ((int32_t) (8192.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q18_14(x) ((int32_t) (16384.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q17_15(x) ((int32_t) (32768.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q16_16(x) ((int32_t) (65536.0*1.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q15_17(x) ((int32_t) (65536.0*2.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q14_18(x) ((int32_t) (65536.0*4.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q13_19(x) ((int32_t) (65536.0*8.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q12_20(x) ((int32_t) (65536.0*16.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q11_21(x) ((int32_t) (65536.0*32.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q10_22(x) ((int32_t) (65536.0*64.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q9_23(x) ((int32_t) (65536.0*128.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q8_24(x) ((int32_t) (65536.0*256.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q7_25(x) ((int32_t) (65536.0*512.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q6_26(x) ((int32_t) (65536.0*1024.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q5_27(x) ((int32_t) (65536.0*2048.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q4_28(x) ((int32_t) (65536.0*4096.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q3_29(x) ((int32_t) (65536.0*8192.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q2_30(x) ((int32_t) (65536.0*16384.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#define FP_Q1_31(x) ((int32_t) (65536.0*32768.0*(x) + (((x) >= 0.0) ? 0.5 : -0.5)))
#if defined(__cplusplus)
/* C++ doesn't seem to have sane rounding functions/macros yet */

View File

@ -66,6 +66,8 @@ enum
{
V18_AUTOMODING_GLOBAL = 0,
V18_AUTOMODING_NONE,
/* 5-bit, V.21, V.23, EDT, DTMF, Bell 103 */
V18_AUTOMODING_AUSTRALIA,
V18_AUTOMODING_IRELAND,
@ -173,6 +175,11 @@ SPAN_DECLARE(int) v18_rx_fillin(v18_state_t *s, int len);
invalid, this function will return -1. */
SPAN_DECLARE(int) v18_put(v18_state_t *s, const char msg[], int len);
/*! \brief Get the current mode of a V.18 connection.
\param s The V.18 context.
\return The mode. */
SPAN_DECLARE(int) v18_get_current_mode(v18_state_t *s);
/*! \brief Return a short name for an V.18 mode
\param mode The code for the V.18 mode.
\return A pointer to the name.

View File

@ -959,6 +959,7 @@ SPAN_DECLARE(void) t30_decode_dis_dtc_dcs(t30_state_t *s, const uint8_t *pkt, in
octet_bit_field(log, pkt, 96, "Extension indicator", NULL, NULL);
if (!(pkt[14] & DISBIT8))
return;
/*endif*/
if (len <= 15)
{
span_log(log, SPAN_LOG_FLOW, " Frame is short\n");

View File

@ -202,6 +202,7 @@ static void report_status_change(v17_rx_state_t *s, int status)
s->status_handler(s->status_user_data, status);
else if (s->put_bit)
s->put_bit(s->put_bit_user_data, status);
/*endif*/
}
/*- End of function --------------------------------------------------------*/
@ -360,6 +361,7 @@ static int descramble(v17_rx_state_t *s, int in_bit)
s->scramble_reg |= out_bit;
else
s->scramble_reg |= (in_bit & 1);
/*endif*/
return out_bit;
}
/*- End of function --------------------------------------------------------*/
@ -382,6 +384,7 @@ static __inline__ void put_bit(v17_rx_state_t *s, int bit)
testing for ones, but just rely on a constellation mismatch measurement. */
//span_log(&s->logging, SPAN_LOG_FLOW, "A 1 is really %d\n", out_bit);
}
/*endif*/
}
/*- End of function --------------------------------------------------------*/
@ -437,6 +440,8 @@ static int decode_baud(v17_rx_state_t *s, complexf_t *z)
int re;
int im;
int raw;
int min_index;
int set;
int constellation_state;
#if defined(SPANDSP_USE_FIXED_POINTx)
#define DIST_FACTOR 1024 /* Something less than sqrt(0xFFFFFFFF/10)/10 */
@ -462,20 +467,23 @@ static int decode_baud(v17_rx_state_t *s, complexf_t *z)
re = 35;
else if (re < 0)
re = 0;
/*endif*/
if (im > 35)
im = 35;
else if (im < 0)
im = 0;
/*endif*/
if (s->bits_per_symbol == 2)
{
/* 4800bps V.32bis mode, without trellis coding */
nearest = constel_map_4800[re][im];
raw = v32bis_4800_differential_decoder[s->diff][nearest];
s->diff = nearest;
constellation_state = constel_map_4800[re][im];
raw = v32bis_4800_differential_decoder[s->diff][constellation_state];
s->diff = constellation_state;
put_bit(s, raw);
put_bit(s, raw >> 1);
return nearest;
return constellation_state;
}
/*endif*/
/* Find a set of 8 candidate constellation positions, that are the closest
to the target, with different patterns in the last 3 bits. */
@ -485,7 +493,7 @@ static int decode_baud(v17_rx_state_t *s, complexf_t *z)
#else
min = 9999999.0f;
#endif
j = 0;
min_index = 0;
for (i = 0; i < 8; i++)
{
nearest = constel_maps[s->space_map][re][im][i];
@ -499,13 +507,16 @@ static int decode_baud(v17_rx_state_t *s, complexf_t *z)
if (min > distances[i])
{
min = distances[i];
j = i;
min_index = i;
}
/*endif*/
}
/* Use the nearest of these soft-decisions as the basis for DFE */
constellation_state = constel_maps[s->space_map][re][im][j];
/* Control the equalizer, carrier tracking, etc. based on the non-trellis
corrected information. The trellis correct stuff comes out a bit late. */
/*endfor*/
/* Use the nearest of these soft-decisions as the basis for DFE and carrier
tracking. This is a compromise. It means we will use the correct error
less often, but using the output of the traceback would put more lag
into the feedback path. */
constellation_state = constel_maps[s->space_map][re][im][min_index];
track_carrier(s, z, &s->constellation[constellation_state]);
//tune_equalizer(s, z, &s->constellation[constellation_state]);
@ -517,70 +528,62 @@ static int decode_baud(v17_rx_state_t *s, complexf_t *z)
/* Update the minimum accumulated distance to each of the 8 states */
if (++s->trellis_ptr >= V17_TRELLIS_STORAGE_DEPTH)
s->trellis_ptr = 0;
for (i = 0; i < 4; i++)
/*endif*/
for (i = 0; i < 8; i++)
{
min = distances[tcm_paths[i][0]] + s->distances[0];
k = 0;
set = i >> 2;
min = distances[tcm_paths[i][0]] + s->distances[set];
min_index = 0;
for (j = 1; j < 4; j++)
{
if (min > distances[tcm_paths[i][j]] + s->distances[j << 1])
k = (j << 1) + set;
if (min > distances[tcm_paths[i][j]] + s->distances[k])
{
min = distances[tcm_paths[i][j]] + s->distances[j << 1];
k = j;
min = distances[tcm_paths[i][j]] + s->distances[k];
min_index = j;
}
/*endif*/
}
/*endfor*/
k = (min_index << 1) + set;
/* Use an elementary IIR filter to track the distance to date. */
#if defined(SPANDSP_USE_FIXED_POINTx)
new_distances[i] = s->distances[k << 1]*9/10 + distances[tcm_paths[i][k]]*1/10;
new_distances[i] = s->distances[k]*9/10 + distances[tcm_paths[i][min_index]]*1/10;
#else
new_distances[i] = s->distances[k << 1]*0.9f + distances[tcm_paths[i][k]]*0.1f;
new_distances[i] = s->distances[k]*0.9f + distances[tcm_paths[i][min_index]]*0.1f;
#endif
s->full_path_to_past_state_locations[s->trellis_ptr][i] = constel_maps[s->space_map][re][im][tcm_paths[i][k]];
s->past_state_locations[s->trellis_ptr][i] = k << 1;
}
for (i = 4; i < 8; i++)
{
min = distances[tcm_paths[i][0]] + s->distances[1];
k = 0;
for (j = 1; j < 4; j++)
{
if (min > distances[tcm_paths[i][j]] + s->distances[(j << 1) + 1])
{
min = distances[tcm_paths[i][j]] + s->distances[(j << 1) + 1];
k = j;
}
}
#if defined(SPANDSP_USE_FIXED_POINTx)
new_distances[i] = s->distances[(k << 1) + 1]*9/10 + distances[tcm_paths[i][k]]*1/10;
#else
new_distances[i] = s->distances[(k << 1) + 1]*0.9f + distances[tcm_paths[i][k]]*0.1f;
#endif
s->full_path_to_past_state_locations[s->trellis_ptr][i] = constel_maps[s->space_map][re][im][tcm_paths[i][k]];
s->past_state_locations[s->trellis_ptr][i] = (k << 1) + 1;
s->full_path_to_past_state_locations[s->trellis_ptr][i] = constel_maps[s->space_map][re][im][tcm_paths[i][min_index]];
s->past_state_locations[s->trellis_ptr][i] = k;
}
/*endfor*/
memcpy(s->distances, new_distances, sizeof(s->distances));
/* Find the minimum distance to date. This is the start of the path back to the result. */
min = s->distances[0];
k = 0;
min_index = 0;
for (i = 1; i < 8; i++)
{
if (min > s->distances[i])
{
min = s->distances[i];
k = i;
min_index = i;
}
/*endif*/
}
/*endfor*/
/* Trace back through every time step, starting with the current one, and find the
state from which the path came one step before. At the end of this search, the
last state found also points to the constellation point at that state. This is the
output of the trellis. */
k = min_index;
for (i = 0, j = s->trellis_ptr; i < V17_TRELLIS_LOOKBACK_DEPTH - 1; i++)
{
k = s->past_state_locations[j][k];
if (--j < 0)
j = V17_TRELLIS_STORAGE_DEPTH - 1;
/*endif*/
}
/*endfor*/
nearest = s->full_path_to_past_state_locations[j][k] >> 1;
/* Differentially decode */
@ -591,6 +594,7 @@ static int decode_baud(v17_rx_state_t *s, complexf_t *z)
put_bit(s, raw);
raw >>= 1;
}
/*endfor*/
return constellation_state;
}
/*- End of function --------------------------------------------------------*/
@ -645,10 +649,12 @@ static __inline__ void symbol_sync(v17_rx_state_t *s)
i = (v > FP_SYNC_SCALE_32(1000.0f)) ? 15 : 1;
if (s->baud_phase < FP_SYNC_SCALE_32(0.0f))
i = -i;
/*endif*/
//printf("v = %10.5f %5d - %f %f %d\n", v, i, p, s->baud_phase, s->total_baud_timing_correction);
s->eq_put_step += i;
s->total_baud_timing_correction += i;
}
/*endif*/
}
/*- End of function --------------------------------------------------------*/
@ -696,10 +702,12 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
s->eq_buf[s->eq_step] = *sample;
if (++s->eq_step >= V17_EQUALIZER_LEN)
s->eq_step = 0;
/*endif*/
/* On alternate insertions we have a whole baud and must process it. */
if ((s->baud_half ^= 1))
return;
/*endif*/
/* Symbol timing synchronisation */
symbol_sync(s);
@ -725,7 +733,9 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
s->last_angles[0] = arctan2(z.im, z.re);
if (s->agc_scaling_save == FP_SCALE(0.0f))
s->agc_scaling_save = s->agc_scaling;
/*endif*/
}
/*endif*/
break;
case TRAINING_STAGE_LOG_PHASE:
/* Record the current alternate phase angle */
@ -749,6 +759,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
s->last_angles[0] = DDS_PHASE(180.0f + 18.433f);
s->last_angles[1] = DDS_PHASE(270.0f + 18.433f);
}
/*endif*/
/* Make a step shift in the phase, to pull it into line. We need to rotate the equalizer
buffer, as well as the carrier phase, for this to play out nicely. */
/* angle is now the difference between where A is, and where it should be */
@ -759,6 +770,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
z16 = complex_seti16(fixed_cos(ip), -fixed_sin(ip));
for (i = 0; i < V17_EQUALIZER_LEN; i++)
s->eq_buf[i] = complex_mul_q1_15(&s->eq_buf[i], &z16);
/*endfor*/
s->carrier_track_p = 500000;
#else
p = dds_phase_to_radians(phase_step);
@ -766,6 +778,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
zz = complex_setf(cosf(p), -sinf(p));
for (i = 0; i < V17_EQUALIZER_LEN; i++)
s->eq_buf[i] = complex_mulf(&s->eq_buf[i], &zz);
/*endfor*/
s->carrier_track_p = 500000.0f;
#endif
s->carrier_phase += phase_step;
@ -776,6 +789,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
s->last_angles[1] = angle;
s->training_stage = TRAINING_STAGE_WAIT_FOR_CDBA;
}
/*endif*/
break;
case TRAINING_STAGE_WAIT_FOR_CDBA:
target = &zero;
@ -803,6 +817,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
s->carrier_phase_rate += 3*16*(ang/20);
span_log(&s->logging, SPAN_LOG_FLOW, "Angles %x, %x, dist %d\n", s->last_angles[0], s->last_angles[1], i);
}
/*endif*/
span_log(&s->logging, SPAN_LOG_FLOW, "Coarse carrier frequency %7.2f (%d)\n", dds_frequencyf(s->carrier_phase_rate), s->training_count);
/* Check if the carrier frequency is plausible */
if (s->carrier_phase_rate < DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ - 20.0f)
@ -816,6 +831,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
break;
}
/*endif*/
/* Make a step shift in the phase, to pull it into line. We need to rotate the equalizer buffer,
as well as the carrier phase, for this to play out nicely. */
@ -827,12 +843,14 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
z16 = complex_seti16(fixed_cos(ip), -fixed_sin(ip));
for (i = 0; i < V17_EQUALIZER_LEN; i++)
s->eq_buf[i] = complex_mul_q1_15(&s->eq_buf[i], &z16);
/*endfor*/
#else
p = dds_phase_to_radians(phase_step);
span_log(&s->logging, SPAN_LOG_FLOW, "Spin (long) by %.5f rads\n", p);
zz = complex_setf(cosf(p), -sinf(p));
for (i = 0; i < V17_EQUALIZER_LEN; i++)
s->eq_buf[i] = complex_mulf(&s->eq_buf[i], &zz);
/*endfor*/
#endif
s->carrier_phase += phase_step;
@ -845,6 +863,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
report_status_change(s, SIG_STATUS_TRAINING_IN_PROGRESS);
break;
}
/*endif*/
if (++s->training_count > V17_TRAINING_SEG_1_LEN)
{
/* This is bogus. There are not this many bits in this section
@ -855,6 +874,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
s->training_stage = TRAINING_STAGE_PARKED;
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
}
/*endif*/
break;
case TRAINING_STAGE_COARSE_TRAIN_ON_CDBA:
/* Train on the scrambled CDBA section. */
@ -886,6 +906,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
#endif
s->training_stage = TRAINING_STAGE_FINE_TRAIN_ON_CDBA;
}
/*endif*/
break;
case TRAINING_STAGE_FINE_TRAIN_ON_CDBA:
/* Train on the scrambled CDBA section. */
@ -907,6 +928,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
#endif
s->training_stage = TRAINING_STAGE_TRAIN_ON_CDBA_AND_TEST;
}
/*endif*/
break;
case TRAINING_STAGE_TRAIN_ON_CDBA_AND_TEST:
/* Continue training on the scrambled CDBA section, but measure the quality of training too. */
@ -950,7 +972,9 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
s->training_stage = TRAINING_STAGE_PARKED;
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
}
/*endif*/
}
/*endif*/
break;
case TRAINING_STAGE_BRIDGE:
descramble(s, V17_BRIDGE_WORD >> ((s->training_count & 0x7) << 1));
@ -972,7 +996,9 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
/* Wait for the trellis to wind up */
s->training_stage = TRAINING_STAGE_TCM_WINDUP;
}
/*endif*/
}
/*endif*/
break;
case TRAINING_STAGE_SHORT_WAIT_FOR_CDBA:
/* Look for the initial ABAB sequence to display a phase reversal, which will
@ -989,19 +1015,23 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
s->training_error = FP_SCALE(0.0f);
s->training_count = 1;
s->training_stage = TRAINING_STAGE_SHORT_TRAIN_ON_CDBA_AND_TEST;
break;
}
target = &cdba[(s->training_count & 1) + 2];
track_carrier(s, &z, target);
if (++s->training_count > V17_TRAINING_SEG_1_LEN)
else
{
/* This is bogus. There are not this many bits in this section
of a real training sequence. Note that this might be TEP. */
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n");
/* Park this modem */
s->training_stage = TRAINING_STAGE_PARKED;
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
target = &cdba[(s->training_count & 1) + 2];
track_carrier(s, &z, target);
if (++s->training_count > V17_TRAINING_SEG_1_LEN)
{
/* This is bogus. There are not this many bits in this section
of a real training sequence. Note that this might be TEP. */
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n");
/* Park this modem */
s->training_stage = TRAINING_STAGE_PARKED;
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
}
/*endif*/
}
/*endif*/
break;
case TRAINING_STAGE_SHORT_TRAIN_ON_CDBA_AND_TEST:
/* Short retrain on the scrambled CDBA section, but measure the quality of training too. */
@ -1022,6 +1052,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
s->training_error += powerf(&zz);
#endif
}
/*endif*/
if (++s->training_count >= V17_TRAINING_SHORT_SEG_2_LEN)
{
#if defined(SPANDSP_USE_FIXED_POINTx)
@ -1052,6 +1083,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
/* Wait for the trellis to wind up */
s->training_stage = TRAINING_STAGE_TCM_WINDUP;
}
/*endif*/
report_status_change(s, SIG_STATUS_TRAINING_IN_PROGRESS);
}
else
@ -1061,7 +1093,9 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
s->training_stage = TRAINING_STAGE_PARKED;
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
}
/*endif*/
}
/*endif*/
break;
case TRAINING_STAGE_TCM_WINDUP:
/* We need to wait 15 bauds while the trellis fills up. */
@ -1084,6 +1118,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
s->diff = (s->short_train) ? 0 : 1;
s->training_stage = TRAINING_STAGE_TEST_ONES;
}
/*endif*/
break;
case TRAINING_STAGE_TEST_ONES:
/* We are in the test phase, where we check that we can receive reliably.
@ -1128,10 +1163,13 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
#endif
if (!s->short_train)
s->agc_scaling_save = FP_SCALE(0.0f);
/*endif*/
s->training_stage = TRAINING_STAGE_PARKED;
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
}
/*endif*/
}
/*endif*/
break;
case TRAINING_STAGE_PARKED:
default:
@ -1140,6 +1178,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
target = &zero;
break;
}
/*endswitch*/
if (s->qam_report)
{
#if defined(SPANDSP_USE_FIXED_POINT)
@ -1155,6 +1194,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
s->qam_report(s->qam_user_data, &z, target, constellation_state);
#endif
}
/*endif*/
}
/*- End of function --------------------------------------------------------*/
@ -1183,13 +1223,16 @@ static __inline__ int signal_detect(v17_rx_state_t *s, int16_t amp)
s->high_sample = 0;
s->low_samples = 0;
}
/*endif*/
}
else
{
s->low_samples = 0;
if (diff > s->high_sample)
s->high_sample = diff;
/*endif*/
}
/*endif*/
#endif
if (s->signal_present > 0)
{
@ -1208,23 +1251,27 @@ static __inline__ int signal_detect(v17_rx_state_t *s, int16_t amp)
report_status_change(s, SIG_STATUS_CARRIER_DOWN);
return 0;
}
/*endif*/
#if defined(IAXMODEM_STUFF)
/* Carrier has dropped, but the put_bit is pending the signal_present delay. */
s->carrier_drop_pending = true;
#endif
}
/*endif*/
}
else
{
/* Look for power exceeding turn-on threshold to turn the carrier on */
if (power < s->carrier_on_power)
return 0;
/*endif*/
s->signal_present = 1;
#if defined(IAXMODEM_STUFF)
s->carrier_drop_pending = false;
#endif
report_status_change(s, SIG_STATUS_CARRIER_UP);
}
/*endif*/
return power;
}
/*- End of function --------------------------------------------------------*/
@ -1252,21 +1299,26 @@ SPAN_DECLARE(int) v17_rx(v17_rx_state_t *s, const int16_t amp[], int len)
s->rrc_filter[s->rrc_filter_step] = amp[i];
if (++s->rrc_filter_step >= V17_RX_FILTER_STEPS)
s->rrc_filter_step = 0;
/*endif*/
if ((power = signal_detect(s, amp[i])) == 0)
continue;
/*endif*/
if (s->training_stage == TRAINING_STAGE_PARKED)
continue;
/*endif*/
/* Only spend effort processing this data if the modem is not
parked, after training failure. */
s->eq_put_step -= RX_PULSESHAPER_COEFF_SETS;
step = -s->eq_put_step;
if (step < 0)
step += RX_PULSESHAPER_COEFF_SETS;
/*endif*/
if (step < 0)
step = 0;
else if (step > RX_PULSESHAPER_COEFF_SETS - 1)
step = RX_PULSESHAPER_COEFF_SETS - 1;
/*endif*/
#if defined(SPANDSP_USE_FIXED_POINTx)
v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_re[step], V17_RX_FILTER_STEPS, s->rrc_filter_step) >> 15;
sample.re = (v*s->agc_scaling) >> 10;
@ -1305,12 +1357,14 @@ SPAN_DECLARE(int) v17_rx(v17_rx_state_t *s, const int16_t amp[], int len)
{
if ((root_power = fixed_sqrt32(power)) == 0)
root_power = 1;
/*endif*/
#if defined(SPANDSP_USE_FIXED_POINTx)
s->agc_scaling = saturate16(((int32_t) (FP_SCALE(2.17f)*1024.0f))/root_power);
#else
s->agc_scaling = (FP_SCALE(2.17f)/RX_PULSESHAPER_GAIN)/root_power;
#endif
}
/*endif*/
/* Pulse shape while still at the carrier frequency, using a quadrature
pair of filters. This results in a properly bandpass filtered complex
signal, which can be brought directly to baseband by complex mixing.
@ -1331,12 +1385,14 @@ SPAN_DECLARE(int) v17_rx(v17_rx_state_t *s, const int16_t amp[], int len)
s->eq_put_step += RX_PULSESHAPER_COEFF_SETS*10/(3*2);
process_half_baud(s, &zz);
}
/*endif*/
#if defined(SPANDSP_USE_FIXED_POINT)
dds_advance(&s->carrier_phase, s->carrier_phase_rate);
#else
dds_advancef(&s->carrier_phase, s->carrier_phase_rate);
#endif
}
/*endfor*/
return 0;
}
/*- End of function --------------------------------------------------------*/
@ -1350,8 +1406,10 @@ SPAN_DECLARE(int) v17_rx_fillin(v17_rx_state_t *s, int len)
span_log(&s->logging, SPAN_LOG_FLOW, "Fill-in %d samples\n", len);
if (s->signal_present <= 0)
return 0;
/*endif*/
if (s->training_stage == TRAINING_STAGE_PARKED)
return 0;
/*endif*/
for (i = 0; i < len; i++)
{
#if defined(SPANDSP_USE_FIXED_POINT)
@ -1363,8 +1421,10 @@ SPAN_DECLARE(int) v17_rx_fillin(v17_rx_state_t *s, int len)
s->eq_put_step -= RX_PULSESHAPER_COEFF_SETS;
if (s->eq_put_step <= 0)
s->eq_put_step += RX_PULSESHAPER_COEFF_SETS*10/(3*2);
/*endif*/
/* TODO: Should we rotate any buffers */
}
/*endfor*/
return 0;
}
/*- End of function --------------------------------------------------------*/
@ -1426,6 +1486,7 @@ SPAN_DECLARE(int) v17_rx_restart(v17_rx_state_t *s, int bit_rate, int short_trai
default:
return -1;
}
/*endswitch*/
s->bit_rate = bit_rate;
#if defined(SPANDSP_USE_FIXED_POINTx)
vec_zeroi16(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
@ -1447,6 +1508,7 @@ SPAN_DECLARE(int) v17_rx_restart(v17_rx_state_t *s, int bit_rate, int short_trai
#endif
if (short_train != 2)
s->short_train = short_train;
/*endif*/
vec_zeroi32(s->last_angles, 2);
vec_zeroi32(s->diff_angles, 16);
@ -1456,6 +1518,7 @@ SPAN_DECLARE(int) v17_rx_restart(v17_rx_state_t *s, int bit_rate, int short_trai
initial paths to merge at the zero states. */
for (i = 0; i < 8; i++)
s->distances[i] = FP_CONSTELLATION_SCALE(99.0f)*FP_CONSTELLATION_SCALE(1.0f);
/*endfor*/
memset(s->full_path_to_past_state_locations, 0, sizeof(s->full_path_to_past_state_locations));
memset(s->past_state_locations, 0, sizeof(s->past_state_locations));
s->distances[0] = 0;
@ -1493,6 +1556,7 @@ SPAN_DECLARE(int) v17_rx_restart(v17_rx_state_t *s, int bit_rate, int short_trai
s->carrier_track_p = 40000.0f;
#endif
}
/*endif*/
s->last_sample = 0;
span_log(&s->logging, SPAN_LOG_FLOW, "Gains %f %f\n", (float) s->agc_scaling_save, (float) s->agc_scaling);
span_log(&s->logging, SPAN_LOG_FLOW, "Phase rates %f %f\n", dds_frequencyf(s->carrier_phase_rate), dds_frequencyf(s->carrier_phase_rate_save));
@ -1504,6 +1568,7 @@ SPAN_DECLARE(int) v17_rx_restart(v17_rx_state_t *s, int bit_rate, int short_trai
s->symbol_sync_high[i] = FP_SCALE(0.0f);
s->symbol_sync_dc_filter[i] = FP_SCALE(0.0f);
}
/*endfor*/
s->baud_phase = FP_SCALE(0.0f);
s->baud_half = 0;
@ -1527,11 +1592,14 @@ SPAN_DECLARE(v17_rx_state_t *) v17_rx_init(v17_rx_state_t *s, int bit_rate, put_
default:
return NULL;
}
/*endswitch*/
if (s == NULL)
{
if ((s = (v17_rx_state_t *) span_alloc(sizeof(*s))) == NULL)
return NULL;
/*endif*/
}
/*endif*/
memset(s, 0, sizeof(*s));
span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
span_log_set_protocol(&s->logging, "V.17 RX");

View File

@ -5,7 +5,7 @@
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2004-2009 Steve Underwood
* Copyright (C) 2004-2015 Steve Underwood
*
* All rights reserved.
*

View File

@ -71,8 +71,10 @@
enum
{
V8_WAIT_1S = 0, /* Start point when sending CI */
V8_AWAIT_ANSAM, /* Start point when sending initial silence */
/* Start point when sending CI */
V8_WAIT_1S = 0,
/* Start point when sending initial silence */
V8_AWAIT_ANSAM,
V8_CI_ON,
V8_CI_OFF,
V8_HEARD_ANSAM,
@ -113,6 +115,8 @@ enum
V8_V92_SYNC_OCTET = 0x55
};
#define Te_TIMEOUT 500
SPAN_DECLARE(const char *) v8_call_function_to_str(int call_function)
{
switch (call_function)
@ -134,6 +138,7 @@ SPAN_DECLARE(const char *) v8_call_function_to_str(int call_function)
case V8_CALL_FUNCTION_EXTENSION:
return "Call function is in extension octet";
}
/*endswitch*/
return "Unknown call function";
}
/*- End of function --------------------------------------------------------*/
@ -171,6 +176,7 @@ SPAN_DECLARE(const char *) v8_modulation_to_str(int modulation_scheme)
case V8_MOD_V92:
return "V.92 duplex";
}
/*endswitch*/
return "???";
}
/*- End of function --------------------------------------------------------*/
@ -186,6 +192,7 @@ SPAN_DECLARE(const char *) v8_protocol_to_str(int protocol)
case V8_PROTOCOL_EXTENSION:
return "Extension";
}
/*endswitch*/
return "Undefined";
}
/*- End of function --------------------------------------------------------*/
@ -209,6 +216,7 @@ SPAN_DECLARE(const char *) v8_pstn_access_to_str(int pstn_access)
case (V8_PSTN_ACCESS_DCE_ON_DIGITAL | V8_PSTN_ACCESS_ANSWER_DCE_CELLULAR | V8_PSTN_ACCESS_CALL_DCE_CELLULAR):
return "DCE on digital, and answering and calling modems on cellular";
}
/*endswitch*/
return "PSTN access unknown";
}
/*- End of function --------------------------------------------------------*/
@ -220,6 +228,7 @@ SPAN_DECLARE(const char *) v8_nsf_to_str(int nsf)
case 0:
return "???";
}
/*endswitch*/
return "???";
}
/*- End of function --------------------------------------------------------*/
@ -245,6 +254,7 @@ SPAN_DECLARE(const char *) v8_pcm_modem_availability_to_str(int pcm_modem_availa
case (V8_PSTN_PCM_MODEM_V91 | V8_PSTN_PCM_MODEM_V90_V92_DIGITAL | V8_PSTN_PCM_MODEM_V90_V92_ANALOGUE):
return "V.91 and V.90/V.92 digital/analogue available";
}
/*endswitch*/
return "PCM availability unknown";
}
/*- End of function --------------------------------------------------------*/
@ -271,6 +281,7 @@ SPAN_DECLARE(const char *) v8_t66_to_str(int t66)
case 7:
return "Reserved TIA + others";
}
/*endswitch*/
return "???";
}
/*- End of function --------------------------------------------------------*/
@ -289,7 +300,9 @@ SPAN_DECLARE(void) v8_log_supported_modulations(v8_state_t *s, int modulation_sc
span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, "%s%s", comma, v8_modulation_to_str(modulation_schemes & (1 << i)));
comma = ", ";
}
/*endif*/
}
/*endfor*/
span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, " supported\n");
}
/*- End of function --------------------------------------------------------*/
@ -298,6 +311,7 @@ static int report_event(v8_state_t *s)
{
if (s->result_handler)
s->result_handler(s->result_handler_user_data, &s->result);
/*endif*/
return 0;
}
/*- End of function --------------------------------------------------------*/
@ -321,10 +335,13 @@ static const uint8_t *process_modulation_mode(v8_state_t *s, const uint8_t *p)
s->modulation_bytes = 1;
if (*p & 0x80)
modulations |= V8_MOD_V34HDX;
/*endif*/
if (*p & 0x40)
modulations |= V8_MOD_V34;
/*endif*/
if (*p & 0x20)
modulations |= V8_MOD_V90;
/*endif*/
++p;
/* Check for an extension octet */
@ -333,14 +350,19 @@ static const uint8_t *process_modulation_mode(v8_state_t *s, const uint8_t *p)
s->modulation_bytes++;
if (*p & 0x80)
modulations |= V8_MOD_V27TER;
/*endif*/
if (*p & 0x40)
modulations |= V8_MOD_V29;
/*endif*/
if (*p & 0x04)
modulations |= V8_MOD_V17;
/*endif*/
if (*p & 0x02)
modulations |= V8_MOD_V22;
/*endif*/
if (*p & 0x01)
modulations |= V8_MOD_V32;
/*endif*/
++p;
/* Check for an extension octet */
@ -349,17 +371,24 @@ static const uint8_t *process_modulation_mode(v8_state_t *s, const uint8_t *p)
s->modulation_bytes++;
if (*p & 0x80)
modulations |= V8_MOD_V21;
/*endif*/
if (*p & 0x40)
modulations |= V8_MOD_V23HDX;
/*endif*/
if (*p & 0x04)
modulations |= V8_MOD_V23;
/*endif*/
if (*p & 0x02)
modulations |= V8_MOD_V26BIS;
/*endif*/
if (*p & 0x01)
modulations |= V8_MOD_V26TER;
++p;
/*endif*/
++p;
}
/*endif*/
}
/*endif*/
s->result.modulations = modulations;
v8_log_supported_modulations(s, modulations);
return p;
@ -411,6 +440,7 @@ static void ci_decode(v8_state_t *s)
{
if ((s->rx_data[0] & 0x1F) == V8_CALL_FUNCTION_TAG)
process_call_function(s, &s->rx_data[0]);
/*endif*/
}
/*- End of function --------------------------------------------------------*/
@ -420,6 +450,7 @@ static void cm_jm_decode(v8_state_t *s)
if (s->got_cm_jm)
return;
/*endif*/
/* We must receive two consecutive identical CM or JM sequences to accept it. */
if (s->cm_jm_len <= 0
@ -433,6 +464,7 @@ static void cm_jm_decode(v8_state_t *s)
memcpy(s->cm_jm_data, s->rx_data, s->rx_data_ptr);
return;
}
/*endif*/
/* We have a matching pair of CMs or JMs, so we are happy this is correct. */
s->got_cm_jm = true;
@ -473,10 +505,13 @@ static void cm_jm_decode(v8_state_t *s)
p++;
break;
}
/*endswitch*/
/* Skip any future extensions we do not understand */
while ((*p & 0x38) == 0x10)
p++;
/*endwhile*/
}
/*endwhile*/
}
/*- End of function --------------------------------------------------------*/
@ -501,8 +536,10 @@ static void put_bit(void *user_data, int bit)
default:
break;
}
/*endswitch*/
return;
}
/*endif*/
//span_log(&s->logging, SPAN_LOG_FLOW, "Bit %d\n", bit);
/* Wait until we sync. */
s->bit_stream = (s->bit_stream >> 1) | (bit << 19);
@ -529,6 +566,7 @@ static void put_bit(void *user_data, int bit)
new_preamble_type = V8_SYNC_UNKNOWN;
break;
}
/*endswitch*/
if (new_preamble_type != V8_SYNC_UNKNOWN)
{
/* We have seen a fresh sync code */
@ -552,9 +590,12 @@ static void put_bit(void *user_data, int bit)
tag = ">??: ";
break;
}
/*endswitch*/
span_log_buf(&s->logging, SPAN_LOG_FLOW, tag, s->rx_data, s->rx_data_ptr);
}
/*endif*/
}
/*endif*/
/* If we were handling a valid sync code then we should process what has been
received to date. */
switch (s->preamble_type)
@ -566,10 +607,12 @@ static void put_bit(void *user_data, int bit)
cm_jm_decode(s);
break;
}
/*endswitch*/
s->preamble_type = new_preamble_type;
s->bit_cnt = 0;
s->rx_data_ptr = 0;
}
/*endif*/
if (s->preamble_type != V8_SYNC_UNKNOWN)
{
@ -585,17 +628,22 @@ static void put_bit(void *user_data, int bit)
{
if (++s->zero_byte_count == 3)
s->got_cj = true;
/*endif*/
}
else
{
s->zero_byte_count = 0;
}
/*endif*/
if (s->rx_data_ptr < (int) (sizeof(s->rx_data) - 1))
s->rx_data[s->rx_data_ptr++] = data;
/*endif*/
s->bit_cnt = 0;
}
/*endif*/
}
/*endif*/
}
/*- End of function --------------------------------------------------------*/
@ -625,6 +673,7 @@ static int get_bit(void *user_data)
s = user_data;
if (queue_read(s->tx_queue, &bit, 1) <= 0)
return SIG_STATUS_END_OF_DATA;
/*endif*/
return bit;
}
/*- End of function --------------------------------------------------------*/
@ -657,9 +706,11 @@ static void v8_put_bytes(v8_state_t *s, uint8_t buf[], int len)
bits[j] = byte & 1;
byte >>= 1;
}
/*endfor*/
bits[9] = 1;
queue_write(s->tx_queue, bits, 10);
}
/*endfor*/
}
/*- End of function --------------------------------------------------------*/
@ -684,50 +735,68 @@ static void send_cm_jm(v8_state_t *s)
val = 0x05;
if (offered_modulations & V8_MOD_V90)
val |= 0x20;
/*endif*/
if (offered_modulations & V8_MOD_V34)
val |= 0x40;
/*endif*/
if (offered_modulations & V8_MOD_V34HDX)
val |= 0x80;
/*endif*/
buf[ptr++] = val;
if (++bytes < s->modulation_bytes)
{
val = 0x10;
if (offered_modulations & V8_MOD_V32)
val |= 0x01;
/*endif*/
if (offered_modulations & V8_MOD_V22)
val |= 0x02;
/*endif*/
if (offered_modulations & V8_MOD_V17)
val |= 0x04;
/*endif*/
if (offered_modulations & V8_MOD_V29)
val |= 0x40;
/*endif*/
if (offered_modulations & V8_MOD_V27TER)
val |= 0x80;
/*endif*/
buf[ptr++] = val;
}
/*endif*/
if (++bytes < s->modulation_bytes)
{
val = 0x10;
if (offered_modulations & V8_MOD_V26TER)
val |= 0x01;
/*endif*/
if (offered_modulations & V8_MOD_V26BIS)
val |= 0x02;
/*endif*/
if (offered_modulations & V8_MOD_V23)
val |= 0x04;
/*endif*/
if (offered_modulations & V8_MOD_V23HDX)
val |= 0x40;
/*endif*/
if (offered_modulations & V8_MOD_V21)
val |= 0x80;
/*endif*/
buf[ptr++] = val;
}
/*endif*/
if (s->parms.protocol)
buf[ptr++] = (s->parms.protocol << 5) | V8_PROTOCOLS_TAG;
/*endif*/
if (s->parms.pstn_access)
buf[ptr++] = (s->parms.pstn_access << 5) | V8_PSTN_ACCESS_TAG;
/*endif*/
if (s->parms.pcm_modem_availability)
buf[ptr++] = (s->parms.pcm_modem_availability << 5) | V8_PCM_MODEM_AVAILABILITY_TAG;
/*endif*/
if (s->parms.t66 >= 0)
buf[ptr++] = (s->parms.t66 << 5) | V8_T66_TAG;
/*endif*/
/* No NSF */
//buf[ptr++] = (0 << 5) | V8_NSF_TAG;
span_log_buf(&s->logging, SPAN_LOG_FLOW, (s->calling_party) ? "<CM: " : "<JM: ", &buf[1], ptr - 1);
@ -743,23 +812,25 @@ SPAN_DECLARE(int) v8_tx(v8_state_t *s, int16_t *amp, int max_len)
len = 0;
if (s->modem_connect_tone_tx_on)
{
if (s->modem_connect_tone_tx_on == (ms_to_samples(75) + 2))
if (s->modem_connect_tone_tx_on == (milliseconds_to_samples(75) + 2))
{
if (s->fsk_tx_on)
{
/* The initial silence is over */
s->modem_connect_tone_tx_on = 0;
}
/*endif*/
}
else if (s->modem_connect_tone_tx_on == (ms_to_samples(75) + 1))
else if (s->modem_connect_tone_tx_on == (milliseconds_to_samples(75) + 1))
{
/* Send the ANSam tone */
len = modem_connect_tones_tx(&s->ansam_tx, amp, max_len);
if (len < max_len)
{
span_log(&s->logging, SPAN_LOG_FLOW, "ANSam or ANSam/ ended\n");
s->modem_connect_tone_tx_on = ms_to_samples(75);
s->modem_connect_tone_tx_on = milliseconds_to_samples(75);
}
/*endif*/
}
else
{
@ -768,10 +839,13 @@ SPAN_DECLARE(int) v8_tx(v8_state_t *s, int16_t *amp, int max_len)
len = s->modem_connect_tone_tx_on;
else
len = max_len;
/*endif*/
vec_zeroi16(amp, len);
s->modem_connect_tone_tx_on -= len;
}
/*endif*/
}
/*endif*/
if (s->fsk_tx_on && len < max_len)
{
len += fsk_tx(&s->v21tx, &amp[len], max_len - len);
@ -781,33 +855,38 @@ SPAN_DECLARE(int) v8_tx(v8_state_t *s, int16_t *amp, int max_len)
s->fsk_tx_on = false;
//s->state = V8_PARKED;
}
/*endif*/
}
/*endif*/
if (s->state != V8_PARKED && len < max_len)
{
vec_zeroi16(&amp[len], max_len - len);
len = max_len;
}
/*endif*/
return len;
}
/*- End of function --------------------------------------------------------*/
static void send_v92(v8_state_t *s)
static void conditionally_send_v92(v8_state_t *s)
{
int i;
uint8_t buf[2];
if (s->result.v92 >= 0)
if (s->parms.v92 >= 0)
{
/* Send 2 V.92 packets */
for (i = 0; i < 2; i++)
{
v8_put_preamble(s);
buf[0] = V8_V92_SYNC_OCTET;
buf[1] = s->result.v92;
buf[1] = s->parms.v92;
span_log_buf(&s->logging, SPAN_LOG_FLOW, "<V.92: ", &buf[1], 1);
v8_put_bytes(s, buf, 2);
}
/*endfor*/
}
/*endif*/
}
/*- End of function --------------------------------------------------------*/
@ -825,6 +904,7 @@ static void send_ci(v8_state_t *s)
span_log_buf(&s->logging, SPAN_LOG_FLOW, "<CI: ", &buf[1], 1);
v8_put_bytes(s, buf, 2);
}
/*endfor*/
}
/*- End of function --------------------------------------------------------*/
@ -839,7 +919,9 @@ static void handle_modem_connect_tone(v8_state_t *s, int tone)
/* Set the Te interval. The spec. says 500ms is the minimum,
but gives reasons why 1 second is a better value (V.8/8.1.1). */
s->state = V8_HEARD_ANSAM;
s->ci_timer = ms_to_samples(1000);
s->ci_timer = milliseconds_to_samples(2*Te_TIMEOUT);
s->negotiation_timer = milliseconds_to_samples(5000);
v8_decode_init(s);
}
else
{
@ -850,6 +932,7 @@ static void handle_modem_connect_tone(v8_state_t *s, int tone)
s->result.status = V8_STATUS_NON_V8_CALL;
report_event(s);
}
/*endif*/
}
/*- End of function --------------------------------------------------------*/
@ -868,6 +951,7 @@ SPAN_DECLARE(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
/* Wait 1 second before sending the first CI packet */
if ((s->negotiation_timer -= len) > 0)
break;
/*endif*/
fsk_tx_restart(&s->v21tx, &preset_fsk_specs[FSK_V21CH1]);
send_ci(s);
s->state = V8_CI_ON;
@ -881,12 +965,15 @@ SPAN_DECLARE(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
handle_modem_connect_tone(s, tone);
break;
}
/*endif*/
if (!s->fsk_tx_on)
{
s->state = V8_CI_OFF;
s->ci_timer = ms_to_samples(500);
s->ci_timer = milliseconds_to_samples(Te_TIMEOUT);
s->negotiation_timer = milliseconds_to_samples(5000);
break;
}
/*endif*/
break;
case V8_CI_OFF:
residual_samples = modem_connect_tones_rx(&s->ansam_rx, amp, len);
@ -896,6 +983,7 @@ SPAN_DECLARE(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
handle_modem_connect_tone(s, tone);
break;
}
/*endif*/
if ((s->ci_timer -= len) <= 0)
{
if (++s->ci_count >= 10)
@ -914,28 +1002,30 @@ SPAN_DECLARE(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
s->state = V8_CI_ON;
s->fsk_tx_on = true;
}
/*endif*/
}
/*endif*/
break;
case V8_AWAIT_ANSAM:
residual_samples = modem_connect_tones_rx(&s->ansam_rx, amp, len);
/* Check if an ANSam or ANSam/ tone has been detected */
if ((tone = modem_connect_tones_rx_get(&s->ansam_rx)) != MODEM_CONNECT_TONES_NONE)
handle_modem_connect_tone(s, tone);
/*endif*/
break;
case V8_HEARD_ANSAM:
/* We have heard the ANSam or ANSam/ signal, but we still need to wait for the
end of the Te timeout period to comply with the spec. */
if ((s->ci_timer -= len) <= 0)
{
v8_decode_init(s);
s->negotiation_timer = ms_to_samples(5000);
fsk_tx_restart(&s->v21tx, &preset_fsk_specs[FSK_V21CH1]);
send_v92(s);
conditionally_send_v92(s);
send_cm_jm(s);
s->state = V8_CM_ON;
s->fsk_tx_on = true;
s->state = V8_CM_ON;
}
break;
/*endif*/
/* Fall through */
case V8_CM_ON:
residual_samples = fsk_rx(&s->v21rx, amp, len);
if (s->got_cm_jm)
@ -951,6 +1041,7 @@ SPAN_DECLARE(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
s->fsk_tx_on = true;
break;
}
/*endif*/
if ((s->negotiation_timer -= len) <= 0)
{
/* Timeout */
@ -959,20 +1050,23 @@ SPAN_DECLARE(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
s->result.status = V8_STATUS_FAILED;
report_event(s);
}
/*endif*/
if (queue_contents(s->tx_queue) < 10)
{
/* Send CM again */
send_cm_jm(s);
}
/*endif*/
break;
case V8_CJ_ON:
residual_samples = fsk_rx(&s->v21rx, amp, len);
if (!s->fsk_tx_on)
{
#if 0
s->negotiation_timer = ms_to_samples(75);
s->negotiation_timer = milliseconds_to_samples(75);
s->state = V8_SIGC;
}
/*endif*/
break;
case V8_SIGC:
if ((s->negotiation_timer -= len) <= 0)
@ -984,6 +1078,7 @@ SPAN_DECLARE(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
s->result.status = V8_STATUS_V8_CALL;
report_event(s);
}
/*endif*/
break;
case V8_CM_WAIT:
residual_samples = fsk_rx(&s->v21rx, amp, len);
@ -997,13 +1092,14 @@ SPAN_DECLARE(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
/* Stop sending ANSam or ANSam/ and send JM instead */
fsk_tx_init(&s->v21tx, &preset_fsk_specs[FSK_V21CH2], get_bit, s);
/* Set the timeout for JM */
s->negotiation_timer = ms_to_samples(5000);
s->negotiation_timer = milliseconds_to_samples(5000);
s->state = V8_JM_ON;
send_cm_jm(s);
s->modem_connect_tone_tx_on = ms_to_samples(75);
s->modem_connect_tone_tx_on = milliseconds_to_samples(75);
s->fsk_tx_on = true;
break;
}
/*endif*/
if ((s->negotiation_timer -= len) <= 0)
{
/* Timeout */
@ -1012,6 +1108,7 @@ SPAN_DECLARE(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
s->result.status = V8_STATUS_FAILED;
report_event(s);
}
/*endif*/
break;
case V8_JM_ON:
residual_samples = fsk_rx(&s->v21rx, amp, len);
@ -1020,10 +1117,11 @@ SPAN_DECLARE(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
span_log(&s->logging, SPAN_LOG_FLOW, "CJ recognised\n");
/* Stop sending JM, flushing anything left in the buffer, and wait 75 ms */
queue_flush(s->tx_queue);
s->negotiation_timer = ms_to_samples(75);
s->negotiation_timer = milliseconds_to_samples(75);
s->state = V8_SIGA;
break;
}
/*endif*/
if ((s->negotiation_timer -= len) <= 0)
{
/* Timeout */
@ -1033,11 +1131,13 @@ SPAN_DECLARE(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
report_event(s);
break;
}
/*endif*/
if (queue_contents(s->tx_queue) < 10)
{
/* Send JM */
send_cm_jm(s);
}
/*endif*/
break;
case V8_SIGA:
if (!s->fsk_tx_on)
@ -1049,11 +1149,13 @@ SPAN_DECLARE(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
s->result.status = V8_STATUS_V8_CALL;
report_event(s);
}
/*endif*/
break;
case V8_PARKED:
residual_samples = len;
break;
}
/*endswitch*/
return residual_samples;
}
/*- End of function --------------------------------------------------------*/
@ -1085,30 +1187,34 @@ SPAN_DECLARE(int) v8_restart(v8_state_t *s, bool calling_party, v8_parms_t *parm
if (s->result.send_ci)
{
s->state = V8_WAIT_1S;
s->negotiation_timer = ms_to_samples(1000);
s->negotiation_timer = milliseconds_to_samples(1000);
s->ci_count = 0;
}
else
{
s->state = V8_AWAIT_ANSAM;
}
/*endif*/
modem_connect_tones_rx_init(&s->ansam_rx, MODEM_CONNECT_TONES_ANS_PR, NULL, NULL);
fsk_tx_init(&s->v21tx, &preset_fsk_specs[FSK_V21CH1], get_bit, s);
s->modem_connect_tone_tx_on = ms_to_samples(75) + 2;
s->modem_connect_tone_tx_on = milliseconds_to_samples(75) + 2;
}
else
{
/* Send the ANSam or ANSam/ tone */
s->state = V8_CM_WAIT;
s->negotiation_timer = ms_to_samples(200 + 5000);
s->negotiation_timer = milliseconds_to_samples(200 + 5000);
v8_decode_init(s);
modem_connect_tones_tx_init(&s->ansam_tx, s->parms.modem_connect_tone);
s->modem_connect_tone_tx_on = ms_to_samples(75) + 1;
s->modem_connect_tone_tx_on = milliseconds_to_samples(75) + 1;
}
/*endif*/
if (s->tx_queue)
queue_free(s->tx_queue);
/*endif*/
if ((s->tx_queue = queue_init(NULL, 1024, 0)) == NULL)
return -1;
/*endif*/
return 0;
}
/*- End of function --------------------------------------------------------*/
@ -1123,7 +1229,9 @@ SPAN_DECLARE(v8_state_t *) v8_init(v8_state_t *s,
{
if ((s = (v8_state_t *) span_alloc(sizeof(*s))) == NULL)
return NULL;
/*endif*/
}
/*endif*/
memset(s, 0, sizeof(*s));
span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
span_log_set_protocol(&s->logging, "V.8");

View File

@ -188,6 +188,10 @@ static int modem_tests(int use_gui, int log_audio, int test_sending)
bert_set_report(bert[i], 100000, reporter, (void *) (intptr_t) i);
if ((data_modems_state[i] = data_modems_init(NULL,
calling_party,
NULL,
NULL,
NULL,
NULL,
put_msg,
get_msg,
NULL)) == NULL)

View File

@ -67,6 +67,61 @@ int16_t wave_buffer[4096];
data_modems_state_t *data_modem_state;
int answered = false;
int done = false;
static int modem_call_control(data_modems_state_t *s, void *user_data, int op, const char *num)
{
printf("\nModem control - %s", at_modem_control_to_str(op));
switch (op)
{
case AT_MODEM_CONTROL_CALL:
printf(" %s", num);
data_modems_call_event(s, AT_CALL_EVENT_CONNECTED);
break;
case AT_MODEM_CONTROL_ANSWER:
answered = true;
data_modems_call_event(s, AT_CALL_EVENT_ANSWERED);
break;
case AT_MODEM_CONTROL_HANGUP:
done = true;
break;
case AT_MODEM_CONTROL_OFFHOOK:
break;
case AT_MODEM_CONTROL_DTR:
printf(" %d", (int) (intptr_t) num);
break;
case AT_MODEM_CONTROL_RTS:
printf(" %d", (int) (intptr_t) num);
break;
case AT_MODEM_CONTROL_CTS:
printf(" %d", (int) (intptr_t) num);
break;
case AT_MODEM_CONTROL_CAR:
printf(" %d", (int) (intptr_t) num);
break;
case AT_MODEM_CONTROL_RNG:
printf(" %d", (int) (intptr_t) num);
break;
case AT_MODEM_CONTROL_DSR:
printf(" %d", (int) (intptr_t) num);
break;
case AT_MODEM_CONTROL_SETID:
printf(" %d", (int) (intptr_t) num);
break;
case AT_MODEM_CONTROL_RESTART:
printf(" %d", (int) (intptr_t) num);
break;
case AT_MODEM_CONTROL_DTE_TIMEOUT:
printf(" %d", (int) (intptr_t) num);
break;
}
/*endswitch*/
printf("\n");
return 0;
}
/*- End of function --------------------------------------------------------*/
static int get_msg(void *user_data, uint8_t msg[], int len)
{
return 0;
@ -79,17 +134,31 @@ static void put_msg(void *user_data, const uint8_t msg[], int len)
printf("Status %s\n", signal_status_to_str(len));
else
printf("Put %d '%s'\n", len, msg);
/*endif*/
}
/*- End of function --------------------------------------------------------*/
static void terminal_callback(void *user_data, const uint8_t msg[], int len)
{
data_modems_state_t *s;
int i;
s = (data_modems_state_t *) user_data;
printf("terminal callback %d\n", len);
for (i = 0; i < len; i++)
{
printf("0x%x ", msg[i]);
}
printf("\n");
at_interpreter(&s->at_state, msg, len);
}
/*- End of function --------------------------------------------------------*/
static int termios_callback(void *user_data, struct termios *termios)
{
data_modems_state_t *s;
s = (data_modems_state_t *) user_data;
printf("termios callback\n");
return 0;
}
@ -116,7 +185,9 @@ static int rx_callback(void *user_data, const int16_t amp[], int samples)
{
for (i = 0; i < samples; i++)
wave_buffer[2*i] = amp[i];
/*endfor*/
}
/*endif*/
return out_samples;
}
/*- End of function --------------------------------------------------------*/
@ -137,10 +208,13 @@ static int tx_callback(void *user_data, int16_t amp[], int samples)
{
if (out_samples < samples)
memset(&amp[out_samples], 0, (samples - out_samples)*2);
/*endif*/
for (i = 0; i < samples; i++)
wave_buffer[2*i + 1] = amp[i];
/*endfor*/
sf_writef_short(wave_handle, wave_buffer, samples);
}
/*endif*/
return samples;
}
/*- End of function --------------------------------------------------------*/
@ -153,6 +227,10 @@ static int modem_tests(int use_gui, int log_audio, bool calling_party)
/* Now set up and run the modems */
if ((data_modem_state = data_modems_init(NULL,
calling_party,
terminal_write,
NULL,
modem_call_control,
NULL,
put_msg,
get_msg,
NULL)) == NULL)
@ -160,6 +238,7 @@ static int modem_tests(int use_gui, int log_audio, bool calling_party)
fprintf(stderr, " Cannot start the data modem\n");
exit(2);
}
/*endif*/
logging = data_modems_get_logging_state(data_modem_state);
span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_DATE);
span_log_set_tag(logging, "Modem");
@ -180,6 +259,9 @@ static int modem_tests(int use_gui, int log_audio, bool calling_party)
fprintf(stderr, " Cannot start the socket harness\n");
exit(2);
}
/*endif*/
data_modems_set_at_tx_handler(data_modem_state, terminal_write, s);
wave_handle = NULL;
if (log_audio)
@ -189,9 +271,11 @@ static int modem_tests(int use_gui, int log_audio, bool calling_party)
fprintf(stderr, " Cannot create audio file '%s'\n", OUTPUT_WAVE_FILE_NAME);
exit(2);
}
/*endif*/
}
/*endif*/
socket_harness_run(s);
socket_harness_run(s, calling_party);
if (log_audio)
{
@ -200,7 +284,9 @@ static int modem_tests(int use_gui, int log_audio, bool calling_party)
fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_WAVE_FILE_NAME);
exit(2);
}
/*endif*/
}
/*endif*/
return 0;
}
@ -242,10 +328,13 @@ int main(int argc, char *argv[])
exit(2);
break;
}
/*endswitch*/
}
/*endwhile*/
if (modem_tests(use_gui, log_audio, calling_party))
exit(2);
/*endif*/
printf("Tests passed\n");
return 0;
}

View File

@ -79,7 +79,16 @@ static void log_signal(int signum)
}
/*- End of function --------------------------------------------------------*/
int socket_harness_run(socket_harness_state_t *s)
int terminal_write(void *user_data, const char *buf, int len)
{
socket_harness_state_t *s;
s = (socket_harness_state_t *) user_data;
return write(s->pty_fd, buf, len);
}
/*- End of function --------------------------------------------------------*/
int socket_harness_run(socket_harness_state_t *s, int kick)
{
struct timeval tmo;
fd_set rset;
@ -91,6 +100,23 @@ int socket_harness_run(socket_harness_state_t *s)
int tx_samples;
int ret;
if (kick)
{
samples = 160;
tx_samples = s->tx_callback(s->user_data, outbuf, samples);
if (tx_samples < samples)
memset(&outbuf[tx_samples], 0, (samples - tx_samples)*2);
if ((count = write(s->audio_fd, outbuf, samples*2)) < 0)
{
if (errno != EAGAIN)
{
fprintf(stderr, "Error: audio write: %s\n", strerror(errno));
return -1;
}
/* TODO: */
}
}
while (keep_running)
{
//if (s->modem->event)
@ -131,7 +157,6 @@ int socket_harness_run(socket_harness_state_t *s)
fprintf(stderr, "Error: select: %s\n", strerror(errno));
return ret;
}
if (ret == 0)
{
/* Timeout */

View File

@ -53,7 +53,9 @@ typedef struct socket_harness_state_s
modem_t modem;
} socket_harness_state_t;
int socket_harness_run(socket_harness_state_t *s);
int socket_harness_run(socket_harness_state_t *s, int kick);
int terminal_write(void *user_data, const char *buf, int len);
socket_harness_state_t *socket_harness_init(socket_harness_state_t *s,
const char *socket_name,