diff spandsp-0.0.6pre17/tests/fax_tester.c @ 4:26cd8f1ef0b1

import spandsp-0.0.6pre17
author Peter Meerwald <pmeerw@cosy.sbg.ac.at>
date Fri, 25 Jun 2010 15:50:58 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spandsp-0.0.6pre17/tests/fax_tester.c	Fri Jun 25 15:50:58 2010 +0200
@@ -0,0 +1,741 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * faxtester_tests.c
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2008 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: fax_tester.c,v 1.23 2009/11/02 13:25:20 steveu Exp $
+ */
+
+/*! \file */
+
+#if defined(HAVE_CONFIG_H)
+#include <config.h>
+#endif
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#if defined(HAVE_TGMATH_H)
+#include <tgmath.h>
+#endif
+#if defined(HAVE_MATH_H)
+#include <math.h>
+#endif
+#include "floating_fudge.h"
+#include <assert.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+
+#if defined(HAVE_LIBXML_XMLMEMORY_H)
+#include <libxml/xmlmemory.h>
+#endif
+#if defined(HAVE_LIBXML_PARSER_H)
+#include <libxml/parser.h>
+#endif
+#if defined(HAVE_LIBXML_XINCLUDE_H)
+#include <libxml/xinclude.h>
+#endif
+
+//#if defined(WITH_SPANDSP_INTERNALS)
+#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
+//#endif
+
+#include "spandsp.h"
+
+#include "fax_tester.h"
+
+#define HDLC_FRAMING_OK_THRESHOLD       5
+
+static void timer_update(faxtester_state_t *s, int len)
+{
+    s->timer += len;
+    if (s->timer > s->timeout)
+    {
+        s->timeout = 0x7FFFFFFFFFFFFFFFLL;
+        if (s->front_end_step_timeout_handler)
+            s->front_end_step_timeout_handler(s, s->front_end_step_timeout_user_data);
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+static void front_end_step_complete(faxtester_state_t *s)
+{
+    if (s->front_end_step_complete_handler)
+        s->front_end_step_complete_handler(s, s->front_end_step_complete_user_data);
+}
+/*- End of function --------------------------------------------------------*/
+
+void faxtester_send_hdlc_flags(faxtester_state_t *s, int flags)
+{
+    hdlc_tx_flags(&(s->modems.hdlc_tx), flags);
+}
+/*- End of function --------------------------------------------------------*/
+
+void faxtester_send_hdlc_msg(faxtester_state_t *s, const uint8_t *msg, int len, int crc_ok)
+{
+    hdlc_tx_frame(&(s->modems.hdlc_tx), msg, len);
+    if (!crc_ok)
+        hdlc_tx_corrupt_frame(&(s->modems.hdlc_tx));
+}
+/*- End of function --------------------------------------------------------*/
+
+static void hdlc_underflow_handler(void *user_data)
+{
+    faxtester_state_t *s;
+    uint8_t buf[400];
+
+    s = (faxtester_state_t *) user_data;
+    
+    if (s->image_buffer)
+    {
+        /* We are sending an ECM image */
+        if (s->image_ptr < s->image_len)
+        {
+            buf[0] = 0xFF;
+            buf[1] = 0x03;
+            buf[2] = 0x06;
+            buf[3] = s->image_ptr/s->ecm_frame_size;
+            memcpy(buf + 4, &s->image_buffer[s->image_ptr], s->ecm_frame_size);
+            hdlc_tx_frame(&(s->modems.hdlc_tx), buf, 4 + s->ecm_frame_size);
+            if (s->corrupt_crc >= 0  &&  s->corrupt_crc == s->image_ptr/s->ecm_frame_size)
+                hdlc_tx_corrupt_frame(&(s->modems.hdlc_tx));
+            s->image_ptr += s->ecm_frame_size;
+            return;
+        }
+        else
+        {
+            /* The actual image is over. We are sending the final RCP frames. */
+            if (s->image_bit_ptr > 2)
+            {
+                s->image_bit_ptr--;
+                buf[0] = 0xFF;
+                buf[1] = 0x03;
+                buf[2] = 0x86;
+                hdlc_tx_frame(&(s->modems.hdlc_tx), buf, 3);
+                return;
+            }
+            else
+            {
+                /* All done. */
+                s->image_buffer = NULL;
+            }
+        }
+    }
+    front_end_step_complete(s);
+}
+/*- End of function --------------------------------------------------------*/
+
+static void modem_tx_status(void *user_data, int status)
+{
+    faxtester_state_t *s;
+
+    s = (faxtester_state_t *) user_data;
+    printf("Tx status is %s (%d)\n", signal_status_to_str(status), status);
+    switch (status)
+    {
+    case SIG_STATUS_SHUTDOWN_COMPLETE:
+        front_end_step_complete(s);
+        break;
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+static void tone_detected(void *user_data, int tone, int level, int delay)
+{
+    faxtester_state_t *s;
+
+    s = (faxtester_state_t *) user_data;
+    span_log(&s->logging,
+             SPAN_LOG_FLOW,
+             "%s (%d) declared (%ddBm0)\n",
+             modem_connect_tone_to_str(tone),
+             tone,
+             level);
+    if (tone != MODEM_CONNECT_TONES_NONE)
+    {
+        s->tone_on_time = s->timer;
+    }
+    else
+    {
+        span_log(&s->logging,
+                 SPAN_LOG_FLOW,
+                 "Tone was on for %fs\n",
+                 (float) (s->timer - s->tone_on_time)/SAMPLE_RATE + 0.55);
+    }    
+    s->tone_state = tone;
+    if (tone == MODEM_CONNECT_TONES_NONE)
+        front_end_step_complete(s);
+}
+/*- End of function --------------------------------------------------------*/
+
+static int non_ecm_get_bit(void *user_data)
+{
+    faxtester_state_t *s;
+    int bit;
+
+    s = (faxtester_state_t *) user_data;
+    if (s->image_bit_ptr == 0)
+    {
+        if (s->image_ptr >= s->image_len)
+        {
+            s->image_buffer = NULL;
+            return SIG_STATUS_END_OF_DATA;
+        }
+        s->image_bit_ptr = 8;
+        s->image_ptr++;
+    }
+    s->image_bit_ptr--;
+    bit = (s->image_buffer[s->image_ptr] >> (7 - s->image_bit_ptr)) & 0x01;
+    //printf("Rx bit - %d\n", bit);
+    return bit;
+}
+/*- End of function --------------------------------------------------------*/
+
+void faxtester_set_non_ecm_image_buffer(faxtester_state_t *s, const uint8_t *buf, int len)
+{
+    s->image_ptr = 0;
+    s->image_bit_ptr = 8;
+    s->image_len = len;
+    s->image_buffer = buf;
+}
+/*- End of function --------------------------------------------------------*/
+
+void faxtester_set_ecm_image_buffer(faxtester_state_t *s, const uint8_t *buf, int len, int block, int frame_size, int crc_hit)
+{
+    int start;
+
+    start = 256*frame_size*block;
+    if (len > start + 256*frame_size)
+        len = start + 256*frame_size;
+
+    s->ecm_frame_size = frame_size;
+    s->image_ptr = start;
+    s->image_bit_ptr = 8;
+    s->image_len = len;
+    s->image_buffer = buf;
+    s->corrupt_crc = crc_hit;
+    /* Send the first frame */
+    hdlc_underflow_handler(s);
+}
+/*- End of function --------------------------------------------------------*/
+
+static void non_ecm_rx_status(void *user_data, int status)
+{
+    faxtester_state_t *s;
+
+    s = (faxtester_state_t *) user_data;
+    span_log(&s->logging, SPAN_LOG_FLOW, "Non-ECM carrier status is %s (%d)\n", signal_status_to_str(status), status);
+    switch (status)
+    {
+    case SIG_STATUS_TRAINING_FAILED:
+        s->modems.rx_trained = FALSE;
+        break;
+    case SIG_STATUS_TRAINING_SUCCEEDED:
+        /* The modem is now trained */
+        s->modems.rx_trained = TRUE;
+        break;
+    case SIG_STATUS_CARRIER_UP:
+        s->modems.rx_signal_present = TRUE;
+        break;
+    case SIG_STATUS_CARRIER_DOWN:
+        if (s->modems.rx_trained)
+        {
+            if (s->real_time_frame_handler)
+                s->real_time_frame_handler(s, s->real_time_frame_user_data, TRUE, NULL, 0);
+        }
+        s->modems.rx_signal_present = FALSE;
+        s->modems.rx_trained = FALSE;
+        break;
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+static void non_ecm_put_bit(void *user_data, int bit)
+{
+    faxtester_state_t *s;
+
+    if (bit < 0)
+    {
+        non_ecm_rx_status(user_data, bit);
+        return;
+    }
+    s = (faxtester_state_t *) user_data;
+}
+/*- End of function --------------------------------------------------------*/
+
+static void hdlc_rx_status(void *user_data, int status)
+{
+    faxtester_state_t *s;
+
+    s = (faxtester_state_t *) user_data;
+    fprintf(stderr, "HDLC carrier status is %s (%d)\n", signal_status_to_str(status), status);
+    switch (status)
+    {
+    case SIG_STATUS_TRAINING_FAILED:
+        s->modems.rx_trained = FALSE;
+        break;
+    case SIG_STATUS_TRAINING_SUCCEEDED:
+        /* The modem is now trained */
+        s->modems.rx_trained = TRUE;
+        break;
+    case SIG_STATUS_CARRIER_UP:
+        s->modems.rx_signal_present = TRUE;
+        break;
+    case SIG_STATUS_CARRIER_DOWN:
+        s->modems.rx_signal_present = FALSE;
+        s->modems.rx_trained = FALSE;
+        break;
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+static void hdlc_accept(void *user_data, const uint8_t *msg, int len, int ok)
+{
+    faxtester_state_t *s;
+
+    if (len < 0)
+    {
+        hdlc_rx_status(user_data, len);
+        return;
+    }
+    s = (faxtester_state_t *) user_data;
+    if (s->real_time_frame_handler)
+        s->real_time_frame_handler(s, s->real_time_frame_user_data, TRUE, msg, len);
+}
+/*- End of function --------------------------------------------------------*/
+
+static int v17_v21_rx(void *user_data, const int16_t amp[], int len)
+{
+    faxtester_state_t *t;
+    fax_modems_state_t *s;
+
+    t = (faxtester_state_t *) user_data;
+    s = &t->modems;
+    v17_rx(&s->v17_rx, amp, len);
+    fsk_rx(&s->v21_rx, amp, len);
+    if (s->rx_trained)
+    {
+        /* The fast modem has trained, so we no longer need to run the slow
+           one in parallel. */
+        span_log(&t->logging, SPAN_LOG_FLOW, "Switching from V.17 + V.21 to V.17 (%.2fdBm0)\n", v17_rx_signal_power(&s->v17_rx));
+        s->rx_handler = (span_rx_handler_t *) &v17_rx;
+        s->rx_user_data = &s->v17_rx;
+    }
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int v27ter_v21_rx(void *user_data, const int16_t amp[], int len)
+{
+    faxtester_state_t *t;
+    fax_modems_state_t *s;
+
+    t = (faxtester_state_t *) user_data;
+    s = &t->modems;
+    v27ter_rx(&s->v27ter_rx, amp, len);
+    fsk_rx(&s->v21_rx, amp, len);
+    if (s->rx_trained)
+    {
+        /* The fast modem has trained, so we no longer need to run the slow
+           one in parallel. */
+        span_log(&t->logging, SPAN_LOG_FLOW, "Switching from V.27ter + V.21 to V.27ter (%.2fdBm0)\n", v27ter_rx_signal_power(&s->v27ter_rx));
+        s->rx_handler = (span_rx_handler_t *) &v27ter_rx;
+        s->rx_user_data = &s->v27ter_rx;
+    }
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int v29_v21_rx(void *user_data, const int16_t amp[], int len)
+{
+    faxtester_state_t *t;
+    fax_modems_state_t *s;
+
+    t = (faxtester_state_t *) user_data;
+    s = &t->modems;
+    v29_rx(&s->v29_rx, amp, len);
+    fsk_rx(&s->v21_rx, amp, len);
+    if (s->rx_trained)
+    {
+        /* The fast modem has trained, so we no longer need to run the slow
+           one in parallel. */
+        span_log(&t->logging, SPAN_LOG_FLOW, "Switching from V.29 + V.21 to V.29 (%.2fdBm0)\n", v29_rx_signal_power(&s->v29_rx));
+        s->rx_handler = (span_rx_handler_t *) &v29_rx;
+        s->rx_user_data = &s->v29_rx;
+    }
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+int faxtester_rx(faxtester_state_t *s, int16_t *amp, int len)
+{
+    int i;
+
+    for (i = 0;  i < len;  i++)
+        amp[i] = dc_restore(&(s->modems.dc_restore), amp[i]);
+    s->modems.rx_handler(s->modems.rx_user_data, amp, len);
+    timer_update(s, len);
+    if (s->wait_for_silence)
+    {
+        if (!s->modems.rx_signal_present)
+        {
+            s->wait_for_silence = FALSE;
+            front_end_step_complete(s);
+        }
+    }
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+int faxtester_tx(faxtester_state_t *s, int16_t *amp, int max_len)
+{
+    int len;
+    int required_len;
+    
+    required_len = max_len;
+    len = 0;
+    if (s->transmit)
+    {
+        while ((len += s->modems.tx_handler(s->modems.tx_user_data, amp + len, max_len - len)) < max_len)
+        {
+            /* Allow for a change of tx handler within a block */
+            front_end_step_complete(s);
+            if (!s->transmit)
+            {
+                if (s->modems.transmit_on_idle)
+                {
+                    /* Pad to the requested length with silence */
+                    memset(amp + len, 0, (max_len - len)*sizeof(int16_t));
+                    len = max_len;        
+                }
+                break;
+            }
+        }
+    }
+    else
+    {
+        if (s->modems.transmit_on_idle)
+        {
+            /* Pad to the requested length with silence */
+            memset(amp, 0, max_len*sizeof(int16_t));
+            len = max_len;        
+        }
+    }
+    return len;
+}
+/*- End of function --------------------------------------------------------*/
+
+void faxtest_set_rx_silence(faxtester_state_t *s)
+{
+    s->wait_for_silence = TRUE;
+}
+/*- End of function --------------------------------------------------------*/
+
+void faxtester_set_rx_type(void *user_data, int type, int bit_rate, int short_train, int use_hdlc)
+{
+    faxtester_state_t *s;
+    put_bit_func_t put_bit_func;
+    void *put_bit_user_data;
+    fax_modems_state_t *t;
+    int tone;
+
+    s = (faxtester_state_t *) user_data;
+    t = &s->modems;
+    span_log(&s->logging, SPAN_LOG_FLOW, "Set rx type %d\n", type);
+    if (s->current_rx_type == type)
+        return;
+    s->current_rx_type = type;
+    if (use_hdlc)
+    {
+        put_bit_func = (put_bit_func_t) hdlc_rx_put_bit;
+        put_bit_user_data = (void *) &t->hdlc_rx;
+        hdlc_rx_init(&t->hdlc_rx, FALSE, FALSE, HDLC_FRAMING_OK_THRESHOLD, hdlc_accept, s);
+    }
+    else
+    {
+        put_bit_func = non_ecm_put_bit;
+        put_bit_user_data = (void *) s;
+    }
+    switch (type)
+    {
+    case T30_MODEM_CED:
+    case T30_MODEM_CNG:
+        if (type == T30_MODEM_CED)
+            tone = MODEM_CONNECT_TONES_FAX_CED;
+        else
+            tone = MODEM_CONNECT_TONES_FAX_CNG;
+        modem_connect_tones_rx_init(&t->connect_rx,
+                                    tone,
+                                    tone_detected,
+                                    (void *) s);
+        t->rx_handler = (span_rx_handler_t *) &modem_connect_tones_rx;
+        t->rx_user_data = &t->connect_rx;
+        s->tone_state = MODEM_CONNECT_TONES_NONE;
+        break;
+    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], 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;
+        break;
+    case T30_MODEM_V27TER:
+        v27ter_rx_restart(&t->v27ter_rx, bit_rate, FALSE);
+        v27ter_rx_set_put_bit(&t->v27ter_rx, put_bit_func, put_bit_user_data);
+        t->rx_handler = (span_rx_handler_t *) &v27ter_v21_rx;
+        t->rx_user_data = s;
+        break;
+    case T30_MODEM_V29:
+        v29_rx_restart(&t->v29_rx, bit_rate, FALSE);
+        v29_rx_set_put_bit(&t->v29_rx, put_bit_func, put_bit_user_data);
+        t->rx_handler = (span_rx_handler_t *) &v29_v21_rx;
+        t->rx_user_data = s;
+        break;
+    case T30_MODEM_V17:
+        v17_rx_restart(&t->v17_rx, bit_rate, short_train);
+        v17_rx_set_put_bit(&t->v17_rx, put_bit_func, put_bit_user_data);
+        t->rx_handler = (span_rx_handler_t *) &v17_v21_rx;
+        t->rx_user_data = s;
+        break;
+    case T30_MODEM_DONE:
+        span_log(&s->logging, SPAN_LOG_FLOW, "FAX exchange complete\n");
+    default:
+        t->rx_handler = (span_rx_handler_t *) &span_dummy_rx;
+        t->rx_user_data = s;
+        break;
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+void faxtester_set_tx_type(void *user_data, int type, int bit_rate, int short_train, int use_hdlc)
+{
+    faxtester_state_t *s;
+    get_bit_func_t get_bit_func;
+    void *get_bit_user_data;
+    fax_modems_state_t *t;
+    int tone;
+
+    s = (faxtester_state_t *) user_data;
+    t = &s->modems;
+    span_log(&s->logging, SPAN_LOG_FLOW, "Set tx type %d\n", type);
+    if (s->current_tx_type == type)
+        return;
+    if (use_hdlc)
+    {
+        get_bit_func = (get_bit_func_t) hdlc_tx_get_bit;
+        get_bit_user_data = (void *) &t->hdlc_tx;
+    }
+    else
+    {
+        get_bit_func = non_ecm_get_bit;
+        get_bit_user_data = (void *) s;
+    }
+    switch (type)
+    {
+    case T30_MODEM_PAUSE:
+        silence_gen_alter(&t->silence_gen, ms_to_samples(short_train));
+        t->tx_handler = (span_tx_handler_t *) &silence_gen;
+        t->tx_user_data = &t->silence_gen;
+        s->transmit = TRUE;
+        break;
+    case T30_MODEM_CED:
+    case T30_MODEM_CNG:
+        if (type == T30_MODEM_CED)
+            tone = MODEM_CONNECT_TONES_FAX_CED;
+        else
+            tone = MODEM_CONNECT_TONES_FAX_CNG;
+        modem_connect_tones_tx_init(&t->connect_tx, tone);
+        t->tx_handler = (span_tx_handler_t *) &modem_connect_tones_tx;
+        t->tx_user_data = &t->connect_tx;
+        s->transmit = TRUE;
+        break;
+    case T30_MODEM_V21:
+        fsk_tx_init(&t->v21_tx, &preset_fsk_specs[FSK_V21CH2], get_bit_func, get_bit_user_data);
+        fsk_tx_set_modem_status_handler(&t->v21_tx, modem_tx_status, (void *) s);
+        t->tx_handler = (span_tx_handler_t *) &fsk_tx;
+        t->tx_user_data = &t->v21_tx;
+        s->transmit = TRUE;
+        break;
+    case T30_MODEM_V27TER:
+        v27ter_tx_restart(&t->v27ter_tx, bit_rate, t->use_tep);
+        v27ter_tx_set_get_bit(&t->v27ter_tx, get_bit_func, get_bit_user_data);
+        v27ter_tx_set_modem_status_handler(&t->v27ter_tx, modem_tx_status, (void *) s);
+        t->tx_handler = (span_tx_handler_t *) &v27ter_tx;
+        t->tx_user_data = &t->v27ter_tx;
+        /* For any fast modem, set 200ms of preamble flags */
+        hdlc_tx_flags(&t->hdlc_tx, bit_rate/(8*5));
+        s->transmit = TRUE;
+        break;
+    case T30_MODEM_V29:
+        v29_tx_restart(&t->v29_tx, bit_rate, t->use_tep);
+        v29_tx_set_get_bit(&t->v29_tx, get_bit_func, get_bit_user_data);
+        v29_tx_set_modem_status_handler(&t->v29_tx, modem_tx_status, (void *) s);
+        t->tx_handler = (span_tx_handler_t *) &v29_tx;
+        t->tx_user_data = &t->v29_tx;
+        /* For any fast modem, set 200ms of preamble flags */
+        hdlc_tx_flags(&t->hdlc_tx, bit_rate/(8*5));
+        s->transmit = TRUE;
+        break;
+    case T30_MODEM_V17:
+        v17_tx_restart(&t->v17_tx, bit_rate, t->use_tep, short_train);
+        v17_tx_set_get_bit(&t->v17_tx, get_bit_func, get_bit_user_data);
+        v17_tx_set_modem_status_handler(&t->v17_tx, modem_tx_status, (void *) s);
+        t->tx_handler = (span_tx_handler_t *) &v17_tx;
+        t->tx_user_data = &t->v17_tx;
+        /* For any fast modem, set 200ms of preamble flags */
+        hdlc_tx_flags(&t->hdlc_tx, bit_rate/(8*5));
+        s->transmit = TRUE;
+        break;
+    case T30_MODEM_DONE:
+        span_log(&s->logging, SPAN_LOG_FLOW, "FAX exchange complete\n");
+        /* Fall through */
+    default:
+        silence_gen_alter(&t->silence_gen, 0);
+        t->tx_handler = (span_tx_handler_t *) &silence_gen;
+        t->tx_user_data = &t->silence_gen;
+        s->transmit = FALSE;
+        break;
+    }
+    s->current_tx_type = type;
+}
+/*- End of function --------------------------------------------------------*/
+
+void faxtester_set_timeout(faxtester_state_t *s, int timeout)
+{
+    if (timeout >= 0)
+        s->timeout = s->timer + timeout*SAMPLE_RATE/1000;
+    else
+        s->timeout = 0x7FFFFFFFFFFFFFFFLL;
+}
+/*- End of function --------------------------------------------------------*/
+
+void faxtester_set_transmit_on_idle(faxtester_state_t *s, int transmit_on_idle)
+{
+    s->modems.transmit_on_idle = transmit_on_idle;
+}
+/*- End of function --------------------------------------------------------*/
+
+void faxtester_set_tep_mode(faxtester_state_t *s, int use_tep)
+{
+    s->modems.use_tep = use_tep;
+}
+/*- End of function --------------------------------------------------------*/
+
+void faxtester_set_real_time_frame_handler(faxtester_state_t *s, faxtester_real_time_frame_handler_t *handler, void *user_data)
+{
+    s->real_time_frame_handler = handler;
+    s->real_time_frame_user_data = user_data;
+}
+/*- End of function --------------------------------------------------------*/
+
+void faxtester_set_front_end_step_complete_handler(faxtester_state_t *s, faxtester_front_end_step_complete_handler_t *handler, void *user_data)
+{
+    s->front_end_step_complete_handler = handler;
+    s->front_end_step_complete_user_data = user_data;
+}
+/*- End of function --------------------------------------------------------*/
+
+void faxtester_set_front_end_step_timeout_handler(faxtester_state_t *s, faxtester_front_end_step_complete_handler_t *handler, void *user_data)
+{
+    s->front_end_step_timeout_handler = handler;
+    s->front_end_step_timeout_user_data = user_data;
+}
+/*- End of function --------------------------------------------------------*/
+
+static void faxtester_fax_modems_init(fax_modems_state_t *s, int use_tep, void *user_data)
+{
+    s->use_tep = use_tep;
+
+    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], 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);
+    v17_rx_init(&s->v17_rx, 14400, non_ecm_put_bit, user_data);
+    v17_tx_init(&s->v17_tx, 14400, s->use_tep, non_ecm_get_bit, user_data);
+    v17_tx_set_modem_status_handler(&s->v17_tx, modem_tx_status, user_data);
+    v29_rx_init(&s->v29_rx, 9600, non_ecm_put_bit, user_data);
+    v29_rx_signal_cutoff(&s->v29_rx, -45.5);
+    v29_tx_init(&s->v29_tx, 9600, s->use_tep, non_ecm_get_bit, user_data);
+    v29_tx_set_modem_status_handler(&s->v29_tx, modem_tx_status, user_data);
+    v27ter_rx_init(&s->v27ter_rx, 4800, non_ecm_put_bit, user_data);
+    v27ter_tx_init(&s->v27ter_tx, 4800, s->use_tep, non_ecm_get_bit, user_data);
+    v27ter_tx_set_modem_status_handler(&s->v27ter_tx, modem_tx_status, user_data);
+    silence_gen_init(&s->silence_gen, 0);
+    modem_connect_tones_tx_init(&s->connect_tx, MODEM_CONNECT_TONES_FAX_CNG);
+    modem_connect_tones_rx_init(&s->connect_rx,
+                                MODEM_CONNECT_TONES_FAX_CNG,
+                                tone_detected,
+                                user_data);
+    dc_restore_init(&s->dc_restore);
+
+    s->rx_signal_present = FALSE;
+    s->rx_handler = (span_rx_handler_t *) &span_dummy_rx;
+    s->rx_user_data = NULL;
+    s->tx_handler = (span_tx_handler_t *) &silence_gen;
+    s->tx_user_data = &s->silence_gen;
+}
+/*- End of function --------------------------------------------------------*/
+
+faxtester_state_t *faxtester_init(faxtester_state_t *s, int calling_party)
+{
+    if (s == NULL)
+    {
+        if ((s = (faxtester_state_t *) malloc(sizeof(*s))) == NULL)
+            return NULL;
+    }
+
+    memset(s, 0, sizeof(*s));
+    span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
+    span_log_set_protocol(&s->logging, "TST");
+    faxtester_fax_modems_init(&s->modems, FALSE, s);
+    faxtester_set_timeout(s, -1);
+    faxtester_set_tx_type(s, T30_MODEM_NONE, 0, FALSE, FALSE);
+
+    return s;
+}
+/*- End of function --------------------------------------------------------*/
+
+int faxtester_release(faxtester_state_t *s)
+{
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+int faxtester_free(faxtester_state_t *s)
+{
+    free(s);
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+void faxtester_set_flush_handler(faxtester_state_t *s, faxtester_flush_handler_t *handler, void *user_data)
+{
+    s->flush_handler = handler;
+    s->flush_user_data = user_data;
+}
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/

Repositories maintained by Peter Meerwald, pmeerw@pmeerw.net.