From 3549488e8eb56fe230db92728c895c68a0c91004 Mon Sep 17 00:00:00 2001
From: Steve Underwood <steveu@coppice.org>
Date: Wed, 4 Jun 2014 23:54:03 +0800
Subject: [PATCH] Fixed a problem in FAX where a received handshake, delayed so
 much it is received as we queue a retry, causes the retry frame to remain
 queued in the HDLC entity.

---
 libs/spandsp/spandsp/fax-tests.xml      | 41 +++++++++++++++++++++++
 libs/spandsp/src/adsi.c                 |  6 ++--
 libs/spandsp/src/at_interpreter.c       |  2 +-
 libs/spandsp/src/fax_modems.c           |  5 ++-
 libs/spandsp/src/hdlc.c                 | 38 ++++++++++++++++++++--
 libs/spandsp/src/plc.c                  | 12 +++----
 libs/spandsp/src/queue.c                | 32 +++++++++---------
 libs/spandsp/src/spandsp/hdlc.h         | 25 +++++++++++++-
 libs/spandsp/src/t30.c                  | 43 ++++++++++++++++---------
 libs/spandsp/src/t30_api.c              |  6 ++--
 libs/spandsp/src/t31.c                  |  2 +-
 libs/spandsp/src/t38_core.c             |  2 +-
 libs/spandsp/src/t38_terminal.c         | 28 ++++++++++------
 libs/spandsp/src/time_scale.c           | 18 +++++------
 libs/spandsp/src/v42.c                  |  2 +-
 libs/spandsp/tests/fax_decode.c         | 43 ++++++++++++++++++-------
 libs/spandsp/tests/fax_tester.c         |  2 +-
 libs/spandsp/tests/power_meter_tests.c  |  2 +-
 libs/spandsp/tests/t43_tests.c          |  4 +--
 libs/spandsp/tests/tsb85_extra_tests.sh |  2 +-
 libs/spandsp/tests/tsb85_tests.c        |  2 +-
 21 files changed, 228 insertions(+), 89 deletions(-)

diff --git a/libs/spandsp/spandsp/fax-tests.xml b/libs/spandsp/spandsp/fax-tests.xml
index 23f333a396..495eadec7e 100644
--- a/libs/spandsp/spandsp/fax-tests.xml
+++ b/libs/spandsp/spandsp/fax-tests.xml
@@ -184,5 +184,46 @@
         <step dir="T" type="HDLC" tag="DCN" value="FF C8 5F"/>
         <step dir="T" type="POSTAMBLE"/>
     </test>
+    <test name="Phase-D-collision">
+        <!-- DUT calls tester and sends 1 IMPRESS and 1 WHITE page. The MCF after the first
+             page is delayed enough to cause a collision with a retry of the MPS from the DUT. -->
+        <step type="ANSWER" value="etsi_300_242_a4_impress_white.tif"/>
+        <step dir="T" type="SET" tag="IDENT" value="+0123456789"/>
+
+        <step dir="R" type="CNG"/>
+
+        <step dir="T" type="CED"/>
+        <step type="WAIT" value="75"/>
+        <step dir="T" type="PREAMBLE" modem="V.21"/>
+        <step dir="T" type="HDLC" tag="DIS" value="FF C8 01 00 50 00"/>
+        <step dir="T" type="POSTAMBLE"/>
+
+        <step dir="R" type="HDLC" modem="V.21" tag="TSI+" value="FF C0 C2 9C 1C EC 6C AC 2C CC 4C 8C 0C D4 04 04 04 04 04 04 04 04 04 ..."/>
+        <step dir="R" type="HDLC" tag="DCS+" value="FF C8 C1 ..."/>
+        <step dir="R" type="TCF" modem="V.27ter/4800" timeout="60000"/>
+
+        <step type="WAIT" value="75"/>
+        <step dir="T" type="PREAMBLE" modem="V.21"/>
+        <step dir="T" type="HDLC" tag="CFR" value="FF C8 21"/>
+        <step dir="T" type="POSTAMBLE"/>
+
+        <step dir="R" type="MSG" modem="V.27ter/4800" timeout="180000"/>
+        <step dir="R" type="HDLC" modem="V.21" tag="MPS+" value="FF C8 F2"/>
+
+        <step type="WAIT" value="3500"/>
+        <step dir="T" type="PREAMBLE" modem="V.21"/>
+        <step dir="T" type="HDLC" tag="MCF" value="FF C8 31"/>
+        <step dir="T" type="POSTAMBLE"/>
+
+        <step dir="R" type="MSG" modem="V.27ter/4800"  timeout="60000"/>
+        <step dir="R" type="HDLC" modem="V.21" tag="EOP+" value="FF C8 F4"/>
+
+        <step type="WAIT" value="75"/>
+        <step dir="T" type="PREAMBLE" modem="V.21"/>
+        <step dir="T" type="HDLC" tag="MCF" value="FF C8 31"/>
+        <step dir="T" type="POSTAMBLE"/>
+
+        <step dir="R" type="HDLC" modem="V.21" tag="DCN+" value="FF C8 DF"/>
+    </test>
 </test-group>
 </fax-tests>
diff --git a/libs/spandsp/src/adsi.c b/libs/spandsp/src/adsi.c
index 1f711bf44f..72d85319c1 100644
--- a/libs/spandsp/src/adsi.c
+++ b/libs/spandsp/src/adsi.c
@@ -1029,13 +1029,13 @@ SPAN_DECLARE(int) adsi_add_field(adsi_tx_state_t *s, uint8_t *msg, int len, uint
                 msg[len++] = (uint8_t) field_len;
                 if (field_len == DLE)
                     msg[len++] = (uint8_t) field_len;
-                memcpy(msg + len, field_body, field_len);
+                memcpy(&msg[len], field_body, field_len);
                 len += field_len;
             }
             else
             {
                 /* No field type or length, for restricted single message formats */
-                memcpy(msg + len, field_body, field_len);
+                memcpy(&msg[len], field_body, field_len);
                 len += field_len;
             }
         }
@@ -1080,7 +1080,7 @@ SPAN_DECLARE(int) adsi_add_field(adsi_tx_state_t *s, uint8_t *msg, int len, uint
             x = msg[--len];
             if (field_type != CLIP_DTMF_HASH_UNSPECIFIED)
                 msg[len++] = field_type;
-            memcpy(msg + len, field_body, field_len);
+            memcpy(&msg[len], field_body, field_len);
             msg[len + field_len] = (uint8_t) x;
             len += (field_len + 1);
         }
diff --git a/libs/spandsp/src/at_interpreter.c b/libs/spandsp/src/at_interpreter.c
index 9bebde6272..5d6dc42043 100644
--- a/libs/spandsp/src/at_interpreter.c
+++ b/libs/spandsp/src/at_interpreter.c
@@ -5411,7 +5411,7 @@ static int command_search(const char *u, int *matched)
 
     entry = 0;
     /* Loop over the length of the string to search the trie... */
-    for (i = 0, ptr = 0;  ptr < COMMAND_TRIE_LEN;  i++)
+    for (i = 0, ptr = 0;  ptr < COMMAND_TRIE_LEN - 2;  i++)
     {
         /* The character in u we are processing... */
         /* V.250 5.4.1 says upper and lower case are equivalent in commands */
diff --git a/libs/spandsp/src/fax_modems.c b/libs/spandsp/src/fax_modems.c
index a09b0c9506..df89b088c2 100644
--- a/libs/spandsp/src/fax_modems.c
+++ b/libs/spandsp/src/fax_modems.c
@@ -172,7 +172,10 @@ SPAN_DECLARE_NONSTD(void) fax_modems_hdlc_tx_frame(void *user_data, const uint8_
 
     s = (fax_modems_state_t *) user_data;
 
-    hdlc_tx_frame(&s->hdlc_tx, msg, len);
+    if (len == -1)
+        hdlc_tx_restart(&s->hdlc_tx);
+    else
+        hdlc_tx_frame(&s->hdlc_tx, msg, len);
 }
 /*- End of function --------------------------------------------------------*/
 
diff --git a/libs/spandsp/src/hdlc.c b/libs/spandsp/src/hdlc.c
index 7a20bf2451..74b2760e70 100644
--- a/libs/spandsp/src/hdlc.c
+++ b/libs/spandsp/src/hdlc.c
@@ -311,6 +311,20 @@ SPAN_DECLARE(void) hdlc_rx_set_octet_counting_report_interval(hdlc_rx_state_t *s
 }
 /*- End of function --------------------------------------------------------*/
 
+SPAN_DECLARE(int) hdlc_rx_restart(hdlc_rx_state_t *s)
+{
+    s->framing_ok_announced = false;
+    s->flags_seen = 0;
+    s->raw_bit_stream = 0;
+    s->byte_in_progress = 0;
+    s->num_bits = 0;
+    s->octet_counting_mode = false;
+    s->octet_count = 0;
+    s->len = 0;
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
 SPAN_DECLARE(hdlc_rx_state_t *) hdlc_rx_init(hdlc_rx_state_t *s,
                                              bool crc32,
                                              bool report_bad_frames,
@@ -375,7 +389,7 @@ SPAN_DECLARE(int) hdlc_rx_get_stats(hdlc_rx_state_t *s,
 
 SPAN_DECLARE(int) hdlc_tx_frame(hdlc_tx_state_t *s, const uint8_t *frame, size_t len)
 {
-    if (len <= 0)
+    if (len == 0)
     {
         s->tx_end = true;
         return 0;
@@ -394,7 +408,7 @@ SPAN_DECLARE(int) hdlc_tx_frame(hdlc_tx_state_t *s, const uint8_t *frame, size_t
         if (s->len)
             return -1;
     }
-    memcpy(s->buffer + s->len, frame, len);
+    memcpy(&s->buffer[s->len], frame, len);
     if (s->crc_bytes == 2)
         s->crc = crc_itu16_calc(frame, len, (uint16_t) s->crc);
     else
@@ -589,6 +603,24 @@ SPAN_DECLARE(void) hdlc_tx_set_max_frame_len(hdlc_tx_state_t *s, size_t max_len)
 }
 /*- End of function --------------------------------------------------------*/
 
+SPAN_DECLARE(int) hdlc_tx_restart(hdlc_tx_state_t *s)
+{
+    s->octets_in_progress = 0;
+    s->num_bits = 0;
+    s->idle_octet = 0x7E;
+    s->flag_octets = 0;
+    s->abort_octets = 0;
+    s->report_flag_underflow = false;
+    s->len = 0;
+    s->pos = 0;
+    s->crc = 0;
+    s->byte = 0;
+    s->bits = 0;
+    s->tx_end = false;
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
 SPAN_DECLARE(hdlc_tx_state_t *) hdlc_tx_init(hdlc_tx_state_t *s,
                                              bool crc32,
                                              int inter_frame_flags,
@@ -602,7 +634,6 @@ SPAN_DECLARE(hdlc_tx_state_t *) hdlc_tx_init(hdlc_tx_state_t *s,
             return NULL;
     }
     memset(s, 0, sizeof(*s));
-    s->idle_octet = 0x7E;
     s->underflow_handler = handler;
     s->user_data = user_data;
     s->inter_frame_flags = (inter_frame_flags < 1)  ?  1  :  inter_frame_flags;
@@ -616,6 +647,7 @@ SPAN_DECLARE(hdlc_tx_state_t *) hdlc_tx_init(hdlc_tx_state_t *s,
         s->crc_bytes = 2;
         s->crc = 0xFFFF;
     }
+    s->idle_octet = 0x7E;
     s->progressive = progressive;
     s->max_frame_len = HDLC_MAXFRAME_LEN;
     return s;
diff --git a/libs/spandsp/src/plc.c b/libs/spandsp/src/plc.c
index cb40ea88e0..52f4e24044 100644
--- a/libs/spandsp/src/plc.c
+++ b/libs/spandsp/src/plc.c
@@ -58,21 +58,21 @@ static void save_history(plc_state_t *s, int16_t *buf, int len)
     if (len >= PLC_HISTORY_LEN)
     {
         /* Just keep the last part of the new data, starting at the beginning of the buffer */
-        memcpy(s->history, buf + len - PLC_HISTORY_LEN, sizeof(int16_t)*PLC_HISTORY_LEN);
+        memcpy(s->history, &buf[len - PLC_HISTORY_LEN], sizeof(int16_t)*PLC_HISTORY_LEN);
         s->buf_ptr = 0;
         return;
     }
     if (s->buf_ptr + len > PLC_HISTORY_LEN)
     {
         /* Wraps around - must break into two sections */
-        memcpy(s->history + s->buf_ptr, buf, sizeof(int16_t)*(PLC_HISTORY_LEN - s->buf_ptr));
+        memcpy(&s->history[s->buf_ptr], buf, sizeof(int16_t)*(PLC_HISTORY_LEN - s->buf_ptr));
         len -= (PLC_HISTORY_LEN - s->buf_ptr);
-        memcpy(s->history, buf + (PLC_HISTORY_LEN - s->buf_ptr), sizeof(int16_t)*len);
+        memcpy(s->history, &buf[PLC_HISTORY_LEN - s->buf_ptr], sizeof(int16_t)*len);
         s->buf_ptr = len;
         return;
     }
     /* Can use just one section */
-    memcpy(s->history + s->buf_ptr, buf, sizeof(int16_t)*len);
+    memcpy(&s->history[s->buf_ptr], buf, sizeof(int16_t)*len);
     s->buf_ptr += len;
 }
 /*- End of function --------------------------------------------------------*/
@@ -84,8 +84,8 @@ static __inline__ void normalise_history(plc_state_t *s)
     if (s->buf_ptr == 0)
         return;
     memcpy(tmp, s->history, sizeof(int16_t)*s->buf_ptr);
-    memmove(s->history, s->history + s->buf_ptr, sizeof(int16_t)*(PLC_HISTORY_LEN - s->buf_ptr));
-    memcpy(s->history + PLC_HISTORY_LEN - s->buf_ptr, tmp, sizeof(int16_t)*s->buf_ptr);
+    memmove(s->history, &s->history[s->buf_ptr], sizeof(int16_t)*(PLC_HISTORY_LEN - s->buf_ptr));
+    memcpy(&s->history[PLC_HISTORY_LEN - s->buf_ptr], tmp, sizeof(int16_t)*s->buf_ptr);
     s->buf_ptr = 0;
 }
 /*- End of function --------------------------------------------------------*/
diff --git a/libs/spandsp/src/queue.c b/libs/spandsp/src/queue.c
index d569039969..98f19e3962 100644
--- a/libs/spandsp/src/queue.c
+++ b/libs/spandsp/src/queue.c
@@ -119,8 +119,8 @@ SPAN_DECLARE(int) queue_view(queue_state_t *s, uint8_t *buf, int len)
         /* A two step process */
         if (buf)
         {
-            memcpy(buf, s->data + optr, to_end);
-            memcpy(buf + to_end, s->data, real_len - to_end);
+            memcpy(buf, &s->data[optr], to_end);
+            memcpy(&buf[to_end], s->data, real_len - to_end);
         }
         /*endif*/
     }
@@ -128,7 +128,7 @@ SPAN_DECLARE(int) queue_view(queue_state_t *s, uint8_t *buf, int len)
     {
         /* A one step process */
         if (buf)
-            memcpy(buf, s->data + optr, real_len);
+            memcpy(buf, &s->data[optr], real_len);
         /*endif*/
     }
     /*endif*/
@@ -170,8 +170,8 @@ SPAN_DECLARE(int) queue_read(queue_state_t *s, uint8_t *buf, int len)
         /* A two step process */
         if (buf)
         {
-            memcpy(buf, s->data + optr, to_end);
-            memcpy(buf + to_end, s->data, real_len - to_end);
+            memcpy(buf, &s->data[optr], to_end);
+            memcpy(&buf[to_end], s->data, real_len - to_end);
         }
         /*endif*/
         new_optr = real_len - to_end;
@@ -180,7 +180,7 @@ SPAN_DECLARE(int) queue_read(queue_state_t *s, uint8_t *buf, int len)
     {
         /* A one step process */
         if (buf)
-            memcpy(buf, s->data + optr, real_len);
+            memcpy(buf, &s->data[optr], real_len);
         /*endif*/
         new_optr = optr + real_len;
         if (new_optr >= s->len)
@@ -253,7 +253,7 @@ SPAN_DECLARE(int) queue_write(queue_state_t *s, const uint8_t *buf, int len)
     if (iptr < optr  ||  to_end >= real_len)
     {
         /* A one step process */
-        memcpy(s->data + iptr, buf, real_len);
+        memcpy(&s->data[iptr], buf, real_len);
         new_iptr = iptr + real_len;
         if (new_iptr >= s->len)
             new_iptr = 0;
@@ -262,8 +262,8 @@ SPAN_DECLARE(int) queue_write(queue_state_t *s, const uint8_t *buf, int len)
     else
     {
         /* A two step process */
-        memcpy(s->data + iptr, buf, to_end);
-        memcpy(s->data, buf + to_end, real_len - to_end);
+        memcpy(&s->data[iptr], buf, to_end);
+        memcpy(s->data, &buf[to_end], real_len - to_end);
         new_iptr = real_len - to_end;
     }
     /*endif*/
@@ -367,8 +367,8 @@ SPAN_DECLARE(int) queue_write_msg(queue_state_t *s, const uint8_t *buf, int len)
     if (iptr < optr  ||  to_end >= real_len)
     {
         /* A one step process */
-        memcpy(s->data + iptr, &lenx, sizeof(uint16_t));
-        memcpy(s->data + iptr + sizeof(uint16_t), buf, len);
+        memcpy(&s->data[iptr], &lenx, sizeof(uint16_t));
+        memcpy(&s->data[iptr + sizeof(uint16_t)], buf, len);
         new_iptr = iptr + real_len;
         if (new_iptr >= s->len)
             new_iptr = 0;
@@ -380,16 +380,16 @@ SPAN_DECLARE(int) queue_write_msg(queue_state_t *s, const uint8_t *buf, int len)
         if (to_end >= sizeof(uint16_t))
         {
             /* The actual message wraps around the end of the buffer */
-            memcpy(s->data + iptr, &lenx, sizeof(uint16_t));
-            memcpy(s->data + iptr + sizeof(uint16_t), buf, to_end - sizeof(uint16_t));
-            memcpy(s->data, buf + to_end - sizeof(uint16_t), real_len - to_end);
+            memcpy(&s->data[iptr], &lenx, sizeof(uint16_t));
+            memcpy(&s->data[iptr + sizeof(uint16_t)], buf, to_end - sizeof(uint16_t));
+            memcpy(s->data, &buf[to_end - sizeof(uint16_t)], real_len - to_end);
         }
         else
         {
             /* The message length wraps around the end of the buffer */
-            memcpy(s->data + iptr, (uint8_t *) &lenx, to_end);
+            memcpy(&s->data[iptr], (uint8_t *) &lenx, to_end);
             memcpy(s->data, ((uint8_t *) &lenx) + to_end, sizeof(uint16_t) - to_end);
-            memcpy(s->data + sizeof(uint16_t) - to_end, buf, len);
+            memcpy(&s->data[sizeof(uint16_t) - to_end], buf, len);
         }
         new_iptr = real_len - to_end;
     }
diff --git a/libs/spandsp/src/spandsp/hdlc.h b/libs/spandsp/src/spandsp/hdlc.h
index a0916d1d5f..52f68505b1 100644
--- a/libs/spandsp/src/spandsp/hdlc.h
+++ b/libs/spandsp/src/spandsp/hdlc.h
@@ -99,6 +99,13 @@ SPAN_DECLARE(hdlc_rx_state_t *) hdlc_rx_init(hdlc_rx_state_t *s,
                                              hdlc_frame_handler_t handler,
                                              void *user_data);
 
+/*! Re-initialise an HDLC receiver context. This does not reset the usage statistics.
+    \brief Re-initialise an HDLC receiver context.
+    \param s A pointer to an HDLC receiver context.
+    \return 0 for success.
+*/
+SPAN_DECLARE(int) hdlc_rx_restart(hdlc_rx_state_t *s);
+
 /*! Change the put_bit function associated with an HDLC receiver context.
     \brief Change the put_bit function associated with an HDLC receiver context.
     \param s A pointer to an HDLC receiver context.
@@ -167,7 +174,8 @@ SPAN_DECLARE_NONSTD(void) hdlc_rx_put_byte(hdlc_rx_state_t *s, int new_byte);
 */
 SPAN_DECLARE_NONSTD(void) hdlc_rx_put(hdlc_rx_state_t *s, const uint8_t buf[], int len);
 
-/*! \brief Initialise an HDLC transmitter context.
+/*! Initialise an HDLC transmitter context.
+    \brief Initialise an HDLC transmitter context.
     \param s A pointer to an HDLC transmitter context.
     \param crc32 True to use ITU CRC32. False to use ITU CRC16.
     \param inter_frame_flags The minimum flag octets to insert between frames (usually one).
@@ -183,8 +191,23 @@ SPAN_DECLARE(hdlc_tx_state_t *) hdlc_tx_init(hdlc_tx_state_t *s,
                                              hdlc_underflow_handler_t handler,
                                              void *user_data);
 
+/*! Re-initialise an HDLC transmitter context.
+    \brief Re-initialise an HDLC transmitter context.
+    \param s A pointer to an HDLC transmitter context.
+    \return 0 for success.
+*/
+SPAN_DECLARE(int) hdlc_tx_restart(hdlc_tx_state_t *s);
+
+/*! Release an HDLC transmitter context.
+    \brief Release an HDLC transmitter context.
+    \param s A pointer to an HDLC transmitter context.
+    \return 0 for OK */
 SPAN_DECLARE(int) hdlc_tx_release(hdlc_tx_state_t *s);
 
+/*! Free an HDLC transmitter context.
+    \brief Free an HDLC transmitter context.
+    \param s A pointer to an HDLC transmitter context.
+    \return 0 for OK */
 SPAN_DECLARE(int) hdlc_tx_free(hdlc_tx_state_t *s);
 
 /*! \brief Set the maximum frame length for an HDLC transmitter context.
diff --git a/libs/spandsp/src/t30.c b/libs/spandsp/src/t30.c
index 8a9c1cd193..e7f958552c 100644
--- a/libs/spandsp/src/t30.c
+++ b/libs/spandsp/src/t30.c
@@ -5109,20 +5109,34 @@ static void queue_phase(t30_state_t *s, int phase)
     if (s->rx_signal_present)
     {
         /* We need to wait for that signal to go away */
+        if (s->next_phase != T30_PHASE_IDLE)
+        {
+            span_log(&s->logging, SPAN_LOG_FLOW, "Flushing queued phase %s\n", phase_names[s->next_phase]);
+            /* Ensure nothing has been left in the queue that was scheduled to go out in the previous next
+               phase */
+            if (s->send_hdlc_handler)
+                s->send_hdlc_handler(s->send_hdlc_user_data, NULL, -1);
+        }
         s->next_phase = phase;
     }
     else
     {
+        /* We don't need to queue the new phase. We can change to it immediately. */
         set_phase(s, phase);
-        s->next_phase = T30_PHASE_IDLE;
     }
 }
 /*- End of function --------------------------------------------------------*/
 
 static void set_phase(t30_state_t *s, int phase)
 {
-    //if (phase = s->phase)
-    //    return;
+    if (phase != s->next_phase  &&  s->next_phase != T30_PHASE_IDLE)
+    {
+        span_log(&s->logging, SPAN_LOG_FLOW, "Flushing queued phase %s\n", phase_names[s->next_phase]);
+        /* Ensure nothing has been left in the queue that was scheduled to go out in the previous next
+           phase */
+        if (s->send_hdlc_handler)
+            s->send_hdlc_handler(s->send_hdlc_user_data, NULL, -1);
+    }
     span_log(&s->logging, SPAN_LOG_FLOW, "Changing from phase %s to %s\n", phase_names[s->phase], phase_names[phase]);
     /* We may be killing a receiver before it has declared the end of the
        signal. Force the signal present indicator to off, because the
@@ -5132,6 +5146,7 @@ static void set_phase(t30_state_t *s, int phase)
     s->rx_trained = false;
     s->rx_frame_received = false;
     s->phase = phase;
+    s->next_phase = T30_PHASE_IDLE;
     switch (phase)
     {
     case T30_PHASE_A_CED:
@@ -5470,6 +5485,14 @@ static void timer_t1_expired(t30_state_t *s)
 }
 /*- 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 %s. An HDLC frame lasted too long.\n", phase_names[s->phase], state_names[s->state]);
+    t30_set_status(s, T30_ERR_HDLC_CARRIER);
+    disconnect(s);
+}
+/*- End of function --------------------------------------------------------*/
+
 static void timer_t2_expired(t30_state_t *s)
 {
     if (s->timer_t2_t4_is != TIMER_IS_T2B)
@@ -5541,14 +5564,6 @@ static void timer_t2_expired(t30_state_t *s)
 }
 /*- 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 %s. An HDLC frame lasted too long.\n", phase_names[s->phase], state_names[s->state]);
-    t30_set_status(s, 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 %s. An HDLC frame lasted too long.\n", phase_names[s->phase], state_names[s->state]);
@@ -5680,7 +5695,7 @@ static int decode_nsf_nss_nsc(t30_state_t *s, uint8_t *msg[], const uint8_t *pkt
 
     if ((t = span_alloc(len - 1)) == NULL)
         return 0;
-    memcpy(t, pkt + 1, len - 1);
+    memcpy(t, &pkt[1], len - 1);
     *msg = t;
     return len - 1;
 }
@@ -5777,10 +5792,7 @@ static void t30_non_ecm_rx_status(void *user_data, int status)
             break;
         }
         if (s->next_phase != T30_PHASE_IDLE)
-        {
             set_phase(s, s->next_phase);
-            s->next_phase = T30_PHASE_IDLE;
-        }
         break;
     default:
         span_log(&s->logging, SPAN_LOG_WARNING, "Unexpected non-ECM rx status - %d!\n", status);
@@ -6012,7 +6024,6 @@ static void t30_hdlc_rx_status(void *user_data, int status)
         {
             /* The appropriate timer for the next phase should already be in progress */
             set_phase(s, s->next_phase);
-            s->next_phase = T30_PHASE_IDLE;
         }
         else
         {
diff --git a/libs/spandsp/src/t30_api.c b/libs/spandsp/src/t30_api.c
index 6d0bca3840..5bf164b998 100644
--- a/libs/spandsp/src/t30_api.c
+++ b/libs/spandsp/src/t30_api.c
@@ -282,7 +282,7 @@ SPAN_DECLARE(int) t30_set_tx_nsf(t30_state_t *s, const uint8_t *nsf, int len)
         span_free(s->tx_info.nsf);
     if (nsf  &&  len > 0  &&  (s->tx_info.nsf = span_alloc(len + 3)))
     {
-        memcpy(s->tx_info.nsf + 3, nsf, len);
+        memcpy(&s->tx_info.nsf[3], nsf, len);
         s->tx_info.nsf_len = len;
     }
     else
@@ -316,7 +316,7 @@ SPAN_DECLARE(int) t30_set_tx_nsc(t30_state_t *s, const uint8_t *nsc, int len)
         span_free(s->tx_info.nsc);
     if (nsc  &&  len > 0  &&  (s->tx_info.nsc = span_alloc(len + 3)))
     {
-        memcpy(s->tx_info.nsc + 3, nsc, len);
+        memcpy(&s->tx_info.nsc[3], nsc, len);
         s->tx_info.nsc_len = len;
     }
     else
@@ -350,7 +350,7 @@ SPAN_DECLARE(int) t30_set_tx_nss(t30_state_t *s, const uint8_t *nss, int len)
         span_free(s->tx_info.nss);
     if (nss  &&  len > 0  &&  (s->tx_info.nss = span_alloc(len + 3)))
     {
-        memcpy(s->tx_info.nss + 3, nss, len);
+        memcpy(&s->tx_info.nss[3], nss, len);
         s->tx_info.nss_len = len;
     }
     else
diff --git a/libs/spandsp/src/t31.c b/libs/spandsp/src/t31.c
index 47f26c9e49..ef8dcd16f6 100644
--- a/libs/spandsp/src/t31.c
+++ b/libs/spandsp/src/t31.c
@@ -1877,7 +1877,7 @@ static void hdlc_accept_frame(void *user_data, const uint8_t *msg, int len, int
             buf[0] = (ok)  ?  AT_RESPONSE_CODE_OK  :  AT_RESPONSE_CODE_ERROR;
             /* It is safe to look at the two bytes beyond the length of the message,
                and expect to find the FCS there. */
-            memcpy(buf + 1, msg, len + 2);
+            memcpy(&buf[1], msg, len + 2);
             queue_write_msg(s->rx_queue, buf, len + 3);
         }
         /*endif*/
diff --git a/libs/spandsp/src/t38_core.c b/libs/spandsp/src/t38_core.c
index 5fb57bbc82..c310ebbd95 100644
--- a/libs/spandsp/src/t38_core.c
+++ b/libs/spandsp/src/t38_core.c
@@ -842,7 +842,7 @@ static int t38_encode_data(t38_core_state_t *s, uint8_t buf[], int data_type, co
                         return -1;
                     buf[len++] = (uint8_t) (((q->field_len - 1) >> 8) & 0xFF);
                     buf[len++] = (uint8_t) ((q->field_len - 1) & 0xFF);
-                    memcpy(buf + len, q->field, q->field_len);
+                    memcpy(&buf[len], q->field, q->field_len);
                     len += q->field_len;
                 }
                 data_field_no++;
diff --git a/libs/spandsp/src/t38_terminal.c b/libs/spandsp/src/t38_terminal.c
index 0349eb4283..03f8ede658 100644
--- a/libs/spandsp/src/t38_terminal.c
+++ b/libs/spandsp/src/t38_terminal.c
@@ -616,20 +616,28 @@ static void send_hdlc(void *user_data, const uint8_t *msg, int len)
     t38_terminal_state_t *s;
 
     s = (t38_terminal_state_t *) user_data;
-    if (len <= 0)
+    if (len == 0)
     {
+        /* A length of zero means shut down the HDLC transmission */
+        /* Setting len to -1 makes HDLC shut down */
         s->t38_fe.hdlc_tx.len = -1;
-    }
-    else
-    {
-        if (s->t38_fe.us_per_tx_chunk)
-            s->t38_fe.hdlc_tx.extra_bits = extra_bits_in_stuffed_frame(msg, len);
-        /*endif*/
-        bit_reverse(s->t38_fe.hdlc_tx.buf, msg, len);
-        s->t38_fe.hdlc_tx.len = len;
-        s->t38_fe.hdlc_tx.ptr = 0;
+        return;
     }
     /*endif*/
+    if (len == -1)
+    {
+        /* A length of -1 means flush any buffered HDLC data */
+        s->t38_fe.hdlc_tx.len = 0;
+        s->t38_fe.hdlc_tx.ptr = 0;
+        return;
+    }
+    /*endif*/
+    if (s->t38_fe.us_per_tx_chunk)
+        s->t38_fe.hdlc_tx.extra_bits = extra_bits_in_stuffed_frame(msg, len);
+    /*endif*/
+    bit_reverse(s->t38_fe.hdlc_tx.buf, msg, len);
+    s->t38_fe.hdlc_tx.len = len;
+    s->t38_fe.hdlc_tx.ptr = 0;
 }
 /*- End of function --------------------------------------------------------*/
 
diff --git a/libs/spandsp/src/time_scale.c b/libs/spandsp/src/time_scale.c
index 6006333674..2378b4f1c8 100644
--- a/libs/spandsp/src/time_scale.c
+++ b/libs/spandsp/src/time_scale.c
@@ -190,12 +190,12 @@ SPAN_DECLARE(int) time_scale(time_scale_state_t *s, int16_t out[], int16_t in[],
     if (s->fill + len < s->buf_len)
     {
         /* Cannot continue without more samples */
-        memcpy(s->buf + s->fill, in, sizeof(int16_t)*len);
+        memcpy(&s->buf[s->fill], in, sizeof(int16_t)*len);
         s->fill += len;
         return out_len;
     }
     k = s->buf_len - s->fill;
-    memcpy(s->buf + s->fill, in, sizeof(int16_t)*k);
+    memcpy(&s->buf[s->fill], in, sizeof(int16_t)*k);
     in_len += k;
     s->fill = s->buf_len;
     while (s->fill == s->buf_len)
@@ -207,12 +207,12 @@ SPAN_DECLARE(int) time_scale(time_scale_state_t *s, int16_t out[], int16_t in[],
             if (len - in_len < s->buf_len)
             {
                 /* Cannot continue without more samples */
-                memcpy(s->buf, in + in_len, sizeof(int16_t)*(len - in_len));
+                memcpy(s->buf, &in[in_len], sizeof(int16_t)*(len - in_len));
                 s->fill = len - in_len;
                 s->lcp -= s->buf_len;
                 return out_len;
             }
-            memcpy(s->buf, in + in_len, sizeof(int16_t)*s->buf_len);
+            memcpy(s->buf, &in[in_len], sizeof(int16_t)*s->buf_len);
             in_len += s->buf_len;
             s->lcp -= s->buf_len;
         }
@@ -220,16 +220,16 @@ SPAN_DECLARE(int) time_scale(time_scale_state_t *s, int16_t out[], int16_t in[],
         {
             memcpy(&out[out_len], s->buf, sizeof(int16_t)*s->lcp);
             out_len += s->lcp;
-            memcpy(s->buf, s->buf + s->lcp, sizeof(int16_t)*(s->buf_len - s->lcp));
+            memcpy(s->buf, &s->buf[s->lcp], sizeof(int16_t)*(s->buf_len - s->lcp));
             if (len - in_len < s->lcp)
             {
                 /* Cannot continue without more samples */
-                memcpy(s->buf + (s->buf_len - s->lcp), in + in_len, sizeof(int16_t)*(len - in_len));
+                memcpy(&s->buf[s->buf_len - s->lcp], &in[in_len], sizeof(int16_t)*(len - in_len));
                 s->fill = s->buf_len - s->lcp + len - in_len;
                 s->lcp = 0;
                 return out_len;
             }
-            memcpy(s->buf + (s->buf_len - s->lcp), in + in_len, sizeof(int16_t)*s->lcp);
+            memcpy(&s->buf[s->buf_len - s->lcp], &in[in_len], sizeof(int16_t)*s->lcp);
             in_len += s->lcp;
             s->lcp = 0;
         }
@@ -263,11 +263,11 @@ SPAN_DECLARE(int) time_scale(time_scale_state_t *s, int16_t out[], int16_t in[],
                 if (len - in_len < pitch)
                 {
                     /* Cannot continue without more samples */
-                    memcpy(s->buf + s->buf_len - pitch, in + in_len, sizeof(int16_t)*(len - in_len));
+                    memcpy(&s->buf[s->buf_len - pitch], &in[in_len], sizeof(int16_t)*(len - in_len));
                     s->fill += (len - in_len - pitch);
                     return out_len;
                 }
-                memcpy(s->buf + s->buf_len - pitch, in + in_len, sizeof(int16_t)*pitch);
+                memcpy(&s->buf[s->buf_len - pitch], &in[in_len], sizeof(int16_t)*pitch);
                 in_len += pitch;
             }
             else
diff --git a/libs/spandsp/src/v42.c b/libs/spandsp/src/v42.c
index fb54fa5b39..806f7aa212 100644
--- a/libs/spandsp/src/v42.c
+++ b/libs/spandsp/src/v42.c
@@ -238,7 +238,7 @@ static int tx_unnumbered_frame(lapm_state_t *s, uint8_t addr, uint8_t ctrl, uint
     f->len = 2;
     if (info  &&  len)
     {
-        memcpy(buf + f->len, info, len);
+        memcpy(&buf[f->len], info, len);
         f->len += len;
     }
     return 0;
diff --git a/libs/spandsp/tests/fax_decode.c b/libs/spandsp/tests/fax_decode.c
index 9fedc23c66..12cc11bb92 100644
--- a/libs/spandsp/tests/fax_decode.c
+++ b/libs/spandsp/tests/fax_decode.c
@@ -211,12 +211,24 @@ static int check_rx_dcs(const uint8_t *msg, int len)
     }
 
     octets_per_ecm_frame = (dcs_frame[6] & DISBIT4)  ?  256  :  64;
+
     if ((dcs_frame[8] & DISBIT1))
         y_resolution = T4_Y_RESOLUTION_SUPERFINE;
     else if (dcs_frame[4] & DISBIT7)
         y_resolution = T4_Y_RESOLUTION_FINE;
     else
         y_resolution = T4_Y_RESOLUTION_STANDARD;
+
+    if ((dcs_frame[8] & DISBIT3))
+    {
+        x_resolution = T4_X_RESOLUTION_R16;
+        y_resolution = T4_Y_RESOLUTION_SUPERFINE;
+    }
+    else
+    {
+        x_resolution = T4_X_RESOLUTION_R8;
+    }
+
     image_width = widths[(dcs_frame[8] & DISBIT3)  ?  2  :  1][dcs_frame[5] & (DISBIT2 | DISBIT1)];
 
     /* Check which compression we will use. */
@@ -344,9 +356,9 @@ static void v21_put_bit(void *user_data, int bit)
         }
         return;
     }
+    fprintf(stderr, "V.21 Rx bit %d - %d\n", rx_bits++, bit);
     if (fast_trained == FAX_NONE)
         hdlc_rx_put_bit(&hdlcrx, bit);
-    //printf("V.21 Rx bit %d - %d\n", rx_bits++, bit);
 }
 /*- End of function --------------------------------------------------------*/
 
@@ -501,8 +513,10 @@ int main(int argc, char *argv[])
     }
 
     memset(&t30_dummy, 0, sizeof(t30_dummy));
-    span_log_init(&t30_dummy.logging, SPAN_LOG_FLOW, NULL);
-    span_log_set_protocol(&t30_dummy.logging, "T.30");
+    logging = t30_get_logging_state(&t30_dummy);
+    span_log_init(logging, SPAN_LOG_NONE, NULL);
+    span_log_set_protocol(logging, "T.30");
+    span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
 
     hdlc_rx_init(&hdlcrx, false, true, 5, hdlc_accept, NULL);
     fsk = fsk_rx_init(NULL, &preset_fsk_specs[FSK_V21CH2], FSK_FRAME_MODE_SYNC, v21_put_bit, NULL);
@@ -520,24 +534,20 @@ int main(int argc, char *argv[])
 
 #if 1
     logging = v17_rx_get_logging_state(v17);
-    span_log_init(logging, SPAN_LOG_FLOW, NULL);
     span_log_set_protocol(logging, "V.17");
-    span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW);
+    span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
 
     logging = v29_rx_get_logging_state(v29);
-    span_log_init(logging, SPAN_LOG_FLOW, NULL);
     span_log_set_protocol(logging, "V.29");
-    span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW);
+    span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
 
     logging = v27ter_rx_get_logging_state(v27ter_4800);
-    span_log_init(logging, SPAN_LOG_FLOW, NULL);
     span_log_set_protocol(logging, "V.27ter-4800");
-    span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW);
+    span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
 
     logging = v27ter_rx_get_logging_state(v27ter_2400);
-    span_log_init(logging, SPAN_LOG_FLOW, NULL);
     span_log_set_protocol(logging, "V.27ter-2400");
-    span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW);
+    span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
 #endif
 
     if (t4_rx_init(&t4_rx_state, "fax_decode.tif", T4_COMPRESSION_T4_2D) == NULL)
@@ -556,6 +566,17 @@ int main(int argc, char *argv[])
         v29_rx(v29, amp, len);
         v27ter_rx(v27ter_4800, amp, len);
         v27ter_rx(v27ter_2400, amp, len);
+
+        logging = t30_get_logging_state(&t30_dummy);
+        span_log_bump_samples(logging, len);
+        logging = v17_rx_get_logging_state(v17);
+        span_log_bump_samples(logging, len);
+        logging = v29_rx_get_logging_state(v29);
+        span_log_bump_samples(logging, len);
+        logging = v27ter_rx_get_logging_state(v27ter_4800);
+        span_log_bump_samples(logging, len);
+        logging = v27ter_rx_get_logging_state(v27ter_2400);
+        span_log_bump_samples(logging, len);
     }
     t4_rx_release(&t4_rx_state);
 
diff --git a/libs/spandsp/tests/fax_tester.c b/libs/spandsp/tests/fax_tester.c
index df6aeeaf60..4cd85d68a7 100644
--- a/libs/spandsp/tests/fax_tester.c
+++ b/libs/spandsp/tests/fax_tester.c
@@ -112,7 +112,7 @@ static void hdlc_underflow_handler(void *user_data)
             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);
+            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);
diff --git a/libs/spandsp/tests/power_meter_tests.c b/libs/spandsp/tests/power_meter_tests.c
index da04372778..518fa3a694 100644
--- a/libs/spandsp/tests/power_meter_tests.c
+++ b/libs/spandsp/tests/power_meter_tests.c
@@ -168,7 +168,7 @@ static int power_surge_detector_file_test(const char *file)
 
     if ((inhandle = sf_open_telephony_read(file, 1)) == NULL)
     {
-        printf("    Cannot open audio file '%s'\n", file);
+        fprintf(stderr, "    Cannot open audio file '%s'\n", file);
         exit(2);
     }
 
diff --git a/libs/spandsp/tests/t43_tests.c b/libs/spandsp/tests/t43_tests.c
index 76946b94b3..bc9242d044 100644
--- a/libs/spandsp/tests/t43_tests.c
+++ b/libs/spandsp/tests/t43_tests.c
@@ -68,7 +68,7 @@ typedef struct
 static const TIFFFieldInfo tiff_fx_tiff_field_info[] =
 {
     {TIFFTAG_INDEXED, 1, 1, TIFF_SHORT, FIELD_CUSTOM, false, false, (char *) "Indexed"},
-	{TIFFTAG_GLOBALPARAMETERSIFD, 1, 1, TIFF_IFD8, FIELD_CUSTOM, false, false, (char *) "GlobalParametersIFD"},
+    {TIFFTAG_GLOBALPARAMETERSIFD, 1, 1, TIFF_IFD8, FIELD_CUSTOM, false, false, (char *) "GlobalParametersIFD"},
     {TIFFTAG_PROFILETYPE, 1, 1, TIFF_LONG, FIELD_CUSTOM, false, false, (char *) "ProfileType"},
     {TIFFTAG_FAXPROFILE, 1, 1, TIFF_BYTE, FIELD_CUSTOM, false, false, (char *) "FaxProfile"},
     {TIFFTAG_CODINGMETHODS, 1, 1, TIFF_LONG, FIELD_CUSTOM, false, false, (char *) "CodingMethods"},
@@ -86,7 +86,7 @@ static TIFFFieldArray tifffxFieldArray;
 static TIFFField tiff_fx_tiff_fields[] =
 {
     { TIFFTAG_INDEXED, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "Indexed" },
-	{ TIFFTAG_GLOBALPARAMETERSIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, (char *) "GlobalParametersIFD", &tifffxFieldArray },
+    { TIFFTAG_GLOBALPARAMETERSIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, (char *) "GlobalParametersIFD", &tifffxFieldArray },
     { TIFFTAG_PROFILETYPE, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "ProfileType", NULL },
     { TIFFTAG_FAXPROFILE, 1, 1, TIFF_BYTE, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "FaxProfile", NULL },
     { TIFFTAG_CODINGMETHODS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "CodingMethods", NULL },
diff --git a/libs/spandsp/tests/tsb85_extra_tests.sh b/libs/spandsp/tests/tsb85_extra_tests.sh
index 8aa3b24740..08d8336eee 100755
--- a/libs/spandsp/tests/tsb85_extra_tests.sh
+++ b/libs/spandsp/tests/tsb85_extra_tests.sh
@@ -28,7 +28,7 @@ run_tsb85_test()
     fi
 }
 
-for TEST in PPS-MPS-lost-PPS V17-12000-V29-9600
+for TEST in PPS-MPS-lost-PPS V17-12000-V29-9600 Phase-D-collision
 do
     run_tsb85_test
 done
diff --git a/libs/spandsp/tests/tsb85_tests.c b/libs/spandsp/tests/tsb85_tests.c
index 221c70634b..f383eb8f47 100644
--- a/libs/spandsp/tests/tsb85_tests.c
+++ b/libs/spandsp/tests/tsb85_tests.c
@@ -299,7 +299,7 @@ static int document_handler(void *user_data, int event)
 
     ch = 'A';
     s = (t30_state_t *) user_data;
-    fprintf(stderr, "%d: Document handler on channel %d - event %d\n", ch, ch, event);
+    fprintf(stderr, "%c: Document handler on channel %c - event %d\n", ch, ch, event);
     if (next_tx_file[0])
     {
         t30_set_tx_file(s, next_tx_file, -1, -1);