More movement towards colour FAXing

This commit is contained in:
Steve Underwood 2013-04-21 22:02:09 +08:00
parent 8e49f7a556
commit 88b3b54ef4
27 changed files with 1607 additions and 483 deletions

View File

@ -261,6 +261,8 @@ fi
SPANDSP_SUPPORT_T42="#undef SPANDSP_SUPPORT_T42" SPANDSP_SUPPORT_T42="#undef SPANDSP_SUPPORT_T42"
#AC_DEFINE([SPANDSP_SUPPORT_T43], [1], [Support T.43 JBIG gray and colour compression]) #AC_DEFINE([SPANDSP_SUPPORT_T43], [1], [Support T.43 JBIG gray and colour compression])
SPANDSP_SUPPORT_T43="#undef SPANDSP_SUPPORT_T43" SPANDSP_SUPPORT_T43="#undef SPANDSP_SUPPORT_T43"
#AC_DEFINE([SPANDSP_SUPPORT_V32BIS], [1], [Support the V.32bis modem])
SPANDSP_SUPPORT_V32BIS="#undef SPANDSP_SUPPORT_V32BIS"
#AC_DEFINE([SPANDSP_SUPPORT_V34], [1], [Support the V.34 FAX modem]) #AC_DEFINE([SPANDSP_SUPPORT_V34], [1], [Support the V.34 FAX modem])
SPANDSP_SUPPORT_V34="#undef SPANDSP_SUPPORT_V34" SPANDSP_SUPPORT_V34="#undef SPANDSP_SUPPORT_V34"
@ -567,6 +569,7 @@ AC_SUBST(SPANDSP_MISALIGNED_ACCESS_FAILS)
AC_SUBST(SPANDSP_USE_EXPORT_CAPABILITY) AC_SUBST(SPANDSP_USE_EXPORT_CAPABILITY)
AC_SUBST(SPANDSP_SUPPORT_T42) AC_SUBST(SPANDSP_SUPPORT_T42)
AC_SUBST(SPANDSP_SUPPORT_T43) AC_SUBST(SPANDSP_SUPPORT_T43)
AC_SUBST(SPANDSP_SUPPORT_V32BIS)
AC_SUBST(SPANDSP_SUPPORT_V34) AC_SUBST(SPANDSP_SUPPORT_V34)
AC_SUBST(SPANDSP_SUPPORT_TIFF_FX) AC_SUBST(SPANDSP_SUPPORT_TIFF_FX)
AC_SUBST(INSERT_INTTYPES_HEADER) AC_SUBST(INSERT_INTTYPES_HEADER)

View File

@ -22,28 +22,17 @@ AM_LDFLAGS = $(COMP_VENDOR_LDFLAGS)
DISTCLEANFILES = $(srcdir)/at_interpreter_dictionary.h \ DISTCLEANFILES = $(srcdir)/at_interpreter_dictionary.h \
$(srcdir)/cielab_luts.h \ $(srcdir)/cielab_luts.h \
$(srcdir)/math_fixed_tables.h \ $(srcdir)/math_fixed_tables.h \
$(srcdir)/v17_v32bis_rx_fixed_rrc.h \ $(srcdir)/v17_v32bis_rx_rrc.h \
$(srcdir)/v17_v32bis_rx_floating_rrc.h \ $(srcdir)/v17_v32bis_tx_rrc.h \
$(srcdir)/v17_v32bis_tx_fixed_rrc.h \ $(srcdir)/v22bis_rx_1200_rrc.h \
$(srcdir)/v17_v32bis_tx_floating_rrc.h \ $(srcdir)/v22bis_rx_2400_rrc.h \
$(srcdir)/v22bis_rx_1200_fixed_rrc.h \ $(srcdir)/v22bis_tx_rrc.h \
$(srcdir)/v22bis_rx_2400_fixed_rrc.h \ $(srcdir)/v27ter_rx_2400_rrc.h \
$(srcdir)/v22bis_rx_1200_floating_rrc.h \ $(srcdir)/v27ter_rx_4800_rrc.h \
$(srcdir)/v22bis_rx_2400_floating_rrc.h \ $(srcdir)/v27ter_tx_2400_rrc.h \
$(srcdir)/v22bis_tx_fixed_rrc.h \ $(srcdir)/v27ter_tx_4800_rrc.h \
$(srcdir)/v22bis_tx_floating_rrc.h \ $(srcdir)/v29rx_rrc.h \
$(srcdir)/v27ter_rx_2400_fixed_rrc.h \ $(srcdir)/v29tx_rrc.h
$(srcdir)/v27ter_rx_4800_fixed_rrc.h \
$(srcdir)/v27ter_rx_2400_floating_rrc.h \
$(srcdir)/v27ter_rx_4800_floating_rrc.h \
$(srcdir)/v27ter_tx_2400_fixed_rrc.h \
$(srcdir)/v27ter_tx_4800_fixed_rrc.h \
$(srcdir)/v27ter_tx_2400_floating_rrc.h \
$(srcdir)/v27ter_tx_4800_floating_rrc.h \
$(srcdir)/v29rx_fixed_rrc.h \
$(srcdir)/v29rx_floating_rrc.h \
$(srcdir)/v29tx_fixed_rrc.h \
$(srcdir)/v29tx_floating_rrc.h
CLEANFILES = ${DISTCLEANFILES} CLEANFILES = ${DISTCLEANFILES}
MOSTLYCLEANFILES = ${DISTCLEANFILES} MOSTLYCLEANFILES = ${DISTCLEANFILES}
@ -160,6 +149,7 @@ libspandsp_la_SOURCES = ademco_contactid.c \
t4_rx.c \ t4_rx.c \
t4_tx.c \ t4_tx.c \
t42.c \ t42.c \
t43.c \
t81_t82_arith_coding.c \ t81_t82_arith_coding.c \
t85_decode.c \ t85_decode.c \
t85_encode.c \ t85_encode.c \
@ -251,6 +241,7 @@ nobase_include_HEADERS = spandsp/ademco_contactid.h \
spandsp/t4_t6_decode.h \ spandsp/t4_t6_decode.h \
spandsp/t4_t6_encode.h \ spandsp/t4_t6_encode.h \
spandsp/t42.h \ spandsp/t42.h \
spandsp/t43.h \
spandsp/t81_t82_arith_coding.h \ spandsp/t81_t82_arith_coding.h \
spandsp/t85.h \ spandsp/t85.h \
spandsp/telephony.h \ spandsp/telephony.h \
@ -318,6 +309,7 @@ nobase_include_HEADERS = spandsp/ademco_contactid.h \
spandsp/private/t4_t6_decode.h \ spandsp/private/t4_t6_decode.h \
spandsp/private/t4_t6_encode.h \ spandsp/private/t4_t6_encode.h \
spandsp/private/t42.h \ spandsp/private/t42.h \
spandsp/private/t43.h \
spandsp/private/t81_t82_arith_coding.h \ spandsp/private/t81_t82_arith_coding.h \
spandsp/private/t85.h \ spandsp/private/t85.h \
spandsp/private/time_scale.h \ spandsp/private/time_scale.h \

View File

@ -511,6 +511,9 @@ SPAN_DECLARE(fax_modems_state_t *) fax_modems_init(fax_modems_state_t *s,
s->use_tep = use_tep; s->use_tep = use_tep;
modem_connect_tones_tx_init(&s->connect_tx, MODEM_CONNECT_TONES_FAX_CNG); modem_connect_tones_tx_init(&s->connect_tx, MODEM_CONNECT_TONES_FAX_CNG);
span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
span_log_set_protocol(&s->logging, "FAX modems");
s->tone_callback = tone_callback; s->tone_callback = tone_callback;
s->tone_callback_user_data = user_data; s->tone_callback_user_data = user_data;
if (tone_callback) if (tone_callback)
@ -521,9 +524,6 @@ SPAN_DECLARE(fax_modems_state_t *) fax_modems_init(fax_modems_state_t *s,
s->tone_callback_user_data); s->tone_callback_user_data);
} }
/*endif*/ /*endif*/
span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
span_log_set_protocol(&s->logging, "FAX modems");
dc_restore_init(&s->dc_restore); dc_restore_init(&s->dc_restore);
s->get_bit = non_ecm_get_bit; s->get_bit = non_ecm_get_bit;

View File

@ -35,6 +35,7 @@
@SPANDSP_SUPPORT_T42@ @SPANDSP_SUPPORT_T42@
@SPANDSP_SUPPORT_T43@ @SPANDSP_SUPPORT_T43@
@SPANDSP_SUPPORT_V32BIS@
@SPANDSP_SUPPORT_V34@ @SPANDSP_SUPPORT_V34@
@SPANDSP_SUPPORT_TIFF_FX@ @SPANDSP_SUPPORT_TIFF_FX@
@ -96,11 +97,15 @@
#include <spandsp/v29tx.h> #include <spandsp/v29tx.h>
#include <spandsp/v17rx.h> #include <spandsp/v17rx.h>
#include <spandsp/v17tx.h> #include <spandsp/v17tx.h>
/*#include <spandsp/v32bis.h>*/ #if defined(SPANDSP_SUPPORT_V32BIS)
#include <spandsp/v32bis.h>
#endif
#include <spandsp/v22bis.h> #include <spandsp/v22bis.h>
#include <spandsp/v27ter_rx.h> #include <spandsp/v27ter_rx.h>
#include <spandsp/v27ter_tx.h> #include <spandsp/v27ter_tx.h>
/*#include <spandsp/v34.h>*/ #if defined(SPANDSP_SUPPORT_V34)
#include <spandsp/v34.h>
#endif
#include <spandsp/v18.h> #include <spandsp/v18.h>
#include <spandsp/timezone.h> #include <spandsp/timezone.h>
#include <spandsp/t4_rx.h> #include <spandsp/t4_rx.h>
@ -111,7 +116,9 @@
#include <spandsp/t81_t82_arith_coding.h> #include <spandsp/t81_t82_arith_coding.h>
#include <spandsp/t85.h> #include <spandsp/t85.h>
#include <spandsp/t42.h> #include <spandsp/t42.h>
/*#include <spandsp/t43.h>*/ #if defined(SPANDSP_SUPPORT_T43)
#include <spandsp/t43.h>
#endif
#include <spandsp/t30.h> #include <spandsp/t30.h>
#include <spandsp/t30_api.h> #include <spandsp/t30_api.h>
#include <spandsp/t30_fcf.h> #include <spandsp/t30_fcf.h>

View File

@ -35,6 +35,10 @@ struct fax_modems_state_s
{ {
/*! TRUE is talker echo protection should be sent for the image modems */ /*! TRUE is talker echo protection should be sent for the image modems */
int use_tep; int use_tep;
/*! \brief The callback function used to report detected tones. */
tone_report_func_t tone_callback;
/*! \brief A user specified opaque pointer passed to the tone_callback function. */
void *tone_callback_user_data;
/*! If TRUE, transmit silence when there is nothing else to transmit. If FALSE return only /*! If TRUE, transmit silence when there is nothing else to transmit. If FALSE return only
the actual generated audio. Note that this only affects untimed silences. Timed silences the actual generated audio. Note that this only affects untimed silences. Timed silences
@ -82,11 +86,6 @@ struct fax_modems_state_s
/*! \brief */ /*! \brief */
dc_restore_state_t dc_restore; dc_restore_state_t dc_restore;
/*! \brief The callback function used to report detected tones. */
tone_report_func_t tone_callback;
/*! \brief A user specified opaque pointer passed to the tone_callback function. */
void *tone_callback_user_data;
/*! \brief The fast modem type currently in use */ /*! \brief The fast modem type currently in use */
int fast_modem; int fast_modem;

View File

@ -50,8 +50,12 @@ struct t30_state_s
int iaf; int iaf;
/*! \brief A bit mask of the currently supported modem types. */ /*! \brief A bit mask of the currently supported modem types. */
int supported_modems; int supported_modems;
/*! \brief A bit mask of the currently supported image compression modes. */ /*! \brief A bit mask of the currently supported image compression modes for use
between FAX entities. */
int supported_compressions; int supported_compressions;
/*! \brief A bit mask of the currently supported image compression modes for the output
of received page images. */
int supported_output_compressions;
/*! \brief A bit mask of the currently supported bi-level image resolutions. */ /*! \brief A bit mask of the currently supported bi-level image resolutions. */
int supported_bilevel_resolutions; int supported_bilevel_resolutions;
/*! \brief A bit mask of the currently supported gray-scale and colour image resolutions. */ /*! \brief A bit mask of the currently supported gray-scale and colour image resolutions. */

View File

@ -497,6 +497,12 @@
#define T30_DCS_BIT_T38_FAX_MODE 123 #define T30_DCS_BIT_T38_FAX_MODE 123
/* Bits 124 to 126 specify the T.89 applications profile. */ /* Bits 124 to 126 specify the T.89 applications profile. */
#define T30_DIS_BIT_T88_CAPABILITY_1 124
#define T30_DCS_BIT_T88_MODE_1 124
#define T30_DIS_BIT_T88_CAPABILITY_2 125
#define T30_DCS_BIT_T88_MODE_2 125
#define T30_DIS_BIT_T88_CAPABILITY_3 126
#define T30_DCS_BIT_T88_MODE_3 126
/* When either bit of 31, 36, 38, 51, 53, 54, 55, 57, 59, 60, 62, 65, 68, 78, 79, 115, 116 and 127 is /* When either bit of 31, 36, 38, 51, 53, 54, 55, 57, 59, 60, 62, 65, 68, 78, 79, 115, 116 and 127 is
set to "1", ECM must be used. If the value of bit field 92 to 94 is non-zero, then ECM must be used. set to "1", ECM must be used. If the value of bit field 92 to 94 is non-zero, then ECM must be used.

View File

@ -66,10 +66,6 @@ typedef struct
{ {
/*! \brief The FAX modem set for the audio side fo the gateway. */ /*! \brief The FAX modem set for the audio side fo the gateway. */
fax_modems_state_t modems; fax_modems_state_t modems;
/*! \brief CED detector */
modem_connect_tones_rx_state_t connect_rx_ced;
/*! \brief CNG detector */
modem_connect_tones_rx_state_t connect_rx_cng;
} t38_gateway_audio_state_t; } t38_gateway_audio_state_t;
/*! /*!

View File

@ -0,0 +1,87 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* private/t43.h - ITU T.43 JBIG for gray and colour FAX image processing
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2011 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.
*/
#if !defined(_SPANDSP_PRIVATE_T43_H_)
#define _SPANDSP_PRIVATE_T43_H_
/* State of a working instance of the T.43 JBIG for gray and colour FAX encoder */
struct t43_encode_state_s
{
/*! \brief Callback function to read a row of pixels from the image source. */
t4_row_read_handler_t row_read_handler;
/*! \brief Opaque pointer passed to row_read_handler. */
void *row_read_user_data;
struct lab_params_s lab;
struct t85_encode_state_s t85;
int bit_planes[4];
int colour_map_entries;
uint8_t colour_map[3*256];
/*! The width of the full image, in pixels */
uint32_t xd;
/*! The height of the full image, in pixels */
uint32_t yd;
int x_resolution;
int y_resolution;
/*! \brief Error and flow logging control */
logging_state_t logging;
};
/* State of a working instance of the T.43 JBIG for gray and colour FAX decoder */
struct t43_decode_state_s
{
/*! A callback routine to handle decoded pixel rows */
t4_row_write_handler_t row_write_handler;
/*! An opaque pointer passed to row_write_handler() */
void *row_write_user_data;
struct lab_params_s lab;
struct t85_decode_state_s t85;
int bit_planes[4];
uint8_t bit_plane_mask;
int current_bit_plane;
int plane_ptr;
int colour_map_entries;
uint8_t colour_map[3*256];
int x_resolution;
int y_resolution;
uint8_t *buf;
int ptr;
int row;
/*! \brief Error and flow logging control */
logging_state_t logging;
};
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -94,6 +94,10 @@ struct t4_rx_state_s
/*! \brief Opaque pointer passed to row_write_handler. */ /*! \brief Opaque pointer passed to row_write_handler. */
void *row_handler_user_data; void *row_handler_user_data;
/*! \brief A bit mask of the currently supported image compression modes for writing
to the TIFF file. */
int supported_tiff_compressions;
/*! \brief The number of pages transferred to date. */ /*! \brief The number of pages transferred to date. */
int current_page; int current_page;
@ -111,12 +115,24 @@ struct t4_rx_state_s
union union
{ {
t4_t6_decode_state_t t4_t6; t4_t6_decode_state_t t4_t6;
t85_decode_state_t t85;
#if defined(SPANDSP_SUPPORT_T88)
t88_decode_state_t t88;
#endif
t42_decode_state_t t42; t42_decode_state_t t42;
#if defined(SPANDSP_SUPPORT_T43) #if defined(SPANDSP_SUPPORT_T43)
t43_decode_state_t t43; t43_decode_state_t t43;
#endif #endif
t85_decode_state_t t85; #if defined(SPANDSP_SUPPORT_T45)
t45_decode_state_t t45;
#endif
} decoder; } decoder;
int current_decoder;
uint8_t *pre_encoded_buf;
int pre_encoded_len;
int pre_encoded_ptr;
int pre_encoded_bit;
/* Supporting information, like resolutions, which the backend may want. */ /* Supporting information, like resolutions, which the backend may want. */
t4_rx_metadata_t metadata; t4_rx_metadata_t metadata;

View File

@ -146,11 +146,17 @@ struct t4_tx_state_s
union union
{ {
t4_t6_encode_state_t t4_t6; t4_t6_encode_state_t t4_t6;
t85_encode_state_t t85;
#if defined(SPANDSP_SUPPORT_T88)
t88_encode_state_t t88;
#endif
t42_encode_state_t t42; t42_encode_state_t t42;
#if defined(SPANDSP_SUPPORT_T43) #if defined(SPANDSP_SUPPORT_T43)
t43_encode_state_t t43; t43_encode_state_t t43;
#endif #endif
t85_encode_state_t t85; #if defined(SPANDSP_SUPPORT_T45)
t45_encode_state_t t45;
#endif
} encoder; } encoder;
image_translate_state_t translator; image_translate_state_t translator;
@ -160,6 +166,11 @@ struct t4_tx_state_s
uint8_t *colour_map; uint8_t *colour_map;
int colour_map_entries; int colour_map_entries;
uint8_t *pre_encoded_buf;
int pre_encoded_len;
int pre_encoded_ptr;
int pre_encoded_bit;
/* Supporting information, like resolutions, which the backend may want. */ /* Supporting information, like resolutions, which the backend may want. */
t4_tx_metadata_t metadata; t4_tx_metadata_t metadata;

View File

@ -48,7 +48,6 @@ struct v18_state_s
int baudot_tx_shift; int baudot_tx_shift;
int tx_signal_on; int tx_signal_on;
uint8_t next_byte; uint8_t next_byte;
int byte_no;
fsk_rx_state_t fskrx; fsk_rx_state_t fskrx;
dtmf_rx_state_t dtmfrx; dtmf_rx_state_t dtmfrx;

View File

@ -439,12 +439,10 @@ SPAN_DECLARE(int) t30_set_ecm_capability(t30_state_t *s, int enabled);
/*! Specify the output encoding for TIFF files created during FAX reception. /*! Specify the output encoding for TIFF files created during FAX reception.
\brief Specify the output encoding for TIFF files created during FAX reception. \brief Specify the output encoding for TIFF files created during FAX reception.
\param s The T.30 context. \param s The T.30 context.
\param encoding The coding required. The options are T4_COMPRESSION_T4_1D, \param supported_compressions Bit field list of the supported compression types, for
T4_COMPRESSION_T4_2D, T4_COMPRESSION_T6. T6 is usually the output of received page images.
densest option, but support for it is broken in a number of software
packages.
\return 0 if OK, else -1. */ \return 0 if OK, else -1. */
SPAN_DECLARE(int) t30_set_rx_encoding(t30_state_t *s, int encoding); SPAN_DECLARE(int) t30_set_supported_output_compressions(t30_state_t *s, int supported_compressions);
/*! Specify the minimum scan line time supported by a T.30 context. /*! Specify the minimum scan line time supported by a T.30 context.
\brief Specify minimum scan line time. \brief Specify minimum scan line time.

View File

@ -0,0 +1,196 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* t43.h - ITU T.43 JBIG for grey and colour FAX image processing
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2011 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.
*/
/*! \file */
#if !defined(_SPANDSP_T43_H_)
#define _SPANDSP_T43_H_
/*! \page t43_page T.43 (JBIG for gray and colour FAX) image compression and decompression
\section t43_page_sec_1 What does it do?
\section t43_page_sec_1 How does it work?
*/
/*! State of a working instance of the T.43 encoder */
typedef struct t43_encode_state_s t43_encode_state_t;
/*! State of a working instance of the T.43 decoder */
typedef struct t43_decode_state_s t43_decode_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
SPAN_DECLARE(const char *) t43_image_type_to_str(int type);
SPAN_DECLARE(void) t43_encode_set_options(t43_encode_state_t *s,
uint32_t l0,
int mx,
int options);
SPAN_DECLARE(int) t43_encode_set_image_width(t43_encode_state_t *s, uint32_t image_width);
SPAN_DECLARE(int) t43_encode_set_image_length(t43_encode_state_t *s, uint32_t length);
SPAN_DECLARE(void) t43_encode_abort(t43_encode_state_t *s);
SPAN_DECLARE(void) t43_encode_comment(t43_encode_state_t *s, const uint8_t comment[], size_t len);
/*! \brief Check if we are at the end of the current document page.
\param s The T.43 context.
\return 0 for more data to come. SIG_STATUS_END_OF_DATA for no more data. */
SPAN_DECLARE(int) t43_encode_image_complete(t43_encode_state_t *s);
SPAN_DECLARE(int) t43_encode_get(t43_encode_state_t *s, uint8_t buf[], size_t max_len);
SPAN_DECLARE(uint32_t) t43_encode_get_image_width(t43_encode_state_t *s);
SPAN_DECLARE(uint32_t) t43_encode_get_image_length(t43_encode_state_t *s);
SPAN_DECLARE(int) t43_encode_get_compressed_image_size(t43_encode_state_t *s);
SPAN_DECLARE(int) t43_encode_set_row_read_handler(t43_encode_state_t *s,
t4_row_read_handler_t handler,
void *user_data);
/*! Get the logging context associated with a T.43 encode context.
\brief Get the logging context associated with a T.43 encode context.
\param s The T.43 encode context.
\return A pointer to the logging context */
SPAN_DECLARE(logging_state_t *) t43_encode_get_logging_state(t43_encode_state_t *s);
/*! \brief Restart a T.43 encode context.
\param s The T.43 context.
\param image image_width The image width, in pixels.
\param image image_width The image length, in pixels.
\return 0 for success, otherwise -1. */
SPAN_DECLARE(int) t43_encode_restart(t43_encode_state_t *s, uint32_t image_width, uint32_t image_length);
/*! \brief Prepare to encode an image in T.43 format.
\param s The T.43 context.
\param image_width Image width, in pixels.
\param image_length Image length, in pixels.
\param handler A callback routine to handle encoded image rows.
\param user_data An opaque pointer passed to handler.
\return A pointer to the context, or NULL if there was a problem. */
SPAN_DECLARE(t43_encode_state_t *) t43_encode_init(t43_encode_state_t *s,
uint32_t image_width,
uint32_t image_length,
t4_row_read_handler_t handler,
void *user_data);
/*! \brief Release a T.43 encode context.
\param s The T.43 encode context.
\return 0 for OK, else -1. */
SPAN_DECLARE(int) t43_encode_release(t43_encode_state_t *s);
/*! \brief Free a T.43 encode context.
\param s The T.43 encode context.
\return 0 for OK, else -1. */
SPAN_DECLARE(int) t43_encode_free(t43_encode_state_t *s);
SPAN_DECLARE(int) t43_create_header(t43_decode_state_t *s, uint8_t data[], size_t len);
SPAN_DECLARE(void) t43_decode_rx_status(t43_decode_state_t *s, int status);
/*! \brief Decode a chunk of T.43 data.
\param s The T.43 context.
\param data The data to be decoded.
\param len The length of the data to be decoded.
\return 0 for OK. */
SPAN_DECLARE(int) t43_decode_put(t43_decode_state_t *s, const uint8_t data[], size_t len);
/*! \brief Set the row handler routine.
\param s The T.43 context.
\param handler A callback routine to handle decoded image rows.
\param user_data An opaque pointer passed to handler.
\return 0 for OK. */
SPAN_DECLARE(int) t43_decode_set_row_write_handler(t43_decode_state_t *s,
t4_row_write_handler_t handler,
void *user_data);
/*! \brief Set the comment handler routine.
\param s The T.43 context.
\param max_comment_len The maximum length of comment to be passed to the handler.
\param handler A callback routine to handle decoded comment.
\param user_data An opaque pointer passed to handler.
\return 0 for OK. */
SPAN_DECLARE(int) t43_decode_set_comment_handler(t43_decode_state_t *s,
uint32_t max_comment_len,
t4_row_write_handler_t handler,
void *user_data);
SPAN_DECLARE(int) t43_decode_set_image_size_constraints(t43_decode_state_t *s,
uint32_t max_xd,
uint32_t max_yd);
/*! \brief Get the width of the image.
\param s The T.43 context.
\return The width of the image, in pixels. */
SPAN_DECLARE(uint32_t) t43_decode_get_image_width(t43_decode_state_t *s);
/*! \brief Get the length of the image.
\param s The T.43 context.
\return The length of the image, in pixels. */
SPAN_DECLARE(uint32_t) t43_decode_get_image_length(t43_decode_state_t *s);
SPAN_DECLARE(int) t43_decode_get_compressed_image_size(t43_decode_state_t *s);
/*! Get the logging context associated with a T.43 decode context.
\brief Get the logging context associated with a T.43 decode context.
\param s The T.43 decode context.
\return A pointer to the logging context */
SPAN_DECLARE(logging_state_t *) t43_decode_get_logging_state(t43_decode_state_t *s);
SPAN_DECLARE(int) t43_decode_restart(t43_decode_state_t *s);
/*! \brief Prepare to decode an image in T.43 format.
\param s The T.43 context.
\param handler A callback routine to handle decoded image rows.
\param user_data An opaque pointer passed to handler.
\return A pointer to the context, or NULL if there was a problem. */
SPAN_DECLARE(t43_decode_state_t *) t43_decode_init(t43_decode_state_t *s,
t4_row_write_handler_t handler,
void *user_data);
/*! \brief Release a T.43 decode context.
\param s The T.43 decode context.
\return 0 for OK, else -1. */
SPAN_DECLARE(int) t43_decode_release(t43_decode_state_t *s);
/*! \brief Free a T.43 decode context.
\param s The T.43 decode context.
\return 0 for OK, else -1. */
SPAN_DECLARE(int) t43_decode_free(t43_decode_state_t *s);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -67,47 +67,49 @@ typedef enum
/*! T.42 + T.81 + T.30 Annex E colour JPEG coding */ /*! T.42 + T.81 + T.30 Annex E colour JPEG coding */
T4_COMPRESSION_T42_T81 = 8, T4_COMPRESSION_T42_T81 = 8,
/*! T.42 + T.81 + T.30 Annex K colour sYCC-JPEG coding */ /*! T.42 + T.81 + T.30 Annex K colour sYCC-JPEG coding */
T4_COMPRESSION_SYCC_T81 = 9 T4_COMPRESSION_SYCC_T81 = 9,
/*! T.88 monochrome JBIG2 compression */
T4_COMPRESSION_T88 = 10
} t4_image_compression_t; } t4_image_compression_t;
enum enum
{ {
/*! No compression */ /*! No compression */
T30_SUPPORT_COMPRESSION_NONE = 0x01, T4_SUPPORT_COMPRESSION_NONE = 0x01,
/*! T.1 1D compression */ /*! T.1 1D compression */
T30_SUPPORT_COMPRESSION_T4_1D = 0x02, T4_SUPPORT_COMPRESSION_T4_1D = 0x02,
/*! T.4 2D compression */ /*! T.4 2D compression */
T30_SUPPORT_COMPRESSION_T4_2D = 0x04, T4_SUPPORT_COMPRESSION_T4_2D = 0x04,
/*! T.6 2D compression */ /*! T.6 2D compression */
T30_SUPPORT_COMPRESSION_T6 = 0x08, T4_SUPPORT_COMPRESSION_T6 = 0x08,
/*! T.85 monochrome JBIG compression, with fixed L0 */ /*! T.85 monochrome JBIG compression, with fixed L0 */
T30_SUPPORT_COMPRESSION_T85 = 0x10, T4_SUPPORT_COMPRESSION_T85 = 0x10,
/*! T.85 monochrome JBIG compression, with variable L0 */ /*! T.85 monochrome JBIG compression, with variable L0 */
T30_SUPPORT_COMPRESSION_T85_L0 = 0x20, T4_SUPPORT_COMPRESSION_T85_L0 = 0x20,
/*! T.43 colour JBIG compression */ /*! T.43 colour JBIG compression */
T30_SUPPORT_COMPRESSION_T43 = 0x40, T4_SUPPORT_COMPRESSION_T43 = 0x40,
/*! T.45 run length colour compression */ /*! T.45 run length colour compression */
T30_SUPPORT_COMPRESSION_T45 = 0x80, T4_SUPPORT_COMPRESSION_T45 = 0x80,
/*! T.81 + T.30 Annex E colour JPEG compression */ /*! T.81 + T.30 Annex E colour JPEG compression */
T30_SUPPORT_COMPRESSION_T42_T81 = 0x100, T4_SUPPORT_COMPRESSION_T42_T81 = 0x100,
/*! T.81 + T.30 Annex K colour sYCC-JPEG compression */ /*! T.81 + T.30 Annex K colour sYCC-JPEG compression */
T30_SUPPORT_COMPRESSION_SYCC_T81 = 0x200, T4_SUPPORT_COMPRESSION_SYCC_T81 = 0x200,
/*! T.88 monochrome JBIG2 compression */ /*! T.88 monochrome JBIG2 compression */
T30_SUPPORT_COMPRESSION_T88 = 0x400, T4_SUPPORT_COMPRESSION_T88 = 0x400,
/*! Gray-scale support by multi-level codecs */ /*! Gray-scale support by multi-level codecs */
T30_SUPPORT_COMPRESSION_GRAYSCALE = 0x1000000, T4_SUPPORT_COMPRESSION_GRAYSCALE = 0x1000000,
/*! Colour support by multi-level codecs */ /*! Colour support by multi-level codecs */
T30_SUPPORT_COMPRESSION_COLOUR = 0x2000000, T4_SUPPORT_COMPRESSION_COLOUR = 0x2000000,
/*! 12 bit mode for gray-scale and colour */ /*! 12 bit mode for gray-scale and colour */
T30_SUPPORT_COMPRESSION_12BIT = 0x4000000, T4_SUPPORT_COMPRESSION_12BIT = 0x4000000,
/*! Convert a colour image to a gray-scale one */ /*! Convert a colour image to a gray-scale one */
T30_SUPPORT_COMPRESSION_COLOUR_TO_GRAY = 0x8000000, T4_SUPPORT_COMPRESSION_COLOUR_TO_GRAY = 0x8000000,
/*! Dither a gray-scale image down a simple bilevel image, with rescaling to fit a FAX page */ /*! Dither a gray-scale image down a simple bilevel image, with rescaling to fit a FAX page */
T30_SUPPORT_GRAY_TO_BILEVEL = 0x10000000, T30_SUPPORT_GRAY_TO_BILEVEL = 0x10000000,
/*! Dither a colour image down a simple bilevel image, with rescaling to fit a FAX page */ /*! Dither a colour image down a simple bilevel image, with rescaling to fit a FAX page */
T30_SUPPORT_COLOUR_TO_BILEVEL = 0x20000000, T30_SUPPORT_COLOUR_TO_BILEVEL = 0x20000000,
/*! Rescale an image (except a bi-level image) to fit a permitted FAX width when necessary */ /*! Rescale an image (except a bi-level image) to fit a permitted FAX width when necessary */
T30_SUPPORT_COMPRESSION_RESCALING = 0x40000000 T4_SUPPORT_COMPRESSION_RESCALING = 0x40000000
}; };
/*! Image type */ /*! Image type */
@ -561,9 +563,9 @@ SPAN_DECLARE(logging_state_t *) t4_rx_get_logging_state(t4_rx_state_t *s);
/*! \brief Prepare for reception of a document. /*! \brief Prepare for reception of a document.
\param s The T.4 context. \param s The T.4 context.
\param file The name of the file to be received. \param file The name of the file to be received.
\param output_encoding The output encoding. \param supported_compressions The compression schemes supported for output to a TIFF file.
\return A pointer to the context, or NULL if there was a problem. */ \return A pointer to the context, or NULL if there was a problem. */
SPAN_DECLARE(t4_rx_state_t *) t4_rx_init(t4_rx_state_t *s, const char *file, int output_encoding); SPAN_DECLARE(t4_rx_state_t *) t4_rx_init(t4_rx_state_t *s, const char *file, int supported_compressions);
/*! \brief End reception of a document. Tidy up and close the file. /*! \brief End reception of a document. Tidy up and close the file.
This should be used to end T.4 reception started with t4_rx_init. This should be used to end T.4 reception started with t4_rx_init.

View File

@ -30,8 +30,8 @@
#endif #endif
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <inttypes.h> #include <inttypes.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include <fcntl.h> #include <fcntl.h>
#include <time.h> #include <time.h>
@ -1195,9 +1195,9 @@ int t30_build_dis_or_dtc(t30_state_t *s)
/* No scan-line padding required, but some may be specified by the application. */ /* No scan-line padding required, but some may be specified by the application. */
set_ctrl_bits(s->local_dis_dtc_frame, s->local_min_scan_time_code, T30_DIS_BIT_MIN_SCAN_LINE_TIME_CAPABILITY_1); set_ctrl_bits(s->local_dis_dtc_frame, s->local_min_scan_time_code, T30_DIS_BIT_MIN_SCAN_LINE_TIME_CAPABILITY_1);
if ((s->supported_compressions & T30_SUPPORT_COMPRESSION_T4_2D)) if ((s->supported_compressions & T4_SUPPORT_COMPRESSION_T4_2D))
set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_2D_CAPABLE); set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_2D_CAPABLE);
if ((s->supported_compressions & T30_SUPPORT_COMPRESSION_NONE)) if ((s->supported_compressions & T4_SUPPORT_COMPRESSION_NONE))
set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_UNCOMPRESSED_CAPABLE); set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_UNCOMPRESSED_CAPABLE);
if (s->ecm_allowed) if (s->ecm_allowed)
{ {
@ -1206,46 +1206,46 @@ int t30_build_dis_or_dtc(t30_state_t *s)
/* Only offer the option of fancy compression schemes, if we are /* Only offer the option of fancy compression schemes, if we are
also offering the ECM option needed to support them. */ also offering the ECM option needed to support them. */
if ((s->supported_compressions & T30_SUPPORT_COMPRESSION_T6)) if ((s->supported_compressions & T4_SUPPORT_COMPRESSION_T6))
set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T6_CAPABLE); set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T6_CAPABLE);
if ((s->supported_compressions & T30_SUPPORT_COMPRESSION_T85)) if ((s->supported_compressions & T4_SUPPORT_COMPRESSION_T85))
{ {
set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T85_CAPABLE); set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T85_CAPABLE);
/* Bit 79 set with bit 78 clear is invalid, so only check for L0 /* Bit 79 set with bit 78 clear is invalid, so only check for L0
support here. */ support here. */
if ((s->supported_compressions & T30_SUPPORT_COMPRESSION_T85_L0)) if ((s->supported_compressions & T4_SUPPORT_COMPRESSION_T85_L0))
set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T85_L0_CAPABLE); set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T85_L0_CAPABLE);
} }
if ((s->supported_compressions & T30_SUPPORT_COMPRESSION_COLOUR)) if ((s->supported_compressions & T4_SUPPORT_COMPRESSION_COLOUR))
set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_FULL_COLOUR_CAPABLE); set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_FULL_COLOUR_CAPABLE);
if ((s->supported_compressions & T30_SUPPORT_COMPRESSION_T42_T81)) if ((s->supported_compressions & T4_SUPPORT_COMPRESSION_T42_T81))
set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T81_CAPABLE); set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T81_CAPABLE);
if ((s->supported_compressions & T30_SUPPORT_COMPRESSION_T43)) if ((s->supported_compressions & T4_SUPPORT_COMPRESSION_T43))
{ {
/* Note 25 of table 2/T.30 */ /* Note 25 of table 2/T.30 */
set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T43_CAPABLE); set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T43_CAPABLE);
set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T81_CAPABLE); set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T81_CAPABLE);
} }
if ((s->supported_compressions & T30_SUPPORT_COMPRESSION_T45)) if ((s->supported_compressions & T4_SUPPORT_COMPRESSION_T45))
set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T45_CAPABLE); set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T45_CAPABLE);
if ((s->supported_compressions & T30_SUPPORT_COMPRESSION_SYCC_T81)) if ((s->supported_compressions & T4_SUPPORT_COMPRESSION_SYCC_T81))
{ {
set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T81_CAPABLE); set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T81_CAPABLE);
set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_SYCC_T81_CAPABLE); set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_SYCC_T81_CAPABLE);
} }
//if ((s->supported_compressions & T30_SUPPORT_COMPRESSION_T88)) //if ((s->supported_compressions & T4_SUPPORT_COMPRESSION_T88))
//{ //{
// set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T88_CAPABILITY_1); // set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T88_CAPABILITY_1);
// set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T88_CAPABILITY_2); // set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T88_CAPABILITY_2);
// set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T88_CAPABILITY_3); // set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T88_CAPABILITY_3);
//} //}
if ((s->supported_compressions & T30_SUPPORT_COMPRESSION_12BIT)) if ((s->supported_compressions & T4_SUPPORT_COMPRESSION_12BIT))
set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_12BIT_CAPABLE); set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_12BIT_CAPABLE);
//if ((s->supported_compressions & T30_SUPPORT_COMPRESSION_NO_SUBSAMPLING)) //if ((s->supported_compressions & T4_SUPPORT_COMPRESSION_NO_SUBSAMPLING))
// set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NO_SUBSAMPLING); // set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NO_SUBSAMPLING);
/* No custom illuminant */ /* No custom illuminant */
@ -1345,8 +1345,8 @@ int t30_build_dis_or_dtc(t30_state_t *s)
if ((s->supported_bilevel_resolutions & T4_SUPPORT_RESOLUTION_200_200)) if ((s->supported_bilevel_resolutions & T4_SUPPORT_RESOLUTION_200_200))
{ {
set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_200_200_CAPABLE); set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_200_200_CAPABLE);
//if ((s->supported_colour_resolutions & T4_SUPPORT_RESOLUTION_200_200)) if ((s->supported_colour_resolutions & T4_SUPPORT_RESOLUTION_200_200))
// set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_???_CAPABLE); set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_FULL_COLOUR_CAPABLE);
} }
/* Standard FAX resolution bi-level image support goes without saying */ /* Standard FAX resolution bi-level image support goes without saying */
if ((s->supported_colour_resolutions & T4_SUPPORT_RESOLUTION_100_100)) if ((s->supported_colour_resolutions & T4_SUPPORT_RESOLUTION_100_100))
@ -1421,14 +1421,14 @@ static int build_dcs(t30_state_t *s)
int bad; int bad;
int row_squashing_ratio; int row_squashing_ratio;
int use_bilevel; int use_bilevel;
//int image_type; int image_type;
/* Reacquire page information, in case the image was resized, flattened, etc. */ /* Reacquire page information, in case the image was resized, flattened, etc. */
s->x_resolution = t4_tx_get_x_resolution(&s->t4.tx); s->x_resolution = t4_tx_get_x_resolution(&s->t4.tx);
s->y_resolution = t4_tx_get_y_resolution(&s->t4.tx); s->y_resolution = t4_tx_get_y_resolution(&s->t4.tx);
//s->current_page_resolution = t4_tx_get_resolution(&s->t4.tx); s->current_page_resolution = t4_tx_get_resolution(&s->t4.tx);
s->image_width = t4_tx_get_image_width(&s->t4.tx); s->image_width = t4_tx_get_image_width(&s->t4.tx);
//image_type = t4_tx_get_image_type(&s->t4.tx); image_type = t4_tx_get_image_type(&s->t4.tx);
/* Make a DCS frame based on local issues and the latest received DIS/DTC frame. /* Make a DCS frame based on local issues and the latest received DIS/DTC frame.
Negotiate the result based on what both parties can do. */ Negotiate the result based on what both parties can do. */
@ -1483,22 +1483,24 @@ static int build_dcs(t30_state_t *s)
#endif #endif
case T4_COMPRESSION_T42_T81: case T4_COMPRESSION_T42_T81:
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T81_MODE); set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T81_MODE);
//if (image_type == T4_IMAGE_TYPE_COLOUR_8BIT || image_type == T4_IMAGE_TYPE_COLOUR_12BIT) if (image_type == T4_IMAGE_TYPE_COLOUR_8BIT || image_type == T4_IMAGE_TYPE_COLOUR_12BIT)
// set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_FULL_COLOUR_MODE); set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_FULL_COLOUR_MODE);
//if (image_type == T4_IMAGE_TYPE_GRAY_12BIT || image_type == T4_IMAGE_TYPE_COLOUR_12BIT) if (image_type == T4_IMAGE_TYPE_GRAY_12BIT || image_type == T4_IMAGE_TYPE_COLOUR_12BIT)
// set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_12BIT_COMPONENT); set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_12BIT_COMPONENT);
//if (???????? & T4_COMPRESSION_?????)) //if (???????? & T4_COMPRESSION_?????))
// set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_NO_SUBSAMPLING); // set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_NO_SUBSAMPLING);
//if (???????? & T4_COMPRESSION_?????))
// set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_PREFERRED_HUFFMAN_TABLES);
set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, T30_DCS_BIT_MIN_SCAN_LINE_TIME_1); set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, T30_DCS_BIT_MIN_SCAN_LINE_TIME_1);
use_bilevel = FALSE; use_bilevel = FALSE;
break; break;
#if defined(SPANDSP_SUPPORT_T43) #if defined(SPANDSP_SUPPORT_T43)
case T4_COMPRESSION_T43: case T4_COMPRESSION_T43:
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T43_MODE); set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T43_MODE);
//if (image_type == T4_IMAGE_TYPE_COLOUR_8BIT || image_type == T4_IMAGE_TYPE_COLOUR_12BIT) if (image_type == T4_IMAGE_TYPE_COLOUR_8BIT || image_type == T4_IMAGE_TYPE_COLOUR_12BIT)
// set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_FULL_COLOUR_MODE); set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_FULL_COLOUR_MODE);
//if (image_type == T4_IMAGE_TYPE_GRAY_12BIT || image_type == T4_IMAGE_TYPE_COLOUR_12BIT) if (image_type == T4_IMAGE_TYPE_GRAY_12BIT || image_type == T4_IMAGE_TYPE_COLOUR_12BIT)
// set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_12BIT_COMPONENT); set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_12BIT_COMPONENT);
//if (???????? & T4_COMPRESSION_?????)) //if (???????? & T4_COMPRESSION_?????))
// set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_NO_SUBSAMPLING); // set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_NO_SUBSAMPLING);
set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, T30_DCS_BIT_MIN_SCAN_LINE_TIME_1); set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, T30_DCS_BIT_MIN_SCAN_LINE_TIME_1);
@ -1523,159 +1525,139 @@ static int build_dcs(t30_state_t *s)
/* Set the Y resolution bits */ /* Set the Y resolution bits */
row_squashing_ratio = 1; row_squashing_ratio = 1;
bad = T30_ERR_NORESSUPPORT; bad = T30_ERR_NORESSUPPORT;
if (use_bilevel) if ((use_bilevel && (s->current_page_resolution & s->mutual_bilevel_resolutions))
||
(!use_bilevel && (s->current_page_resolution & s->mutual_colour_resolutions)))
{ {
switch (s->y_resolution) /* The resolution is supported by both parties */
switch (s->current_page_resolution)
{ {
case T4_Y_RESOLUTION_1200: case T4_RESOLUTION_1200_1200:
switch (s->x_resolution) set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_1200_1200);
{ set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION);
case T4_X_RESOLUTION_1200: if (!use_bilevel)
if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_1200_1200)) set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_COLOUR_GRAY_1200_1200);
{
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_1200_1200);
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION);
bad = T30_ERR_OK;
}
break;
case T4_X_RESOLUTION_600:
if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_600_1200))
{
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_600_1200);
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION);
bad = T30_ERR_OK;
}
break;
}
break; break;
case T4_Y_RESOLUTION_800: case T4_RESOLUTION_600_1200:
switch (s->x_resolution) set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_600_1200);
{ set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION);
case T4_X_RESOLUTION_R16:
if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_400_800))
{
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_400_800);
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION);
bad = T30_ERR_OK;
}
break;
}
break; break;
case T4_Y_RESOLUTION_600: case T4_RESOLUTION_600_600:
switch (s->x_resolution) set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_600_600);
{ set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION);
case T4_X_RESOLUTION_600: if (!use_bilevel)
if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_600_600)) set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_COLOUR_GRAY_600_600);
{
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_600_600);
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION);
bad = T30_ERR_OK;
}
break;
case T4_X_RESOLUTION_300:
if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_300_600))
{
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_300_600);
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION);
bad = T30_ERR_OK;
}
break;
}
break; break;
case T4_Y_RESOLUTION_300: case T4_RESOLUTION_400_800:
switch (s->x_resolution) set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_400_800);
{ set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION);
case T4_X_RESOLUTION_300:
if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_300_300))
{
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_300_300);
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION);
bad = T30_ERR_OK;
}
break;
}
break; break;
case T4_Y_RESOLUTION_SUPERFINE: case T4_RESOLUTION_400_400:
case T4_Y_RESOLUTION_400: set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_400_400);
if (s->x_resolution == T4_X_RESOLUTION_400 && s->y_resolution == T4_Y_RESOLUTION_400) set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION);
if (!use_bilevel)
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_COLOUR_GRAY_300_300_400_400);
break;
case T4_RESOLUTION_300_600:
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_300_600);
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION);
break;
case T4_RESOLUTION_300_300:
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_300_300);
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION);
if (!use_bilevel)
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_COLOUR_GRAY_300_300_400_400);
break;
case T4_RESOLUTION_200_400:
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_400);
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION);
break;
case T4_RESOLUTION_200_200:
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_200);
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION);
if (!use_bilevel)
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_FULL_COLOUR_MODE);
break;
case T4_RESOLUTION_200_100:
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION);
break;
case T4_RESOLUTION_100_100:
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION);
if (!use_bilevel)
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_COLOUR_GRAY_100_100);
break;
case T4_RESOLUTION_R16_SUPERFINE:
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_400_400);
break;
case T4_RESOLUTION_R8_SUPERFINE:
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_400);
break;
case T4_RESOLUTION_R8_FINE:
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_200);
break;
case T4_RESOLUTION_R8_STANDARD:
/* Nothing special to set */
break;
}
bad = T30_ERR_OK;
}
else
{
#if 0
/* Deal with resolution fudging */
if ((s->current_page_resolution & (T4_RESOLUTION_R16_SUPERFINE | T4_RESOLUTION_R8_SUPERFINE | T4_RESOLUTION_R8_FINE | T4_RESOLUTION_R8_STANDARD)))
{
if ((s->mutual_bilevel_resolutions & (T4_RESOLUTION_400_400 | T4_RESOLUTION_200_400 | T4_RESOLUTION_200_200 | T4_RESOLUTION_200_100)))
{ {
if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_400_400)) /* Fudge between imperial and metric */
{
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_400_400);
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION);
bad = T30_ERR_OK;
break;
}
} }
else if (s->x_resolution == T4_X_RESOLUTION_R16 && s->y_resolution == T4_Y_RESOLUTION_SUPERFINE) }
else if ((s->current_page_resolution & (T4_RESOLUTION_400_400 | T4_RESOLUTION_200_400 | T4_RESOLUTION_200_200 | T4_RESOLUTION_200_100))
{
if ((s->mutual_bilevel_resolutions & (T4_RESOLUTION_R16_SUPERFINE | T4_RESOLUTION_R8_SUPERFINE | T4_RESOLUTION_R8_FINE | T4_RESOLUTION_R8_STANDARD)))
{ {
if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_R16_SUPERFINE)) /* Fudge between imperial and metric */
{
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_400_400);
bad = T30_ERR_OK;
break;
}
} }
else if (s->x_resolution == T4_X_RESOLUTION_200 && s->y_resolution == T4_Y_RESOLUTION_400) }
#endif
/* Deal with squashing options */
if ((s->current_page_resolution & T4_RESOLUTION_R8_SUPERFINE))
{
if ((s->mutual_bilevel_resolutions & T4_RESOLUTION_R8_FINE))
{ {
if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_200_400)) set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_200);
{ row_squashing_ratio = 2;
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_400);
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION);
bad = T30_ERR_OK;
break;
}
}
else if (s->x_resolution == T4_X_RESOLUTION_R8 && s->y_resolution == T4_Y_RESOLUTION_SUPERFINE)
{
if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_R8_SUPERFINE))
{
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_400);
bad = T30_ERR_OK;
break;
}
}
row_squashing_ratio <<= 1;
/* Fall through */
case T4_Y_RESOLUTION_FINE:
case T4_Y_RESOLUTION_200:
if (s->x_resolution == T4_X_RESOLUTION_200 && s->y_resolution == T4_Y_RESOLUTION_200)
{
if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_200_200))
{
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_200);
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION);
bad = T30_ERR_OK;
break;
}
}
else if (s->x_resolution == T4_X_RESOLUTION_R8 && s->y_resolution == T4_Y_RESOLUTION_FINE)
{
if ((s->mutual_bilevel_resolutions & T4_SUPPORT_RESOLUTION_R8_FINE))
{
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_200);
bad = T30_ERR_OK;
break;
}
}
row_squashing_ratio <<= 1;
/* Fall through */
default:
case T4_Y_RESOLUTION_STANDARD:
case T4_Y_RESOLUTION_100:
if (s->x_resolution == T4_X_RESOLUTION_R8 && s->y_resolution == T4_Y_RESOLUTION_STANDARD)
{
/* No bits to set for this */
bad = T30_ERR_OK; bad = T30_ERR_OK;
break;
} }
else if (s->x_resolution == T4_X_RESOLUTION_200 && s->y_resolution == T4_Y_RESOLUTION_100) else if ((s->mutual_bilevel_resolutions & T4_RESOLUTION_R8_STANDARD))
{ {
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INCH_RESOLUTION); row_squashing_ratio = 4;
bad = T30_ERR_OK; bad = T30_ERR_OK;
break;
} }
break; }
else if ((s->current_page_resolution & T4_RESOLUTION_R8_FINE) && (s->mutual_bilevel_resolutions & T4_RESOLUTION_R8_STANDARD))
{
row_squashing_ratio = 2;
bad = T30_ERR_OK;
}
else if ((s->current_page_resolution & T4_RESOLUTION_200_400))
{
if ((s->mutual_bilevel_resolutions & T4_RESOLUTION_200_200))
{
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_200);
row_squashing_ratio = 2;
bad = T30_ERR_OK;
}
else if ((s->mutual_bilevel_resolutions & T4_RESOLUTION_200_100))
{
row_squashing_ratio = 4;
bad = T30_ERR_OK;
}
}
else if ((s->current_page_resolution & T4_RESOLUTION_200_200) && (s->mutual_bilevel_resolutions & T4_RESOLUTION_200_100))
{
row_squashing_ratio = 2;
bad = T30_ERR_OK;
} }
} }
@ -1768,10 +1750,15 @@ static int build_dcs(t30_state_t *s)
/* Deal with the image length */ /* Deal with the image length */
/* If the other end supports unlimited length, then use that. Otherwise, if the other end supports /* If the other end supports unlimited length, then use that. Otherwise, if the other end supports
B4 use that, as its longer than the default A4 length. */ B4 use that, as its longer than the default A4 length. */
printf("Size1 0x%x\n", s->mutual_image_sizes);
if ((s->mutual_image_sizes & T4_SUPPORT_LENGTH_UNLIMITED)) if ((s->mutual_image_sizes & T4_SUPPORT_LENGTH_UNLIMITED))
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_UNLIMITED_LENGTH); set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_UNLIMITED_LENGTH);
else if ((s->mutual_image_sizes & T4_SUPPORT_LENGTH_B4)) else if ((s->mutual_image_sizes & T4_SUPPORT_LENGTH_B4))
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_B4_LENGTH); set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_B4_LENGTH);
else if ((s->mutual_image_sizes & T4_SUPPORT_LENGTH_US_LETTER))
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_NORTH_AMERICAN_LETTER);
else if ((s->mutual_image_sizes & T4_SUPPORT_LENGTH_US_LEGAL))
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_NORTH_AMERICAN_LEGAL);
if (s->error_correcting_mode) if (s->error_correcting_mode)
set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_ECM_MODE); set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_ECM_MODE);
@ -1845,40 +1832,40 @@ static int analyze_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len)
if (!s->error_correcting_mode) if (!s->error_correcting_mode)
{ {
/* Remove any compression schemes which need error correction to work. */ /* Remove any compression schemes which need error correction to work. */
s->mutual_compressions &= (0xF0000000 | T30_SUPPORT_COMPRESSION_NONE | T30_SUPPORT_COMPRESSION_T4_1D | T30_SUPPORT_COMPRESSION_T4_2D); s->mutual_compressions &= (0xF0000000 | T4_SUPPORT_COMPRESSION_NONE | T4_SUPPORT_COMPRESSION_T4_1D | T4_SUPPORT_COMPRESSION_T4_2D);
if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_2D_CAPABLE)) if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_2D_CAPABLE))
s->mutual_compressions &= ~T30_SUPPORT_COMPRESSION_T4_2D; s->mutual_compressions &= ~T4_SUPPORT_COMPRESSION_T4_2D;
} }
else else
{ {
/* Check the bi-level capabilities */ /* Check the bi-level capabilities */
if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_2D_CAPABLE)) if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_2D_CAPABLE))
s->mutual_compressions &= ~T30_SUPPORT_COMPRESSION_T4_2D; s->mutual_compressions &= ~T4_SUPPORT_COMPRESSION_T4_2D;
if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T6_CAPABLE)) if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T6_CAPABLE))
s->mutual_compressions &= ~T30_SUPPORT_COMPRESSION_T6; s->mutual_compressions &= ~T4_SUPPORT_COMPRESSION_T6;
/* T.85 L0 capable without T.85 capable is an invalid combination, so let /* T.85 L0 capable without T.85 capable is an invalid combination, so let
just zap both capabilities if the far end is not T.85 capable. */ just zap both capabilities if the far end is not T.85 capable. */
if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T85_CAPABLE)) if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T85_CAPABLE))
s->mutual_compressions &= ~(T30_SUPPORT_COMPRESSION_T85 | T30_SUPPORT_COMPRESSION_T85_L0); s->mutual_compressions &= ~(T4_SUPPORT_COMPRESSION_T85 | T4_SUPPORT_COMPRESSION_T85_L0);
if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T85_L0_CAPABLE)) if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T85_L0_CAPABLE))
s->mutual_compressions &= ~T30_SUPPORT_COMPRESSION_T85_L0; s->mutual_compressions &= ~T4_SUPPORT_COMPRESSION_T85_L0;
/* Check for full colour or only gray-scale from the multi-level codecs */ /* Check for full colour or only gray-scale from the multi-level codecs */
//if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_FULL_COLOUR_CAPABLE)) if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_FULL_COLOUR_CAPABLE))
// s->mutual_compressions &= ~T4_SUPPORT_COMPRESSION_COLOUR; s->mutual_compressions &= ~T4_SUPPORT_COMPRESSION_COLOUR;
/* Check the colour capabilities */ /* Check the colour capabilities */
if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T81_CAPABLE)) if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T81_CAPABLE))
s->mutual_compressions &= ~T30_SUPPORT_COMPRESSION_T42_T81; s->mutual_compressions &= ~T4_SUPPORT_COMPRESSION_T42_T81;
if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_SYCC_T81_CAPABLE)) if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_SYCC_T81_CAPABLE))
s->mutual_compressions &= ~T30_SUPPORT_COMPRESSION_SYCC_T81; s->mutual_compressions &= ~T4_SUPPORT_COMPRESSION_SYCC_T81;
if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T43_CAPABLE)) if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T43_CAPABLE))
s->mutual_compressions &= ~T30_SUPPORT_COMPRESSION_T43; s->mutual_compressions &= ~T4_SUPPORT_COMPRESSION_T43;
if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T45_CAPABLE)) if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T45_CAPABLE))
s->mutual_compressions &= ~T30_SUPPORT_COMPRESSION_T45; s->mutual_compressions &= ~T4_SUPPORT_COMPRESSION_T45;
if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_12BIT_CAPABLE)) if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_12BIT_CAPABLE))
s->mutual_compressions &= ~T30_SUPPORT_COMPRESSION_12BIT; s->mutual_compressions &= ~T4_SUPPORT_COMPRESSION_12BIT;
//if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_NO_SUBSAMPLING)) //if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_NO_SUBSAMPLING))
// ???? = T4_COMPRESSION_T42_T81_SUBSAMPLING; // ???? = T4_COMPRESSION_T42_T81_SUBSAMPLING;
@ -1975,9 +1962,9 @@ static int analyze_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len)
if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_A4_B4_LENGTH_CAPABLE)) if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_A4_B4_LENGTH_CAPABLE))
s->mutual_image_sizes &= ~T4_SUPPORT_LENGTH_B4; s->mutual_image_sizes &= ~T4_SUPPORT_LENGTH_B4;
} }
if (!test_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NORTH_AMERICAN_LETTER_CAPABLE)) if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_NORTH_AMERICAN_LETTER_CAPABLE))
s->mutual_image_sizes &= ~T4_SUPPORT_LENGTH_US_LETTER; s->mutual_image_sizes &= ~T4_SUPPORT_LENGTH_US_LETTER;
if (!test_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NORTH_AMERICAN_LEGAL_CAPABLE)) if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_NORTH_AMERICAN_LEGAL_CAPABLE))
s->mutual_image_sizes &= ~T4_SUPPORT_LENGTH_US_LEGAL; s->mutual_image_sizes &= ~T4_SUPPORT_LENGTH_US_LEGAL;
switch (s->far_dis_dtc_frame[4] & (DISBIT6 | DISBIT5 | DISBIT4 | DISBIT3)) switch (s->far_dis_dtc_frame[4] & (DISBIT6 | DISBIT5 | DISBIT4 | DISBIT3))
@ -2067,6 +2054,7 @@ static int analyze_rx_dcs(t30_state_t *s, const uint8_t *msg, int len)
s->x_resolution = -1; s->x_resolution = -1;
s->y_resolution = -1; s->y_resolution = -1;
s->current_page_resolution = 0; s->current_page_resolution = 0;
s->line_encoding = -1;
x = -1; x = -1;
if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T81_MODE) if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T81_MODE)
|| ||
@ -2081,17 +2069,28 @@ static int analyze_rx_dcs(t30_state_t *s, const uint8_t *msg, int len)
/* Note 35 of Table 2/T.30 */ /* Note 35 of Table 2/T.30 */
if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_FULL_COLOUR_MODE)) if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_FULL_COLOUR_MODE))
{ {
/* We are going to work in full colour mode */ if ((s->supported_colour_resolutions & T4_SUPPORT_COMPRESSION_COLOUR))
{
/* We are going to work in full colour mode */
}
} }
if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_12BIT_COMPONENT)) if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_12BIT_COMPONENT))
{ {
/* We are going to work in 12 bit mode */ if ((s->supported_colour_resolutions & T4_SUPPORT_COMPRESSION_12BIT))
{
/* We are going to work in 12 bit mode */
}
} }
if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_NO_SUBSAMPLING)) if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_NO_SUBSAMPLING))
{ {
//???? = T30_SUPPORT_COMPRESSION_T42_T81_SUBSAMPLING; //???? = T4_SUPPORT_COMPRESSION_T42_T81_SUBSAMPLING;
}
if (!test_ctrl_bit(dcs_frame, T30_DCS_BIT_PREFERRED_HUFFMAN_TABLES))
{
//???? = T4_SUPPORT_COMPRESSION_T42_T81_HUFFMAN;
} }
if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_COLOUR_GRAY_1200_1200)) if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_COLOUR_GRAY_1200_1200))
@ -2154,6 +2153,28 @@ static int analyze_rx_dcs(t30_state_t *s, const uint8_t *msg, int len)
x = 0; x = 0;
} }
} }
/* Check which compression the far end has decided to use. */
if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T81_MODE))
{
if ((s->supported_compressions & T4_SUPPORT_COMPRESSION_T42_T81))
s->line_encoding = T4_COMPRESSION_T42_T81;
}
else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T43_MODE))
{
if ((s->supported_compressions & T4_SUPPORT_COMPRESSION_T43))
s->line_encoding = T4_COMPRESSION_T43;
}
else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T45_MODE))
{
if ((s->supported_compressions & T4_SUPPORT_COMPRESSION_T45))
s->line_encoding = T4_COMPRESSION_T45;
}
else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_SYCC_T81_MODE))
{
if ((s->supported_compressions & T4_SUPPORT_COMPRESSION_SYCC_T81))
s->line_encoding = T4_COMPRESSION_SYCC_T81;
}
} }
else else
{ {
@ -2304,8 +2325,51 @@ static int analyze_rx_dcs(t30_state_t *s, const uint8_t *msg, int len)
x = 1; x = 1;
} }
} }
/* Check which compression the far end has decided to use. */
if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T88_MODE_1)
||
test_ctrl_bit(dcs_frame, T30_DCS_BIT_T88_MODE_2)
||
test_ctrl_bit(dcs_frame, T30_DCS_BIT_T88_MODE_3))
{
if ((s->supported_compressions & T4_SUPPORT_COMPRESSION_T88))
s->line_encoding = T4_COMPRESSION_T88;
}
if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T85_L0_MODE))
{
if ((s->supported_compressions & T4_SUPPORT_COMPRESSION_T85_L0))
s->line_encoding = T4_COMPRESSION_T85_L0;
}
else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T85_MODE))
{
if ((s->supported_compressions & T4_SUPPORT_COMPRESSION_T85))
s->line_encoding = T4_COMPRESSION_T85;
}
else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T6_MODE))
{
if ((s->supported_compressions & T4_SUPPORT_COMPRESSION_T6))
s->line_encoding = T4_COMPRESSION_T6;
}
else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_2D_MODE))
{
if ((s->supported_compressions & T4_SUPPORT_COMPRESSION_T4_2D))
s->line_encoding = T4_COMPRESSION_T4_2D;
}
else
{
if ((s->supported_compressions & T4_SUPPORT_COMPRESSION_T4_1D))
s->line_encoding = T4_COMPRESSION_T4_1D;
}
} }
if (s->line_encoding == -1)
{
t30_set_status(s, T30_ERR_INCOMPATIBLE);
return -1;
}
span_log(&s->logging, SPAN_LOG_FLOW, "Far end selected compression %s (%d)\n", t4_encoding_to_str(s->line_encoding), s->line_encoding);
if (x < 0) if (x < 0)
{ {
t30_set_status(s, T30_ERR_NORESSUPPORT); t30_set_status(s, T30_ERR_NORESSUPPORT);
@ -2313,43 +2377,8 @@ static int analyze_rx_dcs(t30_state_t *s, const uint8_t *msg, int len)
} }
s->image_width = widths[x][dcs_frame[5] & (DISBIT2 | DISBIT1)]; s->image_width = widths[x][dcs_frame[5] & (DISBIT2 | DISBIT1)];
/* We don't care that much about the image length control bits. Just accept what arrives */
/* Check which compression the far end has decided to use. */
#if defined(SPANDSP_SUPPORT_T42)
if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T81_MODE))
{
s->line_encoding = T4_COMPRESSION_T42_T81;
}
else
#endif
#if defined(SPANDSP_SUPPORT_T43)
if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T43_MODE))
{
s->line_encoding = T4_COMPRESSION_T43;
}
else
#endif
if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T85_L0_MODE))
{
s->line_encoding = T4_COMPRESSION_T85_L0;
}
else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T85_MODE))
{
s->line_encoding = T4_COMPRESSION_T85;
}
else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T6_MODE))
{
s->line_encoding = T4_COMPRESSION_T6;
}
else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_2D_MODE))
{
s->line_encoding = T4_COMPRESSION_T4_2D;
}
else
{
s->line_encoding = T4_COMPRESSION_T4_1D;
}
span_log(&s->logging, SPAN_LOG_FLOW, "Far end selected compression %s (%d)\n", t4_encoding_to_str(s->line_encoding), s->line_encoding);
if (!test_ctrl_bit(dcs_frame, T30_DCS_BIT_RECEIVE_FAX_DOCUMENT)) if (!test_ctrl_bit(dcs_frame, T30_DCS_BIT_RECEIVE_FAX_DOCUMENT))
span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Remote is not requesting receive in DCS\n"); span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Remote is not requesting receive in DCS\n");
@ -2749,13 +2778,13 @@ static int process_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len)
} }
/* Choose a compression scheme from amongst those mutually available */ /* Choose a compression scheme from amongst those mutually available */
if ((s->mutual_compressions & T30_SUPPORT_COMPRESSION_T85_L0)) if ((s->mutual_compressions & T4_SUPPORT_COMPRESSION_T85_L0))
s->line_encoding = T4_COMPRESSION_T85_L0; s->line_encoding = T4_COMPRESSION_T85_L0;
else if ((s->mutual_compressions & T30_SUPPORT_COMPRESSION_T85)) else if ((s->mutual_compressions & T4_SUPPORT_COMPRESSION_T85))
s->line_encoding = T4_COMPRESSION_T85; s->line_encoding = T4_COMPRESSION_T85;
else if ((s->mutual_compressions & T30_SUPPORT_COMPRESSION_T6)) else if ((s->mutual_compressions & T4_SUPPORT_COMPRESSION_T6))
s->line_encoding = T4_COMPRESSION_T6; s->line_encoding = T4_COMPRESSION_T6;
else if ((s->mutual_compressions & T30_SUPPORT_COMPRESSION_T4_2D)) else if ((s->mutual_compressions & T4_SUPPORT_COMPRESSION_T4_2D))
s->line_encoding = T4_COMPRESSION_T4_2D; s->line_encoding = T4_COMPRESSION_T4_2D;
else else
s->line_encoding = T4_COMPRESSION_T4_1D; s->line_encoding = T4_COMPRESSION_T4_1D;
@ -6766,7 +6795,7 @@ SPAN_DECLARE(t30_state_t *) t30_init(t30_state_t *s,
/* Default to the basic modems. */ /* Default to the basic modems. */
s->supported_modems = T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17; s->supported_modems = T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17;
s->supported_compressions = T30_SUPPORT_COMPRESSION_T4_1D | T30_SUPPORT_COMPRESSION_T4_2D; s->supported_compressions = T4_SUPPORT_COMPRESSION_T4_1D | T4_SUPPORT_COMPRESSION_T4_2D;
s->supported_bilevel_resolutions = T4_SUPPORT_RESOLUTION_R8_STANDARD s->supported_bilevel_resolutions = T4_SUPPORT_RESOLUTION_R8_STANDARD
| T4_SUPPORT_RESOLUTION_R8_FINE | T4_SUPPORT_RESOLUTION_R8_FINE
| T4_SUPPORT_RESOLUTION_R8_SUPERFINE; | T4_SUPPORT_RESOLUTION_R8_SUPERFINE;

View File

@ -646,19 +646,11 @@ SPAN_DECLARE(int) t30_set_ecm_capability(t30_state_t *s, int enabled)
} }
/*- End of function --------------------------------------------------------*/ /*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t30_set_rx_encoding(t30_state_t *s, int encoding) SPAN_DECLARE(int) t30_set_supported_output_compressions(t30_state_t *s, int supported_compressions)
{ {
switch (encoding) s->supported_output_compressions = supported_compressions;
{ s->output_encoding = supported_compressions;
case T4_COMPRESSION_T4_1D: return 0;
case T4_COMPRESSION_T4_2D:
case T4_COMPRESSION_T6:
//case T4_COMPRESSION_T85:
//case T4_COMPRESSION_T85_L0:
s->output_encoding = encoding;
return 0;
}
return -1;
} }
/*- End of function --------------------------------------------------------*/ /*- End of function --------------------------------------------------------*/
@ -694,14 +686,14 @@ SPAN_DECLARE(int) t30_set_supported_modems(t30_state_t *s, int supported_modems)
SPAN_DECLARE(int) t30_set_supported_compressions(t30_state_t *s, int supported_compressions) SPAN_DECLARE(int) t30_set_supported_compressions(t30_state_t *s, int supported_compressions)
{ {
/* Mask out the ones we actually support today. */ /* Mask out the ones we actually support today. */
supported_compressions &= T30_SUPPORT_COMPRESSION_T4_1D supported_compressions &= T4_SUPPORT_COMPRESSION_T4_1D
| T30_SUPPORT_COMPRESSION_T4_2D | T4_SUPPORT_COMPRESSION_T4_2D
| T30_SUPPORT_COMPRESSION_T6 | T4_SUPPORT_COMPRESSION_T6
| T30_SUPPORT_COMPRESSION_T85 | T4_SUPPORT_COMPRESSION_T85
| T30_SUPPORT_COMPRESSION_T85_L0 | T4_SUPPORT_COMPRESSION_T85_L0
//| T30_SUPPORT_COMPRESSION_T81 //| T4_SUPPORT_COMPRESSION_T81
#if defined(SPANDSP_SUPPORT_T43) #if defined(SPANDSP_SUPPORT_T43)
| T30_SUPPORT_COMPRESSION_T43 | T4_SUPPORT_COMPRESSION_T43
#endif #endif
| 0; | 0;
s->supported_compressions = supported_compressions; s->supported_compressions = supported_compressions;

845
libs/spandsp/src/t43.c Normal file
View File

@ -0,0 +1,845 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* t43.c - ITU T.43 JBIG for grey and colour FAX image processing
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2011, 2013 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.
*/
/*! \file */
#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <tiffio.h>
#if defined(HAVE_TGMATH_H)
#include <tgmath.h>
#endif
#if defined(HAVE_MATH_H)
#include <math.h>
#endif
#include <time.h>
#include "floating_fudge.h"
#include <jpeglib.h>
#include <setjmp.h>
#include "spandsp/telephony.h"
#include "spandsp/logging.h"
#include "spandsp/async.h"
#include "spandsp/timezone.h"
#include "spandsp/t4_rx.h"
#include "spandsp/t4_tx.h"
#include "spandsp/t81_t82_arith_coding.h"
#include "spandsp/t85.h"
#include "spandsp/t42.h"
#include "spandsp/t43.h"
#include "spandsp/private/logging.h"
#include "spandsp/private/t81_t82_arith_coding.h"
#include "spandsp/private/t85.h"
#include "spandsp/private/t42.h"
#include "spandsp/private/t43.h"
#include "t42_t43_local.h"
#if !defined(FALSE)
#define FALSE 0
#endif
#if !defined(TRUE)
#define TRUE (!FALSE)
#endif
SPAN_DECLARE(const char *) t43_image_type_to_str(int type)
{
switch (type)
{
case 0:
return "1 bit/colour image (RGB primaries)";
case 1:
return "1 bit/colour image (CMY primaries)";
case 2:
return "1 bit/colour image (CMYK primaries)";
case 16:
return "Palettized colour image (CIELAB 8 bits/component precision table)";
case 17:
return "Palettized colour image (CIELAB 12 bits/component precision table)";
case 32:
return "Gray-scale image (using L*)";
case 48:
return "Continuous-tone colour image (CIELAB)";
}
return "???";
}
/*- End of function --------------------------------------------------------*/
static __inline__ uint16_t pack_16(const uint8_t *s)
{
uint16_t value;
value = ((uint16_t) s[0] << 8) | (uint16_t) s[1];
return value;
}
/*- End of function --------------------------------------------------------*/
static __inline__ uint32_t pack_32(const uint8_t *s)
{
uint32_t value;
value = ((uint32_t) s[0] << 24) | ((uint32_t) s[1] << 16) | ((uint32_t) s[2] << 8) | (uint32_t) s[3];
return value;
}
/*- End of function --------------------------------------------------------*/
static __inline__ int unpack_16(uint8_t *s, uint16_t value)
{
s[0] = (value >> 8) & 0xFF;
s[1] = value & 0xFF;
return sizeof(uint16_t);
}
/*- End of function --------------------------------------------------------*/
static __inline__ int unpack_32(uint8_t *s, uint32_t value)
{
s[0] = (value >> 24) & 0xFF;
s[1] = (value >> 16) & 0xFF;
s[2] = (value >> 8) & 0xFF;
s[3] = value & 0xFF;
return sizeof(uint16_t);
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t43_create_header(t43_decode_state_t *s, uint8_t data[], size_t len)
{
int pos;
pos = 0;
unpack_16(data, 0xFFA8);
pos += 2;
span_log(&s->logging, SPAN_LOG_FLOW, "Putting G3FAX0\n");
unpack_16(&data[pos], 0xFFE1);
pos += 2;
unpack_16(&data[pos], 2 + 6 + 10);
pos += 2;
memcpy(&data[pos], "G3FAX\0", 6);
pos += 6;
unpack_16(&data[pos], 1997);
pos += 2;
unpack_16(&data[pos], s->x_resolution);
pos += 2;
/* JBIG coding method (0) is the only possible value here */
data[pos] = 0;
pos += 1;
data[pos] = 42; //image_type;
pos += 1;
data[pos] = s->bit_planes[0];
pos += 1;
data[pos] = s->bit_planes[1];
pos += 1;
data[pos] = s->bit_planes[2];
pos += 1;
data[pos] = s->bit_planes[3];
pos += 1;
if (s->lab.offset_L != 0
||
s->lab.range_L != 100
||
s->lab.offset_a != 128
||
s->lab.range_a != 170
||
s->lab.offset_b != 96
||
s->lab.range_b != 200)
{
span_log(&s->logging, SPAN_LOG_FLOW, "Putting G3FAX1\n");
unpack_16(&data[pos], 0xFFE1);
pos += 2;
unpack_16(&data[pos], 2 + 6 + 12);
pos += 2;
memcpy(&data[pos], "G3FAX\1", 6);
pos += 6;
unpack_16(&data[pos + 0], s->lab.offset_L);
unpack_16(&data[pos + 2], s->lab.range_L);
unpack_16(&data[pos + 4], s->lab.offset_a);
unpack_16(&data[pos + 6], s->lab.range_a);
unpack_16(&data[pos + 8], s->lab.offset_b);
unpack_16(&data[pos + 10], s->lab.range_b);
pos += 12;
}
if (s->lab.x_n != 0.9638f || s->lab.y_n != 1.0f || s->lab.z_n != 0.8245f)
{
span_log(&s->logging, SPAN_LOG_FLOW, "Putting G3FAX2\n");
unpack_16(&data[pos], 0xFFE1);
pos += 2;
unpack_16(&data[pos], 2 + 6 + 6);
pos += 2;
memcpy(&data[pos], "G3FAX\2", 6);
pos += 6;
unpack_16(&data[pos], 0);
unpack_16(&data[pos + 2], 0);
unpack_16(&data[pos + 4], 0);
set_illuminant_from_code(&s->logging, &s->lab, &data[pos]);
pos += 6;
}
#if 0
if (s->colour_map)
{
span_log(&s->logging, SPAN_LOG_FLOW, "Putting G3FAX3\n");
unpack_16(&data[pos], 0xFFE3);
pos += 2;
unpack_32(&data[pos], ???);
pos += 4;
memcpy(&data[pos], "G3FAX\3", 6);
pos += 6;
unpack_16(&data[pos], table_id);
pos += 2;
unpack_32(&data[pos], s->colour_map_entries);
pos += 4;
srgb_to_lab(&s->lab, &data[pos], s->colour_map, s->colour_map_entries);
pos += 3*s->colour_map_entries;
}
#endif
span_log(&s->logging, SPAN_LOG_FLOW, "Putting G3FAX-FF\n");
unpack_16(&data[pos], 0xFFE1);
pos += 2;
unpack_16(&data[pos], 2 + 6);
pos += 2;
memcpy(&data[pos], "G3FAX\xFF", 6);
pos += 6;
return pos;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(void) t43_encode_set_options(t43_encode_state_t *s,
uint32_t l0,
int mx,
int options)
{
t85_encode_set_options(&s->t85, l0, mx, options);
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t43_encode_set_image_width(t43_encode_state_t *s, uint32_t image_width)
{
return t85_encode_set_image_width(&s->t85, image_width);
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t43_encode_set_image_length(t43_encode_state_t *s, uint32_t image_length)
{
return t85_encode_set_image_length(&s->t85, image_length);
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(void) t43_encode_abort(t43_encode_state_t *s)
{
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(void) t43_encode_comment(t43_encode_state_t *s, const uint8_t comment[], size_t len)
{
t85_encode_comment(&s->t85, comment, len);
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t43_encode_image_complete(t43_encode_state_t *s)
{
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t43_encode_get(t43_encode_state_t *s, uint8_t buf[], size_t max_len)
{
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(uint32_t) t43_encode_get_image_width(t43_encode_state_t *s)
{
return t85_encode_get_image_width(&s->t85);
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(uint32_t) t43_encode_get_image_length(t43_encode_state_t *s)
{
return t85_encode_get_image_length(&s->t85);
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t43_encode_get_compressed_image_size(t43_encode_state_t *s)
{
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t43_encode_set_row_read_handler(t43_encode_state_t *s,
t4_row_read_handler_t handler,
void *user_data)
{
s->row_read_handler = handler;
s->row_read_user_data = user_data;
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(logging_state_t *) t43_encode_get_logging_state(t43_encode_state_t *s)
{
return &s->logging;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t43_encode_restart(t43_encode_state_t *s, uint32_t image_width, uint32_t image_length)
{
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(t43_encode_state_t *) t43_encode_init(t43_encode_state_t *s,
uint32_t image_width,
uint32_t image_length,
t4_row_read_handler_t handler,
void *user_data)
{
if (s == NULL)
{
if ((s = (t43_encode_state_t *) malloc(sizeof(*s))) == NULL)
return NULL;
}
memset(s, 0, sizeof(*s));
span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
span_log_set_protocol(&s->logging, "T.43");
s->row_read_handler = handler;
s->row_read_user_data = user_data;
t85_encode_init(&s->t85,
image_width,
image_length,
handler,
user_data);
return s;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t43_encode_release(t43_encode_state_t *s)
{
t85_encode_release(&s->t85);
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t43_encode_free(t43_encode_state_t *s)
{
int ret;
t85_encode_free(&s->t85);
ret = t43_encode_release(s);
free(s);
return ret;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(void) t43_decode_rx_status(t43_decode_state_t *s, int status)
{
span_log(&s->logging, SPAN_LOG_FLOW, "Signal status is %s (%d)\n", signal_status_to_str(status), status);
switch (status)
{
case SIG_STATUS_TRAINING_IN_PROGRESS:
case SIG_STATUS_TRAINING_FAILED:
case SIG_STATUS_TRAINING_SUCCEEDED:
case SIG_STATUS_CARRIER_UP:
/* Ignore these */
break;
case SIG_STATUS_CARRIER_DOWN:
case SIG_STATUS_END_OF_DATA:
/* Finalise the image */
t85_decode_put(&s->t85, NULL, 0);
break;
default:
span_log(&s->logging, SPAN_LOG_WARNING, "Unexpected rx status - %d!\n", status);
break;
}
}
/*- End of function --------------------------------------------------------*/
static void set_simple_colour_map(t43_decode_state_t *s, int code)
{
switch (code)
{
case 0:
/* Table 3/T.43 1 bit/colour image (using RGB primaries) */
memset(s->colour_map, 0, sizeof(s->colour_map));
/* Black */
/* Blue */
s->colour_map[3*0x20 + 2] = 0xF0;
/* Green */
s->colour_map[3*0x40 + 1] = 0xF0;
/* Green + Blue */
s->colour_map[3*0x60 + 1] = 0xF0;
s->colour_map[3*0x60 + 2] = 0xF0;
/* Red */
s->colour_map[3*0x80 + 0] = 0xF0;
/* Red + Blue */
s->colour_map[3*0xA0 + 0] = 0xF0;
s->colour_map[3*0xA0 + 2] = 0xF0;
/* Red + Green */
s->colour_map[3*0xC0 + 0] = 0xF0;
s->colour_map[3*0xC0 + 1] = 0xF0;
/* White */
s->colour_map[3*0xE0 + 0] = 0xF0;
s->colour_map[3*0xE0 + 1] = 0xF0;
s->colour_map[3*0xE0 + 2] = 0xF0;
s->colour_map_entries = 256;
break;
case 1:
/* Table 2/T.43 1 bit/colour image (using CMY primaries) */
memset(s->colour_map, 0, sizeof(s->colour_map));
/* White */
s->colour_map[3*0x00 + 0] = 0xF0;
s->colour_map[3*0x00 + 1] = 0xF0;
s->colour_map[3*0x00 + 2] = 0xF0;
/* Yellow */
s->colour_map[3*0x20 + 0] = 0xF0;
s->colour_map[3*0x20 + 1] = 0xF0;
/* Magenta */
s->colour_map[3*0x40 + 0] = 0xF0;
s->colour_map[3*0x40 + 2] = 0xF0;
/* Magenta + Yellow */
s->colour_map[3*0x60 + 0] = 0xF0;
/* Cyan */
s->colour_map[3*0x80 + 1] = 0xF0;
/* Cyan + Yellow */
s->colour_map[3*0xA0 + 1] = 0xF0;
/* Cyan + Magenta */
s->colour_map[3*0xC0 + 2] = 0xF0;
/* Black */
s->colour_map_entries = 256;
break;
case 2:
/* Table 1/T.43 1 bit/colour image (using CMYK primaries) */
memset(s->colour_map, 0, sizeof(s->colour_map));
/* White */
s->colour_map[3*0x00 + 0] = 0xF0;
s->colour_map[3*0x00 + 1] = 0xF0;
s->colour_map[3*0x00 + 2] = 0xF0;
/* Yellow */
s->colour_map[3*0x20 + 0] = 0xF0;
s->colour_map[3*0x20 + 1] = 0xF0;
/* Magenta */
s->colour_map[3*0x40 + 0] = 0xF0;
s->colour_map[3*0x40 + 2] = 0xF0;
/* Magenta + Yellow */
s->colour_map[3*0x60 + 0] = 0xF0;
/* Cyan */
s->colour_map[3*0x80 + 1] = 0xF0;
/* Cyan + Yellow */
s->colour_map[3*0xA0 + 1] = 0xF0;
/* Cyan + Magenta */
s->colour_map[3*0xC0 + 2] = 0xF0;
/* Black */
s->colour_map_entries = 256;
break;
case 16:
/* Palettized colour image (using CIELAB 8 bits/component precision table) */
break;
case 17:
/* Palettized colour image (using CIELAB 12 bits/component precision table) */
break;
case 32:
/* Gray-scale image (using L*) */
break;
case 48:
/* Continuous-tone colour image (using CIELAB) */
break;
}
}
/*- End of function --------------------------------------------------------*/
static int t43_analyse_header(t43_decode_state_t *s, const uint8_t data[], size_t len)
{
int seg;
int pos;
int table_id;
int val[6];
uint8_t col[3];
int i;
/* Set defaults */
set_lab_illuminant(&s->lab, 0.9638f, 1.0f, 0.8245f);
set_lab_gamut(&s->lab, 0, 100, -85, 85, -75, 125, FALSE);
pos = 0;
if (pack_16(&data[pos]) != 0xFFA8)
return 0;
span_log(&s->logging, SPAN_LOG_FLOW, "Got BCIH (bit-plane colour image header)\n");
pos += 2;
for (;;)
{
if (pack_16(&data[pos]) == 0xFFE1)
{
pos += 2;
seg = pack_16(&data[pos]);
pos += 2;
seg -= 2;
if (seg >= 6 && strncmp((char *) &data[pos], "G3FAX", 5) == 0)
{
if (data[pos + 5] == 0xFF)
{
span_log(&s->logging, SPAN_LOG_FLOW, "Got ECIH (end of colour image header)\n");
if (seg != 6)
span_log(&s->logging, SPAN_LOG_FLOW, "Got bad ECIH length - %d\n", seg);
pos += seg;
break;
}
switch (data[pos + 5])
{
case 0:
span_log(&s->logging, SPAN_LOG_FLOW, "Got G3FAX0\n");
if (seg >= 6 + 10)
{
val[0] = pack_16(&data[pos + 6 + 0]);
s->x_resolution = pack_16(&data[pos + 6 + 2]);
val[2] = data[pos + 6 + 4];
val[3] = data[pos + 6 + 5];
s->bit_planes[0] = data[pos + 6 + 6];
s->bit_planes[1] = data[pos + 6 + 7];
s->bit_planes[2] = data[pos + 6 + 8];
s->bit_planes[3] = data[pos + 6 + 9];
span_log(&s->logging,
SPAN_LOG_FLOW,
"Version %d, resolution %.2fdpi, coding method %d, type %s (%d), bit planes %d,%d,%d,%d\n",
val[0],
s->x_resolution/100.0f,
val[2],
t43_image_type_to_str(val[3]),
val[3],
s->bit_planes[0],
s->bit_planes[1],
s->bit_planes[2],
s->bit_planes[3]);
set_simple_colour_map(s, val[3]);
}
else
{
span_log(&s->logging, SPAN_LOG_FLOW, "Got bad G3FAX0 length - %d\n", seg);
}
break;
case 1:
span_log(&s->logging, SPAN_LOG_FLOW, "Set gamut\n");
if (seg >= 6 + 12)
set_gamut_from_code(&s->logging, &s->lab, &data[pos + 6]);
else
span_log(&s->logging, SPAN_LOG_FLOW, "Got bad G3FAX1 length - %d\n", seg);
break;
case 2:
span_log(&s->logging, SPAN_LOG_FLOW, "Set illuminant\n");
if (seg >= 6 + 4)
set_illuminant_from_code(&s->logging, &s->lab, &data[pos + 6]);
else
span_log(&s->logging, SPAN_LOG_FLOW, "Got bad G3FAX2 length - %d\n", seg);
break;
default:
span_log(&s->logging, SPAN_LOG_FLOW, "Got unexpected G3FAX%d length - %d\n", data[pos + 5], seg);
break;
}
}
pos += seg;
}
else if (pack_16(&data[pos]) == 0xFFE3)
{
pos += 2;
seg = pack_32(&data[pos]);
pos += 4;
seg -= 4;
if (seg >= 6)
{
if (strncmp((char *) &data[pos], "G3FAX\3", 6) == 0)
{
span_log(&s->logging, SPAN_LOG_FLOW, "Got G3FAX3\n");
table_id = pack_16(&data[pos + 6]);
span_log(&s->logging, SPAN_LOG_FLOW, " Table ID %3d\n", table_id);
switch (table_id)
{
case 0:
/* 8 bit CIELAB */
s->colour_map_entries = pack_32(&data[pos + 8]);
span_log(&s->logging, SPAN_LOG_FLOW, " Entries %6d\n", s->colour_map_entries);
if (seg >= 12 + s->colour_map_entries*3)
{
lab_to_srgb(&s->lab, s->colour_map, &data[pos + 12], s->colour_map_entries);
}
else
{
span_log(&s->logging, SPAN_LOG_FLOW, "Got bad G3FAX3 length - %d\n", seg);
}
break;
case 4:
/* 12 bit CIELAB */
s->colour_map_entries = pack_32(&data[pos + 8]);
span_log(&s->logging, SPAN_LOG_FLOW, " Entries %6d\n", s->colour_map_entries);
/* TODO: implement 12bit stuff */
if (seg >= 12 + s->colour_map_entries*3*2)
{
for (i = 0; i < s->colour_map_entries; i++)
{
col[0] = pack_16(&data[pos + 12 + 6*i]) >> 4;
col[1] = pack_16(&data[pos + 12 + 6*i + 2]) >> 4;
col[2] = pack_16(&data[pos + 12 + 6*i + 4]) >> 4;
lab_to_srgb(&s->lab, &s->colour_map[3*i], col, 1);
}
}
else
{
span_log(&s->logging, SPAN_LOG_FLOW, "Got bad G3FAX3 length - %d\n", seg);
}
break;
default:
span_log(&s->logging, SPAN_LOG_FLOW, "Got bad G3FAX3 table ID - %d\n", table_id);
break;
}
}
}
pos += seg;
}
else
{
break;
}
}
return pos;
}
/*- End of function --------------------------------------------------------*/
static int t85_row_write_handler(void *user_data, const uint8_t buf[], size_t len)
{
t43_decode_state_t *s;
int i;
int j;
int image_size;
uint8_t mask;
/* Repack the bit packed T.85 image plane to a 3 x 8 bits per pixel colour image.
We use the red entry now. This will be remapped to RGB later, as we apply the
colour map. */
s = (t43_decode_state_t *) user_data;
if (s->buf == NULL)
{
image_size = 3*s->t85.xd*s->t85.yd;
if ((s->buf = malloc(image_size)) == NULL)
return -1;
memset(s->buf, 0, image_size);
}
for (i = 0; i < len; i++)
{
mask = 0x80;
for (j = 0; j < 24; j += 3)
{
if ((buf[i] & mask))
s->buf[s->ptr + j] |= s->bit_plane_mask;
mask >>= 1;
}
s->ptr += 3*8;
}
s->row++;
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t43_decode_put(t43_decode_state_t *s, const uint8_t data[], size_t len)
{
int i;
int j;
int plane_len;
int total_len;
int result;
/* TODO: this isn't allowing for the header arriving in chunks */
if (s->current_bit_plane < 0)
{
i = t43_analyse_header(s, data, len);
data += i;
len -= i;
s->bit_plane_mask = 0x80;
s->current_bit_plane++;
/* There must be at least one bit plane. The real value for this will
be filled in as the first plane is processed */
s->t85.bit_planes = 1;
s->ptr = 0;
s->row = 0;
s->buf = NULL;
s->plane_ptr = 0;
t85_decode_new_plane(&s->t85);
}
/* Now deal the bit-planes, one after another. */
while (s->current_bit_plane < s->t85.bit_planes)
{
j = s->current_bit_plane;
result = t85_decode_put(&s->t85, data, len);
if (result != T4_DECODE_OK)
{
s->plane_ptr += len;
return result;
}
plane_len = t85_decode_get_compressed_image_size(&s->t85);
data += (plane_len/8 - s->plane_ptr);
len -= (plane_len/8 - s->plane_ptr);
total_len = s->ptr;
/* Start the next plane */
s->bit_plane_mask >>= 1;
s->current_bit_plane++;
s->ptr = 0;
s->row = 0;
s->plane_ptr = 0;
t85_decode_new_plane(&s->t85);
}
/* Apply the colour map, and produce the RGB data from the collected bit-planes */
for (j = 0; j < total_len; j += 3)
{
i = s->buf[j];
s->buf[j] = s->colour_map[3*i];
s->buf[j + 1] = s->colour_map[3*i + 1];
s->buf[j + 2] = s->colour_map[3*i + 2];
}
for (j = 0; j < s->t85.yd; j++)
{
s->row_write_handler(s->row_write_user_data, &s->buf[j*3*s->t85.xd], 3*s->t85.xd);
}
return result;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t43_decode_set_row_write_handler(t43_decode_state_t *s,
t4_row_write_handler_t handler,
void *user_data)
{
s->row_write_handler = handler;
s->row_write_user_data = user_data;
s->t85.row_write_handler = handler;
s->t85.row_write_user_data = user_data;
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t43_decode_set_comment_handler(t43_decode_state_t *s,
uint32_t max_comment_len,
t4_row_write_handler_t handler,
void *user_data)
{
return t85_decode_set_comment_handler(&s->t85, max_comment_len, handler, user_data);
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t43_decode_set_image_size_constraints(t43_decode_state_t *s,
uint32_t max_xd,
uint32_t max_yd)
{
return t85_decode_set_image_size_constraints(&s->t85, max_xd, max_yd);
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(uint32_t) t43_decode_get_image_width(t43_decode_state_t *s)
{
return t85_decode_get_image_width(&s->t85);
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(uint32_t) t43_decode_get_image_length(t43_decode_state_t *s)
{
return t85_decode_get_image_length(&s->t85);
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t43_decode_get_compressed_image_size(t43_decode_state_t *s)
{
return t85_decode_get_compressed_image_size(&s->t85);
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(logging_state_t *) t43_decode_get_logging_state(t43_decode_state_t *s)
{
return &s->logging;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t43_decode_restart(t43_decode_state_t *s)
{
return t85_decode_restart(&s->t85);
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(t43_decode_state_t *) t43_decode_init(t43_decode_state_t *s,
t4_row_write_handler_t handler,
void *user_data)
{
if (s == NULL)
{
if ((s = (t43_decode_state_t *) malloc(sizeof(*s))) == NULL)
return NULL;
}
memset(s, 0, sizeof(*s));
span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
span_log_set_protocol(&s->logging, "T.43");
s->row_write_handler = handler;
s->row_write_user_data = user_data;
t85_decode_init(&s->t85, t85_row_write_handler, s);
s->t85.min_bit_planes = 1;
s->t85.max_bit_planes = 8;
s->bit_plane_mask = 0x80;
s->current_bit_plane = -1;
return s;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t43_decode_release(t43_decode_state_t *s)
{
t85_decode_release(&s->t85);
return 0;
}
/*- End of function --------------------------------------------------------*/
SPAN_DECLARE(int) t43_decode_free(t43_decode_state_t *s)
{
int ret;
ret = t43_decode_release(s);
t85_decode_free(&s->t85);
free(s);
return ret;
}
/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/

View File

@ -107,6 +107,8 @@ SPAN_DECLARE(const char *) t4_encoding_to_str(int encoding)
return "T.85"; return "T.85";
case T4_COMPRESSION_T85_L0: case T4_COMPRESSION_T85_L0:
return "T.85(L0)"; return "T.85(L0)";
case T4_COMPRESSION_T88:
return "T.88";
case T4_COMPRESSION_T42_T81: case T4_COMPRESSION_T42_T81:
return "T.81"; return "T.81";
case T4_COMPRESSION_SYCC_T81: case T4_COMPRESSION_SYCC_T81:

View File

@ -104,12 +104,12 @@ static void t4_tx_set_image_length(t4_tx_state_t *s, int image_length);
static const res_table_t x_res_table[] = static const res_table_t x_res_table[] =
{ {
//{ 100.0f/CM_PER_INCH, T4_X_RESOLUTION_100}, { 100.0f/CM_PER_INCH, T4_X_RESOLUTION_100},
{ 102.0f/CM_PER_INCH, T4_X_RESOLUTION_R4}, { 102.0f/CM_PER_INCH, T4_X_RESOLUTION_R4},
//{ 200.0f/CM_PER_INCH, T4_X_RESOLUTION_200}, { 200.0f/CM_PER_INCH, T4_X_RESOLUTION_200},
{ 204.0f/CM_PER_INCH, T4_X_RESOLUTION_R8}, { 204.0f/CM_PER_INCH, T4_X_RESOLUTION_R8},
{ 300.0f/CM_PER_INCH, T4_X_RESOLUTION_300}, { 300.0f/CM_PER_INCH, T4_X_RESOLUTION_300},
//{ 400.0f/CM_PER_INCH, T4_X_RESOLUTION_400}, { 400.0f/CM_PER_INCH, T4_X_RESOLUTION_400},
{ 408.0f/CM_PER_INCH, T4_X_RESOLUTION_R16}, { 408.0f/CM_PER_INCH, T4_X_RESOLUTION_R16},
{ 600.0f/CM_PER_INCH, T4_X_RESOLUTION_600}, { 600.0f/CM_PER_INCH, T4_X_RESOLUTION_600},
{ 800.0f/CM_PER_INCH, T4_X_RESOLUTION_800}, { 800.0f/CM_PER_INCH, T4_X_RESOLUTION_800},
@ -120,12 +120,12 @@ static const res_table_t x_res_table[] =
static const res_table_t y_res_table[] = static const res_table_t y_res_table[] =
{ {
{ 38.50f, T4_Y_RESOLUTION_STANDARD}, { 38.50f, T4_Y_RESOLUTION_STANDARD},
//{ 100.0f/CM_PER_INCH, T4_Y_RESOLUTION_100}, { 100.0f/CM_PER_INCH, T4_Y_RESOLUTION_100},
{ 77.00f, T4_Y_RESOLUTION_FINE}, { 77.00f, T4_Y_RESOLUTION_FINE},
//{ 200.0f/CM_PER_INCH, T4_Y_RESOLUTION_200}, { 200.0f/CM_PER_INCH, T4_Y_RESOLUTION_200},
{ 300.0f/CM_PER_INCH, T4_Y_RESOLUTION_300}, { 300.0f/CM_PER_INCH, T4_Y_RESOLUTION_300},
{ 154.00f, T4_Y_RESOLUTION_SUPERFINE}, { 154.00f, T4_Y_RESOLUTION_SUPERFINE},
//{ 400.0f/CM_PER_INCH, T4_Y_RESOLUTION_400}, { 400.0f/CM_PER_INCH, T4_Y_RESOLUTION_400},
{ 600.0f/CM_PER_INCH, T4_Y_RESOLUTION_600}, { 600.0f/CM_PER_INCH, T4_Y_RESOLUTION_600},
{ 800.0f/CM_PER_INCH, T4_Y_RESOLUTION_800}, { 800.0f/CM_PER_INCH, T4_Y_RESOLUTION_800},
{1200.0f/CM_PER_INCH, T4_Y_RESOLUTION_1200}, {1200.0f/CM_PER_INCH, T4_Y_RESOLUTION_1200},
@ -385,7 +385,7 @@ static int get_tiff_directory_info(t4_tx_state_t *s)
best_y_entry = 0; best_y_entry = 0;
s->metadata.y_resolution = y_res_table[best_y_entry].code; s->metadata.y_resolution = y_res_table[best_y_entry].code;
//s->metadata.resolution_code = resolution_map[best_y_entry][best_x_entry]; s->metadata.resolution_code = resolution_map[best_y_entry][best_x_entry];
t4_tx_set_image_width(s, s->image_width); t4_tx_set_image_width(s, s->image_width);
t4_tx_set_image_length(s, s->image_length); t4_tx_set_image_length(s, s->image_length);

View File

@ -73,10 +73,21 @@
#define FP_SCALE(x) (x) #define FP_SCALE(x) (x)
#endif #endif
#include "v17_v32bis_rx_rrc.h" #if defined(SPANDSP_USE_FIXED_POINTx)
#define FP_SYNC_SCALE(x) FP_Q_6_10(x)
#define FP_SYNC_SCALE_32(x) FP_Q_6_10_32(x)
#define FP_SYNC_SHIFT_FACTOR 10
#else
#define FP_SYNC_SCALE(x) (x)
#define FP_SYNC_SCALE_32(x) (x)
#endif
#define FP_CONSTELLATION_SCALE(x) FP_SCALE(x) #define FP_CONSTELLATION_SCALE(x) FP_SCALE(x)
#if defined(SPANDSP_USE_FIXED_POINT)
#define FP_CONSTELLATION_SHIFT_FACTOR FP_SHIFT_FACTOR
#endif
#include "v17_v32bis_rx_rrc.h"
#include "v17_v32bis_tx_constellation_maps.h" #include "v17_v32bis_tx_constellation_maps.h"
#include "v17_v32bis_rx_constellation_maps.h" #include "v17_v32bis_rx_constellation_maps.h"
@ -106,6 +117,23 @@
/*! The 16 bit pattern used in the bridge section of the training sequence */ /*! The 16 bit pattern used in the bridge section of the training sequence */
#define V17_BRIDGE_WORD 0x8880 #define V17_BRIDGE_WORD 0x8880
/* Coefficients for the band edge symbol timing synchroniser (alpha = 0.99) */
/* low_edge = 2.0f*M_PI*(CARRIER_NOMINAL_FREQ - BAUD_RATE/2.0f)/SAMPLE_RATE; */
/* high_edge = 2.0f*M_PI*(CARRIER_NOMINAL_FREQ + BAUD_RATE/2.0f)/SAMPLE_RATE; */
#define SIN_LOW_BAND_EDGE 0.453990499f
#define COS_LOW_BAND_EDGE 0.891006542f
#define SIN_HIGH_BAND_EDGE 0.707106781f
#define COS_HIGH_BAND_EDGE -0.707106781f
#define ALPHA 0.99f
#define SYNC_LOW_BAND_EDGE_COEFF_0 FP_SYNC_SCALE(2.0f*ALPHA*COS_LOW_BAND_EDGE)
#define SYNC_LOW_BAND_EDGE_COEFF_1 FP_SYNC_SCALE(-ALPHA*ALPHA)
#define SYNC_LOW_BAND_EDGE_COEFF_2 FP_SYNC_SCALE(-ALPHA*SIN_LOW_BAND_EDGE)
#define SYNC_HIGH_BAND_EDGE_COEFF_0 FP_SYNC_SCALE(2.0f*ALPHA*COS_HIGH_BAND_EDGE)
#define SYNC_HIGH_BAND_EDGE_COEFF_1 FP_SYNC_SCALE(-ALPHA*ALPHA)
#define SYNC_HIGH_BAND_EDGE_COEFF_2 FP_SYNC_SCALE(-ALPHA*SIN_HIGH_BAND_EDGE)
#define SYNC_MIXED_EDGES_COEFF_3 FP_SYNC_SCALE(-ALPHA*ALPHA*(SIN_HIGH_BAND_EDGE*COS_LOW_BAND_EDGE - SIN_LOW_BAND_EDGE*COS_HIGH_BAND_EDGE))
enum enum
{ {
TRAINING_STAGE_NORMAL_OPERATION = 0, TRAINING_STAGE_NORMAL_OPERATION = 0,
@ -123,33 +151,6 @@ enum
TRAINING_STAGE_PARKED TRAINING_STAGE_PARKED
}; };
/* Coefficients for the band edge symbol timing synchroniser (alpha = 0.99) */
/* low_edge = 2.0f*M_PI*(CARRIER_NOMINAL_FREQ - BAUD_RATE/2.0f)/SAMPLE_RATE; */
/* high_edge = 2.0f*M_PI*(CARRIER_NOMINAL_FREQ + BAUD_RATE/2.0f)/SAMPLE_RATE; */
#define SIN_LOW_BAND_EDGE 0.453990499f
#define COS_LOW_BAND_EDGE 0.891006542f
#define SIN_HIGH_BAND_EDGE 0.707106781f
#define COS_HIGH_BAND_EDGE -0.707106781f
#define ALPHA 0.99f
#if defined(SPANDSP_USE_FIXED_POINTx)
#define SYNC_LOW_BAND_EDGE_COEFF_0 FP_Q_6_10(2.0f*ALPHA*COS_LOW_BAND_EDGE)
#define SYNC_LOW_BAND_EDGE_COEFF_1 FP_Q_6_10(-ALPHA*ALPHA)
#define SYNC_LOW_BAND_EDGE_COEFF_2 FP_Q_6_10(-ALPHA*SIN_LOW_BAND_EDGE)
#define SYNC_HIGH_BAND_EDGE_COEFF_0 FP_Q_6_10(2.0f*ALPHA*COS_HIGH_BAND_EDGE)
#define SYNC_HIGH_BAND_EDGE_COEFF_1 FP_Q_6_10(-ALPHA*ALPHA)
#define SYNC_HIGH_BAND_EDGE_COEFF_2 FP_Q_6_10(-ALPHA*SIN_HIGH_BAND_EDGE)
#define SYNC_MIXED_EDGES_COEFF_3 FP_Q_6_10(-ALPHA*ALPHA*(SIN_HIGH_BAND_EDGE*COS_LOW_BAND_EDGE - SIN_LOW_BAND_EDGE*COS_HIGH_BAND_EDGE))
#else
#define SYNC_LOW_BAND_EDGE_COEFF_0 (2.0f*ALPHA*COS_LOW_BAND_EDGE)
#define SYNC_LOW_BAND_EDGE_COEFF_1 (-ALPHA*ALPHA)
#define SYNC_LOW_BAND_EDGE_COEFF_2 (-ALPHA*SIN_LOW_BAND_EDGE)
#define SYNC_HIGH_BAND_EDGE_COEFF_0 (2.0f*ALPHA*COS_HIGH_BAND_EDGE)
#define SYNC_HIGH_BAND_EDGE_COEFF_1 (-ALPHA*ALPHA)
#define SYNC_HIGH_BAND_EDGE_COEFF_2 (-ALPHA*SIN_HIGH_BAND_EDGE)
#define SYNC_MIXED_EDGES_COEFF_3 (-ALPHA*ALPHA*(SIN_HIGH_BAND_EDGE*COS_LOW_BAND_EDGE - SIN_LOW_BAND_EDGE*COS_HIGH_BAND_EDGE))
#endif
#if defined(SPANDSP_USE_FIXED_POINTx) #if defined(SPANDSP_USE_FIXED_POINTx)
static const int16_t constellation_spacing[4] = static const int16_t constellation_spacing[4] =
#else #else
@ -245,14 +246,14 @@ static void equalizer_reset(v17_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) #if defined(SPANDSP_USE_FIXED_POINTx)
static const complexi16_t x = {FP_SCALE(3.0f), FP_SCALE(0.0f)}; static const complexi16_t x = {FP_CONSTELLATION_SCALE(3.0f), FP_CONSTELLATION_SCALE(0.0f)};
cvec_zeroi16(s->eq_coeff, V17_EQUALIZER_LEN); cvec_zeroi16(s->eq_coeff, V17_EQUALIZER_LEN);
s->eq_coeff[V17_EQUALIZER_PRE_LEN] = x; s->eq_coeff[V17_EQUALIZER_PRE_LEN] = x;
cvec_zeroi16(s->eq_buf, V17_EQUALIZER_LEN); cvec_zeroi16(s->eq_buf, V17_EQUALIZER_LEN);
s->eq_delta = 32768.0f*EQUALIZER_DELTA/V17_EQUALIZER_LEN; s->eq_delta = 32768.0f*EQUALIZER_DELTA/V17_EQUALIZER_LEN;
#else #else
static const complexf_t x = {3.0f, 0.0f}; static const complexf_t x = {FP_CONSTELLATION_SCALE(3.0f), FP_CONSTELLATION_SCALE(0.0f)};
cvec_zerof(s->eq_coeff, V17_EQUALIZER_LEN); cvec_zerof(s->eq_coeff, V17_EQUALIZER_LEN);
s->eq_coeff[V17_EQUALIZER_PRE_LEN] = x; s->eq_coeff[V17_EQUALIZER_PRE_LEN] = x;
@ -313,20 +314,6 @@ static void tune_equalizer(v17_rx_state_t *s, const complexf_t *z, const complex
#endif #endif
/*- End of function --------------------------------------------------------*/ /*- End of function --------------------------------------------------------*/
static int descramble(v17_rx_state_t *s, int in_bit)
{
int out_bit;
out_bit = (in_bit ^ (s->scramble_reg >> s->scrambler_tap) ^ (s->scramble_reg >> (23 - 1))) & 1;
s->scramble_reg <<= 1;
if (s->training_stage > TRAINING_STAGE_NORMAL_OPERATION && s->training_stage < TRAINING_STAGE_TCM_WINDUP)
s->scramble_reg |= out_bit;
else
s->scramble_reg |= (in_bit & 1);
return out_bit;
}
/*- End of function --------------------------------------------------------*/
#if defined(SPANDSP_USE_FIXED_POINTx) #if defined(SPANDSP_USE_FIXED_POINTx)
static __inline__ void track_carrier(v17_rx_state_t *s, const complexi16_t *z, const complexi16_t *target) static __inline__ void track_carrier(v17_rx_state_t *s, const complexi16_t *z, const complexi16_t *target)
#else #else
@ -355,6 +342,21 @@ static __inline__ void track_carrier(v17_rx_state_t *s, const complexf_t *z, con
} }
/*- End of function --------------------------------------------------------*/ /*- End of function --------------------------------------------------------*/
static int descramble(v17_rx_state_t *s, int in_bit)
{
int out_bit;
in_bit &= 1;
out_bit = (in_bit ^ (s->scramble_reg >> s->scrambler_tap) ^ (s->scramble_reg >> (23 - 1))) & 1;
s->scramble_reg <<= 1;
if (s->training_stage > TRAINING_STAGE_NORMAL_OPERATION && s->training_stage < TRAINING_STAGE_TCM_WINDUP)
s->scramble_reg |= out_bit;
else
s->scramble_reg |= (in_bit & 1);
return out_bit;
}
/*- End of function --------------------------------------------------------*/
static __inline__ void put_bit(v17_rx_state_t *s, int bit) static __inline__ void put_bit(v17_rx_state_t *s, int bit)
{ {
int out_bit; int out_bit;
@ -675,13 +677,13 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
complexi16_t z; complexi16_t z;
complexi16_t z16; complexi16_t z16;
const complexi16_t *target; const complexi16_t *target;
static const complexi16_t zero = {0, 0}; static const complexi16_t zero = {FP_SCALE(0.0f), FP_SCALE(0.0f)};
#else #else
float p; float p;
complexf_t z; complexf_t z;
complexf_t zz; complexf_t zz;
const complexf_t *target; const complexf_t *target;
static const complexf_t zero = {0.0f, 0.0f}; static const complexf_t zero = {FP_SCALE(0.0f), FP_SCALE(0.0f)};
#endif #endif
int bit; int bit;
int i; int i;
@ -724,13 +726,8 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
s->training_stage = TRAINING_STAGE_LOG_PHASE; s->training_stage = TRAINING_STAGE_LOG_PHASE;
vec_zeroi32(s->diff_angles, 16); vec_zeroi32(s->diff_angles, 16);
s->last_angles[0] = arctan2(z.im, z.re); s->last_angles[0] = arctan2(z.im, z.re);
#if defined(SPANDSP_USE_FIXED_POINTx) if (s->agc_scaling_save == FP_SCALE(0.0f))
if (s->agc_scaling_save == 0)
s->agc_scaling_save = s->agc_scaling; s->agc_scaling_save = s->agc_scaling;
#else
if (s->agc_scaling_save == 0.0f)
s->agc_scaling_save = s->agc_scaling;
#endif
} }
break; break;
case TRAINING_STAGE_LOG_PHASE: case TRAINING_STAGE_LOG_PHASE:
@ -816,11 +813,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
{ {
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n"); span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n");
/* Park this modem */ /* Park this modem */
#if defined(SPANDSP_USE_FIXED_POINTx) s->agc_scaling_save = FP_SCALE(0.0f);
s->agc_scaling_save = 0;
#else
s->agc_scaling_save = 0.0f;
#endif
s->training_stage = TRAINING_STAGE_PARKED; s->training_stage = TRAINING_STAGE_PARKED;
report_status_change(s, SIG_STATUS_TRAINING_FAILED); report_status_change(s, SIG_STATUS_TRAINING_FAILED);
break; break;
@ -860,11 +853,7 @@ 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. */ of a real training sequence. Note that this might be TEP. */
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n"); span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n");
/* Park this modem */ /* Park this modem */
#if defined(SPANDSP_USE_FIXED_POINTx) s->agc_scaling_save = FP_SCALE(0.0f);
s->agc_scaling_save = 0;
#else
s->agc_scaling_save = 0.0f;
#endif
s->training_stage = TRAINING_STAGE_PARKED; s->training_stage = TRAINING_STAGE_PARKED;
report_status_change(s, SIG_STATUS_TRAINING_FAILED); report_status_change(s, SIG_STATUS_TRAINING_FAILED);
} }
@ -880,12 +869,11 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
#if defined(SPANDSP_USE_FIXED_POINTx) #if defined(SPANDSP_USE_FIXED_POINTx)
z16 = complex_subi16(&z, target); z16 = complex_subi16(&z, target);
s->training_error += poweri16(&z16); s->training_error += poweri16(&z16);
if (++s->training_count == V17_TRAINING_SEG_2_LEN - 2000 || s->training_error < 1*FP_FACTOR*FP_FACTOR || s->training_error > 200*FP_FACTOR*FP_FACTOR)
#else #else
zz = complex_subf(&z, target); zz = complex_subf(&z, target);
s->training_error = powerf(&zz); s->training_error = powerf(&zz);
if (++s->training_count == V17_TRAINING_SEG_2_LEN - 2000 || s->training_error < 1.0f || s->training_error > 200.0f)
#endif #endif
if (++s->training_count == V17_TRAINING_SEG_2_LEN - 2000 || s->training_error < FP_SCALE(1.0f)*FP_SCALE(1.0f) || s->training_error > FP_SCALE(200.0f)*FP_SCALE(1.0f))
#else #else
if (++s->training_count == V17_TRAINING_SEG_2_LEN - 2000) if (++s->training_count == V17_TRAINING_SEG_2_LEN - 2000)
#endif #endif
@ -948,15 +936,12 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
{ {
#if defined(SPANDSP_USE_FIXED_POINTx) #if defined(SPANDSP_USE_FIXED_POINTx)
span_log(&s->logging, SPAN_LOG_FLOW, "Long training error %d\n", s->training_error); span_log(&s->logging, SPAN_LOG_FLOW, "Long training error %d\n", s->training_error);
if (s->training_error < 20.0f*1.414f*FP_FACTOR*FP_FACTOR*constellation_spacing[s->space_map])
{
s->training_error = 0;
#else #else
span_log(&s->logging, SPAN_LOG_FLOW, "Long training error %f\n", s->training_error); span_log(&s->logging, SPAN_LOG_FLOW, "Long training error %f\n", s->training_error);
if (s->training_error < 20.0f*1.414f*constellation_spacing[s->space_map])
{
s->training_error = 0.0f;
#endif #endif
if (s->training_error < FP_SCALE(20.0f)*FP_SCALE(1.414f)*constellation_spacing[s->space_map])
{
s->training_error = FP_SCALE(0.0f);
s->training_count = 0; s->training_count = 0;
s->training_stage = TRAINING_STAGE_BRIDGE; s->training_stage = TRAINING_STAGE_BRIDGE;
} }
@ -964,11 +949,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
{ {
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (convergence failed)\n"); span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (convergence failed)\n");
/* Park this modem */ /* Park this modem */
#if defined(SPANDSP_USE_FIXED_POINTx) s->agc_scaling_save = FP_SCALE(0.0f);
s->agc_scaling_save = 0;
#else
s->agc_scaling_save = 0.0f;
#endif
s->training_stage = TRAINING_STAGE_PARKED; s->training_stage = TRAINING_STAGE_PARKED;
report_status_change(s, SIG_STATUS_TRAINING_FAILED); report_status_change(s, SIG_STATUS_TRAINING_FAILED);
} }
@ -980,11 +961,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
target = &z; target = &z;
if (++s->training_count >= V17_TRAINING_SEG_3_LEN) if (++s->training_count >= V17_TRAINING_SEG_3_LEN)
{ {
#if defined(SPANDSP_USE_FIXED_POINTx) s->training_error = FP_SCALE(0.0f);
s->training_error = 0;
#else
s->training_error = 0.0f;
#endif
s->training_count = 0; s->training_count = 0;
if (s->bits_per_symbol == 2) if (s->bits_per_symbol == 2)
{ {
@ -1012,11 +989,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
bit = descramble(s, 1); bit = descramble(s, 1);
bit = (bit << 1) | descramble(s, 1); bit = (bit << 1) | descramble(s, 1);
target = &cdba[bit]; target = &cdba[bit];
#if defined(SPANDSP_USE_FIXED_POINTx) s->training_error = FP_SCALE(0.0f);
s->training_error = 0;
#else
s->training_error = 0.0f;
#endif
s->training_count = 1; s->training_count = 1;
s->training_stage = TRAINING_STAGE_SHORT_TRAIN_ON_CDBA_AND_TEST; s->training_stage = TRAINING_STAGE_SHORT_TRAIN_ON_CDBA_AND_TEST;
break; break;
@ -1066,11 +1039,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
/* TODO: This was increased by a factor of 10 after studying real world failures. /* TODO: This was increased by a factor of 10 after studying real world failures.
However, it is not clear why this is an improvement, If something gives However, it is not clear why this is an improvement, If something gives
a huge training error, surely it shouldn't decode too well? */ a huge training error, surely it shouldn't decode too well? */
#if defined(SPANDSP_USE_FIXED_POINTx) if (s->training_error < (V17_TRAINING_SHORT_SEG_2_LEN - 8)*FP_SCALE(4.0f)*FP_SCALE(1.0f)*constellation_spacing[s->space_map])
if (s->training_error < (V17_TRAINING_SHORT_SEG_2_LEN - 8)*4.0f*FP_FACTOR*FP_FACTOR*constellation_spacing[s->space_map])
#else
if (s->training_error < (V17_TRAINING_SHORT_SEG_2_LEN - 8)*4.0f*constellation_spacing[s->space_map])
#endif
{ {
s->training_count = 0; s->training_count = 0;
if (s->bits_per_symbol == 2) if (s->bits_per_symbol == 2)
@ -1078,11 +1047,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
/* There is no trellis, so go straight to processing decoded data */ /* There is no trellis, so go straight to processing decoded data */
/* Restart the differential decoder */ /* Restart the differential decoder */
s->diff = (s->short_train) ? 0 : 1; s->diff = (s->short_train) ? 0 : 1;
#if defined(SPANDSP_USE_FIXED_POINTx) s->training_error = FP_SCALE(0.0f);
s->training_error = 0;
#else
s->training_error = 0.0f;
#endif
s->training_stage = TRAINING_STAGE_TEST_ONES; s->training_stage = TRAINING_STAGE_TEST_ONES;
} }
else else
@ -1116,11 +1081,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
#endif #endif
if (++s->training_count >= V17_TRAINING_SEG_4A_LEN) if (++s->training_count >= V17_TRAINING_SEG_4A_LEN)
{ {
#if defined(SPANDSP_USE_FIXED_POINTx) s->training_error = FP_SCALE(0.0f);
s->training_error = 0;
#else
s->training_error = 0.0f;
#endif
s->training_count = 0; s->training_count = 0;
/* Restart the differential decoder */ /* Restart the differential decoder */
s->diff = (s->short_train) ? 0 : 1; s->diff = (s->short_train) ? 0 : 1;
@ -1143,13 +1104,11 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
#endif #endif
if (++s->training_count >= V17_TRAINING_SEG_4_LEN) if (++s->training_count >= V17_TRAINING_SEG_4_LEN)
{ {
#if defined(SPANDSP_USE_FIXED_POINTx) if (s->training_error < V17_TRAINING_SEG_4_LEN*FP_SCALE(1.0f)*FP_SCALE(1.0f)*constellation_spacing[s->space_map])
if (s->training_error < V17_TRAINING_SEG_4_LEN*FP_FACTOR*FP_FACTOR*constellation_spacing[s->space_map])
{ {
#if defined(SPANDSP_USE_FIXED_POINTx)
span_log(&s->logging, SPAN_LOG_FLOW, "Training succeeded at %dbps (constellation mismatch %d)\n", s->bit_rate, s->training_error); span_log(&s->logging, SPAN_LOG_FLOW, "Training succeeded at %dbps (constellation mismatch %d)\n", s->bit_rate, s->training_error);
#else #else
if (s->training_error < V17_TRAINING_SEG_4_LEN*constellation_spacing[s->space_map])
{
span_log(&s->logging, SPAN_LOG_FLOW, "Training succeeded at %dbps (constellation mismatch %f)\n", s->bit_rate, s->training_error); span_log(&s->logging, SPAN_LOG_FLOW, "Training succeeded at %dbps (constellation mismatch %f)\n", s->bit_rate, s->training_error);
#endif #endif
/* We are up and running */ /* We are up and running */
@ -1167,13 +1126,11 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
/* Training has failed. Park this modem. */ /* Training has failed. Park this modem. */
#if defined(SPANDSP_USE_FIXED_POINTx) #if defined(SPANDSP_USE_FIXED_POINTx)
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (constellation mismatch %d)\n", s->training_error); span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (constellation mismatch %d)\n", s->training_error);
if (!s->short_train)
s->agc_scaling_save = 0;
#else #else
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (constellation mismatch %f)\n", s->training_error); span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (constellation mismatch %f)\n", s->training_error);
if (!s->short_train)
s->agc_scaling_save = 0.0f;
#endif #endif
if (!s->short_train)
s->agc_scaling_save = FP_SCALE(0.0f);
s->training_stage = TRAINING_STAGE_PARKED; s->training_stage = TRAINING_STAGE_PARKED;
report_status_change(s, SIG_STATUS_TRAINING_FAILED); report_status_change(s, SIG_STATUS_TRAINING_FAILED);
} }
@ -1317,11 +1274,15 @@ SPAN_DECLARE_NONSTD(int) v17_rx(v17_rx_state_t *s, const int16_t amp[], int len)
sample.re = (v*s->agc_scaling) >> 10; sample.re = (v*s->agc_scaling) >> 10;
/* Symbol timing synchronisation band edge filters */ /* Symbol timing synchronisation band edge filters */
/* Low Nyquist band edge filter */ /* Low Nyquist band edge filter */
v = ((s->symbol_sync_low[0]*SYNC_LOW_BAND_EDGE_COEFF_0) >> 10) + ((s->symbol_sync_low[1]*SYNC_LOW_BAND_EDGE_COEFF_1) >> 10) + sample.re; v = ((s->symbol_sync_low[0]*SYNC_LOW_BAND_EDGE_COEFF_0) >> 10)
+ ((s->symbol_sync_low[1]*SYNC_LOW_BAND_EDGE_COEFF_1) >> 10)
+ sample.re;
s->symbol_sync_low[1] = s->symbol_sync_low[0]; s->symbol_sync_low[1] = s->symbol_sync_low[0];
s->symbol_sync_low[0] = v; s->symbol_sync_low[0] = v;
/* High Nyquist band edge filter */ /* High Nyquist band edge filter */
v = ((s->symbol_sync_high[0]*SYNC_HIGH_BAND_EDGE_COEFF_0) >> 10) + ((s->symbol_sync_high[1]*SYNC_HIGH_BAND_EDGE_COEFF_1) >> 10) + sample.re; v = ((s->symbol_sync_high[0]*SYNC_HIGH_BAND_EDGE_COEFF_0) >> 10)
+ ((s->symbol_sync_high[1]*SYNC_HIGH_BAND_EDGE_COEFF_1) >> 10)
+ sample.re;
s->symbol_sync_high[1] = s->symbol_sync_high[0]; s->symbol_sync_high[1] = s->symbol_sync_high[0];
s->symbol_sync_high[0] = v; s->symbol_sync_high[0] = v;
#else #else
@ -1342,18 +1303,16 @@ SPAN_DECLARE_NONSTD(int) v17_rx(v17_rx_state_t *s, const int16_t amp[], int len)
if (s->eq_put_step <= 0) if (s->eq_put_step <= 0)
{ {
/* Only AGC until we have locked down the setting. */ /* Only AGC until we have locked down the setting. */
if (s->agc_scaling_save == FP_SCALE(0.0f))
#if defined(SPANDSP_USE_FIXED_POINTx) #if defined(SPANDSP_USE_FIXED_POINTx)
if (s->agc_scaling_save == 0) s->agc_scaling = saturate16(((int32_t) (FP_SCALE(2.17f)*1024.0f))/fixed_sqrt32(power));
s->agc_scaling = saturate16(((int32_t) (1024.0f*FP_FACTOR*2.17f))/fixed_sqrt32(power));
#else #else
if (s->agc_scaling_save == 0.0f) s->agc_scaling = (FP_SCALE(2.17f)/RX_PULSESHAPER_GAIN)/sqrtf(power);
s->agc_scaling = (1.0f/RX_PULSESHAPER_GAIN)*2.17f/sqrtf(power);
#endif #endif
/* Pulse shape while still at the carrier frequency, using a quadrature /* Pulse shape while still at the carrier frequency, using a quadrature
pair of filters. This results in a properly bandpass filtered complex pair of filters. This results in a properly bandpass filtered complex
signal, which can be brought directly to baseband by complex mixing. signal, which can be brought directly to baseband by complex mixing.
No further filtering, to remove mixer harmonics, is needed. */ No further filtering, to remove mixer harmonics, is needed. */
s->eq_put_step += RX_PULSESHAPER_COEFF_SETS*10/(3*2);
#if defined(SPANDSP_USE_FIXED_POINTx) #if defined(SPANDSP_USE_FIXED_POINTx)
v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_im[step], V17_RX_FILTER_STEPS, s->rrc_filter_step) >> 15; v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_im[step], V17_RX_FILTER_STEPS, s->rrc_filter_step) >> 15;
sample.im = (v*s->agc_scaling) >> 10; sample.im = (v*s->agc_scaling) >> 10;
@ -1367,6 +1326,7 @@ SPAN_DECLARE_NONSTD(int) v17_rx(v17_rx_state_t *s, const int16_t amp[], int len)
zz.re = sample.re*z.re - sample.im*z.im; zz.re = sample.re*z.re - sample.im*z.im;
zz.im = -sample.re*z.im - sample.im*z.re; zz.im = -sample.re*z.im - sample.im*z.re;
#endif #endif
s->eq_put_step += RX_PULSESHAPER_COEFF_SETS*10/(3*2);
process_half_baud(s, &zz); process_half_baud(s, &zz);
} }
#if defined(SPANDSP_USE_FIXED_POINT) #if defined(SPANDSP_USE_FIXED_POINT)
@ -1467,11 +1427,10 @@ SPAN_DECLARE(int) v17_rx_restart(v17_rx_state_t *s, int bit_rate, int short_trai
s->bit_rate = bit_rate; s->bit_rate = bit_rate;
#if defined(SPANDSP_USE_FIXED_POINTx) #if defined(SPANDSP_USE_FIXED_POINTx)
vec_zeroi16(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0])); vec_zeroi16(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
s->training_error = 0;
#else #else
vec_zerof(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0])); vec_zerof(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
s->training_error = 0.0f;
#endif #endif
s->training_error = FP_SCALE(0.0f);
s->rrc_filter_step = 0; s->rrc_filter_step = 0;
s->diff = 1; s->diff = 1;
@ -1486,8 +1445,8 @@ SPAN_DECLARE(int) v17_rx_restart(v17_rx_state_t *s, int bit_rate, int short_trai
#endif #endif
if (short_train != 2) if (short_train != 2)
s->short_train = short_train; s->short_train = short_train;
memset(s->last_angles, 0, sizeof(s->last_angles)); vec_zeroi32(s->last_angles, 2);
memset(s->diff_angles, 0, sizeof(s->diff_angles)); vec_zeroi32(s->diff_angles, 16);
/* Initialise the TCM decoder parameters. */ /* Initialise the TCM decoder parameters. */
/* The accumulated distance vectors are set so state zero starts /* The accumulated distance vectors are set so state zero starts
@ -1525,17 +1484,13 @@ SPAN_DECLARE(int) v17_rx_restart(v17_rx_state_t *s, int bit_rate, int short_trai
{ {
s->carrier_phase_rate = DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ); s->carrier_phase_rate = DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ);
equalizer_reset(s); equalizer_reset(s);
s->agc_scaling_save = FP_SCALE(0.0f);
#if defined(SPANDSP_USE_FIXED_POINTx) #if defined(SPANDSP_USE_FIXED_POINTx)
s->agc_scaling_save = 0; s->agc_scaling = (float) (FP_SCALE(2.17f)*1024.0f)/735.0f;
s->agc_scaling = (float) (1024.0f*FP_FACTOR)*2.17f/735.0f;
#else
s->agc_scaling_save = 0.0f;
s->agc_scaling = (1.0f/RX_PULSESHAPER_GAIN)*2.17f/735.0f;
#endif
#if defined(SPANDSP_USE_FIXED_POINTx)
s->carrier_track_i = 5000; s->carrier_track_i = 5000;
s->carrier_track_p = 40000; s->carrier_track_p = 40000;
#else #else
s->agc_scaling = (FP_SCALE(2.17f)/RX_PULSESHAPER_GAIN)/735.0f;
s->carrier_track_i = 5000.0f; s->carrier_track_i = 5000.0f;
s->carrier_track_p = 40000.0f; s->carrier_track_p = 40000.0f;
#endif #endif
@ -1545,23 +1500,13 @@ SPAN_DECLARE(int) v17_rx_restart(v17_rx_state_t *s, int bit_rate, int short_trai
span_log(&s->logging, SPAN_LOG_FLOW, "Phase rates %f %f\n", dds_frequencyf(s->carrier_phase_rate), dds_frequencyf(s->carrier_phase_rate_save)); span_log(&s->logging, SPAN_LOG_FLOW, "Phase rates %f %f\n", dds_frequencyf(s->carrier_phase_rate), dds_frequencyf(s->carrier_phase_rate_save));
/* Initialise the working data for symbol timing synchronisation */ /* Initialise the working data for symbol timing synchronisation */
#if defined(SPANDSP_USE_FIXED_POINTx)
for (i = 0; i < 2; i++) for (i = 0; i < 2; i++)
{ {
s->symbol_sync_low[i] = 0; s->symbol_sync_low[i] = FP_SCALE(0.0f);
s->symbol_sync_high[i] = 0; s->symbol_sync_high[i] = FP_SCALE(0.0f);
s->symbol_sync_dc_filter[i] = 0; s->symbol_sync_dc_filter[i] = FP_SCALE(0.0f);
} }
s->baud_phase = 0; s->baud_phase = FP_SCALE(0.0f);
#else
for (i = 0; i < 2; i++)
{
s->symbol_sync_low[i] = 0.0f;
s->symbol_sync_high[i] = 0.0f;
s->symbol_sync_dc_filter[i] = 0.0f;
}
s->baud_phase = 0.0f;
#endif
s->baud_half = 0; s->baud_half = 0;
s->total_baud_timing_correction = 0; s->total_baud_timing_correction = 0;

View File

@ -861,24 +861,15 @@ int main(int argc, char *argv[])
| T4_SUPPORT_RESOLUTION_600_1200 | T4_SUPPORT_RESOLUTION_600_1200
| T4_SUPPORT_RESOLUTION_1200_1200); | T4_SUPPORT_RESOLUTION_1200_1200);
t30_set_supported_colour_resolutions(t30_state[i], 0); t30_set_supported_colour_resolutions(t30_state[i], 0);
//t30_set_rx_encoding(t30_state[i], T4_COMPRESSION_T85); //t30_set_rx_encoding(t30_state[i], T4_COMPRESSION_T6);
t30_set_ecm_capability(t30_state[i], use_ecm); t30_set_ecm_capability(t30_state[i], use_ecm);
if (use_ecm) t30_set_supported_compressions(t30_state[i],
{ T4_SUPPORT_COMPRESSION_T4_1D
t30_set_supported_compressions(t30_state[i], | T4_SUPPORT_COMPRESSION_T4_2D
T30_SUPPORT_COMPRESSION_T4_1D | T4_SUPPORT_COMPRESSION_T6
| T30_SUPPORT_COMPRESSION_T4_2D //| T4_SUPPORT_COMPRESSION_t42_T81
| T30_SUPPORT_COMPRESSION_T6 | T4_SUPPORT_COMPRESSION_T85
//| T30_SUPPORT_COMPRESSION_T81 | T4_SUPPORT_COMPRESSION_T85_L0);
| T30_SUPPORT_COMPRESSION_T85
| T30_SUPPORT_COMPRESSION_T85_L0);
}
else
{
t30_set_supported_compressions(t30_state[i],
T30_SUPPORT_COMPRESSION_T4_1D
| T30_SUPPORT_COMPRESSION_T4_2D);
}
t30_set_minimum_scan_line_time(t30_state[i], scan_line_time); t30_set_minimum_scan_line_time(t30_state[i], scan_line_time);
if (mode[i] == T38_GATEWAY_FAX) if (mode[i] == T38_GATEWAY_FAX)
@ -954,6 +945,10 @@ int main(int argc, char *argv[])
logging = fax_get_logging_state(fax_state[i]); logging = fax_get_logging_state(fax_state[i]);
span_log_bump_samples(logging, SAMPLES_PER_CHUNK); span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
#if 0
/* Mute the signal */
vec_zeroi16(fax_rx_buf[i], SAMPLES_PER_CHUNK);
#endif
fax_rx(fax_state[i], fax_rx_buf[i], SAMPLES_PER_CHUNK); fax_rx(fax_state[i], fax_rx_buf[i], SAMPLES_PER_CHUNK);
if (!t30_call_active(t30_state[i])) if (!t30_call_active(t30_state[i]))
{ {

View File

@ -106,9 +106,9 @@ static const struct command_response_s fax_send_test_seq[] =
EXCHANGE("AT+FRH=3\r", "\r\nCONNECT\r\n"), EXCHANGE("AT+FRH=3\r", "\r\nCONNECT\r\n"),
//<DIS frame data> //<DIS frame data>
#if 1 #if 1
RESPONSE("\xFF\x13\x80\x00\xEE\xF8\x80\x80\x91\x80\x80\x80\x18\x78\x57\x10\x03"), // For audio FAXing RESPONSE("\xFF\x13\x80\x00\xEE\xF8\x80\x80\x89\x80\x80\x80\x18\x18\xB9\x10\x03"), // For audio FAXing
#else #else
RESPONSE("\xFF\x13\x80\x04\xEE\xF8\x80\x80\x91\x80\x80\x80\x18\xE4\xE7\x10\x03"), // For T.38 FAXing RESPONSE("\xFF\x13\x80\x04\xEE\xF8\x80\x80\x89\x80\x80\x80\x18\x84\x09\x10\x03"), // For T.38 FAXing
#endif #endif
RESPONSE("\r\nOK\r\n"), RESPONSE("\r\nOK\r\n"),
//EXCHANGE("AT+FRH=3\r", "\r\nNO CARRIER\r\n"), //EXCHANGE("AT+FRH=3\r", "\r\nNO CARRIER\r\n"),
@ -870,7 +870,7 @@ static int t30_tests(int t38_mode, int use_gui, int log_audio, int test_sending,
if (!done || !sequence_terminated) if (!done || !sequence_terminated)
{ {
printf("Tests failed\n"); printf("Tests failed\n");
return 2; return -1;
} }
return 0; return 0;
@ -934,7 +934,8 @@ int main(int argc, char *argv[])
} }
} }
t30_tests(t38_mode, use_gui, log_audio, test_sending, g1050_model_no, g1050_speed_pattern_no); if (t30_tests(t38_mode, use_gui, log_audio, test_sending, g1050_model_no, g1050_speed_pattern_no) < 0)
return 2;
printf("Tests passed\n"); printf("Tests passed\n");
return 0; return 0;
} }

View File

@ -440,7 +440,7 @@ int main(int argc, char *argv[])
t30_set_phase_d_handler(t30, phase_d_handler, (void *) (intptr_t) 'A'); t30_set_phase_d_handler(t30, phase_d_handler, (void *) (intptr_t) 'A');
t30_set_phase_e_handler(t30, phase_e_handler, (void *) (intptr_t) 'A'); t30_set_phase_e_handler(t30, phase_e_handler, (void *) (intptr_t) 'A');
t30_set_ecm_capability(t30, use_ecm); t30_set_ecm_capability(t30, use_ecm);
t30_set_supported_compressions(t30, T30_SUPPORT_COMPRESSION_T4_1D | T30_SUPPORT_COMPRESSION_T4_2D | T30_SUPPORT_COMPRESSION_T6 | T30_SUPPORT_COMPRESSION_T85); t30_set_supported_compressions(t30, T4_SUPPORT_COMPRESSION_T4_1D | T4_SUPPORT_COMPRESSION_T4_2D | T4_SUPPORT_COMPRESSION_T6 | T4_SUPPORT_COMPRESSION_T85);
if (pcap_scan_pkts(input_file_name, src_addr, src_port, dest_addr, dest_port, t38_terminal_timing_update, process_packet, NULL)) if (pcap_scan_pkts(input_file_name, src_addr, src_port, dest_addr, dest_port, t38_terminal_timing_update, process_packet, NULL))
exit(2); exit(2);
@ -497,7 +497,7 @@ int main(int argc, char *argv[])
t30_set_phase_d_handler(t30, phase_d_handler, (void *) (intptr_t) 'B'); t30_set_phase_d_handler(t30, phase_d_handler, (void *) (intptr_t) 'B');
t30_set_phase_e_handler(t30, phase_e_handler, (void *) (intptr_t) 'B'); t30_set_phase_e_handler(t30, phase_e_handler, (void *) (intptr_t) 'B');
t30_set_ecm_capability(t30, use_ecm); t30_set_ecm_capability(t30, use_ecm);
t30_set_supported_compressions(t30, T30_SUPPORT_COMPRESSION_T4_1D | T30_SUPPORT_COMPRESSION_T4_2D | T30_SUPPORT_COMPRESSION_T6); t30_set_supported_compressions(t30, T4_SUPPORT_COMPRESSION_T4_1D | T4_SUPPORT_COMPRESSION_T4_2D | T4_SUPPORT_COMPRESSION_T6);
logging = fax_get_logging_state(fax_state); logging = fax_get_logging_state(fax_state);
span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);

View File

@ -47,7 +47,6 @@
#include <tif_dir.h> #include <tif_dir.h>
#endif #endif
//#define IN_FILE_NAME "../test-data/itu/t24/F21_200.TIF"
#define IN_FILE_NAME "../test-data/itu/t24/F21B400.TIF" #define IN_FILE_NAME "../test-data/itu/t24/F21B400.TIF"
#define OUT_FILE_NAME "t42_tests_receive.tif" #define OUT_FILE_NAME "t42_tests_receive.tif"

View File

@ -409,7 +409,7 @@ static void fax_prepare(void)
| T4_SUPPORT_RESOLUTION_1200_1200); | T4_SUPPORT_RESOLUTION_1200_1200);
t30_set_supported_colour_resolutions(t30, 0); t30_set_supported_colour_resolutions(t30, 0);
t30_set_supported_modems(t30, T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17); t30_set_supported_modems(t30, T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17);
t30_set_supported_compressions(t30, T30_SUPPORT_COMPRESSION_T4_1D | T30_SUPPORT_COMPRESSION_T4_2D | T30_SUPPORT_COMPRESSION_T6); t30_set_supported_compressions(t30, T4_SUPPORT_COMPRESSION_T4_1D | T4_SUPPORT_COMPRESSION_T4_2D | T4_SUPPORT_COMPRESSION_T6);
t30_set_phase_b_handler(t30, phase_b_handler, (void *) (intptr_t) 'A'); t30_set_phase_b_handler(t30, phase_b_handler, (void *) (intptr_t) 'A');
t30_set_phase_d_handler(t30, phase_d_handler, (void *) (intptr_t) 'A'); t30_set_phase_d_handler(t30, phase_d_handler, (void *) (intptr_t) 'A');
t30_set_phase_e_handler(t30, phase_e_handler, (void *) (intptr_t) 'A'); t30_set_phase_e_handler(t30, phase_e_handler, (void *) (intptr_t) 'A');
@ -882,7 +882,7 @@ static int next_step(faxtester_state_t *s)
t30 = fax_get_t30_state(fax); t30 = fax_get_t30_state(fax);
t30_set_rx_file(t30, output_tiff_file_name, -1); t30_set_rx_file(t30, output_tiff_file_name, -1);
/* Avoid libtiff 3.8.2 and earlier bug on complex 2D lines. */ /* Avoid libtiff 3.8.2 and earlier bug on complex 2D lines. */
t30_set_rx_encoding(t30, T4_COMPRESSION_T4_1D); t30_set_supported_output_compressions(t30, T4_COMPRESSION_T4_1D);
if (value) if (value)
{ {
sprintf(path, "%s/%s", image_path, (const char *) value); sprintf(path, "%s/%s", image_path, (const char *) value);
@ -897,7 +897,7 @@ static int next_step(faxtester_state_t *s)
next_tx_file[0] = '\0'; next_tx_file[0] = '\0';
t30 = fax_get_t30_state(fax); t30 = fax_get_t30_state(fax);
/* Avoid libtiff 3.8.2 and earlier bug on complex 2D lines. */ /* Avoid libtiff 3.8.2 and earlier bug on complex 2D lines. */
t30_set_rx_encoding(t30, T4_COMPRESSION_T4_1D); t30_set_supported_output_compressions(t30, T4_COMPRESSION_T4_1D);
if (value) if (value)
{ {
sprintf(path, "%s/%s", image_path, (const char *) value); sprintf(path, "%s/%s", image_path, (const char *) value);

View File

@ -890,11 +890,11 @@ static switch_status_t spanfax_init(pvt_t *pvt, transport_mode_t trans_mode)
} }
if (pvt->use_ecm) { if (pvt->use_ecm) {
t30_set_supported_compressions(t30, T30_SUPPORT_COMPRESSION_T4_1D | T30_SUPPORT_COMPRESSION_T4_2D | T30_SUPPORT_COMPRESSION_T6 | T30_SUPPORT_COMPRESSION_T85 | T30_SUPPORT_COMPRESSION_T85_L0); t30_set_supported_compressions(t30, T4_SUPPORT_COMPRESSION_T4_1D | T4_SUPPORT_COMPRESSION_T4_2D | T4_SUPPORT_COMPRESSION_T6 | T4_SUPPORT_COMPRESSION_T85 | T4_SUPPORT_COMPRESSION_T85_L0);
t30_set_ecm_capability(t30, TRUE); t30_set_ecm_capability(t30, TRUE);
switch_channel_set_variable(channel, "fax_ecm_requested", "1"); switch_channel_set_variable(channel, "fax_ecm_requested", "1");
} else { } else {
t30_set_supported_compressions(t30, T30_SUPPORT_COMPRESSION_T4_1D | T30_SUPPORT_COMPRESSION_T4_2D); t30_set_supported_compressions(t30, T4_SUPPORT_COMPRESSION_T4_1D | T4_SUPPORT_COMPRESSION_T4_2D);
switch_channel_set_variable(channel, "fax_ecm_requested", "0"); switch_channel_set_variable(channel, "fax_ecm_requested", "0");
} }