update to spandsp-20091222 snapshot

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@16035 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Michael Jerris
2009-12-23 01:38:36 +00:00
parent 8d517cfbc5
commit 8c06fb8b06
74 changed files with 19428 additions and 1193 deletions
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: line_model.h,v 1.7 2009/09/23 16:02:59 steveu Exp $
* $Id: line_model.h,v 1.7.4.1 2009/12/19 10:16:44 steveu Exp $
*/
/*! \file */
@@ -70,7 +70,7 @@ typedef struct
codec_munge_state_t *munge;
/*! The coefficients for the near end analogue section simulation filter */
float *near_filter;
const float *near_filter;
/*! The number of coefficients for the near end analogue section simulation filter */
int near_filter_len;
/*! Last transmitted samples (ring buffer, used by the line filter) */
@@ -88,7 +88,7 @@ typedef struct
int16_t bulk_delay_buf[8000];
/*! The coefficients for the far end analogue section simulation filter */
float *far_filter;
const float *far_filter;
/*! The number of coefficients for the far end analogue section simulation filter */
int far_filter_len;
/*! Last transmitted samples (ring buffer, used by the line filter) */
+40 -12
View File
@@ -16,13 +16,37 @@
## License along with this program; if not, write to the Free Software
## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
##
## $Id: Makefile.am,v 1.137 2009/09/22 14:52:31 steveu Exp $
## $Id: Makefile.am,v 1.138.4.3 2009/12/19 10:30:10 steveu Exp $
AM_CFLAGS = $(COMP_VENDOR_CFLAGS)
AM_LDFLAGS = $(COMP_VENDOR_LDFLAGS)
MAINTAINERCLEANFILES = Makefile.in
DISTCLEANFILES = $(srcdir)/at_interpreter_dictionary.h \
$(srcdir)/v17_v32bis_rx_fixed_rrc.h \
$(srcdir)/v17_v32bis_rx_floating_rrc.h \
$(srcdir)/v17_v32bis_tx_fixed_rrc.h \
$(srcdir)/v17_v32bis_tx_floating_rrc.h \
$(srcdir)/v22bis_rx_1200_fixed_rrc.h \
$(srcdir)/v22bis_rx_2400_fixed_rrc.h \
$(srcdir)/v22bis_rx_1200_floating_rrc.h \
$(srcdir)/v22bis_rx_2400_floating_rrc.h \
$(srcdir)/v22bis_tx_fixed_rrc.h \
$(srcdir)/v22bis_tx_floating_rrc.h \
$(srcdir)/v27ter_rx_2400_fixed_rrc.h \
$(srcdir)/v27ter_rx_4800_fixed_rrc.h \
$(srcdir)/v27ter_rx_2400_floating_rrc.h \
$(srcdir)/v27ter_rx_4800_floating_rrc.h \
$(srcdir)/v27ter_tx_2400_fixed_rrc.h \
$(srcdir)/v27ter_tx_4800_fixed_rrc.h \
$(srcdir)/v27ter_tx_2400_floating_rrc.h \
$(srcdir)/v27ter_tx_4800_floating_rrc.h \
$(srcdir)/v29rx_fixed_rrc.h \
$(srcdir)/v29rx_floating_rrc.h \
$(srcdir)/v29tx_fixed_rrc.h \
$(srcdir)/v29tx_floating_rrc.h
EXTRA_DIST = floating_fudge.h \
libspandsp.dsp \
libspandsp.2005.sln \
@@ -31,6 +55,9 @@ EXTRA_DIST = floating_fudge.h \
libspandsp.2008.vcproj \
libtiff.2005.vcproj \
libtiff.2008.vcproj \
filter_tools.c \
make_at_dictionary.c \
make_modem_filter.c \
msvc/config.h \
msvc/Download_TIFF.2005.vcproj \
msvc/Download_TIFF.2008.vcproj \
@@ -111,7 +138,8 @@ libspandsp_la_SOURCES = adsi.c \
super_tone_rx.c \
super_tone_tx.c \
swept_tone.c \
t4.c \
t4_rx.c \
t4_tx.c \
t30.c \
t30_api.c \
t30_logging.c \
@@ -190,7 +218,8 @@ nobase_include_HEADERS = spandsp/adsi.h \
spandsp/super_tone_rx.h \
spandsp/super_tone_tx.h \
spandsp/swept_tone.h \
spandsp/t4.h \
spandsp/t4_rx.h \
spandsp/t4_tx.h \
spandsp/t30.h \
spandsp/t30_api.h \
spandsp/t30_fcf.h \
@@ -252,12 +281,14 @@ nobase_include_HEADERS = spandsp/adsi.h \
spandsp/private/super_tone_tx.h \
spandsp/private/swept_tone.h \
spandsp/private/t30.h \
spandsp/private/t30_dis_dtc_dcs_bits.h \
spandsp/private/t31.h \
spandsp/private/t38_core.h \
spandsp/private/t38_gateway.h \
spandsp/private/t38_non_ecm_buffer.h \
spandsp/private/t38_terminal.h \
spandsp/private/t4.h \
spandsp/private/t4_rx.h \
spandsp/private/t4_tx.h \
spandsp/private/time_scale.h \
spandsp/private/tone_detect.h \
spandsp/private/tone_generate.h \
@@ -282,7 +313,7 @@ noinst_HEADERS = faxfont.h \
lpc10_encdecs.h \
mmx_sse_decs.h \
t30_local.h \
t4_states.h \
t4_t6_decode_states.h \
v17_v32bis_rx_constellation_maps.h \
v17_v32bis_tx_constellation_maps.h \
v29tx_constellation_maps.h
@@ -290,7 +321,7 @@ noinst_HEADERS = faxfont.h \
make_at_dictionary$(EXEEXT): $(top_srcdir)/src/make_at_dictionary.c
$(CC_FOR_BUILD) -o make_at_dictionary$(EXEEXT) $(top_srcdir)/src/make_at_dictionary.c -DHAVE_CONFIG_H -I$(top_builddir)/src
make_modem_filter$(EXEEXT): $(top_srcdir)/src/make_modem_filter.c $(top_srcdir)/src/filter_tools.c
make_modem_filter$(EXEEXT): $(top_srcdir)/src/make_modem_filter.c $(top_srcdir)/src/filter_tools.c
$(CC_FOR_BUILD) -o make_modem_filter$(EXEEXT) $(top_srcdir)/src/make_modem_filter.c $(top_srcdir)/src/filter_tools.c -DHAVE_CONFIG_H -I$(top_builddir)/src -lm
# We need to run make_at_dictionary, so it generates the
@@ -489,13 +520,10 @@ $(srcdir)/msvc/spandsp.h: spandsp.h.in
-e "s/\@INSERT_MATH_HEADER\@/#include <math.h>/" $(srcdir)/spandsp.h.in > $(srcdir)/msvc/spandsp.h
spandsp/version.h:
mkdir -p $(@D)
NOWDATE=`date --utc +"%Y%m%d"` ; \
NOWTIME=`date --utc +"%H%M%S"` ; \
sed 's/$$SPANDSP_RELEASE_DATE/'$$NOWDATE'/;s/$$SPANDSP_RELEASE_TIME/'$$NOWTIME'/' \
<spandsp/version.h.in >spandsp/version.h
<$(srcdir)/spandsp/version.h.in >$@
dist-hook:
NOWDATE=`date --utc +"%Y%m%d"` ; \
NOWTIME=`date --utc +"%H%M%S"` ; \
sed 's/$$SPANDSP_RELEASE_DATE/'$$NOWDATE'/;s/$$SPANDSP_RELEASE_TIME/'$$NOWTIME'/' \
<spandsp/version.h.in >spandsp/version.h
dist-hook: spandsp/version.h
+4 -4
View File
@@ -23,7 +23,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: adsi.c,v 1.76 2009/04/12 09:12:10 steveu Exp $
* $Id: adsi.c,v 1.77 2009/11/02 13:25:20 steveu Exp $
*/
/*! \file */
@@ -431,12 +431,12 @@ SPAN_DECLARE(adsi_rx_state_t *) adsi_rx_init(adsi_rx_state_t *s,
switch (standard)
{
case ADSI_STANDARD_CLASS:
fsk_rx_init(&(s->fskrx), &preset_fsk_specs[FSK_BELL202], FALSE, adsi_rx_put_bit, s);
fsk_rx_init(&(s->fskrx), &preset_fsk_specs[FSK_BELL202], FSK_FRAME_MODE_ASYNC, adsi_rx_put_bit, s);
break;
case ADSI_STANDARD_CLIP:
case ADSI_STANDARD_ACLIP:
case ADSI_STANDARD_JCLIP:
fsk_rx_init(&(s->fskrx), &preset_fsk_specs[FSK_V23CH1], FALSE, adsi_rx_put_bit, s);
fsk_rx_init(&(s->fskrx), &preset_fsk_specs[FSK_V23CH1], FSK_FRAME_MODE_ASYNC, adsi_rx_put_bit, s);
break;
case ADSI_STANDARD_CLIP_DTMF:
dtmf_rx_init(&(s->dtmfrx), adsi_rx_dtmf, s);
@@ -444,7 +444,7 @@ SPAN_DECLARE(adsi_rx_state_t *) adsi_rx_init(adsi_rx_state_t *s,
case ADSI_STANDARD_TDD:
/* TDD uses 5 bit data, no parity and 1.5 stop bits. We scan for the first stop bit, and
ride over the fraction. */
fsk_rx_init(&(s->fskrx), &preset_fsk_specs[FSK_WEITBRECHT], 7, adsi_tdd_put_async_byte, s);
fsk_rx_init(&(s->fskrx), &preset_fsk_specs[FSK_WEITBRECHT], FSK_FRAME_MODE_5N1_FRAMES, adsi_tdd_put_async_byte, s);
break;
}
s->standard = standard;
+23 -2
View File
@@ -25,7 +25,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: at_interpreter.c,v 1.41 2009/10/03 04:37:25 steveu Exp $
* $Id: at_interpreter.c,v 1.42 2009/10/09 14:53:56 steveu Exp $
*/
/*! \file */
@@ -3358,9 +3358,30 @@ static const char *at_cmd_plus_EWIND(at_state_t *s, const char *t)
}
/*- End of function --------------------------------------------------------*/
static const char *at_cmd_plus_F34(at_state_t *s, const char *t)
{
static const int maxes[5] =
{
14, 14, 2, 14, 14
};
int *locations[5];
int i;
/* T.31 B.6.1 - Initial V.34 rate controls for FAX */
/* Syntax: +F34=[<maxp>][,[<minp>][,<prefc>][,<maxp2>][,<minp2]] */
/* TODO */
t += 4;
for (i = 0; i < 5; i++)
locations[i] = NULL;
if (!parse_n_out(s, &t, locations, maxes, 5, "+F34:", "(0-14),(0-14),(0-2),(0-14),(0-14)"))
return NULL;
return t;
}
/*- End of function --------------------------------------------------------*/
static const char *at_cmd_plus_FAA(at_state_t *s, const char *t)
{
/* T.32 8.5.2.5 - Adaptive Answer parameter */
/* T.32 8.5.2.5 - Adaptive answer parameter */
/* TODO */
t += 4;
return t;
+8 -6
View File
@@ -23,7 +23,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: fax.c,v 1.94 2009/09/04 14:38:46 steveu Exp $
* $Id: fax.c,v 1.96.4.1 2009/12/19 10:44:10 steveu Exp $
*/
/*! \file */
@@ -71,7 +71,8 @@
#include "spandsp/v17rx.h"
#include "spandsp/super_tone_rx.h"
#include "spandsp/modem_connect_tones.h"
#include "spandsp/t4.h"
#include "spandsp/t4_rx.h"
#include "spandsp/t4_tx.h"
#include "spandsp/t30_fcf.h"
#include "spandsp/t35.h"
@@ -94,7 +95,8 @@
#include "spandsp/private/modem_connect_tones.h"
#include "spandsp/private/hdlc.h"
#include "spandsp/private/fax_modems.h"
#include "spandsp/private/t4.h"
#include "spandsp/private/t4_rx.h"
#include "spandsp/private/t4_tx.h"
#include "spandsp/private/t30.h"
#include "spandsp/private/fax.h"
@@ -110,12 +112,12 @@ static void fax_send_hdlc(void *user_data, const uint8_t *msg, int len)
}
/*- End of function --------------------------------------------------------*/
static void tone_detected(void *user_data, int on, int level, int delay)
static void tone_detected(void *user_data, int tone, int level, int delay)
{
t30_state_t *s;
s = (t30_state_t *) user_data;
span_log(&s->logging, SPAN_LOG_FLOW, "FAX tone declared %s (%ddBm0)\n", (on) ? "on" : "off", level);
span_log(&s->logging, SPAN_LOG_FLOW, "%s detected (%ddBm0)\n", modem_connect_tone_to_str(tone), level);
}
/*- End of function --------------------------------------------------------*/
@@ -423,7 +425,7 @@ static void fax_set_rx_type(void *user_data, int type, int bit_rate, int short_t
switch (type)
{
case T30_MODEM_V21:
fsk_rx_init(&t->v21_rx, &preset_fsk_specs[FSK_V21CH2], TRUE, (put_bit_func_t) hdlc_rx_put_bit, put_bit_user_data);
fsk_rx_init(&t->v21_rx, &preset_fsk_specs[FSK_V21CH2], FSK_FRAME_MODE_SYNC, (put_bit_func_t) hdlc_rx_put_bit, put_bit_user_data);
fsk_rx_signal_cutoff(&t->v21_rx, -45.5f);
set_rx_handler(s, (span_rx_handler_t *) &fsk_rx, (span_rx_fillin_handler_t *) &fsk_rx_fillin, &t->v21_rx);
break;
+5 -2
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: fax_modems.c,v 1.7 2009/10/05 16:33:25 steveu Exp $
* $Id: fax_modems.c,v 1.8 2009/11/02 13:25:20 steveu Exp $
*/
/*! \file */
@@ -45,6 +45,9 @@
#include <assert.h>
#include <fcntl.h>
#include <time.h>
#if defined(LOG_FAX_AUDIO)
#include <unistd.h>
#endif
#include "spandsp/telephony.h"
#include "spandsp/logging.h"
@@ -280,7 +283,7 @@ SPAN_DECLARE(fax_modems_state_t *) fax_modems_init(fax_modems_state_t *s,
hdlc_rx_init(&s->hdlc_rx, FALSE, FALSE, HDLC_FRAMING_OK_THRESHOLD, hdlc_accept, user_data);
hdlc_tx_init(&s->hdlc_tx, FALSE, 2, FALSE, hdlc_tx_underflow, user_data);
fsk_rx_init(&s->v21_rx, &preset_fsk_specs[FSK_V21CH2], TRUE, (put_bit_func_t) hdlc_rx_put_bit, &s->hdlc_rx);
fsk_rx_init(&s->v21_rx, &preset_fsk_specs[FSK_V21CH2], FSK_FRAME_MODE_SYNC, (put_bit_func_t) hdlc_rx_put_bit, &s->hdlc_rx);
fsk_rx_signal_cutoff(&s->v21_rx, -39.09f);
fsk_tx_init(&s->v21_tx, &preset_fsk_specs[FSK_V21CH2], (get_bit_func_t) hdlc_tx_get_bit, &s->hdlc_tx);
v17_rx_init(&s->v17_rx, 14400, non_ecm_put_bit, user_data);
+42 -28
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: fsk.c,v 1.59 2009/06/02 16:03:56 steveu Exp $
* $Id: fsk.c,v 1.60 2009/11/02 13:25:20 steveu Exp $
*/
/*! \file */
@@ -128,6 +128,22 @@ const fsk_spec_t preset_fsk_specs[] =
}
};
SPAN_DECLARE(int) fsk_tx_restart(fsk_tx_state_t *s, const fsk_spec_t *spec)
{
s->baud_rate = spec->baud_rate;
s->phase_rates[0] = dds_phase_rate((float) spec->freq_zero);
s->phase_rates[1] = dds_phase_rate((float) spec->freq_one);
s->scaling = dds_scaling_dbm0((float) spec->tx_level);
/* Initialise fractional sample baud generation. */
s->phase_acc = 0;
s->baud_frac = 0;
s->current_phase_rate = s->phase_rates[1];
s->shutdown = FALSE;
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(fsk_tx_state_t *) fsk_tx_init(fsk_tx_state_t *s,
const fsk_spec_t *spec,
get_bit_func_t get_bit,
@@ -138,20 +154,11 @@ SPAN_DECLARE(fsk_tx_state_t *) fsk_tx_init(fsk_tx_state_t *s,
if ((s = (fsk_tx_state_t *) malloc(sizeof(*s))) == NULL)
return NULL;
}
memset(s, 0, sizeof(*s));
s->baud_rate = spec->baud_rate;
s->get_bit = get_bit;
s->get_bit_user_data = user_data;
s->phase_rates[0] = dds_phase_rate((float) spec->freq_zero);
s->phase_rates[1] = dds_phase_rate((float) spec->freq_one);
s->scaling = dds_scaling_dbm0((float) spec->tx_level);
/* Initialise fractional sample baud generation. */
s->phase_acc = 0;
s->baud_frac = 0;
s->current_phase_rate = s->phase_rates[1];
s->shutdown = FALSE;
fsk_tx_restart(s, spec);
return s;
}
/*- End of function --------------------------------------------------------*/
@@ -250,26 +257,13 @@ SPAN_DECLARE(void) fsk_rx_set_modem_status_handler(fsk_rx_state_t *s, modem_tx_s
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(fsk_rx_state_t *) fsk_rx_init(fsk_rx_state_t *s,
const fsk_spec_t *spec,
int framing_mode,
put_bit_func_t put_bit,
void *user_data)
SPAN_DECLARE(int) fsk_rx_restart(fsk_rx_state_t *s, const fsk_spec_t *spec, int framing_mode)
{
int chop;
if (s == NULL)
{
if ((s = (fsk_rx_state_t *) malloc(sizeof(*s))) == NULL)
return NULL;
}
memset(s, 0, sizeof(*s));
s->baud_rate = spec->baud_rate;
s->framing_mode = framing_mode;
fsk_rx_signal_cutoff(s, (float) spec->min_level);
s->put_bit = put_bit;
s->put_bit_user_data = user_data;
/* Detect by correlating against the tones we want, over a period
of one baud. The correlation must be quadrature. */
@@ -307,6 +301,26 @@ SPAN_DECLARE(fsk_rx_state_t *) fsk_rx_init(fsk_rx_state_t *s,
/* Initialise a power detector, so sense when a signal is present. */
power_meter_init(&(s->power), 4);
s->signal_present = 0;
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(fsk_rx_state_t *) fsk_rx_init(fsk_rx_state_t *s,
const fsk_spec_t *spec,
int framing_mode,
put_bit_func_t put_bit,
void *user_data)
{
if (s == NULL)
{
if ((s = (fsk_rx_state_t *) malloc(sizeof(*s))) == NULL)
return NULL;
}
memset(s, 0, sizeof(*s));
s->put_bit = put_bit;
s->put_bit_user_data = user_data;
fsk_rx_restart(s, spec, framing_mode);
return s;
}
/*- End of function --------------------------------------------------------*/
@@ -421,7 +435,7 @@ SPAN_DECLARE_NONSTD(int) fsk_rx(fsk_rx_state_t *s, const int16_t *amp, int len)
baudstate = (sum[0] < sum[1]);
switch (s->framing_mode)
{
case 1:
case FSK_FRAME_MODE_SYNC:
/* Synchronous serial operation - e.g. for HDLC */
if (s->last_bit != baudstate)
{
@@ -442,7 +456,7 @@ SPAN_DECLARE_NONSTD(int) fsk_rx(fsk_rx_state_t *s, const int16_t *amp, int len)
s->put_bit(s->put_bit_user_data, baudstate);
}
break;
case 0:
case FSK_FRAME_MODE_ASYNC:
/* Fully asynchronous mode */
if (s->last_bit != baudstate)
{
+3 -3
View File
@@ -25,7 +25,7 @@
* This code is based on the widely used GSM 06.10 code available from
* http://kbs.cs.tu-berlin.de/~jutta/toast.html
*
* $Id: gsm0610_rpe.c,v 1.25 2009/02/03 16:28:39 steveu Exp $
* $Id: gsm0610_rpe.c,v 1.25.4.1 2009/12/19 09:47:56 steveu Exp $
*/
/*! \file */
@@ -87,13 +87,13 @@ static void weighting_filter(const int16_t *e, // signal [-5..0.39.44] IN
" emms;\n"
" addl $-10,%%ecx;\n"
" movl $0x1000,%%eax;\n"
" movd %%eax,%%mm5;\n" /* for rounding */
" movd %%eax,%%mm5;\n" /* For rounding */
" movq %[gsm_H],%%mm1;\n"
" movq %[gsm_H8],%%mm2;\n"
" movq %[gsm_H16],%%mm3;\n"
" xorl %%esi,%%esi;\n"
" .p2align 2;\n"
"1:;\n"
"1:\n"
" movq (%%ecx,%%esi,2),%%mm0;\n"
" pmaddwd %%mm1,%%mm0;\n"
+7 -3
View File
@@ -143,7 +143,8 @@
<File RelativePath="super_tone_rx.c"></File>
<File RelativePath="super_tone_tx.c"></File>
<File RelativePath="swept_tone.c"></File>
<File RelativePath="t4.c"></File>
<File RelativePath="t4_rx.c"></File>
<File RelativePath="t4_tx.c"></File>
<File RelativePath="t30.c"></File>
<File RelativePath="t30_api.c"></File>
<File RelativePath="t30_logging.c"></File>
@@ -221,7 +222,8 @@
<File RelativePath="spandsp/super_tone_rx.h"></File>
<File RelativePath="spandsp/super_tone_tx.h"></File>
<File RelativePath="spandsp/swept_tone.h"></File>
<File RelativePath="spandsp/t4.h"></File>
<File RelativePath="spandsp/t4_rx.h"></File>
<File RelativePath="spandsp/t4_tx.h"></File>
<File RelativePath="spandsp/t30.h"></File>
<File RelativePath="spandsp/t30_api.h"></File>
<File RelativePath="spandsp/t30_fcf.h"></File>
@@ -283,12 +285,14 @@
<File RelativePath="spandsp/private/super_tone_tx.h"></File>
<File RelativePath="spandsp/private/swept_tone.h"></File>
<File RelativePath="spandsp/private/t30.h"></File>
<File RelativePath="spandsp/private/t30_dis_dtc_dcs_bits.h"></File>
<File RelativePath="spandsp/private/t31.h"></File>
<File RelativePath="spandsp/private/t38_core.h"></File>
<File RelativePath="spandsp/private/t38_gateway.h"></File>
<File RelativePath="spandsp/private/t38_non_ecm_buffer.h"></File>
<File RelativePath="spandsp/private/t38_terminal.h"></File>
<File RelativePath="spandsp/private/t4.h"></File>
<File RelativePath="spandsp/private/t4_rx.h"></File>
<File RelativePath="spandsp/private/t4_tx.h"></File>
<File RelativePath="spandsp/private/time_scale.h"></File>
<File RelativePath="spandsp/private/tone_detect.h"></File>
<File RelativePath="spandsp/private/tone_generate.h"></File>
+7 -3
View File
@@ -213,7 +213,8 @@
<File RelativePath="super_tone_rx.c"></File>
<File RelativePath="super_tone_tx.c"></File>
<File RelativePath="swept_tone.c"></File>
<File RelativePath="t4.c"></File>
<File RelativePath="t4_rx.c"></File>
<File RelativePath="t4_tx.c"></File>
<File RelativePath="t30.c"></File>
<File RelativePath="t30_api.c"></File>
<File RelativePath="t30_logging.c"></File>
@@ -291,7 +292,8 @@
<File RelativePath="spandsp/super_tone_rx.h"></File>
<File RelativePath="spandsp/super_tone_tx.h"></File>
<File RelativePath="spandsp/swept_tone.h"></File>
<File RelativePath="spandsp/t4.h"></File>
<File RelativePath="spandsp/t4_rx.h"></File>
<File RelativePath="spandsp/t4_tx.h"></File>
<File RelativePath="spandsp/t30.h"></File>
<File RelativePath="spandsp/t30_api.h"></File>
<File RelativePath="spandsp/t30_fcf.h"></File>
@@ -353,12 +355,14 @@
<File RelativePath="spandsp/private/super_tone_tx.h"></File>
<File RelativePath="spandsp/private/swept_tone.h"></File>
<File RelativePath="spandsp/private/t30.h"></File>
<File RelativePath="spandsp/private/t30_dis_dtc_dcs_bits.h"></File>
<File RelativePath="spandsp/private/t31.h"></File>
<File RelativePath="spandsp/private/t38_core.h"></File>
<File RelativePath="spandsp/private/t38_gateway.h"></File>
<File RelativePath="spandsp/private/t38_non_ecm_buffer.h"></File>
<File RelativePath="spandsp/private/t38_terminal.h"></File>
<File RelativePath="spandsp/private/t4.h"></File>
<File RelativePath="spandsp/private/t4_rx.h"></File>
<File RelativePath="spandsp/private/t4_tx.h"></File>
<File RelativePath="spandsp/private/time_scale.h"></File>
<File RelativePath="spandsp/private/tone_detect.h"></File>
<File RelativePath="spandsp/private/tone_generate.h"></File>
+19 -3
View File
@@ -297,7 +297,11 @@ SOURCE=.\swept_tone.c
# End Source File
# Begin Source File
SOURCE=.\t4.c
SOURCE=.\t4_rx.c
# End Source File
# Begin Source File
SOURCE=.\t4_tx.c
# End Source File
# Begin Source File
@@ -607,7 +611,11 @@ SOURCE=.\spandsp/swept_tone.h
# End Source File
# Begin Source File
SOURCE=.\spandsp/t4.h
SOURCE=.\spandsp/t4_rx.h
# End Source File
# Begin Source File
SOURCE=.\spandsp/t4_tx.h
# End Source File
# Begin Source File
@@ -855,6 +863,10 @@ SOURCE=.\spandsp/private/t30.h
# End Source File
# Begin Source File
SOURCE=.\spandsp/private/t30_dis_dtc_dcs_bits.h
# End Source File
# Begin Source File
SOURCE=.\spandsp/private/t31.h
# End Source File
# Begin Source File
@@ -875,7 +887,11 @@ SOURCE=.\spandsp/private/t38_terminal.h
# End Source File
# Begin Source File
SOURCE=.\spandsp/private/t4.h
SOURCE=.\spandsp/private/t4_rx.h
# End Source File
# Begin Source File
SOURCE=.\spandsp/private/t4_tx.h
# End Source File
# Begin Source File
+2 -1
View File
@@ -23,7 +23,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: make_at_dictionary.c,v 1.5 2009/10/05 16:36:42 steveu Exp $
* $Id: make_at_dictionary.c,v 1.6 2009/10/09 14:53:57 steveu Exp $
*/
#if defined(HAVE_CONFIG_H)
@@ -231,6 +231,7 @@ const char *wordlist[] =
"+ESR", /* V.250 6.5.3 - Selective repeat */
"+ETBM", /* V.250 6.5.6 - Call termination buffer management */
"+EWIND", /* V.250 6.5.7 - Window size */
"+F34", /* T.31 B.6.1 - Initial V.34 rate controls for FAX */
"+FAA", /* T.32 8.5.2.5 - Adaptive Answer parameter */
"+FAP", /* T.32 8.5.1.12 - Addressing and polling capabilities parameter */
"+FAR", /* T.31 8.5.1 - Adaptive reception control */
+82 -31
View File
@@ -23,11 +23,23 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: modem_connect_tones.c,v 1.37 2009/06/02 16:03:56 steveu Exp $
* $Id: modem_connect_tones.c,v 1.41 2009/11/06 19:21:33 steveu Exp $
*/
/*! \file */
/* 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.
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.
The modulated envelope ranges in amplitude between (0.8+-0.01) and (1.2+-0.01) times its average
amplitude. It lasts up to 5s, but will be stopped early if the V.8 protocol proceeds. */
#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif
@@ -158,9 +170,9 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_tx(modem_connect_tones_tx_state_t *
case MODEM_CONNECT_TONES_ANSAM:
if (s->duration_timer < len)
len = s->duration_timer;
if (s->duration_timer > ms_to_samples(3300))
if (s->duration_timer > ms_to_samples(5000))
{
if ((i = s->duration_timer - ms_to_samples(3300)) > len)
if ((i = s->duration_timer - ms_to_samples(5000)) > len)
i = len;
memset(amp, 0, sizeof(int16_t)*i);
}
@@ -174,9 +186,9 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_tx(modem_connect_tones_tx_state_t *
case MODEM_CONNECT_TONES_ANSAM_PR:
if (s->duration_timer < len)
len = s->duration_timer;
if (s->duration_timer > ms_to_samples(3300))
if (s->duration_timer > ms_to_samples(5000))
{
if ((i = s->duration_timer - ms_to_samples(3300)) > len)
if ((i = s->duration_timer - ms_to_samples(5000)) > len)
i = len;
memset(amp, 0, sizeof(int16_t)*i);
}
@@ -221,28 +233,48 @@ SPAN_DECLARE(modem_connect_tones_tx_state_t *) modem_connect_tones_tx_init(modem
s->tone_phase = 0;
s->mod_phase = 0;
s->mod_level = 0;
s->hop_timer = 0;
break;
case MODEM_CONNECT_TONES_ANS:
case MODEM_CONNECT_TONES_ANSAM:
/* 0.2s of silence, then 2.6s to 4s of 2100Hz+-15Hz tone, then 75ms of silence. */
s->tone_phase_rate = dds_phase_rate(2100.0);
s->level = dds_scaling_dbm0(-11);
s->duration_timer = ms_to_samples(200 + 2600);
s->mod_phase_rate = dds_phase_rate(15.0);
if (s->tone_type == MODEM_CONNECT_TONES_ANSAM)
{
s->mod_phase_rate = dds_phase_rate(15.0);
s->mod_level = s->level/5;
s->duration_timer = ms_to_samples(200 + 5000);
}
else
{
s->mod_phase_rate = 0;
s->mod_level = 0;
s->duration_timer = ms_to_samples(200 + 2600);
}
s->tone_phase = 0;
s->mod_phase = 0;
s->mod_level = (s->tone_type == MODEM_CONNECT_TONES_ANSAM) ? s->level/5 : 0;
s->hop_timer = 0;
break;
case MODEM_CONNECT_TONES_ANS_PR:
case MODEM_CONNECT_TONES_ANSAM_PR:
s->tone_phase_rate = dds_phase_rate(2100.0);
s->level = dds_scaling_dbm0(-12);
s->duration_timer = ms_to_samples(200 + 3300);
s->mod_phase_rate = dds_phase_rate(15.0);
if (s->tone_type == MODEM_CONNECT_TONES_ANSAM_PR)
{
s->mod_phase_rate = dds_phase_rate(15.0);
s->mod_level = s->level/5;
s->duration_timer = ms_to_samples(200 + 5000);
}
else
{
s->mod_phase_rate = 0;
s->mod_level = 0;
s->duration_timer = ms_to_samples(200 + 3300);
}
s->tone_phase = 0;
s->mod_phase = 0;
s->hop_timer = ms_to_samples(450);
s->mod_level = (s->tone_type == MODEM_CONNECT_TONES_ANSAM_PR) ? s->level/5 : 0;
break;
default:
if (alloced)
@@ -362,19 +394,20 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t *
int16_t notched;
float v1;
float famp;
float filtered;
switch (s->tone_type)
{
case MODEM_CONNECT_TONES_FAX_CNG:
for (i = 0; i < len; i++)
{
famp = amp[i];
/* A Cauer notch at 1100Hz, spread just wide enough to meet our detection bandwidth
criteria. */
famp = amp[i];
v1 = 0.792928f*famp + 1.0018744927985f*s->z1 - 0.54196833412465f*s->z2;
famp = v1 - 1.2994747954630f*s->z1 + s->z2;
s->z2 = s->z1;
s->z1 = v1;
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;
s->znotch_1 = v1;
notched = (int16_t) lfastrintf(famp);
/* Estimate the overall energy in the channel, and the energy in
@@ -413,22 +446,29 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t *
case MODEM_CONNECT_TONES_ANS:
for (i = 0; i < len; i++)
{
famp = amp[i];
/* A Cauer bandpass at 15Hz, with which we demodulate the AM signal. */
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;
s->z15hz_1 = v1;
s->am_level += abs(lfastrintf(filtered)) - (s->am_level >> 8);
//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 */
famp = amp[i];
v1 = 0.76000f*famp - 0.1183852f*s->z1 - 0.5104039f*s->z2;
famp = v1 + 0.1567596f*s->z1 + s->z2;
s->z2 = s->z1;
s->z1 = v1;
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;
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?).
Damp the overall energy a little more for a stable result.
Damp the notch energy a little less, so we don't damp out the
blip every time the phase reverses */
blip every time the phase reverses. */
s->channel_level += ((abs(amp[i]) - s->channel_level) >> 5);
s->notch_level += ((abs(notched) - s->notch_level) >> 4);
/* This should cut off at about -43dBm0 */
@@ -455,7 +495,11 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t *
if (s->tone_cycle_duration >= ms_to_samples(450 - 25))
{
if (++s->good_cycles == 3)
report_tone_state(s, MODEM_CONNECT_TONES_ANS_PR, lfastrintf(log10f(s->channel_level/32768.0f)*20.0f + DBM0_MAX_POWER + 0.8f));
{
report_tone_state(s,
(s->am_level*15/256 > s->channel_level) ? MODEM_CONNECT_TONES_ANSAM_PR : MODEM_CONNECT_TONES_ANS_PR,
lfastrintf(log10f(s->channel_level/32768.0f)*20.0f + DBM0_MAX_POWER + 0.8f));
}
}
else
{
@@ -466,17 +510,21 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t *
}
else
{
if (s->tone_cycle_duration >= ms_to_samples(550))
if (s->tone_cycle_duration >= ms_to_samples(450 + 100))
{
if (s->tone_present == MODEM_CONNECT_TONES_NONE)
report_tone_state(s, MODEM_CONNECT_TONES_ANS, lfastrintf(log10f(s->channel_level/32768.0f)*20.0f + DBM0_MAX_POWER + 0.8f));
{
report_tone_state(s,
(s->am_level*15/256 > s->channel_level) ? MODEM_CONNECT_TONES_ANSAM : MODEM_CONNECT_TONES_ANS,
lfastrintf(log10f(s->channel_level/32768.0f)*20.0f + DBM0_MAX_POWER + 0.8f));
}
s->good_cycles = 0;
s->tone_cycle_duration = ms_to_samples(550);
s->tone_cycle_duration = ms_to_samples(450 + 100);
}
}
s->tone_on = TRUE;
}
else
else if (s->notch_level*5 > s->channel_level)
{
if (s->tone_present == MODEM_CONNECT_TONES_ANS)
{
@@ -528,7 +576,7 @@ SPAN_DECLARE(modem_connect_tones_rx_state_t *) modem_connect_tones_rx_init(modem
{
case MODEM_CONNECT_TONES_FAX_PREAMBLE:
case MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE:
fsk_rx_init(&(s->v21rx), &preset_fsk_specs[FSK_V21CH2], TRUE, v21_put_bit, s);
fsk_rx_init(&(s->v21rx), &preset_fsk_specs[FSK_V21CH2], FSK_FRAME_MODE_SYNC, v21_put_bit, s);
fsk_rx_signal_cutoff(&(s->v21rx), -45.5f);
break;
case MODEM_CONNECT_TONES_ANS_PR:
@@ -540,6 +588,7 @@ SPAN_DECLARE(modem_connect_tones_rx_state_t *) modem_connect_tones_rx_init(modem
}
s->channel_level = 0;
s->notch_level = 0;
s->am_level = 0;
s->tone_present = MODEM_CONNECT_TONES_NONE;
s->tone_cycle_duration = 0;
s->good_cycles = 0;
@@ -547,8 +596,10 @@ SPAN_DECLARE(modem_connect_tones_rx_state_t *) modem_connect_tones_rx_init(modem
s->tone_on = FALSE;
s->tone_callback = tone_callback;
s->callback_data = user_data;
s->z1 = 0.0f;
s->z2 = 0.0f;
s->znotch_1 = 0.0f;
s->znotch_2 = 0.0f;
s->z15hz_1 = 0.0f;
s->z15hz_2 = 0.0f;
s->num_bits = 0;
s->flags_seen = 0;
s->framing_ok_announced = FALSE;
+3 -2
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: spandsp.h.in,v 1.19 2009/09/22 13:11:04 steveu Exp $
* $Id: spandsp.h.in,v 1.19.4.1 2009/12/19 09:47:56 steveu Exp $
*/
/*! \file */
@@ -99,7 +99,8 @@
#include <spandsp/v18.h>
#include <spandsp/v42.h>
#include <spandsp/v42bis.h>
#include <spandsp/t4.h>
#include <spandsp/t4_rx.h>
#include <spandsp/t4_tx.h>
#include <spandsp/t30.h>
#include <spandsp/t30_api.h>
#include <spandsp/t30_fcf.h>
+3 -2
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: spandsp.h.in,v 1.19 2009/09/22 13:11:04 steveu Exp $
* $Id: spandsp.h.in,v 1.19.4.1 2009/12/19 09:47:56 steveu Exp $
*/
/*! \file */
@@ -96,7 +96,8 @@
#include <spandsp/v18.h>
#include <spandsp/v42.h>
#include <spandsp/v42bis.h>
#include <spandsp/t4.h>
#include <spandsp/t4_rx.h>
#include <spandsp/t4_tx.h>
#include <spandsp/t30.h>
#include <spandsp/t30_api.h>
#include <spandsp/t30_fcf.h>
+3 -2
View File
@@ -23,7 +23,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: expose.h,v 1.14 2009/09/22 13:11:04 steveu Exp $
* $Id: expose.h,v 1.14.4.1 2009/12/19 09:47:56 steveu Exp $
*/
/*! \file */
@@ -71,7 +71,8 @@
#include <spandsp/private/modem_connect_tones.h>
#include <spandsp/private/at_interpreter.h>
#include <spandsp/private/fax_modems.h>
#include <spandsp/private/t4.h>
#include <spandsp/private/t4_rx.h>
#include <spandsp/private/t4_tx.h>
#include <spandsp/private/t30.h>
#include <spandsp/private/fax.h>
#include <spandsp/private/t38_core.h>
+14 -1
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: fsk.h,v 1.40 2009/06/02 16:03:56 steveu Exp $
* $Id: fsk.h,v 1.41 2009/11/02 13:25:20 steveu Exp $
*/
/*! \file */
@@ -115,6 +115,15 @@ enum
FSK_WEITBRECHT50 /* 50 baud version, used for TDD (Telecom Device for the Deaf) */
};
enum
{
FSK_FRAME_MODE_ASYNC = 0,
FSK_FRAME_MODE_SYNC = 1,
FSK_FRAME_MODE_5N1_FRAMES = 7, /* 5 bits of data + start bit + stop bit */
FSK_FRAME_MODE_7N1_FRAMES = 9, /* 7 bits of data + start bit + stop bit */
FSK_FRAME_MODE_8N1_FRAMES = 10 /* 8 bits of data + start bit + stop bit */
};
SPAN_DECLARE_DATA extern const fsk_spec_t preset_fsk_specs[];
/*!
@@ -149,6 +158,8 @@ SPAN_DECLARE(fsk_tx_state_t *) fsk_tx_init(fsk_tx_state_t *s,
get_bit_func_t get_bit,
void *user_data);
SPAN_DECLARE(int) fsk_tx_restart(fsk_tx_state_t *s, const fsk_spec_t *spec);
SPAN_DECLARE(int) fsk_tx_release(fsk_tx_state_t *s);
SPAN_DECLARE(int) fsk_tx_free(fsk_tx_state_t *s);
@@ -203,6 +214,8 @@ SPAN_DECLARE(fsk_rx_state_t *) fsk_rx_init(fsk_rx_state_t *s,
put_bit_func_t put_bit,
void *user_data);
SPAN_DECLARE(int) fsk_rx_restart(fsk_rx_state_t *s, const fsk_spec_t *spec, int framing_mode);
SPAN_DECLARE(int) fsk_rx_release(fsk_rx_state_t *s);
SPAN_DECLARE(int) fsk_rx_free(fsk_rx_state_t *s);
@@ -24,7 +24,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: modem_connect_tones.h,v 1.2 2009/01/29 18:30:14 steveu Exp $
* $Id: modem_connect_tones.h,v 1.3 2009/11/02 13:25:20 steveu Exp $
*/
/*! \file */
@@ -66,12 +66,17 @@ struct modem_connect_tones_rx_state_s
void *callback_data;
/*! \brief The notch filter state. */
float z1;
float z2;
float znotch_1;
float znotch_2;
/*! \brief The 15Hz AM filter state. */
float z15hz_1;
float z15hz_2;
/*! \brief The in notch power estimate */
int notch_level;
int32_t notch_level;
/*! \brief The total channel power estimate */
int channel_level;
int32_t channel_level;
/*! \brief The 15Hz AM power estimate */
int32_t am_level;
/*! \brief Sample counter for the small chunks of samples, after which a test is conducted. */
int chunk_remainder;
/*! \brief TRUE is the tone is currently confirmed present in the audio. */
+2 -2
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t30.h,v 1.5 2009/09/20 13:42:29 steveu Exp $
* $Id: t30.h,v 1.5.4.1 2009/12/19 09:47:56 steveu Exp $
*/
/*! \file */
@@ -253,7 +253,7 @@ struct t30_state_s
int tx_stop_page;
/*! \brief The current completion status. */
int current_status;
/*! \brief Internet Aware FAX mode bit mask. */
/*! \brief Internet aware FAX mode bit mask. */
int iaf;
/*! \brief A bit mask of the currently supported modem types. */
int supported_modems;
@@ -0,0 +1,387 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* t30_dis_dtc_dcs_bits.h - ITU T.30 fax control bits definitions
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2009 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t30_dis_dtc_dcs_bits.h,v 1.1.4.1 2009/12/19 09:47:57 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_PRIVATE_T30_DIS_DTC_DCS_BITS_H_)
#define _SPANDSP_PRIVATE_T30_DIS_DTC_DCS_BITS_H_
/* Indicates that the terminal has the Simple mode capability defined in ITU-T Rec. T.37.
Internet address signals CIA, TSA or CSA can be sent and received. The recipient terminal
may process or ignore this signal. */
#define T30_DIS_BIT_T37 1
#define T30_DCS_BIT_T37 1
/* Indicates that the terminal has the capability to communicate using ITU-T Rec. T.38.
Internet address signals CIA, TSA or CSA can be sent and received. The recipient terminal
may process or ignore this signal. */
#define T30_DIS_BIT_T38 3
#define T30_DCS_BIT_T38 3
/* Bit 4 set to "1" indicates 3rd Generation Mobile Network Access to the GSTN Connection.
Bit 4 set to "0" conveys no information about the type of connection. */
#define T30_DIS_BIT_3G_MOBILE 4
#define T30_DCS_BIT_3G_MOBILE 4
/* When ISDN mode is used, in DIS/DTC bit 6 shall be set to "0". */
#define T30_DIS_BIT_V8_CAPABILITY 6
/* When ISDN mode is used, in DIS/DTC bit 7 shall be set to "0". */
#define T30_DIS_BIT_64_OCTET_ECM_FRAMES_PREFERRED 7
/* Bit 9 indicates that there is a facsimile document ready to be polled from the answering
terrminal. It is not an indication of a capability. */
#define T30_DIS_BIT_READY_TO_TRANSMIT_FAX_DOCUMENT 9
/* In DIS/DTC bit 10 indicates that the answering terminal has receiving capabilities.
In DCS it is a command to the receiving terminal to set itself in the receive mode. */
#define T30_DIS_BIT_READY_TO_RECEIVE_FAX_DOCUMENT 10
#define T30_DCS_BIT_RECEIVE_FAX_DOCUMENT 10
/* Bits 11, 12, 13, 14 - modem type */
#define T30_DIS_BIT_200_200_CAPABLE 15
#define T30_DCS_BIT_200_200 15
#define T30_DIS_BIT_2D_CAPABLE 16
#define T30_DCS_BIT_2D_CODING 16
/* Standard facsimile terminals conforming to ITU-T Rec. T.4 must have the following capability:
Paper length = 297 mm. */
/* Bits 17, 18 - recording width */
/* Bits 19, 20 - paper length */
/* Bits 21, 22, 23 - min scan line time */
/* When ISDN mode is used, in DIS/DTC bits 21 to 23 shall be set to "1". */
#define T30_DIS_BIT_UNCOMPRESSED_CAPABLE 26
#define T30_DCS_BIT_UNCOMPRESSED_MODE 26
/* When ISDN mode is used, in DIS/DTC bit 27 shall be set to "1". */
#define T30_DIS_BIT_ECM_CAPABLE 27
#define T30_DCS_BIT_ECM 27
/* The value of bit 28 in the DCS command is only valid when ECM is selected. */
#define T30_DCS_BIT_64_OCTET_ECM_FRAMES 28
/* The value of bit 31 in the DCS command is only valid when ECM is selected. */
#define T30_DIS_BIT_T6_CAPABLE 31
#define T30_DCS_BIT_T6_MODE 31
#define T30_DIS_BIT_FNV_CAPABLE 33
#define T30_DCS_BIT_FNV_CAPABLE 33
#define T30_DIS_BIT_MULTIPLE_SELECTIVE_POLLING_CAPABLE 34
#define T30_DIS_BIT_POLLED_SUBADDRESSING_CAPABLE 35
#define T30_DIS_BIT_T43_CAPABLE 36
#define T30_DCS_BIT_T43_CODING 36
#define T30_DIS_BIT_PLANE_INTERLEAVE_CAPABLE 37
#define T30_DCS_BIT_PLANE_INTERLEAVE 37
#define T30_DIS_BIT_G726_CAPABLE 38
#define T30_DCS_BIT_G726 38
#define T30_DIS_BIT_200_400_CAPABLE 41
#define T30_DCS_BIT_200_400 41
#define T30_DIS_BIT_300_300_CAPABLE 42
#define T30_DCS_BIT_300_300 42
#define T30_DIS_BIT_400_400_CAPABLE 43
#define T30_DCS_BIT_400_400 43
/* Bits 44 and 45 are used only in conjunction with bits 15 and 43. Bit 44 in DCS, when used,
shall correctly indicate the resolution of the transmitted document, which means that bit 44 in DCS may
not always match the indication of bits 44 and 45 in DIS/DTC. Cross selection will cause the distortion
and reduction of reproducible area.
If a receiver indicates in DIS that it prefers to receive metric-based information, but the transmitter has
only the equivalent inch-based information (or vice versa), then communication shall still take place.
Bits 44 and 45 do not require the provision of any additional features on the terminal to
indicate to the sending or receiving user whether the information was transmitted or received on a metric-metric,
inch-inch, metric-inch, inch-metric basis. */
#define T30_DIS_BIT_INCH_RESOLUTION_PREFERRED 44
#define T30_DCS_BIT_INCH_RESOLUTION 44
#define T30_DIS_BIT_METRIC_RESOLUTION_PREFERRED 45
#define T30_DIS_BIT_MIN_SCAN_TIME_HALVES 46
#define T30_DIS_BIT_SELECTIVE_POLLING_CAPABLE 47
#define T30_DIS_BIT_SUBADDRESSING_CAPABLE 49
#define T30_DCS_BIT_SUBADDRESS_TRANSMISSION 49
#define T30_DIS_BIT_PASSWORD 50
#define T30_DCS_BIT_SENDER_ID_TRANSMISSION 50
/* Bit 51 indicates that there is a data file ready to be polled from the answering terminal. It is
not an indication of a capability. This bit is used in conjunction with bits 53, 54, 55 and 57. */
#define T30_DIS_BIT_READY_TO_TRANSMIT_DATA_FILE 51
/* The binary file transfer protocol is described in ITU-T Rec. T.434. */
#define T30_DIS_BIT_BFT_CAPABLE 53
#define T30_DCS_BIT_BFT 53
#define T30_DIS_BIT_DTM_CAPABLE 54
#define T30_DCS_BIT_DTM 54
#define T30_DIS_BIT_EDI_CAPABLE 55
#define T30_DCS_BIT_EDI 55
#define T30_DIS_BIT_BTM_CAPABLE 57
#define T30_DCS_BIT_BTM 57
/* Bit 59 indicates that there is a character-coded or mixed-mode document ready to be polled
from the answering terminal. It is not an indication of a capability. This bit is used in
conjunction with bits 60, 62 and 65. */
#define T30_DIS_BIT_READY_TO_TRANSMIT_MIXED_MODE_DOCUMENT 59
#define T30_DIS_BIT_CHARACTER_MODE 60
#define T30_DCS_BIT_CHARACTER_MODE 60
#define T30_DIS_BIT_MIXED_MODE 62
#define T30_DCS_BIT_MIXED_MODE 62
#define T30_DIS_BIT_PROCESSABLE_MODE_26 65
#define T30_DIS_BIT_DIGITAL_NETWORK_CAPABLE 66
#define T30_DCS_BIT_DIGITAL_NETWORK_CAPABLE 66
#define T30_DIS_BIT_DUPLEX_CAPABLE 67
#define T30_DCS_BIT_DUPLEX_CAPABLE 67
#define T30_DIS_BIT_T81_CAPABLE 68
#define T30_DCS_BIT_FULL_COLOUR_MODEX 68
#define T30_DIS_BIT_FULL_COLOUR_CAPABLE 69
#define T30_DCS_BIT_FULL_COLOUR_MODE 69
/* In a DIS/DTC frame, setting bit 71 to "0" indicates that the called terminal can only accept
image data which has been digitized to 8 bits/pel/component for JPEG mode. This is also true for T.43
mode if bit 36 is also set to "1". Setting bit 71 to "1" indicates that the called terminal can also accept
image data that are digitized to 12 bits/pel/component for JPEG mode. This is also true for T.43 mode if
bit 36 is also set to "1". In a DCS frame, setting bit 71 to "0" indicates that the calling terminal's image
data are digitized to 8 bits/pel/component for JPEG mode. This is also true for T.43 mode if bit 36 is also
set to "1". Setting bit 71 to "1" indicates that the calling terminal transmits image data which has been
digitized to 12 bits/pel/component for JPEG mode. This is also true for T.43 mode if bit 36 is also set
to "1". */
#define T30_DIS_BIT_12BIT_CAPABLE 71
#define T30_DCS_BIT_12BIT_COMPONENT 71
#define T30_DIS_BIT_NO_SUBSAMPLING 73
#define T30_DCS_BIT_NO_SUBSAMPLING 73
#define T30_DIS_BIT_CUSTOM_ILLUMINANT 74
#define T30_DCS_BIT_CUSTOM_ILLUMINANT 74
#define T30_DIS_BIT_CUSTOM_GAMUT_RANGE 75
#define T30_DCS_BIT_CUSTOM_GAMUT_RANGE 75
#define T30_DIS_BIT_NORTH_AMERICAN_LETTER_CAPABLE 76
#define T30_DCS_BIT_NORTH_AMERICAN_LETTER 76
#define T30_DIS_BIT_NORTH_AMERICAN_LEGAL_CAPABLE 77
#define T30_DCS_BIT_NORTH_AMERICAN_LEGAL 77
#define T30_DIS_BIT_T85_CAPABLE 78
#define T30_DCS_BIT_T85_MODE 78
#define T30_DIS_BIT_T85_L0_CAPABLE 79
#define T30_DCS_BIT_T85_L0_MODE 79
/* In a DIS/DTC frame, setting bit 97 to "0" indicates that the called terminal does not have the
capability to accept 300 pels/25.4 mm x 300 lines/25.4 mm or 400 pels/25.4 mm x 400 lines/25.4 mm
resolutions for colour/gray-scale images or T.44 Mixed Raster Content (MRC) mask layer.
Setting bit 97 to "1" indicates that the called terminal does have the capability to accept
300 pels/25.4 mm x 300 lines/25.4 mm or 400 pels/25.4 mm x 400 lines/25.4 mm resolutions for
colour/gray-scale images and MRC mask layer. Bit 97 is valid only when bits 68 and 42 or 43
(300 pels/25.4 mm x 300 lines/25.4 mm or 400 pels/25.4 mm x 400 lines/25.4 mm) are set to "1".
In a DCS frame, setting bit 97 to "0" indicates that the calling terminal does not use
300 pels/25.4 mm x 300 lines/25.4 mm or 400 pels/25.4 mm x 400 lines/25.4 mm resolutions
for colour/gray-scale images and mask layer.
Setting bit 97 to "1" indicates that the calling terminal uses 300 pels/25.4 mm x 300 lines/25.4 mm
or 400 pels/25.4 mm x 400 lines/25.4 mm resolutions for colour/gray-scale images and MRC mask layer.
Bit 97 is valid only when bits 68 and 42 or 43 (300 pels/25.4 mm x 300 lines/25.4 mm and
400 pels/25.4 mm x 400 lines/25.4 mm) are set to "1".
In a DIS/DTC frame, combinations of bit 42, bit 43 and bit 97 indicate that the called terminal
has higher resolution capabilities as follows:
Resolution capabilities (pels/25.4 mm)
DIS/DTC Monochrome Colour/gray-scale
42 43 97 300 x 300 400 x 400 300 x 300 400 x 400
0 0 0 no no no no
1 0 0 yes no no no
0 1 0 no yes no no
1 1 0 yes yes no no
0 0 1 (invalid)
1 0 1 yes no yes no
0 1 1 no yes no yes
1 1 1 yes yes yes yes
"yes" means that the called terminal has the corresponding capability.
"no" means that the called terminal does not have the corresponding capability. */
#define T30_DIS_BIT_COLOUR_GREY_300_300_400_400_CAPABLE 97
#define T30_DCS_BIT_COLOUR_GREY_300_300_400_400 97
/* In a DIS/DTC frame, setting bit 98 to "0" indicates that the called terminal does not have the
capability to accept 100 pels/25.4 mm x 100 lines/25.4 mm spatial resolution for colour or gray-scale
images. Setting bit 98 to "1" indicates that the called terminal does have the capability to accept
100 pels/25.4 mm x 100 lines/25.4 mm spatial resolution for colour or gray-scale images. Bit 98 is valid
only when bit 68 is set to "1". In a DCS frame, setting bit 98 to "0" indicates that the calling terminal does
not use 100 pels/25.4 mm x 100 lines/25.4 mm spatial resolution for colour or gray-scale images. Setting
bit 98 to "1" indicates that the calling terminal uses 100 pels/25.4 mm x 100 lines/25.4 mm spatial
resolution for colour or gray-scale images. */
#define T30_DIS_BIT_COLOUR_GREY_100_100_CAPABLE 98
#define T30_DCS_BIT_COLOUR_GREY_100_100 98
/* To provide an error recovery mechanism, when PWD/SEP/SUB/SID/PSA/IRA/ISP frames are sent with DCS or DTC,
bits 49, 102 and 50 in DCS or bits 47, 101, 50 and 35 in DTC shall be set to "1" with the following
meaning:
Bit DIS DTC DCS
35 Polled SubAddress capability Polled SubAddress transmission Not allowed set to "0"
47 Selective polling capability Selective polling transmission Not allowed set to "0"
49 Subaddressing capability Not allowed (Set to "0") Subaddressing transmission
50 Password Password transmission Sender Identification transmission
101 Internet Selective Polling Address capability Internet Selective Polling Address transmission Not allowed set to "0"
102 Internet Routing Address capability Not allowed (Set to "0") Internet Routing Address transmission
Terminals conforming to the 1993 version of T.30 may set the above bits to "0" even though PWD/SEP/SUB
frames are transmitted. */
#define T30_DIS_BIT_INTERNET_SELECTIVE_POLLING_ADDRESS 101
#define T30_DIS_BIT_INTERNET_ROUTING_ADDRESS 102
#define T30_DCS_BIT_INTERNET_ROUTING_ADDRESS_TRANSMISSION 102
#define T30_DIS_BIT_600_600_CAPABLE 105
#define T30_DCS_BIT_600_600 105
#define T30_DIS_BIT_1200_1200_CAPABLE 106
#define T30_DCS_BIT_1200_1200 106
#define T30_DIS_BIT_300_600_CAPABLE 107
#define T30_DCS_BIT_300_600 107
#define T30_DIS_BIT_400_800_CAPABLE 108
#define T30_DCS_BIT_400_800 108
#define T30_DIS_BIT_600_1200_CAPABLE 109
#define T30_DCS_BIT_600_1200 109
#define T30_DIS_BIT_COLOUR_GREY_600_600_CAPABLE 110
#define T30_DCS_BIT_COLOUR_GREY_600_600 110
#define T30_DIS_BIT_COLOUR_GREY_1200_1200_CAPABLE 111
#define T30_DCS_BIT_COLOUR_GREY_1200_1200 111
#define T30_DIS_BIT_ALTERNATE_DOUBLE_SIDED_CAPABLE 113
#define T30_DCS_BIT_ALTERNATE_DOUBLE_SIDED_CAPABLE 113
#define T30_DIS_BIT_CONTINUOUS_DOUBLE_SIDED_CAPABLE 114
#define T30_DCS_BIT_CONTINUOUS_DOUBLE_SIDED_CAPABLE 114
#define T30_DIS_BIT_BLACK_AND_WHITE_MRC 115
#define T30_DIS_BIT_T45_CAPABLE 116
#define T30_DCS_BIT_T45_MODE 116
/* This bit defines the available colour space, when bit 92, 93 or 94 is set to "1".
Available colour space for all combinations of bits 92, 93, 94 and 119 are shown in the following table.
It should be noted that terminals which conform to the 2003 and earlier versions of this Recommendation
will send LAB with "1" in bit 92, 93 or 94 even if bit 119 is set to "1".
Available colour space for DIS/DTC bits 92, 93, 94 and 119
92 93 94 119 Mode of T.44 Available colour space
0 0 0 x Not available -
1 0 0 0 Mode 1 LAB only
1 0 0 1 Mode 1 YCC only
x 1 x 0 Mode 2 or higher LAB only
x x 1 0 Mode 2 or higher LAB only
x 1 x 1 Mode 2 or higher LAB and YCC
x x 1 1 Mode 2 or higher LAB and YCC
Colour space for DCS bits 92, 93, 94 and 119
92 93 94 119 Mode of T.44 Colour space
0 0 0 x* Not available -
1 0 0 0 Mode 1 LAB
1 0 0 1 Mode 1 YCC
x 1 x 0 Mode 2 or higher LAB
x x 1 0 Mode 2 or higher LAB
x 1 x 1 Mode 2 or higher YCC or mixing of YCC and LAB
x x 1 1 Mode 2 or higher YCC or mixing of YCC and LAB */
#define T30_DIS_BIT_T44_COLOUR_SPACE 119
#define T30_DCS_BIT_T44_COLOUR_SPACE 119
/* Can only be set in the communication through the T.38 gateway, to cope with delay of network.
T.x timer (12+-1s) should be used after emitting RNR or TNR. However, after receiving
PPS signal in ECM mode, T.5 timer should be used. */
#define T30_DIS_BIT_T38_FLOW_CONTROL_CAPABLE 121
#define T30_DCS_BIT_T38_FLOW_CONTROL_CAPABLE 121
/* For resolutions greater than 200 lines/25.4 mm, 4.2.1.1/T.4 specifies the use of specific K
factors for each standardized vertical resolution. To ensure backward compatibility with earlier
versions of ITU-T Rec. T.4, bit 122 indicates when such K factors are being used. */
#define T30_DIS_BIT_K_GREATER_THAN_4 122
/* This bit should be set to "1" if the fax device is an Internet-Aware Fax Device as defined in
ITU-T Rec. T.38 and if it is not affected by the data signal rate indicated by the DIS and DTC
signals when communicating with another Internet-Aware Fax Device operating in T.38 mode. This
bit shall not be used in GSTN mode. */
#define T30_DIS_BIT_T38_FAX_CAPABLE 123
/* This bit should be set to "1" if the fax device elects to operate in an Internet-Aware Fax mode
as defined in ITU-T Rec. T.38 in response to a device which has set the related DIS bit to "1".
When this bit is set to "1", the data signal rate of the modem (bits 11-14) should be set to "0". */
#define T30_DCS_BIT_T38_FAX_MODE 123
/* When either bit of 31, 36, 38, 51, 53, 54, 55, 57, 59, 60, 62, 65, 68, 78, 79, 115, 116 and 127 is
set to "1", ECM must be used. If the value of bit field 92 to 94 is non-zero, then ECM must be used.
Annex K describes the optional continuous-tone colour and gray scale images mode
(sYCC-JPEG mode) protocol. When bit 127 in DIS/DTC frame is set to "1", the called terminal has the
capability to accept sYCC-JPEG mode. This is defined with complete independent in the colour space
CIELAB. In addition, when bit 127 in DCS frame is set to "1", ECM must be used and bits 15, 17, 18,
19, 20, 41, 42, 43, 45, 46, 68, 69, 71, 73, 74, 75, 76, 77, 97, 98, 105, 106, 107, 108,
109, 110 and 111 in DCS frame are "Don't care", and should be set to "0". In the case of
transmission of multiple images, a post message signal PPS-MPS between pages, PPS-NULL between
partial pages and PPS-EOP following the last page should be sent from the calling terminal to the
called terminal. */
#define T30_DIS_BIT_SYCC_T81_CAPABLE 127
#define T30_DCS_BIT_SYCC_T81_MODE 127
#endif
/*- End of file ------------------------------------------------------------*/
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t38_gateway.h,v 1.4 2009/05/16 03:34:45 steveu Exp $
* $Id: t38_gateway.h,v 1.5 2009/11/07 08:58:58 steveu Exp $
*/
/*! \file */
@@ -163,8 +163,8 @@ typedef struct
int ecm_mode;
/*! \brief The current bit rate for the fast modem. */
int fast_bit_rate;
/*! \brief The current fast modem type. */
int fast_modem;
/*! \brief The current fast receive modem type. */
int fast_rx_modem;
/*! \brief The type of fast receive modem currently active, which may be T38_NONE */
int fast_rx_active;
@@ -23,7 +23,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t38_non_ecm_buffer.h,v 1.2 2008/10/13 14:19:18 steveu Exp $
* $Id: t38_non_ecm_buffer.h,v 1.2.4.1 2009/12/19 06:43:28 steveu Exp $
*/
#if !defined(_SPANDSP_PRIVATE_T38_NON_ECM_BUFFER_H_)
@@ -36,7 +36,7 @@ struct t38_non_ecm_buffer_state_s
{
/*! \brief Minimum number of bits per row, used when fill bits are being deleted on the
link, and restored at the emitting gateway. */
int min_row_bits;
int min_bits_per_row;
/*! \brief non-ECM modem transmit data buffer. */
uint8_t data[T38_NON_ECM_TX_BUF_LEN];
@@ -55,8 +55,8 @@ struct t38_non_ecm_buffer_state_s
/*! \brief The non-ECM flow control fill octet (0xFF before the first data, and 0x00
once data has started). */
uint8_t flow_control_fill_octet;
/*! \brief TRUE if we are in the initial all ones part of non-ECM transmission. */
int at_initial_all_ones;
/*! \brief A code for the phase of input buffering, from initial all ones to completion. */
int input_phase;
/*! \brief TRUE is the end of non-ECM data indication has been received. */
int data_finished;
/*! \brief The current octet being transmitted from the buffer. */
+131
View File
@@ -0,0 +1,131 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* private/t4_rx.h - definitions for T.4 FAX receive processing
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t4_rx.h,v 1.6.2.8 2009/12/21 17:18:40 steveu Exp $
*/
#if !defined(_SPANDSP_PRIVATE_T4_RX_H_)
#define _SPANDSP_PRIVATE_T4_RX_H_
/*!
TIFF specific state information to go with T.4 compression or decompression handling.
*/
typedef struct
{
/*! \brief The current file name. */
const char *file;
/*! \brief The libtiff context for the current TIFF file */
TIFF *tiff_file;
/*! \brief The number of pages in the current image file. */
int pages_in_file;
/*! \brief The compression type for output to the TIFF file. */
int32_t output_compression;
/*! \brief The TIFF photometric setting for the current page. */
uint16_t photo_metric;
/*! \brief The TIFF fill order setting for the current page. */
uint16_t fill_order;
/*! \brief The TIFF G3 FAX options. */
int32_t output_t4_options;
/* "Background" information about the FAX, which can be stored in the image file. */
/*! \brief The vendor of the machine which produced the file. */
const char *vendor;
/*! \brief The model of machine which produced the file. */
const char *model;
/*! \brief The local ident string. */
const char *local_ident;
/*! \brief The remote end's ident string. */
const char *far_ident;
/*! \brief The FAX sub-address. */
const char *sub_address;
/*! \brief The FAX DCS information, as an ASCII string. */
const char *dcs;
/*! \brief The first page to transfer. -1 to start at the beginning of the file. */
int start_page;
/*! \brief The last page to transfer. -1 to continue to the end of the file. */
int stop_page;
} t4_tiff_state_t;
typedef struct t4_t6_decode_state_s t4_t6_decode_state_t;
/*!
T.4 1D, T4 2D and T6 decompressor state.
*/
struct t4_t6_decode_state_s
{
/*! \brief Callback function to write a row of pixels to the image destination. */
t4_row_write_handler_t row_write_handler;
/*! \brief Opaque pointer passed to row_write_handler. */
void *row_write_user_data;
/*! \brief Incoming bit buffer for decompression. */
uint32_t rx_bitstream;
/*! \brief The number of bits currently in rx_bitstream. */
int rx_bits;
/*! \brief The number of bits to be skipped before trying to match the next code word. */
int rx_skip_bits;
/*! \brief This variable is used to count the consecutive EOLS we have seen. If it
reaches six, this is the end of the image. It is initially set to -1 for
1D and 2D decoding, as an indicator that we must wait for the first EOL,
before decoding any image data. */
int consecutive_eols;
/*! \brief The reference or starting changing element on the coding line. At the
start of the coding line, a0 is set on an imaginary white changing element
situated just before the first element on the line. During the coding of
the coding line, the position of a0 is defined by the previous coding mode.
(See T.4/4.2.1.3.2.). */
int a0;
/*! \brief The first changing element on the reference line to the right of a0 and of
opposite colour to a0. */
int b1;
/*! \brief The length of the in-progress run of black or white. */
int run_length;
/*! \brief 2D horizontal mode control. */
int black_white;
/*! \brief TRUE if the current run is black */
int its_black;
/*! \brief The current step into the current row run-lengths buffer. */
int a_cursor;
/*! \brief The current step into the reference row run-lengths buffer. */
int b_cursor;
/*! \brief A pointer into the image buffer indicating where the last row begins */
int last_row_starts_at;
/*! \brief The current number of consecutive bad rows. */
int curr_bad_row_run;
/*! \brief The longest run of consecutive bad rows seen in the current page. */
int longest_bad_row_run;
/*! \brief The total number of bad rows in the current page. */
int bad_rows;
};
#endif
/*- End of file ------------------------------------------------------------*/
+142
View File
@@ -0,0 +1,142 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* private/t4_tx.h - definitions for T.4 FAX transmit processing
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t4_tx.h,v 1.7.2.4 2009/12/21 17:18:40 steveu Exp $
*/
#if !defined(_SPANDSP_PRIVATE_T4_TX_H_)
#define _SPANDSP_PRIVATE_T4_TX_H_
typedef struct t4_t6_encode_state_s t4_t6_encode_state_t;
/*!
T.4 1D, T4 2D and T6 compressor state.
*/
struct t4_t6_encode_state_s
{
/*! \brief The minimum number of encoded bits per row. This is a timing thing
for hardware FAX machines. */
int min_bits_per_row;
/*! \brief The current maximum contiguous rows that may be 2D encoded. */
int max_rows_to_next_1d_row;
/*! \brief The text which will be used in FAX page header. No text results
in no header line. */
const char *header_info;
/*! \brief Number of rows left that can be 2D encoded, before a 1D encoded row
must be used. */
int rows_to_next_1d_row;
/*! \brief The number of runs currently in the reference row. */
int ref_steps;
/*! \brief Pointer to the byte containing the next image bit to transmit. */
int bit_pos;
/*! \brief Pointer to the bit within the byte containing the next image bit to transmit. */
int bit_ptr;
/*! \brief Callback function to read a row of pixels from the image source. */
t4_row_read_handler_t row_read_handler;
/*! \brief Opaque pointer passed to row_read_handler. */
void *row_read_user_data;
};
/*!
T.4 FAX compression/decompression descriptor. This defines the working state
for a single instance of a T.4 FAX compression or decompression channel.
*/
struct t4_state_s
{
/*! \brief The same structure is used for T.4 transmit and receive. This variable
records which mode is in progress. */
int rx;
/*! \brief The type of compression used between the FAX machines. */
int line_encoding;
/*! \brief The time at which handling of the current page began. */
time_t page_start_time;
/*! \brief The size of the compressed image on the line side, in bits. */
int line_image_size;
/*! \brief The current number of bytes per row of uncompressed image data. */
int bytes_per_row;
/*! \brief The size of the image in the image buffer, in bytes. */
int image_size;
/*! \brief The current size of the image buffer. */
int image_buffer_size;
/*! \brief A point to the image buffer. */
uint8_t *image_buffer;
/*! \brief The number of pages transferred to date. */
int current_page;
/*! \brief Column-to-column (X) resolution in pixels per metre. */
int x_resolution;
/*! \brief Row-to-row (Y) resolution in pixels per metre. */
int y_resolution;
/*! \brief Width of the current page, in pixels. */
int image_width;
/*! \brief Length of the current page, in pixels. */
int image_length;
/*! \brief Current pixel row number. */
int row;
/*! \brief This variable is set if we are treating the current row as a 2D encoded
one. */
int row_is_2d;
/*! \brief The current length of the current row. */
int row_len;
/*! \brief Black and white run-lengths for the current row. */
uint32_t *cur_runs;
/*! \brief Black and white run-lengths for the reference row. */
uint32_t *ref_runs;
/*! \brief Pointer to the buffer for the current pixel row. */
uint8_t *row_buf;
/*! \brief Encoded data bits buffer. */
uint32_t tx_bitstream;
/*! \brief The number of bits currently in tx_bitstream. */
int tx_bits;
/*! \brief The current number of bits in the current encoded row. */
int row_bits;
/*! \brief The minimum bits in any row of the current page. For monitoring only. */
int min_row_bits;
/*! \brief The maximum bits in any row of the current page. For monitoring only. */
int max_row_bits;
/*! \brief Error and flow logging control */
logging_state_t logging;
/*! \brief All TIFF file specific state information for the T.4 context. */
t4_tiff_state_t tiff;
t4_t6_decode_state_t t4_t6_rx;
t4_t6_encode_state_t t4_t6_tx;
};
#endif
/*- End of file ------------------------------------------------------------*/
+2 -2
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v18.h,v 1.4 2009/04/11 15:16:14 steveu Exp $
* $Id: v18.h,v 1.5 2009/11/04 15:52:06 steveu Exp $
*/
#if !defined(_SPANDSP_PRIVATE_V18_H_)
@@ -31,7 +31,7 @@
struct v18_state_s
{
/*! \brief TRUE if we are the calling modem */
int caller;
int calling_party;
int mode;
put_msg_func_t put_msg;
void *user_data;
+2 -2
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v22bis.h,v 1.11 2009/07/09 13:52:09 steveu Exp $
* $Id: v22bis.h,v 1.12 2009/11/04 15:52:06 steveu Exp $
*/
#if !defined(_SPANDSP_PRIVATE_V22BIS_H_)
@@ -76,7 +76,7 @@ struct v22bis_state_s
/*! \brief The maximum permitted bit rate of the modem. Valid values are 1200 and 2400. */
int bit_rate;
/*! \brief TRUE is this is the calling side modem. */
int caller;
int calling_party;
/*! \brief The callback function used to get the next bit to be transmitted. */
get_bit_func_t get_bit;
/*! \brief A user specified opaque pointer passed to the get_bit callback routine. */
+2 -2
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v42.h,v 1.1 2008/11/15 14:43:08 steveu Exp $
* $Id: v42.h,v 1.2 2009/11/04 15:52:06 steveu Exp $
*/
#if !defined(_SPANDSP_PRIVATE_V42_H_)
@@ -92,7 +92,7 @@ struct lapm_state_s
struct v42_state_s
{
/*! TRUE if we are the calling party, otherwise FALSE */
int caller;
int calling_party;
/*! TRUE if we should detect whether the far end is V.42 capable. FALSE if we go
directly to protocol establishment */
int detect;
+15 -19
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v8.h,v 1.1 2008/10/13 13:14:01 steveu Exp $
* $Id: v8.h,v 1.3 2009/11/04 15:52:06 steveu Exp $
*/
#if !defined(_SPANDSP_PRIVATE_V8_H_)
@@ -31,9 +31,15 @@
struct v8_state_s
{
/*! \brief TRUE if we are the calling modem */
int caller;
/*! \brief The current state of the V8 protocol */
int calling_party;
v8_result_handler_t *result_handler;
void *result_handler_user_data;
/*! \brief The current state of the V.8 protocol */
int state;
int fsk_tx_on;
int modem_connect_tone_tx_on;
int negotiation_timer;
int ci_timer;
int ci_count;
@@ -43,24 +49,14 @@ struct v8_state_s
modem_connect_tones_tx_state_t ansam_tx;
modem_connect_tones_rx_state_t ansam_rx;
v8_result_handler_t *result_handler;
void *result_handler_user_data;
/*! \brief Modulation schemes available at this end. */
int available_modulations;
int local_end_modulations;
int common_modulations;
int negotiated_modulation;
int far_end_modulations;
int call_function;
int protocol;
int pstn_access;
int nsf_seen;
int pcm_modem_availability;
int t66_seen;
/* V8 data parsing */
unsigned int bit_stream;
v8_result_t result;
/* V.8 data parsing */
uint32_t bit_stream;
int bit_cnt;
/* Indicates the type of message coming up */
int preamble_type;
@@ -70,7 +66,7 @@ struct v8_state_s
/*! \brief a reference copy of the last CM or JM message, used when
testing for matches. */
uint8_t cm_jm_data[64];
int cm_jm_count;
int cm_jm_len;
int got_cm_jm;
int got_cj;
int zero_byte_count;
+9 -7
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t30.h,v 1.126 2009/09/21 15:52:39 steveu Exp $
* $Id: t30.h,v 1.126.4.1 2009/12/19 09:47:56 steveu Exp $
*/
/*! \file */
@@ -347,7 +347,7 @@ enum
T30_SUPPORT_V17 = 0x04,
/*! Support the V.34 modem (up to 33,600bps) for image transfer. */
T30_SUPPORT_V34 = 0x08,
/*! Support the Internet Aware FAX mode (no bit rate limit) for image transfer. */
/*! Support the Internet aware FAX mode (no bit rate limit) for image transfer. */
T30_SUPPORT_IAF = 0x10
};
@@ -361,16 +361,18 @@ enum
T30_SUPPORT_T4_2D_COMPRESSION = 0x04,
/*! T.6 2D compression */
T30_SUPPORT_T6_COMPRESSION = 0x08,
/*! T.85 monochrome JBIG coding */
/*! T.85 monochrome JBIG compression */
T30_SUPPORT_T85_COMPRESSION = 0x10,
/*! T.43 colour JBIG coding */
/*! T.43 colour JBIG compression */
T30_SUPPORT_T43_COMPRESSION = 0x20,
/*! T.45 run length colour compression */
T30_SUPPORT_T45_COMPRESSION = 0x40,
/*! T.81 + T.30 Annex E colour JPEG coding */
/*! T.81 + T.30 Annex E colour JPEG compression */
T30_SUPPORT_T81_COMPRESSION = 0x80,
/*! T.81 + T.30 Annex K colour sYCC-JPEG coding */
T30_SUPPORT_SYCC_T81_COMPRESSION = 0x100
/*! T.81 + T.30 Annex K colour sYCC-JPEG compression */
T30_SUPPORT_SYCC_T81_COMPRESSION = 0x100,
/*! T.88 monochrome JBIG2 compression */
T30_SUPPORT_T88_COMPRESSION = 0x200
};
enum
+2 -2
View File
@@ -1,7 +1,7 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* fcf.h - ITU T.30 fax control field definitions
* t30_fcf.h - ITU T.30 fax control field definitions
*
* Written by Steve Underwood <steveu@coppice.org>
*
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t30_fcf.h,v 1.17 2008/08/03 03:44:00 steveu Exp $
* $Id: t30_fcf.h,v 1.18 2009/10/08 15:14:31 steveu Exp $
*/
/*! \file */
+31 -2
View File
@@ -23,7 +23,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t38_non_ecm_buffer.h,v 1.7 2009/02/10 13:06:47 steveu Exp $
* $Id: t38_non_ecm_buffer.h,v 1.7.4.1 2009/12/19 06:43:28 steveu Exp $
*/
/*! \file */
@@ -35,9 +35,38 @@
\section t38_non_ecm_buffer_page_sec_1 What does it do?
The T.38 rate adapting non-ECM image data buffer is used to buffer TCF and non-ECM
FAX image data being gatewayed from a T.38 linke to an analogue FAX modem link.
FAX image data being gatewayed from a T.38 link to an analogue FAX modem link.
As well as rate adapting, the buffer has the ability to impose a minimum on the number
of bits per row of image data. This allows any row padding zeros to be stripped from
the data stream, to minimise the data sent as T.38 packets, and be reinserted before
the data is sent to its final destination. Not all T.38 implementations support this
feature, so it's use must be negotiated.
\section t38_non_ecm_buffer_page_sec_2 How does it work?
When inserting padding bits, whether to ensure a minimum row time or for flow control,
it is important the right value is inserted at the right point in the data sequence.
If we are in the optional initial period of all ones, we can insert a byte of extra
ones at any time. Once we pass that initial stage, TCF and image data need separate
handling.
TCF data is all zeros. Once the period of all zeros has begun it is OK to insert
additional bytes of zeros at any point.
Image data consists of rows, separated by EOL (end of line) markers. Inserting
zeros at arbitrary times would corrupt the image. However, it is OK to insert a
considerable number of extra zeros just before an EOL. Therefore we track where the
EOL markers occur as we fill the buffer. As we empty the buffer stop outputting real
data, and start outputting bytes of zero, if we reach this last EOL marker location.
The EOL marker is 11 zeros following by 1 (1D mode) or 2 (2D mode) ones. Therefore, it
always spills across 2 bytes in the buffer, and there is always a point where we can
insert our extra zeros between bytes.
Padding between the group of successive EOL markers which for the RTC (return to control)
marker that ends an image causes some FAX machines not to recognise them as an RTC condition.
Therefore, our padding applies special protection so padding never occurs between two
successive EOL markers, with no pixel data between them.
*/
/*! The buffer length much be a power of two. The chosen length is big enough for
+344
View File
@@ -0,0 +1,344 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* t4_rx.h - definitions for T.4 FAX receive processing
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t4_rx.h,v 1.3.2.3 2009/12/21 17:18:40 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_T4_RX_H_)
#define _SPANDSP_T4_RX_H_
/*! \page t4_page T.4 image compression and decompression
\section t4_page_sec_1 What does it do?
The T.4 image compression and decompression routines implement the 1D and 2D
encoding methods defined in ITU specification T.4. They also implement the pure
2D encoding method defined in T.6. These are image compression algorithms used
for FAX transmission.
\section t4_page_sec_1 How does it work?
*/
typedef int (*t4_row_write_handler_t)(void *user_data, const uint8_t buf[], size_t len);
/*! Supported compression modes. */
typedef enum
{
/*! No compression */
T4_COMPRESSION_NONE = 0,
/*! T.1 1D compression */
T4_COMPRESSION_ITU_T4_1D = 1,
/*! T.4 2D compression */
T4_COMPRESSION_ITU_T4_2D = 2,
/*! T.6 2D compression */
T4_COMPRESSION_ITU_T6 = 3,
/*! T.85 monochrome JBIG coding */
T4_COMPRESSION_ITU_T85 = 4,
/*! T.43 colour JBIG coding */
T4_COMPRESSION_ITU_T43 = 5,
/*! T.45 run length colour compression */
T4_COMPRESSION_ITU_T45 = 6,
/*! T.81 + T.30 Annex E colour JPEG coding */
T4_COMPRESSION_ITU_T81 = 7,
/*! T.81 + T.30 Annex K colour sYCC-JPEG coding */
T4_COMPRESSION_ITU_SYCC_T81 = 8
} t4_image_compression_t;
/*! Supported X resolutions, in pixels per metre. */
typedef enum
{
T4_X_RESOLUTION_R4 = 4016,
T4_X_RESOLUTION_R8 = 8031,
T4_X_RESOLUTION_300 = 11811,
T4_X_RESOLUTION_R16 = 16063,
T4_X_RESOLUTION_600 = 23622,
T4_X_RESOLUTION_800 = 31496,
T4_X_RESOLUTION_1200 = 47244
} t4_image_x_resolution_t;
/*! Supported Y resolutions, in pixels per metre. */
typedef enum
{
T4_Y_RESOLUTION_STANDARD = 3850,
T4_Y_RESOLUTION_FINE = 7700,
T4_Y_RESOLUTION_300 = 11811,
T4_Y_RESOLUTION_SUPERFINE = 15400, /* 400 is 15748 */
T4_Y_RESOLUTION_600 = 23622,
T4_Y_RESOLUTION_800 = 31496,
T4_Y_RESOLUTION_1200 = 47244
} t4_image_y_resolution_t;
/*!
Exact widths in PELs for the difference resolutions, and page widths.
Note:
The A4 widths also apply to North American letter and legal.
The R4 resolution widths are not supported in recent versions of T.30
Only images of exactly these widths are acceptable for FAX transmisson.
R4 864 pels/215mm for ISO A4, North American Letter and Legal
R4 1024 pels/255mm for ISO B4
R4 1216 pels/303mm for ISO A3
R8 1728 pels/215mm for ISO A4, North American Letter and Legal
R8 2048 pels/255mm for ISO B4
R8 2432 pels/303mm for ISO A3
R16 3456 pels/215mm for ISO A4, North American Letter and Legal
R16 4096 pels/255mm for ISO B4
R16 4864 pels/303mm for ISO A3
*/
typedef enum
{
T4_WIDTH_R4_A4 = 864,
T4_WIDTH_R4_B4 = 1024,
T4_WIDTH_R4_A3 = 1216,
T4_WIDTH_R8_A4 = 1728,
T4_WIDTH_R8_B4 = 2048,
T4_WIDTH_R8_A3 = 2432,
T4_WIDTH_300_A4 = 2592,
T4_WIDTH_300_B4 = 3072,
T4_WIDTH_300_A3 = 3648,
T4_WIDTH_R16_A4 = 3456,
T4_WIDTH_R16_B4 = 4096,
T4_WIDTH_R16_A3 = 4864,
T4_WIDTH_600_A4 = 5184,
T4_WIDTH_600_B4 = 6144,
T4_WIDTH_600_A3 = 7296,
T4_WIDTH_1200_A4 = 10368,
T4_WIDTH_1200_B4 = 12288,
T4_WIDTH_1200_A3 = 14592
} t4_image_width_t;
/*!
Length of the various supported paper sizes, in pixels at the various Y resolutions.
Paper sizes are
A4 (215mm x 297mm)
B4 (255mm x 364mm)
A3 (303mm x 418.56mm)
North American Letter (215.9mm x 279.4mm)
North American Legal (215.9mm x 355.6mm)
Unlimited
T.4 does not accurately define the maximum number of scan lines in a page. A wide
variety of maximum row counts are used in the real world. It is important not to
set our sending limit too high, or a receiving machine might split pages. It is
important not to set it too low, or we might clip pages.
Values seen for standard resolution A4 pages include 1037, 1045, 1109, 1126 and 1143.
1109 seems the most-popular. At fine res 2150, 2196, 2200, 2237, 2252-2262, 2264,
2286, and 2394 are used. 2255 seems the most popular. We try to use balanced choices
here.
*/
typedef enum
{
/* A4 is 297mm long */
T4_LENGTH_STANDARD_A4 = 1143,
T4_LENGTH_FINE_A4 = 2286,
T4_LENGTH_300_A4 = 4665,
T4_LENGTH_SUPERFINE_A4 = 4573,
T4_LENGTH_600_A4 = 6998,
T4_LENGTH_800_A4 = 9330,
T4_LENGTH_1200_A4 = 13996,
/* B4 is 364mm long */
T4_LENGTH_STANDARD_B4 = 1401,
T4_LENGTH_FINE_B4 = 2802,
T4_LENGTH_300_B4 = 0,
T4_LENGTH_SUPERFINE_B4 = 5605,
T4_LENGTH_600_B4 = 0,
T4_LENGTH_800_B4 = 0,
T4_LENGTH_1200_B4 = 0,
/* North American letter is 279.4mm long */
T4_LENGTH_STANDARD_US_LETTER = 1075,
T4_LENGTH_FINE_US_LETTER = 2151,
T4_LENGTH_300_US_LETTER = 0,
T4_LENGTH_SUPERFINE_US_LETTER = 4302,
T4_LENGTH_600_US_LETTER = 0,
T4_LENGTH_800_US_LETTER = 0,
T4_LENGTH_1200_US_LETTER = 0,
/* North American legal is 355.6mm long */
T4_LENGTH_STANDARD_US_LEGAL = 1369,
T4_LENGTH_FINE_US_LEGAL = 2738,
T4_LENGTH_300_US_LEGAL = 0,
T4_LENGTH_SUPERFINE_US_LEGAL = 5476,
T4_LENGTH_600_US_LEGAL = 0,
T4_LENGTH_800_US_LEGAL = 0,
T4_LENGTH_1200_US_LEGAL = 0
} t4_image_length_t;
/*!
T.4 FAX compression/decompression descriptor. This defines the working state
for a single instance of a T.4 FAX compression or decompression channel.
*/
typedef struct t4_state_s t4_state_t;
/*!
T.4 FAX compression/decompression statistics.
*/
typedef struct
{
/*! \brief The number of pages transferred so far. */
int pages_transferred;
/*! \brief The number of pages in the file (<0 if unknown). */
int pages_in_file;
/*! \brief The number of horizontal pixels in the most recent page. */
int width;
/*! \brief The number of vertical pixels in the most recent page. */
int length;
/*! \brief The number of bad pixel rows in the most recent page. */
int bad_rows;
/*! \brief The largest number of bad pixel rows in a block in the most recent page. */
int longest_bad_row_run;
/*! \brief The horizontal resolution of the page in pixels per metre */
int x_resolution;
/*! \brief The vertical resolution of the page in pixels per metre */
int y_resolution;
/*! \brief The type of compression used between the FAX machines */
int encoding;
/*! \brief The size of the image on the line, in bytes */
int line_image_size;
} t4_stats_t;
#if defined(__cplusplus)
extern "C" {
#endif
/*! \brief Prepare for reception of a document.
\param s The T.4 context.
\param file The name of the file to be received.
\param output_encoding The output encoding.
\return A pointer to the context, or NULL if there was a problem. */
SPAN_DECLARE(t4_state_t *) t4_rx_init(t4_state_t *s, const char *file, int output_encoding);
/*! \brief Prepare to receive the next page of the current document.
\param s The T.4 context.
\return zero for success, -1 for failure. */
SPAN_DECLARE(int) t4_rx_start_page(t4_state_t *s);
/*! \brief Put a bit of the current document page.
\param s The T.4 context.
\param bit The data bit.
\return TRUE when the bit ends the document page, otherwise FALSE. */
SPAN_DECLARE(int) t4_rx_put_bit(t4_state_t *s, int bit);
/*! \brief Put a byte of the current document page.
\param s The T.4 context.
\param byte The data byte.
\return TRUE when the byte ends the document page, otherwise FALSE. */
SPAN_DECLARE(int) t4_rx_put_byte(t4_state_t *s, uint8_t byte);
/*! \brief Put a byte of the current document page.
\param s The T.4 context.
\param buf The buffer containing the chunk.
\param len The length of the chunk.
\return TRUE when the byte ends the document page, otherwise FALSE. */
SPAN_DECLARE(int) t4_rx_put_chunk(t4_state_t *s, const uint8_t buf[], int len);
/*! \brief Complete the reception of a page.
\param s The T.4 receive context.
\return 0 for success, otherwise -1. */
SPAN_DECLARE(int) t4_rx_end_page(t4_state_t *s);
/*! \brief End reception of a document. Tidy up and close the file.
This should be used to end T.4 reception started with
t4_rx_init.
\param s The T.4 receive context.
\return 0 for success, otherwise -1. */
SPAN_DECLARE(int) t4_rx_release(t4_state_t *s);
/*! \brief End reception of a document. Tidy up, close the file and
free the context. This should be used to end T.4 reception
started with t4_rx_init.
\param s The T.4 receive context.
\return 0 for success, otherwise -1. */
SPAN_DECLARE(int) t4_rx_free(t4_state_t *s);
/*! \brief Set the row write handler for a T.4 receive context.
\param s The T.4 receive context.
\param handler A pointer to the handler routine.
\param user_data An opaque pointer passed to the handler routine.
\return 0 for success, otherwise -1. */
SPAN_DECLARE(int) t4_rx_set_row_write_handler(t4_state_t *s, t4_row_write_handler_t handler, void *user_data);
/*! \brief Set the encoding for the received data.
\param s The T.4 context.
\param encoding The encoding. */
SPAN_DECLARE(void) t4_rx_set_rx_encoding(t4_state_t *s, int encoding);
/*! \brief Set the expected width of the received image, in pixel columns.
\param s The T.4 context.
\param width The number of pixels across the image. */
SPAN_DECLARE(void) t4_rx_set_image_width(t4_state_t *s, int width);
/*! \brief Set the row-to-row (y) resolution to expect for a received image.
\param s The T.4 context.
\param resolution The resolution, in pixels per metre. */
SPAN_DECLARE(void) t4_rx_set_y_resolution(t4_state_t *s, int resolution);
/*! \brief Set the column-to-column (x) resolution to expect for a received image.
\param s The T.4 context.
\param resolution The resolution, in pixels per metre. */
SPAN_DECLARE(void) t4_rx_set_x_resolution(t4_state_t *s, int resolution);
/*! \brief Set the DCS information of the fax, for inclusion in the file.
\param s The T.4 context.
\param dcs The DCS information, formatted as an ASCII string. */
SPAN_DECLARE(void) t4_rx_set_dcs(t4_state_t *s, const char *dcs);
/*! \brief Set the sub-address of the fax, for inclusion in the file.
\param s The T.4 context.
\param sub_address The sub-address string. */
SPAN_DECLARE(void) t4_rx_set_sub_address(t4_state_t *s, const char *sub_address);
/*! \brief Set the identity of the remote machine, for inclusion in the file.
\param s The T.4 context.
\param ident The identity string. */
SPAN_DECLARE(void) t4_rx_set_far_ident(t4_state_t *s, const char *ident);
/*! \brief Set the vendor of the remote machine, for inclusion in the file.
\param s The T.4 context.
\param vendor The vendor string, or NULL. */
SPAN_DECLARE(void) t4_rx_set_vendor(t4_state_t *s, const char *vendor);
/*! \brief Set the model of the remote machine, for inclusion in the file.
\param s The T.4 context.
\param model The model string, or NULL. */
SPAN_DECLARE(void) t4_rx_set_model(t4_state_t *s, const char *model);
/*! Get the current image transfer statistics.
\brief Get the current transfer statistics.
\param s The T.4 context.
\param t A pointer to a statistics structure. */
SPAN_DECLARE(void) t4_get_transfer_statistics(t4_state_t *s, t4_stats_t *t);
/*! Get the short text name of an encoding format.
\brief Get the short text name of an encoding format.
\param encoding The encoding type.
\return A pointer to the string. */
SPAN_DECLARE(const char *) t4_encoding_to_str(int encoding);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/
+179
View File
@@ -0,0 +1,179 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* t4_tx.h - definitions for T.4 FAX transmit processing
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t4_tx.h,v 1.2.2.3 2009/12/21 17:18:40 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_T4_TX_H_)
#define _SPANDSP_T4_TX_H_
typedef int (*t4_row_read_handler_t)(void *user_data, uint8_t buf[], size_t len);
#if defined(__cplusplus)
extern "C" {
#endif
/*! \brief Prepare for transmission of a document.
\param s The T.4 context.
\param file The name of the file to be sent.
\param start_page The first page to send. -1 for no restriction.
\param stop_page The last page to send. -1 for no restriction.
\return A pointer to the context, or NULL if there was a problem. */
SPAN_DECLARE(t4_state_t *) t4_tx_init(t4_state_t *s, const char *file, int start_page, int stop_page);
/*! \brief Prepare to send the next page of the current document.
\param s The T.4 context.
\return zero for success, -1 for failure. */
SPAN_DECLARE(int) t4_tx_start_page(t4_state_t *s);
/*! \brief Prepare the current page for a resend.
\param s The T.4 context.
\return zero for success, -1 for failure. */
SPAN_DECLARE(int) t4_tx_restart_page(t4_state_t *s);
/*! \brief Check for the existance of the next page, and whether its format is like the
current one. This information can be needed before it is determined that the current
page is finished with.
\param s The T.4 context.
\return 0 for next page found with the same format as the current page.
1 for next page found with different format from the current page.
-1 for no page found, or file failure. */
SPAN_DECLARE(int) t4_tx_next_page_has_different_format(t4_state_t *s);
/*! \brief Complete the sending of a page.
\param s The T.4 context.
\return zero for success, -1 for failure. */
SPAN_DECLARE(int) t4_tx_end_page(t4_state_t *s);
/*! \brief Return the next bit of the current document page, without actually
moving forward in the buffer. The document will be padded for the
current minimum scan line time.
\param s The T.4 context.
\return The next bit (i.e. 0 or 1). For the last bit of data, bit 1 is
set (i.e. the returned value is 2 or 3). */
SPAN_DECLARE(int) t4_tx_check_bit(t4_state_t *s);
/*! \brief Get the next bit of the current document page. The document will
be padded for the current minimum scan line time.
\param s The T.4 context.
\return The next bit (i.e. 0 or 1). For the last bit of data, bit 1 is
set (i.e. the returned value is 2 or 3). */
SPAN_DECLARE(int) t4_tx_get_bit(t4_state_t *s);
/*! \brief Get the next byte of the current document page. The document will
be padded for the current minimum scan line time.
\param s The T.4 context.
\return The next byte. For the last byte of data, bit 8 is
set. In this case, one or more bits of the byte may be padded with
zeros, to complete the byte. */
SPAN_DECLARE(int) t4_tx_get_byte(t4_state_t *s);
/*! \brief Get the next chunk of the current document page. The document will
be padded for the current minimum scan line time.
\param s The T.4 context.
\param buf The buffer into which the chunk is to written.
\param max_len The maximum length of the chunk.
\return The actual length of the chunk. If this is less than max_len it
indicates that the end of the document has been reached. */
SPAN_DECLARE(int) t4_tx_get_chunk(t4_state_t *s, uint8_t buf[], int max_len);
/*! \brief End the transmission of a document. Tidy up and close the file.
This should be used to end T.4 transmission started with t4_tx_init.
\param s The T.4 context.
\return 0 for success, otherwise -1. */
SPAN_DECLARE(int) t4_tx_release(t4_state_t *s);
/*! \brief End the transmission of a document. Tidy up, close the file and
free the context. This should be used to end T.4 transmission
started with t4_tx_init.
\param s The T.4 context.
\return 0 for success, otherwise -1. */
SPAN_DECLARE(int) t4_tx_free(t4_state_t *s);
/*! \brief Set the encoding for the encoded data.
\param s The T.4 context.
\param encoding The encoding. */
SPAN_DECLARE(void) t4_tx_set_tx_encoding(t4_state_t *s, int encoding);
/*! \brief Set the minimum number of encoded bits per row. This allows the
makes the encoding process to be set to comply with the minimum row
time specified by a remote receiving machine.
\param s The T.4 context.
\param bits The minimum number of bits per row. */
SPAN_DECLARE(void) t4_tx_set_min_row_bits(t4_state_t *s, int bits);
/*! \brief Set the identity of the local machine, for inclusion in page headers.
\param s The T.4 context.
\param ident The identity string. */
SPAN_DECLARE(void) t4_tx_set_local_ident(t4_state_t *s, const char *ident);
/*! Set the info field, included in the header line included in each page of an encoded
FAX. This is a string of up to 50 characters. Other information (date, local ident, etc.)
are automatically included in the header. If the header info is set to NULL or a zero
length string, no header lines will be added to the encoded FAX.
\brief Set the header info.
\param s The T.4 context.
\param info A string, of up to 50 bytes, which will form the info field. */
SPAN_DECLARE(void) t4_tx_set_header_info(t4_state_t *s, const char *info);
/*! \brief Set the row read handler for a T.4 transmit context.
\param s The T.4 transmit context.
\param handler A pointer to the handler routine.
\param user_data An opaque pointer passed to the handler routine.
\return 0 for success, otherwise -1. */
SPAN_DECLARE(int) t4_tx_set_row_read_handler(t4_state_t *s, t4_row_read_handler_t handler, void *user_data);
/*! \brief Get the row-to-row (y) resolution of the current page.
\param s The T.4 context.
\return The resolution, in pixels per metre. */
SPAN_DECLARE(int) t4_tx_get_y_resolution(t4_state_t *s);
/*! \brief Get the column-to-column (x) resolution of the current page.
\param s The T.4 context.
\return The resolution, in pixels per metre. */
SPAN_DECLARE(int) t4_tx_get_x_resolution(t4_state_t *s);
/*! \brief Get the width of the current page, in pixel columns.
\param s The T.4 context.
\return The number of columns. */
SPAN_DECLARE(int) t4_tx_get_image_width(t4_state_t *s);
/*! \brief Get the number of pages in the file.
\param s The T.4 context.
\return The number of pages, or -1 if there is an error. */
SPAN_DECLARE(int) t4_tx_get_pages_in_file(t4_state_t *s);
/*! \brief Get the currnet page number in the file.
\param s The T.4 context.
\return The page number, or -1 if there is an error. */
SPAN_DECLARE(int) t4_tx_get_current_page_in_file(t4_state_t *s);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/
+3 -3
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: telephony.h,v 1.18 2009/03/23 14:17:42 steveu Exp $
* $Id: telephony.h,v 1.18.4.2 2009/12/21 18:38:06 steveu Exp $
*/
#if !defined(_SPANDSP_TELEPHONY_H_)
@@ -69,8 +69,8 @@ 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 ms_to_samples(t) (((t)*SAMPLE_RATE)/1000)
#define us_to_samples(t) (((t)*SAMPLE_RATE)/1000000)
#define ms_to_samples(t) ((t)*(SAMPLE_RATE/1000))
#define us_to_samples(t) ((t)/(1000000/SAMPLE_RATE))
#if !defined(FALSE)
#define FALSE 0
+3 -3
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v18.h,v 1.5 2009/06/02 16:03:56 steveu Exp $
* $Id: v18.h,v 1.6 2009/11/04 15:52:06 steveu Exp $
*/
/*! \file */
@@ -69,14 +69,14 @@ SPAN_DECLARE(logging_state_t *) v18_get_logging_state(v18_state_t *s);
/*! Initialise a V.18 context.
\brief Initialise a V.18 context.
\param s The V.18 context.
\param caller TRUE if caller mode, else answerer mode.
\param calling_party TRUE if caller mode, else answerer mode.
\param mode Mode of operation.
\param put_msg A callback routine called to deliver the received text
to the application.
\param user_data An opaque pointer for the callback routine.
\return A pointer to the V.18 context, or NULL if there was a problem. */
SPAN_DECLARE(v18_state_t *) v18_init(v18_state_t *s,
int caller,
int calling_party,
int mode,
put_msg_func_t put_msg,
void *user_data);
+3 -3
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v22bis.h,v 1.45 2009/07/09 13:52:09 steveu Exp $
* $Id: v22bis.h,v 1.46 2009/11/04 15:52:06 steveu Exp $
*/
/*! \file */
@@ -164,7 +164,7 @@ SPAN_DECLARE(int) v22bis_current_bit_rate(v22bis_state_t *s);
\param s The modem context.
\param bit_rate The bit rate of the modem. Valid values are 1200 and 2400.
\param guard The guard tone option. 0 = none, 1 = 550Hz, 2 = 1800Hz.
\param caller TRUE if this is the calling modem.
\param calling_party TRUE if this is the calling modem.
\param get_bit The callback routine used to get the data to be transmitted.
\param put_bit The callback routine used to get the data to be transmitted.
\param user_data An opaque pointer, passed in calls to the get and put routines.
@@ -172,7 +172,7 @@ SPAN_DECLARE(int) v22bis_current_bit_rate(v22bis_state_t *s);
SPAN_DECLARE(v22bis_state_t *) v22bis_init(v22bis_state_t *s,
int bit_rate,
int guard,
int caller,
int calling_party,
get_bit_func_t get_bit,
void *get_bit_user_data,
put_bit_func_t put_bit,
+3 -3
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v42.h,v 1.30 2009/02/10 13:06:47 steveu Exp $
* $Id: v42.h,v 1.31 2009/11/04 15:52:06 steveu Exp $
*/
/*! \page v42_page V.42 modem error correction
@@ -130,12 +130,12 @@ SPAN_DECLARE(int) v42_tx_bit(void *user_data);
/*! Initialise a V.42 context.
\param s The V.42 context.
\param caller TRUE if caller mode, else answerer mode.
\param calling_party TRUE if caller mode, else answerer mode.
\param frame_handler A callback function to handle received frames of data.
\param user_data An opaque pointer passed to the frame handler routine.
\return ???
*/
SPAN_DECLARE(v42_state_t *) v42_init(v42_state_t *s, int caller, int detect, v42_frame_handler_t frame_handler, void *user_data);
SPAN_DECLARE(v42_state_t *) v42_init(v42_state_t *s, int calling_party, int detect, v42_frame_handler_t frame_handler, void *user_data);
/*! Restart a V.42 context.
\param s The V.42 context.
+24 -17
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v8.h,v 1.28 2009/06/02 16:03:56 steveu Exp $
* $Id: v8.h,v 1.31 2009/11/04 16:10:14 steveu Exp $
*/
/*! \file */
@@ -50,13 +50,13 @@ typedef void (v8_result_handler_t)(void *user_data, v8_result_t *result);
enum v8_call_function_e
{
V8_CALL_TBS = 0,
V8_CALL_H324,
V8_CALL_V18,
V8_CALL_T101,
V8_CALL_T30_TX,
V8_CALL_T30_RX,
V8_CALL_V_SERIES,
V8_CALL_FUNCTION_EXTENSION
V8_CALL_H324 = 1,
V8_CALL_V18 = 2,
V8_CALL_T101 = 3,
V8_CALL_T30_TX = 4,
V8_CALL_T30_RX = 5,
V8_CALL_V_SERIES = 6,
V8_CALL_FUNCTION_EXTENSION = 7
};
enum v8_modulation_e
@@ -88,30 +88,33 @@ enum v8_protocol_e
enum v8_pstn_access_e
{
V8_PSTN_ACCESS_CALL_DCE_CELLULAR = 0x20,
V8_PSTN_ACCESS_ANSWER_DCE_CELLULAR = 0x40,
V8_PSTN_ACCESS_DCE_ON_DIGTIAL = 0x80
V8_PSTN_ACCESS_CALL_DCE_CELLULAR = 0x01,
V8_PSTN_ACCESS_ANSWER_DCE_CELLULAR = 0x02,
V8_PSTN_ACCESS_DCE_ON_DIGITAL = 0x04
};
enum v8_pcm_modem_availability_e
{
V8_PSTN_PCM_MODEM_V90_V92_ANALOGUE = 0x20,
V8_PSTN_PCM_MODEM_V90_V92_DIGITAL = 0x40,
V8_PSTN_PCM_MODEM_V91 = 0x80
V8_PSTN_PCM_MODEM_V90_V92_ANALOGUE = 0x01,
V8_PSTN_PCM_MODEM_V90_V92_DIGITAL = 0x02,
V8_PSTN_PCM_MODEM_V91 = 0x04
};
typedef struct v8_state_s v8_state_t;
struct v8_result_s
{
int modem_connect_tone_detected;
int call_function;
int available_modulations;
int far_end_modulations;
int negotiated_modulation;
int protocol;
int pstn_access;
int nsf_seen;
int nsf;
int pcm_modem_availability;
int t66_seen;
int t66;
};
#if defined(__cplusplus)
@@ -122,14 +125,16 @@ extern "C"
/*! Initialise a V.8 context.
\brief Initialise a V.8 context.
\param s The V.8 context.
\param caller TRUE if caller mode, else answerer mode.
\param calling_party TRUE if caller mode, else answerer mode.
\param use_ansam_pr TRUE if ANSam/ is to be used, else ANSam will be used.
\param available_modulations A bitwise list of the modulation schemes to be
advertised as available here.
\param result_handler The callback routine used to handle the results of negotiation.
\param user_data An opaque pointer passed to the result_handler routine.
\return A pointer to the V.8 context, or NULL if there was a problem. */
SPAN_DECLARE(v8_state_t *) v8_init(v8_state_t *s,
int caller,
int calling_party,
int use_ansam_pr,
int available_modulations,
v8_result_handler_t *result_handler,
void *user_data);
@@ -175,7 +180,9 @@ SPAN_DECLARE(const char *) v8_call_function_to_str(int call_function);
SPAN_DECLARE(const char *) v8_modulation_to_str(int modulation_scheme);
SPAN_DECLARE(const char *) v8_protocol_to_str(int protocol);
SPAN_DECLARE(const char *) v8_pstn_access_to_str(int pstn_access);
SPAN_DECLARE(const char *) v8_nsf_to_str(int nsf);
SPAN_DECLARE(const char *) v8_pcm_modem_availability_to_str(int pcm_modem_availability);
SPAN_DECLARE(const char *) v8_t66_to_str(int t66);
#if defined(__cplusplus)
}
+9 -9
View File
@@ -10,19 +10,19 @@
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: version.h.in,v 1.3 2009/03/01 12:39:02 steveu Exp $
* $Id: version.h.in,v 1.3.4.1 2009/12/19 09:47:56 steveu Exp $
*/
#if !defined(_SPANDSP_VERSION_H_)
@@ -30,9 +30,9 @@
/* The date and time of the version are in UTC form. */
#define SPANDSP_RELEASE_DATE 20091005
#define SPANDSP_RELEASE_TIME 163835
#define SPANDSP_RELEASE_DATETIME_STRING "20091005 163835"
#define SPANDSP_RELEASE_DATE 20091221
#define SPANDSP_RELEASE_TIME 183911
#define SPANDSP_RELEASE_DATETIME_STRING "20091221 183911"
#endif
/*- End of file ------------------------------------------------------------*/
+6 -6
View File
@@ -10,19 +10,19 @@
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: version.h.in,v 1.3 2009/03/01 12:39:02 steveu Exp $
* $Id: version.h.in,v 1.3.4.1 2009/12/19 09:47:56 steveu Exp $
*/
#if !defined(_SPANDSP_VERSION_H_)
+16 -1
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: super_tone_rx.c,v 1.33 2009/02/10 13:06:46 steveu Exp $
* $Id: super_tone_rx.c,v 1.33.4.1 2009/12/19 09:47:56 steveu Exp $
*/
/*! \file */
@@ -218,8 +218,23 @@ SPAN_DECLARE(super_tone_rx_descriptor_t *) super_tone_rx_make_descriptor(super_t
SPAN_DECLARE(int) super_tone_rx_free_descriptor(super_tone_rx_descriptor_t *desc)
{
int i;
if (desc)
{
for (i = 0; i < desc->tones; i++)
{
if (desc->tone_list[i])
free(desc->tone_list[i]);
}
if (desc->tone_list)
free(desc->tone_list);
if (desc->tone_segs)
free(desc->tone_segs);
if (desc->desc)
free(desc->desc);
free(desc);
}
return 0;
}
/*- End of function --------------------------------------------------------*/
+273 -218
View File
File diff suppressed because it is too large Load Diff
+7 -5
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t30_api.c,v 1.13 2009/02/03 16:28:40 steveu Exp $
* $Id: t30_api.c,v 1.13.4.2 2009/12/19 14:18:13 steveu Exp $
*/
/*! \file */
@@ -60,7 +60,8 @@
#include "spandsp/v29tx.h"
#include "spandsp/v27ter_rx.h"
#include "spandsp/v27ter_tx.h"
#include "spandsp/t4.h"
#include "spandsp/t4_rx.h"
#include "spandsp/t4_tx.h"
#include "spandsp/t30_fcf.h"
#include "spandsp/t35.h"
#include "spandsp/t30.h"
@@ -68,7 +69,8 @@
#include "spandsp/t30_logging.h"
#include "spandsp/private/logging.h"
#include "spandsp/private/t4.h"
#include "spandsp/private/t4_rx.h"
#include "spandsp/private/t4_tx.h"
#include "spandsp/private/t30.h"
#include "t30_local.h"
@@ -83,7 +85,7 @@ SPAN_DECLARE(int) t30_set_tx_ident(t30_state_t *s, const char *id)
if (strlen(id) > T30_MAX_IDENT_LEN)
return -1;
strcpy(s->tx_info.ident, id);
t4_tx_set_local_ident(&(s->t4), s->tx_info.ident);
t4_tx_set_local_ident(&s->t4, s->tx_info.ident);
return 0;
}
/*- End of function --------------------------------------------------------*/
@@ -544,7 +546,7 @@ SPAN_DECLARE(int) t30_set_tx_page_header_info(t30_state_t *s, const char *info)
if (strlen(info) > T30_MAX_PAGE_HEADER_INFO)
return -1;
strcpy(s->header_info, info);
t4_tx_set_header_info(&(s->t4), s->header_info);
t4_tx_set_header_info(&s->t4, s->header_info);
return 0;
}
/*- End of function --------------------------------------------------------*/
+6 -4
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t30_logging.c,v 1.12 2009/04/12 09:12:10 steveu Exp $
* $Id: t30_logging.c,v 1.12.4.2 2009/12/19 10:44:10 steveu Exp $
*/
/*! \file */
@@ -60,14 +60,16 @@
#include "spandsp/v29tx.h"
#include "spandsp/v27ter_rx.h"
#include "spandsp/v27ter_tx.h"
#include "spandsp/t4.h"
#include "spandsp/t4_rx.h"
#include "spandsp/t4_tx.h"
#include "spandsp/t30_fcf.h"
#include "spandsp/t35.h"
#include "spandsp/t30.h"
#include "spandsp/t30_logging.h"
#include "spandsp/private/logging.h"
#include "spandsp/private/t4.h"
#include "spandsp/private/t4_rx.h"
#include "spandsp/private/t4_tx.h"
#include "spandsp/private/t30.h"
#include "t30_local.h"
@@ -931,7 +933,7 @@ SPAN_DECLARE(void) t30_decode_dis_dtc_dcs(t30_state_t *s, const uint8_t *pkt, in
octet_bit_field(log, pkt, 121, "Flow control capability for T.38 communication", NULL, NULL);
octet_bit_field(log, pkt, 122, "K>4", NULL, NULL);
octet_bit_field(log, pkt, 123, "Internet aware T.38 mode fax (not affected by data signal rate bits)", NULL, NULL);
octet_field(log, pkt, 124, 126, "T.89 (Application profiles for ITU-T Rec T.8)", t89_profile_tags);
octet_field(log, pkt, 124, 126, "T.89 (Application profiles for ITU-T Rec T.88)", t89_profile_tags);
octet_bit_field(log, pkt, 127, "sYCC-JPEG coding", NULL, NULL);
octet_bit_field(log, pkt, 128, "Extension indicator", NULL, NULL);
if (!(pkt[18] & DISBIT8))
+6 -5
View File
@@ -25,7 +25,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t31.c,v 1.153 2009/10/05 16:33:25 steveu Exp $
* $Id: t31.c,v 1.155.4.1 2009/12/19 10:44:10 steveu Exp $
*/
/*! \file */
@@ -74,7 +74,8 @@
#include "spandsp/v17rx.h"
#include "spandsp/super_tone_rx.h"
#include "spandsp/modem_connect_tones.h"
#include "spandsp/t4.h"
#include "spandsp/t4_rx.h"
#include "spandsp/t4_tx.h"
#include "spandsp/t30.h"
#include "spandsp/t30_logging.h"
#include "spandsp/t38_core.h"
@@ -1293,12 +1294,12 @@ static int non_ecm_get_chunk(void *user_data, uint8_t buf[], int len)
}
/*- End of function --------------------------------------------------------*/
static void tone_detected(void *user_data, int on, int level, int delay)
static void tone_detected(void *user_data, int tone, int level, int delay)
{
t31_state_t *s;
s = (t31_state_t *) user_data;
span_log(&s->logging, SPAN_LOG_FLOW, "FAX tone declared %s (%ddBm0)\n", (on) ? "on" : "off", level);
span_log(&s->logging, SPAN_LOG_FLOW, "%s detected (%ddBm0)\n", modem_connect_tone_to_str(tone), level);
}
/*- End of function --------------------------------------------------------*/
@@ -1509,7 +1510,7 @@ static void t31_v21_rx(t31_state_t *s)
s->hdlc_tx.len = 0;
s->dled = FALSE;
hdlc_rx_init(&(s->audio.modems.hdlc_rx), FALSE, TRUE, HDLC_FRAMING_OK_THRESHOLD, hdlc_accept_frame, s);
fsk_rx_init(&(s->audio.modems.v21_rx), &preset_fsk_specs[FSK_V21CH2], TRUE, (put_bit_func_t) hdlc_rx_put_bit, &(s->audio.modems.hdlc_rx));
fsk_rx_init(&(s->audio.modems.v21_rx), &preset_fsk_specs[FSK_V21CH2], FSK_FRAME_MODE_SYNC, (put_bit_func_t) hdlc_rx_put_bit, &(s->audio.modems.hdlc_rx));
fsk_rx_signal_cutoff(&(s->audio.modems.v21_rx), -39.09f);
s->at_state.transmit = TRUE;
}
+9 -9
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t38_core.c,v 1.53 2009/07/14 13:54:22 steveu Exp $
* $Id: t38_core.c,v 1.54 2009/10/09 14:53:57 steveu Exp $
*/
/*! \file */
@@ -224,17 +224,17 @@ SPAN_DECLARE(const char *) t38_cm_profile_to_str(int profile)
switch (profile)
{
case '1':
return "G3 Facsimile Terminal: (Sending Facsimile)";
return "G3 FAX sending terminal";
case '2':
return "G3 Facsimile Terminal: (Receiving Facsimile)";
return "G3 FAX receiving terminal";
case '3':
return "V.34 HDX and G3 Facsimile Terminal: (Sending Facsimile)";
return "V.34 HDX and G3 FAX sending terminal";
case '4':
return "V.34 HDX and G3 Facsimile Terminal: (Receiving Facsimile)";
return "V.34 HDX and G3 FAX receiving terminal";
case '5':
return "V.34 HDX-only Facsimile Terminal: (Sending Facsimile)";
return "V.34 HDX-only FAX sending terminal";
case '6':
return "V.34 HDX-only Facsimile Terminal: (Receiving Facsimile)";
return "V.34 HDX-only FAX receiving terminal";
}
return "???";
}
@@ -260,10 +260,10 @@ SPAN_DECLARE(const char *) t38_jm_to_str(const uint8_t *data, int len)
return "NACK: No compatible mode available";
case '1':
/* Response for profiles 1 and 2 */
return "NACK: No V.34 fax, use G3 fax";
return "NACK: No V.34 FAX, use G3 FAX";
case '2':
/* Response for profiles 5 and 6 */
return "NACK: V.34 fax only.";
return "NACK: V.34 only FAX.";
}
break;
}
+119 -66
View File
@@ -23,7 +23,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t38_gateway.c,v 1.164 2009/07/14 13:54:22 steveu Exp $
* $Id: t38_gateway.c,v 1.171.4.2 2009/12/19 10:44:10 steveu Exp $
*/
/*! \file */
@@ -73,7 +73,8 @@
#include "spandsp/v17rx.h"
#include "spandsp/super_tone_rx.h"
#include "spandsp/modem_connect_tones.h"
#include "spandsp/t4.h"
#include "spandsp/t4_rx.h"
#include "spandsp/t4_tx.h"
#include "spandsp/t30_fcf.h"
#include "spandsp/t35.h"
#include "spandsp/t30.h"
@@ -95,7 +96,8 @@
#include "spandsp/private/modem_connect_tones.h"
#include "spandsp/private/hdlc.h"
#include "spandsp/private/fax_modems.h"
#include "spandsp/private/t4.h"
#include "spandsp/private/t4_rx.h"
#include "spandsp/private/t4_tx.h"
#include "spandsp/private/t30.h"
#include "spandsp/private/t38_core.h"
#include "spandsp/private/t38_non_ecm_buffer.h"
@@ -181,7 +183,7 @@ static void t38_hdlc_rx_put_bit(hdlc_rx_state_t *t, int new_bit);
static void non_ecm_put_bit(void *user_data, int bit);
static void non_ecm_remove_fill_and_put_bit(void *user_data, int bit);
static void non_ecm_push_residue(t38_gateway_state_t *s);
static void tone_detected(void *user_data, int on, int level, int delay);
static void tone_detected(void *user_data, int tone, int level, int delay);
static void set_rx_handler(t38_gateway_state_t *s, span_rx_handler_t *handler, void *user_data)
{
@@ -302,12 +304,12 @@ static int v29_v21_rx(void *user_data, const int16_t amp[], int len)
}
/*- End of function --------------------------------------------------------*/
static void tone_detected(void *user_data, int on, int level, int delay)
static void tone_detected(void *user_data, int tone, int level, int delay)
{
t38_gateway_state_t *s;
s = (t38_gateway_state_t *) user_data;
span_log(&s->logging, SPAN_LOG_FLOW, "FAX tone declared %s (%ddBm0)\n", (on) ? "on" : "off", level);
span_log(&s->logging, SPAN_LOG_FLOW, "%s detected (%ddBm0)\n", modem_connect_tone_to_str(tone), level);
}
/*- End of function --------------------------------------------------------*/
@@ -540,16 +542,16 @@ static int set_next_tx_type(t38_gateway_state_t *s)
set_rx_active(s, TRUE);
break;
case T38_IND_V8_ANSAM:
t->tx_bit_rate = 0;
t->tx_bit_rate = 300;
break;
case T38_IND_V8_SIGNAL:
t->tx_bit_rate = 0;
t->tx_bit_rate = 300;
break;
case T38_IND_V34_CNTL_CHANNEL_1200:
t->tx_bit_rate = 0;
t->tx_bit_rate = 1200;
break;
case T38_IND_V34_PRI_CHANNEL:
t->tx_bit_rate = 0;
t->tx_bit_rate = 33600;
break;
case T38_IND_V34_CC_RETRAIN:
t->tx_bit_rate = 0;
@@ -796,6 +798,13 @@ static void monitor_control_messages(t38_gateway_state_t *s,
case T30_DCS | 1:
/* We need to check which modem type is about to be used, so we can start the
correct modem. */
s->core.fast_bit_rate = 0;
s->core.fast_rx_modem = T38_NONE;
s->core.image_data_mode = FALSE;
s->core.short_train = FALSE;
if (from_modem)
s->core.timed_mode = TIMED_MODE_TCF_PREDICTABLE_MODEM_START_BEGIN;
/*endif*/
if (len >= 5)
{
/* The table is short, and not searched often, so a brain-dead linear scan seems OK */
@@ -807,8 +816,12 @@ static void monitor_control_messages(t38_gateway_state_t *s,
/*endif*/
}
/*endfor*/
/* If we are processing a message from the modem side, the contents determine the fast receive modem.
we are to use. If it comes from the T.38 side the contents do not. */
s->core.fast_bit_rate = modem_codes[i].bit_rate;
s->core.fast_modem = modem_codes[i].modem_type;
if (from_modem)
s->core.fast_rx_modem = modem_codes[i].modem_type;
/*endif*/
}
/*endif*/
if (len >= 6)
@@ -816,26 +829,34 @@ static void monitor_control_messages(t38_gateway_state_t *s,
j = (buf[5] & (DISBIT7 | DISBIT6 | DISBIT5)) >> 4;
span_log(&s->logging, SPAN_LOG_FLOW, "Min bits test = 0x%X\n", buf[5]);
s->core.min_row_bits = (s->core.fast_bit_rate*minimum_scan_line_times[j])/1000;
span_log(&s->logging, SPAN_LOG_FLOW, "Min bits per row = %d\n", j);
}
else
{
s->core.min_row_bits = 0;
}
/*endif*/
s->core.ecm_mode = (len >= 7) && (buf[6] & DISBIT3);
s->core.image_data_mode = FALSE;
s->core.short_train = FALSE;
if (from_modem)
s->core.timed_mode = TIMED_MODE_TCF_PREDICTABLE_MODEM_START_BEGIN;
/*endif*/
span_log(&s->logging, SPAN_LOG_FLOW, "Fast rx modem = %d/%d, ECM = %d, Min bits per row = %d\n", s->core.fast_rx_modem, s->core.fast_bit_rate, s->core.ecm_mode, s->core.min_row_bits);
break;
case T30_PPS:
case T30_PPS | 1:
switch (buf[3] & 0xFE)
{
case T30_EOP:
case T30_EOM:
case T30_EOS:
case T30_MPS:
case T30_PRI_EOP:
case T30_EOM:
case T30_PRI_EOM:
case T30_EOS:
#if 0
/* If we are hitting one of these conditions, it will take another DCS/DTC to select
the fast modem again, so abandon our idea of it. */
s->core.fast_bit_rate = 0;
s->core.fast_rx_modem = T38_NONE;
s->core.image_data_mode = FALSE;
s->core.short_train = FALSE;
#endif
/* Fall through */
case T30_MPS:
case T30_PRI_MPS:
s->core.count_page_on_mcf = TRUE;
break;
@@ -843,18 +864,27 @@ static void monitor_control_messages(t38_gateway_state_t *s,
/*endswitch*/
break;
case T30_EOP:
case T30_EOM:
case T30_EOS:
case T30_MPS:
case T30_PRI_EOP:
case T30_PRI_EOM:
case T30_PRI_MPS:
case T30_EOP | 1:
case T30_EOM | 1:
case T30_EOS | 1:
case T30_MPS | 1:
case T30_PRI_EOP:
case T30_PRI_EOP | 1:
case T30_EOM:
case T30_EOM | 1:
case T30_PRI_EOM:
case T30_PRI_EOM | 1:
case T30_EOS:
case T30_EOS | 1:
#if 0
/* If we are hitting one of these conditions, it will take another DCS/DTC to select
the fast modem again, so abandon our idea of t. */
s->core.fast_bit_rate = 0;
s->core.fast_rx_modem = T38_NONE;
s->core.image_data_mode = FALSE;
s->core.short_train = FALSE;
#endif
/* Fall through */
case T30_MPS:
case T30_MPS | 1:
case T30_PRI_MPS:
case T30_PRI_MPS | 1:
s->core.count_page_on_mcf = TRUE;
break;
@@ -1015,6 +1045,62 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
s = (t38_gateway_state_t *) user_data;
xx = &s->t38x;
/* There are a couple of special cases of data type that need their own treatment. */
switch (data_type)
{
case T38_DATA_V8:
switch (field_type)
{
case T38_FIELD_CM_MESSAGE:
if (len >= 1)
span_log(&s->logging, SPAN_LOG_FLOW, "CM profile %d - %s\n", buf[0] - '0', t38_cm_profile_to_str(buf[0]));
else
span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for CM message - %d\n", len);
/*endif*/
break;
case T38_FIELD_JM_MESSAGE:
if (len >= 2)
span_log(&s->logging, SPAN_LOG_FLOW, "JM - %s\n", t38_jm_to_str(buf, len));
else
span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for JM message - %d\n", len);
/*endif*/
break;
case T38_FIELD_CI_MESSAGE:
if (len >= 1)
span_log(&s->logging, SPAN_LOG_FLOW, "CI 0x%X\n", buf[0]);
else
span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for CI message - %d\n", len);
/*endif*/
break;
default:
break;
}
/*endswitch*/
return 0;
case T38_DATA_V34_PRI_RATE:
switch (field_type)
{
case T38_FIELD_V34RATE:
if (len >= 3)
{
xx->t38.v34_rate = t38_v34rate_to_bps(buf, len);
span_log(&s->logging, SPAN_LOG_FLOW, "V.34 rate %d bps\n", xx->t38.v34_rate);
}
else
{
span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for V34rate message - %d\n", len);
}
/*endif*/
break;
default:
break;
}
/*endswitch*/
return 0;
default:
break;
}
/*endswitch*/
switch (field_type)
{
case T38_FIELD_HDLC_DATA:
@@ -1352,39 +1438,6 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
/*endif*/
xx->corrupt_current_frame[0] = FALSE;
break;
case T38_FIELD_CM_MESSAGE:
if (len >= 1)
span_log(&s->logging, SPAN_LOG_FLOW, "CM profile %d - %s\n", buf[0] - '0', t38_cm_profile_to_str(buf[0]));
else
span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for CM message - %d\n", len);
/*endif*/
break;
case T38_FIELD_JM_MESSAGE:
if (len >= 2)
span_log(&s->logging, SPAN_LOG_FLOW, "JM - %s\n", t38_jm_to_str(buf, len));
else
span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for JM message - %d\n", len);
/*endif*/
break;
case T38_FIELD_CI_MESSAGE:
if (len >= 1)
span_log(&s->logging, SPAN_LOG_FLOW, "CI 0x%X\n", buf[0]);
else
span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for CI message - %d\n", len);
/*endif*/
break;
case T38_FIELD_V34RATE:
if (len >= 3)
{
xx->t38.v34_rate = t38_v34rate_to_bps(buf, len);
span_log(&s->logging, SPAN_LOG_FLOW, "V.34 rate %d bps\n", xx->t38.v34_rate);
}
else
{
span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for V34rate message - %d\n", len);
}
/*endif*/
break;
default:
break;
}
@@ -1944,14 +1997,14 @@ static int restart_rx_modem(t38_gateway_state_t *s)
s->core.to_t38.in_bits = 0;
s->core.to_t38.out_octets = 0;
}
span_log(&s->logging, SPAN_LOG_FLOW, "Restart rx modem - modem = %d, short train = %d, ECM = %d\n", s->core.fast_modem, s->core.short_train, s->core.ecm_mode);
span_log(&s->logging, SPAN_LOG_FLOW, "Restart rx modem - modem = %d, short train = %d, ECM = %d\n", s->core.fast_rx_modem, s->core.short_train, s->core.ecm_mode);
hdlc_rx_init(&(s->audio.modems.hdlc_rx), FALSE, TRUE, HDLC_FRAMING_OK_THRESHOLD, NULL, s);
s->audio.modems.rx_signal_present = FALSE;
s->audio.modems.rx_trained = FALSE;
/* Default to the transmit data being V.21, unless a faster modem pops up trained. */
s->t38x.current_tx_data_type = T38_DATA_V21;
fsk_rx_init(&(s->audio.modems.v21_rx), &preset_fsk_specs[FSK_V21CH2], TRUE, (put_bit_func_t) t38_hdlc_rx_put_bit, &(s->audio.modems.hdlc_rx));
fsk_rx_init(&(s->audio.modems.v21_rx), &preset_fsk_specs[FSK_V21CH2], FSK_FRAME_MODE_SYNC, (put_bit_func_t) t38_hdlc_rx_put_bit, &(s->audio.modems.hdlc_rx));
#if 0
fsk_rx_signal_cutoff(&(s->audio.modems.v21_rx), -45.5f);
#endif
@@ -1971,7 +2024,7 @@ static int restart_rx_modem(t38_gateway_state_t *s)
/*endif*/
to_t38_buffer_init(&s->core.to_t38);
s->core.to_t38.octets_per_data_packet = 1;
switch (s->core.fast_modem)
switch (s->core.fast_rx_modem)
{
case T38_V17_RX:
v17_rx_restart(&s->audio.modems.v17_rx, s->core.fast_bit_rate, s->core.short_train);
@@ -2245,7 +2298,7 @@ SPAN_DECLARE(t38_gateway_state_t *) t38_gateway_init(t38_gateway_state_t *s,
t38_gateway_set_nsx_suppression(s, (const uint8_t *) "\x00\x00\x00", 3, (const uint8_t *) "\x00\x00\x00", 3);
s->core.to_t38.octets_per_data_packet = 1;
s->core.ecm_allowed = FALSE;
s->core.ecm_allowed = TRUE;
t38_non_ecm_buffer_init(&s->core.non_ecm_to_modem, FALSE, 0);
restart_rx_modem(s);
s->core.timed_mode = TIMED_MODE_STARTUP;
+145 -55
View File
@@ -23,7 +23,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t38_non_ecm_buffer.c,v 1.9 2009/10/05 16:33:25 steveu Exp $
* $Id: t38_non_ecm_buffer.c,v 1.9.4.1 2009/12/19 06:43:28 steveu Exp $
*/
/*! \file */
@@ -57,13 +57,22 @@
#include "spandsp/private/t38_non_ecm_buffer.h"
/* Phases */
enum
{
TCF_AT_INITIAL_ALL_ONES = 0,
TCF_AT_ALL_ZEROS = 1,
IMAGE_WAITING_FOR_FIRST_EOL = 2,
IMAGE_IN_PROGRESS = 3
};
static void restart_buffer(t38_non_ecm_buffer_state_t *s)
{
/* This should be called when draining the buffer is complete, which should
occur before any fresh data can possibly arrive to begin refilling it. */
s->octet = 0xFF;
s->flow_control_fill_octet = 0xFF;
s->at_initial_all_ones = TRUE;
s->input_phase = (s->image_data_mode) ? IMAGE_WAITING_FOR_FIRST_EOL : TCF_AT_INITIAL_ALL_ONES;
s->bit_stream = 0xFFFF;
s->out_ptr = 0;
s->in_ptr = 0;
@@ -126,61 +135,164 @@ SPAN_DECLARE(void) t38_non_ecm_buffer_inject(t38_non_ecm_buffer_state_t *s, cons
int upper;
int lower;
/* TCF consists of:
- zero or more ones, followed by
- about 1.5s of zeros
There may be a little junk at the end, as the modem shuts down.
We can stuff with extra ones in the initial period of all ones, and we can stuff with extra
zeros once the zeros start. The thing we need to be wary about is the odd zero bit in the
midst of the ones, due to a bit error. */
/* Non-ECM image data consists of:
- zero or more ones, followed by
- zero or more zeros, followed by
- an EOL (end of line), which marks the start of the image, followed by
- a succession of data rows, with an EOL at the end of each, followed by
- an RTC (return to control)
There may be a little junk at the end, as the modem shuts down.
An EOL 11 zeros followed by a one in a T.4 1D image or 11 zeros followed by a one followed
by a one or a zero in a T.4 2D image. An RTC consists of 6 EOLs in succession, with no
pixel data between them.
We can stuff with ones until we get the first EOL into our buffer, then we can stuff with
zeros in front of each EOL at any point up the the RTC. We should not pad between the EOLs
which make up the RTC. Most FAX machines don't care about this, but a few will not recognise
the RTC if here is padding between the EOLs.
We need to buffer whole rows before we output their beginning, so there is no possibility
of underflow mid-row. */
/* FoIP has latency issues, because of the fairly tight timeouts in the T.30 spec. We must
ensure our buffering does everything needed to avoid underflows, and to meet the minimum
row length requirements imposed by many mechanical FAX machines. We cannot, however,
afford to bulk up the data, by sending superfluous bytes. The resulting loop delay could
provoke an erroneous timeout of the acknowledgement signal. */
i = 0;
if (s->at_initial_all_ones)
switch (s->input_phase)
{
case TCF_AT_INITIAL_ALL_ONES:
/* Dump initial 0xFF bytes. We will add enough of our own to makes things flow
smoothly. If we don't strip these off, we might end up delaying the start of
forwarding by a large amount, as we could end up with a large block of 0xFF
forwarding by a substantial amount, as we could end up with a large block of 0xFF
bytes before the real data begins. This is especially true with PC FAX
systems. This test is very simplistic, as a single bit error will throw it
off course. */
systems. This test is very simplistic, as bit errors could confuse it. */
for ( ; i < len; i++)
{
if (buf[i] != 0xFF)
{
s->at_initial_all_ones = FALSE;
s->input_phase = TCF_AT_ALL_ZEROS;
s->flow_control_fill_octet = 0x00;
break;
}
}
}
if (s->image_data_mode)
{
/* This is image data */
/* Fall through */
case TCF_AT_ALL_ZEROS:
for ( ; i < len; i++)
{
s->data[s->in_ptr] = buf[i];
s->latest_eol_ptr = s->in_ptr;
/* TODO: We can't buffer overflow, since we wrap around. However, the tail could
overwrite itself if things fall badly behind. */
s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1);
s->in_octets++;
}
break;
case IMAGE_WAITING_FOR_FIRST_EOL:
/* Dump anything up to the first EOL. Let the output side stuff with 0xFF bytes while waiting
for that first EOL. What occurs before the first EOL is expected to be a period of all ones
and then a period of all zeros. We really don't care what junk might be there. By definition,
the image only starts at the first EOL. */
for ( ; i < len; i++)
{
/* Check for EOLs, because at an EOL we can pause and pump out zeros while
waiting for more incoming data. */
if (buf[i])
{
/* There might be an EOL here. Look for at least 11 zeros, followed by a one, split
between two octets. Between those two octets we can insert numerous zero octets
as a means of flow control. Note that we stuff in blocks of 8 bits, and not at
the minimal level. */
/* Or'ing with 0x800 here is simply to avoid zero words looking like they have -1
/* Or'ing with 0x800 here is to avoid zero words looking like they have -1
trailing zeros */
upper = bottom_bit(s->bit_stream | 0x800);
lower = top_bit(buf[i]);
if (upper - lower > 3)
if ((upper - lower) > (11 - 8))
{
/* This is an EOL - our first row is beginning. */
s->input_phase = IMAGE_IN_PROGRESS;
/* Start a new row */
s->row_bits = lower - 8;
s->latest_eol_ptr = s->in_ptr;
s->flow_control_fill_octet = 0x00;
/* If we push out two bytes of zero, and our latest non-zero byte
we should definitely form a proper EOL to begin things, with a
few harmless extra zero bits at the front. */
s->data[s->in_ptr] = 0x00;
s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1);
s->data[s->in_ptr] = 0x00;
s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1);
s->data[s->in_ptr] = buf[i];
s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1);
s->in_octets += 3;
s->bit_stream = (s->bit_stream << 8) | buf[i];
i++;
break;
}
}
s->bit_stream = (s->bit_stream << 8) | buf[i];
}
if (i >= len)
break;
/* Fall through */
case IMAGE_IN_PROGRESS:
/* Now we have seen an EOL, we can stuff with zeros just in front of that EOL, or any
subsequent EOL that does not immediately follow a previous EOL (i.e. a candidate RTC).
We need to track our way through the image data, allowing the output side to only send
up to the last EOL. This prevents the possibility of underflow mid-row, where we cannot
safely stuff anything in the bit stream. */
for ( ; i < len; i++)
{
if (buf[i])
{
/* There might be an EOL here. Look for at least 11 zeros, followed by a one, split
between two octets. Between those two octets we can insert numerous zero octets
as a means of flow control. Note that we stuff in blocks of 8 bits, and not at
the minimal level. */
/* Or'ing with 0x800 here is to avoid zero words looking like they have -1
trailing zeros */
upper = bottom_bit(s->bit_stream | 0x800);
lower = top_bit(buf[i]);
if ((upper - lower) > (11 - 8))
{
/* This is an EOL. */
s->row_bits += (8 - lower);
/* If the row is too short, extend it in chunks of a whole byte. */
/* TODO: extend by the precise amount we should, instead of this
rough approach. */
while (s->row_bits < s->min_row_bits)
/* Make sure we don't stretch back to back EOLs, as that could spoil the RTC.
This is a slightly crude check, as we don't know if we are processing a T.4 1D
or T.4 2D image. Accepting 12 or 12 bits apart as meaning back to back is fine,
as no 1D image row could be 1 bit long. */
if (s->row_bits < 12 || s->row_bits > 13)
{
s->min_row_bits_fill_octets++;
s->data[s->in_ptr] = 0;
s->row_bits += 8;
/* TODO: We can't buffer overflow, since we wrap around. However, the tail could
overwrite itself if things fall badly behind. */
s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1);
/* If the row is too short, extend it in chunks of a whole byte. */
/* TODO: extend by the precise amount we should, instead of this
rough approach. */
while (s->row_bits < s->min_bits_per_row)
{
s->min_row_bits_fill_octets++;
s->data[s->in_ptr] = 0;
s->row_bits += 8;
/* TODO: We can't buffer overflow, since we wrap around. However,
the tail could overwrite itself if things fall badly behind. */
s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1);
}
/* This is now the limit for the output side, before it starts
stuffing. */
s->latest_eol_ptr = s->in_ptr;
}
/* Start a new row */
s->row_bits = lower - 8;
s->in_rows++;
s->latest_eol_ptr = s->in_ptr;
s->flow_control_fill_octet = 0x00;
}
}
s->bit_stream = (s->bit_stream << 8) | buf[i];
@@ -191,26 +303,7 @@ SPAN_DECLARE(void) t38_non_ecm_buffer_inject(t38_non_ecm_buffer_state_t *s, cons
s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1);
s->in_octets++;
}
}
else
{
/* This is TCF data */
for ( ; i < len; i++)
{
/* Check for zero bytes, as we can pause and pump out zeros while waiting
for more incoming data. Of course, the entire TCF data should be zero,
but it might not be, due to bit errors, or something weird happening. */
if (buf[i] == 0x00)
{
s->latest_eol_ptr = s->in_ptr;
s->flow_control_fill_octet = 0x00;
}
s->data[s->in_ptr] = buf[i];
/* TODO: We can't buffer overflow, since we wrap around. However, the tail could
overwrite itself if things fall badly behind. */
s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1);
s->in_octets++;
}
break;
}
}
/*- End of function --------------------------------------------------------*/
@@ -249,14 +342,14 @@ SPAN_DECLARE(void) t38_non_ecm_buffer_report_output_status(t38_non_ecm_buffer_st
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(void) t38_non_ecm_buffer_set_mode(t38_non_ecm_buffer_state_t *s, int mode, int min_row_bits)
SPAN_DECLARE(void) t38_non_ecm_buffer_set_mode(t38_non_ecm_buffer_state_t *s, int mode, int min_bits_per_row)
{
s->image_data_mode = mode;
s->min_row_bits = min_row_bits;
s->min_bits_per_row = min_bits_per_row;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(t38_non_ecm_buffer_state_t *) t38_non_ecm_buffer_init(t38_non_ecm_buffer_state_t *s, int mode, int min_row_bits)
SPAN_DECLARE(t38_non_ecm_buffer_state_t *) t38_non_ecm_buffer_init(t38_non_ecm_buffer_state_t *s, int mode, int min_bits_per_row)
{
if (s == NULL)
{
@@ -264,12 +357,9 @@ SPAN_DECLARE(t38_non_ecm_buffer_state_t *) t38_non_ecm_buffer_init(t38_non_ecm_b
return NULL;
}
memset(s, 0, sizeof(*s));
s->octet = 0xFF;
s->flow_control_fill_octet = 0xFF;
s->at_initial_all_ones = TRUE;
s->bit_stream = 0xFFFF;
s->image_data_mode = mode;
s->min_row_bits = min_row_bits;
s->min_bits_per_row = min_bits_per_row;
restart_buffer(s);
return s;
}
/*- End of function --------------------------------------------------------*/
+79 -59
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t38_terminal.c,v 1.128 2009/09/04 14:38:46 steveu Exp $
* $Id: t38_terminal.c,v 1.129.4.2 2009/12/19 10:44:10 steveu Exp $
*/
/*! \file */
@@ -63,7 +63,8 @@
#include "spandsp/v27ter_rx.h"
#include "spandsp/v17tx.h"
#include "spandsp/v17rx.h"
#include "spandsp/t4.h"
#include "spandsp/t4_rx.h"
#include "spandsp/t4_tx.h"
#include "spandsp/t30_fcf.h"
#include "spandsp/t35.h"
#include "spandsp/t30.h"
@@ -73,7 +74,8 @@
#include "spandsp/t38_terminal.h"
#include "spandsp/private/logging.h"
#include "spandsp/private/t4.h"
#include "spandsp/private/t4_rx.h"
#include "spandsp/private/t4_tx.h"
#include "spandsp/private/t30.h"
#include "spandsp/private/t38_core.h"
#include "spandsp/private/t38_terminal.h"
@@ -231,8 +233,6 @@ static int process_rx_indicator(t38_core_state_t *t, void *user_data, int indica
front_end_status(s, T30_FRONT_END_CED_PRESENT);
break;
case T38_IND_V21_PREAMBLE:
/* Some T.38 implementations insert these preamble indicators between HDLC frames, so
we need to be tolerant of that. */
fe->timeout_rx_samples = fe->samples + ms_to_samples(MID_RX_TIMEOUT);
front_end_status(s, T30_FRONT_END_SIGNAL_PRESENT);
break;
@@ -248,6 +248,8 @@ static int process_rx_indicator(t38_core_state_t *t, void *user_data, int indica
case T38_IND_V17_12000_LONG_TRAINING:
case T38_IND_V17_14400_SHORT_TRAINING:
case T38_IND_V17_14400_LONG_TRAINING:
case T38_IND_V34_CNTL_CHANNEL_1200:
case T38_IND_V34_PRI_CHANNEL:
case T38_IND_V33_12000_TRAINING:
case T38_IND_V33_14400_TRAINING:
/* We really don't care what kind of modem is delivering the following image data.
@@ -257,22 +259,30 @@ static int process_rx_indicator(t38_core_state_t *t, void *user_data, int indica
break;
case T38_IND_V8_ANSAM:
case T38_IND_V8_SIGNAL:
case T38_IND_V34_CNTL_CHANNEL_1200:
case T38_IND_V34_PRI_CHANNEL:
case T38_IND_V34_CC_RETRAIN:
/* V.34 support is a work in progress. */
front_end_status(s, T30_FRONT_END_SIGNAL_PRESENT);
break;
default:
front_end_status(s, T30_FRONT_END_SIGNAL_ABSENT);
break;
}
/*endswitch*/
fe->hdlc_rx.len = 0;
fe->rx_data_missing = FALSE;
return 0;
}
/*- End of function --------------------------------------------------------*/
static int fake_rx_indicator(t38_core_state_t *t, t38_terminal_state_t *s, int indicator)
{
int ret;
ret = process_rx_indicator(t, s, indicator);
t->current_rx_indicator = indicator;
return ret;
}
/*- End of function --------------------------------------------------------*/
static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, int field_type, const uint8_t *buf, int len)
{
t38_terminal_state_t *s;
@@ -285,29 +295,64 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
s = (t38_terminal_state_t *) user_data;
fe = &s->t38_fe;
#if 0
/* In termination mode we don't care very much what the data type is. */
/* In termination mode we don't care very much what the data type is apart from a couple of
special cases. */
switch (data_type)
{
case T38_DATA_V21:
case T38_DATA_V27TER_2400:
case T38_DATA_V27TER_4800:
case T38_DATA_V29_7200:
case T38_DATA_V29_9600:
case T38_DATA_V17_7200:
case T38_DATA_V17_9600:
case T38_DATA_V17_12000:
case T38_DATA_V17_14400:
case T38_DATA_V8:
switch (field_type)
{
case T38_FIELD_CM_MESSAGE:
if (len >= 1)
span_log(&s->logging, SPAN_LOG_FLOW, "CM profile %d - %s\n", buf[0] - '0', t38_cm_profile_to_str(buf[0]));
else
span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for CM message - %d\n", len);
//front_end_status(s, T30_FRONT_END_RECEIVE_COMPLETE);
break;
case T38_FIELD_JM_MESSAGE:
if (len >= 2)
span_log(&s->logging, SPAN_LOG_FLOW, "JM - %s\n", t38_jm_to_str(buf, len));
else
span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for JM message - %d\n", len);
//front_end_status(s, T30_FRONT_END_RECEIVE_COMPLETE);
break;
case T38_FIELD_CI_MESSAGE:
if (len >= 1)
span_log(&s->logging, SPAN_LOG_FLOW, "CI 0x%X\n", buf[0]);
else
span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for CI message - %d\n", len);
//front_end_status(s, T30_FRONT_END_RECEIVE_COMPLETE);
break;
default:
break;
}
/*endswitch*/
return 0;
case T38_DATA_V34_PRI_RATE:
case T38_DATA_V34_CC_1200:
case T38_DATA_V34_PRI_CH:
case T38_DATA_V33_12000:
case T38_DATA_V33_14400:
switch (field_type)
{
case T38_FIELD_V34RATE:
if (len >= 3)
{
/* Just get and store the rate. The front end has no real interest in the
actual bit rate. */
fe->t38.v34_rate = t38_v34rate_to_bps(buf, len);
span_log(&s->logging, SPAN_LOG_FLOW, "V.34 rate %d bps\n", fe->t38.v34_rate);
}
else
{
span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for V34rate message - %d\n", len);
}
break;
default:
break;
}
/*endswitch*/
return 0;
default:
break;
}
#endif
/*endswitch*/
switch (field_type)
{
case T38_FIELD_HDLC_DATA:
@@ -316,8 +361,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
/* HDLC can just start without any signal indicator on some platforms, even when
there is zero packet lost. Nasty, but true. Its a good idea to be tolerant of
loss, though, so accepting a sudden start of HDLC data is the right thing to do. */
fe->timeout_rx_samples = fe->samples + ms_to_samples(MID_RX_TIMEOUT);
front_end_status(s, T30_FRONT_END_SIGNAL_PRESENT);
fake_rx_indicator(t, s, T38_IND_V21_PREAMBLE);
/* All real HDLC messages in the FAX world start with 0xFF. If this one is not starting
with 0xFF it would appear some octets must have been missed before this one. */
if (len <= 0 || buf[0] != 0xFF)
@@ -386,7 +430,8 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
}
fe->hdlc_rx.len = 0;
fe->rx_data_missing = FALSE;
fe->timeout_rx_samples = 0;
/* Treat this like a no signal indicator has occurred, so if the no signal indicator is missing, we are still OK */
fake_rx_indicator(t, s, T38_IND_NO_SIGNAL);
break;
case T38_FIELD_HDLC_FCS_BAD_SIG_END:
if (len > 0)
@@ -406,7 +451,8 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
}
fe->hdlc_rx.len = 0;
fe->rx_data_missing = FALSE;
fe->timeout_rx_samples = 0;
/* Treat this like a no signal indicator has occurred, so if the no signal indicator is missing, we are still OK */
fake_rx_indicator(t, s, T38_IND_NO_SIGNAL);
break;
case T38_FIELD_HDLC_SIG_END:
if (len > 0)
@@ -428,9 +474,10 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
The other is because the HDLC signal drops unexpectedly - i.e. not just after a final frame. */
fe->hdlc_rx.len = 0;
fe->rx_data_missing = FALSE;
fe->timeout_rx_samples = 0;
front_end_status(s, T30_FRONT_END_RECEIVE_COMPLETE);
}
/* Treat this like a no signal indicator has occurred, so if the no signal indicator is missing, we are still OK */
fake_rx_indicator(t, s, T38_IND_NO_SIGNAL);
break;
case T38_FIELD_T4_NON_ECM_DATA:
if (!fe->rx_signal_present)
@@ -468,40 +515,13 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
front_end_status(s, T30_FRONT_END_RECEIVE_COMPLETE);
}
fe->rx_signal_present = FALSE;
fe->timeout_rx_samples = 0;
break;
case T38_FIELD_CM_MESSAGE:
if (len >= 1)
span_log(&s->logging, SPAN_LOG_FLOW, "CM profile %d - %s\n", buf[0] - '0', t38_cm_profile_to_str(buf[0]));
else
span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for CM message - %d\n", len);
break;
case T38_FIELD_JM_MESSAGE:
if (len >= 2)
span_log(&s->logging, SPAN_LOG_FLOW, "JM - %s\n", t38_jm_to_str(buf, len));
else
span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for JM message - %d\n", len);
break;
case T38_FIELD_CI_MESSAGE:
if (len >= 1)
span_log(&s->logging, SPAN_LOG_FLOW, "CI 0x%X\n", buf[0]);
else
span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for CI message - %d\n", len);
break;
case T38_FIELD_V34RATE:
if (len >= 3)
{
fe->t38.v34_rate = t38_v34rate_to_bps(buf, len);
span_log(&s->logging, SPAN_LOG_FLOW, "V.34 rate %d bps\n", fe->t38.v34_rate);
}
else
{
span_log(&s->logging, SPAN_LOG_FLOW, "Bad length for V34rate message - %d\n", len);
}
/* Treat this like a no signal indicator has occurred, so if the no signal indicator is missing, we are still OK */
fake_rx_indicator(t, s, T38_IND_NO_SIGNAL);
break;
default:
break;
}
/*endswitch*/
return 0;
}
/*- End of function --------------------------------------------------------*/
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+35 -23
View File
@@ -23,7 +23,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v17rx.c,v 1.153 2009/07/09 14:17:57 steveu Exp $
* $Id: v17rx.c,v 1.153.4.4 2009/12/19 14:18:13 steveu Exp $
*/
/*! \file */
@@ -121,22 +121,28 @@ enum
/* Coefficients for the band edge symbol timing synchroniser (alpha = 0.99) */
/* low_edge = 2.0f*M_PI*(CARRIER_NOMINAL_FREQ - BAUD_RATE/2.0f)/SAMPLE_RATE; */
/* high_edge = 2.0f*M_PI*(CARRIER_NOMINAL_FREQ + BAUD_RATE/2.0f)/SAMPLE_RATE; */
#define SIN_LOW_BAND_EDGE 0.453990499f
#define COS_LOW_BAND_EDGE 0.891006542f
#define SIN_HIGH_BAND_EDGE 0.707106781f
#define COS_HIGH_BAND_EDGE -0.707106781f
#define ALPHA 0.99f
#if defined(SPANDSP_USE_FIXED_POINTx)
#define SYNC_LOW_BAND_EDGE_COEFF_0 ((int)(FP_FACTOR* 1.764193f)) /* 2*alpha*cos(low_edge) */
#define SYNC_LOW_BAND_EDGE_COEFF_1 ((int)(FP_FACTOR*-0.980100f)) /* -alpha^2 */
#define SYNC_HIGH_BAND_EDGE_COEFF_0 ((int)(FP_FACTOR*-1.400072f)) /* 2*alpha*cos(high_edge) */
#define SYNC_HIGH_BAND_EDGE_COEFF_1 ((int)(FP_FACTOR*-0.980100f)) /* -alpha^2 */
#define SYNC_CROSS_CORR_COEFF_A ((int)(FP_FACTOR*-0.932131f)) /* -alpha^2*sin(freq_diff) */
#define SYNC_CROSS_CORR_COEFF_B ((int)(FP_FACTOR* 0.700036f)) /* alpha*sin(high_edge) */
#define SYNC_CROSS_CORR_COEFF_C ((int)(FP_FACTOR*-0.449451f)) /* -alpha*sin(low_edge) */
#define SYNC_LOW_BAND_EDGE_COEFF_0 ((int)(FP_FACTOR*(2.0f*ALPHA*COS_LOW_BAND_EDGE)))
#define SYNC_LOW_BAND_EDGE_COEFF_1 ((int)(FP_FACTOR*(-ALPHA*ALPHA)))
#define SYNC_LOW_BAND_EDGE_COEFF_2 ((int)(FP_FACTOR*(-ALPHA*SIN_LOW_BAND_EDGE)))
#define SYNC_HIGH_BAND_EDGE_COEFF_0 ((int)(FP_FACTOR*(2.0f*ALPHA*COS_HIGH_BAND_EDGE)))
#define SYNC_HIGH_BAND_EDGE_COEFF_1 ((int)(FP_FACTOR*(-ALPHA*ALPHA)))
#define SYNC_HIGH_BAND_EDGE_COEFF_2 ((int)(FP_FACTOR*(-ALPHA*SIN_HIGH_BAND_EDGE)))
#define SYNC_MIXED_EDGES_COEFF_3 ((int)(FP_FACTOR*(-ALPHA*ALPHA*(SIN_HIGH_BAND_EDGE*COS_LOW_BAND_EDGE - SIN_LOW_BAND_EDGE*COS_HIGH_BAND_EDGE))))
#else
#define SYNC_LOW_BAND_EDGE_COEFF_0 1.764193f /* 2*alpha*cos(low_edge) */
#define SYNC_LOW_BAND_EDGE_COEFF_1 -0.980100f /* -alpha^2 */
#define SYNC_HIGH_BAND_EDGE_COEFF_0 -1.400072f /* 2*alpha*cos(high_edge) */
#define SYNC_HIGH_BAND_EDGE_COEFF_1 -0.980100f /* -alpha^2 */
#define SYNC_CROSS_CORR_COEFF_A -0.932131f /* -alpha^2*sin(freq_diff) */
#define SYNC_CROSS_CORR_COEFF_B 0.700036f /* alpha*sin(high_edge) */
#define SYNC_CROSS_CORR_COEFF_C -0.449451f /* -alpha*sin(low_edge) */
#define SYNC_LOW_BAND_EDGE_COEFF_0 (2.0f*ALPHA*COS_LOW_BAND_EDGE)
#define SYNC_LOW_BAND_EDGE_COEFF_1 (-ALPHA*ALPHA)
#define SYNC_LOW_BAND_EDGE_COEFF_2 (-ALPHA*SIN_LOW_BAND_EDGE)
#define SYNC_HIGH_BAND_EDGE_COEFF_0 (2.0f*ALPHA*COS_HIGH_BAND_EDGE)
#define SYNC_HIGH_BAND_EDGE_COEFF_1 (-ALPHA*ALPHA)
#define SYNC_HIGH_BAND_EDGE_COEFF_2 (-ALPHA*SIN_HIGH_BAND_EDGE)
#define SYNC_MIXED_EDGES_COEFF_3 (-ALPHA*ALPHA*(SIN_HIGH_BAND_EDGE*COS_LOW_BAND_EDGE - SIN_LOW_BAND_EDGE*COS_HIGH_BAND_EDGE))
#endif
#if defined(SPANDSP_USE_FIXED_POINTx)
@@ -533,12 +539,18 @@ static __inline__ void symbol_sync(v17_rx_state_t *s)
/* This routine adapts the position of the half baud samples entering the equalizer. */
/* This symbol sync scheme is based on the technique first described by Dominique Godard in
Passband Timing Recovery in an All-Digital Modem Receiver
IEEE TRANSACTIONS ON COMMUNICATIONS, VOL. COM-26, NO. 5, MAY 1978 */
/* This is slightly rearranged for figure 3b of the Godard paper, as this saves a couple of
maths operations */
#if defined(SPANDSP_USE_FIXED_POINTx)
/* TODO: The scalings used here need more thorough evaluation, to see if overflows are possible. */
/* Cross correlate */
v = (((s->symbol_sync_low[1] >> 5)*(s->symbol_sync_high[1] >> 4)) >> 15)*SYNC_CROSS_CORR_COEFF_A
+ (((s->symbol_sync_low[0] >> 5)*(s->symbol_sync_high[1] >> 4)) >> 15)*SYNC_CROSS_CORR_COEFF_B
+ (((s->symbol_sync_low[1] >> 5)*(s->symbol_sync_high[0] >> 4)) >> 15)*SYNC_CROSS_CORR_COEFF_C;
v = (((s->symbol_sync_low[1] >> 5)*(s->symbol_sync_high[0] >> 4)) >> 15)*SYNC_LOW_BAND_EDGE_COEFF_2
- (((s->symbol_sync_low[0] >> 5)*(s->symbol_sync_high[1] >> 4)) >> 15)*SYNC_HIGH_BAND_EDGE_COEFF_2
+ (((s->symbol_sync_low[1] >> 5)*(s->symbol_sync_high[1] >> 4)) >> 15)*SYNC_MIXED_EDGES_COEFF_3;
/* Filter away any DC component */
p = v - s->symbol_sync_dc_filter[1];
s->symbol_sync_dc_filter[1] = s->symbol_sync_dc_filter[0];
@@ -548,9 +560,9 @@ static __inline__ void symbol_sync(v17_rx_state_t *s)
if (abs(s->baud_phase) > 100*FP_FACTOR)
{
if (s->baud_phase > 0)
i = (s->baud_phase > 1000*FP_FACTOR) ? 5 : 1;
i = (s->baud_phase > 1000*FP_FACTOR) ? 15 : 1;
else
i = (s->baud_phase < -1000*FP_FACTOR) ? -5 : -1;
i = (s->baud_phase < -1000*FP_FACTOR) ? -15 : -1;
//printf("v = %10.5f %5d - %f %f %d %d\n", v, i, p, s->baud_phase, s->total_baud_timing_correction);
s->eq_put_step += i;
@@ -558,9 +570,9 @@ static __inline__ void symbol_sync(v17_rx_state_t *s)
}
#else
/* Cross correlate */
v = s->symbol_sync_low[1]*s->symbol_sync_high[1]*SYNC_CROSS_CORR_COEFF_A
+ s->symbol_sync_low[0]*s->symbol_sync_high[1]*SYNC_CROSS_CORR_COEFF_B
+ s->symbol_sync_low[1]*s->symbol_sync_high[0]*SYNC_CROSS_CORR_COEFF_C;
v = s->symbol_sync_low[1]*s->symbol_sync_high[0]*SYNC_LOW_BAND_EDGE_COEFF_2
- s->symbol_sync_low[0]*s->symbol_sync_high[1]*SYNC_HIGH_BAND_EDGE_COEFF_2
+ s->symbol_sync_low[1]*s->symbol_sync_high[1]*SYNC_MIXED_EDGES_COEFF_3;
/* Filter away any DC component */
p = v - s->symbol_sync_dc_filter[1];
+5 -5
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v18.c,v 1.10 2009/06/02 16:03:56 steveu Exp $
* $Id: v18.c,v 1.12 2009/11/04 15:52:06 steveu Exp $
*/
/*! \file */
@@ -738,7 +738,7 @@ SPAN_DECLARE(logging_state_t *) v18_get_logging_state(v18_state_t *s)
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(v18_state_t *) v18_init(v18_state_t *s,
int caller,
int calling_party,
int mode,
put_msg_func_t put_msg,
void *user_data)
@@ -749,7 +749,7 @@ SPAN_DECLARE(v18_state_t *) v18_init(v18_state_t *s,
return NULL;
}
memset(s, 0, sizeof(*s));
s->caller = caller;
s->calling_party = calling_party;
s->mode = mode;
s->put_msg = put_msg;
s->user_data = user_data;
@@ -763,7 +763,7 @@ SPAN_DECLARE(v18_state_t *) v18_init(v18_state_t *s,
s->baudot_tx_shift = 2;
/* TDD uses 5 bit data, no parity and 1.5 stop bits. We scan for the first stop bit, and
ride over the fraction. */
fsk_rx_init(&(s->fskrx), &preset_fsk_specs[FSK_WEITBRECHT], 7, v18_tdd_put_async_byte, s);
fsk_rx_init(&(s->fskrx), &preset_fsk_specs[FSK_WEITBRECHT], FSK_FRAME_MODE_5N1_FRAMES, v18_tdd_put_async_byte, s);
s->baudot_rx_shift = 0;
break;
case V18_MODE_5BIT_50:
@@ -773,7 +773,7 @@ SPAN_DECLARE(v18_state_t *) v18_init(v18_state_t *s,
s->baudot_tx_shift = 2;
/* TDD uses 5 bit data, no parity and 1.5 stop bits. We scan for the first stop bit, and
ride over the fraction. */
fsk_rx_init(&(s->fskrx), &preset_fsk_specs[FSK_WEITBRECHT50], 7, v18_tdd_put_async_byte, s);
fsk_rx_init(&(s->fskrx), &preset_fsk_specs[FSK_WEITBRECHT50], FSK_FRAME_MODE_5N1_FRAMES, v18_tdd_put_async_byte, s);
s->baudot_rx_shift = 0;
break;
case V18_MODE_DTMF:
+9 -9
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v22bis_rx.c,v 1.68 2009/06/02 16:03:56 steveu Exp $
* $Id: v22bis_rx.c,v 1.69 2009/11/04 15:52:06 steveu Exp $
*/
/*! \file */
@@ -490,7 +490,7 @@ static void process_half_baud(v22bis_state_t *s, const complexf_t *sample)
error could be higher. */
s->rx.gardner_step = 4;
s->rx.pattern_repeats = 0;
if (s->caller)
if (s->calling_party)
s->rx.training = V22BIS_RX_TRAINING_STAGE_UNSCRAMBLED_ONES;
else
s->rx.training = V22BIS_RX_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200;
@@ -586,7 +586,7 @@ static void process_half_baud(v22bis_state_t *s, const complexf_t *sample)
span_log(&s->logging, SPAN_LOG_FLOW, "+++ S1 detected (%d long)\n", s->rx.pattern_repeats);
if (s->bit_rate == 2400)
{
if (!s->caller)
if (!s->calling_party)
{
/* Accept establishment at 2400bps */
span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting U0011 (S1) (Answerer)\n");
@@ -601,7 +601,7 @@ static void process_half_baud(v22bis_state_t *s, const complexf_t *sample)
if (s->rx.training_count >= ms_to_symbols(270))
{
/* If we haven't seen the S1 signal by now, we are committed to be in 1200bps mode */
if (s->caller)
if (s->calling_party)
{
span_log(&s->logging, SPAN_LOG_FLOW, "+++ Rx normal operation (1200)\n");
/* The transmit side needs to sustain the scrambled ones for a timed period */
@@ -625,7 +625,7 @@ static void process_half_baud(v22bis_state_t *s, const complexf_t *sample)
}
else
{
if (s->caller)
if (s->calling_party)
{
if (s->rx.training_count >= ms_to_symbols(100 + 450))
{
@@ -716,7 +716,7 @@ SPAN_DECLARE_NONSTD(int) v22bis_rx(v22bis_state_t *s, const int16_t amp[], int l
/* Calculate the I filter, with an arbitrary phase step, just so we can calculate
the signal power of the required carrier, with any guard tone or spillback of our
own transmitted signal suppressed. */
if (s->caller)
if (s->calling_party)
{
ii = rx_pulseshaper_2400_re[6][0]*s->rx.rrc_filter[s->rx.rrc_filter_step];
for (j = 1; j < V22BIS_RX_FILTER_STEPS; j++)
@@ -769,7 +769,7 @@ SPAN_DECLARE_NONSTD(int) v22bis_rx(v22bis_state_t *s, const int16_t amp[], int l
if (step > PULSESHAPER_COEFF_SETS - 1)
step = PULSESHAPER_COEFF_SETS - 1;
s->rx.eq_put_step += PULSESHAPER_COEFF_SETS*40/(3*2);
if (s->caller)
if (s->calling_party)
{
ii = rx_pulseshaper_2400_re[step][0]*s->rx.rrc_filter[s->rx.rrc_filter_step];
qq = rx_pulseshaper_2400_im[step][0]*s->rx.rrc_filter[s->rx.rrc_filter_step];
@@ -836,7 +836,7 @@ int v22bis_rx_restart(v22bis_state_t *s)
s->rx.training_count = 0;
s->rx.signal_present = FALSE;
s->rx.carrier_phase_rate = dds_phase_ratef((s->caller) ? 2400.0f : 1200.0f);
s->rx.carrier_phase_rate = dds_phase_ratef((s->calling_party) ? 2400.0f : 1200.0f);
s->rx.carrier_phase = 0;
power_meter_init(&(s->rx.rx_power), 5);
v22bis_rx_signal_cutoff(s, -45.5f);
@@ -855,7 +855,7 @@ int v22bis_rx_restart(v22bis_state_t *s)
s->rx.training_error = 0.0f;
s->rx.total_baud_timing_correction = 0;
/* We want the carrier to pull in faster on the answerer side, as it has very little time to adapt. */
s->rx.carrier_track_i = (s->caller) ? 8000.0f : 40000.0f;
s->rx.carrier_track_i = (s->calling_party) ? 8000.0f : 40000.0f;
s->rx.carrier_track_p = 8000000.0f;
s->negotiated_bit_rate = 1200;
+6 -6
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v22bis_tx.c,v 1.63 2009/06/02 16:03:56 steveu Exp $
* $Id: v22bis_tx.c,v 1.64 2009/11/04 15:52:06 steveu Exp $
*/
/*! \file */
@@ -346,7 +346,7 @@ static complexf_t training_get(v22bis_state_t *s)
if (++s->tx.training_count >= ms_to_symbols(100))
{
span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting S11 after U0011\n");
if (s->caller)
if (s->calling_party)
{
s->tx.training_count = 0;
s->tx.training = V22BIS_TX_TRAINING_STAGE_S11;
@@ -523,7 +523,7 @@ static int v22bis_tx_restart(v22bis_state_t *s)
s->tx.rrc_filter_step = 0;
s->tx.scramble_reg = 0;
s->tx.scrambler_pattern_count = 0;
if (s->caller)
if (s->calling_party)
s->tx.training = V22BIS_TX_TRAINING_STAGE_INITIAL_SILENCE;
else
s->tx.training = V22BIS_TX_TRAINING_STAGE_INITIAL_TIMED_SILENCE;
@@ -634,7 +634,7 @@ SPAN_DECLARE(int) v22bis_current_bit_rate(v22bis_state_t *s)
SPAN_DECLARE(v22bis_state_t *) v22bis_init(v22bis_state_t *s,
int bit_rate,
int guard,
int caller,
int calling_party,
get_bit_func_t get_bit,
void *get_bit_user_data,
put_bit_func_t put_bit,
@@ -657,14 +657,14 @@ SPAN_DECLARE(v22bis_state_t *) v22bis_init(v22bis_state_t *s,
span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
span_log_set_protocol(&s->logging, "V.22bis");
s->bit_rate = bit_rate;
s->caller = caller;
s->calling_party = calling_party;
s->get_bit = get_bit;
s->get_bit_user_data = get_bit_user_data;
s->put_bit = put_bit;
s->put_bit_user_data = put_bit_user_data;
if (s->caller)
if (s->calling_party)
{
s->tx.carrier_phase_rate = dds_phase_ratef(1200.0f);
}
+33 -21
View File
@@ -23,7 +23,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v29rx.c,v 1.167 2009/07/08 15:11:09 steveu Exp $
* $Id: v29rx.c,v 1.167.4.4 2009/12/19 14:18:13 steveu Exp $
*/
/*! \file */
@@ -131,22 +131,28 @@ static const uint8_t space_map_9600[20][20] =
/* Coefficients for the band edge symbol timing synchroniser (alpha = 0.99) */
/* low_edge = 2.0f*M_PI*(CARRIER_NOMINAL_FREQ - BAUD_RATE/2.0f)/SAMPLE_RATE; */
/* high_edge = 2.0f*M_PI*(CARRIER_NOMINAL_FREQ + BAUD_RATE/2.0f)/SAMPLE_RATE; */
#define SIN_LOW_BAND_EDGE 0.382683432f
#define COS_LOW_BAND_EDGE 0.923879533f
#define SIN_HIGH_BAND_EDGE 0.760405966f
#define COS_HIGH_BAND_EDGE -0.649448048f
#define ALPHA 0.99f
#if defined(SPANDSP_USE_FIXED_POINT)
#define SYNC_LOW_BAND_EDGE_COEFF_0 ((int)(FP_FACTOR* 1.829281f)) /* 2*alpha*cos(low_edge) */
#define SYNC_LOW_BAND_EDGE_COEFF_1 ((int)(FP_FACTOR*-0.980100f)) /* -alpha^2 */
#define SYNC_HIGH_BAND_EDGE_COEFF_0 ((int)(FP_FACTOR*-1.285907f)) /* 2*alpha*cos(high_edge) */
#define SYNC_HIGH_BAND_EDGE_COEFF_1 ((int)(FP_FACTOR*-0.980100f)) /* -alpha^2 */
#define SYNC_CROSS_CORR_COEFF_A ((int)(FP_FACTOR*-0.932131f)) /* -alpha^2*sin(freq_diff) */
#define SYNC_CROSS_CORR_COEFF_B ((int)(FP_FACTOR* 0.752802f)) /* alpha*sin(high_edge) */
#define SYNC_CROSS_CORR_COEFF_C ((int)(FP_FACTOR*-0.378857f)) /* -alpha*sin(low_edge) */
#define SYNC_LOW_BAND_EDGE_COEFF_0 ((int)(FP_FACTOR*(2.0f*ALPHA*COS_LOW_BAND_EDGE)))
#define SYNC_LOW_BAND_EDGE_COEFF_1 ((int)(FP_FACTOR*(-ALPHA*ALPHA)))
#define SYNC_LOW_BAND_EDGE_COEFF_2 ((int)(FP_FACTOR*(-ALPHA*SIN_LOW_BAND_EDGE)))
#define SYNC_HIGH_BAND_EDGE_COEFF_0 ((int)(FP_FACTOR*(2.0f*ALPHA*COS_HIGH_BAND_EDGE)))
#define SYNC_HIGH_BAND_EDGE_COEFF_1 ((int)(FP_FACTOR*(-ALPHA*ALPHA)))
#define SYNC_HIGH_BAND_EDGE_COEFF_2 ((int)(FP_FACTOR*(-ALPHA*SIN_HIGH_BAND_EDGE)))
#define SYNC_MIXED_EDGES_COEFF_3 ((int)(FP_FACTOR*(-ALPHA*ALPHA*(SIN_HIGH_BAND_EDGE*COS_LOW_BAND_EDGE - SIN_LOW_BAND_EDGE*COS_HIGH_BAND_EDGE))))
#else
#define SYNC_LOW_BAND_EDGE_COEFF_0 1.829281f /* 2*alpha*cos(low_edge) */
#define SYNC_LOW_BAND_EDGE_COEFF_1 -0.980100f /* -alpha^2 */
#define SYNC_HIGH_BAND_EDGE_COEFF_0 -1.285907f /* 2*alpha*cos(high_edge) */
#define SYNC_HIGH_BAND_EDGE_COEFF_1 -0.980100f /* -alpha^2 */
#define SYNC_CROSS_CORR_COEFF_A -0.932131f /* -alpha^2*sin(freq_diff) */
#define SYNC_CROSS_CORR_COEFF_B 0.752802f /* alpha*sin(high_edge) */
#define SYNC_CROSS_CORR_COEFF_C -0.378857f /* -alpha*sin(low_edge) */
#define SYNC_LOW_BAND_EDGE_COEFF_0 (2.0f*ALPHA*COS_LOW_BAND_EDGE)
#define SYNC_LOW_BAND_EDGE_COEFF_1 (-ALPHA*ALPHA)
#define SYNC_LOW_BAND_EDGE_COEFF_2 (-ALPHA*SIN_LOW_BAND_EDGE)
#define SYNC_HIGH_BAND_EDGE_COEFF_0 (2.0f*ALPHA*COS_HIGH_BAND_EDGE)
#define SYNC_HIGH_BAND_EDGE_COEFF_1 (-ALPHA*ALPHA)
#define SYNC_HIGH_BAND_EDGE_COEFF_2 (-ALPHA*SIN_HIGH_BAND_EDGE)
#define SYNC_MIXED_EDGES_COEFF_3 (-ALPHA*ALPHA*(SIN_HIGH_BAND_EDGE*COS_LOW_BAND_EDGE - SIN_LOW_BAND_EDGE*COS_HIGH_BAND_EDGE))
#endif
SPAN_DECLARE(float) v29_rx_carrier_frequency(v29_rx_state_t *s)
@@ -489,12 +495,18 @@ static __inline__ void symbol_sync(v29_rx_state_t *s)
/* This routine adapts the position of the half baud samples entering the equalizer. */
/* This symbol sync scheme is based on the technique first described by Dominique Godard in
Passband Timing Recovery in an All-Digital Modem Receiver
IEEE TRANSACTIONS ON COMMUNICATIONS, VOL. COM-26, NO. 5, MAY 1978 */
/* This is slightly rearranged for figure 3b of the Godard paper, as this saves a couple of
maths operations */
#if defined(SPANDSP_USE_FIXED_POINT)
/* TODO: The scalings used here need more thorough evaluation, to see if overflows are possible. */
/* Cross correlate */
v = (((s->symbol_sync_low[1] >> 5)*(s->symbol_sync_high[1] >> 4)) >> 15)*SYNC_CROSS_CORR_COEFF_A
+ (((s->symbol_sync_low[0] >> 5)*(s->symbol_sync_high[1] >> 4)) >> 15)*SYNC_CROSS_CORR_COEFF_B
+ (((s->symbol_sync_low[1] >> 5)*(s->symbol_sync_high[0] >> 4)) >> 15)*SYNC_CROSS_CORR_COEFF_C;
v = (((s->symbol_sync_low[1] >> 5)*(s->symbol_sync_high[0] >> 4)) >> 15)*SYNC_LOW_BAND_EDGE_COEFF_2
- (((s->symbol_sync_low[0] >> 5)*(s->symbol_sync_high[1] >> 4)) >> 15)*SYNC_HIGH_BAND_EDGE_COEFF_2
+ (((s->symbol_sync_low[1] >> 5)*(s->symbol_sync_high[1] >> 4)) >> 15)*SYNC_MIXED_EDGES_COEFF_3;
/* Filter away any DC component */
p = v - s->symbol_sync_dc_filter[1];
s->symbol_sync_dc_filter[1] = s->symbol_sync_dc_filter[0];
@@ -514,9 +526,9 @@ static __inline__ void symbol_sync(v29_rx_state_t *s)
}
#else
/* Cross correlate */
v = s->symbol_sync_low[1]*s->symbol_sync_high[1]*SYNC_CROSS_CORR_COEFF_A
+ s->symbol_sync_low[0]*s->symbol_sync_high[1]*SYNC_CROSS_CORR_COEFF_B
+ s->symbol_sync_low[1]*s->symbol_sync_high[0]*SYNC_CROSS_CORR_COEFF_C;
v = s->symbol_sync_low[1]*s->symbol_sync_high[0]*SYNC_LOW_BAND_EDGE_COEFF_2
- s->symbol_sync_low[0]*s->symbol_sync_high[1]*SYNC_HIGH_BAND_EDGE_COEFF_2
+ s->symbol_sync_low[1]*s->symbol_sync_high[1]*SYNC_MIXED_EDGES_COEFF_3;
/* Filter away any DC component */
p = v - s->symbol_sync_dc_filter[1];
s->symbol_sync_dc_filter[1] = s->symbol_sync_dc_filter[0];
+11 -11
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v42.c,v 1.50 2009/02/10 13:06:47 steveu Exp $
* $Id: v42.c,v 1.51 2009/11/04 15:52:06 steveu Exp $
*/
/* THIS IS A WORK IN PROGRESS. IT IS NOT FINISHED. */
@@ -1138,11 +1138,11 @@ static void negotiation_rx_bit(v42_state_t *s, int new_bit)
break;
/*endif*/
s->rxstream &= 0x3FF;
if (s->caller && s->rxstream == 0x145)
if (s->calling_party && s->rxstream == 0x145)
{
s->rx_negotiation_step++;
}
else if (!s->caller && s->rxstream == 0x111)
else if (!s->calling_party && s->rxstream == 0x111)
{
s->rx_negotiation_step++;
}
@@ -1174,15 +1174,15 @@ static void negotiation_rx_bit(v42_state_t *s, int new_bit)
break;
/*endif*/
s->rxstream &= 0x3FF;
if (s->caller && s->rxstream == 0x185)
if (s->calling_party && s->rxstream == 0x185)
{
s->rx_negotiation_step++;
}
else if (s->caller && s->rxstream == 0x001)
else if (s->calling_party && s->rxstream == 0x001)
{
s->rx_negotiation_step++;
}
else if (!s->caller && s->rxstream == 0x113)
else if (!s->calling_party && s->rxstream == 0x113)
{
s->rx_negotiation_step++;
}
@@ -1206,7 +1206,7 @@ static void negotiation_rx_bit(v42_state_t *s, int new_bit)
{
/* HIT */
s->rx_negotiation_step++;
if (s->caller)
if (s->calling_party)
{
if (s->t400_timer >= 0)
{
@@ -1252,7 +1252,7 @@ static int v42_support_negotiation_tx_bit(v42_state_t *s)
{
int bit;
if (s->caller)
if (s->calling_party)
{
if (s->txbits <= 0)
{
@@ -1355,7 +1355,7 @@ SPAN_DECLARE(void) v42_restart(v42_state_t *s)
{
span_schedule_init(&s->lapm.sched);
s->lapm.we_are_originator = s->caller;
s->lapm.we_are_originator = s->calling_party;
lapm_restart(&s->lapm);
if (s->detect)
{
@@ -1379,7 +1379,7 @@ fprintf(stderr, "Setting T400 i\n");
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(v42_state_t *) v42_init(v42_state_t *s, int caller, int detect, v42_frame_handler_t frame_handler, void *user_data)
SPAN_DECLARE(v42_state_t *) v42_init(v42_state_t *s, int calling_party, int detect, v42_frame_handler_t frame_handler, void *user_data)
{
int alloced;
@@ -1394,7 +1394,7 @@ SPAN_DECLARE(v42_state_t *) v42_init(v42_state_t *s, int caller, int detect, v42
alloced = TRUE;
}
memset(s, 0, sizeof(*s));
s->caller = caller;
s->calling_party = calling_party;
s->detect = detect;
s->lapm.iframe_receive = frame_handler;
s->lapm.iframe_receive_user_data = user_data;
+340 -194
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v8.c,v 1.39 2009/06/24 00:34:38 steveu Exp $
* $Id: v8.c,v 1.42 2009/11/04 16:10:14 steveu Exp $
*/
/*! \file */
@@ -47,6 +47,7 @@
#include "spandsp/logging.h"
#include "spandsp/queue.h"
#include "spandsp/async.h"
#include "spandsp/vector_int.h"
#include "spandsp/complex.h"
#include "spandsp/dds.h"
#include "spandsp/tone_detect.h"
@@ -67,7 +68,6 @@
enum
{
V8_WAIT_1S,
V8_CI,
V8_CI_ON,
V8_CI_OFF,
V8_HEARD_ANSAM,
@@ -76,7 +76,6 @@ enum
V8_CM_WAIT,
V8_SIGC,
V8_WAIT_200MS,
V8_JM_ON,
V8_SIGA,
@@ -91,6 +90,23 @@ enum
V8_SYNC_V92
} v8_sync_types_e;
enum
{
V8_CALL_FUNCTION_TAG = 0x01,
V8_MODULATION_TAG = 0x05,
V8_PROTOCOLS_TAG = 0x0A,
V8_PSTN_ACCESS_TAG = 0x0D,
V8_NSF_TAG = 0x0F,
V8_PCM_MODEM_AVAILABILITY_TAG = 0x07,
V8_T66_TAG = 0x0E
};
enum
{
V8_CI_SYNC_OCTET = 0x00,
V8_CM_JM_SYNC_OCTET = 0xE0
};
SPAN_DECLARE(const char *) v8_call_function_to_str(int call_function)
{
switch (call_function)
@@ -172,12 +188,85 @@ SPAN_DECLARE(const char *) v8_protocol_to_str(int protocol)
SPAN_DECLARE(const char *) v8_pstn_access_to_str(int pstn_access)
{
switch (pstn_access)
{
case V8_PSTN_ACCESS_CALL_DCE_CELLULAR:
return "Calling modem on cellular";
case V8_PSTN_ACCESS_ANSWER_DCE_CELLULAR:
return "Answering modem on cellular";
case V8_PSTN_ACCESS_ANSWER_DCE_CELLULAR | V8_PSTN_ACCESS_CALL_DCE_CELLULAR:
return "Answering and calling modems on cellular";
case V8_PSTN_ACCESS_DCE_ON_DIGITAL:
return "DCE on digital";
case V8_PSTN_ACCESS_DCE_ON_DIGITAL | V8_PSTN_ACCESS_CALL_DCE_CELLULAR:
return "DCE on digital, and calling modem on cellular";
case V8_PSTN_ACCESS_DCE_ON_DIGITAL | V8_PSTN_ACCESS_ANSWER_DCE_CELLULAR:
return "DCE on digital, answering modem on cellular";
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";
}
return "???";
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(const char *) v8_nsf_to_str(int nsf)
{
switch (nsf)
{
case 0:
return "???";
}
return "???";
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(const char *) v8_pcm_modem_availability_to_str(int pcm_modem_availability)
{
switch (pcm_modem_availability)
{
case 0:
return "PCM unavailable";
case V8_PSTN_PCM_MODEM_V90_V92_ANALOGUE:
return "V.90/V.92 analogue available";
case V8_PSTN_PCM_MODEM_V90_V92_DIGITAL:
return "V.90/V.92 digital available";
case V8_PSTN_PCM_MODEM_V90_V92_DIGITAL | V8_PSTN_PCM_MODEM_V90_V92_ANALOGUE:
return "V.90/V.92 digital/analogue available";
case V8_PSTN_PCM_MODEM_V91:
return "V.91 available";
case V8_PSTN_PCM_MODEM_V91 | V8_PSTN_PCM_MODEM_V90_V92_ANALOGUE:
return "V.91 and V.90/V.92 analogue available";
case V8_PSTN_PCM_MODEM_V91 | V8_PSTN_PCM_MODEM_V90_V92_DIGITAL:
return "V.91 and V.90/V.92 digital available";
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";
}
return "???";
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(const char *) v8_t66_to_str(int t66)
{
/* T.66 doesn't really define any V.8 values. The bits are all reserved. */
switch (t66)
{
case 0:
return "???";
case 1:
return "Reserved TIA";
case 2:
return "Reserved";
case 3:
return "Reserved TIA + others";
case 4:
return "Reserved";
case 5:
return "Reserved TIA + others";
case 6:
return "Reserved";
case 7:
return "Reserved TIA + others";
}
return "???";
}
/*- End of function --------------------------------------------------------*/
@@ -203,11 +292,8 @@ SPAN_DECLARE(void) v8_log_supported_modulations(v8_state_t *s, int modulation_sc
static const uint8_t *process_call_function(v8_state_t *s, const uint8_t *p)
{
int call_function;
call_function = (*p >> 5) & 0x07;
span_log(&s->logging, SPAN_LOG_FLOW, "%s\n", v8_call_function_to_str(call_function));
s->call_function = call_function;
s->result.call_function = (*p >> 5) & 0x07;
span_log(&s->logging, SPAN_LOG_FLOW, "%s\n", v8_call_function_to_str(s->result.call_function));
return ++p;
}
/*- End of function --------------------------------------------------------*/
@@ -225,6 +311,7 @@ static const uint8_t *process_modulation_mode(v8_state_t *s, const uint8_t *p)
if (*p & 0x20)
far_end_modulations |= V8_MOD_V90;
/* Check for an extension octet */
if ((*++p & 0x38) == 0x10)
{
if (*p & 0x80)
@@ -238,6 +325,7 @@ static const uint8_t *process_modulation_mode(v8_state_t *s, const uint8_t *p)
if (*p & 0x01)
far_end_modulations |= V8_MOD_V32;
/* Check for an extension octet */
if ((*++p & 0x38) == 0x10)
{
if (*p & 0x80)
@@ -250,77 +338,59 @@ static const uint8_t *process_modulation_mode(v8_state_t *s, const uint8_t *p)
far_end_modulations |= V8_MOD_V26BIS;
if (*p & 0x01)
far_end_modulations |= V8_MOD_V26TER;
/* Skip any future extensions we do not understand */
while ((*++p & 0x38) == 0x10)
/* dummy loop */;
}
}
s->far_end_modulations = far_end_modulations;
v8_log_supported_modulations(s, s->far_end_modulations);
s->result.far_end_modulations = far_end_modulations;
v8_log_supported_modulations(s, s->result.far_end_modulations);
return ++p;
}
/*- End of function --------------------------------------------------------*/
static const uint8_t *process_protocols(v8_state_t *s, const uint8_t *p)
{
int protocol;
protocol = (*p >> 5) & 0x07;
span_log(&s->logging, SPAN_LOG_FLOW, "%s\n", v8_protocol_to_str(protocol));
s->protocol = protocol;
s->result.protocol = (*p >> 5) & 0x07;
span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, "%s\n", v8_protocol_to_str(s->result.protocol));
return ++p;
}
/*- End of function --------------------------------------------------------*/
static const uint8_t *process_pstn_access(v8_state_t *s, const uint8_t *p)
{
int pstn_access;
pstn_access = (*p >> 5) & 0x07;
if (pstn_access & V8_PSTN_ACCESS_DCE_ON_DIGTIAL)
span_log(&s->logging, SPAN_LOG_FLOW, "DCE on digital network connection\n");
else
span_log(&s->logging, SPAN_LOG_FLOW, "DCE on analogue network connection\n");
if (pstn_access & V8_PSTN_ACCESS_ANSWER_DCE_CELLULAR)
span_log(&s->logging, SPAN_LOG_FLOW, "Answer DCE on cellular connection\n");
if (pstn_access & V8_PSTN_ACCESS_CALL_DCE_CELLULAR)
span_log(&s->logging, SPAN_LOG_FLOW, "Call DCE on cellular connection\n");
s->result.pstn_access = (*p >> 5) & 0x07;
span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, "%s\n", v8_pstn_access_to_str(s->result.pstn_access));
return ++p;
}
/*- End of function --------------------------------------------------------*/
static const uint8_t *process_non_standard_facilities(v8_state_t *s, const uint8_t *p)
{
++p;
p += *p;
s->result.nsf = (*p >> 5) & 0x07;
s->result.nsf_seen = TRUE;
span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, "%s\n", v8_nsf_to_str(s->result.nsf));
return p;
}
/*- End of function --------------------------------------------------------*/
static const uint8_t *process_pcm_modem_availability(v8_state_t *s, const uint8_t *p)
{
int pcm_availability;
pcm_availability = (*p >> 5) & 0x07;
if (pcm_availability & V8_PSTN_PCM_MODEM_V91)
span_log(&s->logging, SPAN_LOG_FLOW, "V.91 available\n");
if (pcm_availability & V8_PSTN_PCM_MODEM_V90_V92_DIGITAL)
span_log(&s->logging, SPAN_LOG_FLOW, "V.90 or V.92 digital modem available\n");
if (pcm_availability & V8_PSTN_PCM_MODEM_V90_V92_ANALOGUE)
span_log(&s->logging, SPAN_LOG_FLOW, "V.90 or V.92 analogue modem available\n");
s->result.pcm_modem_availability = (*p >> 5) & 0x07;
span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, "%s\n", v8_pcm_modem_availability_to_str(s->result.pcm_modem_availability));
return ++p;
}
/*- End of function --------------------------------------------------------*/
static const uint8_t *process_t66(v8_state_t *s, const uint8_t *p)
{
s->result.t66 = (*p >> 5) & 0x07;
s->result.t66_seen = TRUE;
span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, "%s\n", v8_t66_to_str(s->result.t66));
return ++p;
}
/*- End of function --------------------------------------------------------*/
static void ci_decode(v8_state_t *s)
{
if ((s->rx_data[0] & 0x1F) == 0x01)
if ((s->rx_data[0] & 0x1F) == V8_CALL_FUNCTION_TAG)
process_call_function(s, &s->rx_data[0]);
}
/*- End of function --------------------------------------------------------*/
@@ -333,57 +403,60 @@ static void cm_jm_decode(v8_state_t *s)
return;
/* We must receive two consecutive identical CM or JM sequences to accept it. */
if (s->cm_jm_count <= 0
if (s->cm_jm_len <= 0
||
s->cm_jm_count != s->rx_data_ptr
s->cm_jm_len != s->rx_data_ptr
||
memcmp(s->cm_jm_data, s->rx_data, s->rx_data_ptr))
{
/* Save the current CM or JM sequence */
s->cm_jm_count = s->rx_data_ptr;
s->cm_jm_len = s->rx_data_ptr;
memcpy(s->cm_jm_data, s->rx_data, s->rx_data_ptr);
return;
}
/* We have a pair of matching CMs or JMs */
/* We have a matching pair of CMs or JMs, so we are happy this is correct. */
s->got_cm_jm = TRUE;
span_log(&s->logging, SPAN_LOG_FLOW, "Decoding\n");
/* Zero indicates the end */
s->cm_jm_data[s->cm_jm_count] = 0;
s->cm_jm_data[s->cm_jm_len] = 0;
s->far_end_modulations = 0;
s->result.far_end_modulations = 0;
p = s->cm_jm_data;
while (*p)
{
switch (*p & 0x1F)
{
case 0x01:
case V8_CALL_FUNCTION_TAG:
p = process_call_function(s, p);
break;
case 0x05:
case V8_MODULATION_TAG:
p = process_modulation_mode(s, p);
break;
case 0x0A:
case V8_PROTOCOLS_TAG:
p = process_protocols(s, p);
break;
case 0x0D:
case V8_PSTN_ACCESS_TAG:
p = process_pstn_access(s, p);
break;
case 0x0F:
case V8_NSF_TAG:
p = process_non_standard_facilities(s, p);
break;
case 0x07:
case V8_PCM_MODEM_AVAILABILITY_TAG:
p = process_pcm_modem_availability(s, p);
break;
case 0x0E:
case V8_T66_TAG:
p = process_t66(s, p);
break;
default:
p++;
break;
}
/* Skip any future extensions we do not understand */
while ((*p & 0x38) == 0x10)
p++;
}
}
/*- End of function --------------------------------------------------------*/
@@ -411,43 +484,60 @@ static void put_bit(void *user_data, int bit)
}
return;
}
//span_log(&s->logging, SPAN_LOG_FLOW, "Bit %d\n", bit);
/* Wait until we sync. */
s->bit_stream = (s->bit_stream >> 1) | (bit << 19);
if (s->bit_stream == 0x803FF)
new_preamble_type = V8_SYNC_CI;
else if (s->bit_stream == 0xF03FF)
new_preamble_type = V8_SYNC_CM_JM;
else if (s->bit_stream == 0xAABFF)
new_preamble_type = V8_SYNC_V92;
else
new_preamble_type = V8_SYNC_UNKNOWN;
if (new_preamble_type)
/* CI preamble is 10 ones then a framed 0x00
CM/JM preamble is 10 ones then a framed 0x07
V.92 preamble is 10 ones then a framed 0x55
Should we look at all 10 ones? The first couple might be
settling down. */
/* The preamble + synchronisation bit sequence should be unique in
any bit stream, so we can rely on seeing this at any time as being
a real sync code. */
switch (s->bit_stream)
{
case 0x803FF:
new_preamble_type = V8_SYNC_CI;
break;
case 0xF03FF:
new_preamble_type = V8_SYNC_CM_JM;
break;
case 0xAABFF:
new_preamble_type = V8_SYNC_V92;
break;
default:
new_preamble_type = V8_SYNC_UNKNOWN;
break;
}
if (new_preamble_type != V8_SYNC_UNKNOWN)
{
/* We have seen a fresh sync code */
/* Debug */
if (span_log_test(&s->logging, SPAN_LOG_FLOW))
{
if (s->preamble_type == V8_SYNC_CI)
if (s->preamble_type != V8_SYNC_UNKNOWN)
{
tag = "CI: ";
switch (s->preamble_type)
{
case V8_SYNC_CI:
tag = "CI: ";
break;
case V8_SYNC_CM_JM:
tag = (s->calling_party) ? "JM: " : "CM: ";
break;
case V8_SYNC_V92:
tag = "V92: ";
break;
default:
tag = "??: ";
break;
}
span_log_buf(&s->logging, SPAN_LOG_FLOW, tag, s->rx_data, s->rx_data_ptr);
}
else if (s->preamble_type == V8_SYNC_CM_JM)
{
if (s->caller)
tag = "JM: ";
else
tag = "CM: ";
}
else if (s->preamble_type == V8_SYNC_V92)
{
tag = "V92: ";
}
else
{
tag = "??: ";
}
span_log_buf(&s->logging, SPAN_LOG_FLOW, tag, s->rx_data, s->rx_data_ptr);
}
/* Decode previous sequence */
/* If we were handling a valid sync code then we should process what has been
received to date. */
switch (s->preamble_type)
{
case V8_SYNC_CI:
@@ -462,16 +552,16 @@ static void put_bit(void *user_data, int bit)
s->rx_data_ptr = 0;
}
/* Parse octets with 1 bit start, 1 bit stop */
if (s->preamble_type)
if (s->preamble_type != V8_SYNC_UNKNOWN)
{
/* Parse octets with 1 bit start, 1 bit stop */
s->bit_cnt++;
/* Start, stop? */
if ((s->bit_stream & 0x80400) == 0x80000 && s->bit_cnt >= 10)
{
/* Store the available data */
data = (uint8_t) ((s->bit_stream >> 11) & 0xFF);
/* CJ detection */
/* CJ (3 successive zero octets) detection */
if (data == 0)
{
if (++s->zero_byte_count == 3)
@@ -492,13 +582,14 @@ static void put_bit(void *user_data, int bit)
static void v8_decode_init(v8_state_t *s)
{
if (s->caller)
fsk_rx_init(&s->v21rx, &preset_fsk_specs[FSK_V21CH2], FALSE, put_bit, s);
else
fsk_rx_init(&s->v21rx, &preset_fsk_specs[FSK_V21CH1], FALSE, put_bit, s);
s->preamble_type = 0;
fsk_rx_init(&s->v21rx,
&preset_fsk_specs[(s->calling_party) ? FSK_V21CH2 : FSK_V21CH1],
FSK_FRAME_MODE_ASYNC,
put_bit,
s);
s->preamble_type = V8_SYNC_UNKNOWN;
s->bit_stream = 0;
s->cm_jm_count = 0;
s->cm_jm_len = 0;
s->got_cm_jm = FALSE;
s->got_cj = FALSE;
s->zero_byte_count = 0;
@@ -513,11 +604,22 @@ static int get_bit(void *user_data)
s = user_data;
if (queue_read(s->tx_queue, &bit, 1) <= 0)
bit = 1;
return SIG_STATUS_END_OF_DATA;
return bit;
}
/*- End of function --------------------------------------------------------*/
static void v8_put_preamble(v8_state_t *s)
{
static const uint8_t preamble[10] =
{
1, 1, 1, 1, 1, 1, 1, 1, 1, 1
};
queue_write(s->tx_queue, preamble, 10);
}
/*- End of function --------------------------------------------------------*/
static void v8_put_byte(v8_state_t *s, int data)
{
int i;
@@ -538,17 +640,12 @@ static void v8_put_byte(v8_state_t *s, int data)
static void send_cm_jm(v8_state_t *s, int mod_mask)
{
int val;
static const uint8_t preamble[20] =
{
/* 10 1's (0x3FF), then 10 bits of CM sync (0x00F) */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1
};
/* Send a CM, or a JM as appropriate */
queue_write(s->tx_queue, preamble, 20);
v8_put_preamble(s);
v8_put_byte(s, V8_CM_JM_SYNC_OCTET);
/* Data call */
v8_put_byte(s, (V8_CALL_V_SERIES << 5) | 0x01);
v8_put_byte(s, (V8_CALL_V_SERIES << 5) | V8_CALL_FUNCTION_TAG);
/* Supported modulations */
val = 0x05;
@@ -584,12 +681,12 @@ static void send_cm_jm(v8_state_t *s, int mod_mask)
val |= 0x80;
v8_put_byte(s, val);
v8_put_byte(s, (0 << 5) | 0x07);
v8_put_byte(s, (0 << 5) | V8_PCM_MODEM_AVAILABILITY_TAG);
v8_put_byte(s, (V8_PROTOCOL_LAPM_V42 << 5) | 0x0A);
v8_put_byte(s, (V8_PROTOCOL_LAPM_V42 << 5) | V8_PROTOCOLS_TAG);
/* No cellular right now */
v8_put_byte(s, (0 << 5) | 0x0D);
v8_put_byte(s, (0 << 5) | V8_PSTN_ACCESS_TAG);
}
/*- End of function --------------------------------------------------------*/
@@ -615,75 +712,122 @@ SPAN_DECLARE_NONSTD(int) v8_tx(v8_state_t *s, int16_t *amp, int max_len)
//span_log(&s->logging, SPAN_LOG_FLOW, "v8_tx state %d\n", s->state);
len = 0;
switch (s->state)
if (s->modem_connect_tone_tx_on)
{
case V8_CI_ON:
case V8_CM_ON:
case V8_JM_ON:
case V8_CJ_ON:
len = fsk_tx(&s->v21tx, amp, max_len);
break;
case V8_CM_WAIT:
/* Send the ANSam tone */
len = modem_connect_tones_tx(&s->ansam_tx, amp, max_len);
break;
if (s->modem_connect_tone_tx_on > ms_to_samples(75))
{
/* 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);
}
}
else
{
if (max_len > s->modem_connect_tone_tx_on)
len = s->modem_connect_tone_tx_on;
else
len = max_len;
vec_zeroi16(amp, len);
s->modem_connect_tone_tx_on -= len;
}
}
if (s->fsk_tx_on && len < max_len)
{
max_len -= len;
len = fsk_tx(&s->v21tx, amp + len, max_len);
if (len < max_len)
{
span_log(&s->logging, SPAN_LOG_FLOW, "FSK ends\n");
s->fsk_tx_on = FALSE;
}
}
return len;
}
/*- End of function --------------------------------------------------------*/
static void v8_send_ci(v8_state_t *s)
{
int i;
/* Send 4 CI packets in a burst (the spec says at least 3) */
for (i = 0; i < 4; i++)
{
v8_put_preamble(s);
v8_put_byte(s, V8_CI_SYNC_OCTET);
v8_put_byte(s, (V8_CALL_V_SERIES << 5) | V8_CALL_FUNCTION_TAG);
}
}
/*- End of function --------------------------------------------------------*/
static void handle_modem_connect_tone(v8_state_t *s, int tone)
{
s->result.modem_connect_tone_detected = tone;
span_log(&s->logging, SPAN_LOG_FLOW, "'%s' recognised\n", modem_connect_tone_to_str(tone));
if (tone == MODEM_CONNECT_TONES_ANSAM
||
tone == MODEM_CONNECT_TONES_ANSAM_PR)
{
/* Set the Te interval. The spec. says 500ms is the minimum,
but gives reasons why 1 second is a better value. */
s->state = V8_HEARD_ANSAM;
s->ci_timer = ms_to_samples(1000);
}
else
{
/* If we found a connect tone, and it isn't one of the modulated answer tones,
indicating V.8 startup, we are not going to do V.8 processing. */
span_log(&s->logging, SPAN_LOG_FLOW, "Non-V.8 modem connect tone detected\n");
s->state = V8_PARKED;
if (s->result_handler)
s->result_handler(s->result_handler_user_data, &s->result);
}
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
{
int i;
int residual_samples;
v8_result_t result;
static const uint8_t preamble[20] =
{
/* 10 1's (0x3FF), then 10 bits of CI sync (0x001) */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
};
int tone;
//span_log(&s->logging, SPAN_LOG_FLOW, "v8_rx state %d\n", s->state);
residual_samples = 0;
switch (s->state)
{
case V8_WAIT_1S:
residual_samples = modem_connect_tones_rx(&s->ansam_rx, amp, len);
/* Wait 1 second before sending the first CI packet */
if ((s->negotiation_timer -= len) > 0)
break;
s->state = V8_CI;
s->ci_count = 0;
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);
/* Fall through to the next state */
case V8_CI:
residual_samples = modem_connect_tones_rx(&s->ansam_rx, amp, len);
/* Send 4 CI packets in a burst (the spec says at least 3) */
for (i = 0; i < 4; i++)
{
/* 10 1's (0x3FF), then CI sync (0x001) */
queue_write(s->tx_queue, preamble, 20);
v8_put_byte(s, (V8_CALL_V_SERIES << 5) | 0x01);
}
fsk_tx_restart(&s->v21tx, &preset_fsk_specs[FSK_V21CH1]);
v8_send_ci(s);
s->state = V8_CI_ON;
s->fsk_tx_on = TRUE;
break;
case V8_CI_ON:
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;
}
if (queue_empty(s->tx_queue))
{
s->state = V8_CI_OFF;
s->ci_timer = ms_to_samples(500);
break;
}
break;
case V8_CI_OFF:
residual_samples = modem_connect_tones_rx(&s->ansam_rx, amp, len);
/* Check if an ANSam tone has been detected */
if (modem_connect_tones_rx_get(&s->ansam_rx))
/* Check if an ANSam or ANSam/ tone has been detected */
if ((tone = modem_connect_tones_rx_get(&s->ansam_rx)) != MODEM_CONNECT_TONES_NONE)
{
/* Set the Te interval. The spec. says 500ms is the minimum,
but gives reasons why 1 second is a better value. */
s->ci_timer = ms_to_samples(1000);
s->state = V8_HEARD_ANSAM;
handle_modem_connect_tone(s, tone);
break;
}
if ((s->ci_timer -= len) <= 0)
@@ -691,6 +835,7 @@ SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
if (++s->ci_count >= 10)
{
/* The spec says we should give up now. */
span_log(&s->logging, SPAN_LOG_FLOW, "Timeout waiting for modem connect tone\n");
s->state = V8_PARKED;
if (s->result_handler)
s->result_handler(s->result_handler_user_data, NULL);
@@ -698,46 +843,54 @@ SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
else
{
/* Try again */
s->state = V8_CI;
fsk_tx_restart(&s->v21tx, &preset_fsk_specs[FSK_V21CH1]);
v8_send_ci(s);
s->state = V8_CI_ON;
s->fsk_tx_on = TRUE;
}
}
break;
case V8_HEARD_ANSAM:
/* We have heard the ANSam signal, but we still need to wait for the
/* 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->state = V8_CM_ON;
s->negotiation_timer = ms_to_samples(5000);
send_cm_jm(s, s->available_modulations);
fsk_tx_restart(&s->v21tx, &preset_fsk_specs[FSK_V21CH1]);
send_cm_jm(s, s->local_end_modulations);
s->state = V8_CM_ON;
s->fsk_tx_on = TRUE;
}
break;
case V8_CM_ON:
residual_samples = fsk_rx(&s->v21rx, amp, len);
if (s->got_cm_jm)
{
/* Now JM has been detected we send CJ and wait for 75 ms
span_log(&s->logging, SPAN_LOG_FLOW, "JM recognised\n");
/* Now JM has been detected, we send CJ and wait for 75 ms
before finishing the V.8 analysis. */
s->negotiated_modulation = select_modulation(s->far_end_modulations);
s->result.negotiated_modulation = select_modulation(s->result.far_end_modulations);
queue_flush(s->tx_queue);
for (i = 0; i < 9; i++)
fsk_tx_restart(&s->v21tx, &preset_fsk_specs[FSK_V21CH1]);
for (i = 0; i < 3; i++)
v8_put_byte(s, 0);
s->state = V8_CJ_ON;
s->fsk_tx_on = TRUE;
break;
}
if ((s->negotiation_timer -= len) <= 0)
{
/* Timeout */
span_log(&s->logging, SPAN_LOG_FLOW, "Timeout waiting for JM\n");
s->state = V8_PARKED;
if (s->result_handler)
s->result_handler(s->result_handler_user_data, NULL);
}
if (queue_empty(s->tx_queue))
if (queue_contents(s->tx_queue) < 10)
{
/* Send CM again */
send_cm_jm(s, s->available_modulations);
send_cm_jm(s, s->local_end_modulations);
}
break;
case V8_CJ_ON:
@@ -752,49 +905,33 @@ SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
if ((s->negotiation_timer -= len) <= 0)
{
/* The V.8 negotiation has succeeded. */
span_log(&s->logging, SPAN_LOG_FLOW, "Negotiation succeeded\n");
s->state = V8_PARKED;
if (s->result_handler)
{
result.call_function = s->call_function;
result.available_modulations = s->far_end_modulations;
result.negotiated_modulation = s->negotiated_modulation;
result.protocol = s->protocol;
result.pstn_access = s->pstn_access;
result.nsf_seen = s->nsf_seen;
result.pcm_modem_availability = s->pcm_modem_availability;
result.t66_seen = s->t66_seen;
s->result_handler(s->result_handler_user_data, &result);
}
}
break;
case V8_WAIT_200MS:
if ((s->negotiation_timer -= len) <= 0)
{
/* Send the ANSam tone */
modem_connect_tones_tx_init(&s->ansam_tx, MODEM_CONNECT_TONES_ANSAM_PR);
v8_decode_init(s);
s->state = V8_CM_WAIT;
s->negotiation_timer = ms_to_samples(5000);
s->result_handler(s->result_handler_user_data, &s->result);
}
break;
case V8_CM_WAIT:
residual_samples = fsk_rx(&s->v21rx, amp, len);
if (s->got_cm_jm)
{
/* Stop sending ANSam and send JM instead */
span_log(&s->logging, SPAN_LOG_FLOW, "CM recognised\n");
/* 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->state = V8_JM_ON;
s->common_modulations = s->available_modulations & s->far_end_modulations;
s->negotiated_modulation = select_modulation(s->common_modulations);
s->common_modulations = s->local_end_modulations & s->result.far_end_modulations;
s->result.negotiated_modulation = select_modulation(s->common_modulations);
send_cm_jm(s, s->common_modulations);
s->modem_connect_tone_tx_on = ms_to_samples(75);
s->fsk_tx_on = TRUE;
break;
}
if ((s->negotiation_timer -= len) <= 0)
{
/* Timeout */
span_log(&s->logging, SPAN_LOG_FLOW, "Timeout waiting for CM\n");
s->state = V8_PARKED;
if (s->result_handler)
s->result_handler(s->result_handler_user_data, NULL);
@@ -804,7 +941,9 @@ SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
residual_samples = fsk_rx(&s->v21rx, amp, len);
if (s->got_cj)
{
/* Stop sending JM, and wait 75 ms */
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->state = V8_SIGA;
break;
@@ -812,12 +951,13 @@ SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
if ((s->negotiation_timer -= len) <= 0)
{
/* Timeout */
span_log(&s->logging, SPAN_LOG_FLOW, "Timeout waiting for CJ\n");
s->state = V8_PARKED;
if (s->result_handler)
s->result_handler(s->result_handler_user_data, NULL);
break;
}
if (queue_empty(s->tx_queue))
if (queue_contents(s->tx_queue) < 10)
{
/* Send JM */
send_cm_jm(s, s->common_modulations);
@@ -827,19 +967,10 @@ SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
if ((s->negotiation_timer -= len) <= 0)
{
/* The V.8 negotiation has succeeded. */
span_log(&s->logging, SPAN_LOG_FLOW, "Negotiation succeeded\n");
s->state = V8_PARKED;
if (s->result_handler)
{
result.call_function = s->call_function;
result.available_modulations = s->far_end_modulations;
result.negotiated_modulation = s->negotiated_modulation;
result.protocol = s->protocol;
result.pstn_access = s->pstn_access;
result.nsf_seen = s->nsf_seen;
result.pcm_modem_availability = s->pcm_modem_availability;
result.t66_seen = s->t66_seen;
s->result_handler(s->result_handler_user_data, &result);
}
s->result_handler(s->result_handler_user_data, &s->result);
}
break;
case V8_PARKED:
@@ -857,7 +988,8 @@ SPAN_DECLARE(logging_state_t *) v8_get_logging_state(v8_state_t *s)
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(v8_state_t *) v8_init(v8_state_t *s,
int caller,
int calling_party,
int use_ansam_pr,
int available_modulations,
v8_result_handler_t *result_handler,
void *user_data)
@@ -868,22 +1000,36 @@ SPAN_DECLARE(v8_state_t *) v8_init(v8_state_t *s,
return NULL;
}
memset(s, 0, sizeof(*s));
s->caller = caller;
s->available_modulations = available_modulations;
span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
span_log_set_protocol(&s->logging, "V.8");
s->local_end_modulations = available_modulations;
s->result_handler = result_handler;
s->result_handler_user_data = user_data;
s->ci_timer = 0;
if (s->caller)
if (calling_party)
{
s->calling_party = TRUE;
s->state = V8_WAIT_1S;
s->negotiation_timer = ms_to_samples(1000);
s->ci_count = 0;
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);
}
else
{
s->state = V8_WAIT_200MS;
s->negotiation_timer = ms_to_samples(200);
/* Send the ANSam or ANSam/ tone */
s->calling_party = FALSE;
modem_connect_tones_tx_init(&s->ansam_tx,
(use_ansam_pr) ? MODEM_CONNECT_TONES_ANSAM_PR : MODEM_CONNECT_TONES_ANSAM);
v8_decode_init(s);
s->state = V8_CM_WAIT;
s->negotiation_timer = ms_to_samples(200 + 5000);
s->modem_connect_tone_tx_on = ms_to_samples(75) + 1;
}
s->result.modem_connect_tone_detected = MODEM_CONNECT_TONES_NONE;
if ((s->tx_queue = queue_init(NULL, 1024, 0)) == NULL)
return NULL;
return s;
+4 -1
View File
@@ -22,7 +22,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: at_interpreter_tests.c,v 1.23 2009/05/30 15:23:13 steveu Exp $
* $Id: at_interpreter_tests.c,v 1.24 2009/10/09 14:53:57 steveu Exp $
*/
/*! \file */
@@ -234,6 +234,9 @@ static const struct command_response_s general_test_seq[] =
{"AT+ETBM?\r", "\r\n+ETBM:0,0\r\n\r\nOK\r\n"},
{"AT+EWIND=?\r", "\r\n+EWIND:(1-127),(1-127)\r\n\r\nOK\r\n"}, /* V.250 6.5.7 - Window size */
{"AT+EWIND?\r", "\r\n+EWIND:0,0\r\n\r\nOK\r\n"},
{"AT+F34=?\r", "\r\n+F34:(0-14),(0-14),(0-2),(0-14),(0-14)\r\n\r\nOK\r\n"},
/* T.31 B.6.1 - Initial V.34 rate controls for FAX */
{"AT+F34?\r", "\r\n+F34:0,0,0,0,0\r\n\r\nOK\r\n"},
{"AT+FAR=?\r", "\r\n0,1\r\n\r\nOK\r\n"}, /* T.31 8.5.1 - Adaptive reception control */
{"AT+FAR?\r", "\r\n0\r\n\r\nOK\r\n"},
{"AT+FCL=?\r", "\r\n(0-255)\r\n\r\nOK\r\n"}, /* T.31 8.5.2 - Carrier loss timeout */
+2 -2
View File
@@ -22,7 +22,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: fax_decode.c,v 1.57 2009/09/15 14:01:53 steveu Exp $
* $Id: fax_decode.c,v 1.58 2009/11/02 13:25:20 steveu Exp $
*/
/*! \page fax_decode_page FAX decoder
@@ -479,7 +479,7 @@ int main(int argc, char *argv[])
span_log_set_protocol(&t30_dummy.logging, "T.30");
hdlc_rx_init(&hdlcrx, FALSE, TRUE, 5, hdlc_accept, NULL);
fsk = fsk_rx_init(NULL, &preset_fsk_specs[FSK_V21CH2], TRUE, v21_put_bit, NULL);
fsk = fsk_rx_init(NULL, &preset_fsk_specs[FSK_V21CH2], FSK_FRAME_MODE_SYNC, v21_put_bit, NULL);
v17 = v17_rx_init(NULL, 14400, v17_put_bit, NULL);
v29 = v29_rx_init(NULL, 9600, v29_put_bit, NULL);
//v29 = v29_rx_init(NULL, 7200, v29_put_bit, NULL);
+3 -3
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: fax_tester.c,v 1.22 2009/02/12 12:38:39 steveu Exp $
* $Id: fax_tester.c,v 1.23 2009/11/02 13:25:20 steveu Exp $
*/
/*! \file */
@@ -496,7 +496,7 @@ void faxtester_set_rx_type(void *user_data, int type, int bit_rate, int short_tr
case T30_MODEM_V21:
if (s->flush_handler)
s->flush_handler(s, s->flush_user_data, 3);
fsk_rx_init(&t->v21_rx, &preset_fsk_specs[FSK_V21CH2], TRUE, (put_bit_func_t) hdlc_rx_put_bit, put_bit_user_data);
fsk_rx_init(&t->v21_rx, &preset_fsk_specs[FSK_V21CH2], FSK_FRAME_MODE_SYNC, (put_bit_func_t) hdlc_rx_put_bit, put_bit_user_data);
fsk_rx_signal_cutoff(&t->v21_rx, -45.5);
t->rx_handler = (span_rx_handler_t *) &fsk_rx;
t->rx_user_data = &t->v21_rx;
@@ -670,7 +670,7 @@ static void faxtester_fax_modems_init(fax_modems_state_t *s, int use_tep, void *
hdlc_rx_init(&s->hdlc_rx, FALSE, FALSE, HDLC_FRAMING_OK_THRESHOLD, hdlc_accept, user_data);
hdlc_tx_init(&s->hdlc_tx, FALSE, 2, FALSE, hdlc_underflow_handler, user_data);
fsk_rx_init(&s->v21_rx, &preset_fsk_specs[FSK_V21CH2], TRUE, (put_bit_func_t) hdlc_rx_put_bit, &s->hdlc_rx);
fsk_rx_init(&s->v21_rx, &preset_fsk_specs[FSK_V21CH2], FSK_FRAME_MODE_SYNC, (put_bit_func_t) hdlc_rx_put_bit, &s->hdlc_rx);
fsk_rx_signal_cutoff(&s->v21_rx, -45.5);
fsk_tx_init(&s->v21_tx, &preset_fsk_specs[FSK_V21CH2], (get_bit_func_t) hdlc_tx_get_bit, &s->hdlc_tx);
fsk_tx_set_modem_status_handler(&s->v21_tx, modem_tx_status, user_data);
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
#
# spandsp fax tests
#
+3 -3
View File
@@ -22,7 +22,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: fax_utils.c,v 1.3 2009/05/16 03:34:45 steveu Exp $
* $Id: fax_utils.c,v 1.3.4.1 2009/12/19 09:47:57 steveu Exp $
*/
#if defined(HAVE_CONFIG_H)
@@ -95,8 +95,8 @@ void log_transfer_statistics(t30_state_t *s, const char *tag)
printf("%s: ECM %s\n", tag, (t.error_correcting_mode) ? "on" : "off");
printf("%s: tx pages %d, rx pages %d\n", tag, t.pages_tx, t.pages_rx);
printf("%s: pages in the file %d\n", tag, t.pages_in_file);
printf("%s: image size %d x %d\n", tag, t.width, t.length);
printf("%s: image resolution %d x %d\n", tag, t.x_resolution, t.y_resolution);
printf("%s: image size %d pels x %d pels\n", tag, t.width, t.length);
printf("%s: image resolution %d pels/m x %d pels/m\n", tag, t.x_resolution, t.y_resolution);
printf("%s: bad rows %d, longest bad row run %d\n", tag, t.bad_rows, t.longest_bad_row_run);
printf("%s: bad ECM frames %d\n", tag, t.error_correcting_mode_retries);
printf("%s: compression type %d\n", tag, t.encoding);
+7 -7
View File
@@ -22,7 +22,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: fsk_tests.c,v 1.58 2009/07/09 13:52:09 steveu Exp $
* $Id: fsk_tests.c,v 1.59 2009/11/02 13:25:20 steveu Exp $
*/
/*! \page fsk_tests_page FSK modem tests
@@ -283,7 +283,7 @@ int main(int argc, char *argv[])
fprintf(stderr, " Cannot open audio file '%s'\n", decode_test_file);
exit(2);
}
caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], TRUE, put_bit, NULL);
caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], FSK_FRAME_MODE_SYNC, put_bit, NULL);
fsk_rx_set_modem_status_handler(caller_rx, rx_status, (void *) &caller_rx);
test_bps = preset_fsk_specs[modem_under_test_1].baud_rate;
@@ -306,7 +306,7 @@ int main(int argc, char *argv[])
else
{
printf("Test cutoff level\n");
caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], TRUE, cutoff_test_put_bit, NULL);
caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], FSK_FRAME_MODE_SYNC, cutoff_test_put_bit, NULL);
fsk_rx_signal_cutoff(caller_rx, -30.0f);
fsk_rx_set_modem_status_handler(caller_rx, cutoff_test_rx_status, (void *) &caller_rx);
on_at = 0;
@@ -370,14 +370,14 @@ int main(int argc, char *argv[])
{
caller_tx = fsk_tx_init(NULL, &preset_fsk_specs[modem_under_test_1], (get_bit_func_t) bert_get_bit, &caller_bert);
fsk_tx_set_modem_status_handler(caller_tx, tx_status, (void *) &caller_tx);
answerer_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], TRUE, (put_bit_func_t) bert_put_bit, &answerer_bert);
answerer_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], FSK_FRAME_MODE_SYNC, (put_bit_func_t) bert_put_bit, &answerer_bert);
fsk_rx_set_modem_status_handler(answerer_rx, rx_status, (void *) &answerer_rx);
}
if (modem_under_test_2 >= 0)
{
answerer_tx = fsk_tx_init(NULL, &preset_fsk_specs[modem_under_test_2], (get_bit_func_t) bert_get_bit, &answerer_bert);
fsk_tx_set_modem_status_handler(answerer_tx, tx_status, (void *) &answerer_tx);
caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_2], TRUE, (put_bit_func_t) bert_put_bit, &caller_bert);
caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_2], FSK_FRAME_MODE_SYNC, (put_bit_func_t) bert_put_bit, &caller_bert);
fsk_rx_set_modem_status_handler(caller_rx, rx_status, (void *) &caller_rx);
}
test_bps = preset_fsk_specs[modem_under_test_1].baud_rate;
@@ -477,14 +477,14 @@ int main(int argc, char *argv[])
{
caller_tx = fsk_tx_init(NULL, &preset_fsk_specs[modem_under_test_1], (get_bit_func_t) bert_get_bit, &caller_bert);
fsk_tx_set_modem_status_handler(caller_tx, tx_status, (void *) &caller_tx);
answerer_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], TRUE, (put_bit_func_t) bert_put_bit, &answerer_bert);
answerer_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], FSK_FRAME_MODE_SYNC, (put_bit_func_t) bert_put_bit, &answerer_bert);
fsk_rx_set_modem_status_handler(answerer_rx, rx_status, (void *) &answerer_rx);
}
if (modem_under_test_2 >= 0)
{
answerer_tx = fsk_tx_init(NULL, &preset_fsk_specs[modem_under_test_2], (get_bit_func_t) bert_get_bit, &answerer_bert);
fsk_tx_set_modem_status_handler(answerer_tx, tx_status, (void *) &answerer_tx);
caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_2], TRUE, (put_bit_func_t) bert_put_bit, &caller_bert);
caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_2], FSK_FRAME_MODE_SYNC, (put_bit_func_t) bert_put_bit, &caller_bert);
fsk_rx_set_modem_status_handler(caller_rx, rx_status, (void *) &caller_rx);
}
noise_level++;
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -22,7 +22,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t38_gateway_tests.c,v 1.82 2009/05/30 15:23:14 steveu Exp $
* $Id: t38_gateway_tests.c,v 1.82.4.1 2009/12/19 09:47:57 steveu Exp $
*/
/*! \file */
@@ -99,7 +99,7 @@ static int phase_b_handler(t30_state_t *s, void *user_data, int result)
char tag[20];
i = (int) (intptr_t) user_data;
snprintf(tag, sizeof(tag), "%c: Phase B:", i);
snprintf(tag, sizeof(tag), "%c: Phase B", i);
printf("%c: Phase B handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result));
log_rx_parameters(s, tag);
return T30_ERR_OK;
@@ -112,7 +112,7 @@ static int phase_d_handler(t30_state_t *s, void *user_data, int result)
char tag[20];
i = (int) (intptr_t) user_data;
snprintf(tag, sizeof(tag), "%c: Phase D:", i);
snprintf(tag, sizeof(tag), "%c: Phase D", i);
printf("%c: Phase D handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result));
log_transfer_statistics(s, tag);
log_tx_parameters(s, tag);
@@ -128,7 +128,7 @@ static void phase_e_handler(t30_state_t *s, void *user_data, int result)
char tag[20];
i = (int) (intptr_t) user_data;
snprintf(tag, sizeof(tag), "%c: Phase E:", i);
snprintf(tag, sizeof(tag), "%c: Phase E", i);
printf("%c: Phase E handler on channel %c - (%d) %s\n", i, i, result, t30_completion_code_to_str(result));
log_transfer_statistics(s, tag);
log_tx_parameters(s, tag);
@@ -22,7 +22,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t38_gateway_to_terminal_tests.c,v 1.66 2009/05/30 15:23:14 steveu Exp $
* $Id: t38_gateway_to_terminal_tests.c,v 1.66.4.1 2009/12/19 09:47:57 steveu Exp $
*/
/*! \file */
@@ -94,7 +94,7 @@ static int phase_b_handler(t30_state_t *s, void *user_data, int result)
char tag[20];
i = (int) (intptr_t) user_data;
snprintf(tag, sizeof(tag), "%c: Phase B:", i);
snprintf(tag, sizeof(tag), "%c: Phase B", i);
printf("%c: Phase B handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result));
log_rx_parameters(s, tag);
return T30_ERR_OK;
@@ -107,7 +107,7 @@ static int phase_d_handler(t30_state_t *s, void *user_data, int result)
char tag[20];
i = (int) (intptr_t) user_data;
snprintf(tag, sizeof(tag), "%c: Phase D:", i);
snprintf(tag, sizeof(tag), "%c: Phase D", i);
printf("%c: Phase D handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result));
log_transfer_statistics(s, tag);
log_tx_parameters(s, tag);
@@ -123,7 +123,7 @@ static void phase_e_handler(t30_state_t *s, void *user_data, int result)
char tag[20];
i = (int) (intptr_t) user_data;
snprintf(tag, sizeof(tag), "%c: Phase E:", i);
snprintf(tag, sizeof(tag), "%c: Phase E", i);
printf("%c: Phase E handler on channel %c - (%d) %s\n", i, i, result, t30_completion_code_to_str(result));
log_transfer_statistics(s, tag);
log_tx_parameters(s, tag);
+548 -27
View File
@@ -22,7 +22,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t38_non_ecm_buffer_tests.c,v 1.5 2009/04/25 14:17:47 steveu Exp $
* $Id: t38_non_ecm_buffer_tests.c,v 1.5.4.1 2009/12/19 06:43:28 steveu Exp $
*/
/*! \file */
@@ -50,6 +50,88 @@ module, used for T.38 gateways.
#include "spandsp.h"
/* A pattern of widening gaps between ones, until at 11 apart an
EOL should be registered */
static const uint8_t spreader[] =
{
0x55,
0x55,
0x55,
0x55,
0x55,
0x55,
0x55,
0x55, /* 1 apart */
0x22, /* 2 and 3 apart */
0x10, /* 4 apart */
0x40, /* 5 apart */
0x80, /* 6 apart */
0x80, /* 7 apart */
0x40, /* 8 apart */
0x10, /* 9 apart */
0x02, /* 10 apart */
0x00,
0x25 /* 11 apart */
};
static int bit_no;
static int xxx(t38_non_ecm_buffer_state_t *s, logging_state_t *l, int log_bits, int n, int expected)
{
int i;
int j;
int bit;
t38_non_ecm_buffer_inject(s, &spreader[n], 1);
if (expected >= 0)
{
for (i = 0; i < 128; i++)
{
bit = t38_non_ecm_buffer_get_bit((void *) s);
if (log_bits)
printf("Rx bit %d - %d\n", bit_no, bit);
if (bit != expected)
{
printf("Tests failed - %d %d %d\n", bit_no, bit, expected);
exit(2);
}
bit_no++;
}
}
else
{
j = -1;
for (i = 0; i < 256; i++)
{
bit = t38_non_ecm_buffer_get_bit((void *) s);
if (log_bits)
printf("Rx bit %d - %d\n", bit_no, bit);
if (j < 0)
{
if (bit == 1)
j = 18*8 - 5;
}
else
{
expected = (spreader[j >> 3] >> (7 - (j & 7))) & 1;
if (bit != expected)
{
printf("Tests failed - %d %d %d\n", bit_no, bit, expected);
exit(2);
}
j++;
if (j >= 18*8)
j = 0;
}
bit_no++;
if (j == 17*8)
return 0;
}
}
return 0;
}
/*- End of function --------------------------------------------------------*/
int main(int argc, char *argv[])
{
t38_non_ecm_buffer_state_t buffer;
@@ -60,65 +142,170 @@ int main(int argc, char *argv[])
int log_bits;
int i;
log_bits = FALSE;
log_bits = (argc > 1);
printf("T.38 non-ECM rate adapting buffer tests.\n");
span_log_init(&logging, SPAN_LOG_FLOW, NULL);
span_log_set_protocol(&logging, "Buffer");
printf("1 - Impose no minimum for the bits per row\n");
t38_non_ecm_buffer_init(&buffer, TRUE, 0);
memset(buf, 0, sizeof(buf));
memset(buf + 10, 0x55, 10);
buf[25] = 0x80;
memset(buf + 30, 0x55, 10);
t38_non_ecm_buffer_inject(&buffer, buf, 50);
t38_non_ecm_buffer_push(&buffer);
n = 0;
do
{
bit = t38_non_ecm_buffer_get_bit((void *) &buffer);
if (log_bits)
printf("Rx bit %d - %d\n", n++, bit);
}
while (bit >= 0);
bit_no = 0;
/* We should get ones until the buffers recognises an EOL */
printf(" We should get ones here\n");
for (i = 0; i < 17; i++)
xxx(&buffer, &logging, log_bits, i, 1);
printf(" We should change to zeros here\n");
xxx(&buffer, &logging, log_bits, i, 0);
for (i = 0; i < 17; i++)
xxx(&buffer, &logging, log_bits, i, 0);
printf(" We should get the first row here\n");
xxx(&buffer, &logging, log_bits, i, -1);
for (i = 0; i < 17; i++)
xxx(&buffer, &logging, log_bits, i, 0);
printf(" We should get the second row here\n");
xxx(&buffer, &logging, log_bits, i, -1);
for (i = 0; i < 17; i++)
xxx(&buffer, &logging, log_bits, i, 0);
printf(" We should get the third row here\n");
xxx(&buffer, &logging, log_bits, i, -1);
printf(" Done\n");
t38_non_ecm_buffer_report_input_status(&buffer, &logging);
t38_non_ecm_buffer_report_output_status(&buffer, &logging);
printf("2 - Impose no minimum for the bits per row, different alignment\n");
t38_non_ecm_buffer_init(&buffer, TRUE, 0);
n = 0;
memset(buf, 0, sizeof(buf));
/* The first one in this should be seen as the first EOL */
memset(buf + 10, 0x55, 10);
buf[25] = 0x40;
/* EOL 2 */
buf[25] = 0x20;
/* EOL 3 */
memset(buf + 30, 0x55, 10);
/* EOL 4 */
buf[45] = 0x10;
t38_non_ecm_buffer_inject(&buffer, buf, 50);
t38_non_ecm_buffer_push(&buffer);
n = 0;
do
for (;;)
{
bit = t38_non_ecm_buffer_get_bit((void *) &buffer);
if (log_bits)
printf("Rx bit %d - %d\n", n++, bit);
printf("Rx bit %d - %d\n", n, bit);
n++;
if (bit == SIG_STATUS_END_OF_DATA)
{
if (n != 337)
{
printf("Tests failed\n");
exit(2);
}
break;
}
if (n >= 18 && n <= 96)
{
if (bit == (n & 1))
{
printf("Tests failed\n");
exit(2);
}
}
else if (n >= 178 && n <= 256)
{
if (bit == (n & 1))
{
printf("Tests failed\n");
exit(2);
}
}
else if (n == 139 || n == 300)
{
if (bit != 1)
{
printf("Tests failed\n");
exit(2);
}
}
else
{
if (bit != 0)
{
printf("Tests failed\n");
exit(2);
}
}
}
while (bit >= 0);
t38_non_ecm_buffer_report_input_status(&buffer, &logging);
t38_non_ecm_buffer_report_output_status(&buffer, &logging);
printf("3 - Demand a fairly high minimum for the bits per row\n");
t38_non_ecm_buffer_init(&buffer, TRUE, 400);
n = 0;
memset(buf, 0, sizeof(buf));
/* The first one in this should be seen as the first EOL */
memset(buf + 10, 0x55, 10);
buf[25] = 0x01;
/* EOL 2 */
buf[25] = 0x08;
/* EOL 3 */
memset(buf + 30, 0x55, 10);
/* EOL 4 */
buf[45] = 0x04;
t38_non_ecm_buffer_inject(&buffer, buf, 50);
t38_non_ecm_buffer_push(&buffer);
n = 0;
do
for (;;)
{
bit = t38_non_ecm_buffer_get_bit((void *) &buffer);
if (log_bits)
printf("Rx bit %d - %d\n", n++, bit);
printf("Rx bit %d - %d\n", n, bit);
n++;
if (bit == SIG_STATUS_END_OF_DATA)
{
if (n != 1273)
{
printf("Tests failed\n");
exit(2);
}
break;
}
if (n >= 18 && n <= 96)
{
if (bit == (n & 1))
{
printf("Tests failed\n");
exit(2);
}
}
else if (n >= 834 && n <= 912)
{
if (bit == (n & 1))
{
printf("Tests failed\n");
exit(2);
}
}
else if (n == 429 || n == 1238)
{
if (bit != 1)
{
printf("Tests failed\n");
exit(2);
}
}
else
{
if (bit != 0)
{
printf("Tests failed\n");
exit(2);
}
}
}
while (bit >= 0);
t38_non_ecm_buffer_report_input_status(&buffer, &logging);
t38_non_ecm_buffer_report_output_status(&buffer, &logging);
printf("4 - Take some time to get to the first row of the image, output ahead\n");
t38_non_ecm_buffer_init(&buffer, TRUE, 400);
n = 0;
/* Get some initial bits from an empty buffer. These should be ones */
for (i = 0; i < 1000; i++)
{
@@ -131,6 +318,7 @@ int main(int argc, char *argv[])
exit(2);
}
}
printf(" Initial ones OK\n");
/* Now put some zeros into the buffer, but no EOL. We should continue
getting ones out. */
memset(buf, 0, sizeof(buf));
@@ -146,6 +334,7 @@ int main(int argc, char *argv[])
exit(2);
}
}
printf(" Continuing initial ones OK\n");
/* Now add a one, to make an EOL. We should see the zeros come out. */
buf[0] = 0x01;
t38_non_ecm_buffer_inject(&buffer, buf, 1);
@@ -160,8 +349,9 @@ int main(int argc, char *argv[])
exit(2);
}
}
printf(" First EOL caused zeros to output OK\n");
/* Now add another line. We should see the first line come out. This means just the
eighth bit from now will be a one. */
23rd bit from now will be a one. */
buf[0] = 0x00;
buf[4] = 0x01;
t38_non_ecm_buffer_inject(&buffer, buf, 5);
@@ -170,12 +360,343 @@ int main(int argc, char *argv[])
bit = t38_non_ecm_buffer_get_bit((void *) &buffer);
if (log_bits)
printf("Rx bit %d - %d\n", n++, bit);
if (i != 7 && bit != 0)
if ((i == 23 && bit == 0) || (i != 23 && bit != 0))
{
printf("Tests failed (%d)\n", i);
exit(2);
}
}
printf(" Second EOL caused the first row to output OK\n");
/* Now inject an RTC - 6 EOLs */
memset(buf, 0, sizeof(buf));
/* T.4 1D style */
for (i = 10; i < 19; i += 3)
{
buf[i] = 0x00;
buf[i + 1] = 0x10;
buf[i + 2] = 0x01;
}
/* T.4 2D style */
buf[25 + 0] = 0x00;
buf[25 + 1] = 0x18;
buf[25 + 2] = 0x00;
buf[25 + 3] = 0xC0;
buf[25 + 4] = 0x06;
buf[25 + 5] = 0x00;
buf[25 + 6] = 0x30;
buf[25 + 7] = 0x01;
buf[25 + 8] = 0x80;
buf[25 + 9] = 0x0C;
t38_non_ecm_buffer_inject(&buffer, buf, 50);
t38_non_ecm_buffer_push(&buffer);
for (i = 0; i < 1000; i++)
{
bit = t38_non_ecm_buffer_get_bit((void *) &buffer);
if (log_bits)
printf("Rx bit %d - %d\n", n++, bit);
if (i == 7
||
i == 400 + 11 + 0*12
||
i == 400 + 11 + 1*12
||
i == 400 + 11 + 2*12
||
i == 400 + 11 + 3*12
||
i == 400 + 11 + 4*12
||
i == 400 + 11 + 5*12
||
i == 400 + 11 + 60 + 400 + 4 + 0*13
||
i == 400 + 11 + 60 + 400 + 4 + 0*13 + 1
||
i == 400 + 11 + 60 + 400 + 4 + 1*13
||
i == 400 + 11 + 60 + 400 + 4 + 1*13 + 1
||
i == 400 + 11 + 60 + 400 + 4 + 2*13
||
i == 400 + 11 + 60 + 400 + 4 + 2*13 + 1
||
i == 400 + 11 + 60 + 400 + 4 + 3*13
||
i == 400 + 11 + 60 + 400 + 4 + 3*13 + 1
||
i == 400 + 11 + 60 + 400 + 4 + 4*13
||
i == 400 + 11 + 60 + 400 + 4 + 4*13 + 1
||
i == 400 + 11 + 60 + 400 + 4 + 5*13
||
i == 400 + 11 + 60 + 400 + 4 + 5*13 + 1)
{
if (bit == 0)
{
printf("Tests failed (%d)\n", i);
exit(2);
}
}
else
{
if (bit == 1)
{
printf("Tests failed (%d)\n", i);
exit(2);
}
}
}
printf(" RTC output OK\n");
t38_non_ecm_buffer_report_input_status(&buffer, &logging);
t38_non_ecm_buffer_report_output_status(&buffer, &logging);
printf("5 - Take some time to get to the first row of the image, output behind\n");
t38_non_ecm_buffer_init(&buffer, TRUE, 400);
n = 0;
/* Inject some ones. */
memset(buf, 0xFF, 100);
t38_non_ecm_buffer_inject(&buffer, buf, 100);
/* Inject some zeros */
memset(buf, 0, sizeof(buf));
t38_non_ecm_buffer_inject(&buffer, buf, 100);
for (i = 0; i < 1000; i++)
{
bit = t38_non_ecm_buffer_get_bit((void *) &buffer);
if (log_bits)
printf("Rx bit %d - %d\n", n++, bit);
if (bit != 1)
{
printf("Tests failed\n");
exit(2);
}
}
printf(" Initial ones OK\n");
/* Now add a one, to make an EOL. We should see the zeros come out. */
buf[0] = 0x01;
t38_non_ecm_buffer_inject(&buffer, buf, 1);
for (i = 0; i < 1000; i++)
{
bit = t38_non_ecm_buffer_get_bit((void *) &buffer);
if (log_bits)
printf("Rx bit %d - %d\n", n++, bit);
if (bit != 0)
{
printf("Tests failed\n");
exit(2);
}
}
printf(" First EOL caused zeros to output OK\n");
/* Now add another line. We should see the first line come out. This means just the
23rd bit from now will be a one. */
buf[0] = 0x00;
buf[4] = 0x01;
t38_non_ecm_buffer_inject(&buffer, buf, 5);
for (i = 0; i < 1000; i++)
{
bit = t38_non_ecm_buffer_get_bit((void *) &buffer);
if (log_bits)
printf("Rx bit %d - %d\n", n++, bit);
if ((i == 23 && bit == 0) || (i != 23 && bit != 0))
{
printf("Tests failed (%d)\n", i);
exit(2);
}
}
printf(" Second EOL caused the first row to output OK\n");
/* Now inject an RTC - 6 EOLs */
memset(buf, 0, sizeof(buf));
/* T.4 1D style */
for (i = 10; i < 19; i += 3)
{
buf[i] = 0x00;
buf[i + 1] = 0x10;
buf[i + 2] = 0x01;
}
/* T.4 2D style */
buf[25 + 0] = 0x00;
buf[25 + 1] = 0x18;
buf[25 + 2] = 0x00;
buf[25 + 3] = 0xC0;
buf[25 + 4] = 0x06;
buf[25 + 5] = 0x00;
buf[25 + 6] = 0x30;
buf[25 + 7] = 0x01;
buf[25 + 8] = 0x80;
buf[25 + 9] = 0x0C;
t38_non_ecm_buffer_inject(&buffer, buf, 50);
t38_non_ecm_buffer_push(&buffer);
for (i = 0; i < 1000; i++)
{
bit = t38_non_ecm_buffer_get_bit((void *) &buffer);
if (log_bits)
printf("Rx bit %d - %d\n", n++, bit);
if (i == 7
||
i == 400 + 11 + 0*12
||
i == 400 + 11 + 1*12
||
i == 400 + 11 + 2*12
||
i == 400 + 11 + 3*12
||
i == 400 + 11 + 4*12
||
i == 400 + 11 + 5*12
||
i == 400 + 11 + 60 + 400 + 4 + 0*13
||
i == 400 + 11 + 60 + 400 + 4 + 0*13 + 1
||
i == 400 + 11 + 60 + 400 + 4 + 1*13
||
i == 400 + 11 + 60 + 400 + 4 + 1*13 + 1
||
i == 400 + 11 + 60 + 400 + 4 + 2*13
||
i == 400 + 11 + 60 + 400 + 4 + 2*13 + 1
||
i == 400 + 11 + 60 + 400 + 4 + 3*13
||
i == 400 + 11 + 60 + 400 + 4 + 3*13 + 1
||
i == 400 + 11 + 60 + 400 + 4 + 4*13
||
i == 400 + 11 + 60 + 400 + 4 + 4*13 + 1
||
i == 400 + 11 + 60 + 400 + 4 + 5*13
||
i == 400 + 11 + 60 + 400 + 4 + 5*13 + 1)
{
if (bit == 0)
{
printf("Tests failed (%d)\n", i);
exit(2);
}
}
else
{
if (bit == 1)
{
printf("Tests failed (%d)\n", i);
exit(2);
}
}
}
printf(" RTC output OK\n");
t38_non_ecm_buffer_report_input_status(&buffer, &logging);
t38_non_ecm_buffer_report_output_status(&buffer, &logging);
printf("6 - TCF without leading ones\n");
t38_non_ecm_buffer_init(&buffer, FALSE, 400);
n = 0;
/* Get some initial bits from an empty buffer. These should be ones */
for (i = 0; i < 1000; i++)
{
bit = t38_non_ecm_buffer_get_bit((void *) &buffer);
if (log_bits)
printf("Rx bit %d - %d\n", n++, bit);
if (bit != 1)
{
printf("Tests failed\n");
exit(2);
}
}
printf(" Initial ones from an empty TCF buffer OK\n");
/* Now send some TCF through, and see that it comes out */
memset(buf, 0x00, sizeof(buf));
t38_non_ecm_buffer_inject(&buffer, buf, 500);
t38_non_ecm_buffer_push(&buffer);
for (i = 0; i < 500*8; i++)
{
bit = t38_non_ecm_buffer_get_bit((void *) &buffer);
if (log_bits)
printf("Rx bit %d - %d\n", n++, bit);
if (bit != 0)
{
printf("Tests failed\n");
exit(2);
}
}
printf(" Passthrough of TCF OK\n");
/* Check the right number of bits was buffered */
bit = t38_non_ecm_buffer_get_bit((void *) &buffer);
if (log_bits)
printf("Rx bit %d - %d\n", n++, bit);
if (bit != SIG_STATUS_END_OF_DATA)
{
printf("Tests failed\n");
exit(2);
}
printf(" End of data seen OK\n");
t38_non_ecm_buffer_report_input_status(&buffer, &logging);
t38_non_ecm_buffer_report_output_status(&buffer, &logging);
printf("7 - TCF with leading ones\n");
t38_non_ecm_buffer_init(&buffer, FALSE, 400);
n = 0;
/* Get some initial bits from an empty buffer. These should be ones */
for (i = 0; i < 1000; i++)
{
bit = t38_non_ecm_buffer_get_bit((void *) &buffer);
if (log_bits)
printf("Rx bit %d - %d\n", n++, bit);
if (bit != 1)
{
printf("Tests failed\n");
exit(2);
}
}
printf(" Initial ones from an empty TCF buffer OK\n");
/* Now send some initial ones, and see that we continue to get all ones
as the stuffing. */
memset(buf, 0xFF, 500);
t38_non_ecm_buffer_inject(&buffer, buf, 500);
for (i = 0; i < 500*8; i++)
{
bit = t38_non_ecm_buffer_get_bit((void *) &buffer);
if (log_bits)
printf("Rx bit %d - %d\n", n++, bit);
if (bit != 1)
{
printf("Tests failed\n");
exit(2);
}
}
printf(" Sustaining ones OK\n");
/* Now send some initial ones, and some TCF through, and see that only
the TCF comes out */
memset(buf, 0x00, sizeof(buf));
memset(buf, 0xFF, 100);
/* End the ones mid byte */
buf[100] = 0xF0;
t38_non_ecm_buffer_inject(&buffer, buf, 500);
t38_non_ecm_buffer_push(&buffer);
for (i = 0; i < 400*8; i++)
{
bit = t38_non_ecm_buffer_get_bit((void *) &buffer);
if (log_bits)
printf("Rx bit %d - %d\n", n++, bit);
if ((i < 4 && bit == 0) || (i >= 4 && bit != 0))
{
printf("Tests failed\n");
exit(2);
}
}
printf(" Passthrough of TCF OK\n");
/* Check the right number of bits was buffered */
bit = t38_non_ecm_buffer_get_bit((void *) &buffer);
if (log_bits)
printf("Rx bit %d - %d\n", n++, bit);
if (bit != SIG_STATUS_END_OF_DATA)
{
printf("Tests failed\n");
exit(2);
}
printf(" End of data seen OK\n");
t38_non_ecm_buffer_report_input_status(&buffer, &logging);
t38_non_ecm_buffer_report_output_status(&buffer, &logging);
+4 -4
View File
@@ -22,7 +22,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t38_terminal_tests.c,v 1.67 2009/04/25 14:34:45 steveu Exp $
* $Id: t38_terminal_tests.c,v 1.67.4.1 2009/12/19 09:47:57 steveu Exp $
*/
/*! \file */
@@ -90,7 +90,7 @@ static int phase_b_handler(t30_state_t *s, void *user_data, int result)
char tag[20];
i = (int) (intptr_t) user_data;
snprintf(tag, sizeof(tag), "%c: Phase B:", i);
snprintf(tag, sizeof(tag), "%c: Phase B", i);
printf("%c: Phase B handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result));
log_rx_parameters(s, tag);
return T30_ERR_OK;
@@ -103,7 +103,7 @@ static int phase_d_handler(t30_state_t *s, void *user_data, int result)
char tag[20];
i = (int) (intptr_t) user_data;
snprintf(tag, sizeof(tag), "%c: Phase D:", i);
snprintf(tag, sizeof(tag), "%c: Phase D", i);
printf("%c: Phase D handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result));
log_transfer_statistics(s, tag);
log_tx_parameters(s, tag);
@@ -119,7 +119,7 @@ static void phase_e_handler(t30_state_t *s, void *user_data, int result)
char tag[20];
i = (int) (intptr_t) user_data;
snprintf(tag, sizeof(tag), "%c: Phase E:", i);
snprintf(tag, sizeof(tag), "%c: Phase E", i);
printf("%c: Phase E handler on channel %c - (%d) %s\n", i, i, result, t30_completion_code_to_str(result));
log_transfer_statistics(s, tag);
log_tx_parameters(s, tag);
@@ -22,7 +22,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t38_terminal_to_gateway_tests.c,v 1.65 2009/05/30 15:23:14 steveu Exp $
* $Id: t38_terminal_to_gateway_tests.c,v 1.65.4.1 2009/12/19 09:47:57 steveu Exp $
*/
/*! \file */
@@ -94,7 +94,7 @@ static int phase_b_handler(t30_state_t *s, void *user_data, int result)
char tag[20];
i = (int) (intptr_t) user_data;
snprintf(tag, sizeof(tag), "%c: Phase B:", i);
snprintf(tag, sizeof(tag), "%c: Phase B", i);
printf("%c: Phase B handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result));
log_rx_parameters(s, tag);
return T30_ERR_OK;
@@ -107,7 +107,7 @@ static int phase_d_handler(t30_state_t *s, void *user_data, int result)
char tag[20];
i = (int) (intptr_t) user_data;
snprintf(tag, sizeof(tag), "%c: Phase D:", i);
snprintf(tag, sizeof(tag), "%c: Phase D", i);
printf("%c: Phase D handler on channel %c - (0x%X) %s\n", i, i, result, t30_frametype(result));
log_transfer_statistics(s, tag);
log_tx_parameters(s, tag);
@@ -123,7 +123,7 @@ static void phase_e_handler(t30_state_t *s, void *user_data, int result)
char tag[20];
i = (int) (intptr_t) user_data;
snprintf(tag, sizeof(tag), "%c: Phase E:", i);
snprintf(tag, sizeof(tag), "%c: Phase E", i);
printf("%c: Phase E handler on channel %c - (%d) %s\n", i, i, result, t30_completion_code_to_str(result));
log_transfer_statistics(s, tag);
log_tx_parameters(s, tag);
+14 -6
View File
@@ -22,7 +22,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t4_tests.c,v 1.69 2009/05/16 03:34:45 steveu Exp $
* $Id: t4_tests.c,v 1.69.4.1 2009/12/19 09:47:57 steveu Exp $
*/
/*! \file */
@@ -129,8 +129,8 @@ static void display_page_stats(t4_state_t *s)
t4_get_transfer_statistics(s, &stats);
printf("Pages = %d\n", stats.pages_transferred);
printf("Image size = %d x %d pixels\n", stats.width, stats.length);
printf("Image resolution = %d/m x %d/m\n", stats.x_resolution, stats.y_resolution);
printf("Image size = %d pels x %d pels\n", stats.width, stats.length);
printf("Image resolution = %d pels/m x %d pels/m\n", stats.x_resolution, stats.y_resolution);
printf("Bad rows = %d\n", stats.bad_rows);
printf("Longest bad row run = %d\n", stats.longest_bad_row_run);
printf("Bits per row - min %d, max %d\n", s->min_row_bits, s->max_row_bits);
@@ -144,6 +144,7 @@ static int row_read_handler(void *user_data, uint8_t buf[], size_t len)
const char *s;
static int row = 0;
/* Send the test pattern. */
s = t4_test_patterns[row++];
if (row >= 16)
return 0;
@@ -170,6 +171,7 @@ static int row_write_handler(void *user_data, const uint8_t buf[], size_t len)
static int row = 0;
uint8_t ref[8192];
/* Verify that what is received matches the test pattern. */
if (len == 0)
return 0;
s = t4_test_patterns[row++];
@@ -280,9 +282,15 @@ int main(int argc, char *argv[])
{
static const int compression_sequence[] =
{
//T4_COMPRESSION_NONE,
T4_COMPRESSION_ITU_T4_1D,
T4_COMPRESSION_ITU_T4_2D,
T4_COMPRESSION_ITU_T6
T4_COMPRESSION_ITU_T6,
//T4_COMPRESSION_ITU_T85,
//T4_COMPRESSION_ITU_T43,
//T4_COMPRESSION_ITU_T45,
//T4_COMPRESSION_ITU_T81,
//T4_COMPRESSION_ITU_SYCC_T81
};
int sends;
int page_no;
@@ -486,11 +494,11 @@ int main(int argc, char *argv[])
}
span_log_set_level(&receive_state.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
t4_rx_set_row_write_handler(&receive_state, row_write_handler, NULL);
t4_rx_set_image_width(&receive_state, t4_tx_get_image_width(&send_state));
t4_rx_set_x_resolution(&receive_state, t4_tx_get_x_resolution(&send_state));
t4_rx_set_y_resolution(&receive_state, t4_tx_get_y_resolution(&send_state));
t4_rx_set_image_width(&receive_state, t4_tx_get_image_width(&send_state));
/* Now send and receive all the pages in the source TIFF file */
/* Now send and receive the test data with all compression modes. */
page_no = 1;
/* If we are stepping around the compression schemes, reset to the start of the sequence. */
if (compression_step > 0)
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
#
# spandsp fax tests
#
+303 -66
View File
@@ -22,7 +22,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v8_tests.c,v 1.33 2009/05/30 15:23:14 steveu Exp $
* $Id: v8_tests.c,v 1.36 2009/11/04 16:10:14 steveu Exp $
*/
/*! \page v8_tests_page V.8 tests
@@ -70,30 +70,303 @@ static void handler(void *user_data, v8_result_t *result)
printf("%s V.8 negotiation failed\n", s);
return;
}
printf("%s V.8 negotiation result:\n", s);
printf(" Call function '%s'\n", v8_call_function_to_str(result->call_function));
printf(" Negotiated modulation '%s'\n", v8_modulation_to_str(result->negotiated_modulation));
printf(" Protocol '%s'\n", v8_protocol_to_str(result->protocol));
printf(" PSTN access '%s'\n", v8_pstn_access_to_str(result->pstn_access));
printf(" PCM modem availability '%s'\n", v8_pcm_modem_availability_to_str(result->pcm_modem_availability));
if (result->call_function == V8_CALL_V_SERIES
&&
result->negotiated_modulation == V8_MOD_V90
&&
result->protocol == V8_PROTOCOL_LAPM_V42)
if (result->modem_connect_tone_detected == MODEM_CONNECT_TONES_ANSAM
||
result->modem_connect_tone_detected == MODEM_CONNECT_TONES_ANSAM_PR
||
result->modem_connect_tone_detected == MODEM_CONNECT_TONES_NONE)
{
negotiations_ok++;
printf("%s V.8 negotiation result:\n", s);
printf(" Modem connect tone '%s'\n", modem_connect_tone_to_str(result->modem_connect_tone_detected));
printf(" Call function '%s'\n", v8_call_function_to_str(result->call_function));
printf(" Negotiated modulation '%s'\n", v8_modulation_to_str(result->negotiated_modulation));
printf(" Protocol '%s'\n", v8_protocol_to_str(result->protocol));
printf(" PSTN access '%s'\n", v8_pstn_access_to_str(result->pstn_access));
printf(" NSF %d %d\n", result->nsf_seen, result->nsf);
printf(" PCM modem availability '%s'\n", v8_pcm_modem_availability_to_str(result->pcm_modem_availability));
printf(" T.66 %d %d\n", result->t66_seen, result->t66);
if (result->call_function == V8_CALL_V_SERIES
&&
result->negotiated_modulation == V8_MOD_V90
&&
result->protocol == V8_PROTOCOL_LAPM_V42)
{
negotiations_ok++;
}
}
else
{
printf("%s V.8 negotiation result:\n", s);
printf(" Modem connect tone '%s'\n", modem_connect_tone_to_str(result->modem_connect_tone_detected));
}
}
/*- End of function --------------------------------------------------------*/
static int v8_calls_v8_tests(SNDFILE *outhandle)
{
v8_state_t *v8_caller;
v8_state_t *v8_answerer;
logging_state_t *caller_logging;
logging_state_t *answerer_logging;
int caller_available_modulations;
int answerer_available_modulations;
int i;
int samples;
int remnant;
int outframes;
int16_t amp[SAMPLES_PER_CHUNK];
int16_t out_amp[2*SAMPLES_PER_CHUNK];
caller_available_modulations = V8_MOD_V17
| V8_MOD_V21
| V8_MOD_V22
| V8_MOD_V23HALF
| V8_MOD_V23
| V8_MOD_V26BIS
| V8_MOD_V26TER
| V8_MOD_V27TER
| V8_MOD_V29
| V8_MOD_V32
| V8_MOD_V34HALF
| V8_MOD_V34
| V8_MOD_V90
| V8_MOD_V92;
answerer_available_modulations = V8_MOD_V17
| V8_MOD_V21
| V8_MOD_V22
| V8_MOD_V23HALF
| V8_MOD_V23
| V8_MOD_V26BIS
| V8_MOD_V26TER
| V8_MOD_V27TER
| V8_MOD_V29
| V8_MOD_V32
| V8_MOD_V34HALF
| V8_MOD_V34
| V8_MOD_V90
| V8_MOD_V92;
negotiations_ok = 0;
v8_caller = v8_init(NULL, TRUE, TRUE, caller_available_modulations, handler, (void *) "caller");
v8_answerer = v8_init(NULL, FALSE, TRUE, answerer_available_modulations, handler, (void *) "answerer");
caller_logging = v8_get_logging_state(v8_caller);
span_log_set_level(caller_logging, SPAN_LOG_FLOW | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
span_log_set_tag(caller_logging, "caller");
answerer_logging = v8_get_logging_state(v8_answerer);
span_log_set_level(answerer_logging, SPAN_LOG_FLOW | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
span_log_set_tag(answerer_logging, "answerer");
for (i = 0; i < 1000; i++)
{
samples = v8_tx(v8_caller, amp, SAMPLES_PER_CHUNK);
if (samples < SAMPLES_PER_CHUNK)
{
memset(amp + samples, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - samples));
samples = SAMPLES_PER_CHUNK;
}
span_log_bump_samples(caller_logging, samples);
remnant = v8_rx(v8_answerer, amp, samples);
for (i = 0; i < samples; i++)
out_amp[2*i] = amp[i];
samples = v8_tx(v8_answerer, amp, SAMPLES_PER_CHUNK);
if (samples < SAMPLES_PER_CHUNK)
{
memset(amp + samples, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - samples));
samples = SAMPLES_PER_CHUNK;
}
span_log_bump_samples(answerer_logging, samples);
if (v8_rx(v8_caller, amp, samples) && remnant)
break;
for (i = 0; i < samples; i++)
out_amp[2*i + 1] = amp[i];
outframes = sf_writef_short(outhandle, out_amp, samples);
if (outframes != samples)
{
fprintf(stderr, " Error writing audio file\n");
exit(2);
}
}
v8_free(v8_caller);
v8_free(v8_answerer);
if (negotiations_ok != 2)
{
printf("Tests failed.\n");
exit(2);
}
return 0;
}
/*- End of function --------------------------------------------------------*/
static int non_v8_calls_v8_tests(SNDFILE *outhandle)
{
silence_gen_state_t *non_v8_caller_tx;
modem_connect_tones_rx_state_t *non_v8_caller_rx;
v8_state_t *v8_answerer;
logging_state_t *answerer_logging;
int answerer_available_modulations;
int i;
int samples;
int remnant;
int outframes;
int tone;
int16_t amp[SAMPLES_PER_CHUNK];
int16_t out_amp[2*SAMPLES_PER_CHUNK];
answerer_available_modulations = V8_MOD_V17
| V8_MOD_V21
| V8_MOD_V22
| V8_MOD_V23HALF
| V8_MOD_V23
| V8_MOD_V26BIS
| V8_MOD_V26TER
| V8_MOD_V27TER
| V8_MOD_V29
| V8_MOD_V32
| V8_MOD_V34HALF
| V8_MOD_V34
| V8_MOD_V90
| V8_MOD_V92;
negotiations_ok = 0;
non_v8_caller_tx = silence_gen_init(NULL, 10*SAMPLE_RATE);
non_v8_caller_rx = modem_connect_tones_rx_init(NULL, MODEM_CONNECT_TONES_ANS_PR, NULL, NULL);
v8_answerer = v8_init(NULL, FALSE, TRUE, answerer_available_modulations, handler, (void *) "answerer");
answerer_logging = v8_get_logging_state(v8_answerer);
span_log_set_level(answerer_logging, SPAN_LOG_FLOW | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
span_log_set_tag(answerer_logging, "answerer");
for (i = 0; i < 1000; i++)
{
samples = silence_gen(non_v8_caller_tx, amp, SAMPLES_PER_CHUNK);
if (samples < SAMPLES_PER_CHUNK)
{
memset(amp + samples, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - samples));
samples = SAMPLES_PER_CHUNK;
}
remnant = v8_rx(v8_answerer, amp, samples);
if (remnant)
break;
for (i = 0; i < samples; i++)
out_amp[2*i] = amp[i];
samples = v8_tx(v8_answerer, amp, SAMPLES_PER_CHUNK);
if (samples < SAMPLES_PER_CHUNK)
{
memset(amp + samples, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - samples));
samples = SAMPLES_PER_CHUNK;
}
span_log_bump_samples(answerer_logging, samples);
modem_connect_tones_rx(non_v8_caller_rx, amp, samples);
if ((tone = modem_connect_tones_rx_get(non_v8_caller_rx)) != MODEM_CONNECT_TONES_NONE)
{
printf("Detected %s (%d)\n", modem_connect_tone_to_str(tone), tone);
if (tone == MODEM_CONNECT_TONES_ANSAM_PR)
negotiations_ok++;
}
for (i = 0; i < samples; i++)
out_amp[2*i + 1] = amp[i];
outframes = sf_writef_short(outhandle, out_amp, samples);
if (outframes != samples)
{
fprintf(stderr, " Error writing audio file\n");
exit(2);
}
}
silence_gen_free(non_v8_caller_tx);
modem_connect_tones_rx_free(non_v8_caller_rx);
v8_free(v8_answerer);
if (negotiations_ok != 1)
{
printf("Tests failed.\n");
exit(2);
}
return 0;
}
/*- End of function --------------------------------------------------------*/
static int v8_calls_non_v8_tests(SNDFILE *outhandle)
{
v8_state_t *v8_caller;
modem_connect_tones_tx_state_t *non_v8_answerer_tx;
logging_state_t *caller_logging;
int caller_available_modulations;
int i;
int samples;
int outframes;
int16_t amp[SAMPLES_PER_CHUNK];
int16_t out_amp[2*SAMPLES_PER_CHUNK];
caller_available_modulations = V8_MOD_V17
| V8_MOD_V21
| V8_MOD_V22
| V8_MOD_V23HALF
| V8_MOD_V23
| V8_MOD_V26BIS
| V8_MOD_V26TER
| V8_MOD_V27TER
| V8_MOD_V29
| V8_MOD_V32
| V8_MOD_V34HALF
| V8_MOD_V34
| V8_MOD_V90
| V8_MOD_V92;
negotiations_ok = 0;
v8_caller = v8_init(NULL, TRUE, TRUE, caller_available_modulations, handler, (void *) "caller");
non_v8_answerer_tx = modem_connect_tones_tx_init(NULL, MODEM_CONNECT_TONES_ANS_PR);
caller_logging = v8_get_logging_state(v8_caller);
span_log_set_level(caller_logging, SPAN_LOG_FLOW | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
span_log_set_tag(caller_logging, "caller");
for (i = 0; i < 1000; i++)
{
samples = v8_tx(v8_caller, amp, SAMPLES_PER_CHUNK);
if (samples < SAMPLES_PER_CHUNK)
{
memset(amp + samples, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - samples));
samples = SAMPLES_PER_CHUNK;
}
span_log_bump_samples(caller_logging, samples);
for (i = 0; i < samples; i++)
out_amp[2*i] = amp[i];
samples = modem_connect_tones_tx(non_v8_answerer_tx, amp, SAMPLES_PER_CHUNK);
if (samples < SAMPLES_PER_CHUNK)
{
memset(amp + samples, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - samples));
samples = SAMPLES_PER_CHUNK;
}
if (v8_rx(v8_caller, amp, samples))
break;
for (i = 0; i < samples; i++)
out_amp[2*i + 1] = amp[i];
outframes = sf_writef_short(outhandle, out_amp, samples);
if (outframes != samples)
{
fprintf(stderr, " Error writing audio file\n");
exit(2);
}
}
v8_free(v8_caller);
modem_connect_tones_tx_free(non_v8_answerer_tx);
#if 0
if (negotiations_ok != 1)
{
printf("Tests failed.\n");
exit(2);
}
#endif
return 0;
}
/*- End of function --------------------------------------------------------*/
int main(int argc, char *argv[])
{
int i;
int16_t amp[SAMPLES_PER_CHUNK];
int16_t out_amp[2*SAMPLES_PER_CHUNK];
v8_state_t *v8_caller;
v8_state_t *v8_answerer;
int outframes;
int samples;
int remnant;
int caller_available_modulations;
@@ -102,6 +375,7 @@ int main(int argc, char *argv[])
SNDFILE *outhandle;
int opt;
char *decode_test_file;
v8_state_t *v8_answerer;
logging_state_t *logging;
decode_test_file = NULL;
@@ -155,65 +429,28 @@ int main(int argc, char *argv[])
fprintf(stderr, " Cannot create audio file '%s'\n", OUTPUT_FILE_NAME);
exit(2);
}
v8_caller = v8_init(NULL, TRUE, caller_available_modulations, handler, (void *) "caller");
v8_answerer = v8_init(NULL, FALSE, answerer_available_modulations, handler, (void *) "answerer");
logging = v8_get_logging_state(v8_caller);
span_log_set_level(logging, SPAN_LOG_FLOW | SPAN_LOG_SHOW_TAG);
span_log_set_tag(logging, "caller");
logging = v8_get_logging_state(v8_answerer);
span_log_set_level(logging, SPAN_LOG_FLOW | SPAN_LOG_SHOW_TAG);
span_log_set_tag(logging, "answerer");
for (i = 0; i < 1000; i++)
{
samples = v8_tx(v8_caller, amp, SAMPLES_PER_CHUNK);
if (samples < SAMPLES_PER_CHUNK)
{
memset(amp + samples, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - samples));
samples = SAMPLES_PER_CHUNK;
}
remnant = v8_rx(v8_answerer, amp, samples);
for (i = 0; i < samples; i++)
out_amp[2*i] = amp[i];
samples = v8_tx(v8_answerer, amp, SAMPLES_PER_CHUNK);
if (samples < SAMPLES_PER_CHUNK)
{
memset(amp + samples, 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - samples));
samples = SAMPLES_PER_CHUNK;
}
if (v8_rx(v8_caller, amp, samples) && remnant)
break;
for (i = 0; i < samples; i++)
out_amp[2*i + 1] = amp[i];
outframes = sf_writef_short(outhandle, out_amp, samples);
if (outframes != samples)
{
fprintf(stderr, " Error writing audio file\n");
exit(2);
}
}
printf("Test 1: V.8 terminal calls V.8 terminal\n");
v8_calls_v8_tests(outhandle);
printf("Test 2: non-V.8 terminal calls V.8 terminal\n");
non_v8_calls_v8_tests(outhandle);
printf("Test 3: V.8 terminal calls non-V.8 terminal\n");
v8_calls_non_v8_tests(outhandle);
if (sf_close(outhandle))
{
fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_FILE_NAME);
exit(2);
}
v8_free(v8_caller);
v8_free(v8_answerer);
if (negotiations_ok != 2)
{
printf("Tests failed.\n");
exit(2);
}
printf("Tests passed.\n");
}
else
{
printf("Decode file '%s'\n", decode_test_file);
v8_answerer = v8_init(NULL, FALSE, answerer_available_modulations, handler, (void *) "answerer");
v8_answerer = v8_init(NULL, FALSE, TRUE, answerer_available_modulations, handler, (void *) "answerer");
logging = v8_get_logging_state(v8_answerer);
span_log_set_level(logging, SPAN_LOG_FLOW | SPAN_LOG_SHOW_TAG);
span_log_set_tag(logging, "decoder");