[Freeswitch-svn] [commit] r13311 - in freeswitch/trunk/libs/spandsp: src src/spandsp src/spandsp/private tests

FreeSWITCH SVN mikej at freeswitch.org
Thu May 14 14:52:52 PDT 2009


Author: mikej
Date: Thu May 14 16:52:52 2009
New Revision: 13311

Log:
update to spandsp-0.0.6pre12

Modified:
   freeswitch/trunk/libs/spandsp/src/spandsp/private/v22bis.h
   freeswitch/trunk/libs/spandsp/src/spandsp/v22bis.h
   freeswitch/trunk/libs/spandsp/src/spandsp/version.h
   freeswitch/trunk/libs/spandsp/src/t30.c
   freeswitch/trunk/libs/spandsp/src/t38_terminal.c
   freeswitch/trunk/libs/spandsp/src/t4.c
   freeswitch/trunk/libs/spandsp/src/v22bis_rx.c
   freeswitch/trunk/libs/spandsp/src/v22bis_tx.c
   freeswitch/trunk/libs/spandsp/tests/fax_decode.c
   freeswitch/trunk/libs/spandsp/tests/t4_tests.c
   freeswitch/trunk/libs/spandsp/tests/tsb85_tests.sh

Modified: freeswitch/trunk/libs/spandsp/src/spandsp/private/v22bis.h
==============================================================================
--- freeswitch/trunk/libs/spandsp/src/spandsp/private/v22bis.h	(original)
+++ freeswitch/trunk/libs/spandsp/src/spandsp/private/v22bis.h	Thu May 14 16:52:52 2009
@@ -22,12 +22,40 @@
  * 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.9 2009/04/26 09:50:28 steveu Exp $
+ * $Id: v22bis.h,v 1.10 2009/04/29 12:37:45 steveu Exp $
  */
 
 #if !defined(_SPANDSP_PRIVATE_V22BIS_H_)
 #define _SPANDSP_PRIVATE_V22BIS_H_
 
+/*! Segments of the training sequence on the receive side */
+enum
+{
+    V22BIS_RX_TRAINING_STAGE_NORMAL_OPERATION,
+    V22BIS_RX_TRAINING_STAGE_SYMBOL_ACQUISITION,
+    V22BIS_RX_TRAINING_STAGE_LOG_PHASE,
+    V22BIS_RX_TRAINING_STAGE_UNSCRAMBLED_ONES,
+    V22BIS_RX_TRAINING_STAGE_UNSCRAMBLED_ONES_SUSTAINING,
+    V22BIS_RX_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200,
+    V22BIS_RX_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200_SUSTAINING,
+    V22BIS_RX_TRAINING_STAGE_WAIT_FOR_SCRAMBLED_ONES_AT_2400,
+    V22BIS_RX_TRAINING_STAGE_PARKED
+};
+
+/*! Segments of the training sequence on the transmit side */
+enum
+{
+    V22BIS_TX_TRAINING_STAGE_NORMAL_OPERATION = 0,
+    V22BIS_TX_TRAINING_STAGE_INITIAL_TIMED_SILENCE,
+    V22BIS_TX_TRAINING_STAGE_INITIAL_SILENCE,
+    V22BIS_TX_TRAINING_STAGE_U11,
+    V22BIS_TX_TRAINING_STAGE_U0011,
+    V22BIS_TX_TRAINING_STAGE_S11,
+    V22BIS_TX_TRAINING_STAGE_TIMED_S11,
+    V22BIS_TX_TRAINING_STAGE_S1111,
+    V22BIS_TX_TRAINING_STAGE_PARKED
+};
+
 /*!
     V.22bis modem descriptor. This defines the working state for a single instance
     of a V.22bis modem.
@@ -195,6 +223,8 @@
 
 void v22bis_report_status_change(v22bis_state_t *s, int status);
 
+void v22bis_equalizer_coefficient_reset(v22bis_state_t *s);
+
 #if defined(__cplusplus)
 }
 #endif

Modified: freeswitch/trunk/libs/spandsp/src/spandsp/v22bis.h
==============================================================================
--- freeswitch/trunk/libs/spandsp/src/spandsp/v22bis.h	(original)
+++ freeswitch/trunk/libs/spandsp/src/spandsp/v22bis.h	Thu May 14 16:52:52 2009
@@ -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.41 2009/04/25 10:18:50 steveu Exp $
+ * $Id: v22bis.h,v 1.42 2009/04/29 12:37:45 steveu Exp $
  */
 
 /*! \file */
@@ -150,13 +150,20 @@
     \return 0 for OK, -1 for bad parameter. */
 SPAN_DECLARE(int) v22bis_restart(v22bis_state_t *s, int bit_rate);
 
-/*! Request a retrain for a V.22bis modem context. A rate change may also be resquested.
+/*! Request a retrain for a V.22bis modem context. A rate change may also be requested.
     \brief Request a retrain for a V.22bis modem context.
     \param s The modem context.
     \param bit_rate The bit rate of the modem. Valid values are 1200 and 2400.
-    \return 0 for OK, -1 for bad parameter. */
+    \return 0 for OK, -1 for request rejected. */
 SPAN_DECLARE(int) v22bis_request_retrain(v22bis_state_t *s, int bit_rate);
 
+/*! Request a loopback 2 for a V.22bis modem context.
+    \brief Request a loopback 2 for a V.22bis modem context.
+    \param s The modem context.
+    \param enable TRUE to enable loopback, or FALSE to disable it.
+    \return 0 for OK, -1 for request reject. */
+SPAN_DECLARE(int) v22bis_remote_loopback(v22bis_state_t *s, int enable);
+
 /*! Report the current operating bit rate of a V.22bis modem context.
     \brief Report the current operating bit rate of a V.22bis modem context
     \param s The modem context. */

Modified: freeswitch/trunk/libs/spandsp/src/spandsp/version.h
==============================================================================
--- freeswitch/trunk/libs/spandsp/src/spandsp/version.h	(original)
+++ freeswitch/trunk/libs/spandsp/src/spandsp/version.h	Thu May 14 16:52:52 2009
@@ -30,9 +30,9 @@
 
 /* The date and time of the version are in UTC form. */
 
-#define SPANDSP_RELEASE_DATE            20090427
-#define SPANDSP_RELEASE_TIME            151958
-#define SPANDSP_RELEASE_DATETIME_STRING "20090427 151958"
+#define SPANDSP_RELEASE_DATE            20090502
+#define SPANDSP_RELEASE_TIME            044449
+#define SPANDSP_RELEASE_DATETIME_STRING "20090502 044449"
 
 #endif
 /*- End of file ------------------------------------------------------------*/

Modified: freeswitch/trunk/libs/spandsp/src/t30.c
==============================================================================
--- freeswitch/trunk/libs/spandsp/src/t30.c	(original)
+++ freeswitch/trunk/libs/spandsp/src/t30.c	Thu May 14 16:52:52 2009
@@ -5,7 +5,7 @@
  *
  * Written by Steve Underwood <steveu at coppice.org>
  *
- * Copyright (C) 2003, 2004, 2005, 2006, 2007 Steve Underwood
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Steve Underwood
  *
  * All rights reserved.
  *
@@ -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.c,v 1.291 2009/04/23 15:40:32 steveu Exp $
+ * $Id: t30.c,v 1.298 2009/04/30 18:46:14 steveu Exp $
  */
 
 /*! \file */
@@ -73,8 +73,13 @@
 
 #include "t30_local.h"
 
-/*! The maximum number of consecutive retries allowed. */
-#define MAX_MESSAGE_TRIES   3
+/*! The maximum permitted number of retries of a single command allowed. */
+#define MAX_COMMAND_TRIES   3
+
+/*! The maximum permitted number of retries of a single response request allowed. This
+    is not specified in T.30. However, if you don't apply some limit a messed up FAX
+    terminal could keep you retrying all day. Its a backstop protection. */
+#define MAX_RESPONSE_TRIES  6
 
 /*! Conversion between milliseconds and audio samples. */
 #define ms_to_samples(t)    (((t)*SAMPLE_RATE)/1000)
@@ -245,7 +250,7 @@
 end of a frame, after the initial flag has been seen. */
 #define DEFAULT_TIMER_T2A               3000
 
-/*! If the HDLC carrier falls during reception, we need to apply a minimum time before continuing. if we
+/*! If the HDLC carrier falls during reception, we need to apply a minimum time before continuing. If we
    don't, there are circumstances where we could continue and reply before the incoming signals have
    really finished. E.g. if a bad DCS is received in a DCS-TCF sequence, we need wait for the TCF
    carrier to pass, before continuing. This timer is specified as 200ms, but no tolerance is specified.
@@ -316,14 +321,16 @@
 
 enum
 {
-    TIMER_IS_T2 = 0,
-    TIMER_IS_T2A = 1,
-    TIMER_IS_T2B = 2,
-    TIMER_IS_T2C = 3,
-    TIMER_IS_T4 = 4,
-    TIMER_IS_T4A = 5,
-    TIMER_IS_T4B = 6,
-    TIMER_IS_T4C = 7
+    TIMER_IS_IDLE = 0,
+    TIMER_IS_T2,
+    TIMER_IS_T1A,
+    TIMER_IS_T2A,
+    TIMER_IS_T2B,
+    TIMER_IS_T2C,
+    TIMER_IS_T4,
+    TIMER_IS_T4A,
+    TIMER_IS_T4B,
+    TIMER_IS_T4C
 };
 
 /* Start points in the fallback table for different capabilities */
@@ -2507,6 +2514,9 @@
         {
             unexpected_frame_length(s, msg, len);
         }
+        /* We have received something, so any missing carrier status is out of date */
+        if (s->current_status == T30_ERR_RX_NOCARRIER)
+            s->current_status = T30_ERR_OK;
         break;
     default:
         unexpected_non_final_frame(s, msg, len);
@@ -2517,16 +2527,21 @@
 
 static void process_rx_rcp(t30_state_t *s, const uint8_t *msg, int len)
 {
-    /* Return to control for partial page. These might come through with or without the final frame tag,
-       so we have this routine to deal with the "no final frame tag" case. */
+    /* Return to control for partial page. These might come through with or without the final frame tag.
+       Here we deal with the "no final frame tag" case. */
     switch (s->state)
     {
     case T30_STATE_F_DOC_ECM:
         set_state(s, T30_STATE_F_POST_DOC_ECM);
         queue_phase(s, T30_PHASE_D_RX);
+        timer_t2_start(s);
+        /* We have received something, so any missing carrier status is out of date */
+        if (s->current_status == T30_ERR_RX_NOCARRIER)
+            s->current_status = T30_ERR_OK;
         break;
     case T30_STATE_F_POST_DOC_ECM:
-        /* Just ignore this */
+        /* Just ignore this. It must be an extra RCP. Several are usually sent, to maximise the chance
+           of receiving a correct one. */
         break;
     default:
         unexpected_non_final_frame(s, msg, len);
@@ -2773,7 +2788,7 @@
         break;
     case T30_DIS:
         /* It appears they didn't see what we sent - retry the TCF */
-        if (++s->retries >= MAX_MESSAGE_TRIES)
+        if (++s->retries >= MAX_COMMAND_TRIES)
         {
             span_log(&s->logging, SPAN_LOG_FLOW, "Too many retries. Giving up.\n");
             s->current_status = T30_ERR_RETRYDCN;
@@ -2827,6 +2842,10 @@
     /* We're waiting for a response to the CFR we sent */
     switch (msg[2] & 0xFE)
     {
+    case T30_DCS:
+        /* If we received another DCS, they must have missed our CFR */
+        process_rx_dcs(s, msg, len);
+        break;
     case T30_CRP:
         repeat_last_command(s);
         break;
@@ -3150,7 +3169,7 @@
 }
 /*- End of function --------------------------------------------------------*/
 
-static void process_state_f_doc_ecm(t30_state_t *s, const uint8_t *msg, int len)
+static void process_state_f_doc_and_post_doc_ecm(t30_state_t *s, const uint8_t *msg, int len)
 {
     uint8_t fcf2;
     
@@ -3164,16 +3183,22 @@
         process_rx_dcs(s, msg, len);
         break;
     case T4_RCP:
+        /* Return to control for partial page. These might come through with or without the final frame tag.
+           Here we deal with the "final frame tag" case. */
         if (s->state == T30_STATE_F_DOC_ECM)
         {
             /* Return to control for partial page */
-            queue_phase(s, T30_PHASE_D_RX);
             set_state(s, T30_STATE_F_POST_DOC_ECM);
+            queue_phase(s, T30_PHASE_D_RX);
+            timer_t2_start(s);
+            /* We have received something, so any missing carrier status is out of date */
+            if (s->current_status == T30_ERR_RX_NOCARRIER)
+                s->current_status = T30_ERR_OK;
         }
         else
         {
-            /* Ignore extra RCP frames. The source will usually send several to maximise the chance of
-               one getting through OK. */
+            /* Just ignore this. It must be an extra RCP. Several are usually sent, to maximise the chance
+               of receiving a correct one. */
         }
         break;
     case T30_EOR:
@@ -4166,6 +4191,7 @@
             /* Restart the command or response timer, T2 or T4 */
             switch (s->timer_t2_t4_is)
             {
+            case TIMER_IS_T1A:
             case TIMER_IS_T2:
             case TIMER_IS_T2A:
             case TIMER_IS_T2B:
@@ -4358,7 +4384,7 @@
             break;
         case T30_STATE_F_DOC_ECM:
         case T30_STATE_F_POST_DOC_ECM:
-            process_state_f_doc_ecm(s, msg, len);
+            process_state_f_doc_and_post_doc_ecm(s, msg, len);
             break;
         case T30_STATE_F_POST_RCP_MCF:
             process_state_f_post_rcp_mcf(s, msg, len);
@@ -4564,7 +4590,7 @@
 static void repeat_last_command(t30_state_t *s)
 {
     s->step = 0;
-    if (++s->retries >= MAX_MESSAGE_TRIES)
+    if (++s->retries >= MAX_COMMAND_TRIES)
     {
         span_log(&s->logging, SPAN_LOG_FLOW, "Too many retries. Giving up.\n");
         switch (s->state)
@@ -4670,13 +4696,14 @@
     {
         span_log(&s->logging, SPAN_LOG_FLOW, "Start T1A\n");
         s->timer_t2_t4 = ms_to_samples(DEFAULT_TIMER_T1A);
+        s->timer_t2_t4_is = TIMER_IS_T1A;
     }
     else
     {
         span_log(&s->logging, SPAN_LOG_FLOW, "Start T2A\n");
         s->timer_t2_t4 = ms_to_samples(DEFAULT_TIMER_T2A);
+        s->timer_t2_t4_is = TIMER_IS_T2A;
     }
-    s->timer_t2_t4_is = TIMER_IS_T2A;
 }
 /*- End of function --------------------------------------------------------*/
 
@@ -4714,8 +4741,47 @@
 
 static void timer_t2_t4_stop(t30_state_t *s)
 {
-    span_log(&s->logging, SPAN_LOG_FLOW, "Stop T2/T4\n");
+    const char *tag;
+    
+    switch (s->timer_t2_t4_is)
+    {
+    case TIMER_IS_IDLE:
+        tag = "none";
+        break;
+    case TIMER_IS_T1A:
+        tag = "T1A";
+        break;
+    case TIMER_IS_T2:
+        tag = "T2";
+        break;
+    case TIMER_IS_T2A:
+        tag = "T2A";
+        break;
+    case TIMER_IS_T2B:
+        tag = "T2B";
+        break;
+    case TIMER_IS_T2C:
+        tag = "T2C";
+        break;
+    case TIMER_IS_T4:
+        tag = "T4";
+        break;
+    case TIMER_IS_T4A:
+        tag = "T4A";
+        break;
+    case TIMER_IS_T4B:
+        tag = "T4B";
+        break;
+    case TIMER_IS_T4C:
+        tag = "T4C";
+        break;
+    default:
+        tag = "T2/T4";
+        break;
+    }
+    span_log(&s->logging, SPAN_LOG_FLOW, "Stop %s (%d remaining)\n", tag, s->timer_t2_t4);
     s->timer_t2_t4 = 0;
+    s->timer_t2_t4_is = TIMER_IS_IDLE;
 }
 /*- End of function --------------------------------------------------------*/
 
@@ -4754,7 +4820,8 @@
 
 static void timer_t2_expired(t30_state_t *s)
 {
-    span_log(&s->logging, SPAN_LOG_FLOW, "T2 expired in phase %s, state %d\n", phase_names[s->phase], s->state);
+    if (s->timer_t2_t4_is != TIMER_IS_T2B)
+        span_log(&s->logging, SPAN_LOG_FLOW, "T2 expired in phase %s, state %d\n", phase_names[s->phase], s->state);
     switch (s->state)
     {
     case T30_STATE_III_Q_MCF:
@@ -4820,6 +4887,14 @@
 }
 /*- End of function --------------------------------------------------------*/
 
+static void timer_t1a_expired(t30_state_t *s)
+{
+    span_log(&s->logging, SPAN_LOG_FLOW, "T1A expired in phase %s, state %d. An HDLC frame lasted too long.\n", phase_names[s->phase], s->state);
+    s->current_status = T30_ERR_HDLC_CARRIER;
+    disconnect(s);
+}
+/*- End of function --------------------------------------------------------*/
+
 static void timer_t2a_expired(t30_state_t *s)
 {
     span_log(&s->logging, SPAN_LOG_FLOW, "T2A expired in phase %s, state %d. An HDLC frame lasted too long.\n", phase_names[s->phase], s->state);
@@ -5273,6 +5348,7 @@
 static void t30_hdlc_rx_status(void *user_data, int status)
 {
     t30_state_t *s;
+    int was_trained;
 
     s = (t30_state_t *) user_data;
     span_log(&s->logging, SPAN_LOG_FLOW, "HDLC signal status is %s (%d) in state %d\n", signal_status_to_str(status), status, s->state);
@@ -5293,32 +5369,56 @@
         switch (s->timer_t2_t4_is)
         {
         case TIMER_IS_T2B:
-            s->timer_t2_t4_is = TIMER_IS_T2C;
             timer_t2_t4_stop(s);
+            s->timer_t2_t4_is = TIMER_IS_T2C;
             break;
         case TIMER_IS_T4B:
-            s->timer_t2_t4_is = TIMER_IS_T4C;
             timer_t2_t4_stop(s);
+            s->timer_t2_t4_is = TIMER_IS_T4C;
             break;
         }
         break;
     case SIG_STATUS_CARRIER_DOWN:
+        was_trained = s->rx_trained;
         s->rx_signal_present = FALSE;
         s->rx_trained = FALSE;
         /* If a phase change has been queued to occur after the receive signal drops,
            its time to change. */
+        if (s->state == T30_STATE_F_DOC_ECM)
+        {
+            /* We should be receiving a document right now, but we haven't seen an RCP at the end of
+               transmission. */
+            if (was_trained)
+            {
+                /* We trained OK, so we should have some kind of received page, possibly with
+                   zero good HDLC frames. It just did'nt end cleanly with an RCP. */
+                span_log(&s->logging, SPAN_LOG_WARNING, "ECM signal did not end cleanly\n");
+                /* Fake the existance of an RCP, and proceed */
+                set_state(s, T30_STATE_F_POST_DOC_ECM);
+                queue_phase(s, T30_PHASE_D_RX);
+                timer_t2_start(s);
+                /* We at least trained, so any missing carrier status is out of date */
+                if (s->current_status == T30_ERR_RX_NOCARRIER)
+                    s->current_status = T30_ERR_OK;
+            }
+            else
+            {
+                /* Either there was no image carrier, or we failed to train to it. */
+                span_log(&s->logging, SPAN_LOG_WARNING, "ECM carrier not found\n");
+                s->current_status = T30_ERR_RX_NOCARRIER;
+            }
+        }
         if (s->next_phase != T30_PHASE_IDLE)
         {
-            timer_t2_t4_stop(s);
+            /* The appropriate timer for the next phase should already be in progress */
             set_phase(s, s->next_phase);
-            if (s->next_phase == T30_PHASE_C_NON_ECM_RX)
-                timer_t2_start(s);
             s->next_phase = T30_PHASE_IDLE;
         }
         else
         {
             switch (s->timer_t2_t4_is)
             {
+            case TIMER_IS_T1A:
             case TIMER_IS_T2A:
             case TIMER_IS_T2C:
                 timer_t2b_start(s);
@@ -5344,6 +5444,7 @@
         {
             switch(s->timer_t2_t4_is)
             {
+            case TIMER_IS_T1A:
             case TIMER_IS_T2:
             case TIMER_IS_T2A:
                 timer_t2a_start(s);
@@ -5416,7 +5517,7 @@
         return;
     }
     s->rx_frame_received = TRUE;
-    /* Cancel the command or response timer */
+    /* Cancel the command or response timer (if one is running) */
     timer_t2_t4_stop(s);
     process_rx_control_msg(s, msg, len);
 }
@@ -5760,6 +5861,9 @@
         {
             switch (s->timer_t2_t4_is)
             {
+            case TIMER_IS_T1A:
+                timer_t1a_expired(s);
+                break;
             case TIMER_IS_T2:
                 timer_t2_expired(s);
                 break;
@@ -5869,6 +5973,13 @@
     s->far_dis_dtc_len = 0;
     memset(&s->far_dis_dtc_frame, 0, sizeof(s->far_dis_dtc_frame));
     t30_build_dis_or_dtc(s);
+    memset(&s->rx_info, 0, sizeof(s->rx_info));
+    release_resources(s);
+    /* The ECM page number is only reset at call establishment */
+    s->ecm_rx_page = 0;
+    s->ecm_tx_page = 0;
+    s->far_end_detected = FALSE;
+    s->timer_t0_t1 = ms_to_samples(DEFAULT_TIMER_T0);
     if (s->calling_party)
     {
         set_state(s, T30_STATE_T);
@@ -5879,13 +5990,6 @@
         set_state(s, T30_STATE_ANSWERING);
         set_phase(s, T30_PHASE_A_CED);
     }
-    memset(&s->rx_info, 0, sizeof(s->rx_info));
-    s->far_end_detected = FALSE;
-    s->timer_t0_t1 = ms_to_samples(DEFAULT_TIMER_T0);
-    release_resources(s);
-    /* The ECM page number is only reset at call establishment */
-    s->ecm_rx_page = 0;
-    s->ecm_tx_page = 0;
     return 0;
 }
 /*- End of function --------------------------------------------------------*/

Modified: freeswitch/trunk/libs/spandsp/src/t38_terminal.c
==============================================================================
--- freeswitch/trunk/libs/spandsp/src/t38_terminal.c	(original)
+++ freeswitch/trunk/libs/spandsp/src/t38_terminal.c	Thu May 14 16:52:52 2009
@@ -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.124 2009/03/13 14:49:56 steveu Exp $
+ * $Id: t38_terminal.c,v 1.125 2009/05/02 04:43:48 steveu Exp $
  */
 
 /*! \file */
@@ -566,6 +566,8 @@
             /* Create a 75ms silence */
             if (fe->t38.current_tx_indicator != T38_IND_NO_SIGNAL)
                 delay = t38_core_send_indicator(&fe->t38, T38_IND_NO_SIGNAL, fe->t38.indicator_tx_count);
+            else
+                delay = 75000;
             fe->timed_step = T38_TIMED_STEP_NON_ECM_MODEM_2;
             fe->next_tx_samples = fe->samples;
             break;
@@ -663,6 +665,8 @@
             /* Create a 75ms silence */
             if (fe->t38.current_tx_indicator != T38_IND_NO_SIGNAL)
                 delay = t38_core_send_indicator(&fe->t38, T38_IND_NO_SIGNAL, fe->t38.indicator_tx_count);
+            else
+                delay = 75000;
             fe->timed_step = T38_TIMED_STEP_HDLC_MODEM_2;
             fe->next_tx_samples = fe->samples;
             break;

Modified: freeswitch/trunk/libs/spandsp/src/t4.c
==============================================================================
--- freeswitch/trunk/libs/spandsp/src/t4.c	(original)
+++ freeswitch/trunk/libs/spandsp/src/t4.c	Thu May 14 16:52:52 2009
@@ -1668,9 +1668,14 @@
     }
     if (s->row_bits)
     {
-        /* We may need to pad the row to a minimum length. */
-        if (s->row_bits + length < s->min_bits_per_row)
-            put_encoded_bits(s, 0, s->min_bits_per_row - (s->row_bits + length));
+        /* We may need to pad the row to a minimum length, unless we are in T.6 mode.
+           In T.6 we only come here at the end of the page to add the EOFB marker, which
+           is like two 1D EOLs. */
+        if (s->line_encoding != T4_COMPRESSION_ITU_T6)
+        {
+            if (s->row_bits + length < s->min_bits_per_row)
+                put_encoded_bits(s, 0, s->min_bits_per_row - (s->row_bits + length));
+        }
         put_encoded_bits(s, code, length);
         update_row_bit_info(s);
     }
@@ -1678,6 +1683,10 @@
     {
         /* We don't pad zero length rows. They are the consecutive EOLs which end a page. */
         put_encoded_bits(s, code, length);
+        /* Don't do the full update row bit info, or the minimum suddenly drops to the
+           length of an EOL. Just clear the row bits, so we treat the next EOL as an
+           end of page EOL, with no padding. */
+        s->row_bits = 0;
     }
 }
 /*- End of function --------------------------------------------------------*/
@@ -2183,8 +2192,9 @@
             encode_eol(s);
     }
 
-    /* Force any partial byte in progress to flush */
-    put_encoded_bits(s, 0, 7);
+    /* Force any partial byte in progress to flush using ones. Any post EOL padding when
+       sending is normally ones, so this is consistent. */
+    put_encoded_bits(s, 0xFF, 7);
     s->bit_pos = 7;
     s->bit_ptr = 0;
     s->line_image_size = s->image_size*8;

Modified: freeswitch/trunk/libs/spandsp/src/v22bis_rx.c
==============================================================================
--- freeswitch/trunk/libs/spandsp/src/v22bis_rx.c	(original)
+++ freeswitch/trunk/libs/spandsp/src/v22bis_rx.c	Thu May 14 16:52:52 2009
@@ -22,12 +22,19 @@
  * 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.66 2009/04/27 15:18:52 steveu Exp $
+ * $Id: v22bis_rx.c,v 1.67 2009/04/29 12:37:45 steveu Exp $
  */
 
 /*! \file */
 
-/* THIS IS A WORK IN PROGRESS - NOT YET FUNCTIONAL! */
+/* THIS IS A WORK IN PROGRESS - It is basically functional, but it is not feature
+   complete, and doesn't reliably sync over the signal and noise level ranges it
+   should. There are some nasty inefficiencies too!
+   TODO:
+        Better noise performance
+        Retrain is incomplete
+        Rate change is not implemented
+        Remote loopback is not implemented */
 
 #if defined(HAVE_CONFIG_H)
 #include "config.h"
@@ -103,33 +110,6 @@
         Descramble and output the bits represented by the decision.
 */
 
-enum
-{
-    V22BIS_RX_TRAINING_STAGE_NORMAL_OPERATION,
-    V22BIS_RX_TRAINING_STAGE_SYMBOL_ACQUISITION,
-    V22BIS_RX_TRAINING_STAGE_LOG_PHASE,
-    V22BIS_RX_TRAINING_STAGE_UNSCRAMBLED_ONES,
-    V22BIS_RX_TRAINING_STAGE_UNSCRAMBLED_ONES_SUSTAINING,
-    V22BIS_RX_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200,
-    V22BIS_RX_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200_SUSTAINING,
-    V22BIS_RX_TRAINING_STAGE_WAIT_FOR_SCRAMBLED_ONES_AT_2400,
-    V22BIS_RX_TRAINING_STAGE_PARKED
-};
-
-/* Segments of the training sequence */
-enum
-{
-    V22BIS_TX_TRAINING_STAGE_NORMAL_OPERATION = 0,
-    V22BIS_TX_TRAINING_STAGE_INITIAL_TIMED_SILENCE,
-    V22BIS_TX_TRAINING_STAGE_INITIAL_SILENCE,
-    V22BIS_TX_TRAINING_STAGE_U11,
-    V22BIS_TX_TRAINING_STAGE_U0011,
-    V22BIS_TX_TRAINING_STAGE_S11,
-    V22BIS_TX_TRAINING_STAGE_TIMED_S11,
-    V22BIS_TX_TRAINING_STAGE_S1111,
-    V22BIS_TX_TRAINING_STAGE_PARKED
-};
-
 static const uint8_t space_map_v22bis[6][6] =
 {
     {11,  9,  9,  6,  6,  7},
@@ -194,20 +174,29 @@
 }
 /*- End of function --------------------------------------------------------*/
 
-static void equalizer_reset(v22bis_state_t *s)
+void v22bis_equalizer_coefficient_reset(v22bis_state_t *s)
 {
     /* Start with an equalizer based on everything being perfect */
 #if defined(SPANDSP_USE_FIXED_POINTx)
     cvec_zeroi16(s->rx.eq_coeff, 2*V22BIS_EQUALIZER_LEN + 1);
     s->rx.eq_coeff[V22BIS_EQUALIZER_LEN] = complex_seti16(3*FP_FACTOR, 0*FP_FACTOR);
-    cvec_zeroi16(s->rx.eq_buf, V22BIS_EQUALIZER_MASK + 1);
     s->rx.eq_delta = 32768.0f*EQUALIZER_DELTA/(2*V22BIS_EQUALIZER_LEN + 1);
 #else
     cvec_zerof(s->rx.eq_coeff, 2*V22BIS_EQUALIZER_LEN + 1);
     s->rx.eq_coeff[V22BIS_EQUALIZER_LEN] = complex_setf(3.0f, 0.0f);
-    cvec_zerof(s->rx.eq_buf, V22BIS_EQUALIZER_MASK + 1);
     s->rx.eq_delta = EQUALIZER_DELTA/(2*V22BIS_EQUALIZER_LEN + 1);
 #endif
+}
+/*- End of function --------------------------------------------------------*/
+
+static void equalizer_reset(v22bis_state_t *s)
+{
+    v22bis_equalizer_coefficient_reset(s);
+#if defined(SPANDSP_USE_FIXED_POINTx)
+    cvec_zeroi16(s->rx.eq_buf, V22BIS_EQUALIZER_MASK + 1);
+#else
+    cvec_zerof(s->rx.eq_buf, V22BIS_EQUALIZER_MASK + 1);
+#endif
     s->rx.eq_put_step = 20 - 1;
     s->rx.eq_step = 0;
 }
@@ -345,63 +334,18 @@
 }
 /*- End of function --------------------------------------------------------*/
 
-static __inline__ int find_quadrant(const complexf_t *z)
-{
-    int b1;
-    int b2;
-
-    /* Split the space along the two diagonals, as follows:
-         \ 1 /
-          \ /
-       2   X   0
-          / \
-         / 3 \
-     */
-    b1 = (z->im > z->re);
-    b2 = (z->im < -z->re);
-    return (b2 << 1) | (b1 ^ b2);
-}
-/*- End of function --------------------------------------------------------*/
-
-static void process_half_baud(v22bis_state_t *s, const complexf_t *sample)
+static __inline__ void symbol_sync(v22bis_state_t *s)
 {
+    float p;
+    float q;
+    complexf_t zz;
     complexf_t a;
     complexf_t b;
     complexf_t c;
 
-    complexf_t z;
-    complexf_t zz;
-    const complexf_t *target;
-    float p;
-    float q;
-    int re;
-    int im;
-    int nearest;
-    int bitstream;
-    int raw_bits;
-
-    z.re = sample->re;
-    z.im = sample->im;
-
-    /* Add a sample to the equalizer's circular buffer, but don't calculate anything
-       at this time. */
-    s->rx.eq_buf[s->rx.eq_step] = z;
-    s->rx.eq_step = (s->rx.eq_step + 1) & V22BIS_EQUALIZER_MASK;
-
-    /* On alternate insertions we have a whole baud and must process it. */
-    if ((s->rx.baud_phase ^= 1))
-        return;
+    /* This routine adapts the position of the half baud samples entering the equalizer. */
 
     /* Perform a Gardner test for baud alignment on the three most recent samples. */
-#if 0
-    p = s->rx.eq_buf[(s->rx.eq_step - 3) & V22BIS_EQUALIZER_MASK].re
-      - s->rx.eq_buf[(s->rx.eq_step - 1) & V22BIS_EQUALIZER_MASK].re;
-    p *= s->rx.eq_buf[(s->rx.eq_step - 2) & V22BIS_EQUALIZER_MASK].re;
-
-    q = s->rx.eq_buf[(s->rx.eq_step - 3) & V22BIS_EQUALIZER_MASK].im
-      - s->rx.eq_buf[(s->rx.eq_step - 1) & V22BIS_EQUALIZER_MASK].im;
-    q *= s->rx.eq_buf[(s->rx.eq_step - 2) & V22BIS_EQUALIZER_MASK].im;
-#else
     if (s->rx.sixteen_way_decisions)
     {
         p = s->rx.eq_buf[(s->rx.eq_step - 3) & V22BIS_EQUALIZER_MASK].re
@@ -414,18 +358,18 @@
     }
     else
     {
-        /* Rotate the points to the 45 degree positions, to maximise the effectiveness of the Gardner algorithm */
-        zz = complex_setf(cosf(26.57f*3.14159f/180.0f), sinf(26.57f*3.14159f/180.0f));
+        /* Rotate the points to the 45 degree positions, to maximise the effectiveness of
+           the Gardner algorithm. This is particularly significant at the start of operation
+           to pull things in quickly. */
+        zz = complex_setf(0.894427, 0.44721f);
         a = complex_mulf(&s->rx.eq_buf[(s->rx.eq_step - 3) & V22BIS_EQUALIZER_MASK], &zz);
         b = complex_mulf(&s->rx.eq_buf[(s->rx.eq_step - 2) & V22BIS_EQUALIZER_MASK], &zz);
         c = complex_mulf(&s->rx.eq_buf[(s->rx.eq_step - 1) & V22BIS_EQUALIZER_MASK], &zz);
         p = (a.re - c.re)*b.re;
         q = (a.im - c.im)*b.im;
     }
-#endif
 
-    p += q;
-    s->rx.gardner_integrate += ((p + q) > 0.0f)  ?  s->rx.gardner_step  :  -s->rx.gardner_step;
+    s->rx.gardner_integrate += (p + q > 0.0f)  ?  s->rx.gardner_step  :  -s->rx.gardner_step;
 
     if (abs(s->rx.gardner_integrate) >= 16)
     {
@@ -439,9 +383,37 @@
             s->rx.qam_report(s->rx.qam_user_data, NULL, NULL, s->rx.gardner_integrate);
         s->rx.gardner_integrate = 0;
     }
+}
+/*- End of function --------------------------------------------------------*/
+
+static void process_half_baud(v22bis_state_t *s, const complexf_t *sample)
+{
+    complexf_t z;
+    complexf_t zz;
+    const complexf_t *target;
+    int re;
+    int im;
+    int nearest;
+    int bitstream;
+    int raw_bits;
+
+    z.re = sample->re;
+    z.im = sample->im;
+
+    /* Add a sample to the equalizer's circular buffer, but don't calculate anything
+       at this time. */
+    s->rx.eq_buf[s->rx.eq_step] = z;
+    s->rx.eq_step = (s->rx.eq_step + 1) & V22BIS_EQUALIZER_MASK;
+
+    /* On alternate insertions we have a whole baud and must process it. */
+    if ((s->rx.baud_phase ^= 1))
+        return;
+
+    symbol_sync(s);
 
     z = equalizer_get(s);
 
+    /* Find the constellation point */
     if (s->rx.sixteen_way_decisions)
     {
         re = (int) (z.re + 3.0f);
@@ -458,9 +430,17 @@
     }
     else
     {
-        zz = complex_setf(3.0f/3.162278f, -1.0f/3.162278f);
+        /* Rotate to 45 degrees, to make the slicing trivial */
+        zz = complex_setf(0.894427, 0.44721f);
         zz = complex_mulf(&z, &zz);
-        nearest = (find_quadrant(&zz) << 2) | 0x01;
+        nearest = 0x01;
+        if (zz.re < 0.0f)
+            nearest |= 0x04;
+        if (zz.im < 0.0f)
+        {
+            nearest ^= 0x04;
+            nearest |= 0x08;
+        }
     }
     raw_bits = 0;
 
@@ -471,6 +451,31 @@
         target = &v22bis_constellation[nearest];
         track_carrier(s, &z, target);
         tune_equalizer(s, &z, target);
+        raw_bits = phase_steps[((nearest >> 2) - (s->rx.constellation_state >> 2)) & 3];
+        /* TODO: detect unscrambled ones indicating a loopback request */
+
+        /* Search for the S1 signal that might be requesting a retrain */
+        if ((s->rx.last_raw_bits ^ raw_bits) == 0x3)
+        {
+            s->rx.pattern_repeats++;
+        }
+        else
+        {
+            if (s->rx.pattern_repeats >= 50  &&  (s->rx.last_raw_bits == 0x3  ||  s->rx.last_raw_bits == 0x0))
+            {
+                /* We should get a full run of 00 11 (about 60 bauds) at either modem. */
+                span_log(&s->logging, SPAN_LOG_FLOW, "+++ S1 detected (%d long)\n", s->rx.pattern_repeats);
+                span_log(&s->logging, SPAN_LOG_FLOW, "+++ Accepting a retrain request\n");
+                s->rx.pattern_repeats = 0;
+                s->rx.training_count = 0;
+                s->rx.training = V22BIS_RX_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200;
+                s->tx.training_count = 0;
+                s->tx.training = V22BIS_TX_TRAINING_STAGE_U0011;
+                v22bis_equalizer_coefficient_reset(s);
+                v22bis_report_status_change(s, SIG_STATUS_MODEM_RETRAIN_OCCURRED);
+            }
+            s->rx.pattern_repeats = 0;
+        }
         decode_baud(s, nearest);
         break;
     case V22BIS_RX_TRAINING_STAGE_SYMBOL_ACQUISITION:
@@ -505,7 +510,7 @@
         track_carrier(s, &z, target);
         raw_bits = phase_steps[((nearest >> 2) - (s->rx.constellation_state >> 2)) & 3];
         s->rx.constellation_state = nearest;
-        if (raw_bits != s->rx.last_raw_bits) 
+        if (raw_bits != s->rx.last_raw_bits)
             s->rx.pattern_repeats = 0;
         else
             s->rx.pattern_repeats++;
@@ -578,7 +583,7 @@
                 {
                     /* We should get a full run of 00 11 (about 60 bauds) at the calling modem, but only about 20
                        at the answering modem, as the first 40 are TED settling time. */
-                    span_log(&s->logging, SPAN_LOG_FLOW, "+++ S1 detected at %d\n", s->rx.pattern_repeats);
+                    span_log(&s->logging, SPAN_LOG_FLOW, "+++ S1 detected (%d long)\n", s->rx.pattern_repeats);
                     if (s->bit_rate == 2400)
                     {
                         if (!s->caller)
@@ -709,7 +714,8 @@
             s->rx.rrc_filter_step = 0;
 
         /* Calculate the I filter, with an arbitrary phase step, just so we can calculate
-           the signal power. */
+           the signal power of the required carrier, with any guard tone or spillback of our
+           own transmitted signal suppressed. */
         if (s->caller)
         {
             ii = rx_pulseshaper_2400_re[6][0]*s->rx.rrc_filter[s->rx.rrc_filter_step];
@@ -744,7 +750,7 @@
         if (s->rx.training != V22BIS_RX_TRAINING_STAGE_PARKED)
         {
             /* Only spend effort processing this data if the modem is not
-               parked, after training failure. */
+               parked, after a training failure. */
             z = dds_complexf(&s->rx.carrier_phase, s->rx.carrier_phase_rate);
             if (s->rx.training == V22BIS_RX_TRAINING_STAGE_SYMBOL_ACQUISITION)
             {

Modified: freeswitch/trunk/libs/spandsp/src/v22bis_tx.c
==============================================================================
--- freeswitch/trunk/libs/spandsp/src/v22bis_tx.c	(original)
+++ freeswitch/trunk/libs/spandsp/src/v22bis_tx.c	Thu May 14 16:52:52 2009
@@ -22,12 +22,13 @@
  * 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.61 2009/04/25 10:18:50 steveu Exp $
+ * $Id: v22bis_tx.c,v 1.62 2009/04/29 12:37:45 steveu Exp $
  */
 
 /*! \file */
 
-/* THIS IS A WORK IN PROGRESS - NOT YET FUNCTIONAL! */
+/* THIS IS A WORK IN PROGRESS - It is basically functional, but it is not feature
+   complete, and doesn't reliably sync over the signal and noise level ranges it should! */
 
 #if defined(HAVE_CONFIG_H)
 #include "config.h"
@@ -240,20 +241,6 @@
 
 #define ms_to_symbols(t)    (((t)*600)/1000)
 
-/* Segments of the training sequence */
-enum
-{
-    V22BIS_TX_TRAINING_STAGE_NORMAL_OPERATION = 0,
-    V22BIS_TX_TRAINING_STAGE_INITIAL_TIMED_SILENCE,
-    V22BIS_TX_TRAINING_STAGE_INITIAL_SILENCE,
-    V22BIS_TX_TRAINING_STAGE_U11,
-    V22BIS_TX_TRAINING_STAGE_U0011,
-    V22BIS_TX_TRAINING_STAGE_S11,
-    V22BIS_TX_TRAINING_STAGE_TIMED_S11,
-    V22BIS_TX_TRAINING_STAGE_S1111,
-    V22BIS_TX_TRAINING_STAGE_PARKED
-};
-
 static const int phase_steps[4] =
 {
     1, 0, 2, 3
@@ -598,6 +585,7 @@
 
 SPAN_DECLARE(int) v22bis_request_retrain(v22bis_state_t *s, int bit_rate)
 {
+    /* TODO: support bit rate switching */
     switch (bit_rate)
     {
     case 2400:
@@ -606,7 +594,33 @@
     default:
         return -1;
     }
-    /* TODO: Implement retrain and bit rate change */
+    /* TODO: support bit rate changes */
+    /* Retrain is only valid when we are normal operation at 2400bps */
+    if (s->rx.training != V22BIS_RX_TRAINING_STAGE_NORMAL_OPERATION
+        ||
+        s->tx.training != V22BIS_TX_TRAINING_STAGE_NORMAL_OPERATION
+        ||
+        s->negotiated_bit_rate != 2400)
+    {
+        return -1;
+    }
+    /* Send things back into the training process at the appropriate point.
+       The far end should detect the S1 signal, and reciprocate. */
+    span_log(&s->logging, SPAN_LOG_FLOW, "+++ Initiating a retrain\n");
+    s->rx.pattern_repeats = 0;
+    s->rx.training_count = 0;
+    s->rx.training = V22BIS_RX_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200;
+    s->tx.training_count = 0;
+    s->tx.training = V22BIS_TX_TRAINING_STAGE_U0011;
+    v22bis_equalizer_coefficient_reset(s);
+    v22bis_report_status_change(s, SIG_STATUS_MODEM_RETRAIN_OCCURRED);
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+SPAN_DECLARE(int) v22bis_remote_loopback(v22bis_state_t *s, int enable)
+{
+    /* TODO: */
     return -1;
 }
 /*- End of function --------------------------------------------------------*/

Modified: freeswitch/trunk/libs/spandsp/tests/fax_decode.c
==============================================================================
--- freeswitch/trunk/libs/spandsp/tests/fax_decode.c	(original)
+++ freeswitch/trunk/libs/spandsp/tests/fax_decode.c	Thu May 14 16:52:52 2009
@@ -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.54 2009/02/10 13:06:47 steveu Exp $
+ * $Id: fax_decode.c,v 1.55 2009/04/29 12:37:45 steveu Exp $
  */
 
 /*! \page fax_decode_page FAX decoder
@@ -229,7 +229,7 @@
     {
         if (msg[0] != 0xFF  ||  !(msg[1] == 0x03  ||  msg[1] == 0x13))
         {
-            fprintf(stderr, "Bad frame header - %02x %02x", msg[0], msg[1]);
+            fprintf(stderr, "Bad frame header - %02x %02x\n", msg[0], msg[1]);
             return;
         }
         print_frame("HDLC: ", msg, len);

Modified: freeswitch/trunk/libs/spandsp/tests/t4_tests.c
==============================================================================
--- freeswitch/trunk/libs/spandsp/tests/t4_tests.c	(original)
+++ freeswitch/trunk/libs/spandsp/tests/t4_tests.c	Thu May 14 16:52:52 2009
@@ -137,7 +137,6 @@
 }
 /*- End of function --------------------------------------------------------*/
 
-#if 0
 static int row_read_handler(void *user_data, uint8_t buf[], size_t len)
 {
     int i;
@@ -189,22 +188,108 @@
         printf("Oops - '%c' at end of row %d\n", *s, row);
     if (memcmp(buf, ref, len))
     {
-        printf("Failed at row %d\n", row);
+        printf("Test failed at row %d\n", row);
         exit(2);
     }
     return len;
 }
 /*- End of function --------------------------------------------------------*/
-#endif
+
+static int detect_page_end(int bit, int page_ended)
+{
+    static int consecutive_eols;
+    static int max_consecutive_eols;
+    static int consecutive_zeros;
+    static int consecutive_ones;
+    static int eol_zeros;
+    static int eol_ones;
+    static int expected_eols;
+    static int end_marks;
+
+    /* Check the EOLs are added properly to the end of an image. We can't rely on the
+       decoder giving the right answer, as a full set of EOLs is not needed for the
+       decoder to work. */
+    if (bit == -1000000)
+    {
+        /* Reset */
+        consecutive_eols = 0;
+        max_consecutive_eols = 0;
+        consecutive_zeros = 0;
+        consecutive_ones = 0;
+        end_marks = 0;
+
+        eol_zeros = 11;
+        eol_ones = (page_ended == T4_COMPRESSION_ITU_T4_2D)  ?  2  :  1;
+        expected_eols = (page_ended == T4_COMPRESSION_ITU_T6)  ?  2  :  6;
+        return FALSE;
+    }
+
+    /* Monitor whether the EOLs are there in the correct amount */
+    if (bit == 0)
+    {
+        consecutive_zeros++;
+        consecutive_ones = 0;
+    }
+    else if (bit == 1)
+    {
+        if (++consecutive_ones == eol_ones)
+        {
+            if (consecutive_eols == 0  &&  consecutive_zeros >= eol_zeros)
+                consecutive_eols++;
+            else if (consecutive_zeros == eol_zeros)
+                consecutive_eols++;
+            else
+                consecutive_eols = 0;
+            consecutive_zeros = 0;
+            consecutive_ones = 0;
+        }
+        if (max_consecutive_eols < consecutive_eols)
+            max_consecutive_eols = consecutive_eols;
+    }
+    else if (bit == SIG_STATUS_END_OF_DATA)
+    {
+        if (end_marks == 0)
+        {
+            if (max_consecutive_eols != expected_eols)
+            {
+                printf("Only %d EOLs (should be %d)\n", max_consecutive_eols, expected_eols);
+                return 2;
+            }
+            consecutive_zeros = 0;
+            consecutive_eols = 0;
+            max_consecutive_eols = 0;
+        }
+        if (!page_ended)
+        {
+            /* We might need to push a few bits to get the receiver to report the
+                end of page condition (at least with T.6). */
+            if (++end_marks > 50)
+            {
+                printf("Receiver missed the end of page mark\n");
+                return 2;
+            }
+            return 0;
+        }
+        return 1;
+    }
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
 
 int main(int argc, char *argv[])
 {
+    static const int compression_sequence[] =
+    {
+        T4_COMPRESSION_ITU_T4_1D,
+        T4_COMPRESSION_ITU_T4_2D,
+        T4_COMPRESSION_ITU_T6
+    };
     int sends;
     int page_no;
     int bit;
     int end_of_page;
     int end_marks;
-    int decode_test;
+    int res;
     int compression;
     int compression_step;
     int add_page_headers;
@@ -214,6 +299,7 @@
     char buf[1024];
     uint8_t block[1024];
     const char *in_file_name;
+    const char *decode_file_name;
     int opt;
     int i;
     int bit_error_rate;
@@ -221,29 +307,37 @@
     int tests_failed;
     unsigned int last_pkt_no;
     unsigned int pkt_no;
+    int page_ended;
+    FILE *file;
 
     tests_failed = 0;
-    decode_test = FALSE;
     compression = -1;
+    compression_step = 0;
     add_page_headers = FALSE;
     restart_pages = FALSE;
     in_file_name = IN_FILE_NAME;
-    min_row_bits = 0;
+    decode_file_name = NULL;
+    /* Use a non-zero default minimum row length to ensure we test the consecutive EOLs part
+       properly. */
+    min_row_bits = 50;
     block_size = 0;
     bit_error_rate = 0;
     dump_as_xxx = FALSE;
-    while ((opt = getopt(argc, argv, "126b:dehri:m:x")) != -1)
+    while ((opt = getopt(argc, argv, "126b:d:ehri:m:x")) != -1)
     {
         switch (opt)
         {
         case '1':
             compression = T4_COMPRESSION_ITU_T4_1D;
+            compression_step = -1;
             break;
         case '2':
             compression = T4_COMPRESSION_ITU_T4_2D;
+            compression_step = -1;
             break;
         case '6':
             compression = T4_COMPRESSION_ITU_T6;
+            compression_step = -1;
             break;
         case 'b':
             block_size = atoi(optarg);
@@ -251,7 +345,7 @@
                 block_size = 1024;
             break;
         case 'd':
-            decode_test = TRUE;
+            decode_file_name = optarg;
             break;
         case 'e':
             bit_error_rate = 0x3FF;
@@ -282,7 +376,7 @@
     memset(&receive_state, 0, sizeof(receive_state));
 
     end_of_page = FALSE;
-    if (decode_test)
+    if (decode_file_name)
     {
         if (compression < 0)
             compression = T4_COMPRESSION_ITU_T4_1D;
@@ -302,7 +396,8 @@
         page_no = 1;
         t4_rx_start_page(&receive_state);
         last_pkt_no = 0;
-        while (fgets(buf, 1024, stdin))
+        file = fopen(decode_file_name, "r");
+        while (fgets(buf, 1024, file))
         {
             if (sscanf(buf, "HDLC:  FCD: 06 %x", &pkt_no) == 1)
             {
@@ -361,6 +456,7 @@
                 }
             }
         }
+        fclose(file);
         if (dump_as_xxx)
             dump_image_as_xxx(&receive_state);
         t4_rx_end_page(&receive_state);
@@ -370,6 +466,75 @@
     else
     {
 #if 1
+        printf("Testing image_function->compress->decompress->image_function\n");
+        /* Send end gets image from a function */
+        if (t4_tx_init(&send_state, in_file_name, -1, -1) == NULL)
+        {
+            printf("Failed to init T.4 tx\n");
+            exit(2);
+        }
+        span_log_set_level(&send_state.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
+        t4_tx_set_row_read_handler(&send_state, row_read_handler, NULL);
+        t4_tx_set_min_row_bits(&send_state, min_row_bits);
+        t4_tx_set_local_ident(&send_state, "111 2222 3333");
+
+        /* Receive end puts TIFF to a function. */
+        if (t4_rx_init(&receive_state, OUT_FILE_NAME, T4_COMPRESSION_ITU_T4_2D) == NULL)
+        {
+            printf("Failed to init T.4 rx\n");
+            exit(2);
+        }
+        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_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 */
+        page_no = 1;
+        /* If we are stepping around the compression schemes, reset to the start of the sequence. */
+        if (compression_step > 0)
+            compression_step = 0;
+        for (;;)
+        {
+            end_marks = 0;
+            if (compression_step >= 0)
+            {
+                compression = compression_sequence[compression_step++];
+                if (compression_step > 3)
+                    break;
+            }
+            t4_tx_set_tx_encoding(&send_state, compression);
+            t4_rx_set_rx_encoding(&receive_state, compression);
+
+            if (t4_tx_start_page(&send_state))
+                break;
+            t4_rx_start_page(&receive_state);
+            do
+            {
+                bit = t4_tx_get_bit(&send_state);
+                if (bit == SIG_STATUS_END_OF_DATA)
+                {
+                    if (++end_marks > 50)
+                    {
+                        printf("Receiver missed the end of page mark\n");
+                        tests_failed++;
+                        break;
+                    }
+                }
+                end_of_page = t4_rx_put_bit(&receive_state, bit & 1);
+            }
+            while (!end_of_page);
+            t4_tx_end_page(&send_state);
+            t4_rx_end_page(&receive_state);
+            if (compression_step < 0)
+                break;
+        }
+        t4_tx_release(&send_state);
+        t4_rx_release(&receive_state);
+#endif
+#if 1
+        printf("Testing TIFF->compress->decompress->TIFF cycle\n");
         /* Send end gets TIFF from a file */
         if (t4_tx_init(&send_state, in_file_name, -1, -1) == NULL)
         {
@@ -383,7 +548,7 @@
         /* Receive end puts TIFF to a new file. */
         if (t4_rx_init(&receive_state, OUT_FILE_NAME, T4_COMPRESSION_ITU_T4_2D) == NULL)
         {
-            printf("Failed to init T.4 rx\n");
+            printf("Failed to init T.4 rx for '%s'\n", OUT_FILE_NAME);
             exit(2);
         }
         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);
@@ -394,8 +559,9 @@
         /* Now send and receive all the pages in the source TIFF file */
         page_no = 1;
         sends = 0;
-        /* Select whether we step round the compression schemes, or use a single specified one. */
-        compression_step = (compression < 0)  ?  0  :  -1;
+        /* If we are stepping around the compression schemes, reset to the start of the sequence. */
+        if (compression_step > 0)
+            compression_step = 0;
         for (;;)
         {
             end_marks = 0;
@@ -412,20 +578,11 @@
             }
             else
             {
-                switch (compression_step)
+                if (compression_step >= 0)
                 {
-                case 0:
-                    compression = T4_COMPRESSION_ITU_T4_1D;
-                    compression_step++;
-                    break;
-                case 1:
-                    compression = T4_COMPRESSION_ITU_T4_2D;
-                    compression_step++;
-                    break;
-                case 2:
-                    compression = T4_COMPRESSION_ITU_T6;
-                    compression_step = 0;
-                    break;
+                    compression = compression_sequence[compression_step++];
+                    if (compression_step > 2)
+                        compression_step = 0;
                 }
                 t4_tx_set_tx_encoding(&send_state, compression);
                 t4_rx_set_rx_encoding(&receive_state, compression);
@@ -434,32 +591,36 @@
                     break;
             }
             t4_rx_start_page(&receive_state);
+            detect_page_end(-1000000, compression);
+            page_ended = FALSE;
             if (block_size == 0)
             {
-                do
+                for (;;)
                 {
                     bit = t4_tx_get_bit(&send_state);
-                    if (bit == SIG_STATUS_END_OF_DATA)
+                    /* Monitor whether the EOLs are there in the correct amount */
+                    if ((res = detect_page_end(bit, page_ended)))
                     {
-                        /* T.6 data does not contain an image termination sequence.
-                           T.4 1D and 2D do, and should locate that sequence. */
-                        if (compression == T4_COMPRESSION_ITU_T6)
-                            break;
-                        if (++end_marks > 50)
-                        {
-                            printf("Receiver missed the end of page mark\n");
-                            tests_failed++;
-                            break;
-                        }
+                        tests_failed += (res - 1);
+                        break;
                     }
-                    if (bit_error_rate)
+                    if (!page_ended)
                     {
-                        if ((rand() % bit_error_rate) == 0)
-                            bit ^= 1;
+                        if (bit_error_rate)
+                        {
+                            if ((rand() % bit_error_rate) == 0)
+                                bit ^= 1;
+                        }
+                        if (t4_rx_put_bit(&receive_state, bit & 1))
+                            page_ended = TRUE;
                     }
-                    end_of_page = t4_rx_put_bit(&receive_state, bit & 1);
                 }
-                while (!end_of_page);
+                /* Now throw junk at the receive context, to ensure stuff occuring
+                   after the end of page condition has no bad effect. */
+                for (i = 0;  i < 1000;  i++)
+                {
+                    t4_rx_put_bit(&receive_state, (rand() >> 10) & 1);
+                }
             }
             else if (block_size == 1)
             {
@@ -468,10 +629,6 @@
                     bit = t4_tx_get_byte(&send_state);
                     if ((bit & 0x100))
                     {
-                        /* T.6 data does not contain an image termination sequence.
-                           T.4 1D and 2D do, and should locate that sequence. */
-                        if (compression == T4_COMPRESSION_ITU_T6)
-                            break;
                         if (++end_marks > 50)
                         {
                             printf("Receiver missed the end of page mark\n");
@@ -492,10 +649,6 @@
                         end_of_page = t4_rx_put_chunk(&receive_state, block, bit);
                     if (bit < block_size)
                     {
-                        /* T.6 data does not contain an image termination sequence.
-                           T.4 1D and 2D do, and should locate that sequence. */
-                        if (compression == T4_COMPRESSION_ITU_T6)
-                            break;
                         if (++end_marks > 50)
                         {
                             printf("Receiver missed the end of page mark\n");
@@ -520,93 +673,13 @@
            at the image level. TIFF files allow a lot of ways to express the same thing,
            so bit matching of the files is not the normal case. */
         fflush(stdout);
-        sprintf(buf, "tiffcmp -t %s " OUT_FILE_NAME, in_file_name);
-        if (tests_failed)//  ||  system(buf))
+        sprintf(buf, "tiffcmp -t %s %s", in_file_name, OUT_FILE_NAME);
+        if (tests_failed  ||  system(buf))
         {
             printf("Tests failed\n");
             exit(2);
         }
 #endif
-#if 0
-        /* Send end gets TIFF from a function */
-        if (t4_tx_init(&send_state, in_file_name, -1, -1) == NULL)
-        {
-            printf("Failed to init T.4 tx\n");
-            exit(2);
-        }
-        span_log_set_level(&send_state.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
-        t4_tx_set_row_read_handler(&send_state, row_read_handler, NULL);
-        t4_tx_set_min_row_bits(&send_state, min_row_bits);
-        t4_tx_set_local_ident(&send_state, "111 2222 3333");
-
-        /* Receive end puts TIFF to a function. */
-        if (t4_rx_init(&receive_state, OUT_FILE_NAME, T4_COMPRESSION_ITU_T4_2D) == NULL)
-        {
-            printf("Failed to init T.4 rx\n");
-            exit(2);
-        }
-        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_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 */
-        page_no = 1;
-        /* Select whether we step round the compression schemes, or use a single specified one. */
-        compression_step = (compression < 0)  ?  0  :  -1;
-        for (;;)
-        {
-            end_marks = 0;
-            /* Add a header line to alternate pages, if required */
-            switch (compression_step)
-            {
-            case 0:
-                compression = T4_COMPRESSION_ITU_T4_1D;
-                compression_step++;
-                break;
-            case 1:
-                compression = T4_COMPRESSION_ITU_T4_2D;
-                compression_step++;
-                break;
-            case 2:
-                compression = T4_COMPRESSION_ITU_T6;
-                compression_step = 0;
-                break;
-            }
-            t4_tx_set_tx_encoding(&send_state, compression);
-            t4_rx_set_rx_encoding(&receive_state, compression);
-
-            if (t4_tx_start_page(&send_state))
-                break;
-            t4_rx_start_page(&receive_state);
-            do
-            {
-                bit = t4_tx_get_bit(&send_state);
-                if (bit == SIG_STATUS_END_OF_DATA)
-                {
-                    /* T.6 data does not contain an image termination sequence.
-                       T.4 1D and 2D do, and should locate that sequence. */
-                    if (compression == T4_COMPRESSION_ITU_T6)
-                        break;
-                    if (++end_marks > 50)
-                    {
-                        printf("Receiver missed the end of page mark\n");
-                        tests_failed++;
-                        break;
-                    }
-                }
-                end_of_page = t4_rx_put_bit(&receive_state, bit & 1);
-            }
-            while (!end_of_page);
-            t4_tx_end_page(&send_state);
-            t4_rx_end_page(&receive_state);
-            break;
-        }
-        t4_tx_release(&send_state);
-        t4_rx_release(&receive_state);
-#endif
-
         printf("Tests passed\n");
     }
     return 0;

Modified: freeswitch/trunk/libs/spandsp/tests/tsb85_tests.sh
==============================================================================
--- freeswitch/trunk/libs/spandsp/tests/tsb85_tests.sh	(original)
+++ freeswitch/trunk/libs/spandsp/tests/tsb85_tests.sh	Thu May 14 16:52:52 2009
@@ -15,7 +15,7 @@
 # License along with this program; if not, write to the Free Software
 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 #
-# $Id: tsb85_tests.sh,v 1.6 2008/09/11 15:13:42 steveu Exp $
+# $Id: tsb85_tests.sh,v 1.7 2009/04/30 15:04:20 steveu Exp $
 #
 
 run_tsb85_test()
@@ -54,11 +54,12 @@
     run_tsb85_test
 done
 
+# MRGX03 is failing because the V.27ter modemsays it trained on HDLC
 # MRGX05 is failing because we don't distinguish MPS immediately after MCF from MPS after
 # a corrupt image signal.
 
 #for TEST in MRGX01 MRGX02 MRGX03 MRGX04 MRGX05 MRGX06 MRGX07 MRGX08 ; do
-for TEST in MRGX01 MRGX02 MRGX03 MRGX04 MRGX06 MRGX07 MRGX08 ; do
+for TEST in MRGX01 MRGX02 MRGX04 MRGX06 MRGX07 MRGX08 ; do
     run_tsb85_test
 done
 
@@ -94,7 +95,8 @@
     run_tsb85_test
 done
 
-for TEST in OTEN01 OTEN02 OTEN03 OTEN04 OTEN05 OTEN06 ; do
+#for TEST in OTEN01 OTEN02 OTEN03 OTEN04 OTEN05 OTEN06 ; do
+for TEST in OTEN01 OTEN03 OTEN04 OTEN05 OTEN06 ; do
     run_tsb85_test
 done
 



More information about the Freeswitch-svn mailing list