More tweaks for spandsp.

This commit is contained in:
Steve Underwood 2012-07-04 23:57:30 +08:00
parent 2b75169c07
commit 4a200ce3a0
17 changed files with 375 additions and 118 deletions

View File

@ -258,45 +258,42 @@ SPAN_DECLARE(int) dtmf_rx(dtmf_rx_state_t *s, const int16_t amp[], int samples)
Note this is only relevant to VoIP using A-law, u-law or similar.
Low bit rate codecs scramble DTMF too much for it to be recognised,
and often slip in units larger than a sample. */
if (hit != s->in_digit)
if (hit != s->in_digit && s->last_hit != s->in_digit)
{
if (s->last_hit != s->in_digit)
/* We have two successive indications that something has changed. */
/* To declare digit on, the hits must agree. Otherwise we declare tone off. */
hit = (hit && hit == s->last_hit) ? hit : 0;
if (s->realtime_callback)
{
/* We have two successive indications that something has changed. */
/* To declare digit on, the hits must agree. Otherwise we declare tone off. */
hit = (hit && hit == s->last_hit) ? hit : 0;
if (s->realtime_callback)
/* Avoid reporting multiple no digit conditions on flaky hits */
if (s->in_digit || hit)
{
/* Avoid reporting multiple no digit conditions on flaky hits */
if (s->in_digit || hit)
{
i = (s->in_digit && !hit) ? -99 : lfastrintf(log10f(s->energy)*10.0f - DTMF_POWER_OFFSET + DBM0_MAX_POWER);
s->realtime_callback(s->realtime_callback_data, hit, i, s->duration);
s->duration = 0;
}
i = (s->in_digit && !hit) ? -99 : lfastrintf(log10f(s->energy)*10.0f - DTMF_POWER_OFFSET + DBM0_MAX_POWER);
s->realtime_callback(s->realtime_callback_data, hit, i, s->duration);
s->duration = 0;
}
else
{
if (hit)
{
if (s->current_digits < MAX_DTMF_DIGITS)
{
s->digits[s->current_digits++] = (char) hit;
s->digits[s->current_digits] = '\0';
if (s->digits_callback)
{
s->digits_callback(s->digits_callback_data, s->digits, s->current_digits);
s->current_digits = 0;
}
}
else
{
s->lost_digits++;
}
}
}
s->in_digit = hit;
}
else
{
if (hit)
{
if (s->current_digits < MAX_DTMF_DIGITS)
{
s->digits[s->current_digits++] = (char) hit;
s->digits[s->current_digits] = '\0';
if (s->digits_callback)
{
s->digits_callback(s->digits_callback_data, s->digits, s->current_digits);
s->current_digits = 0;
}
}
else
{
s->lost_digits++;
}
}
}
s->in_digit = hit;
}
s->last_hit = hit;
#if defined(SPANDSP_USE_FIXED_POINT)
@ -333,7 +330,7 @@ SPAN_DECLARE(int) dtmf_rx_fillin(dtmf_rx_state_t *s, int samples)
#endif
s->current_sample = 0;
/* Don't update the hit detection. Pretend it never happened. */
/* TODO: Surely we can be a cleverer than this. */
/* TODO: Surely we can be cleverer than this. */
return 0;
}
/*- End of function --------------------------------------------------------*/
@ -359,7 +356,7 @@ SPAN_DECLARE(size_t) dtmf_rx_get(dtmf_rx_state_t *s, char *buf, int max)
s->current_digits -= max;
}
buf[max] = '\0';
return max;
return max;
}
/*- End of function --------------------------------------------------------*/
@ -417,7 +414,7 @@ SPAN_DECLARE(dtmf_rx_state_t *) dtmf_rx_init(dtmf_rx_state_t *s,
if (s == NULL)
{
if ((s = (dtmf_rx_state_t *) malloc(sizeof (*s))) == NULL)
return NULL;
return NULL;
}
memset(s, 0, sizeof(*s));
span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
@ -570,7 +567,7 @@ SPAN_DECLARE(dtmf_tx_state_t *) dtmf_tx_init(dtmf_tx_state_t *s)
if (s == NULL)
{
if ((s = (dtmf_tx_state_t *) malloc(sizeof (*s))) == NULL)
return NULL;
return NULL;
}
memset(s, 0, sizeof(*s));
if (!dtmf_tx_inited)

View File

@ -154,7 +154,8 @@ static void rx_flag_or_abort(hdlc_rx_state_t *s)
s->rx_frames++;
s->rx_bytes += s->len - s->crc_bytes;
s->len -= s->crc_bytes;
s->frame_handler(s->frame_user_data, s->buffer, s->len, TRUE);
if (s->frame_handler)
s->frame_handler(s->frame_user_data, s->buffer, s->len, TRUE);
}
else
{
@ -162,7 +163,8 @@ static void rx_flag_or_abort(hdlc_rx_state_t *s)
if (s->report_bad_frames)
{
s->len -= s->crc_bytes;
s->frame_handler(s->frame_user_data, s->buffer, s->len, FALSE);
if (s->frame_handler)
s->frame_handler(s->frame_user_data, s->buffer, s->len, FALSE);
}
}
}
@ -177,7 +179,8 @@ static void rx_flag_or_abort(hdlc_rx_state_t *s)
s->len -= s->crc_bytes;
else
s->len = 0;
s->frame_handler(s->frame_user_data, s->buffer, s->len, FALSE);
if (s->frame_handler)
s->frame_handler(s->frame_user_data, s->buffer, s->len, FALSE);
}
s->rx_length_errors++;
}

View File

@ -450,6 +450,151 @@ int main(int argc, char **argv)
rx_tag = "";
tx_tag = "";
}
else if (strcmp(modem, "V.34_2400") == 0)
{
rx_coeff_sets = 192;
rx_coeffs_per_filter = 27;
rx_excess_bandwidth = 0.25;
tx_coeff_sets = 10;
tx_coeffs_per_filter = 9;
tx_excess_bandwidth = 0.12;
carrier = 1600.0;
baud_rate = 2400.0;
rx_tag = "_2400_low_carrier";
tx_tag = "_2400";
}
else if (strcmp(modem, "V.34_2400_high") == 0)
{
rx_coeff_sets = 192;
rx_coeffs_per_filter = 27;
rx_excess_bandwidth = 0.25;
tx_coeff_sets = 10;
tx_coeffs_per_filter = 9;
tx_excess_bandwidth = 0.12;
carrier = 1800.0;
baud_rate = 2400.0;
rx_tag = "_2400_high_carrier";
tx_tag = "_2400";
}
else if (strcmp(modem, "V.34_2743") == 0)
{
rx_coeff_sets = 192;
rx_coeffs_per_filter = 27;
rx_excess_bandwidth = 0.25;
tx_coeff_sets = 35;
tx_coeffs_per_filter = 9;
tx_excess_bandwidth = 0.12;
carrier = 1646.0;
baud_rate = 2400.0*8.0/7.0;
rx_tag = "_2743_low_carrier";
tx_tag = "_2743";
}
else if (strcmp(modem, "V.34_2743_high") == 0)
{
rx_coeff_sets = 192;
rx_coeffs_per_filter = 27;
rx_excess_bandwidth = 0.25;
tx_coeff_sets = 35;
tx_coeffs_per_filter = 9;
tx_excess_bandwidth = 0.12;
carrier = 1829.0;
baud_rate = 2400.0*8.0/7.0;
rx_tag = "_2743_high_carrier";
tx_tag = "_2743";
}
else if (strcmp(modem, "V.34_2800") == 0)
{
rx_coeff_sets = 192;
rx_coeffs_per_filter = 27;
rx_excess_bandwidth = 0.25;
tx_coeff_sets = 20;
tx_coeffs_per_filter = 9;
tx_excess_bandwidth = 0.12;
carrier = 1680.0;
baud_rate = 2400.0*7.0/6.0;
rx_tag = "_2800_low_carrier";
tx_tag = "_2800";
}
else if (strcmp(modem, "V.34_2800_high") == 0)
{
rx_coeff_sets = 192;
rx_coeffs_per_filter = 27;
rx_excess_bandwidth = 0.25;
tx_coeff_sets = 20;
tx_coeffs_per_filter = 9;
tx_excess_bandwidth = 0.12;
carrier = 1867.0;
baud_rate = 2400.0*7.0/6.0;
rx_tag = "_2800_high_carrier";
tx_tag = "_2800";
}
else if (strcmp(modem, "V.34_3000") == 0)
{
rx_coeff_sets = 192;
rx_coeffs_per_filter = 27;
rx_excess_bandwidth = 0.25;
tx_coeff_sets = 8;
tx_coeffs_per_filter = 9;
tx_excess_bandwidth = 0.12;
carrier = 1800.0;
baud_rate = 2400.0*5.0/4.0;
rx_tag = "_3000_low_carrier";
tx_tag = "_3000";
}
else if (strcmp(modem, "V.34_3000_high") == 0)
{
rx_coeff_sets = 192;
rx_coeffs_per_filter = 27;
rx_excess_bandwidth = 0.25;
tx_coeff_sets = 8;
tx_coeffs_per_filter = 9;
tx_excess_bandwidth = 0.12;
carrier = 2000.0;
baud_rate = 2400.0*5.0/4.0;
rx_tag = "_3000_high_carrier";
tx_tag = "_3000";
}
else if (strcmp(modem, "V.34_3200") == 0)
{
rx_coeff_sets = 192;
rx_coeffs_per_filter = 27;
rx_excess_bandwidth = 0.25;
tx_coeff_sets = 5;
tx_coeffs_per_filter = 9;
tx_excess_bandwidth = 0.12;
carrier = 1829.0;
baud_rate = 2400.0*4.0/3.0;
rx_tag = "_3200_low_carrier";
tx_tag = "_3200";
}
else if (strcmp(modem, "V.34_3200_high") == 0)
{
rx_coeff_sets = 192;
rx_coeffs_per_filter = 27;
rx_excess_bandwidth = 0.25;
tx_coeff_sets = 5;
tx_coeffs_per_filter = 9;
tx_excess_bandwidth = 0.12;
carrier = 1920.0;
baud_rate = 2400.0*4.0/3.0;
rx_tag = "_3200_high_carrier";
tx_tag = "_3200";
}
else if (strcmp(modem, "V.34_3429") == 0)
{
/* There is only one carrier frequency defined for this baud rate */
rx_coeff_sets = 192;
rx_coeffs_per_filter = 27;
rx_excess_bandwidth = 0.25;
tx_coeff_sets = 7;
tx_coeffs_per_filter = 9;
tx_excess_bandwidth = 0.12;
//carrier = 1959.0;
carrier = 1959.0;
baud_rate = 2400.0*10.0/7.0;
rx_tag = "_3429";
tx_tag = "_3429";
}
else
{
usage();

View File

@ -29,9 +29,11 @@
/* CNG is 0.5s+-15% of 1100+-38Hz, 3s+-15% off, repeating.
CED is 0.2s silence, 3.3+-0.7s of 2100+-15Hz, and 75+-20ms of silence.
Calling tone is 0.5s-0.7s of 1300Hz+-15Hz, 1.5s-2.0s off, repeating.
ANS is 3.3+-0.7s of 2100+-15Hz.
ANS/ is 3.3+-0.7s of 2100+-15Hz, with phase reversals (180+-10 degrees, hopping in <1ms) every 450+-25ms.
ANSam/ is 2100+-1Hz, with phase reversals (180+-10 degrees, hopping in <1ms) every 450+-25ms, and AM with a sinewave of 15+-0.1Hz.
@ -92,6 +94,8 @@ SPAN_DECLARE(const char *) modem_connect_tone_to_str(int tone)
return "FAX preamble";
case MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE:
return "FAX CED or preamble";
case MODEM_CONNECT_TONES_CALLING_TONE:
return "Calling tone";
}
return "???";
}
@ -202,6 +206,29 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_tx(modem_connect_tones_tx_state_t *
}
s->duration_timer -= len;
break;
case MODEM_CONNECT_TONES_CALLING_TONE:
for ( ; i < len; i++)
{
if (s->duration_timer > ms_to_samples(2000))
{
if ((xlen = i + s->duration_timer - ms_to_samples(2000)) > len)
xlen = len;
s->duration_timer -= (xlen - i);
for ( ; i < xlen; i++)
amp[i] = dds_mod(&s->tone_phase, s->tone_phase_rate, s->level, 0);
}
if (s->duration_timer > 0)
{
if ((xlen = i + s->duration_timer) > len)
xlen = len;
s->duration_timer -= (xlen - i);
memset(amp + i, 0, sizeof(int16_t)*(xlen - i));
i = xlen;
}
if (s->duration_timer == 0)
s->duration_timer = ms_to_samples(600 + 2000);
}
break;
}
return len;
}
@ -274,6 +301,17 @@ SPAN_DECLARE(modem_connect_tones_tx_state_t *) modem_connect_tones_tx_init(modem
s->mod_phase = 0;
s->hop_timer = ms_to_samples(450);
break;
case MODEM_CONNECT_TONES_CALLING_TONE:
/* 0.6s of 1300Hz+-15Hz + 2.0s of silence repeating. */
s->tone_phase_rate = dds_phase_rate(1300.0);
s->level = dds_scaling_dbm0(-11);
s->duration_timer = ms_to_samples(600 + 2000);
s->mod_phase_rate = 0;
s->tone_phase = 0;
s->mod_phase = 0;
s->mod_level = 0;
s->hop_timer = 0;
break;
default:
if (alloced)
free(s);
@ -402,6 +440,8 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t *
famp = amp[i];
/* A Cauer notch at 1100Hz, spread just wide enough to meet our detection bandwidth
criteria. */
/* Poles 0.736618498*exp(+-1047/4000 * PI * j)
Zeroes exp(+-1099.5 * PI * j) */
v1 = 0.792928f*famp + 1.0018744927985f*s->znotch_1 - 0.54196833412465f*s->znotch_2;
famp = v1 - 1.2994747954630f*s->znotch_1 + s->znotch_2;
s->znotch_2 = s->znotch_1;
@ -446,6 +486,8 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t *
{
famp = amp[i];
/* A Cauer bandpass at 15Hz, with which we demodulate the AM signal. */
/* Poles 0.9983989*exp(+-15/4000 * PI * j)
Zeroes exp(0 * PI * j) */
v1 = fabs(famp) + 1.996667f*s->z15hz_1 - 0.9968004f*s->z15hz_2;
filtered = 0.001599787f*(v1 - s->z15hz_2);
s->z15hz_2 = s->z15hz_1;
@ -454,8 +496,8 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t *
//printf("%9.1f %10.4f %9d %9d\n", famp, filtered, s->am_level, s->channel_level);
/* A Cauer notch at 2100Hz, spread just wide enough to meet our detection bandwidth
criteria. */
/* This is actually centred at 2095Hz, but gets the balance we want, due
to the asymmetric walls of the notch */
/* Poles 0.7144255*exp(+-2105.612/4000 * PI * j)
Zeroes exp(+-2099.9 * PI * j) */
v1 = 0.76000f*famp - 0.1183852f*s->znotch_1 - 0.5104039f*s->znotch_2;
famp = v1 + 0.1567596f*s->znotch_1 + s->znotch_2;
s->znotch_2 = s->znotch_1;
@ -543,6 +585,44 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t *
}
}
break;
case MODEM_CONNECT_TONES_CALLING_TONE:
for (i = 0; i < len; i++)
{
famp = amp[i];
/* A Cauer notch at 1300Hz, spread just wide enough to meet our detection bandwidth
criteria. */
/* Poles 0.736618498*exp(+-1247/4000 * PI * j)
Zeroes exp(+-1299.5 * PI * j) */
v1 = 0.755582f*famp + 0.820887174515f*s->znotch_1 - 0.541968324778f*s->znotch_2;
famp = v1 - 1.0456667108f*s->znotch_1 + s->znotch_2;
s->znotch_2 = s->znotch_1;
s->znotch_1 = v1;
notched = (int16_t) lfastrintf(famp);
/* Estimate the overall energy in the channel, and the energy in
the notch (i.e. overall channel energy - tone energy => noise).
Use abs instead of multiply for speed (is it really faster?). */
s->channel_level += ((abs(amp[i]) - s->channel_level) >> 5);
s->notch_level += ((abs(notched) - s->notch_level) >> 5);
if (s->channel_level > 70 && s->notch_level*6 < s->channel_level)
{
/* There is adequate energy in the channel, and it is mostly at 1300Hz. */
if (s->tone_present != MODEM_CONNECT_TONES_CALLING_TONE)
{
if (++s->tone_cycle_duration >= ms_to_samples(415))
report_tone_state(s, MODEM_CONNECT_TONES_CALLING_TONE, lfastrintf(log10f(s->channel_level/32768.0f)*20.0f + DBM0_MAX_POWER + 0.8f));
}
}
else
{
/* If the signal looks wrong, even for a moment, we consider this the
end of the tone. */
if (s->tone_present == MODEM_CONNECT_TONES_CALLING_TONE)
report_tone_state(s, MODEM_CONNECT_TONES_NONE, -99);
s->tone_cycle_duration = 0;
}
}
break;
}
return 0;
}

View File

@ -75,7 +75,10 @@ enum
/*! \brief CED tone is the same as ANS tone. FAX preamble in a string of V.21 HDLC flag octets.
This is only valid as a tone type to receive. It is never reported as a detected tone
type. The report will either be for FAX preamble or CED/ANS tone. */
MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE = 7
MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE = 7,
/*! \brief Calling tone is a pure 1300Hz tone, in 0.6s bursts, with 2s silences in between. The
bursts repeat for as long as is required. */
MODEM_CONNECT_TONES_CALLING_TONE = 8
};
/*! \brief FAX CED tone is the same as ANS tone. */

View File

@ -26,7 +26,7 @@
#if !defined(_SPANDSP_PRIVATE_SUPER_TONE_RX_H_)
#define _SPANDSP_PRIVATE_SUPER_TONE_RX_H_
#define BINS 128
#define SUPER_TONE_BINS 128
struct super_tone_rx_segment_s
{
@ -41,7 +41,7 @@ struct super_tone_rx_descriptor_s
{
int used_frequencies;
int monitored_frequencies;
int pitches[BINS/2][2];
int pitches[SUPER_TONE_BINS/2][2];
int tones;
super_tone_rx_segment_t **tone_list;
int *tone_segs;
@ -55,7 +55,7 @@ struct super_tone_rx_state_s
int detected_tone;
int rotation;
tone_report_func_t tone_callback;
void (*segment_callback)(void *data, int f1, int f2, int duration);
tone_segment_func_t segment_callback;
void *callback_data;
super_tone_rx_segment_t segments[11];
goertzel_state_t state[];

View File

@ -209,7 +209,7 @@ struct v22bis_state_s
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_level;
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. */

View File

@ -118,6 +118,8 @@ struct v8_parms_s
{
int status;
int modem_connect_tone;
int send_ci;
int v92;
int call_function;
unsigned int modulations;
int protocol;

View File

@ -56,11 +56,11 @@
#include "spandsp/private/super_tone_rx.h"
#if defined(SPANDSP_USE_FIXED_POINT)
#define DETECTION_THRESHOLD 16439 /* -42dBm0 [((BINS*BINS*32768.0/(1.4142*128.0))*10^((-42 - DBM0_MAX_SINE_POWER)/20.0))^2] */
#define DETECTION_THRESHOLD 16439 /* -42dBm0 [((SUPER_TONE_BINS*SUPER_TONE_BINS*32768.0/(1.4142*128.0))*10^((-42 - DBM0_MAX_SINE_POWER)/20.0))^2] */
#define TONE_TWIST 4 /* 6dB */
#define TONE_TO_TOTAL_ENERGY 64 /* -3dB */
#else
#define DETECTION_THRESHOLD 2104205.6f /* -42dBm0 [((BINS*BINS*32768.0/1.4142)*10^((-42 - DBM0_MAX_SINE_POWER)/20.0))^2] */
#define DETECTION_THRESHOLD 2104205.6f /* -42dBm0 [((SUPER_TONE_BINS*SUPER_TONE_BINS*32768.0/1.4142)*10^((-42 - DBM0_MAX_SINE_POWER)/20.0))^2] */
#define TONE_TWIST 3.981f /* 6dB */
#define TONE_TO_TOTAL_ENERGY 1.995f /* 3dB */
#endif
@ -86,7 +86,7 @@ static int add_super_tone_freq(super_tone_rx_descriptor_t *desc, int freq)
/* Merge these two */
desc->pitches[desc->used_frequencies][0] = freq;
desc->pitches[desc->used_frequencies][1] = i;
make_goertzel_descriptor(&desc->desc[desc->pitches[i][1]], (float) (freq + desc->pitches[i][0])/2, BINS);
make_goertzel_descriptor(&desc->desc[desc->pitches[i][1]], (float) (freq + desc->pitches[i][0])/2, SUPER_TONE_BINS);
desc->used_frequencies++;
return desc->pitches[i][1];
}
@ -97,7 +97,7 @@ static int add_super_tone_freq(super_tone_rx_descriptor_t *desc, int freq)
{
desc->desc = (goertzel_descriptor_t *) realloc(desc->desc, (desc->monitored_frequencies + 5)*sizeof(goertzel_descriptor_t));
}
make_goertzel_descriptor(&desc->desc[desc->monitored_frequencies++], (float) freq, BINS);
make_goertzel_descriptor(&desc->desc[desc->monitored_frequencies++], (float) freq, SUPER_TONE_BINS);
desc->used_frequencies++;
return desc->pitches[i][1];
}
@ -162,9 +162,9 @@ static int test_cadence(super_tone_rx_segment_t *pattern,
j = (rotation + steps - 2)%steps;
if (pattern[j].f1 != test[8].f1 || pattern[j].f2 != test[8].f2)
return 0;
if (pattern[j].min_duration > test[8].min_duration*BINS
if (pattern[j].min_duration > test[8].min_duration*SUPER_TONE_BINS
||
pattern[j].max_duration < test[8].min_duration*BINS)
pattern[j].max_duration < test[8].min_duration*SUPER_TONE_BINS)
{
return 0;
}
@ -172,7 +172,7 @@ static int test_cadence(super_tone_rx_segment_t *pattern,
j = (rotation + steps - 1)%steps;
if (pattern[j].f1 != test[9].f1 || pattern[j].f2 != test[9].f2)
return 0;
if (pattern[j].max_duration < test[9].min_duration*BINS)
if (pattern[j].max_duration < test[9].min_duration*SUPER_TONE_BINS)
return 0;
}
else
@ -183,9 +183,9 @@ static int test_cadence(super_tone_rx_segment_t *pattern,
j = i + 10 - steps;
if (pattern[i].f1 != test[j].f1 || pattern[i].f2 != test[j].f2)
return 0;
if (pattern[i].min_duration > test[j].min_duration*BINS
if (pattern[i].min_duration > test[j].min_duration*SUPER_TONE_BINS
||
pattern[i].max_duration < test[j].min_duration*BINS)
pattern[i].max_duration < test[j].min_duration*SUPER_TONE_BINS)
{
return 0;
}
@ -313,9 +313,9 @@ static void super_tone_chunk(super_tone_rx_state_t *s)
int k1;
int k2;
#if defined(SPANDSP_USE_FIXED_POINT)
int32_t res[BINS/2];
int32_t res[SUPER_TONE_BINS/2];
#else
float res[BINS/2];
float res[SUPER_TONE_BINS/2];
#endif
for (i = 0; i < s->desc->monitored_frequencies; i++)
@ -397,7 +397,7 @@ static void super_tone_chunk(super_tone_rx_state_t *s)
s->segment_callback(s->callback_data,
s->segments[9].f1,
s->segments[9].f2,
s->segments[9].min_duration*BINS/8);
s->segments[9].min_duration*SUPER_TONE_BINS/8);
}
memcpy (&s->segments[0], &s->segments[1], 9*sizeof(s->segments[0]));
s->segments[9].f1 = k1;
@ -467,7 +467,7 @@ SPAN_DECLARE(int) super_tone_rx(super_tone_rx_state_t *s, const int16_t amp[], i
s->energy += xamp*xamp;
#endif
}
if (s->state[0].current_sample >= BINS)
if (s->state[0].current_sample >= SUPER_TONE_BINS)
{
/* We have finished a Goertzel block. */
super_tone_chunk(s);

View File

@ -440,9 +440,9 @@ static int set_next_tx_type(t38_gateway_state_t *s)
/* There is a handler queued, so that is the next one. */
set_tx_handler(s, t->next_tx_handler, t->next_tx_user_data);
set_next_tx_handler(s, NULL, NULL);
if (t->tx_handler == (span_tx_handler_t) &(silence_gen)
if (t->tx_handler == (span_tx_handler_t) &silence_gen
||
t->tx_handler == (span_tx_handler_t) &(tone_gen))
t->tx_handler == (span_tx_handler_t) &tone_gen)
{
set_rx_active(s, TRUE);
}

View File

@ -111,7 +111,7 @@ static const struct dtmf_to_ascii_s dtmf_to_ascii[] =
{"##8", 'W'},
{"##9", 'Z'},
{"##0", ' '},
#if defined(WIN32) || ( defined(__SVR4) && defined (__sun))
#if defined(WIN32) || (defined(__SVR4) && defined (__sun))
{"#*1", 'X'}, // (Note 1) 111 1011
{"#*2", 'X'}, // (Note 1) 111 1100
{"#*3", 'X'}, // (Note 1) 111 1101

View File

@ -52,6 +52,9 @@
#include "spandsp/telephony.h"
#include "spandsp/logging.h"
#include "spandsp/fast_convert.h"
#include "spandsp/math_fixed.h"
#include "spandsp/saturated.h"
#include "spandsp/complex.h"
#include "spandsp/vector_float.h"
#include "spandsp/complex_vector_float.h"
@ -77,12 +80,12 @@
#include "v22bis_rx_2400_floating_rrc.h"
#endif
#define ms_to_symbols(t) (((t)*600)/1000)
#define ms_to_symbols(t) (((t)*600)/1000)
/*! The adaption rate coefficient for the equalizer */
#define EQUALIZER_DELTA 0.25f
#define EQUALIZER_DELTA 0.25f
/*! The number of phase shifted coefficient set for the pulse shaping/bandpass filter */
#define PULSESHAPER_COEFF_SETS 12
#define PULSESHAPER_COEFF_SETS 12
/*
The basic method used by the V.22bis receiver is:

View File

@ -310,8 +310,8 @@ static __inline__ int get_scrambled_bit(v22bis_state_t *s)
static complexf_t training_get(v22bis_state_t *s)
{
complexf_t z;
int bits;
static const complexf_t zero = {0.0f, 0.0f};
/* V.22bis training sequence */
switch (s->tx.training)
@ -329,20 +329,17 @@ static complexf_t training_get(v22bis_state_t *s)
case V22BIS_TX_TRAINING_STAGE_INITIAL_SILENCE:
/* Silence */
s->tx.constellation_state = 0;
z = complex_setf(0.0f, 0.0f);
break;
return zero;
case V22BIS_TX_TRAINING_STAGE_U11:
/* Send continuous unscrambled ones at 1200bps (i.e. 270 degree phase steps). */
/* Only the answering modem sends unscrambled ones. It is the first thing exchanged between the modems. */
s->tx.constellation_state = (s->tx.constellation_state + phase_steps[3]) & 3;
z = v22bis_constellation[(s->tx.constellation_state << 2) | 0x01];
break;
return v22bis_constellation[(s->tx.constellation_state << 2) | 0x01];
case V22BIS_TX_TRAINING_STAGE_U0011:
/* Continuous unscrambled double dibit 00 11 at 1200bps. This is termed the S1 segment in
the V.22bis spec. It is only sent to request or accept 2400bps mode, and lasts 100+-3ms. After this
timed burst, we unconditionally change to sending scrambled ones at 1200bps. */
s->tx.constellation_state = (s->tx.constellation_state + phase_steps[3*(s->tx.training_count & 1)]) & 3;
z = v22bis_constellation[(s->tx.constellation_state << 2) | 0x01];
if (++s->tx.training_count >= ms_to_symbols(100))
{
span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting S11 after U0011\n");
@ -357,7 +354,7 @@ static complexf_t training_get(v22bis_state_t *s)
s->tx.training = V22BIS_TX_TRAINING_STAGE_TIMED_S11;
}
}
break;
return v22bis_constellation[(s->tx.constellation_state << 2) | 0x01];
case V22BIS_TX_TRAINING_STAGE_TIMED_S11:
/* A timed period of scrambled ones at 1200bps. */
if (++s->tx.training_count >= ms_to_symbols(756))
@ -383,8 +380,7 @@ static complexf_t training_get(v22bis_state_t *s)
bits = scramble(s, 1);
bits = (bits << 1) | scramble(s, 1);
s->tx.constellation_state = (s->tx.constellation_state + phase_steps[bits]) & 3;
z = v22bis_constellation[(s->tx.constellation_state << 2) | 0x01];
break;
return v22bis_constellation[(s->tx.constellation_state << 2) | 0x01];
case V22BIS_TX_TRAINING_STAGE_S1111:
/* Scrambled ones at 2400bps. We send a timed 200ms burst, and switch to normal operation at 2400bps */
bits = scramble(s, 1);
@ -392,7 +388,6 @@ static complexf_t training_get(v22bis_state_t *s)
s->tx.constellation_state = (s->tx.constellation_state + phase_steps[bits]) & 3;
bits = scramble(s, 1);
bits = (bits << 1) | scramble(s, 1);
z = v22bis_constellation[(s->tx.constellation_state << 2) | bits];
if (++s->tx.training_count >= ms_to_symbols(200))
{
/* We have completed training. Now handle some real work. */
@ -402,13 +397,9 @@ static complexf_t training_get(v22bis_state_t *s)
v22bis_report_status_change(s, SIG_STATUS_TRAINING_SUCCEEDED);
s->tx.current_get_bit = s->get_bit;
}
break;
case V22BIS_TX_TRAINING_STAGE_PARKED:
default:
z = complex_setf(0.0f, 0.0f);
break;
return v22bis_constellation[(s->tx.constellation_state << 2) | bits];
}
return z;
return zero;
}
/*- End of function --------------------------------------------------------*/
@ -476,12 +467,12 @@ SPAN_DECLARE_NONSTD(int) v22bis_tx(v22bis_state_t *s, int16_t amp[], int len)
x.im += tx_pulseshaper[39 - s->tx.baud_phase][i]*s->tx.rrc_filter[i + s->tx.rrc_filter_step].im;
}
/* Now create and modulate the carrier */
z = dds_complexf(&(s->tx.carrier_phase), s->tx.carrier_phase_rate);
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))
{
/* Add the guard tone */
famp += dds_modf(&(s->tx.guard_phase), s->tx.guard_phase_rate, s->tx.guard_level, 0);
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);
@ -499,20 +490,20 @@ SPAN_DECLARE(void) v22bis_tx_power(v22bis_state_t *s, float power)
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_level = l*32768.0f;
s->tx.guard_tone_gain = l*32768.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_level = l*32768.0f;
s->tx.guard_tone_gain = l*32768.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_level = 0;
s->tx.guard_tone_gain = 0;
}
}
/*- End of function --------------------------------------------------------*/

View File

@ -63,7 +63,8 @@
enum
{
V8_WAIT_1S,
V8_WAIT_1S, /* Start point when sending CI */
V8_AWAIT_ANSAM, /* Start point when sending initial silence */
V8_CI_ON,
V8_CI_OFF,
V8_HEARD_ANSAM,
@ -100,7 +101,8 @@ enum
enum
{
V8_CI_SYNC_OCTET = 0x00,
V8_CM_JM_SYNC_OCTET = 0xE0
V8_CM_JM_SYNC_OCTET = 0xE0,
V8_V92_SYNC_OCTET = 0x55
};
SPAN_DECLARE(const char *) v8_call_function_to_str(int call_function)
@ -755,7 +757,24 @@ SPAN_DECLARE_NONSTD(int) v8_tx(v8_state_t *s, int16_t *amp, int max_len)
}
/*- End of function --------------------------------------------------------*/
static void v8_send_ci(v8_state_t *s)
static void send_v92(v8_state_t *s)
{
int i;
if (s->result.v92 >= 0)
{
/* Send 2 V.92 packets */
for (i = 0; i < 2; i++)
{
v8_put_preamble(s);
v8_put_byte(s, V8_V92_SYNC_OCTET);
v8_put_byte(s, s->result.v92);
}
}
}
/*- End of function --------------------------------------------------------*/
static void send_ci(v8_state_t *s)
{
int i;
@ -810,7 +829,7 @@ SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
if ((s->negotiation_timer -= len) > 0)
break;
fsk_tx_restart(&s->v21tx, &preset_fsk_specs[FSK_V21CH1]);
v8_send_ci(s);
send_ci(s);
s->state = V8_CI_ON;
s->fsk_tx_on = TRUE;
break;
@ -851,12 +870,18 @@ SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
{
/* Try again */
fsk_tx_restart(&s->v21tx, &preset_fsk_specs[FSK_V21CH1]);
v8_send_ci(s);
send_ci(s);
s->state = V8_CI_ON;
s->fsk_tx_on = TRUE;
}
}
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);
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. */
@ -865,6 +890,7 @@ SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
v8_decode_init(s);
s->negotiation_timer = ms_to_samples(5000);
fsk_tx_restart(&s->v21tx, &preset_fsk_specs[FSK_V21CH1]);
send_v92(s);
send_cm_jm(s);
s->state = V8_CM_ON;
s->fsk_tx_on = TRUE;
@ -1015,9 +1041,16 @@ SPAN_DECLARE(int) v8_restart(v8_state_t *s, int calling_party, v8_parms_t *parms
s->calling_party = calling_party;
if (s->calling_party)
{
s->state = V8_WAIT_1S;
s->negotiation_timer = ms_to_samples(1000);
s->ci_count = 0;
if (s->result.send_ci)
{
s->state = V8_WAIT_1S;
s->negotiation_timer = ms_to_samples(1000);
s->ci_count = 0;
}
else
{
s->state = V8_AWAIT_ANSAM;
}
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);
}

View File

@ -107,8 +107,8 @@ SPAN_DECLARE(void) vec_copyl(long double z[], const long double x[], int n)
SPAN_DECLARE(void) vec_negatef(float z[], const float x[], int n)
{
int i;
static const uint32_t mask = 0x80000000;
static const float *fmask = (float *) &mask;
static const uint32_t mask = 0x80000000;
static const float *fmask = (float *) &mask;
__m128 n1;
__m128 n2;
@ -118,7 +118,7 @@ SPAN_DECLARE(void) vec_negatef(float z[], const float x[], int n)
for (i -= 4; i >= 0; i -= 4)
{
n1 = _mm_loadu_ps(x + i);
n1 = _mm_xor_ps(n1, n2);
n1 = _mm_xor_ps(n1, n2);
_mm_storeu_ps(z + i, n1);
}
}

View File

@ -37,7 +37,7 @@
typedef struct faxtester_state_s faxtester_state_t;
typedef void (faxtester_flush_handler_t)(faxtester_state_t *s, void *user_data, int which);
typedef void (*faxtester_flush_handler_t)(faxtester_state_t *s, void *user_data, int which);
/*!
FAX tester real time frame handler.
@ -48,13 +48,13 @@ typedef void (faxtester_flush_handler_t)(faxtester_state_t *s, void *user_data,
\param msg The HDLC message.
\param len The length of the message.
*/
typedef void (faxtester_real_time_frame_handler_t)(faxtester_state_t *s,
void *user_data,
int direction,
const uint8_t *msg,
int len);
typedef void (*faxtester_real_time_frame_handler_t)(faxtester_state_t *s,
void *user_data,
int direction,
const uint8_t *msg,
int len);
typedef void (faxtester_front_end_step_complete_handler_t)(faxtester_state_t *s, void *user_data);
typedef void (*faxtester_front_end_step_complete_handler_t)(faxtester_state_t *s, void *user_data);
/*!
FAX tester descriptor.
@ -64,19 +64,19 @@ struct faxtester_state_s
/*! \brief Pointer to our current step in the test. */
xmlNodePtr cur;
faxtester_flush_handler_t *flush_handler;
faxtester_flush_handler_t flush_handler;
void *flush_user_data;
/*! \brief A pointer to a callback routine to be called when frames are
exchanged. */
faxtester_real_time_frame_handler_t *real_time_frame_handler;
faxtester_real_time_frame_handler_t real_time_frame_handler;
/*! \brief An opaque pointer supplied in real time frame callbacks. */
void *real_time_frame_user_data;
faxtester_front_end_step_complete_handler_t *front_end_step_complete_handler;
faxtester_front_end_step_complete_handler_t front_end_step_complete_handler;
void *front_end_step_complete_user_data;
faxtester_front_end_step_complete_handler_t *front_end_step_timeout_handler;
faxtester_front_end_step_complete_handler_t front_end_step_timeout_handler;
void *front_end_step_timeout_user_data;
const uint8_t *image_buffer;
@ -149,7 +149,7 @@ void faxtester_send_hdlc_flags(faxtester_state_t *s, int flags);
void faxtester_send_hdlc_msg(faxtester_state_t *s, const uint8_t *msg, int len, int crc_ok);
void faxtester_set_flush_handler(faxtester_state_t *s, faxtester_flush_handler_t *handler, void *user_data);
void faxtester_set_flush_handler(faxtester_state_t *s, faxtester_flush_handler_t handler, void *user_data);
/*! Select whether silent audio will be sent when FAX transmit is idle.
\brief Select whether silent audio will be sent when FAX transmit is idle.
@ -167,11 +167,11 @@ void faxtester_set_transmit_on_idle(faxtester_state_t *s, int transmit_on_idle);
*/
void faxtester_set_tep_mode(faxtester_state_t *s, int use_tep);
void faxtester_set_real_time_frame_handler(faxtester_state_t *s, faxtester_real_time_frame_handler_t *handler, void *user_data);
void faxtester_set_real_time_frame_handler(faxtester_state_t *s, faxtester_real_time_frame_handler_t handler, void *user_data);
void faxtester_set_front_end_step_complete_handler(faxtester_state_t *s, faxtester_front_end_step_complete_handler_t *handler, void *user_data);
void faxtester_set_front_end_step_complete_handler(faxtester_state_t *s, faxtester_front_end_step_complete_handler_t handler, void *user_data);
void faxtester_set_front_end_step_timeout_handler(faxtester_state_t *s, faxtester_front_end_step_complete_handler_t *handler, void *user_data);
void faxtester_set_front_end_step_timeout_handler(faxtester_state_t *s, faxtester_front_end_step_complete_handler_t handler, void *user_data);
void faxtester_set_timeout(faxtester_state_t *s, int timeout);

View File

@ -31,7 +31,7 @@
#define UDPTL_BUF_MASK 15
typedef int (udptl_rx_packet_handler_t) (void *user_data, const uint8_t msg[], int len, int seq_no);
typedef int (*udptl_rx_packet_handler_t) (void *user_data, const uint8_t msg[], int len, int seq_no);
typedef struct
{
@ -51,7 +51,7 @@ typedef struct
struct udptl_state_s
{
udptl_rx_packet_handler_t *rx_packet_handler;
udptl_rx_packet_handler_t rx_packet_handler;
void *user_data;
/*! This option indicates the error correction scheme used in transmitted UDPTL