git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@9493 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Anthony Minessale committed 2008-09-09 17:04:42 +00:00
1 parent bc5cf34915
commit ea964d8fe6
79 files changed
+2804 -1642

No files matched your search

+2 -1
View File
@@ -16,7 +16,7 @@
## License along with this program; if not, write to the Free Software
## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
##
## $Id: Makefile.am,v 1.100 2008/08/14 14:06:05 steveu Exp $
## $Id: Makefile.am,v 1.101 2008/09/08 12:45:02 steveu Exp $
AM_CFLAGS = $(COMP_VENDOR_CFLAGS)
AM_LDFLAGS = $(COMP_VENDOR_LDFLAGS)
@@ -120,6 +120,7 @@ nobase_include_HEADERS = spandsp/adsi.h \
spandsp/complex.h \
spandsp/complex_filters.h \
spandsp/complex_vector_float.h \
spandsp/complex_vector_int.h \
spandsp/dc_restore.h \
spandsp/dds.h \
spandsp/dtmf.h \
+7 -8
View File
@@ -23,7 +23,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: adsi.c,v 1.59 2008/07/02 14:48:25 steveu Exp $
* $Id: adsi.c,v 1.60 2008/09/07 12:45:16 steveu Exp $
*/
/*! \file */
@@ -134,7 +134,7 @@ static int adsi_tx_get_bit(void *user_data)
}
else
{
bit = PUTBIT_END_OF_DATA;
bit = SIG_STATUS_END_OF_DATA;
if (s->tx_signal_on)
{
/* The FSK should now be switched off. */
@@ -176,7 +176,7 @@ static void adsi_rx_put_bit(void *user_data, int bit)
/* Special conditions */
switch (bit)
{
case PUTBIT_CARRIER_UP:
case SIG_STATUS_CARRIER_UP:
span_log(&s->logging, SPAN_LOG_FLOW, "Carrier up.\n");
s->consecutive_ones = 0;
s->bit_pos = 0;
@@ -184,7 +184,7 @@ static void adsi_rx_put_bit(void *user_data, int bit)
s->msg_len = 0;
s->baudot_shift = 0;
break;
case PUTBIT_CARRIER_DOWN:
case SIG_STATUS_CARRIER_DOWN:
span_log(&s->logging, SPAN_LOG_FLOW, "Carrier down.\n");
break;
default:
@@ -297,18 +297,17 @@ static void adsi_tdd_put_async_byte(void *user_data, int byte)
if (byte < 0)
{
/* Special conditions */
printf("Status is %s (%d)\n", signal_status_to_str(byte), byte);
switch (byte)
{
case PUTBIT_CARRIER_UP:
span_log(&s->logging, SPAN_LOG_FLOW, "Carrier up.\n");
case SIG_STATUS_CARRIER_UP:
s->consecutive_ones = 0;
s->bit_pos = 0;
s->in_progress = 0;
s->msg_len = 0;
s->baudot_shift = 0;
break;
case PUTBIT_CARRIER_DOWN:
span_log(&s->logging, SPAN_LOG_FLOW, "Carrier down.\n");
case SIG_STATUS_CARRIER_DOWN:
if (s->msg_len > 0)
{
/* Whatever we have to date constitutes the message */
+39 -8
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: async.c,v 1.11 2008/05/13 13:17:21 steveu Exp $
* $Id: async.c,v 1.13 2008/09/07 12:45:16 steveu Exp $
*/
/*! \file */
@@ -39,6 +39,37 @@
#include "spandsp/telephony.h"
#include "spandsp/async.h"
const char *signal_status_to_str(int status)
{
switch (status)
{
case SIG_STATUS_CARRIER_DOWN:
return "Carrier down";
case SIG_STATUS_CARRIER_UP:
return "Carrier up";
case SIG_STATUS_TRAINING_IN_PROGRESS:
return "Training in progress";
case SIG_STATUS_TRAINING_SUCCEEDED:
return "Training succeeded";
case SIG_STATUS_TRAINING_FAILED:
return "Training failed";
case SIG_STATUS_FRAMING_OK:
return "Framing OK";
case SIG_STATUS_END_OF_DATA:
return "End of data";
case SIG_STATUS_ABORT:
return "Abort";
case SIG_STATUS_BREAK:
return "Break";
case SIG_STATUS_SHUTDOWN_COMPLETE:
return "Shutdown complete";
case SIG_STATUS_OCTET_REPORT:
return "Octet report";
}
return "???";
}
/*- End of function --------------------------------------------------------*/
async_rx_state_t *async_rx_init(async_rx_state_t *s,
int data_bits,
int parity,
@@ -80,12 +111,12 @@ void async_rx_put_bit(void *user_data, int bit)
/* Special conditions */
switch (bit)
{
case PUTBIT_CARRIER_UP:
case PUTBIT_CARRIER_DOWN:
case PUTBIT_TRAINING_IN_PROGRESS:
case PUTBIT_TRAINING_SUCCEEDED:
case PUTBIT_TRAINING_FAILED:
case PUTBIT_END_OF_DATA:
case SIG_STATUS_CARRIER_UP:
case SIG_STATUS_CARRIER_DOWN:
case SIG_STATUS_TRAINING_IN_PROGRESS:
case SIG_STATUS_TRAINING_SUCCEEDED:
case SIG_STATUS_TRAINING_FAILED:
case SIG_STATUS_END_OF_DATA:
s->put_byte(s->user_data, bit);
s->bitpos = 0;
s->byte_in_progress = 0;
@@ -194,7 +225,7 @@ int async_tx_get_bit(void *user_data)
if ((s->byte_in_progress = s->get_byte(s->user_data)) < 0)
{
/* No more data */
bit = PUTBIT_END_OF_DATA;
bit = SIG_STATUS_END_OF_DATA;
}
else
{
+3 -23
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: bert.c,v 1.27 2008/05/13 13:17:22 steveu Exp $
* $Id: bert.c,v 1.28 2008/09/07 12:45:16 steveu Exp $
*/
#if defined(HAVE_CONFIG_H)
@@ -78,7 +78,7 @@ int bert_get_bit(bert_state_t *s)
int bit;
if (s->limit && s->tx_bits >= s->limit)
return PUTBIT_END_OF_DATA;
return SIG_STATUS_END_OF_DATA;
bit = 0;
switch (s->pattern_class)
{
@@ -185,27 +185,7 @@ void bert_put_bit(bert_state_t *s, int bit)
if (bit < 0)
{
/* Special conditions */
switch (bit)
{
case PUTBIT_TRAINING_IN_PROGRESS:
span_log(&s->logging, SPAN_LOG_FLOW, "Training in progress\n");
break;
case PUTBIT_TRAINING_FAILED:
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed\n");
break;
case PUTBIT_TRAINING_SUCCEEDED:
span_log(&s->logging, SPAN_LOG_FLOW, "Training succeeded\n");
break;
case PUTBIT_CARRIER_UP:
span_log(&s->logging, SPAN_LOG_FLOW, "Carrier up\n");
break;
case PUTBIT_CARRIER_DOWN:
span_log(&s->logging, SPAN_LOG_FLOW, "Carrier down\n");
break;
default:
span_log(&s->logging, SPAN_LOG_FLOW, "Eh!\n");
break;
}
printf("Status is %s (%d)\n", signal_status_to_str(bit), bit);
return;
}
bit = (bit & 1) ^ s->invert;
+55 -1
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: dds_int.c,v 1.9 2008/07/02 14:48:25 steveu Exp $
* $Id: dds_int.c,v 1.10 2008/09/01 16:07:33 steveu Exp $
*/
/*! \file */
@@ -288,4 +288,58 @@ complexi_t dds_complexi_mod(uint32_t *phase_acc, int32_t phase_rate, int scale,
return amp;
}
/*- End of function --------------------------------------------------------*/
complexi16_t dds_lookup_complexi16(uint32_t phase)
{
return complex_seti16(dds_lookup(phase + (1 << 30)), dds_lookup(phase));
}
/*- End of function --------------------------------------------------------*/
complexi16_t dds_complexi16(uint32_t *phase_acc, int32_t phase_rate)
{
complexi16_t amp;
amp = complex_seti16(dds_lookup(*phase_acc + (1 << 30)), dds_lookup(*phase_acc));
*phase_acc += phase_rate;
return amp;
}
/*- End of function --------------------------------------------------------*/
complexi16_t dds_complexi16_mod(uint32_t *phase_acc, int32_t phase_rate, int scale, int32_t phase)
{
complexi16_t amp;
amp = complex_seti16((dds_lookup(*phase_acc + phase + (1 << 30))*scale) >> 15,
(dds_lookup(*phase_acc + phase)*scale) >> 15);
*phase_acc += phase_rate;
return amp;
}
/*- End of function --------------------------------------------------------*/
complexi32_t dds_lookup_complexi32(uint32_t phase)
{
return complex_seti32(dds_lookup(phase + (1 << 30)), dds_lookup(phase));
}
/*- End of function --------------------------------------------------------*/
complexi32_t dds_complexi32(uint32_t *phase_acc, int32_t phase_rate)
{
complexi32_t amp;
amp = complex_seti32(dds_lookup(*phase_acc + (1 << 30)), dds_lookup(*phase_acc));
*phase_acc += phase_rate;
return amp;
}
/*- End of function --------------------------------------------------------*/
complexi32_t dds_complexi32_mod(uint32_t *phase_acc, int32_t phase_rate, int scale, int32_t phase)
{
complexi32_t amp;
amp = complex_seti32((dds_lookup(*phase_acc + phase + (1 << 30))*scale) >> 15,
(dds_lookup(*phase_acc + phase)*scale) >> 15);
*phase_acc += phase_rate;
return amp;
}
/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/
+6 -6
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: fsk.c,v 1.44 2008/07/16 17:01:49 steveu Exp $
* $Id: fsk.c,v 1.46 2008/09/07 12:45:16 steveu Exp $
*/
/*! \file */
@@ -163,12 +163,12 @@ int fsk_tx(fsk_tx_state_t *s, int16_t *amp, int len)
if ((s->baud_frac += s->baud_inc) >= SAMPLE_RATE*100)
{
s->baud_frac -= SAMPLE_RATE*100;
if ((bit = s->get_bit(s->get_bit_user_data)) == PUTBIT_END_OF_DATA)
if ((bit = s->get_bit(s->get_bit_user_data)) == SIG_STATUS_END_OF_DATA)
{
if (s->status_handler)
s->status_handler(s->status_user_data, MODEM_TX_STATUS_DATA_EXHAUSTED);
s->status_handler(s->status_user_data, SIG_STATUS_END_OF_DATA);
if (s->status_handler)
s->status_handler(s->status_user_data, MODEM_TX_STATUS_SHUTDOWN_COMPLETE);
s->status_handler(s->status_user_data, SIG_STATUS_SHUTDOWN_COMPLETE);
s->shutdown = TRUE;
break;
}
@@ -329,7 +329,7 @@ int fsk_rx(fsk_rx_state_t *s, const int16_t *amp, int len)
{
/* Count down a short delay, to ensure we push the last
few bits through the filters before stopping. */
report_status_change(s, PUTBIT_CARRIER_DOWN);
report_status_change(s, SIG_STATUS_CARRIER_DOWN);
continue;
}
}
@@ -340,7 +340,7 @@ int fsk_rx(fsk_rx_state_t *s, const int16_t *amp, int len)
if (power < s->carrier_on_power)
continue;
s->signal_present = 1;
report_status_change(s, PUTBIT_CARRIER_UP);
report_status_change(s, SIG_STATUS_CARRIER_UP);
}
/* Non-coherent FSK demodulation by correlation with the target tones
over a one baud interval. The slow V.xx specs. are too open ended
+2 -1
View File
@@ -25,7 +25,7 @@
* This code is based on the widely used GSM 06.10 code available from
* http://kbs.cs.tu-berlin.de/~jutta/toast.html
*
* $Id: gsm0610_lpc.c,v 1.20 2008/07/02 14:48:25 steveu Exp $
* $Id: gsm0610_lpc.c,v 1.21 2008/09/04 14:40:05 steveu Exp $
*/
/*! \file */
@@ -44,6 +44,7 @@
#include <math.h>
#endif
#include <stdlib.h>
#include <memory.h>
#include "spandsp/telephony.h"
#include "spandsp/bitstream.h"
+13 -13
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: hdlc.c,v 1.60 2008/05/13 13:17:22 steveu Exp $
* $Id: hdlc.c,v 1.61 2008/09/07 12:45:16 steveu Exp $
*/
/*! \file */
@@ -47,8 +47,8 @@ static void rx_special_condition(hdlc_rx_state_t *s, int condition)
/* Special conditions */
switch (condition)
{
case PUTBIT_CARRIER_UP:
case PUTBIT_TRAINING_SUCCEEDED:
case SIG_STATUS_CARRIER_UP:
case SIG_STATUS_TRAINING_SUCCEEDED:
/* Reset the HDLC receiver. */
s->raw_bit_stream = 0;
s->len = 0;
@@ -56,10 +56,10 @@ static void rx_special_condition(hdlc_rx_state_t *s, int condition)
s->flags_seen = 0;
s->framing_ok_announced = FALSE;
/* Fall through */
case PUTBIT_TRAINING_IN_PROGRESS:
case PUTBIT_TRAINING_FAILED:
case PUTBIT_CARRIER_DOWN:
case PUTBIT_END_OF_DATA:
case SIG_STATUS_TRAINING_IN_PROGRESS:
case SIG_STATUS_TRAINING_FAILED:
case SIG_STATUS_CARRIER_DOWN:
case SIG_STATUS_END_OF_DATA:
s->frame_handler(s->user_data, NULL, condition, TRUE);
break;
default:
@@ -81,7 +81,7 @@ static __inline__ void octet_set_and_count(hdlc_rx_state_t *s)
if (--s->octet_count <= 0)
{
s->octet_count = s->octet_count_report_interval;
s->frame_handler(s->user_data, NULL, PUTBIT_OCTET_REPORT, TRUE);
s->frame_handler(s->user_data, NULL, SIG_STATUS_OCTET_REPORT, TRUE);
}
}
else
@@ -104,7 +104,7 @@ static __inline__ void octet_count(hdlc_rx_state_t *s)
if (--s->octet_count <= 0)
{
s->octet_count = s->octet_count_report_interval;
s->frame_handler(s->user_data, NULL, PUTBIT_OCTET_REPORT, TRUE);
s->frame_handler(s->user_data, NULL, SIG_STATUS_OCTET_REPORT, TRUE);
}
}
}
@@ -116,7 +116,7 @@ static void rx_flag_or_abort(hdlc_rx_state_t *s)
{
/* Hit HDLC abort */
s->rx_aborts++;
s->frame_handler(s->user_data, NULL, PUTBIT_ABORT, TRUE);
s->frame_handler(s->user_data, NULL, SIG_STATUS_ABORT, TRUE);
/* If we have not yet seen enough flags, restart the count. If we
are beyond that point, just back off one step, so we need to see
another flag before proceeding to collect frame octets. */
@@ -184,7 +184,7 @@ static void rx_flag_or_abort(hdlc_rx_state_t *s)
s->flags_seen = 0;
if (++s->flags_seen >= s->framing_ok_threshold && !s->framing_ok_announced)
{
s->frame_handler(s->user_data, NULL, PUTBIT_FRAMING_OK, TRUE);
s->frame_handler(s->user_data, NULL, SIG_STATUS_FRAMING_OK, TRUE);
s->framing_ok_announced = TRUE;
}
}
@@ -493,7 +493,7 @@ int hdlc_tx_get_byte(hdlc_tx_state_t *s)
if (s->tx_end)
{
s->tx_end = FALSE;
return PUTBIT_END_OF_DATA;
return SIG_STATUS_END_OF_DATA;
}
return s->idle_octet;
}
@@ -522,7 +522,7 @@ int hdlc_tx_get(hdlc_tx_state_t *s, uint8_t buf[], size_t max_len)
for (i = 0; i < max_len; i++)
{
if ((x = hdlc_tx_get_byte(s)) == PUTBIT_END_OF_DATA)
if ((x = hdlc_tx_get_byte(s)) == SIG_STATUS_END_OF_DATA)
return i;
buf[i] = x;
}
+4
View File
@@ -459,6 +459,10 @@ SOURCE=.\spandsp/complex_vector_float.h
# End Source File
# Begin Source File
SOURCE=.\spandsp/complex_vector_int.h
# End Source File
# Begin Source File
SOURCE=.\spandsp/dc_restore.h
# End Source File
# Begin Source File
+3 -3
View File
@@ -23,7 +23,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: modem_connect_tones.c,v 1.27 2008/08/13 14:55:51 steveu Exp $
* $Id: modem_connect_tones.c,v 1.28 2008/09/07 12:45:16 steveu Exp $
*/
/*! \file */
@@ -284,12 +284,12 @@ static void v21_put_bit(void *user_data, int bit)
/* Special conditions. */
switch (bit)
{
case PUTBIT_CARRIER_DOWN:
case SIG_STATUS_CARRIER_DOWN:
/* Only declare tone off, if we were the one to declare tone on. */
if (s->tone_present == MODEM_CONNECT_TONES_FAX_PREAMBLE)
report_tone_state(s, MODEM_CONNECT_TONES_NONE, -99);
/* Fall through */
case PUTBIT_CARRIER_UP:
case SIG_STATUS_CARRIER_UP:
s->raw_bit_stream = 0;
s->num_bits = 0;
s->flags_seen = 0;
+2 -1
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: queue.c,v 1.22 2008/05/15 14:26:30 steveu Exp $
* $Id: queue.c,v 1.23 2008/09/09 16:25:51 steveu Exp $
*/
/*! \file */
@@ -39,6 +39,7 @@
#include <inttypes.h>
#include <sys/types.h>
#define FULLY_DEFINE_QUEUE_STATE_T
#include "spandsp/queue.h"
int queue_empty(queue_state_t *s)
+2 -2
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: silence_gen.c,v 1.14 2008/07/26 04:53:00 steveu Exp $
* $Id: silence_gen.c,v 1.16 2008/09/07 12:45:16 steveu Exp $
*/
/*! \file */
@@ -59,7 +59,7 @@ int silence_gen(silence_gen_state_t *s, int16_t *amp, int max_len)
{
max_len = s->remaining_samples;
if (max_len && s->status_handler)
s->status_handler(s->status_user_data, MODEM_TX_STATUS_SHUTDOWN_COMPLETE);
s->status_handler(s->status_user_data, SIG_STATUS_SHUTDOWN_COMPLETE);
}
s->remaining_samples -= max_len;
}
+2 -1
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: spandsp.h.in,v 1.9 2008/08/14 14:06:05 steveu Exp $
* $Id: spandsp.h.in,v 1.10 2008/09/01 16:07:34 steveu Exp $
*/
/*! \file */
@@ -53,6 +53,7 @@
#include <spandsp/vector_float.h>
#include <spandsp/complex_vector_float.h>
#include <spandsp/vector_int.h>
#include <spandsp/complex_vector_int.h>
#include <spandsp/arctan2.h>
#include <spandsp/biquad.h>
#include <spandsp/fir.h>
+25 -25
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: async.h,v 1.16 2008/07/17 14:27:11 steveu Exp $
* $Id: async.h,v 1.18 2008/09/07 12:45:17 steveu Exp $
*/
/*! \file */
@@ -49,42 +49,36 @@ and decoding must occur before data is fed to this module.
#if !defined(_SPANDSP_ASYNC_H_)
#define _SPANDSP_ASYNC_H_
/*! Special "bit" values for the put and get bit functions */
/*! Special "bit" values for the bitstream put and get functions, and the signal status functions. */
enum
{
/*! \brief The carrier signal has dropped. */
PUTBIT_CARRIER_DOWN = -1,
SIG_STATUS_CARRIER_DOWN = -1,
/*! \brief The carrier signal is up. This merely indicates that carrier
energy has been seen. It is not an indication that the carrier is either
valid, or of the expected type. */
PUTBIT_CARRIER_UP = -2,
SIG_STATUS_CARRIER_UP = -2,
/*! \brief The modem is training. This is an early indication that the
signal seems to be of the right type. This may be needed in time critical
applications, like T.38, to forward an early indication of what is happening
on the wire. */
PUTBIT_TRAINING_IN_PROGRESS = -3,
SIG_STATUS_TRAINING_IN_PROGRESS = -3,
/*! \brief The modem has trained, and is ready for data exchange. */
PUTBIT_TRAINING_SUCCEEDED = -4,
SIG_STATUS_TRAINING_SUCCEEDED = -4,
/*! \brief The modem has failed to train. */
PUTBIT_TRAINING_FAILED = -5,
SIG_STATUS_TRAINING_FAILED = -5,
/*! \brief Packet framing (e.g. HDLC framing) is OK. */
PUTBIT_FRAMING_OK = -6,
SIG_STATUS_FRAMING_OK = -6,
/*! \brief The data stream has ended. */
PUTBIT_END_OF_DATA = -7,
SIG_STATUS_END_OF_DATA = -7,
/*! \brief An abort signal (e.g. an HDLC abort) has been received. */
PUTBIT_ABORT = -8,
SIG_STATUS_ABORT = -8,
/*! \brief A break signal (e.g. an async break) has been received. */
PUTBIT_BREAK = -9,
SIG_STATUS_BREAK = -9,
/*! \brief A modem has completed its task, and shut down. */
SIG_STATUS_SHUTDOWN_COMPLETE = -10,
/*! \brief Regular octet report for things like HDLC to the MTP standards. */
PUTBIT_OCTET_REPORT = -10
};
enum
{
/*! \brief The data source for a transmitter is exhausted. */
MODEM_TX_STATUS_DATA_EXHAUSTED = -1,
/*! \brief The transmitter has completed its task, and shut down. */
MODEM_TX_STATUS_SHUTDOWN_COMPLETE = -2
SIG_STATUS_OCTET_REPORT = -11
};
/*! Message put function for data pumps */
@@ -185,6 +179,12 @@ extern "C"
{
#endif
/*! Convert a signal status to a short text description.
\brief Convert a signal status to a short text description.
\param status The modem signal status.
\return A pointer to the description. */
const char *signal_status_to_str(int status);
/*! Initialise an asynchronous data transmit context.
\brief Initialise an asynchronous data transmit context.
\param s The transmitter context.
@@ -231,11 +231,11 @@ async_rx_state_t *async_rx_init(async_rx_state_t *s,
\brief Accept a bit from a received serial bit stream
\param user_data An opaque point which must point to a receiver context.
\param bit The new bit. Some special values are supported for this field.
- PUTBIT_CARRIER_UP
- PUTBIT_CARRIER_DOWN
- PUTBIT_TRAINING_SUCCEEDED
- PUTBIT_TRAINING_FAILED
- PUTBIT_END_OF_DATA */
- SIG_STATUS_CARRIER_UP
- SIG_STATUS_CARRIER_DOWN
- SIG_STATUS_TRAINING_SUCCEEDED
- SIG_STATUS_TRAINING_FAILED
- SIG_STATUS_END_OF_DATA */
void async_rx_put_bit(void *user_data, int bit);
#if defined(__cplusplus)
+72 -2
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: complex.h,v 1.16 2008/04/17 14:27:00 steveu Exp $
* $Id: complex.h,v 1.18 2008/09/03 13:41:42 steveu Exp $
*/
/*! \file */
@@ -329,6 +329,56 @@ static __inline__ complexl_t complex_mull(const complexl_t *x, const complexl_t
/*- End of function --------------------------------------------------------*/
#endif
static __inline__ complexi_t complex_muli(const complexi_t *x, const complexi_t *y)
{
complexi_t z;
z.re = x->re*y->re - x->im*y->im;
z.im = x->re*y->im + x->im*y->re;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complexi16_t complex_muli16(const complexi16_t *x, const complexi16_t *y)
{
complexi16_t z;
z.re = (int32_t) x->re*(int32_t) y->re - (int32_t) x->im*(int32_t) y->im;
z.im = (int32_t) x->re*(int32_t) y->im + (int32_t) x->im*(int32_t) y->re;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complexi16_t complex_mul_q1_15(const complexi16_t *x, const complexi16_t *y)
{
complexi16_t z;
z.re = ((int32_t) x->re*(int32_t) y->re - (int32_t) x->im*(int32_t) y->im) >> 15;
z.im = ((int32_t) x->re*(int32_t) y->im + (int32_t) x->im*(int32_t) y->re) >> 15;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complexi32_t complex_muli32i16(const complexi32_t *x, const complexi16_t *y)
{
complexi32_t z;
z.re = x->re*(int32_t) y->re - x->im*(int32_t) y->im;
z.im = x->re*(int32_t) y->im + x->im*(int32_t) y->re;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complexi32_t complex_muli32(const complexi32_t *x, const complexi32_t *y)
{
complexi32_t z;
z.re = x->re*y->re - x->im*y->im;
z.im = x->re*y->im + x->im*y->re;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complexf_t complex_divf(const complexf_t *x, const complexf_t *y)
{
complexf_t z;
@@ -399,7 +449,7 @@ static __inline__ complexl_t complex_conjl(const complexl_t *x)
/*- End of function --------------------------------------------------------*/
#endif
static __inline__ complexi_t complexi_conj(const complexi_t *x)
static __inline__ complexi_t complex_conji(const complexi_t *x)
{
complexi_t z;
@@ -409,6 +459,26 @@ static __inline__ complexi_t complexi_conj(const complexi_t *x)
}
/*- End of function --------------------------------------------------------*/
static __inline__ complexi16_t complex_conji16(const complexi16_t *x)
{
complexi16_t z;
z.re = x->re;
z.im = -x->im;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complexi32_t complex_conji32(const complexi32_t *x)
{
complexi32_t z;
z.re = x->re;
z.im = -x->im;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ float powerf(const complexf_t *x)
{
return x->re*x->re + x->im*x->im;
@@ -0,0 +1,104 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* complex_vector_int.h
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: complex_vector_int.h,v 1.1 2008/09/01 16:07:34 steveu Exp $
*/
#if !defined(_SPANDSP_COMPLEX_VECTOR_INT_H_)
#define _SPANDSP_COMPLEX_VECTOR_INT_H_
#if defined(__cplusplus)
extern "C"
{
#endif
static __inline__ void cvec_copyi(complexi_t z[], const complexi_t x[], int n)
{
memcpy(z, x, n*sizeof(z[0]));
}
/*- End of function --------------------------------------------------------*/
static __inline__ void cvec_copyi16(complexi16_t z[], const complexi16_t x[], int n)
{
memcpy(z, x, n*sizeof(z[0]));
}
/*- End of function --------------------------------------------------------*/
static __inline__ void cvec_copyi32(complexi32_t z[], const complexi32_t x[], int n)
{
memcpy(z, x, n*sizeof(z[0]));
}
/*- End of function --------------------------------------------------------*/
static __inline__ void cvec_zeroi(complexi_t z[], int n)
{
memset(z, 0, n*sizeof(z[0]));
}
/*- End of function --------------------------------------------------------*/
static __inline__ void cvec_zeroi16(complexi16_t z[], int n)
{
memset(z, 0, n*sizeof(z[0]));
}
/*- End of function --------------------------------------------------------*/
static __inline__ void cvec_zeroi32(complexi32_t z[], int n)
{
memset(z, 0, n*sizeof(z[0]));
}
/*- End of function --------------------------------------------------------*/
static __inline__ void cvec_seti(complexi_t z[], complexi_t *x, int n)
{
int i;
for (i = 0; i < n; i++)
z[i] = *x;
}
/*- End of function --------------------------------------------------------*/
static __inline__ void cvec_seti16(complexi16_t z[], complexi16_t *x, int n)
{
int i;
for (i = 0; i < n; i++)
z[i] = *x;
}
/*- End of function --------------------------------------------------------*/
static __inline__ void cvec_seti32(complexi32_t z[], complexi32_t *x, int n)
{
int i;
for (i = 0; i < n; i++)
z[i] = *x;
}
/*- End of function --------------------------------------------------------*/
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/
+62 -7
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: dds.h,v 1.18 2008/04/17 14:27:00 steveu Exp $
* $Id: dds.h,v 1.20 2008/09/04 14:40:05 steveu Exp $
*/
/*! \file */
@@ -100,6 +100,12 @@ int16_t dds_lookup(uint32_t phase);
*/
int16_t dds_mod(uint32_t *phase_acc, int32_t phase_rate, int scale, int32_t phase);
/*! \brief Lookup the complex integer value of a specified phase.
\param phase The phase accumulator value to be looked up.
\return The complex signal amplitude, between (-32767, -32767) and (32767, 32767).
*/
complexi_t dds_lookup_complexi(uint32_t phase);
/*! \brief Generate a complex integer tone sample.
\param phase_acc A pointer to a phase accumulator value.
\param phase_rate The phase increment to be applied.
@@ -107,12 +113,6 @@ int16_t dds_mod(uint32_t *phase_acc, int32_t phase_rate, int scale, int32_t phas
*/
complexi_t dds_complexi(uint32_t *phase_acc, int32_t phase_rate);
/*! \brief Lookup the complex integer value of a specified phase.
\param phase The phase accumulator value to be looked up.
\return The complex signal amplitude, between (-32767, -32767) and (32767, 32767).
*/
complexi_t dds_lookup_complexi(uint32_t phase);
/*! \brief Generate a complex integer tone sample, with modulation.
\param phase_acc A pointer to a phase accumulator value.
\param phase_rate The phase increment to be applied.
@@ -122,6 +122,61 @@ complexi_t dds_lookup_complexi(uint32_t phase);
*/
complexi_t dds_complexi_mod(uint32_t *phase_acc, int32_t phase_rate, int scale, int32_t phase);
/*! \brief Generate a complex 16 bit integer tone sample.
\param phase_acc A pointer to a phase accumulator value.
\param phase_rate The phase increment to be applied.
\return The complex signal amplitude, between (-32767, -32767) and (32767, 32767).
*/
complexi16_t dds_lookup_complexi16(uint32_t phase);
/*! \brief Generate a complex 16 bit integer tone sample.
\param phase_acc A pointer to a phase accumulator value.
\param phase_rate The phase increment to be applied.
\return The complex signal amplitude, between (-32767, -32767) and (32767, 32767).
*/
complexi16_t dds_complexi16(uint32_t *phase_acc, int32_t phase_rate);
/*! \brief Generate a complex 16bit integer tone sample, with modulation.
\param phase_acc A pointer to a phase accumulator value.
\param phase_rate The phase increment to be applied.
\param scale The scaling factor.
\param phase The phase offset.
\return The complex signal amplitude, between (-32767, -32767) and (32767, 32767).
*/
complexi16_t dds_complexi16_mod(uint32_t *phase_acc, int32_t phase_rate, int scale, int32_t phase);
/*! \brief Generate a complex 32 bit integer tone sample, with modulation.
\param phase_acc A pointer to a phase accumulator value.
\param phase_rate The phase increment to be applied.
\param scale The scaling factor.
\param phase The phase offset.
\return The complex signal amplitude, between (-32767, -32767) and (32767, 32767).
*/
complexi32_t dds_complexi32_mod(uint32_t *phase_acc, int32_t phase_rate, int scale, int32_t phase);
/*! \brief Generate a complex 32 bit integer tone sample.
\param phase_acc A pointer to a phase accumulator value.
\param phase_rate The phase increment to be applied.
\return The complex signal amplitude, between (-32767, -32767) and (32767, 32767).
*/
complexi32_t dds_lookup_complexi32(uint32_t phase);
/*! \brief Generate a complex 32 bit integer tone sample.
\param phase_acc A pointer to a phase accumulator value.
\param phase_rate The phase increment to be applied.
\return The complex signal amplitude, between (-32767, -32767) and (32767, 32767).
*/
complexi32_t dds_complexi32(uint32_t *phase_acc, int32_t phase_rate);
/*! \brief Generate a complex 32 bit integer tone sample, with modulation.
\param phase_acc A pointer to a phase accumulator value.
\param phase_rate The phase increment to be applied.
\param scale The scaling factor.
\param phase The phase offset.
\return The complex signal amplitude, between (-32767, -32767) and (32767, 32767).
*/
complexi32_t dds_complexi32_mod(uint32_t *phase_acc, int32_t phase_rate, int scale, int32_t phase);
/*! \brief Find the phase rate equivalent to a frequency, in Hz.
\param frequency The frequency, in Hz.
\return The equivalent phase rate.
+2 -2
View File
@@ -24,7 +24,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: echo.h,v 1.15 2008/08/29 10:02:47 steveu Exp $
* $Id: echo.h,v 1.16 2008/09/04 14:40:05 steveu Exp $
*/
/*! \file */
@@ -126,7 +126,7 @@ enum
ECHO_CAN_USE_SUPPRESSOR = 0x10,
ECHO_CAN_USE_TX_HPF = 0x20,
ECHO_CAN_USE_RX_HPF = 0x40,
ECHO_CAN_DISABLE = 0x80,
ECHO_CAN_DISABLE = 0x80
};
/*!
+2 -2
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: fsk.h,v 1.30 2008/07/16 14:23:48 steveu Exp $
* $Id: fsk.h,v 1.31 2008/09/04 14:40:05 steveu Exp $
*/
/*! \file */
@@ -111,7 +111,7 @@ enum
FSK_BELL103CH1,
FSK_BELL103CH2,
FSK_BELL202,
FSK_WEITBRECHT, /* Used for TDD (Telecom Device for the Deaf) */
FSK_WEITBRECHT /* Used for TDD (Telecom Device for the Deaf) */
};
extern const fsk_spec_t preset_fsk_specs[];
+3 -1
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: queue.h,v 1.16 2008/05/30 13:51:28 steveu Exp $
* $Id: queue.h,v 1.17 2008/09/09 16:25:51 steveu Exp $
*/
/*! \file */
@@ -63,8 +63,10 @@ typedef struct
volatile int iptr;
/*! \brief The buffer output pointer. */
volatile int optr;
#if defined(FULLY_DEFINE_QUEUE_STATE_T)
/*! \brief The data buffer, sized at the time the structure is created. */
uint8_t data[];
#endif
} queue_state_t;
#define QUEUE_STATE_T_SIZE(len) (sizeof(queue_state_t) + len + 1)
+2 -2
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t30.h,v 1.114 2008/08/13 00:11:30 steveu Exp $
* $Id: t30.h,v 1.115 2008/09/04 14:40:05 steveu Exp $
*/
/*! \file */
@@ -338,7 +338,7 @@ enum
T30_SUPPORT_V29 = 0x02,
T30_SUPPORT_V17 = 0x04,
T30_SUPPORT_V34 = 0x08,
T30_SUPPORT_IAF = 0x10,
T30_SUPPORT_IAF = 0x10
};
enum
+2 -2
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t38_core.h,v 1.28 2008/06/19 13:27:45 steveu Exp $
* $Id: t38_core.h,v 1.29 2008/09/04 14:40:05 steveu Exp $
*/
/*! \file */
@@ -142,7 +142,7 @@ enum t38_field_classes_e
{
T38_FIELD_CLASS_NONE = 0,
T38_FIELD_CLASS_HDLC,
T38_FIELD_CLASS_NON_ECM,
T38_FIELD_CLASS_NON_ECM
};
/*! T.38 message types */
+17 -1
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t38_gateway.h,v 1.56 2008/08/14 14:06:05 steveu Exp $
* $Id: t38_gateway.h,v 1.57 2008/09/02 13:56:10 steveu Exp $
*/
/*! \file */
@@ -125,6 +125,21 @@ typedef struct
typedef struct
{
/*! \brief HDLC message buffers. */
uint8_t buf[T38_MAX_HDLC_LEN];
/*! \brief HDLC message lengths. */
int len;
/*! \brief HDLC message status flags. */
int flags;
/*! \brief HDLC buffer contents. */
int contents;
} t38_gateway_hdlc_buf_t;
typedef struct
{
/*! \brief HDLC message buffers. */
t38_gateway_hdlc_buf_t buf[T38_TX_HDLC_BUFS];
#if 0
/*! \brief HDLC message buffers. */
uint8_t buf[T38_TX_HDLC_BUFS][T38_MAX_HDLC_LEN];
/*! \brief HDLC message lengths. */
@@ -133,6 +148,7 @@ typedef struct
int flags[T38_TX_HDLC_BUFS];
/*! \brief HDLC buffer contents. */
int contents[T38_TX_HDLC_BUFS];
#endif
/*! \brief HDLC buffer number for input. */
int in;
/*! \brief HDLC buffer number for output. */
+20 -5
View File
@@ -23,7 +23,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t38_non_ecm_buffer.h,v 1.1 2008/08/14 14:06:05 steveu Exp $
* $Id: t38_non_ecm_buffer.h,v 1.2 2008/09/02 13:56:10 steveu Exp $
*/
/*! \file */
@@ -83,10 +83,13 @@ typedef struct
/*! \brief The number of octets input to the buffer. */
int in_octets;
/*! \brief The number of octets output from the buffer. */
int out_octets;
/*! \brief The number of rows input to the buffer. */
int in_rows;
/*! \brief The number of non-ECM fill octets generated for minimum row bits
purposes. */
int min_row_bits_fill_octets;
/*! \brief The number of octets output from the buffer. */
int out_octets;
/*! \brief The number of rows output from the buffer. */
int out_rows;
/*! \brief The number of non-ECM fill octets generated for flow control
@@ -106,6 +109,12 @@ extern "C"
\return A pointer to the buffer context, or NULL if there was a problem. */
t38_non_ecm_buffer_state_t *t38_non_ecm_buffer_init(t38_non_ecm_buffer_state_t *s, int mode, int min_row_bits);
/*! \brief Set the mode of a T.38 rate adapting non-ECM buffer context.
\param s The buffer context.
\param mode TRUE for image data mode, or FALSE for TCF mode.
\param bits The minimum number of bits per FAX image row. */
void t38_non_ecm_buffer_set_mode(t38_non_ecm_buffer_state_t *s, int mode, int min_row_bits);
/*! \brief Inject data to T.38 rate adapting non-ECM buffer context.
\param s The buffer context.
\param buf The data buffer to be injected.
@@ -117,11 +126,17 @@ void t38_non_ecm_buffer_inject(t38_non_ecm_buffer_state_t *s, const uint8_t *buf
\param s The buffer context. */
void t38_non_ecm_buffer_push(t38_non_ecm_buffer_state_t *s);
/*! \brief Report the status of a T.38 rate adapting non-ECM buffer context to the specified
/*! \brief Report the input status of a T.38 rate adapting non-ECM buffer context to the specified
logging context.
\param s The buffer context.
\param logging The logging context. */
void t38_non_ecm_buffer_report_status(t38_non_ecm_buffer_state_t *s, logging_state_t *logging);
void t38_non_ecm_buffer_report_input_status(t38_non_ecm_buffer_state_t *s, logging_state_t *logging);
/*! \brief Report the output status of a T.38 rate adapting non-ECM buffer context to the specified
logging context.
\param s The buffer context.
\param logging The logging context. */
void t38_non_ecm_buffer_report_output_status(t38_non_ecm_buffer_state_t *s, logging_state_t *logging);
/*! \brief Get the next bit of data from a T.38 rate adapting non-ECM buffer context.
\param user_data The buffer context, cast to a void pointer.
+23 -15
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v17rx.h,v 1.52 2008/07/16 14:23:48 steveu Exp $
* $Id: v17rx.h,v 1.53 2008/09/08 12:54:32 steveu Exp $
*/
/*! \file */
@@ -306,28 +306,26 @@ typedef struct
/*! \brief The previous value of agc_scaling, needed to reuse old training. */
float agc_scaling_save;
/*! \brief The current delta factor for updating the equalizer coefficients. */
float eq_delta;
#if defined(SPANDSP_USE_FIXED_POINTx)
/*! \brief The adaptive equalizer coefficients. */
complexi_t eq_coeff[V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN];
/*! \brief A saved set of adaptive equalizer coefficients for use after restarts. */
complexi_t eq_coeff_save[V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN];
/*! \brief The equalizer signal buffer. */
complexi_t eq_buf[V17_EQUALIZER_MASK + 1];
#else
complexf_t eq_coeff[V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN];
complexf_t eq_coeff_save[V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN];
complexf_t eq_buf[V17_EQUALIZER_MASK + 1];
#endif
/*! \brief Current read offset into the equalizer buffer. */
int eq_step;
/*! \brief Current write offset into the equalizer buffer. */
int eq_put_step;
/*! \brief Symbol counter to the next equalizer update. */
int eq_skip;
/*! \brief The current half of the baud. */
int baud_half;
#if defined(SPANDSP_USE_FIXED_POINTx)
/*! \brief The current delta factor for updating the equalizer coefficients. */
float eq_delta;
/*! \brief The adaptive equalizer coefficients. */
complexi16_t eq_coeff[V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN];
/*! \brief A saved set of adaptive equalizer coefficients for use after restarts. */
complexi16_t eq_coeff_save[V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN];
/*! \brief The equalizer signal buffer. */
complexi16_t eq_buf[V17_EQUALIZER_MASK + 1];
/*! Low band edge filter for symbol sync. */
int32_t symbol_sync_low[2];
/*! High band edge filter for symbol sync. */
@@ -337,6 +335,15 @@ typedef struct
/*! Baud phase for symbol sync. */
int32_t baud_phase;
#else
/*! \brief The current delta factor for updating the equalizer coefficients. */
float eq_delta;
/*! \brief The adaptive equalizer coefficients. */
complexf_t eq_coeff[V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN];
/*! \brief A saved set of adaptive equalizer coefficients for use after restarts. */
complexf_t eq_coeff_save[V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN];
/*! \brief The equalizer signal buffer. */
complexf_t eq_buf[V17_EQUALIZER_MASK + 1];
/*! Low band edge filter for symbol sync. */
float symbol_sync_low[2];
/*! High band edge filter for symbol sync. */
@@ -346,6 +353,7 @@ typedef struct
/*! Baud phase for symbol sync. */
float baud_phase;
#endif
/*! \brief The total symbol timing correction since the carrier came up.
This is only for performance analysis purposes. */
int total_baud_timing_correction;
+26 -17
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v27ter_rx.h,v 1.47 2008/07/16 14:23:48 steveu Exp $
* $Id: v27ter_rx.h,v 1.48 2008/09/08 12:54:32 steveu Exp $
*/
/*! \file */
@@ -144,22 +144,10 @@ typedef struct
/*! \brief The previous value of agc_scaling, needed to reuse old training. */
float agc_scaling_save;
/*! \brief The position of the current symbol in the constellation, used for
differential decoding. */
int constellation_state;
/*! \brief The current delta factor for updating the equalizer coefficients. */
float eq_delta;
#if defined(SPANDSP_USE_FIXED_POINTx)
/*! \brief The adaptive equalizer coefficients. */
complexi_t eq_coeff[V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN];
/*! \brief A saved set of adaptive equalizer coefficients for use after restarts. */
complexi_t eq_coeff_save[V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN];
/*! \brief The equalizer signal buffer. */
complexi_t eq_buf[V27TER_EQUALIZER_MASK + 1];
#else
complexf_t eq_coeff[V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN];
complexf_t eq_coeff_save[V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN];
complexf_t eq_buf[V27TER_EQUALIZER_MASK + 1];
#endif
/*! \brief Current offset into the equalizer buffer. */
int eq_step;
/*! \brief Current write offset into the equalizer buffer. */
@@ -167,6 +155,29 @@ typedef struct
/*! \brief Symbol counter to the next equalizer update. */
int eq_skip;
/*! \brief The current half of the baud. */
int baud_half;
#if defined(SPANDSP_USE_FIXED_POINTx)
/*! \brief The current delta factor for updating the equalizer coefficients. */
float eq_delta;
/*! \brief The adaptive equalizer coefficients. */
complexi16_t eq_coeff[V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN];
/*! \brief A saved set of adaptive equalizer coefficients for use after restarts. */
complexi16_t eq_coeff_save[V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN];
/*! \brief The equalizer signal buffer. */
complexi16_t eq_buf[V27TER_EQUALIZER_MASK + 1];
#else
/*! \brief The current delta factor for updating the equalizer coefficients. */
float eq_delta;
/*! \brief The adaptive equalizer coefficients. */
complexf_t eq_coeff[V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN];
/*! \brief A saved set of adaptive equalizer coefficients for use after restarts. */
complexf_t eq_coeff_save[V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN];
/*! \brief The equalizer signal buffer. */
complexf_t eq_buf[V27TER_EQUALIZER_MASK + 1];
#endif
/*! \brief Integration variable for damping the Gardner algorithm tests. */
int gardner_integrate;
/*! \brief Current step size of Gardner algorithm integration. */
@@ -174,8 +185,6 @@ typedef struct
/*! \brief The total symbol timing correction since the carrier came up.
This is only for performance analysis purposes. */
int total_baud_timing_correction;
/*! \brief The current fractional phase of the baud timing. */
int baud_phase;
/*! \brief Starting phase angles for the coarse carrier aquisition step. */
int32_t start_angles[2];
+27 -16
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v29rx.h,v 1.55 2008/07/16 14:23:48 steveu Exp $
* $Id: v29rx.h,v 1.59 2008/09/08 12:45:02 steveu Exp $
*/
/*! \file */
@@ -212,22 +212,10 @@ typedef struct
/*! \brief The previous value of agc_scaling, needed to reuse old training. */
float agc_scaling_save;
/*! \brief The position of the current symbol in the constellation, used for
differential decoding. */
int constellation_state;
/*! \brief The current delta factor for updating the equalizer coefficients. */
float eq_delta;
#if defined(SPANDSP_USE_FIXED_POINTx)
/*! \brief The adaptive equalizer coefficients. */
complexi_t eq_coeff[V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN];
/*! \brief A saved set of adaptive equalizer coefficients for use after restarts. */
complexi_t eq_coeff_save[V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN];
/*! \brief The equalizer signal buffer. */
complexi_t eq_buf[V29_EQUALIZER_MASK + 1];
#else
complexf_t eq_coeff[V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN];
complexf_t eq_coeff_save[V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN];
complexf_t eq_buf[V29_EQUALIZER_MASK + 1];
#endif
/*! \brief Current offset into the equalizer buffer. */
int eq_step;
/*! \brief Current write offset into the equalizer buffer. */
@@ -237,7 +225,17 @@ typedef struct
/*! \brief The current half of the baud. */
int baud_half;
#if defined(SPANDSP_USE_FIXED_POINTx)
#if defined(SPANDSP_USE_FIXED_POINT)
/*! \brief The current delta factor for updating the equalizer coefficients. */
int16_t eq_delta;
/*! \brief The adaptive equalizer coefficients. */
complexi16_t eq_coeff[V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN];
/*! \brief A saved set of adaptive equalizer coefficients for use after restarts. */
complexi16_t eq_coeff_save[V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN];
/*! \brief The equalizer signal buffer. */
complexi16_t eq_buf[V29_EQUALIZER_MASK + 1];
/*! Low band edge filter for symbol sync. */
int32_t symbol_sync_low[2];
/*! High band edge filter for symbol sync. */
@@ -247,6 +245,15 @@ typedef struct
/*! Baud phase for symbol sync. */
int32_t baud_phase;
#else
/*! \brief The current delta factor for updating the equalizer coefficients. */
float eq_delta;
/*! \brief The adaptive equalizer coefficients. */
complexf_t eq_coeff[V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN];
/*! \brief A saved set of adaptive equalizer coefficients for use after restarts. */
complexf_t eq_coeff_save[V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN];
/*! \brief The equalizer signal buffer. */
complexf_t eq_buf[V29_EQUALIZER_MASK + 1];
/*! Low band edge filter for symbol sync. */
float symbol_sync_low[2];
/*! High band edge filter for symbol sync. */
@@ -324,7 +331,11 @@ int v29_rx(v29_rx_state_t *s, const int16_t amp[], int len);
\param s The modem context.
\param coeffs The vector of complex coefficients.
\return The number of coefficients in the vector. */
#if defined(SPANDSP_USE_FIXED_POINT)
int v29_rx_equalizer_state(v29_rx_state_t *s, complexi16_t **coeffs);
#else
int v29_rx_equalizer_state(v29_rx_state_t *s, complexf_t **coeffs);
#endif
/*! Get the current received carrier frequency.
\param s The modem context.
+2 -2
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v8.h,v 1.22 2008/05/14 15:41:25 steveu Exp $
* $Id: v8.h,v 1.23 2008/09/04 14:40:05 steveu Exp $
*/
/*! \file */
@@ -76,7 +76,7 @@ enum v8_modulation_e
V8_MOD_V90 = (1 << 12), /* V.90 duplex */
V8_MOD_V92 = (1 << 13), /* V.92 duplex */
V8_MOD_FAILED = (1 << 15), /* Indicates failure to negotiate */
V8_MOD_FAILED = (1 << 15) /* Indicates failure to negotiate */
};
enum v8_protocol_e
+16 -1
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: vector_float.h,v 1.10 2008/04/17 14:27:01 steveu Exp $
* $Id: vector_float.h,v 1.11 2008/09/01 16:07:34 steveu Exp $
*/
#if !defined(_SPANDSP_VECTOR_FLOAT_H_)
@@ -105,11 +105,26 @@ void vec_mul(double z[], const double x[], const double y[], int n);
void vec_mull(long double z[], const long double x[], const long double y[], int n);
#endif
/*! \brief Find the dot product of two float vectors.
\param x The first vector.
\param y The first vector.
\param n The number of elements in the vectors.
\return The dot product of the two vectors. */
float vec_dot_prodf(const float x[], const float y[], int n);
/*! \brief Find the dot product of two double vectors.
\param x The first vector.
\param y The first vector.
\param n The number of elements in the vectors.
\return The dot product of the two vectors. */
double vec_dot_prod(const double x[], const double y[], int n);
#if defined(HAVE_LONG_DOUBLE)
/*! \brief Find the dot product of two long double vectors.
\param x The first vector.
\param y The first vector.
\param n The number of elements in the vectors.
\return The dot product of the two vectors. */
long double vec_dot_prodl(const long double x[], const long double y[], int n);
#endif
+71 -3
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: vector_int.h,v 1.10 2008/04/17 14:27:01 steveu Exp $
* $Id: vector_int.h,v 1.11 2008/09/01 16:07:34 steveu Exp $
*/
#if !defined(_SPANDSP_VECTOR_INT_H_)
@@ -33,11 +33,79 @@ extern "C"
{
#endif
static __inline__ void vec_copyi(int z[], const int x[], int n)
{
memcpy(z, x, n*sizeof(z[0]));
}
/*- End of function --------------------------------------------------------*/
static __inline__ void vec_copyi16(int16_t z[], const int16_t x[], int n)
{
memcpy(z, x, n*sizeof(z[0]));
}
/*- End of function --------------------------------------------------------*/
static __inline__ void vec_copyi32(int32_t z[], const int32_t x[], int n)
{
memcpy(z, x, n*sizeof(z[0]));
}
/*- End of function --------------------------------------------------------*/
static __inline__ void vec_zeroi(int z[], int n)
{
memset(z, 0, n*sizeof(z[0]));
}
/*- End of function --------------------------------------------------------*/
static __inline__ void vec_zeroi16(int16_t z[], int n)
{
memset(z, 0, n*sizeof(z[0]));
}
/*- End of function --------------------------------------------------------*/
static __inline__ void vec_zeroi32(int32_t z[], int n)
{
memset(z, 0, n*sizeof(z[0]));
}
/*- End of function --------------------------------------------------------*/
static __inline__ void vec_seti(int z[], int x, int n)
{
int i;
for (i = 0; i < n; i++)
z[i] = x;
}
/*- End of function --------------------------------------------------------*/
static __inline__ void vec_seti16(int16_t z[], int16_t x, int n)
{
int i;
for (i = 0; i < n; i++)
z[i] = x;
}
/*- End of function --------------------------------------------------------*/
static __inline__ void vec_seti32(int32_t z[], int32_t x, int n)
{
int i;
for (i = 0; i < n; i++)
z[i] = x;
}
/*- End of function --------------------------------------------------------*/
/*! \brief Find the dot product of two int16_t vectors.
\param x The first vector.
\param y The first vector.
\param n The number of elements in the vectors.
\return The dot product of the two vectors. */
int32_t vec_dot_prodi16(const int16_t x[], const int16_t y[], int n);
/*! \brief Find the minimum and maximum values in a vector.
/*! \brief Find the minimum and maximum values in an int16_t vector.
\param x The vector to be searched.
\param n The number of elements in the vetor.
\param n The number of elements in the vector.
\param out A two element vector. The first will receive the
maximum. The second will receive the minimum. This parameter
may be set to NULL.
+2 -2
View File
@@ -30,8 +30,8 @@
/* The date and time of the version are in UTC form. */
#define SPANDSP_RELEASE_DATE 20080829
#define SPANDSP_RELEASE_TIME 104025
#define SPANDSP_RELEASE_DATE 20080909
#define SPANDSP_RELEASE_TIME 162813
#endif
/*- End of file ------------------------------------------------------------*/
+19 -21
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t30.c,v 1.262 2008/08/17 16:25:52 steveu Exp $
* $Id: t30.c,v 1.264 2008/09/09 15:30:43 steveu Exp $
*/
/*! \file */
@@ -1831,7 +1831,6 @@ static int start_receiving_document(t30_state_t *s)
}
span_log(&s->logging, SPAN_LOG_FLOW, "Start receiving document\n");
queue_phase(s, T30_PHASE_B_TX);
s->dis_received = FALSE;
s->ecm_block = 0;
send_dis_or_dtc_sequence(s, TRUE);
return 0;
@@ -2006,7 +2005,6 @@ static int process_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len)
send_dcn(s);
return -1;
}
s->dis_received = TRUE;
if (set_dis_or_dtc(s))
{
s->current_status = T30_ERR_INCOMPATIBLE;
@@ -4823,13 +4821,13 @@ static void t30_non_ecm_rx_status(void *user_data, int status)
s = (t30_state_t *) user_data;
switch (status)
{
case PUTBIT_TRAINING_IN_PROGRESS:
case SIG_STATUS_TRAINING_IN_PROGRESS:
break;
case PUTBIT_TRAINING_FAILED:
case SIG_STATUS_TRAINING_FAILED:
span_log(&s->logging, SPAN_LOG_FLOW, "Non-ECM carrier training failed in state %d\n", s->state);
s->rx_trained = FALSE;
break;
case PUTBIT_TRAINING_SUCCEEDED:
case SIG_STATUS_TRAINING_SUCCEEDED:
/* The modem is now trained */
span_log(&s->logging, SPAN_LOG_FLOW, "Non-ECM carrier trained in state %d\n", s->state);
/* In case we are in trainability test mode... */
@@ -4840,10 +4838,10 @@ static void t30_non_ecm_rx_status(void *user_data, int status)
s->rx_trained = TRUE;
s->timer_t2_t4 = 0;
break;
case PUTBIT_CARRIER_UP:
case SIG_STATUS_CARRIER_UP:
span_log(&s->logging, SPAN_LOG_FLOW, "Non-ECM carrier up in state %d\n", s->state);
break;
case PUTBIT_CARRIER_DOWN:
case SIG_STATUS_CARRIER_DOWN:
span_log(&s->logging, SPAN_LOG_FLOW, "Non-ECM carrier down in state %d\n", s->state);
was_trained = s->rx_trained;
s->rx_signal_present = FALSE;
@@ -5052,7 +5050,7 @@ int t30_non_ecm_get_bit(void *user_data)
if (s->tcf_test_bits-- < 0)
{
/* Finished sending training test. */
bit = PUTBIT_END_OF_DATA;
bit = SIG_STATUS_END_OF_DATA;
}
break;
case T30_STATE_I:
@@ -5066,7 +5064,7 @@ int t30_non_ecm_get_bit(void *user_data)
break;
default:
span_log(&s->logging, SPAN_LOG_WARNING, "t30_non_ecm_get_bit in bad state %d\n", s->state);
bit = PUTBIT_END_OF_DATA;
bit = SIG_STATUS_END_OF_DATA;
break;
}
return bit;
@@ -5150,19 +5148,19 @@ static void t30_hdlc_rx_status(void *user_data, int status)
s = (t30_state_t *) user_data;
switch (status)
{
case PUTBIT_TRAINING_IN_PROGRESS:
case SIG_STATUS_TRAINING_IN_PROGRESS:
break;
case PUTBIT_TRAINING_FAILED:
case SIG_STATUS_TRAINING_FAILED:
span_log(&s->logging, SPAN_LOG_FLOW, "HDLC carrier training failed in state %d\n", s->state);
s->rx_trained = FALSE;
break;
case PUTBIT_TRAINING_SUCCEEDED:
case SIG_STATUS_TRAINING_SUCCEEDED:
/* The modem is now trained */
span_log(&s->logging, SPAN_LOG_FLOW, "HDLC carrier trained in state %d\n", s->state);
s->rx_signal_present = TRUE;
s->rx_trained = TRUE;
break;
case PUTBIT_CARRIER_UP:
case SIG_STATUS_CARRIER_UP:
span_log(&s->logging, SPAN_LOG_FLOW, "HDLC carrier up in state %d\n", s->state);
s->rx_signal_present = TRUE;
switch (s->timer_t2_t4_is)
@@ -5177,7 +5175,7 @@ static void t30_hdlc_rx_status(void *user_data, int status)
break;
}
break;
case PUTBIT_CARRIER_DOWN:
case SIG_STATUS_CARRIER_DOWN:
span_log(&s->logging, SPAN_LOG_FLOW, "HDLC carrier down in state %d\n", s->state);
s->rx_signal_present = FALSE;
s->rx_trained = FALSE;
@@ -5206,7 +5204,7 @@ static void t30_hdlc_rx_status(void *user_data, int status)
}
}
break;
case PUTBIT_FRAMING_OK:
case SIG_STATUS_FRAMING_OK:
span_log(&s->logging, SPAN_LOG_FLOW, "HDLC framing OK in state %d\n", s->state);
if (!s->far_end_detected && s->timer_t0_t1 > 0)
{
@@ -5232,7 +5230,7 @@ static void t30_hdlc_rx_status(void *user_data, int status)
}
}
break;
case PUTBIT_ABORT:
case SIG_STATUS_ABORT:
/* Just ignore these */
break;
default:
@@ -5559,10 +5557,10 @@ void t30_front_end_status(void *user_data, int status)
switch (s->phase)
{
case T30_PHASE_C_NON_ECM_RX:
t30_non_ecm_rx_status(s, PUTBIT_CARRIER_DOWN);
t30_non_ecm_rx_status(s, SIG_STATUS_CARRIER_DOWN);
break;
default:
t30_hdlc_rx_status(s, PUTBIT_CARRIER_DOWN);
t30_hdlc_rx_status(s, SIG_STATUS_CARRIER_DOWN);
break;
}
break;
@@ -5584,8 +5582,8 @@ void t30_front_end_status(void *user_data, int status)
case T30_PHASE_D_RX:
/* We are running a V.21 receive modem, where an explicit training indication
will not occur. */
t30_hdlc_rx_status(s, PUTBIT_CARRIER_UP);
t30_hdlc_rx_status(s, PUTBIT_FRAMING_OK);
t30_hdlc_rx_status(s, SIG_STATUS_CARRIER_UP);
t30_hdlc_rx_status(s, SIG_STATUS_FRAMING_OK);
break;
default:
/* Cancel any receive timeout, and declare that a receive signal is present,
+17 -17
View File
@@ -25,7 +25,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t31.c,v 1.119 2008/08/09 05:09:56 steveu Exp $
* $Id: t31.c,v 1.120 2008/09/07 12:45:17 steveu Exp $
*/
/*! \file */
@@ -341,7 +341,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
packets, when they have sent no data for the body of the frame. */
if (s->tx.out_bytes > 0)
hdlc_accept((void *) s, fe->hdlc_rx.buf, fe->hdlc_rx.len, TRUE);
hdlc_accept((void *) s, NULL, PUTBIT_CARRIER_DOWN, TRUE);
hdlc_accept((void *) s, NULL, SIG_STATUS_CARRIER_DOWN, TRUE);
}
s->tx.out_bytes = 0;
fe->missing_data = FALSE;
@@ -352,7 +352,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_BAD_SIG_END!\n");
span_log(&s->logging, SPAN_LOG_FLOW, "Type %s - CRC bad, sig end (%s)\n", t30_frametype(s->tx.data[2]), (fe->missing_data) ? "missing octets" : "clean");
if (fe->current_rx_type == T31_V21_RX)
hdlc_accept((void *) s, NULL, PUTBIT_CARRIER_DOWN, TRUE);
hdlc_accept((void *) s, NULL, SIG_STATUS_CARRIER_DOWN, TRUE);
fe->hdlc_rx.len = 0;
fe->missing_data = FALSE;
break;
@@ -363,7 +363,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
i.e. they send T38_FIELD_HDLC_FCS_OK, and then T38_FIELD_HDLC_SIG_END when the carrier actually drops.
The other is because the HDLC signal drops unexpectedly - i.e. not just after a final frame. */
if (fe->current_rx_type == T31_V21_RX)
hdlc_accept((void *) s, NULL, PUTBIT_CARRIER_DOWN, TRUE);
hdlc_accept((void *) s, NULL, SIG_STATUS_CARRIER_DOWN, TRUE);
fe->hdlc_rx.len = 0;
fe->missing_data = FALSE;
break;
@@ -709,20 +709,20 @@ static void non_ecm_rx_status(void *user_data, int status)
s = (t31_state_t *) user_data;
switch (status)
{
case PUTBIT_TRAINING_IN_PROGRESS:
case SIG_STATUS_TRAINING_IN_PROGRESS:
break;
case PUTBIT_TRAINING_FAILED:
case SIG_STATUS_TRAINING_FAILED:
s->at_state.rx_trained = FALSE;
break;
case PUTBIT_TRAINING_SUCCEEDED:
case SIG_STATUS_TRAINING_SUCCEEDED:
/* The modem is now trained */
at_put_response_code(&s->at_state, AT_RESPONSE_CODE_CONNECT);
s->at_state.rx_signal_present = TRUE;
s->at_state.rx_trained = TRUE;
break;
case PUTBIT_CARRIER_UP:
case SIG_STATUS_CARRIER_UP:
break;
case PUTBIT_CARRIER_DOWN:
case SIG_STATUS_CARRIER_DOWN:
if (s->at_state.rx_signal_present)
{
s->at_state.rx_data[s->at_state.rx_data_bytes++] = DLE;
@@ -806,7 +806,7 @@ static int non_ecm_get_bit(void *user_data)
s->tx.final = FALSE;
/* This will put the modem into its shutdown sequence. When
it has finally shut down, an OK response will be sent. */
return PUTBIT_END_OF_DATA;
return SIG_STATUS_END_OF_DATA;
}
/* Fill with 0xFF bytes at the start of transmission, or 0x00 if we are in
the middle of transmission. This follows T.31 and T.30 practice. */
@@ -856,24 +856,24 @@ static void hdlc_rx_status(void *user_data, int status)
s = (t31_state_t *) user_data;
switch (status)
{
case PUTBIT_TRAINING_IN_PROGRESS:
case SIG_STATUS_TRAINING_IN_PROGRESS:
break;
case PUTBIT_TRAINING_FAILED:
case SIG_STATUS_TRAINING_FAILED:
s->at_state.rx_trained = FALSE;
break;
case PUTBIT_TRAINING_SUCCEEDED:
case SIG_STATUS_TRAINING_SUCCEEDED:
/* The modem is now trained */
s->at_state.rx_signal_present = TRUE;
s->at_state.rx_trained = TRUE;
break;
case PUTBIT_CARRIER_UP:
case SIG_STATUS_CARRIER_UP:
if (s->modem == T31_CNG_TONE || s->modem == T31_NOCNG_TONE || s->modem == T31_V21_RX)
{
s->at_state.rx_signal_present = TRUE;
s->rx_frame_received = FALSE;
}
break;
case PUTBIT_CARRIER_DOWN:
case SIG_STATUS_CARRIER_DOWN:
if (s->rx_frame_received)
{
if (s->at_state.dte_is_waiting)
@@ -899,7 +899,7 @@ static void hdlc_rx_status(void *user_data, int status)
s->at_state.rx_signal_present = FALSE;
s->at_state.rx_trained = FALSE;
break;
case PUTBIT_FRAMING_OK:
case SIG_STATUS_FRAMING_OK:
if (s->modem == T31_CNG_TONE || s->modem == T31_NOCNG_TONE)
{
/* Once we get any valid HDLC the CNG tone stops, and we drop
@@ -949,7 +949,7 @@ static void hdlc_rx_status(void *user_data, int status)
}
}
break;
case PUTBIT_ABORT:
case SIG_STATUS_ABORT:
/* Just ignore these */
break;
default:
+215 -139
View File
@@ -23,7 +23,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t38_gateway.c,v 1.139 2008/08/17 16:25:52 steveu Exp $
* $Id: t38_gateway.c,v 1.142 2008/09/07 12:45:17 steveu Exp $
*/
/*! \file */
@@ -308,31 +308,31 @@ static void hdlc_underflow_handler(void *user_data)
span_log(&s->logging, SPAN_LOG_FLOW, "HDLC underflow at %d\n", t->out);
/* If the current HDLC buffer is not at the HDLC_FLAG_PROCEED_WITH_OUTPUT stage, this
underflow must be an end of preamble condition. */
if ((t->flags[t->out] & HDLC_FLAG_PROCEED_WITH_OUTPUT))
if ((t->buf[t->out].flags & HDLC_FLAG_PROCEED_WITH_OUTPUT))
{
old_data_type = t->contents[t->out];
t->len[t->out] = 0;
t->flags[t->out] = 0;
t->contents[t->out] = 0;
old_data_type = t->buf[t->out].contents;
t->buf[t->out].len = 0;
t->buf[t->out].flags = 0;
t->buf[t->out].contents = 0;
if (++t->out >= T38_TX_HDLC_BUFS)
t->out = 0;
span_log(&s->logging, SPAN_LOG_FLOW, "HDLC next is 0x%X\n", t->contents[t->out]);
if ((t->contents[t->out] & FLAG_INDICATOR))
span_log(&s->logging, SPAN_LOG_FLOW, "HDLC next is 0x%X\n", t->buf[t->out].contents);
if ((t->buf[t->out].contents & FLAG_INDICATOR))
{
/* The next thing in the queue is an indicator, so we need to stop this modem. */
span_log(&s->logging, SPAN_LOG_FLOW, "HDLC shutdown\n");
hdlc_tx_frame(&s->audio.modems.hdlc_tx, NULL, 0);
}
else if ((t->contents[t->out] & FLAG_DATA))
else if ((t->buf[t->out].contents & FLAG_DATA))
{
/* Check if we should start sending the next frame */
if ((t->flags[t->out] & HDLC_FLAG_PROCEED_WITH_OUTPUT))
if ((t->buf[t->out].flags & HDLC_FLAG_PROCEED_WITH_OUTPUT))
{
/* This frame is ready to go, and uses the same modem we are running now. So, send
whatever we have. This might or might not be an entire frame. */
span_log(&s->logging, SPAN_LOG_FLOW, "HDLC start next frame\n");
hdlc_tx_frame(&s->audio.modems.hdlc_tx, t->buf[t->out], t->len[t->out]);
if ((t->flags[t->out] & HDLC_FLAG_CORRUPT_CRC))
hdlc_tx_frame(&s->audio.modems.hdlc_tx, t->buf[t->out].buf, t->buf[t->out].len);
if ((t->buf[t->out].flags & HDLC_FLAG_CORRUPT_CRC))
hdlc_tx_corrupt_frame(&s->audio.modems.hdlc_tx);
/*endif*/
}
@@ -355,9 +355,10 @@ static int set_next_tx_type(t38_gateway_state_t *s)
t = &s->audio.modems;
u = &s->core.hdlc_to_modem;
t38_non_ecm_buffer_report_output_status(&s->core.non_ecm_to_modem, &s->logging);
if (t->next_tx_handler)
{
/* There is a handler queued, so that is the next one */
/* There is a handler queued, so that is the next one. */
t->tx_handler = t->next_tx_handler;
t->tx_user_data = t->next_tx_user_data;
t->next_tx_handler = NULL;
@@ -378,13 +379,13 @@ static int set_next_tx_type(t38_gateway_state_t *s)
if (u->in == u->out)
return FALSE;
/*endif*/
if ((u->contents[u->out] & FLAG_INDICATOR) == 0)
if ((u->buf[u->out].contents & FLAG_INDICATOR) == 0)
return FALSE;
/*endif*/
indicator = (u->contents[u->out] & 0xFF);
u->len[u->out] = 0;
u->flags[u->out] = 0;
u->contents[u->out] = 0;
indicator = (u->buf[u->out].contents & 0xFF);
u->buf[u->out].len = 0;
u->buf[u->out].flags = 0;
u->buf[u->out].contents = 0;
if (++u->out >= T38_TX_HDLC_BUFS)
u->out = 0;
/*endif*/
@@ -437,7 +438,7 @@ static int set_next_tx_type(t38_gateway_state_t *s)
hdlc_tx_init(&t->hdlc_tx, FALSE, 2, TRUE, hdlc_underflow_handler, s);
hdlc_tx_flags(&t->hdlc_tx, 32);
silence_gen_alter(&t->silence_gen, ms_to_samples(75));
u->len[u->in] = 0;
u->buf[u->in].len = 0;
fsk_tx_init(&t->v21_tx, &preset_fsk_specs[FSK_V21CH2], (get_bit_func_t) hdlc_tx_get_bit, &t->hdlc_tx);
t->tx_handler = (span_tx_handler_t *) &(silence_gen);
t->tx_user_data = &t->silence_gen;
@@ -456,6 +457,7 @@ static int set_next_tx_type(t38_gateway_state_t *s)
t->tx_bit_rate = 2400;
break;
}
/*endswitch*/
silence_gen_alter(&t->silence_gen, ms_to_samples(75));
v27ter_tx_restart(&t->v27ter_tx, t->tx_bit_rate, t->use_tep);
v27ter_tx_set_get_bit(&t->v27ter_tx, get_bit_func, get_bit_user_data);
@@ -476,6 +478,7 @@ static int set_next_tx_type(t38_gateway_state_t *s)
t->tx_bit_rate = 9600;
break;
}
/*endswitch*/
silence_gen_alter(&t->silence_gen, ms_to_samples(75));
v29_tx_restart(&t->v29_tx, t->tx_bit_rate, t->use_tep);
v29_tx_set_get_bit(&t->v29_tx, get_bit_func, get_bit_user_data);
@@ -525,6 +528,7 @@ static int set_next_tx_type(t38_gateway_state_t *s)
t->tx_bit_rate = 14400;
break;
}
/*endswitch*/
silence_gen_alter(&t->silence_gen, ms_to_samples(75));
v17_tx_restart(&t->v17_tx, t->tx_bit_rate, t->use_tep, short_train);
v17_tx_set_get_bit(&t->v17_tx, get_bit_func, get_bit_user_data);
@@ -563,36 +567,41 @@ static int set_next_tx_type(t38_gateway_state_t *s)
if (t->tx_bit_rate > 300)
hdlc_tx_flags(&t->hdlc_tx, t->tx_bit_rate/(8*5));
/*endif*/
t38_non_ecm_buffer_report_status(&s->core.non_ecm_to_modem, &s->logging);
t38_non_ecm_buffer_init(&s->core.non_ecm_to_modem, s->core.image_data_mode, s->core.min_row_bits);
s->t38x.in_progress_rx_indicator = indicator;
return TRUE;
}
/*- End of function --------------------------------------------------------*/
static void pump_out_final_hdlc(t38_gateway_state_t *s, int good_fcs)
static void finalise_hdlc_frame(t38_gateway_state_t *s, int good_fcs)
{
if (!good_fcs)
s->core.hdlc_to_modem.flags[s->core.hdlc_to_modem.in] |= HDLC_FLAG_CORRUPT_CRC;
t38_gateway_hdlc_buf_t *hdlc_buf;
hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in];
if (!good_fcs || (hdlc_buf->flags & HDLC_FLAG_MISSING_DATA))
hdlc_buf->flags |= HDLC_FLAG_CORRUPT_CRC;
/*endif*/
if (s->core.hdlc_to_modem.in == s->core.hdlc_to_modem.out)
{
/* This is the frame in progress at the output. */
if ((s->core.hdlc_to_modem.flags[s->core.hdlc_to_modem.out] & HDLC_FLAG_PROCEED_WITH_OUTPUT) == 0)
if ((hdlc_buf->flags & HDLC_FLAG_PROCEED_WITH_OUTPUT) == 0)
{
/* Output of this frame has not yet begun. Throw it all out now. */
hdlc_tx_frame(&s->audio.modems.hdlc_tx, s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.out], s->core.hdlc_to_modem.len[s->core.hdlc_to_modem.out]);
hdlc_tx_frame(&s->audio.modems.hdlc_tx, hdlc_buf->buf, hdlc_buf->len);
}
/*endif*/
if ((s->core.hdlc_to_modem.flags[s->core.hdlc_to_modem.out] & HDLC_FLAG_CORRUPT_CRC))
if ((hdlc_buf->flags & HDLC_FLAG_CORRUPT_CRC))
hdlc_tx_corrupt_frame(&s->audio.modems.hdlc_tx);
/*endif*/
}
/*endif*/
s->core.hdlc_to_modem.flags[s->core.hdlc_to_modem.in] |= (HDLC_FLAG_PROCEED_WITH_OUTPUT | HDLC_FLAG_FINISHED);
hdlc_buf->flags |= (HDLC_FLAG_PROCEED_WITH_OUTPUT | HDLC_FLAG_FINISHED);
if (++s->core.hdlc_to_modem.in >= T38_TX_HDLC_BUFS)
s->core.hdlc_to_modem.in = 0;
/*endif*/
hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in];
hdlc_buf->len = 0;
hdlc_buf->flags = 0;
hdlc_buf->contents = 0;
}
/*- End of function --------------------------------------------------------*/
@@ -853,53 +862,53 @@ static void monitor_control_messages(t38_gateway_state_t *s, int from_modem, uin
static void queue_missing_indicator(t38_gateway_state_t *s, int data_type)
{
t38_core_state_t *t;
int expected;
int expected_alt;
t = &s->t38x.t38;
expected = -1;
expected_alt = -1;
/* Missing packets might have lost us the indicator that should have put us in
the required mode of operation. It might be a bit late to fill in such a gap
now, but we should try. We may also want to force indicators into the queue,
such as when the data says 'end of signal'. */
/* We have an expectation of whether long or short training should occur, but be
tolerant of either kind of indicator being present. */
switch (data_type)
{
case T38_DATA_NONE:
if (t->current_rx_indicator != T38_IND_NO_SIGNAL)
process_rx_indicator(t, (void *) s, T38_IND_NO_SIGNAL);
expected = T38_IND_NO_SIGNAL;
break;
case T38_DATA_V21:
if (t->current_rx_indicator != T38_IND_V21_PREAMBLE)
process_rx_indicator(t, (void *) s, T38_IND_V21_PREAMBLE);
expected = T38_IND_V21_PREAMBLE;
break;
case T38_DATA_V27TER_2400:
if (t->current_rx_indicator != T38_IND_V27TER_2400_TRAINING)
process_rx_indicator(t, (void *) s, T38_IND_V27TER_2400_TRAINING);
expected = T38_IND_V27TER_2400_TRAINING;
break;
case T38_DATA_V27TER_4800:
if (t->current_rx_indicator != T38_IND_V27TER_4800_TRAINING)
process_rx_indicator(t, (void *) s, T38_IND_V27TER_4800_TRAINING);
expected = T38_IND_V27TER_4800_TRAINING;
break;
case T38_DATA_V29_7200:
if (t->current_rx_indicator != T38_IND_V29_7200_TRAINING)
process_rx_indicator(t, (void *) s, T38_IND_V29_7200_TRAINING);
expected = T38_IND_V29_7200_TRAINING;
break;
case T38_DATA_V29_9600:
if (t->current_rx_indicator != T38_IND_V29_9600_TRAINING)
process_rx_indicator(t, (void *) s, T38_IND_V29_9600_TRAINING);
expected = T38_IND_V29_9600_TRAINING;
break;
case T38_DATA_V17_7200:
if (t->current_rx_indicator != T38_IND_V17_7200_SHORT_TRAINING && t->current_rx_indicator != T38_IND_V17_7200_LONG_TRAINING)
process_rx_indicator(t, (void *) s, T38_IND_V17_7200_LONG_TRAINING);
expected = (s->core.short_train) ? T38_IND_V17_7200_SHORT_TRAINING : T38_IND_V17_7200_LONG_TRAINING;
expected_alt = (s->core.short_train) ? T38_IND_V17_7200_LONG_TRAINING : T38_IND_V17_7200_SHORT_TRAINING;
break;
case T38_DATA_V17_9600:
if (t->current_rx_indicator != T38_IND_V17_9600_SHORT_TRAINING && t->current_rx_indicator != T38_IND_V17_9600_LONG_TRAINING)
process_rx_indicator(t, (void *) s, T38_IND_V17_9600_LONG_TRAINING);
expected = (s->core.short_train) ? T38_IND_V17_9600_SHORT_TRAINING : T38_IND_V17_9600_LONG_TRAINING;
expected_alt = (s->core.short_train) ? T38_IND_V17_9600_LONG_TRAINING : T38_IND_V17_9600_SHORT_TRAINING;
break;
case T38_DATA_V17_12000:
if (t->current_rx_indicator != T38_IND_V17_12000_SHORT_TRAINING && t->current_rx_indicator != T38_IND_V17_12000_LONG_TRAINING)
process_rx_indicator(t, (void *) s, T38_IND_V17_12000_LONG_TRAINING);
expected = (s->core.short_train) ? T38_IND_V17_12000_SHORT_TRAINING : T38_IND_V17_12000_LONG_TRAINING;
expected_alt = (s->core.short_train) ? T38_IND_V17_12000_LONG_TRAINING : T38_IND_V17_12000_SHORT_TRAINING;
break;
case T38_DATA_V17_14400:
if (t->current_rx_indicator != T38_IND_V17_14400_SHORT_TRAINING && t->current_rx_indicator != T38_IND_V17_14400_LONG_TRAINING)
process_rx_indicator(t, (void *) s, T38_IND_V17_14400_LONG_TRAINING);
expected = (s->core.short_train) ? T38_IND_V17_14400_SHORT_TRAINING : T38_IND_V17_14400_LONG_TRAINING;
expected_alt = (s->core.short_train) ? T38_IND_V17_14400_LONG_TRAINING : T38_IND_V17_14400_SHORT_TRAINING;
break;
case T38_DATA_V8:
break;
@@ -914,6 +923,20 @@ static void queue_missing_indicator(t38_gateway_state_t *s, int data_type)
case T38_DATA_V33_14400:
break;
}
/*endswitch*/
if (expected < 0)
return;
if (t->current_rx_indicator == expected)
return;
if (expected_alt >= 0 && t->current_rx_indicator == expected_alt)
return;
span_log(&s->logging,
SPAN_LOG_FLOW,
"Queuing missing indicator - %s\n",
t38_indicator_to_str(expected));
process_rx_indicator(t, (void *) s, expected);
/* Force the indicator setting here, as the core won't set in when its missing. */
t->current_rx_indicator = expected;
}
/*- End of function --------------------------------------------------------*/
@@ -922,7 +945,7 @@ static int process_rx_missing(t38_core_state_t *t, void *user_data, int rx_seq_n
t38_gateway_state_t *s;
s = (t38_gateway_state_t *) user_data;
s->core.hdlc_to_modem.flags[s->core.hdlc_to_modem.in] |= HDLC_FLAG_MISSING_DATA;
s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in].flags |= HDLC_FLAG_MISSING_DATA;
return 0;
}
/*- End of function --------------------------------------------------------*/
@@ -933,23 +956,26 @@ static int process_rx_indicator(t38_core_state_t *t, void *user_data, int indica
s = (t38_gateway_state_t *) user_data;
t38_non_ecm_buffer_report_input_status(&s->core.non_ecm_to_modem, &s->logging);
if (t->current_rx_indicator == indicator)
{
/* This is probably due to the far end repeating itself. Ignore it. Its harmless */
return 0;
}
/*endif*/
if (s->core.hdlc_to_modem.contents[s->core.hdlc_to_modem.in])
if (s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in].contents)
{
if (++s->core.hdlc_to_modem.in >= T38_TX_HDLC_BUFS)
s->core.hdlc_to_modem.in = 0;
/*endif*/
}
/*endif*/
s->core.hdlc_to_modem.contents[s->core.hdlc_to_modem.in] = (indicator | FLAG_INDICATOR);
s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in].contents = (indicator | FLAG_INDICATOR);
if (++s->core.hdlc_to_modem.in >= T38_TX_HDLC_BUFS)
s->core.hdlc_to_modem.in = 0;
/*endif*/
t38_non_ecm_buffer_set_mode(&s->core.non_ecm_to_modem, s->core.image_data_mode, s->core.min_row_bits);
span_log(&s->logging,
SPAN_LOG_FLOW,
"Queued change - (%d) %s -> %s\n",
@@ -967,9 +993,9 @@ static int process_rx_indicator(t38_core_state_t *t, void *user_data, int indica
static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, int field_type, const uint8_t *buf, int len)
{
int i;
int previous;
t38_gateway_state_t *s;
t38_gateway_t38_state_t *xx;
t38_gateway_hdlc_buf_t *hdlc_buf;
s = (t38_gateway_state_t *) user_data;
xx = &s->t38x;
@@ -977,46 +1003,52 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
{
case T38_FIELD_HDLC_DATA:
xx->current_rx_field_class = T38_FIELD_CLASS_HDLC;
if (s->core.hdlc_to_modem.contents[s->core.hdlc_to_modem.in] != (data_type | FLAG_DATA))
hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in];
if (hdlc_buf->contents != (data_type | FLAG_DATA))
{
queue_missing_indicator(s, data_type);
hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in];
}
/*endif*/
previous = s->core.hdlc_to_modem.len[s->core.hdlc_to_modem.in];
/* Check if this data would overflow the buffer. */
if (s->core.hdlc_to_modem.len[s->core.hdlc_to_modem.in] + len > T38_MAX_HDLC_LEN)
if (hdlc_buf->len + len > T38_MAX_HDLC_LEN)
break;
/*endif*/
s->core.hdlc_to_modem.contents[s->core.hdlc_to_modem.in] = (data_type | FLAG_DATA);
bit_reverse(&s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in][s->core.hdlc_to_modem.len[s->core.hdlc_to_modem.in]], buf, len);
hdlc_buf->contents = (data_type | FLAG_DATA);
bit_reverse(&hdlc_buf->buf[hdlc_buf->len], buf, len);
/* We need to send out the control messages as they are arriving. They are
too slow to capture a whole frame, and then pass it on.
too slow to capture a whole frame before starting to pass it on.
For the faster frames, take in the whole frame before sending it out. Also, there
is no need to monitor, or modify, the contents of the faster frames. */
if (data_type == T38_DATA_V21)
{
for (i = 1; i <= len; i++)
edit_control_messages(s, 0, s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in], s->core.hdlc_to_modem.len[s->core.hdlc_to_modem.in] + i);
edit_control_messages(s, 0, hdlc_buf->buf, hdlc_buf->len + i);
/*endfor*/
/* Don't start pumping data into the actual output stream until there is
enough backlog to create some elasticity for jitter tolerance. */
if (s->core.hdlc_to_modem.len[s->core.hdlc_to_modem.in] + len >= HDLC_START_BUFFER_LEVEL)
if (hdlc_buf->len + len >= HDLC_START_BUFFER_LEVEL)
{
if (s->core.hdlc_to_modem.in == s->core.hdlc_to_modem.out)
{
if ((s->core.hdlc_to_modem.flags[s->core.hdlc_to_modem.in] & HDLC_FLAG_PROCEED_WITH_OUTPUT) == 0)
previous = 0;
/* Output is not running, so kick it into life. */
if ((hdlc_buf->flags & HDLC_FLAG_PROCEED_WITH_OUTPUT) == 0)
hdlc_tx_frame(&s->audio.modems.hdlc_tx, hdlc_buf->buf, hdlc_buf->len + len);
else
hdlc_tx_frame(&s->audio.modems.hdlc_tx, hdlc_buf->buf + hdlc_buf->len, len);
/*endif*/
hdlc_tx_frame(&s->audio.modems.hdlc_tx, s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.out] + previous, s->core.hdlc_to_modem.len[s->core.hdlc_to_modem.out] - previous + len);
}
/*endif*/
s->core.hdlc_to_modem.flags[s->core.hdlc_to_modem.in] |= HDLC_FLAG_PROCEED_WITH_OUTPUT;
hdlc_buf->flags |= HDLC_FLAG_PROCEED_WITH_OUTPUT;
}
/*endif*/
}
/*endif*/
s->core.hdlc_to_modem.len[s->core.hdlc_to_modem.in] += len;
s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in].len += len;
break;
case T38_FIELD_HDLC_FCS_OK:
xx->current_rx_field_class = T38_FIELD_CLASS_HDLC;
hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in];
if (len > 0)
{
span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_OK!\n");
@@ -1027,22 +1059,22 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
/* Some T.38 implementations send multiple T38_FIELD_HDLC_FCS_OK messages, in IFP packets with
incrementing sequence numbers, which are actually repeats. They get through to this point because
of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */
if (t->current_rx_data_type != data_type
||
t->current_rx_field_type != field_type)
if (t->current_rx_data_type != data_type || t->current_rx_field_type != field_type)
{
span_log(&s->logging, SPAN_LOG_FLOW, "HDLC frame type %s - CRC good\n", t30_frametype(s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in][2]));
if (s->core.hdlc_to_modem.contents[s->core.hdlc_to_modem.in] != (data_type | FLAG_DATA))
span_log(&s->logging, SPAN_LOG_FLOW, "HDLC frame type %s - CRC good\n", t30_frametype(hdlc_buf->buf[2]));
if (hdlc_buf->contents != (data_type | FLAG_DATA))
{
queue_missing_indicator(s, data_type);
hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in];
}
/*endif*/
s->core.hdlc_to_modem.contents[s->core.hdlc_to_modem.in] = (data_type | FLAG_DATA);
if (data_type == T38_DATA_V21)
{
if ((s->core.hdlc_to_modem.flags[s->core.hdlc_to_modem.in] & HDLC_FLAG_MISSING_DATA) == 0)
if ((hdlc_buf->flags & HDLC_FLAG_MISSING_DATA) == 0)
{
monitor_control_messages(s, FALSE, s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in], s->core.hdlc_to_modem.len[s->core.hdlc_to_modem.in]);
monitor_control_messages(s, FALSE, hdlc_buf->buf, hdlc_buf->len);
if (s->core.real_time_frame_handler)
s->core.real_time_frame_handler(s, s->core.real_time_frame_user_data, FALSE, s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in], s->core.hdlc_to_modem.len[s->core.hdlc_to_modem.in]);
s->core.real_time_frame_handler(s, s->core.real_time_frame_user_data, FALSE, hdlc_buf->buf, hdlc_buf->len);
/*endif*/
}
/*endif*/
@@ -1050,21 +1082,21 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
else
{
/* Make sure we go back to short training if CTC/CTR has kicked us into
long training. Theer has to be more than one value HDLC frame in a
chunk of image data, so just setting short training mode heer should
long training. There has to be more than one value HDLC frame in a
chunk of image data, so just setting short training mode here should
be enough. */
s->core.short_train = TRUE;
}
/*endif*/
pump_out_final_hdlc(s, (s->core.hdlc_to_modem.flags[s->core.hdlc_to_modem.in] & HDLC_FLAG_MISSING_DATA) == 0);
hdlc_buf->contents = (data_type | FLAG_DATA);
finalise_hdlc_frame(s, TRUE);
}
/*endif*/
s->core.hdlc_to_modem.len[s->core.hdlc_to_modem.in] = 0;
s->core.hdlc_to_modem.flags[s->core.hdlc_to_modem.in] = 0;
xx->corrupt_current_frame[0] = FALSE;
break;
case T38_FIELD_HDLC_FCS_BAD:
xx->current_rx_field_class = T38_FIELD_CLASS_HDLC;
hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in];
if (len > 0)
{
span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_BAD!\n");
@@ -1077,24 +1109,32 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */
if (t->current_rx_data_type != data_type || t->current_rx_field_type != field_type)
{
span_log(&s->logging, SPAN_LOG_FLOW, "HDLC frame type %s - CRC bad\n", t30_frametype(s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in][2]));
if (s->core.hdlc_to_modem.contents[s->core.hdlc_to_modem.in] != (data_type | FLAG_DATA))
queue_missing_indicator(s, data_type);
/*endif*/
if (s->core.hdlc_to_modem.len[s->core.hdlc_to_modem.in] > 0)
span_log(&s->logging, SPAN_LOG_FLOW, "HDLC frame type %s - CRC bad\n", t30_frametype(hdlc_buf->buf[2]));
/* Only bother with frames that have a bad CRC, if they also have some content. */
if (hdlc_buf->len > 0)
{
s->core.hdlc_to_modem.contents[s->core.hdlc_to_modem.in] = (data_type | FLAG_DATA);
pump_out_final_hdlc(s, FALSE);
if (hdlc_buf->contents != (data_type | FLAG_DATA))
{
queue_missing_indicator(s, data_type);
hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in];
}
/*endif*/
hdlc_buf->contents = (data_type | FLAG_DATA);
finalise_hdlc_frame(s, FALSE);
}
else
{
/* Just restart using the current frame buffer */
hdlc_buf->contents = 0;
}
/*endif*/
}
/*endif*/
s->core.hdlc_to_modem.len[s->core.hdlc_to_modem.in] = 0;
s->core.hdlc_to_modem.flags[s->core.hdlc_to_modem.in] = 0;
xx->corrupt_current_frame[0] = FALSE;
break;
case T38_FIELD_HDLC_FCS_OK_SIG_END:
xx->current_rx_field_class = T38_FIELD_CLASS_HDLC;
hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in];
if (len > 0)
{
span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_OK_SIG_END!\n");
@@ -1107,23 +1147,35 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */
if (t->current_rx_data_type != data_type || t->current_rx_field_type != field_type)
{
span_log(&s->logging, SPAN_LOG_FLOW, "HDLC frame type %s - CRC OK, sig end\n", t30_frametype(s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in][2]));
if (s->core.hdlc_to_modem.contents[s->core.hdlc_to_modem.in] != (data_type | FLAG_DATA))
queue_missing_indicator(s, data_type);
/*endif*/
s->core.hdlc_to_modem.contents[s->core.hdlc_to_modem.in] = (data_type | FLAG_DATA);
if (data_type == T38_DATA_V21 && (s->core.hdlc_to_modem.flags[s->core.hdlc_to_modem.in] & HDLC_FLAG_MISSING_DATA) == 0)
span_log(&s->logging, SPAN_LOG_FLOW, "HDLC frame type %s - CRC OK, sig end\n", t30_frametype(hdlc_buf->buf[2]));
if (hdlc_buf->contents != (data_type | FLAG_DATA))
{
monitor_control_messages(s, FALSE, s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in], s->core.hdlc_to_modem.len[s->core.hdlc_to_modem.in]);
if (s->core.real_time_frame_handler)
s->core.real_time_frame_handler(s, s->core.real_time_frame_user_data, FALSE, s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in], s->core.hdlc_to_modem.len[s->core.hdlc_to_modem.in]);
/*endif*/
queue_missing_indicator(s, data_type);
hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in];
}
/*endif*/
pump_out_final_hdlc(s, (s->core.hdlc_to_modem.flags[s->core.hdlc_to_modem.in] & HDLC_FLAG_MISSING_DATA) == 0);
s->core.hdlc_to_modem.len[s->core.hdlc_to_modem.in] = 0;
s->core.hdlc_to_modem.flags[s->core.hdlc_to_modem.in] = 0;
s->core.hdlc_to_modem.contents[s->core.hdlc_to_modem.in] = 0;
if (data_type == T38_DATA_V21)
{
if ((hdlc_buf->flags & HDLC_FLAG_MISSING_DATA) == 0)
{
monitor_control_messages(s, FALSE, hdlc_buf->buf, hdlc_buf->len);
if (s->core.real_time_frame_handler)
s->core.real_time_frame_handler(s, s->core.real_time_frame_user_data, FALSE, hdlc_buf->buf, hdlc_buf->len);
/*endif*/
}
/*endif*/
}
else
{
/* Make sure we go back to short training if CTC/CTR has kicked us into
long training. There has to be more than one value HDLC frame in a
chunk of image data, so just setting short training mode here should
be enough. */
s->core.short_train = TRUE;
}
/*endif*/
hdlc_buf->contents = (data_type | FLAG_DATA);
finalise_hdlc_frame(s, TRUE);
queue_missing_indicator(s, T38_DATA_NONE);
xx->current_rx_field_class = T38_FIELD_CLASS_NONE;
}
@@ -1132,6 +1184,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
break;
case T38_FIELD_HDLC_FCS_BAD_SIG_END:
xx->current_rx_field_class = T38_FIELD_CLASS_HDLC;
hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in];
if (len > 0)
{
span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_FCS_BAD_SIG_END!\n");
@@ -1144,19 +1197,25 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */
if (t->current_rx_data_type != data_type || t->current_rx_field_type != field_type)
{
span_log(&s->logging, SPAN_LOG_FLOW, "HDLC frame type %s - CRC bad, sig end\n", t30_frametype(s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in][2]));
if (s->core.hdlc_to_modem.contents[s->core.hdlc_to_modem.in] != (data_type | FLAG_DATA))
queue_missing_indicator(s, data_type);
/*endif*/
if (s->core.hdlc_to_modem.len[s->core.hdlc_to_modem.in] > 0)
span_log(&s->logging, SPAN_LOG_FLOW, "HDLC frame type %s - CRC bad, sig end\n", t30_frametype(hdlc_buf->buf[2]));
if (hdlc_buf->contents != (data_type | FLAG_DATA))
{
s->core.hdlc_to_modem.contents[s->core.hdlc_to_modem.in] = (data_type | FLAG_DATA);
pump_out_final_hdlc(s, FALSE);
queue_missing_indicator(s, data_type);
hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in];
}
/*endif*/
/* Only bother with frames that have a bad CRC, if they also have some content. */
if (hdlc_buf->len > 0)
{
hdlc_buf->contents = (data_type | FLAG_DATA);
finalise_hdlc_frame(s, FALSE);
}
else
{
/* Just restart using the current frame buffer */
hdlc_buf->contents = 0;
}
/*endif*/
s->core.hdlc_to_modem.len[s->core.hdlc_to_modem.in] = 0;
s->core.hdlc_to_modem.flags[s->core.hdlc_to_modem.in] = 0;
s->core.hdlc_to_modem.contents[s->core.hdlc_to_modem.in] = 0;
queue_missing_indicator(s, T38_DATA_NONE);
xx->current_rx_field_class = T38_FIELD_CLASS_NONE;
}
@@ -1164,6 +1223,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
xx->corrupt_current_frame[0] = FALSE;
break;
case T38_FIELD_HDLC_SIG_END:
hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in];
if (len > 0)
{
span_log(&s->logging, SPAN_LOG_WARNING, "There is data in a T38_FIELD_HDLC_SIG_END!\n");
@@ -1176,8 +1236,11 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */
if (t->current_rx_data_type != data_type || t->current_rx_field_type != field_type)
{
if (s->core.hdlc_to_modem.contents[s->core.hdlc_to_modem.in] != (data_type | FLAG_DATA))
if (hdlc_buf->contents != (data_type | FLAG_DATA))
{
queue_missing_indicator(s, data_type);
hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in];
}
/* WORKAROUND: At least some Mediatrix boxes have a bug, where they can send this message at the
end of non-ECM data. We need to tolerate this. */
if (xx->current_rx_field_class == T38_FIELD_CLASS_NON_ECM)
@@ -1190,10 +1253,12 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
{
/* This message is expected under 2 circumstances. One is as an alternative to T38_FIELD_HDLC_FCS_OK_SIG_END -
i.e. they send T38_FIELD_HDLC_FCS_OK, and then T38_FIELD_HDLC_SIG_END when the carrier actually drops.
The other is because the HDLC signal drops unexpectedly - i.e. not just after a final frame. */
s->core.hdlc_to_modem.len[s->core.hdlc_to_modem.in] = 0;
s->core.hdlc_to_modem.flags[s->core.hdlc_to_modem.in] = 0;
s->core.hdlc_to_modem.contents[s->core.hdlc_to_modem.in] = 0;
The other is because the HDLC signal drops unexpectedly - i.e. not just after a final frame. In
this case we just clear out any partial frame data that might be in the buffer. */
/* TODO: what if any junk in the buffer has reached the HDLC_FLAG_PROCEED_WITH_OUTPUT stage? */
hdlc_buf->len = 0;
hdlc_buf->flags = 0;
hdlc_buf->contents = 0;
}
/*endif*/
queue_missing_indicator(s, T38_DATA_NONE);
@@ -1204,12 +1269,17 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
break;
case T38_FIELD_T4_NON_ECM_DATA:
xx->current_rx_field_class = T38_FIELD_CLASS_NON_ECM;
if (s->core.hdlc_to_modem.contents[s->core.hdlc_to_modem.in] != (data_type | FLAG_DATA))
hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in];
if (hdlc_buf->contents != (data_type | FLAG_DATA))
{
queue_missing_indicator(s, data_type);
hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in];
}
t38_non_ecm_buffer_inject(&s->core.non_ecm_to_modem, buf, len);
xx->corrupt_current_frame[0] = FALSE;
break;
case T38_FIELD_T4_NON_ECM_SIG_END:
hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in];
/* Some T.38 implementations send multiple T38_FIELD_T4_NON_ECM_SIG_END messages, in IFP packets with
incrementing sequence numbers, which are actually repeats. They get through to this point because
of the incrementing sequence numbers. We need to filter them here in a context sensitive manner. */
@@ -1222,14 +1292,20 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
{
if (len > 0)
{
if (s->core.hdlc_to_modem.contents[s->core.hdlc_to_modem.in] != (data_type | FLAG_DATA))
if (hdlc_buf->contents != (data_type | FLAG_DATA))
{
queue_missing_indicator(s, data_type);
hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in];
}
/*endif*/
t38_non_ecm_buffer_inject(&s->core.non_ecm_to_modem, buf, len);
}
/*endif*/
if (s->core.hdlc_to_modem.contents[s->core.hdlc_to_modem.in] != (data_type | FLAG_DATA))
if (hdlc_buf->contents != (data_type | FLAG_DATA))
{
queue_missing_indicator(s, data_type);
hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in];
}
/*endif*/
/* Don't flow control the data any more. Just pump out the remainder as fast as we can. */
t38_non_ecm_buffer_push(&s->core.non_ecm_to_modem);
@@ -1237,12 +1313,16 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
else
{
span_log(&s->logging, SPAN_LOG_WARNING, "T38_FIELD_NON_ECM_SIG_END received at the end of HDLC data!\n");
if (s->core.hdlc_to_modem.contents[s->core.hdlc_to_modem.in] != (data_type | FLAG_DATA))
if (s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in].contents != (data_type | FLAG_DATA))
{
queue_missing_indicator(s, data_type);
hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in];
}
/*endif*/
s->core.hdlc_to_modem.len[s->core.hdlc_to_modem.in] = 0;
s->core.hdlc_to_modem.flags[s->core.hdlc_to_modem.in] = 0;
s->core.hdlc_to_modem.contents[s->core.hdlc_to_modem.in] = 0;
/* TODO: what if any junk in the buffer has reached the HDLC_FLAG_PROCEED_WITH_OUTPUT stage? */
hdlc_buf->len = 0;
hdlc_buf->flags = 0;
hdlc_buf->contents = 0;
}
/*endif*/
queue_missing_indicator(s, T38_DATA_NONE);
@@ -1408,27 +1488,27 @@ static void non_ecm_rx_status(void *user_data, int status)
s = (t38_gateway_state_t *) user_data;
switch (status)
{
case PUTBIT_TRAINING_IN_PROGRESS:
case SIG_STATUS_TRAINING_IN_PROGRESS:
span_log(&s->logging, SPAN_LOG_FLOW, "Non-ECM carrier training in progress\n");
if (s->core.tcf_mode_predictable_modem_start)
s->core.tcf_mode_predictable_modem_start = 0;
else
announce_training(s);
break;
case PUTBIT_TRAINING_FAILED:
case SIG_STATUS_TRAINING_FAILED:
span_log(&s->logging, SPAN_LOG_FLOW, "Non-ECM carrier training failed\n");
break;
case PUTBIT_TRAINING_SUCCEEDED:
case SIG_STATUS_TRAINING_SUCCEEDED:
/* The modem is now trained */
span_log(&s->logging, SPAN_LOG_FLOW, "Non-ECM carrier trained\n");
s->audio.modems.rx_signal_present = TRUE;
s->audio.modems.rx_trained = TRUE;
to_t38_buffer_init(&s->core.to_t38);
break;
case PUTBIT_CARRIER_UP:
case SIG_STATUS_CARRIER_UP:
span_log(&s->logging, SPAN_LOG_FLOW, "Non-ECM carrier up\n");
break;
case PUTBIT_CARRIER_DOWN:
case SIG_STATUS_CARRIER_DOWN:
span_log(&s->logging, SPAN_LOG_FLOW, "Non-ECM carrier down\n");
s->core.tcf_mode_predictable_modem_start = 0;
switch (s->t38x.current_tx_data_type)
@@ -1573,26 +1653,23 @@ static void hdlc_rx_status(hdlc_rx_state_t *t, int status)
t38_gateway_state_t *s;
s = (t38_gateway_state_t *) t->user_data;
span_log(&s->logging, SPAN_LOG_FLOW, "HDLC carrier status is %s (%d)\n", signal_status_to_str(status), status);
switch (status)
{
case PUTBIT_TRAINING_IN_PROGRESS:
span_log(&s->logging, SPAN_LOG_FLOW, "HDLC carrier training in progress\n");
case SIG_STATUS_TRAINING_IN_PROGRESS:
announce_training(s);
break;
case PUTBIT_TRAINING_FAILED:
span_log(&s->logging, SPAN_LOG_FLOW, "HDLC carrier training failed\n");
case SIG_STATUS_TRAINING_FAILED:
break;
case PUTBIT_TRAINING_SUCCEEDED:
case SIG_STATUS_TRAINING_SUCCEEDED:
/* The modem is now trained. */
span_log(&s->logging, SPAN_LOG_FLOW, "HDLC carrier trained\n");
s->audio.modems.rx_signal_present = TRUE;
s->audio.modems.rx_trained = TRUE;
/* Behave like HDLC preamble has been announced. */
t->framing_ok_announced = TRUE;
to_t38_buffer_init(&s->core.to_t38);
break;
case PUTBIT_CARRIER_UP:
span_log(&s->logging, SPAN_LOG_FLOW, "HDLC carrier up\n");
case SIG_STATUS_CARRIER_UP:
/* Reset the HDLC receiver. */
t->raw_bit_stream = 0;
t->len = 0;
@@ -1601,8 +1678,7 @@ static void hdlc_rx_status(hdlc_rx_state_t *t, int status)
t->framing_ok_announced = FALSE;
to_t38_buffer_init(&s->core.to_t38);
break;
case PUTBIT_CARRIER_DOWN:
span_log(&s->logging, SPAN_LOG_FLOW, "HDLC carrier down\n");
case SIG_STATUS_CARRIER_DOWN:
if (t->framing_ok_announced)
{
t38_core_send_data(&s->t38x.t38, s->t38x.current_tx_data_type, T38_FIELD_HDLC_SIG_END, NULL, 0, s->t38x.t38.data_end_tx_count);
+49 -18
View File
@@ -23,7 +23,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t38_non_ecm_buffer.c,v 1.1 2008/08/14 14:06:05 steveu Exp $
* $Id: t38_non_ecm_buffer.c,v 1.3 2008/09/07 12:45:17 steveu Exp $
*/
/*! \file */
@@ -59,6 +59,21 @@
#include "spandsp/t38_non_ecm_buffer.h"
static void restart_buffer(t38_non_ecm_buffer_state_t *s)
{
/* This should be called when draining the buffer is complete, which should
occur before any fresh data can possibly arrive to begin refilling it. */
s->octet = 0xFF;
s->flow_control_fill_octet = 0xFF;
s->at_initial_all_ones = TRUE;
s->bit_stream = 0xFFFF;
s->out_ptr = 0;
s->in_ptr = 0;
s->latest_eol_ptr = 0;
s->data_finished = FALSE;
}
/*- End of function --------------------------------------------------------*/
int t38_non_ecm_buffer_get_bit(void *user_data)
{
t38_non_ecm_buffer_state_t *s;
@@ -80,12 +95,8 @@ int t38_non_ecm_buffer_get_bit(void *user_data)
{
/* The queue is empty, and we have received the end of data signal. This must
really be the end to transmission. */
s->data_finished = FALSE;
/* Reset the data pointers for next time. */
s->out_ptr = 0;
s->in_ptr = 0;
s->latest_eol_ptr = 0;
return PUTBIT_END_OF_DATA;
restart_buffer(s);
return SIG_STATUS_END_OF_DATA;
}
/* The queue is blocked, but this does not appear to be the end of the data. Idle with
fill octets, which should be safe at this point. */
@@ -160,10 +171,11 @@ void t38_non_ecm_buffer_inject(t38_non_ecm_buffer_state_t *s, const uint8_t *buf
rough approach. */
while (s->row_bits < s->min_row_bits)
{
s->min_row_bits_fill_octets++;
s->data[s->in_ptr] = 0;
s->row_bits += 8;
/* TODO: We can't buffer overflow, since we wrap around. However, the tail could overwrite
itself if things fall badly behind. */
/* TODO: We can't buffer overflow, since we wrap around. However, the tail could
overwrite itself if things fall badly behind. */
s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1);
}
/* Start a new row */
@@ -205,28 +217,47 @@ void t38_non_ecm_buffer_inject(t38_non_ecm_buffer_state_t *s, const uint8_t *buf
}
/*- End of function --------------------------------------------------------*/
void t38_non_ecm_buffer_report_status(t38_non_ecm_buffer_state_t *s, logging_state_t *logging)
void t38_non_ecm_buffer_report_input_status(t38_non_ecm_buffer_state_t *s, logging_state_t *logging)
{
if (s->in_octets || s->out_octets)
if (s->in_octets || s->min_row_bits_fill_octets)
{
span_log(logging,
SPAN_LOG_FLOW,
"%d incoming non-ECM octets, %d rows. %d outgoing non-ECM octets, %d rows\n",
"%d+%d incoming non-ECM octets, %d rows.\n",
s->in_octets,
s->in_rows,
s->out_octets,
s->out_rows);
s->min_row_bits_fill_octets,
s->in_rows);
s->in_octets = 0;
s->in_rows = 0;
s->min_row_bits_fill_octets = 0;
}
if (s->flow_control_fill_octets)
}
/*- End of function --------------------------------------------------------*/
void t38_non_ecm_buffer_report_output_status(t38_non_ecm_buffer_state_t *s, logging_state_t *logging)
{
if (s->out_octets || s->flow_control_fill_octets)
{
span_log(logging,
SPAN_LOG_FLOW,
"Non-ECM flow control generated %d octets\n",
s->flow_control_fill_octets);
"%d+%d outgoing non-ECM octets, %d rows.\n",
s->out_octets - s->flow_control_fill_octets,
s->flow_control_fill_octets,
s->out_rows);
s->out_octets = 0;
s->out_rows = 0;
s->flow_control_fill_octets = 0;
}
}
/*- End of function --------------------------------------------------------*/
void t38_non_ecm_buffer_set_mode(t38_non_ecm_buffer_state_t *s, int mode, int min_row_bits)
{
s->image_data_mode = mode;
s->min_row_bits = min_row_bits;
}
/*- End of function --------------------------------------------------------*/
t38_non_ecm_buffer_state_t *t38_non_ecm_buffer_init(t38_non_ecm_buffer_state_t *s, int mode, int min_row_bits)
{
memset(s, 0, sizeof(*s));
+6 -6
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t38_terminal.c,v 1.100 2008/08/13 14:55:51 steveu Exp $
* $Id: t38_terminal.c,v 1.101 2008/09/07 12:45:17 steveu Exp $
*/
/*! \file */
@@ -192,7 +192,7 @@ static int process_rx_indicator(t38_core_state_t *t, void *user_data, int indica
&&
(fe->current_rx_type == T30_MODEM_V21 || fe->current_rx_type == T30_MODEM_CNG))
{
t30_hdlc_accept(&s->t30, NULL, PUTBIT_CARRIER_DOWN, TRUE);
t30_hdlc_accept(&s->t30, NULL, SIG_STATUS_CARRIER_DOWN, TRUE);
}
fe->timeout_rx_samples = 0;
t30_front_end_status(&s->t30, T30_FRONT_END_SIGNAL_ABSENT);
@@ -357,7 +357,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
{
span_log(&s->logging, SPAN_LOG_FLOW, "Type %s - CRC OK, sig end (%s)\n", (fe->hdlc_rx.len >= 3) ? t30_frametype(fe->hdlc_rx.buf[2]) : "???", (fe->rx_data_missing) ? "missing octets" : "clean");
t30_hdlc_accept(&s->t30, fe->hdlc_rx.buf, fe->hdlc_rx.len, !fe->rx_data_missing);
t30_hdlc_accept(&s->t30, NULL, PUTBIT_CARRIER_DOWN, TRUE);
t30_hdlc_accept(&s->t30, NULL, SIG_STATUS_CARRIER_DOWN, TRUE);
}
fe->hdlc_rx.len = 0;
fe->rx_data_missing = FALSE;
@@ -377,7 +377,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
{
span_log(&s->logging, SPAN_LOG_FLOW, "Type %s - CRC bad, sig end (%s)\n", (fe->hdlc_rx.len >= 3) ? t30_frametype(fe->hdlc_rx.buf[2]) : "???", (fe->rx_data_missing) ? "missing octets" : "clean");
t30_hdlc_accept(&s->t30, fe->hdlc_rx.buf, fe->hdlc_rx.len, FALSE);
t30_hdlc_accept(&s->t30, NULL, PUTBIT_CARRIER_DOWN, TRUE);
t30_hdlc_accept(&s->t30, NULL, SIG_STATUS_CARRIER_DOWN, TRUE);
}
fe->hdlc_rx.len = 0;
fe->rx_data_missing = FALSE;
@@ -410,7 +410,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
case T38_FIELD_T4_NON_ECM_DATA:
if (!fe->rx_signal_present)
{
t30_non_ecm_put_bit(&s->t30, PUTBIT_TRAINING_SUCCEEDED);
t30_non_ecm_put_bit(&s->t30, SIG_STATUS_TRAINING_SUCCEEDED);
fe->rx_signal_present = TRUE;
}
bit_reverse(buf2, buf, len);
@@ -427,7 +427,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type,
{
if (!fe->rx_signal_present)
{
t30_non_ecm_put_bit(&s->t30, PUTBIT_TRAINING_SUCCEEDED);
t30_non_ecm_put_bit(&s->t30, SIG_STATUS_TRAINING_SUCCEEDED);
fe->rx_signal_present = TRUE;
}
bit_reverse(buf2, buf, len);
+3 -3
View File
@@ -24,7 +24,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t4.c,v 1.112 2008/07/22 13:48:15 steveu Exp $
* $Id: t4.c,v 1.113 2008/09/07 12:45:17 steveu Exp $
*/
/*
@@ -1963,7 +1963,7 @@ int t4_tx_get_bit(t4_state_t *s)
int bit;
if (s->bit_ptr >= s->image_size)
return PUTBIT_END_OF_DATA;
return SIG_STATUS_END_OF_DATA;
bit = (s->image_buffer[s->bit_ptr] >> (7 - s->bit_pos)) & 1;
if (--s->bit_pos < 0)
{
@@ -1999,7 +1999,7 @@ int t4_tx_check_bit(t4_state_t *s)
int bit;
if (s->bit_ptr >= s->image_size)
return PUTBIT_END_OF_DATA;
return SIG_STATUS_END_OF_DATA;
bit = (s->image_buffer[s->bit_ptr] >> s->bit_pos) & 1;
return bit;
}
+67 -53
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v17rx.c,v 1.112 2008/07/17 19:12:27 steveu Exp $
* $Id: v17rx.c,v 1.116 2008/09/07 12:45:17 steveu Exp $
*/
/*! \file */
@@ -471,44 +471,14 @@ static int decode_baud(v17_rx_state_t *s, complexf_t *z)
}
/*- End of function --------------------------------------------------------*/
static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
static __inline__ void symbol_sync(v17_rx_state_t *s)
{
static const complexf_t cdba[4] =
{
{ 6.0f, 2.0f},
{-2.0f, 6.0f},
{ 2.0f, -6.0f},
{-6.0f, -2.0f}
};
complexf_t z;
complexf_t zz;
#if defined(SPANDSP_USE_FIXED_POINTx)
const complexi_t *target;
#else
const complexf_t *target;
#endif
int i;
float v;
float p;
int bit;
int i;
int j;
int32_t angle;
int32_t ang;
int constellation_state;
/* This routine processes every half a baud, as we put things into the equalizer at the T/2 rate.
This routine adapts the position of the half baud samples, which the caller takes. */
/* This routine adapts the position of the half baud samples entering the equalizer. */
/* Add a sample to the equalizer's circular buffer, but don't calculate anything
at this time. */
s->eq_buf[s->eq_step] = *sample;
s->eq_step = (s->eq_step + 1) & V17_EQUALIZER_MASK;
/* On alternate insertions we have a whole baud and must process it. */
if ((s->baud_half ^= 1))
return;
/* Symbol timing synchronisation */
/* Cross correlate */
v = s->symbol_sync_low[1]*s->symbol_sync_high[1]*SYNC_CROSS_CORR_COEFF_A
+ s->symbol_sync_low[0]*s->symbol_sync_high[1]*SYNC_CROSS_CORR_COEFF_B
@@ -532,6 +502,48 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
s->eq_put_step += i;
s->total_baud_timing_correction += i;
}
}
/*- End of function --------------------------------------------------------*/
static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
{
static const complexf_t cdba[4] =
{
{ 6.0f, 2.0f},
{-2.0f, 6.0f},
{ 2.0f, -6.0f},
{-6.0f, -2.0f}
};
complexf_t z;
complexf_t zz;
#if defined(SPANDSP_USE_FIXED_POINTx)
const complexi_t *target;
static const complexi16_t zero = {0, 0};
#else
const complexf_t *target;
static const complexf_t zero = {0, 0};
#endif
float p;
int bit;
int i;
int j;
int32_t angle;
int32_t ang;
int constellation_state;
/* This routine processes every half a baud, as we put things into the equalizer at the T/2 rate. */
/* Add a sample to the equalizer's circular buffer, but don't calculate anything
at this time. */
s->eq_buf[s->eq_step] = *sample;
s->eq_step = (s->eq_step + 1) & V17_EQUALIZER_MASK;
/* On alternate insertions we have a whole baud and must process it. */
if ((s->baud_half ^= 1))
return;
/* Symbol timing synchronisation */
symbol_sync(s);
z = equalizer_get(s);
@@ -545,7 +557,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
break;
case TRAINING_STAGE_SYMBOL_ACQUISITION:
/* Allow time for the symbol synchronisation to settle the symbol timing. */
target = &z;
target = &zero;
#if defined(IAXMODEM_STUFF)
if (++s->training_count >= 100)
#else
@@ -562,7 +574,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
break;
case TRAINING_STAGE_LOG_PHASE:
/* Record the current alternate phase angle */
target = &z;
target = &zero;
angle = arctan2(z.im, z.re);
s->training_count = 1;
if (s->short_train)
@@ -603,7 +615,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
}
break;
case TRAINING_STAGE_WAIT_FOR_CDBA:
target = &z;
target = &zero;
angle = arctan2(z.im, z.re);
/* Look for the initial ABAB sequence to display a phase reversal, which will
signal the start of the scrambled CDBA segment */
@@ -665,7 +677,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
/* Park this modem */
s->agc_scaling_save = 0.0f;
s->training_stage = TRAINING_STAGE_PARKED;
report_status_change(s, PUTBIT_TRAINING_FAILED);
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
break;
}
@@ -684,7 +696,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
descramble(s, 1);
s->training_count = 1;
s->training_stage = TRAINING_STAGE_COARSE_TRAIN_ON_CDBA;
report_status_change(s, PUTBIT_TRAINING_IN_PROGRESS);
report_status_change(s, SIG_STATUS_TRAINING_IN_PROGRESS);
break;
}
if (++s->training_count > V17_TRAINING_SEG_1_LEN)
@@ -695,7 +707,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
/* Park this modem */
s->agc_scaling_save = 0.0f;
s->training_stage = TRAINING_STAGE_PARKED;
report_status_change(s, PUTBIT_TRAINING_FAILED);
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
}
break;
case TRAINING_STAGE_COARSE_TRAIN_ON_CDBA:
@@ -767,7 +779,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
/* Park this modem */
s->agc_scaling_save = 0.0f;
s->training_stage = TRAINING_STAGE_PARKED;
report_status_change(s, PUTBIT_TRAINING_FAILED);
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
}
}
break;
@@ -806,8 +818,8 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
of a real training sequence. Note that this might be TEP. */
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n");
/* Park this modem */
report_status_change(s, PUTBIT_TRAINING_FAILED);
s->training_stage = TRAINING_STAGE_PARKED;
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
}
break;
case TRAINING_STAGE_SHORT_TRAIN_ON_CDBA_AND_TEST:
@@ -836,14 +848,14 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
{
s->training_count = 0;
s->training_stage = TRAINING_STAGE_TCM_WINDUP;
report_status_change(s, PUTBIT_TRAINING_IN_PROGRESS);
report_status_change(s, SIG_STATUS_TRAINING_IN_PROGRESS);
}
else
{
span_log(&s->logging, SPAN_LOG_FLOW, "Short training failed (convergence failed)\n");
/* Park this modem */
report_status_change(s, PUTBIT_TRAINING_FAILED);
s->training_stage = TRAINING_STAGE_PARKED;
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
}
}
break;
@@ -883,7 +895,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
{
/* We are up and running */
span_log(&s->logging, SPAN_LOG_FLOW, "Training succeeded (constellation mismatch %f)\n", s->training_error);
report_status_change(s, PUTBIT_TRAINING_SUCCEEDED);
report_status_change(s, SIG_STATUS_TRAINING_SUCCEEDED);
/* Apply some lag to the carrier off condition, to ensure the last few bits get pushed through
the processing. */
s->signal_present = 60;
@@ -899,8 +911,8 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
/* Park this modem */
if (!s->short_train)
s->agc_scaling_save = 0.0f;
report_status_change(s, PUTBIT_TRAINING_FAILED);
s->training_stage = TRAINING_STAGE_PARKED;
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
}
}
break;
@@ -908,7 +920,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
default:
/* We failed to train! */
/* Park here until the carrier drops. */
target = &z;
target = &zero;
break;
}
if (s->qam_report)
@@ -979,7 +991,7 @@ int v17_rx(v17_rx_state_t *s, const int16_t amp[], int len)
/* Count down a short delay, to ensure we push the last
few bits through the filters before stopping. */
v17_rx_restart(s, s->bit_rate, s->short_train);
report_status_change(s, PUTBIT_CARRIER_DOWN);
report_status_change(s, SIG_STATUS_CARRIER_DOWN);
continue;
}
#if defined(IAXMODEM_STUFF)
@@ -998,7 +1010,7 @@ int v17_rx(v17_rx_state_t *s, const int16_t amp[], int len)
#if defined(IAXMODEM_STUFF)
s->carrier_drop_pending = FALSE;
#endif
report_status_change(s, PUTBIT_CARRIER_UP);
report_status_change(s, SIG_STATUS_CARRIER_UP);
}
if (s->training_stage == TRAINING_STAGE_PARKED)
continue;
@@ -1051,20 +1063,22 @@ int v17_rx(v17_rx_state_t *s, const int16_t amp[], int len)
for (j = 1; j < V17_RX_FILTER_STEPS; j++)
zi.im += (int32_t) rx_pulseshaper[step][j].im*(int32_t) s->rrc_filter[j + s->rrc_filter_step];
sample.im = zi.im*s->agc_scaling;
s->eq_put_step += RX_PULSESHAPER_COEFF_SETS*10/(3*2);
z = dds_lookup_complexf(s->carrier_phase);
zz.re = sample.re*z.re - sample.im*z.im;
zz.im = -sample.re*z.im - sample.im*z.re;
process_half_baud(s, &zz);
#else
zz.im = rx_pulseshaper[step][0].im*s->rrc_filter[s->rrc_filter_step];
for (j = 1; j < V17_RX_FILTER_STEPS; j++)
zz.im += rx_pulseshaper[step][j].im*s->rrc_filter[j + s->rrc_filter_step];
sample.im = zz.im*s->agc_scaling;
#endif
s->eq_put_step += RX_PULSESHAPER_COEFF_SETS*10/(3*2);
/* Shift to baseband - since this is done in a full complex form, the
result is clean, and requires no further filtering, apart from the
equalizer. */
z = dds_lookup_complexf(s->carrier_phase);
zz.re = sample.re*z.re - sample.im*z.im;
zz.im = -sample.re*z.im - sample.im*z.re;
process_half_baud(s, &zz);
#endif
}
dds_advancef(&(s->carrier_phase), s->carrier_phase_rate);
}
+4 -4
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v17tx.c,v 1.62 2008/07/16 14:23:47 steveu Exp $
* $Id: v17tx.c,v 1.64 2008/09/07 12:45:17 steveu Exp $
*/
/*! \file */
@@ -222,19 +222,19 @@ static __inline__ complexf_t getbaud(v17_tx_state_t *s)
if (s->training_step == V17_TRAINING_SHUTDOWN_END)
{
if (s->status_handler)
s->status_handler(s->status_user_data, MODEM_TX_STATUS_SHUTDOWN_COMPLETE);
s->status_handler(s->status_user_data, SIG_STATUS_SHUTDOWN_COMPLETE);
}
}
}
bits = 0;
for (i = 0; i < s->bits_per_symbol; i++)
{
if ((bit = s->current_get_bit(s->get_bit_user_data)) == PUTBIT_END_OF_DATA)
if ((bit = s->current_get_bit(s->get_bit_user_data)) == SIG_STATUS_END_OF_DATA)
{
/* End of real data. Switch to the fake get_bit routine, until we
have shut down completely. */
if (s->status_handler)
s->status_handler(s->status_user_data, MODEM_TX_STATUS_DATA_EXHAUSTED);
s->status_handler(s->status_user_data, SIG_STATUS_END_OF_DATA);
s->current_get_bit = fake_get_bit;
s->in_training = TRUE;
bit = 1;
+3 -3
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v22bis_rx.c,v 1.40 2008/07/25 13:56:54 steveu Exp $
* $Id: v22bis_rx.c,v 1.41 2008/09/07 12:45:17 steveu Exp $
*/
/*! \file */
@@ -607,7 +607,7 @@ int v22bis_rx(v22bis_state_t *s, const int16_t amp[], int len)
if (power < s->rx.carrier_off_power)
{
v22bis_rx_restart(s, s->bit_rate);
s->put_bit(s->user_data, PUTBIT_CARRIER_DOWN);
s->put_bit(s->user_data, SIG_STATUS_CARRIER_DOWN);
continue;
}
}
@@ -617,7 +617,7 @@ int v22bis_rx(v22bis_state_t *s, const int16_t amp[], int len)
if (power < s->rx.carrier_on_power)
continue;
s->rx.signal_present = TRUE;
s->put_bit(s->user_data, PUTBIT_CARRIER_UP);
s->put_bit(s->user_data, SIG_STATUS_CARRIER_UP);
}
if (s->rx.training != V22BIS_TRAINING_STAGE_PARKED)
{
+2 -2
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v22bis_tx.c,v 1.43 2008/07/02 14:48:26 steveu Exp $
* $Id: v22bis_tx.c,v 1.44 2008/09/07 12:45:17 steveu Exp $
*/
/*! \file */
@@ -302,7 +302,7 @@ static __inline__ int get_scrambled_bit(v22bis_state_t *s)
{
int bit;
if ((bit = s->tx.current_get_bit(s->user_data)) == PUTBIT_END_OF_DATA)
if ((bit = s->tx.current_get_bit(s->user_data)) == SIG_STATUS_END_OF_DATA)
{
/* Fill out this symbol with ones, and prepare to send
the rest of the shutdown sequence. */
+217 -47
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v27ter_rx.c,v 1.97 2008/08/04 14:03:17 steveu Exp $
* $Id: v27ter_rx.c,v 1.101 2008/09/08 13:13:29 steveu Exp $
*/
/*! \file */
@@ -48,6 +48,8 @@
#include "spandsp/complex.h"
#include "spandsp/vector_float.h"
#include "spandsp/complex_vector_float.h"
#include "spandsp/vector_int.h"
#include "spandsp/complex_vector_int.h"
#include "spandsp/async.h"
#include "spandsp/power_meter.h"
#include "spandsp/arctan2.h"
@@ -72,6 +74,11 @@
#define CARRIER_NOMINAL_FREQ 1800.0f
#define EQUALIZER_DELTA 0.25f
#if defined(SPANDSP_USE_FIXED_POINT)
#define FP_FACTOR 4096
#define FP_SHIFT_FACTOR 12
#endif
/* Segments of the training sequence */
/* V.27ter defines a long and a short sequence. FAX doesn't use the
short sequence, so it is not implemented here. */
@@ -90,17 +97,31 @@ enum
TRAINING_STAGE_PARKED
};
#if defined(SPANDSP_USE_FIXED_POINTx)
static const complexi16_t v27ter_constellation[8] =
{
{((int)(FP_FACTOR* 1.414f), ((int)(FP_FACTOR* 0.0f)}, /* 0deg */
{((int)(FP_FACTOR* 1.0f), ((int)(FP_FACTOR* 1.0f)}, /* 45deg */
{((int)(FP_FACTOR* 0.0f), ((int)(FP_FACTOR* 1.414f)}, /* 90deg */
{((int)(FP_FACTOR*-1.0f), ((int)(FP_FACTOR* 1.0f)}, /* 135deg */
{((int)(FP_FACTOR*-1.414f), ((int)(FP_FACTOR* 0.0f)}, /* 180deg */
{((int)(FP_FACTOR*-1.0f), ((int)(FP_FACTOR*-1.0f)}, /* 225deg */
{((int)(FP_FACTOR* 0.0f), ((int)(FP_FACTOR*-1.414f)}, /* 270deg */
{((int)(FP_FACTOR* 1.0f), ((int)(FP_FACTOR*-1.0f)} /* 315deg */
};
#else
static const complexf_t v27ter_constellation[8] =
{
{ 1.414f, 0.0f}, /* 0deg */
{ 1.0f, 1.0f}, /* 45deg */
{ 0.0f, 1.414f}, /* 90deg */
{-1.0f, 1.0f}, /* 135deg */
{-1.414f, 0.0f}, /* 180deg */
{-1.0f, -1.0f}, /* 225deg */
{ 0.0f, -1.414f}, /* 270deg */
{ 1.0f, -1.0f} /* 315deg */
{ 1.414f, 0.0f}, /* 0deg */
{ 1.0f, 1.0f}, /* 45deg */
{ 0.0f, 1.414f}, /* 90deg */
{-1.0f, 1.0f}, /* 135deg */
{-1.414f, 0.0f}, /* 180deg */
{-1.0f, -1.0f}, /* 225deg */
{ 0.0f, -1.414f}, /* 270deg */
{ 1.0f, -1.0f} /* 315deg */
};
#endif
float v27ter_rx_carrier_frequency(v27ter_rx_state_t *s)
{
@@ -149,14 +170,23 @@ static void report_status_change(v27ter_rx_state_t *s, int status)
static void equalizer_save(v27ter_rx_state_t *s)
{
#if defined(SPANDSP_USE_FIXED_POINTx)
cvec_copyi16(s->eq_coeff_save, s->eq_coeff, V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN);
#else
cvec_copyf(s->eq_coeff_save, s->eq_coeff, V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN);
#endif
}
/*- End of function --------------------------------------------------------*/
static void equalizer_restore(v27ter_rx_state_t *s)
{
#if defined(SPANDSP_USE_FIXED_POINTx)
cvec_copyi16(s->eq_coeff, s->eq_coeff_save, V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN);
cvec_zeroi16(s->eq_buf, V27TER_EQUALIZER_MASK);
#else
cvec_copyf(s->eq_coeff, s->eq_coeff_save, V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN);
cvec_zerof(s->eq_buf, V27TER_EQUALIZER_MASK);
#endif
s->eq_put_step = (s->bit_rate == 4800) ? RX_PULSESHAPER_4800_COEFF_SETS*5/2 : RX_PULSESHAPER_2400_COEFF_SETS*20/(3*2);
s->eq_step = 0;
@@ -166,10 +196,16 @@ static void equalizer_restore(v27ter_rx_state_t *s)
static void equalizer_reset(v27ter_rx_state_t *s)
{
/* Start with an equalizer based on everything being perfect */
/* Start with an equalizer based on everything being perfect. */
#if defined(SPANDSP_USE_FIXED_POINTx)
cvec_zeroi16(s->eq_coeff, V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN);
s->eq_coeff[V27TER_EQUALIZER_PRE_LEN] = complex_seti16(1.414f*FP_FACTOR, 0);
cvec_zeroi16(s->eq_buf, V27TER_EQUALIZER_MASK);
#else
cvec_zerof(s->eq_coeff, V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN);
s->eq_coeff[V27TER_EQUALIZER_PRE_LEN] = complex_setf(1.414f, 0.0f);
cvec_zerof(s->eq_buf, V27TER_EQUALIZER_MASK);
#endif
s->eq_put_step = (s->bit_rate == 4800) ? RX_PULSESHAPER_4800_COEFF_SETS*5/2 : RX_PULSESHAPER_2400_COEFF_SETS*20/(3*2);
s->eq_step = 0;
@@ -177,60 +213,122 @@ static void equalizer_reset(v27ter_rx_state_t *s)
}
/*- End of function --------------------------------------------------------*/
#if defined(SPANDSP_USE_FIXED_POINTx)
static __inline__ complexi16_t complex_mul_q4_12(const complexi16_t *x, const complexi16_t *y)
{
complexi16_t z;
z.re = ((int32_t) x->re*(int32_t) y->re - (int32_t) x->im*(int32_t) y->im) >> 12;
z.im = ((int32_t) x->re*(int32_t) y->im + (int32_t) x->im*(int32_t) y->re) >> 12;
return z;
}
/*- End of function --------------------------------------------------------*/
#endif
#if defined(SPANDSP_USE_FIXED_POINTx)
static __inline__ complexi16_t equalizer_get(v27ter_rx_state_t *s)
#else
static __inline__ complexf_t equalizer_get(v27ter_rx_state_t *s)
#endif
{
int i;
int p;
#if defined(SPANDSP_USE_FIXED_POINTx)
complexi16_t z;
complexi16_t z1;
#else
complexf_t z;
complexf_t z1;
#endif
/* Get the next equalized value. */
z = complex_setf(0.0f, 0.0f);
p = s->eq_step - 1;
#if defined(SPANDSP_USE_FIXED_POINTx)
z = complex_seti16(0, 0);
for (i = 0; i < V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN; i++)
{
p = (p - 1) & V27TER_EQUALIZER_MASK;
z1 = complex_mul_q4_12(&s->eq_coeff[i], &s->eq_buf[p]);
z = complex_addi16(&z, &z1);
}
#else
z = complex_setf(0.0f, 0.0f);
for (i = 0; i < V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN; i++)
{
p = (p - 1) & V27TER_EQUALIZER_MASK;
z1 = complex_mulf(&s->eq_coeff[i], &s->eq_buf[p]);
z = complex_addf(&z, &z1);
}
#endif
return z;
}
/*- End of function --------------------------------------------------------*/
#if defined(SPANDSP_USE_FIXED_POINTx)
static void tune_equalizer(v27ter_rx_state_t *s, const complexi16_t *z, const complexi16_t *target)
#else
static void tune_equalizer(v27ter_rx_state_t *s, const complexf_t *z, const complexf_t *target)
#endif
{
int i;
int p;
#if defined(SPANDSP_USE_FIXED_POINTx)
complexi16_t ez;
complexi16_t z1;
#else
complexf_t ez;
complexf_t z1;
#endif
/* Find the x and y mismatch from the exact constellation position. */
#if defined(SPANDSP_USE_FIXED_POINTx)
ez.re = target->re*FP_FACTOR - z->re;
ez.im = target->im*FP_FACTOR - z->im;
ez.re = ((int32_t) ez.re*(int32_t) s->eq_delta) >> 15;
ez.im = ((int32_t) ez.im*(int32_t) s->eq_delta) >> 15;
#else
ez = complex_subf(target, z);
ez.re *= s->eq_delta;
ez.im *= s->eq_delta;
#endif
p = s->eq_step - 1;
for (i = 0; i < V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN; i++)
{
p = (p - 1) & V27TER_EQUALIZER_MASK;
#if defined(SPANDSP_USE_FIXED_POINTx)
z1 = complex_conji16(&s->eq_buf[p]);
z1 = complex_mul_q4_12(&ez, &z1);
s->eq_coeff[i] = complex_addi16(&s->eq_coeff[i], &z1);
#else
z1 = complex_conjf(&s->eq_buf[p]);
z1 = complex_mulf(&ez, &z1);
s->eq_coeff[i] = complex_addf(&s->eq_coeff[i], &z1);
/* Leak a little to tame uncontrolled wandering */
s->eq_coeff[i].re *= 0.9999f;
s->eq_coeff[i].im *= 0.9999f;
#endif
}
}
/*- End of function --------------------------------------------------------*/
#if defined(SPANDSP_USE_FIXED_POINTx)
static __inline__ void track_carrier(v27ter_rx_state_t *s, const complexi16_t *z, const complexi16_t *target)
#else
static __inline__ void track_carrier(v27ter_rx_state_t *s, const complexf_t *z, const complexf_t *target)
#endif
{
float error;
/* For small errors the imaginary part of the difference between the actual and the target
positions is proportional to the phase error, for any particular target. However, the
different amplitudes of the various target positions scale things. */
#if defined(SPANDSP_USE_FIXED_POINTx)
error = z->im*target->re - z->re*target->im;
error /= (float) FP_FACTOR;
#else
error = z->im*target->re - z->re*target->im;
#endif
s->carrier_phase_rate += (int32_t) (s->carrier_track_i*error);
s->carrier_phase += (int32_t) (s->carrier_track_p*error);
@@ -295,7 +393,11 @@ static __inline__ void put_bit(v27ter_rx_state_t *s, int bit)
}
/*- End of function --------------------------------------------------------*/
#if defined(SPANDSP_USE_FIXED_POINTx)
static __inline__ int find_quadrant(const complexi16_t *z)
#else
static __inline__ int find_quadrant(const complexf_t *z)
#endif
{
int b1;
int b2;
@@ -307,7 +409,11 @@ static __inline__ int find_quadrant(const complexf_t *z)
}
/*- End of function --------------------------------------------------------*/
#if defined(SPANDSP_USE_FIXED_POINTx)
static __inline__ int find_octant(complexi16_t *z)
#else
static __inline__ int find_octant(complexf_t *z)
#endif
{
float abs_re;
float abs_im;
@@ -336,7 +442,11 @@ static __inline__ int find_octant(complexf_t *z)
}
/*- End of function --------------------------------------------------------*/
#if defined(SPANDSP_USE_FIXED_POINTx)
static void decode_baud(v27ter_rx_state_t *s, complexi16_t *z)
#else
static void decode_baud(v27ter_rx_state_t *s, complexf_t *z)
#endif
{
static const uint8_t phase_steps_4800[8] =
{
@@ -381,33 +491,12 @@ static void decode_baud(v27ter_rx_state_t *s, complexf_t *z)
}
/*- End of function --------------------------------------------------------*/
static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexf_t *sample)
static __inline__ void symbol_sync(v27ter_rx_state_t *s)
{
static const int abab_pos[2] =
{
0, 4
};
complexf_t z;
complexf_t zz;
float p;
float q;
int i;
int j;
int32_t angle;
int32_t ang;
/* Add a sample to the equalizer's circular buffer, but don't calculate anything
at this time. */
s->eq_buf[s->eq_step] = *sample;
s->eq_step = (s->eq_step + 1) & V27TER_EQUALIZER_MASK;
/* On alternate insertions we have a whole baud, and must process it. */
if ((s->baud_phase ^= 1))
{
//span_log(&s->logging, SPAN_LOG_FLOW, "Samp, %f, %f, %f, -1, 0x%X\n", z.re, z.im, sqrtf(z.re*z.re + z.im*z.im), s->eq_put_step);
return;
}
//span_log(&s->logging, SPAN_LOG_FLOW, "Samp, %f, %f, %f, 1, 0x%X\n", z.re, z.im, sqrtf(z.re*z.re + z.im*z.im), s->eq_put_step);
/* This routine adapts the position of the half baud samples entering the equalizer. */
/* Perform a Gardner test for baud alignment */
p = s->eq_buf[(s->eq_step - 3) & V27TER_EQUALIZER_MASK].re
@@ -433,6 +522,37 @@ static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexf_t
s->gardner_integrate = 0;
}
//span_log(&s->logging, SPAN_LOG_FLOW, "Gardner=%10.5f 0x%X\n", p, s->eq_put_step);
}
/*- End of function --------------------------------------------------------*/
#if defined(SPANDSP_USE_FIXED_POINTx)
static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexi16_t *sample)
#else
static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexf_t *sample)
#endif
{
static const int abab_pos[2] =
{
0, 4
};
complexf_t z;
complexf_t zz;
float p;
int i;
int j;
int32_t angle;
int32_t ang;
/* Add a sample to the equalizer's circular buffer, but don't calculate anything
at this time. */
s->eq_buf[s->eq_step] = *sample;
s->eq_step = (s->eq_step + 1) & V27TER_EQUALIZER_MASK;
/* On alternate insertions we have a whole baud, and must process it. */
if ((s->baud_half ^= 1))
return;
symbol_sync(s);
z = equalizer_get(s);
@@ -498,7 +618,7 @@ static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexf_t
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n");
/* Park this modem */
s->training_stage = TRAINING_STAGE_PARKED;
report_status_change(s, PUTBIT_TRAINING_FAILED);
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
break;
}
@@ -506,9 +626,20 @@ static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexf_t
buffer, as well as the carrier phase, for this to play out nicely. */
angle += 0x80000000;
p = angle*2.0f*3.14159f/(65536.0f*65536.0f);
#if defined(SPANDSP_USE_FIXED_POINTx)
zz = complex_setf(cosf(p), -sinf(p));
for (i = 0; i <= V27TER_EQUALIZER_MASK; i++)
{
z1 = complex_setf(s->eq_buf[i].re, s->eq_buf[i].im);
z1 = complex_mulf(&z1, &zz);
s->eq_buf[i].re = z1.re;
s->eq_buf[i].im = z1.im;
}
#else
zz = complex_setf(cosf(p), -sinf(p));
for (i = 0; i <= V27TER_EQUALIZER_MASK; i++)
s->eq_buf[i] = complex_mulf(&s->eq_buf[i], &zz);
#endif
s->carrier_phase += angle;
s->gardner_step = 2;
@@ -519,7 +650,7 @@ static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexf_t
descramble(s, 1);
s->training_count = 1;
s->training_stage = TRAINING_STAGE_TRAIN_ON_ABAB;
report_status_change(s, PUTBIT_TRAINING_IN_PROGRESS);
report_status_change(s, SIG_STATUS_TRAINING_IN_PROGRESS);
}
else if (++s->training_count > V27TER_TRAINING_SEG_3_LEN)
{
@@ -528,7 +659,7 @@ static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexf_t
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n");
/* Park this modem */
s->training_stage = TRAINING_STAGE_PARKED;
report_status_change(s, PUTBIT_TRAINING_FAILED);
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
}
break;
case TRAINING_STAGE_TRAIN_ON_ABAB:
@@ -552,11 +683,22 @@ static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexf_t
case TRAINING_STAGE_TEST_ONES:
decode_baud(s, &z);
/* Measure the training error */
#if defined(SPANDSP_USE_FIXED_POINTx)
z1.re = z.re/(float) FP_FACTOR;
z1.im = z.im/(float) FP_FACTOR;
if (s->bit_rate == 4800)
zz = complex_subf(&z, &v27ter_constellation[s->constellation_state]);
else
zz = complex_subf(&z, &v27ter_constellation[s->constellation_state << 1]);
zz = complex_subf(&z1, &zz);
s->training_error += powerf(&zz);
#else
if (s->bit_rate == 4800)
zz = complex_subf(&z, &v27ter_constellation[s->constellation_state]);
else
zz = complex_subf(&z, &v27ter_constellation[s->constellation_state << 1]);
s->training_error += powerf(&zz);
#endif
if (++s->training_count >= V27TER_TRAINING_SEG_6_LEN)
{
if ((s->bit_rate == 4800 && s->training_error < 0.5f)
@@ -565,7 +707,7 @@ static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexf_t
{
/* We are up and running */
span_log(&s->logging, SPAN_LOG_FLOW, "Training succeeded (constellation mismatch %f)\n", s->training_error);
report_status_change(s, PUTBIT_TRAINING_SUCCEEDED);
report_status_change(s, SIG_STATUS_TRAINING_SUCCEEDED);
/* Apply some lag to the carrier off condition, to ensure the last few bits get pushed through
the processing. */
s->signal_present = (s->bit_rate == 4800) ? 90 : 120;
@@ -580,7 +722,7 @@ static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexf_t
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (constellation mismatch %f)\n", s->training_error);
/* Park this modem */
s->training_stage = TRAINING_STAGE_PARKED;
report_status_change(s, PUTBIT_TRAINING_FAILED);
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
}
}
break;
@@ -591,10 +733,21 @@ static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexf_t
}
if (s->qam_report)
{
#if defined(SPANDSP_USE_FIXED_POINTx)
z1.re = z.re/(float) FP_FACTOR;
z1.im = z.im/(float) FP_FACTOR;
zz.re = v27ter_constellation[s->constellation_state].re;
zz.im = v27ter_constellation[s->constellation_state].im;
s->qam_report(s->qam_user_data,
&z1,
&zz,
s->constellation_state);
#else
s->qam_report(s->qam_user_data,
&z,
&v27ter_constellation[s->constellation_state],
s->constellation_state);
#endif
}
}
/*- End of function --------------------------------------------------------*/
@@ -607,10 +760,15 @@ int v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], int len)
int16_t x;
int32_t diff;
complexf_t z;
complexf_t zz;
complexf_t sample;
#if defined(SPANDSP_USE_FIXED_POINT)
complexi_t zi;
#endif
#if defined(SPANDSP_USE_FIXED_POINTx)
complexi16_t sample;
complexi16_t zz;
#else
complexf_t sample;
complexf_t zz;
#endif
int32_t power;
@@ -664,7 +822,7 @@ int v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], int len)
/* Count down a short delay, to ensure we push the last
few bits through the filters before stopping. */
v27ter_rx_restart(s, s->bit_rate, FALSE);
report_status_change(s, PUTBIT_CARRIER_DOWN);
report_status_change(s, SIG_STATUS_CARRIER_DOWN);
continue;
}
#if defined(IAXMODEM_STUFF)
@@ -683,7 +841,7 @@ int v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], int len)
#if defined(IAXMODEM_STUFF)
s->carrier_drop_pending = FALSE;
#endif
report_status_change(s, PUTBIT_CARRIER_UP);
report_status_change(s, SIG_STATUS_CARRIER_UP);
}
/* Only spend effort processing this data if the modem is not
parked, after training failure. */
@@ -697,7 +855,11 @@ int v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], int len)
if (s->training_stage == TRAINING_STAGE_SYMBOL_ACQUISITION)
{
/* Only AGC during the initial training */
#if defined(SPANDSP_USE_FIXED_POINTx)
s->agc_scaling = (float) FP_FACTOR*(1.0f/RX_PULSESHAPER_4800_GAIN)*1.414f/sqrtf(power);
#else
s->agc_scaling = (1.0f/RX_PULSESHAPER_4800_GAIN)*1.414f/sqrtf(power);
#endif
}
/* Pulse shape while still at the carrier frequency, using a quadrature
pair of filters. This results in a properly bandpass filtered complex
@@ -789,7 +951,7 @@ int v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], int len)
/* Count down a short delay, to ensure we push the last
few bits through the filters before stopping. */
v27ter_rx_restart(s, s->bit_rate, FALSE);
report_status_change(s, PUTBIT_CARRIER_DOWN);
report_status_change(s, SIG_STATUS_CARRIER_DOWN);
continue;
}
#if defined(IAXMODEM_STUFF)
@@ -808,7 +970,7 @@ int v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], int len)
#if defined(IAXMODEM_STUFF)
s->carrier_drop_pending = FALSE;
#endif
report_status_change(s, PUTBIT_CARRIER_UP);
report_status_change(s, SIG_STATUS_CARRIER_UP);
}
/* Only spend effort processing this data if the modem is not
parked, after training failure. */
@@ -822,7 +984,11 @@ int v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], int len)
if (s->training_stage == TRAINING_STAGE_SYMBOL_ACQUISITION)
{
/* Only AGC during the initial training */
#if defined(SPANDSP_USE_FIXED_POINTx)
s->agc_scaling = (float) FP_FACTOR*(1.0f/RX_PULSESHAPER_2400_GAIN)*1.414f/sqrtf(power);
#else
s->agc_scaling = (1.0f/RX_PULSESHAPER_2400_GAIN)*1.414f/sqrtf(power);
#endif
}
/* Pulse shape while still at the carrier frequency, using a quadrature
pair of filters. This results in a properly bandpass filtered complex
@@ -890,7 +1056,7 @@ int v27ter_rx_restart(v27ter_rx_state_t *s, int bit_rate, int old_train)
s->bit_rate = bit_rate;
#if defined(SPANDSP_USE_FIXED_POINT)
memset(s->rrc_filter, 0, sizeof(s->rrc_filter));
vec_zeroi16(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
#else
vec_zerof(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
#endif
@@ -925,7 +1091,11 @@ int v27ter_rx_restart(v27ter_rx_state_t *s, int bit_rate, int old_train)
else
{
s->carrier_phase_rate = dds_phase_ratef(CARRIER_NOMINAL_FREQ);
#if defined(SPANDSP_USE_FIXED_POINTx)
s->agc_scaling = (float) FP_FACTOR*0.005f/RX_PULSESHAPER_4800_GAIN;
#else
s->agc_scaling = 0.005f/RX_PULSESHAPER_4800_GAIN;
#endif
equalizer_reset(s);
}
s->eq_skip = 0;
@@ -934,7 +1104,7 @@ int v27ter_rx_restart(v27ter_rx_state_t *s, int bit_rate, int old_train)
s->gardner_integrate = 0;
s->total_baud_timing_correction = 0;
s->gardner_step = 512;
s->baud_phase = 0;
s->baud_half = 0;
return 0;
}
+4 -4
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v27ter_tx.c,v 1.64 2008/07/16 14:23:47 steveu Exp $
* $Id: v27ter_tx.c,v 1.66 2008/09/07 12:45:17 steveu Exp $
*/
/*! \file */
@@ -108,12 +108,12 @@ static __inline__ int get_scrambled_bit(v27ter_tx_state_t *s)
{
int bit;
if ((bit = s->current_get_bit(s->get_bit_user_data)) == PUTBIT_END_OF_DATA)
if ((bit = s->current_get_bit(s->get_bit_user_data)) == SIG_STATUS_END_OF_DATA)
{
/* End of real data. Switch to the fake get_bit routine, until we
have shut down completely. */
if (s->status_handler)
s->status_handler(s->status_user_data, MODEM_TX_STATUS_DATA_EXHAUSTED);
s->status_handler(s->status_user_data, SIG_STATUS_END_OF_DATA);
s->current_get_bit = fake_get_bit;
s->in_training = TRUE;
bit = 1;
@@ -212,7 +212,7 @@ static complexf_t getbaud(v27ter_tx_state_t *s)
if (s->training_step == V27TER_TRAINING_SHUTDOWN_END)
{
if (s->status_handler)
s->status_handler(s->status_user_data, MODEM_TX_STATUS_SHUTDOWN_COMPLETE);
s->status_handler(s->status_user_data, SIG_STATUS_SHUTDOWN_COMPLETE);
}
}
/* 4800bps uses 8 phases. 2400bps uses 4 phases. */
+344 -129
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v29rx.c,v 1.124 2008/07/17 19:12:27 steveu Exp $
* $Id: v29rx.c,v 1.135 2008/09/09 16:13:12 steveu Exp $
*/
/*! \file */
@@ -48,6 +48,8 @@
#include "spandsp/complex.h"
#include "spandsp/vector_float.h"
#include "spandsp/complex_vector_float.h"
#include "spandsp/vector_int.h"
#include "spandsp/complex_vector_int.h"
#include "spandsp/async.h"
#include "spandsp/power_meter.h"
#include "spandsp/arctan2.h"
@@ -67,6 +69,11 @@
#define BAUD_RATE 2400
#define EQUALIZER_DELTA 0.21f
#if defined(SPANDSP_USE_FIXED_POINT)
#define FP_FACTOR 4096
#define FP_SHIFT_FACTOR 12
#endif
/* Segments of the training sequence */
#define V29_TRAINING_SEG_2_LEN 128
#define V29_TRAINING_SEG_3_LEN 384
@@ -109,13 +116,23 @@ static const uint8_t space_map_9600[20][20] =
};
/* Coefficients for the band edge symbol timing synchroniser (alpha = 0.99) */
#define SYNC_LOW_BAND_EDGE_COEFF_0 1.829281f /* 2*alpha*cos(low_edge) */
#define SYNC_LOW_BAND_EDGE_COEFF_1 -0.980100f /* -alpha^2 */
#define SYNC_HIGH_BAND_EDGE_COEFF_0 -1.285907f /* 2*alpha*cos(high_edge) */
#define SYNC_HIGH_BAND_EDGE_COEFF_1 -0.980100f /* -alpha^2 */
#define SYNC_CROSS_CORR_COEFF_A -0.932131f /* -alpha^2*sin(freq_diff) */
#define SYNC_CROSS_CORR_COEFF_B 0.752802f /* alpha*sin(high_edge) */
#define SYNC_CROSS_CORR_COEFF_C -0.378857f /* -alpha*sin(low_edge) */
#if defined(SPANDSP_USE_FIXED_POINT)
#define SYNC_LOW_BAND_EDGE_COEFF_0 ((int)(FP_FACTOR* 1.829281f)) /* 2*alpha*cos(low_edge) */
#define SYNC_LOW_BAND_EDGE_COEFF_1 ((int)(FP_FACTOR*-0.980100f)) /* -alpha^2 */
#define SYNC_HIGH_BAND_EDGE_COEFF_0 ((int)(FP_FACTOR*-1.285907f)) /* 2*alpha*cos(high_edge) */
#define SYNC_HIGH_BAND_EDGE_COEFF_1 ((int)(FP_FACTOR*-0.980100f)) /* -alpha^2 */
#define SYNC_CROSS_CORR_COEFF_A ((int)(FP_FACTOR*-0.932131f)) /* -alpha^2*sin(freq_diff) */
#define SYNC_CROSS_CORR_COEFF_B ((int)(FP_FACTOR* 0.752802f)) /* alpha*sin(high_edge) */
#define SYNC_CROSS_CORR_COEFF_C ((int)(FP_FACTOR*-0.378857f)) /* -alpha*sin(low_edge) */
#else
#define SYNC_LOW_BAND_EDGE_COEFF_0 1.829281f /* 2*alpha*cos(low_edge) */
#define SYNC_LOW_BAND_EDGE_COEFF_1 -0.980100f /* -alpha^2 */
#define SYNC_HIGH_BAND_EDGE_COEFF_0 -1.285907f /* 2*alpha*cos(high_edge) */
#define SYNC_HIGH_BAND_EDGE_COEFF_1 -0.980100f /* -alpha^2 */
#define SYNC_CROSS_CORR_COEFF_A -0.932131f /* -alpha^2*sin(freq_diff) */
#define SYNC_CROSS_CORR_COEFF_B 0.752802f /* alpha*sin(high_edge) */
#define SYNC_CROSS_CORR_COEFF_C -0.378857f /* -alpha*sin(low_edge) */
#endif
float v29_rx_carrier_frequency(v29_rx_state_t *s)
{
@@ -143,19 +160,17 @@ float v29_rx_signal_power(v29_rx_state_t *s)
}
/*- End of function --------------------------------------------------------*/
#if defined(SPANDSP_USE_FIXED_POINT)
int v29_rx_equalizer_state(v29_rx_state_t *s, complexi16_t **coeffs)
#else
int v29_rx_equalizer_state(v29_rx_state_t *s, complexf_t **coeffs)
#endif
{
*coeffs = s->eq_coeff;
return V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN;
}
/*- End of function --------------------------------------------------------*/
static void equalizer_save(v29_rx_state_t *s)
{
cvec_copyf(s->eq_coeff_save, s->eq_coeff, V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN);
}
/*- End of function --------------------------------------------------------*/
static void report_status_change(v29_rx_state_t *s, int status)
{
if (s->status_handler)
@@ -165,51 +180,105 @@ static void report_status_change(v29_rx_state_t *s, int status)
}
/*- End of function --------------------------------------------------------*/
static void equalizer_save(v29_rx_state_t *s)
{
#if defined(SPANDSP_USE_FIXED_POINT)
cvec_copyi16(s->eq_coeff_save, s->eq_coeff, V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN);
#else
cvec_copyf(s->eq_coeff_save, s->eq_coeff, V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN);
#endif
}
/*- End of function --------------------------------------------------------*/
static void equalizer_restore(v29_rx_state_t *s)
{
#if defined(SPANDSP_USE_FIXED_POINT)
cvec_copyi16(s->eq_coeff, s->eq_coeff_save, V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN);
cvec_zeroi16(s->eq_buf, V29_EQUALIZER_MASK);
s->eq_delta = 32768.0f*EQUALIZER_DELTA/(V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN);
#else
cvec_copyf(s->eq_coeff, s->eq_coeff_save, V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN);
cvec_zerof(s->eq_buf, V29_EQUALIZER_MASK);
s->eq_delta = EQUALIZER_DELTA/(V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN);
#endif
s->eq_put_step = RX_PULSESHAPER_COEFF_SETS*10/(3*2) - 1;
s->eq_step = 0;
s->eq_delta = EQUALIZER_DELTA/(V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN);
}
/*- End of function --------------------------------------------------------*/
static void equalizer_reset(v29_rx_state_t *s)
{
/* Start with an equalizer based on everything being perfect */
#if defined(SPANDSP_USE_FIXED_POINT)
cvec_zeroi16(s->eq_coeff, V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN);
s->eq_coeff[V29_EQUALIZER_PRE_LEN] = complex_seti16(3*FP_FACTOR, 0*FP_FACTOR);
cvec_zeroi16(s->eq_buf, V29_EQUALIZER_MASK);
s->eq_delta = 32768.0f*EQUALIZER_DELTA/(V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN);
#else
cvec_zerof(s->eq_coeff, V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN);
s->eq_coeff[V29_EQUALIZER_PRE_LEN] = complex_setf(3.0f, 0.0f);
cvec_zerof(s->eq_buf, V29_EQUALIZER_MASK);
s->eq_delta = EQUALIZER_DELTA/(V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN);
#endif
s->eq_put_step = RX_PULSESHAPER_COEFF_SETS*10/(3*2) - 1;
s->eq_step = 0;
s->eq_delta = EQUALIZER_DELTA/(V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN);
}
/*- End of function --------------------------------------------------------*/
#if defined(SPANDSP_USE_FIXED_POINT)
static __inline__ complexi16_t complex_mul_q4_12(const complexi16_t *x, const complexi16_t *y)
{
complexi16_t z;
z.re = ((int32_t) x->re*(int32_t) y->re - (int32_t) x->im*(int32_t) y->im) >> 12;
z.im = ((int32_t) x->re*(int32_t) y->im + (int32_t) x->im*(int32_t) y->re) >> 12;
return z;
}
/*- End of function --------------------------------------------------------*/
#endif
#if defined(SPANDSP_USE_FIXED_POINT)
static __inline__ complexi16_t equalizer_get(v29_rx_state_t *s)
#else
static __inline__ complexf_t equalizer_get(v29_rx_state_t *s)
#endif
{
int i;
int p;
#if defined(SPANDSP_USE_FIXED_POINT)
complexi16_t z;
complexi16_t z1;
#else
complexf_t z;
complexf_t z1;
#endif
/* Get the next equalized value. */
z = complex_setf(0.0f, 0.0f);
p = s->eq_step - 1;
#if defined(SPANDSP_USE_FIXED_POINT)
z = complex_seti16(0, 0);
for (i = 0; i < V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN; i++)
{
p = (p - 1) & V29_EQUALIZER_MASK;
z1 = complex_mul_q4_12(&s->eq_coeff[i], &s->eq_buf[p]);
z = complex_addi16(&z, &z1);
}
#else
z = complex_setf(0.0f, 0.0f);
for (i = 0; i < V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN; i++)
{
p = (p - 1) & V29_EQUALIZER_MASK;
z1 = complex_mulf(&s->eq_coeff[i], &s->eq_buf[p]);
z = complex_addf(&z, &z1);
}
#endif
return z;
}
/*- End of function --------------------------------------------------------*/
#if defined(SPANDSP_USE_FIXED_POINTy)
#if defined(SPANDSP_USE_FIXED_POINT)
static void tune_equalizer(v29_rx_state_t *s, const complexi16_t *z, const complexi16_t *target)
#else
static void tune_equalizer(v29_rx_state_t *s, const complexf_t *z, const complexf_t *target)
@@ -217,24 +286,42 @@ static void tune_equalizer(v29_rx_state_t *s, const complexf_t *z, const complex
{
int i;
int p;
#if defined(SPANDSP_USE_FIXED_POINT)
complexi16_t ez;
complexi16_t z1;
#else
complexf_t ez;
complexf_t z1;
#endif
/* Find the x and y mismatch from the exact constellation position. */
#if defined(SPANDSP_USE_FIXED_POINT)
ez.re = target->re*FP_FACTOR - z->re;
ez.im = target->im*FP_FACTOR - z->im;
ez.re = ((int32_t) ez.re*(int32_t) s->eq_delta) >> 15;
ez.im = ((int32_t) ez.im*(int32_t) s->eq_delta) >> 15;
#else
ez = complex_subf(target, z);
ez.re *= s->eq_delta;
ez.im *= s->eq_delta;
#endif
p = s->eq_step - 1;
for (i = 0; i < V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN; i++)
{
p = (p - 1) & V29_EQUALIZER_MASK;
#if defined(SPANDSP_USE_FIXED_POINT)
z1 = complex_conji16(&s->eq_buf[p]);
z1 = complex_mul_q4_12(&ez, &z1);
s->eq_coeff[i] = complex_addi16(&s->eq_coeff[i], &z1);
#else
z1 = complex_conjf(&s->eq_buf[p]);
z1 = complex_mulf(&ez, &z1);
s->eq_coeff[i] = complex_addf(&s->eq_coeff[i], &z1);
/* Leak a little to tame uncontrolled wandering */
s->eq_coeff[i].re *= 0.9999f;
s->eq_coeff[i].im *= 0.9999f;
#endif
}
}
/*- End of function --------------------------------------------------------*/
@@ -253,7 +340,7 @@ static int scrambled_training_bit(v29_rx_state_t *s)
}
/*- End of function --------------------------------------------------------*/
#if defined(SPANDSP_USE_FIXED_POINTy)
#if defined(SPANDSP_USE_FIXED_POINT)
static __inline__ int find_quadrant(const complexi16_t *z)
#else
static __inline__ int find_quadrant(const complexf_t *z)
@@ -269,7 +356,7 @@ static __inline__ int find_quadrant(const complexf_t *z)
}
/*- End of function --------------------------------------------------------*/
#if defined(SPANDSP_USE_FIXED_POINTy)
#if defined(SPANDSP_USE_FIXED_POINT)
static __inline__ void track_carrier(v29_rx_state_t *s, const complexi16_t *z, const complexi16_t *target)
#else
static __inline__ void track_carrier(v29_rx_state_t *s, const complexf_t *z, const complexf_t *target)
@@ -290,7 +377,12 @@ static __inline__ void track_carrier(v29_rx_state_t *s, const complexf_t *z, con
different amplitudes of the various target positions scale things. This isn't all bad,
as the angular error for the larger amplitude constellation points is probably
a more reliable indicator, and we are weighting it as such. */
#if defined(SPANDSP_USE_FIXED_POINT)
error = z->im*target->re - z->re*target->im;
error /= (float) FP_FACTOR;
#else
error = z->im*target->re - z->re*target->im;
#endif
/* Use a proportional-integral approach to tracking the carrier. The PI
parameters are coarser at first, until we get precisely on target. Then,
@@ -326,7 +418,11 @@ static __inline__ void put_bit(v29_rx_state_t *s, int bit)
}
/*- End of function --------------------------------------------------------*/
#if defined(SPANDSP_USE_FIXED_POINT)
static void decode_baud(v29_rx_state_t *s, complexi16_t *z)
#else
static void decode_baud(v29_rx_state_t *s, complexf_t *z)
#endif
{
static const uint8_t phase_steps_9600[8] =
{
@@ -342,57 +438,51 @@ static void decode_baud(v29_rx_state_t *s, complexf_t *z)
int re;
int im;
switch (s->bit_rate)
if (s->bit_rate == 4800)
{
case 9600:
default:
/* 4800 is a special case. */
nearest = find_quadrant(z) << 1;
raw_bits = phase_steps_4800[((nearest - s->constellation_state) >> 1) & 3];
put_bit(s, raw_bits);
put_bit(s, raw_bits >> 1);
}
else
{
/* 9600 and 7200 are quite similar. */
#if defined(SPANDSP_USE_FIXED_POINT)
re = (z->re + 5*FP_FACTOR) >> (FP_SHIFT_FACTOR - 1);
im = (z->im + 5*FP_FACTOR) >> (FP_SHIFT_FACTOR - 1);
#else
re = (int) ((z->re + 5.0f)*2.0f);
im = (int) ((z->im + 5.0f)*2.0f);
#endif
if (re > 19)
re = 19;
else if (re < 0)
re = 0;
im = (int) ((z->im + 5.0f)*2.0f);
if (im > 19)
im = 19;
else if (im < 0)
im = 0;
nearest = space_map_9600[re][im];
/* Deal with the amplitude bit */
put_bit(s, nearest >> 3);
if (s->bit_rate == 9600)
{
/* Send out the top (amplitude) bit. */
put_bit(s, nearest >> 3);
}
else
{
/* We can reuse the space map for 9600, but drop the top bit. */
nearest &= 7;
}
raw_bits = phase_steps_9600[(nearest - s->constellation_state) & 7];
for (i = 0; i < 3; i++)
{
put_bit(s, raw_bits);
raw_bits >>= 1;
}
break;
case 7200:
/* We can reuse the space map for 9600, but drop the top bit */
re = (int) ((z->re + 5.0f)*2.0f);
if (re > 19)
re = 19;
else if (re < 0)
re = 0;
im = (int) ((z->im + 5.0f)*2.0f);
if (im > 19)
im = 19;
else if (im < 0)
im = 0;
nearest = space_map_9600[re][im] & 7;
raw_bits = phase_steps_9600[(nearest - s->constellation_state) & 7];
for (i = 0; i < 3; i++)
{
put_bit(s, raw_bits);
raw_bits >>= 1;
}
break;
case 4800:
nearest = find_quadrant(z) << 1;
raw_bits = phase_steps_4800[((nearest - s->constellation_state) >> 1) & 3];
put_bit(s, raw_bits);
put_bit(s, raw_bits >> 1);
break;
}
track_carrier(s, z, &v29_9600_constellation[nearest]);
if (--s->eq_skip <= 0)
{
@@ -406,7 +496,73 @@ static void decode_baud(v29_rx_state_t *s, complexf_t *z)
}
/*- End of function --------------------------------------------------------*/
static __inline__ void symbol_sync(v29_rx_state_t *s)
{
int i;
#if defined(SPANDSP_USE_FIXED_POINT)
int32_t v;
int32_t p;
#else
float v;
float p;
#endif
/* This routine adapts the position of the half baud samples entering the equalizer. */
#if defined(SPANDSP_USE_FIXED_POINT)
/* TODO: The scalings used here need more thorough evaluation, to see if overflows are possible. */
/* Cross correlate */
v = (((s->symbol_sync_low[1] >> 5)*(s->symbol_sync_high[1] >> 4)) >> 15)*SYNC_CROSS_CORR_COEFF_A
+ (((s->symbol_sync_low[0] >> 5)*(s->symbol_sync_high[1] >> 4)) >> 15)*SYNC_CROSS_CORR_COEFF_B
+ (((s->symbol_sync_low[1] >> 5)*(s->symbol_sync_high[0] >> 4)) >> 15)*SYNC_CROSS_CORR_COEFF_C;
/* Filter away any DC component */
p = v - s->symbol_sync_dc_filter[1];
s->symbol_sync_dc_filter[1] = s->symbol_sync_dc_filter[0];
s->symbol_sync_dc_filter[0] = v;
/* A little integration will now filter away much of the noise */
s->baud_phase -= p;
if (abs(s->baud_phase) > 50*FP_FACTOR)
{
if (s->baud_phase > 0)
i = (s->baud_phase > 1000*FP_FACTOR) ? 5 : 1;
else
i = (s->baud_phase < -1000*FP_FACTOR) ? -5 : -1;
//printf("v = %10.5f %5d - %f %f %d %d\n", v, i, p, s->baud_phase, s->total_baud_timing_correction);
s->eq_put_step += i;
s->total_baud_timing_correction += i;
}
#else
/* Cross correlate */
v = s->symbol_sync_low[1]*s->symbol_sync_high[1]*SYNC_CROSS_CORR_COEFF_A
+ s->symbol_sync_low[0]*s->symbol_sync_high[1]*SYNC_CROSS_CORR_COEFF_B
+ s->symbol_sync_low[1]*s->symbol_sync_high[0]*SYNC_CROSS_CORR_COEFF_C;
/* Filter away any DC component */
p = v - s->symbol_sync_dc_filter[1];
s->symbol_sync_dc_filter[1] = s->symbol_sync_dc_filter[0];
s->symbol_sync_dc_filter[0] = v;
/* A little integration will now filter away much of the noise */
s->baud_phase -= p;
if (fabsf(s->baud_phase) > 50.0f)
{
if (s->baud_phase > 0.0f)
i = (s->baud_phase > 1000.0f) ? 5 : 1;
else
i = (s->baud_phase < -1000.0f) ? -5 : -1;
//printf("v = %10.5f %5d - %f %f %d %d\n", v, i, p, s->baud_phase, s->total_baud_timing_correction);
s->eq_put_step += i;
s->total_baud_timing_correction += i;
}
#endif
}
/*- End of function --------------------------------------------------------*/
#if defined(SPANDSP_USE_FIXED_POINT)
static void process_half_baud(v29_rx_state_t *s, complexi16_t *sample)
#else
static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
#endif
{
static const int cdcd_pos[6] =
{
@@ -414,14 +570,17 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
0, 3,
0, 2
};
complexf_t z;
complexf_t zz;
#if defined(SPANDSP_USE_FIXED_POINTy)
#if defined(SPANDSP_USE_FIXED_POINT)
complexf_t z1;
complexi16_t z;
const complexi16_t *target;
static const complexi16_t zero = {0, 0};
#else
complexf_t z;
const complexf_t *target;
static const complexf_t zero = {0.0f, 0.0f};
#endif
float v;
float p;
int bit;
int i;
@@ -429,8 +588,7 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
int32_t angle;
int32_t ang;
/* This routine processes every half a baud, as we put things into the equalizer at the T/2 rate.
This routine adapts the position of the half baud samples, which the caller takes. */
/* This routine processes every half a baud, as we put things into the equalizer at the T/2 rate. */
/* Add a sample to the equalizer's circular buffer, but don't calculate anything
at this time. */
@@ -442,29 +600,7 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
return;
/* Symbol timing synchronisation */
/* Cross correlate */
v = s->symbol_sync_low[1]*s->symbol_sync_high[1]*SYNC_CROSS_CORR_COEFF_A
+ s->symbol_sync_low[0]*s->symbol_sync_high[1]*SYNC_CROSS_CORR_COEFF_B
+ s->symbol_sync_low[1]*s->symbol_sync_high[0]*SYNC_CROSS_CORR_COEFF_C;
/* Filter away any DC component */
p = v - s->symbol_sync_dc_filter[1];
s->symbol_sync_dc_filter[1] = s->symbol_sync_dc_filter[0];
s->symbol_sync_dc_filter[0] = v;
/* A little integration will now filter away much of the noise */
s->baud_phase -= p;
if (fabsf(s->baud_phase) > 30.0f)
{
if (s->baud_phase > 0.0f)
i = (s->baud_phase > 1000.0f) ? 5 : 1;
else
i = (s->baud_phase < -1000.0f) ? -5 : -1;
//printf("v = %10.5f %5d - %f %f %d %d\n", v, i, p, s->baud_phase, s->total_baud_timing_correction);
s->eq_put_step += i;
s->total_baud_timing_correction += i;
}
symbol_sync(s);
z = equalizer_get(s);
@@ -477,25 +613,27 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
break;
case TRAINING_STAGE_SYMBOL_ACQUISITION:
/* Allow time for symbol synchronisation to settle the symbol timing. */
target = &z;
target = &zero;
if (++s->training_count >= 60)
{
/* Record the current phase angle */
s->training_stage = TRAINING_STAGE_LOG_PHASE;
s->angles[0] =
s->start_angles[0] = arctan2(z.im, z.re);
if (s->agc_scaling_save == 0.0f)
s->agc_scaling_save = s->agc_scaling;
}
break;
case TRAINING_STAGE_LOG_PHASE:
/* Record the current alternate phase angle */
target = &z;
target = &zero;
s->angles[1] =
s->start_angles[1] = arctan2(z.im, z.re);
s->training_count = 1;
s->training_stage = TRAINING_STAGE_WAIT_FOR_CDCD;
break;
case TRAINING_STAGE_WAIT_FOR_CDCD:
target = &z;
target = &zero;
angle = arctan2(z.im, z.re);
/* Look for the initial ABAB sequence to display a phase reversal, which will
signal the start of the scrambled CDCD segment */
@@ -524,24 +662,36 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
||
s->carrier_phase_rate > dds_phase_ratef(CARRIER_NOMINAL_FREQ + 20.0f))
{
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n");
/* Park this modem */
s->training_stage = TRAINING_STAGE_PARKED;
report_status_change(s, PUTBIT_TRAINING_FAILED);
break;
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n");
/* Park this modem */
s->agc_scaling_save = 0.0f;
s->training_stage = TRAINING_STAGE_PARKED;
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
break;
}
/* Make a step shift in the phase, to pull it into line. We need to rotate the equalizer
buffer, as well as the carrier phase, for this to play out nicely. */
p = angle*2.0f*3.14159f/(65536.0f*65536.0f);
#if defined(SPANDSP_USE_FIXED_POINT)
zz = complex_setf(cosf(p), -sinf(p));
for (i = 0; i <= V29_EQUALIZER_MASK; i++)
{
z1 = complex_setf(s->eq_buf[i].re, s->eq_buf[i].im);
z1 = complex_mulf(&z1, &zz);
s->eq_buf[i].re = z1.re;
s->eq_buf[i].im = z1.im;
}
#else
zz = complex_setf(cosf(p), -sinf(p));
for (i = 0; i <= V29_EQUALIZER_MASK; i++)
s->eq_buf[i] = complex_mulf(&s->eq_buf[i], &zz);
#endif
s->carrier_phase += angle;
/* We have just seen the first bit of the scrambled sequence, so skip it. */
bit = scrambled_training_bit(s);
s->training_count = 1;
s->training_stage = TRAINING_STAGE_TRAIN_ON_CDCD;
report_status_change(s, PUTBIT_TRAINING_IN_PROGRESS);
report_status_change(s, SIG_STATUS_TRAINING_IN_PROGRESS);
break;
}
if (++s->training_count > V29_TRAINING_SEG_2_LEN)
@@ -550,8 +700,9 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
of a real training sequence. */
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n");
/* Park this modem */
s->agc_scaling_save = 0.0f;
s->training_stage = TRAINING_STAGE_PARKED;
report_status_change(s, PUTBIT_TRAINING_FAILED);
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
}
break;
case TRAINING_STAGE_TRAIN_ON_CDCD:
@@ -579,8 +730,17 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
track_carrier(s, &z, target);
tune_equalizer(s, &z, target);
/* Measure the training error */
#if defined(SPANDSP_USE_FIXED_POINT)
z1.re = z.re/(float) FP_FACTOR;
z1.im = z.im/(float) FP_FACTOR;
zz.re = target->re;
zz.im = target->im;
zz = complex_subf(&z1, &zz);
s->training_error += powerf(&zz);
#else
zz = complex_subf(&z, target);
s->training_error += powerf(&zz);
#endif
if (++s->training_count >= V29_TRAINING_SEG_3_LEN)
{
span_log(&s->logging, SPAN_LOG_FLOW, "Constellation mismatch %f\n", s->training_error);
@@ -595,8 +755,9 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
{
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (convergence failed)\n");
/* Park this modem */
s->agc_scaling_save = 0.0f;
s->training_stage = TRAINING_STAGE_PARKED;
report_status_change(s, PUTBIT_TRAINING_FAILED);
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
}
}
break;
@@ -607,15 +768,24 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
decode_baud(s, &z);
target = &v29_9600_constellation[s->constellation_state];
/* Measure the training error */
#if defined(SPANDSP_USE_FIXED_POINT)
z1.re = z.re/(float) FP_FACTOR;
z1.im = z.im/(float) FP_FACTOR;
zz.re = target->re;
zz.im = target->im;
zz = complex_subf(&z1, &zz);
s->training_error += powerf(&zz);
#else
zz = complex_subf(&z, target);
s->training_error += powerf(&zz);
#endif
if (++s->training_count >= V29_TRAINING_SEG_4_LEN)
{
if (s->training_error < 50.0f)
{
/* We are up and running */
span_log(&s->logging, SPAN_LOG_FLOW, "Training succeeded (constellation mismatch %f)\n", s->training_error);
report_status_change(s, PUTBIT_TRAINING_SUCCEEDED);
report_status_change(s, SIG_STATUS_TRAINING_SUCCEEDED);
/* Apply some lag to the carrier off condition, to ensure the last few bits get pushed through
the processing. */
s->signal_present = 60;
@@ -629,8 +799,9 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
/* Training has failed */
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (constellation mismatch %f)\n", s->training_error);
/* Park this modem */
report_status_change(s, PUTBIT_TRAINING_FAILED);
s->agc_scaling_save = 0.0f;
s->training_stage = TRAINING_STAGE_PARKED;
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
}
}
break;
@@ -638,11 +809,21 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
default:
/* We failed to train! */
/* Park here until the carrier drops. */
target = &z;
target = &zero;
break;
}
if (s->qam_report)
{
#if defined(SPANDSP_USE_FIXED_POINT)
z1.re = z.re/(float) FP_FACTOR;
z1.im = z.im/(float) FP_FACTOR;
zz.re = target->re;
zz.im = target->im;
s->qam_report(s->qam_user_data, &z1, &zz, s->constellation_state);
#else
s->qam_report(s->qam_user_data, &z, target, s->constellation_state);
#endif
}
}
/*- End of function --------------------------------------------------------*/
@@ -653,14 +834,19 @@ int v29_rx(v29_rx_state_t *s, const int16_t amp[], int len)
int step;
int16_t x;
int32_t diff;
#if defined(SPANDSP_USE_FIXED_POINT)
complexi16_t z;
complexi16_t zz;
complexi16_t sample;
int32_t v;
float y;
#else
complexf_t z;
complexf_t zz;
complexf_t sample;
#if defined(SPANDSP_USE_FIXED_POINT)
complexi_t zi;
float v;
#endif
int32_t power;
float v;
for (i = 0; i < len; i++)
{
@@ -709,7 +895,7 @@ int v29_rx(v29_rx_state_t *s, const int16_t amp[], int len)
/* Count down a short delay, to ensure we push the last
few bits through the filters before stopping. */
v29_rx_restart(s, s->bit_rate, FALSE);
report_status_change(s, PUTBIT_CARRIER_DOWN);
report_status_change(s, SIG_STATUS_CARRIER_DOWN);
continue;
}
#if defined(IAXMODEM_STUFF)
@@ -728,7 +914,7 @@ int v29_rx(v29_rx_state_t *s, const int16_t amp[], int len)
#if defined(IAXMODEM_STUFF)
s->carrier_drop_pending = FALSE;
#endif
report_status_change(s, PUTBIT_CARRIER_UP);
report_status_change(s, SIG_STATUS_CARRIER_UP);
}
if (s->training_stage == TRAINING_STAGE_PARKED)
continue;
@@ -741,18 +927,29 @@ int v29_rx(v29_rx_state_t *s, const int16_t amp[], int len)
if (step < 0)
step += RX_PULSESHAPER_COEFF_SETS;
#if defined(SPANDSP_USE_FIXED_POINT)
zi.re = (int32_t) rx_pulseshaper[step][0].re*(int32_t) s->rrc_filter[s->rrc_filter_step];
v = (int32_t) rx_pulseshaper[step][0].re*(int32_t) s->rrc_filter[s->rrc_filter_step];
for (j = 1; j < V29_RX_FILTER_STEPS; j++)
zi.re += (int32_t) rx_pulseshaper[step][j].re*(int32_t) s->rrc_filter[j + s->rrc_filter_step];
sample.re = zi.re*s->agc_scaling;
v += (int32_t) rx_pulseshaper[step][j].re*(int32_t) s->rrc_filter[j + s->rrc_filter_step];
y = v*s->agc_scaling;
sample.re = y;
#else
zz.re = rx_pulseshaper[step][0].re*s->rrc_filter[s->rrc_filter_step];
v = rx_pulseshaper[step][0].re*s->rrc_filter[s->rrc_filter_step];
for (j = 1; j < V29_RX_FILTER_STEPS; j++)
zz.re += rx_pulseshaper[step][j].re*s->rrc_filter[j + s->rrc_filter_step];
sample.re = zz.re*s->agc_scaling;
v += rx_pulseshaper[step][j].re*s->rrc_filter[j + s->rrc_filter_step];
sample.re = v*s->agc_scaling;
#endif
/* Symbol timing synchronisation band edge filters */
#if defined(SPANDSP_USE_FIXED_POINT)
/* Low Nyquist band edge filter */
v = ((s->symbol_sync_low[0]*SYNC_LOW_BAND_EDGE_COEFF_0) >> 12) + ((s->symbol_sync_low[1]*SYNC_LOW_BAND_EDGE_COEFF_1) >> 12) + sample.re;
s->symbol_sync_low[1] = s->symbol_sync_low[0];
s->symbol_sync_low[0] = v;
/* High Nyquist band edge filter */
v = ((s->symbol_sync_high[0]*SYNC_HIGH_BAND_EDGE_COEFF_0) >> 12) + ((s->symbol_sync_high[1]*SYNC_HIGH_BAND_EDGE_COEFF_1) >> 12) + sample.re;
s->symbol_sync_high[1] = s->symbol_sync_high[0];
s->symbol_sync_high[0] = v;
#else
/* Low Nyquist band edge filter */
v = s->symbol_sync_low[0]*SYNC_LOW_BAND_EDGE_COEFF_0 + s->symbol_sync_low[1]*SYNC_LOW_BAND_EDGE_COEFF_1 + sample.re;
s->symbol_sync_low[1] = s->symbol_sync_low[0];
@@ -761,16 +958,19 @@ int v29_rx(v29_rx_state_t *s, const int16_t amp[], int len)
v = s->symbol_sync_high[0]*SYNC_HIGH_BAND_EDGE_COEFF_0 + s->symbol_sync_high[1]*SYNC_HIGH_BAND_EDGE_COEFF_1 + sample.re;
s->symbol_sync_high[1] = s->symbol_sync_high[0];
s->symbol_sync_high[0] = v;
#endif
/* Put things into the equalization buffer at T/2 rate. The symbol synchronisation
will fiddle the step to align this with the symbols. */
if (s->eq_put_step <= 0)
{
if (s->training_stage == TRAINING_STAGE_SYMBOL_ACQUISITION)
{
/* Only AGC during the initial training */
/* Only AGC until we have locked down the setting. */
#if defined(SPANDSP_USE_FIXED_POINT)
if (s->agc_scaling_save == 0.0f)
s->agc_scaling = (float) FP_FACTOR*(1.0f/RX_PULSESHAPER_GAIN)*5.0f*0.25f/sqrtf(power);
#else
if (s->agc_scaling_save == 0.0f)
s->agc_scaling = (1.0f/RX_PULSESHAPER_GAIN)*5.0f*0.25f/sqrtf(power);
}
#endif
/* Pulse shape while still at the carrier frequency, using a quadrature
pair of filters. This results in a properly bandpass filtered complex
signal, which can be brought directly to baseband by complex mixing.
@@ -778,24 +978,24 @@ int v29_rx(v29_rx_state_t *s, const int16_t amp[], int len)
step = -s->eq_put_step;
if (step > RX_PULSESHAPER_COEFF_SETS - 1)
step = RX_PULSESHAPER_COEFF_SETS - 1;
#if defined(SPANDSP_USE_FIXED_POINT)
zi.im = (int32_t) rx_pulseshaper[step][0].im*(int32_t) s->rrc_filter[s->rrc_filter_step];
for (j = 1; j < V29_RX_FILTER_STEPS; j++)
zi.im += (int32_t) rx_pulseshaper[step][j].im*(int32_t) s->rrc_filter[j + s->rrc_filter_step];
sample.im = zi.im*s->agc_scaling;
#else
zz.im = rx_pulseshaper[step][0].im*s->rrc_filter[s->rrc_filter_step];
for (j = 1; j < V29_RX_FILTER_STEPS; j++)
zz.im += rx_pulseshaper[step][j].im*s->rrc_filter[j + s->rrc_filter_step];
sample.im = zz.im*s->agc_scaling;
#endif
s->eq_put_step += RX_PULSESHAPER_COEFF_SETS*10/(3*2);
/* Shift to baseband - since this is done in a full complex form, the
result is clean, and requires no further filtering, apart from the
equalizer. */
#if defined(SPANDSP_USE_FIXED_POINT)
v = (int32_t) rx_pulseshaper[step][0].im*(int32_t) s->rrc_filter[s->rrc_filter_step];
for (j = 1; j < V29_RX_FILTER_STEPS; j++)
v += (int32_t) rx_pulseshaper[step][j].im*(int32_t) s->rrc_filter[j + s->rrc_filter_step];
sample.im = v*s->agc_scaling;
z = dds_lookup_complexi16(s->carrier_phase);
zz.re = ((int32_t) sample.re*(int32_t) z.re - (int32_t) sample.im*(int32_t) z.im) >> 15;
zz.im = ((int32_t) -sample.re*(int32_t) z.im - (int32_t) sample.im*(int32_t) z.re) >> 15;
#else
v = rx_pulseshaper[step][0].im*s->rrc_filter[s->rrc_filter_step];
for (j = 1; j < V29_RX_FILTER_STEPS; j++)
v += rx_pulseshaper[step][j].im*s->rrc_filter[j + s->rrc_filter_step];
sample.im = v*s->agc_scaling;
z = dds_lookup_complexf(s->carrier_phase);
zz.re = sample.re*z.re - sample.im*z.im;
zz.im = -sample.re*z.im - sample.im*z.re;
#endif
process_half_baud(s, &zz);
}
dds_advancef(&(s->carrier_phase), s->carrier_phase_rate);
@@ -837,7 +1037,7 @@ int v29_rx_restart(v29_rx_state_t *s, int bit_rate, int old_train)
s->bit_rate = bit_rate;
#if defined(SPANDSP_USE_FIXED_POINT)
memset(s->rrc_filter, 0, sizeof(s->rrc_filter));
vec_zeroi16(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
#else
vec_zerof(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
#endif
@@ -856,8 +1056,6 @@ int v29_rx_restart(v29_rx_state_t *s, int bit_rate, int old_train)
s->old_train = old_train;
s->carrier_phase = 0;
s->carrier_track_i = 8000.0f;
s->carrier_track_p = 8000000.0f;
power_meter_init(&(s->power), 4);
@@ -872,13 +1070,29 @@ int v29_rx_restart(v29_rx_state_t *s, int bit_rate, int old_train)
else
{
s->carrier_phase_rate = dds_phase_ratef(CARRIER_NOMINAL_FREQ);
s->agc_scaling_save = 0.0f;
#if defined(SPANDSP_USE_FIXED_POINT)
s->agc_scaling = (float) FP_FACTOR*0.0017f/RX_PULSESHAPER_GAIN;
#else
s->agc_scaling = 0.0017f/RX_PULSESHAPER_GAIN;
#endif
equalizer_reset(s);
}
s->eq_skip = 0;
s->carrier_track_i = 8000.0f;
s->carrier_track_p = 8000000.0f;
s->last_sample = 0;
s->eq_skip = 0;
/* Initialise the working data for symbol timing synchronisation */
#if defined(SPANDSP_USE_FIXED_POINT)
s->symbol_sync_low[0] = 0;
s->symbol_sync_low[1] = 0;
s->symbol_sync_high[0] = 0;
s->symbol_sync_high[1] = 0;
s->symbol_sync_dc_filter[0] = 0;
s->symbol_sync_dc_filter[1] = 0;
s->baud_phase = 0;
#else
s->symbol_sync_low[0] = 0.0f;
s->symbol_sync_low[1] = 0.0f;
s->symbol_sync_high[0] = 0.0f;
@@ -886,6 +1100,7 @@ int v29_rx_restart(v29_rx_state_t *s, int bit_rate, int old_train)
s->symbol_sync_dc_filter[0] = 0.0f;
s->symbol_sync_dc_filter[1] = 0.0f;
s->baud_phase = 0.0f;
#endif
s->baud_half = 0;
s->total_baud_timing_correction = 0;
+4 -8
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v29tx.c,v 1.76 2008/07/16 14:23:47 steveu Exp $
* $Id: v29tx.c,v 1.79 2008/09/07 12:45:17 steveu Exp $
*/
/*! \file */
@@ -54,10 +54,6 @@
#include "spandsp/v29tx.h"
#if defined(SPANDSP_USE_FIXED_POINT)
#define SPANDSP_USE_FIXED_POINTx
#endif
#include "v29tx_constellation_maps.h"
#if defined(SPANDSP_USE_FIXED_POINT)
#include "v29tx_fixed_rrc.h"
@@ -87,12 +83,12 @@ static __inline__ int get_scrambled_bit(v29_tx_state_t *s)
int bit;
int out_bit;
if ((bit = s->current_get_bit(s->get_bit_user_data)) == PUTBIT_END_OF_DATA)
if ((bit = s->current_get_bit(s->get_bit_user_data)) == SIG_STATUS_END_OF_DATA)
{
/* End of real data. Switch to the fake get_bit routine, until we
have shut down completely. */
if (s->status_handler)
s->status_handler(s->status_user_data, MODEM_TX_STATUS_DATA_EXHAUSTED);
s->status_handler(s->status_user_data, SIG_STATUS_END_OF_DATA);
s->current_get_bit = fake_get_bit;
s->in_training = TRUE;
bit = 1;
@@ -166,7 +162,7 @@ static __inline__ complexf_t getbaud(v29_tx_state_t *s)
if (s->training_step == V29_TRAINING_SHUTDOWN_END)
{
if (s->status_handler)
s->status_handler(s->status_user_data, MODEM_TX_STATUS_SHUTDOWN_COMPLETE);
s->status_handler(s->status_user_data, SIG_STATUS_SHUTDOWN_COMPLETE);
}
}
/* 9600bps uses the full constellation.
+4 -4
View File
@@ -23,10 +23,10 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v29tx_constellation_maps.h,v 1.1 2008/07/10 13:34:01 steveu Exp $
* $Id: v29tx_constellation_maps.h,v 1.2 2008/09/04 14:40:05 steveu Exp $
*/
#if defined(SPANDSP_USE_FIXED_POINTx)
#if defined(SPANDSP_USE_FIXED_POINT)
static const complexi16_t v29_abab_constellation[6] =
#else
static const complexf_t v29_abab_constellation[6] =
@@ -40,7 +40,7 @@ static const complexf_t v29_abab_constellation[6] =
{-3, 0} /* 180deg low */
};
#if defined(SPANDSP_USE_FIXED_POINTx)
#if defined(SPANDSP_USE_FIXED_POINT)
static const complexi16_t v29_cdcd_constellation[6] =
#else
static const complexf_t v29_cdcd_constellation[6] =
@@ -54,7 +54,7 @@ static const complexf_t v29_cdcd_constellation[6] =
{ 0, 3} /* 90deg low */
};
#if defined(SPANDSP_USE_FIXED_POINTx)
#if defined(SPANDSP_USE_FIXED_POINT)
static const complexi16_t v29_9600_constellation[16] =
#else
static const complexf_t v29_9600_constellation[16] =
+3 -39
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v42.c,v 1.42 2008/05/13 13:17:25 steveu Exp $
* $Id: v42.c,v 1.43 2008/09/07 12:45:17 steveu Exp $
*/
/* THIS IS A WORK IN PROGRESS. IT IS NOT FINISHED. */
@@ -721,31 +721,7 @@ fprintf(stderr, "LAPM receive %d %d\n", ok, len);
if (len < 0)
{
/* Special conditions */
switch (len)
{
case PUTBIT_TRAINING_FAILED:
span_log(&s->logging, SPAN_LOG_DEBUG, "Training failed\n");
break;
case PUTBIT_TRAINING_SUCCEEDED:
span_log(&s->logging, SPAN_LOG_DEBUG, "Training succeeded\n");
break;
case PUTBIT_CARRIER_UP:
span_log(&s->logging, SPAN_LOG_DEBUG, "Carrier up\n");
break;
case PUTBIT_CARRIER_DOWN:
span_log(&s->logging, SPAN_LOG_DEBUG, "Carrier down\n");
break;
case PUTBIT_FRAMING_OK:
span_log(&s->logging, SPAN_LOG_DEBUG, "Framing OK\n");
break;
case PUTBIT_ABORT:
span_log(&s->logging, SPAN_LOG_DEBUG, "Abort\n");
break;
default:
span_log(&s->logging, SPAN_LOG_DEBUG, "Eh!\n");
break;
}
/*endswitch*/
span_log(&s->logging, SPAN_LOG_DEBUG, "V.42 rx status is %s (%d)\n", signal_status_to_str(len), len);
return;
}
/*endif*/
@@ -1133,19 +1109,7 @@ static void negotiation_rx_bit(v42_state_t *s, int new_bit)
if (new_bit < 0)
{
/* Special conditions */
switch (new_bit)
{
case PUTBIT_CARRIER_UP:
break;
case PUTBIT_CARRIER_DOWN:
case PUTBIT_TRAINING_SUCCEEDED:
case PUTBIT_TRAINING_FAILED:
break;
default:
span_log(&s->logging, SPAN_LOG_WARNING, "Unexpected special 'bit' code %d\n", new_bit);
break;
}
/*endswitch*/
span_log(&s->logging, SPAN_LOG_DEBUG, "V.42 rx status is %s (%d)\n", signal_status_to_str(new_bit), new_bit);
return;
}
/*endif*/
+5 -5
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v8.c,v 1.30 2008/07/02 14:48:26 steveu Exp $
* $Id: v8.c,v 1.31 2008/09/07 12:45:17 steveu Exp $
*/
/*! \file */
@@ -396,10 +396,10 @@ static void put_bit(void *user_data, int bit)
/* Special conditions */
switch (bit)
{
case PUTBIT_CARRIER_UP:
case PUTBIT_CARRIER_DOWN:
case PUTBIT_TRAINING_SUCCEEDED:
case PUTBIT_TRAINING_FAILED:
case SIG_STATUS_CARRIER_UP:
case SIG_STATUS_CARRIER_DOWN:
case SIG_STATUS_TRAINING_SUCCEEDED:
case SIG_STATUS_TRAINING_FAILED:
break;
default:
break;
+5 -5
View File
@@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: vector_int.c,v 1.11 2008/07/02 14:48:26 steveu Exp $
* $Id: vector_int.c,v 1.12 2008/09/01 16:07:34 steveu Exp $
*/
/*! \file */
@@ -87,7 +87,7 @@ int32_t vec_dot_prodi16(const int16_t x[], const int16_t y[], int n)
" .p2align 2;\n"
"1:\n"
" addl $24,%%edx;\n" /* now edx = top - 8 */
" addl $24,%%edx;\n" /* Now edx = top - 8 */
" cmpl %%edx,%%esi;\n"
" ja 3f;\n"
@@ -106,7 +106,7 @@ int32_t vec_dot_prodi16(const int16_t x[], const int16_t y[], int n)
" .p2align 2;\n"
"3:\n"
" addl $4,%%edx;\n" /* now edx = top - 4 */
" addl $4,%%edx;\n" /* Now edx = top - 4 */
" cmpl %%edx,%%esi;\n"
" ja 5f;\n"
@@ -121,7 +121,7 @@ int32_t vec_dot_prodi16(const int16_t x[], const int16_t y[], int n)
" .p2align 2;\n"
"5:\n"
" addl $2,%%edx;\n" /* now edx = top - 2 */
" addl $2,%%edx;\n" /* Now edx = top - 2 */
" cmpl %%edx,%%esi;\n"
" ja 6f;\n"
@@ -141,7 +141,7 @@ int32_t vec_dot_prodi16(const int16_t x[], const int16_t y[], int n)
" movq %%mm0,%%mm1;\n"
" punpckhdq %%mm0,%%mm1;\n"
" paddd %%mm1,%%mm0;\n"
/* et voila, eax has the final result */
/* Et voila, eax has the final result */
" movd %%mm0,%%eax;\n"
" emms;\n"