From d429d7fff1787c6263e450dd1051ec8109de5749 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 5 Dec 2013 22:58:12 +0500 Subject: [PATCH] sync spandsp --- libs/spandsp/.update | 2 +- libs/spandsp/INSTALL | 397 ++- libs/spandsp/Makefile.am | 3 +- libs/spandsp/README | 2 +- libs/spandsp/configure.ac | 98 +- libs/spandsp/m4/ax_check_arm_neon.m4 | 24 +- libs/spandsp/spandsp-sim/Makefile.am | 2 +- libs/spandsp/spandsp.spec | 4 +- libs/spandsp/spandsp/fax-tests.xml | 92 + libs/spandsp/spandsp/global-tones.xml | 820 +++--- libs/spandsp/spandsp/tones.dtd | 88 +- libs/spandsp/spandsp/tsb85.xml | 6 +- libs/spandsp/src/Makefile.am | 121 +- libs/spandsp/src/ademco_contactid.c | 54 +- libs/spandsp/src/adsi.c | 31 +- libs/spandsp/src/alloc.c | 171 ++ libs/spandsp/src/async.c | 18 +- libs/spandsp/src/at_interpreter.c | 133 +- libs/spandsp/src/awgn.c | 5 +- libs/spandsp/src/bell_r2_mf.c | 50 +- libs/spandsp/src/bert.c | 16 +- libs/spandsp/src/bitstream.c | 10 +- libs/spandsp/src/complex_filters.c | 13 +- libs/spandsp/src/complex_vector_float.c | 5 + libs/spandsp/src/complex_vector_int.c | 5 + libs/spandsp/src/crc.c | 9 +- libs/spandsp/src/dtmf.c | 91 +- libs/spandsp/src/echo.c | 46 +- libs/spandsp/src/fax.c | 106 +- libs/spandsp/src/fax_modems.c | 145 +- libs/spandsp/src/filter_tools.c | 20 +- libs/spandsp/src/fsk.c | 28 +- libs/spandsp/src/g711.c | 5 +- libs/spandsp/src/g722.c | 32 +- libs/spandsp/src/g726.c | 26 +- libs/spandsp/src/gsm0610_encode.c | 5 +- libs/spandsp/src/hdlc.c | 52 +- libs/spandsp/src/ima_adpcm.c | 5 +- libs/spandsp/src/image_translate.c | 218 +- libs/spandsp/src/libspandsp.2010.vcxproj | 8 + .../src/libspandsp.2010.vcxproj.filters | 12 + libs/spandsp/src/libspandsp.2012.sln | 318 +++ libs/spandsp/src/libspandsp.2012.vcxproj | 8 + .../src/libspandsp.2012.vcxproj.filters | 20 +- libs/spandsp/src/logging.c | 16 +- libs/spandsp/src/lpc10_analyse.c | 9 +- libs/spandsp/src/lpc10_decode.c | 22 +- libs/spandsp/src/lpc10_encode.c | 12 +- libs/spandsp/src/lpc10_placev.c | 17 +- libs/spandsp/src/lpc10_voicing.c | 5 + libs/spandsp/src/make_at_dictionary.c | 4 - libs/spandsp/src/make_cielab_luts.c | 11 +- libs/spandsp/src/make_math_fixed_tables.c | 16 +- libs/spandsp/src/make_modem_filter.c | 38 +- libs/spandsp/src/make_t43_gray_code_tables.c | 101 + libs/spandsp/src/modem_connect_tones.c | 37 +- libs/spandsp/src/modem_echo.c | 25 +- libs/spandsp/src/msvc/config.h | 2 + libs/spandsp/src/msvc/getopt.c | 352 +-- libs/spandsp/src/msvc/gettimeofday.c | 34 +- .../make_t43_gray_code_tables.2010.vcxproj | 65 + ..._t43_gray_code_tables.2010.vcxproj.filters | 14 + .../make_t43_gray_code_tables.2012.vcxproj | 66 + ..._t43_gray_code_tables.2012.vcxproj.filters | 14 + libs/spandsp/src/msvc/spandsp.h | 8 +- libs/spandsp/src/noise.c | 5 +- libs/spandsp/src/oki_adpcm.c | 5 +- libs/spandsp/src/playout.c | 26 +- libs/spandsp/src/plc.c | 7 +- libs/spandsp/src/power_meter.c | 20 +- libs/spandsp/src/queue.c | 15 +- libs/spandsp/src/schedule.c | 12 +- libs/spandsp/src/sig_tone.c | 27 +- libs/spandsp/src/silence_gen.c | 10 +- libs/spandsp/src/spandsp.h.in | 18 +- libs/spandsp/src/spandsp/alloc.h | 77 + libs/spandsp/src/spandsp/async.h | 8 +- libs/spandsp/src/spandsp/at_interpreter.h | 14 +- libs/spandsp/src/spandsp/bell_r2_mf.h | 8 +- libs/spandsp/src/spandsp/bit_operations.h | 4 +- libs/spandsp/src/spandsp/bitstream.h | 2 +- libs/spandsp/src/spandsp/crc.h | 8 +- libs/spandsp/src/spandsp/dtmf.h | 2 +- libs/spandsp/src/spandsp/expose.h | 16 +- libs/spandsp/src/spandsp/fast_convert.h | 4 + libs/spandsp/src/spandsp/fax.h | 12 +- libs/spandsp/src/spandsp/fax_modems.h | 10 + libs/spandsp/src/spandsp/fsk.h | 7 +- libs/spandsp/src/spandsp/g722.h | 7 - libs/spandsp/src/spandsp/hdlc.h | 16 +- libs/spandsp/src/spandsp/image_translate.h | 26 +- libs/spandsp/src/spandsp/logging.h | 4 +- .../spandsp/src/spandsp/modem_connect_tones.h | 2 +- libs/spandsp/src/spandsp/playout.h | 71 +- libs/spandsp/src/spandsp/plc.h | 16 +- libs/spandsp/src/spandsp/power_meter.h | 23 +- libs/spandsp/src/spandsp/private/async.h | 4 +- .../src/spandsp/private/at_interpreter.h | 8 +- libs/spandsp/src/spandsp/private/bell_r2_mf.h | 8 +- libs/spandsp/src/spandsp/private/bitstream.h | 4 +- libs/spandsp/src/spandsp/private/dtmf.h | 4 +- libs/spandsp/src/spandsp/private/fax_modems.h | 31 +- libs/spandsp/src/spandsp/private/g722.h | 31 +- libs/spandsp/src/spandsp/private/hdlc.h | 28 +- libs/spandsp/src/spandsp/private/lpc10.h | 20 +- .../src/spandsp/private/modem_connect_tones.h | 8 +- libs/spandsp/src/spandsp/private/playout.h | 105 + libs/spandsp/src/spandsp/private/plc.h | 64 + .../spandsp/src/spandsp/private/power_meter.h | 53 + libs/spandsp/src/spandsp/private/sig_tone.h | 8 +- libs/spandsp/src/spandsp/private/t30.h | 116 +- .../spandsp/private/t30_dis_dtc_dcs_bits.h | 202 +- libs/spandsp/src/spandsp/private/t31.h | 40 +- libs/spandsp/src/spandsp/private/t38_core.h | 4 +- .../spandsp/src/spandsp/private/t38_gateway.h | 36 +- .../src/spandsp/private/t38_non_ecm_buffer.h | 8 +- .../src/spandsp/private/t38_terminal.h | 8 +- libs/spandsp/src/spandsp/private/t42.h | 62 +- libs/spandsp/src/spandsp/private/t43.h | 96 + libs/spandsp/src/spandsp/private/t4_rx.h | 46 +- .../src/spandsp/private/t4_t6_decode.h | 4 +- .../src/spandsp/private/t4_t6_encode.h | 2 +- libs/spandsp/src/spandsp/private/t4_tx.h | 87 +- libs/spandsp/src/spandsp/private/t85.h | 4 +- libs/spandsp/src/spandsp/private/timezone.h | 4 +- libs/spandsp/src/spandsp/private/v17rx.h | 4 +- libs/spandsp/src/spandsp/private/v17tx.h | 8 +- libs/spandsp/src/spandsp/private/v18.h | 20 +- libs/spandsp/src/spandsp/private/v22bis.h | 4 +- libs/spandsp/src/spandsp/private/v27ter_rx.h | 4 +- libs/spandsp/src/spandsp/private/v27ter_tx.h | 6 +- libs/spandsp/src/spandsp/private/v29rx.h | 4 +- libs/spandsp/src/spandsp/private/v29tx.h | 6 +- libs/spandsp/src/spandsp/private/v42.h | 14 +- libs/spandsp/src/spandsp/private/v42bis.h | 8 +- libs/spandsp/src/spandsp/private/v8.h | 10 +- libs/spandsp/src/spandsp/queue.h | 4 +- libs/spandsp/src/spandsp/stdbool.h | 55 + libs/spandsp/src/spandsp/t30.h | 137 +- libs/spandsp/src/spandsp/t30_api.h | 43 +- libs/spandsp/src/spandsp/t30_logging.h | 6 + libs/spandsp/src/spandsp/t31.h | 20 +- libs/spandsp/src/spandsp/t35.h | 4 +- libs/spandsp/src/spandsp/t38_core.h | 20 +- libs/spandsp/src/spandsp/t38_gateway.h | 28 +- libs/spandsp/src/spandsp/t38_non_ecm_buffer.h | 8 +- libs/spandsp/src/spandsp/t38_terminal.h | 16 +- libs/spandsp/src/spandsp/t42.h | 53 +- libs/spandsp/src/spandsp/t43.h | 207 ++ libs/spandsp/src/spandsp/t4_rx.h | 329 ++- libs/spandsp/src/spandsp/t4_t6_decode.h | 2 +- libs/spandsp/src/spandsp/t4_t6_encode.h | 15 +- libs/spandsp/src/spandsp/t4_tx.h | 137 +- libs/spandsp/src/spandsp/t85.h | 2 + libs/spandsp/src/spandsp/telephony.h | 7 - libs/spandsp/src/spandsp/v17rx.h | 4 +- libs/spandsp/src/spandsp/v17tx.h | 10 +- libs/spandsp/src/spandsp/v18.h | 56 +- libs/spandsp/src/spandsp/v22bis.h | 8 +- libs/spandsp/src/spandsp/v27ter_rx.h | 4 +- libs/spandsp/src/spandsp/v27ter_tx.h | 8 +- libs/spandsp/src/spandsp/v29rx.h | 4 +- libs/spandsp/src/spandsp/v29tx.h | 8 +- libs/spandsp/src/spandsp/v42.h | 8 +- libs/spandsp/src/spandsp/v8.h | 6 +- libs/spandsp/src/super_tone_rx.c | 25 +- libs/spandsp/src/super_tone_tx.c | 9 +- libs/spandsp/src/swept_tone.c | 10 +- libs/spandsp/src/t30.c | 2509 +++++++++-------- libs/spandsp/src/t30_api.c | 183 +- libs/spandsp/src/t30_logging.c | 39 +- libs/spandsp/src/t31.c | 333 ++- libs/spandsp/src/t35.c | 441 +-- libs/spandsp/src/t38_core.c | 42 +- libs/spandsp/src/t38_gateway.c | 225 +- libs/spandsp/src/t38_non_ecm_buffer.c | 22 +- libs/spandsp/src/t38_terminal.c | 74 +- libs/spandsp/src/t42.c | 1660 +++++------ libs/spandsp/src/t42_t43_local.h | 3 +- libs/spandsp/src/t43.c | 934 ++++++ libs/spandsp/src/t4_rx.c | 1035 +++++-- libs/spandsp/src/t4_t6_decode.c | 76 +- libs/spandsp/src/t4_t6_encode.c | 85 +- libs/spandsp/src/t4_tx.c | 2366 ++++++++++++---- libs/spandsp/src/t81_t82_arith_coding.c | 29 +- libs/spandsp/src/t85_decode.c | 201 +- libs/spandsp/src/t85_encode.c | 30 +- libs/spandsp/src/time_scale.c | 18 +- libs/spandsp/src/timezone.c | 28 +- libs/spandsp/src/tone_detect.c | 5 +- libs/spandsp/src/tone_generate.c | 9 +- libs/spandsp/src/v17rx.c | 292 +- libs/spandsp/src/v17tx.c | 22 +- libs/spandsp/src/v18.c | 629 +++-- libs/spandsp/src/v22bis_rx.c | 16 +- libs/spandsp/src/v22bis_tx.c | 15 +- libs/spandsp/src/v27ter_rx.c | 29 +- libs/spandsp/src/v27ter_tx.c | 20 +- libs/spandsp/src/v29rx.c | 24 +- libs/spandsp/src/v29tx.c | 20 +- libs/spandsp/src/v42.c | 79 +- libs/spandsp/src/v42bis.c | 29 +- libs/spandsp/src/v8.c | 51 +- libs/spandsp/src/vector_int.c | 8 +- .../etsi/fax/generate_etsi_300_242_pages.c | 50 +- libs/spandsp/test-data/itu/fax/Makefile.am | 72 +- .../test-data/itu/fax/generate_dithered_tif.c | 14 +- .../test-data/itu/fax/generate_sized_pages.c | 543 +++- .../itu/fax/generate_striped_pages.c | 11 +- .../test-data/local/lenna-colour-bilevel.tif | Bin 0 -> 990730 bytes libs/spandsp/tests/Makefile.am | 37 +- libs/spandsp/tests/ademco_contactid_tests.c | 20 +- libs/spandsp/tests/adsi_tests.c | 36 +- libs/spandsp/tests/alloc_tests.c | 79 + libs/spandsp/tests/async_tests.c | 80 +- libs/spandsp/tests/bell_mf_rx_tests.c | 12 +- libs/spandsp/tests/bert_tests.c | 26 +- libs/spandsp/tests/bitstream_tests.c | 12 +- libs/spandsp/tests/dtmf_rx_tests.c | 48 +- libs/spandsp/tests/dtmf_tx_tests.c | 4 +- libs/spandsp/tests/echo_tests.c | 28 +- libs/spandsp/tests/fax_decode.c | 32 +- libs/spandsp/tests/fax_tester.c | 52 +- libs/spandsp/tests/fax_tester.h | 16 +- libs/spandsp/tests/fax_tests.c | 234 +- libs/spandsp/tests/fax_tests.sh | 321 ++- libs/spandsp/tests/fax_utils.c | 2 +- libs/spandsp/tests/fsk_tests.c | 22 +- libs/spandsp/tests/g1050_tests.c | 4 +- libs/spandsp/tests/g168_tests.c | 5 +- libs/spandsp/tests/g711_tests.c | 22 +- libs/spandsp/tests/g722_tests.c | 50 +- libs/spandsp/tests/g726_tests.c | 6 +- libs/spandsp/tests/gsm0610_tests.c | 34 +- libs/spandsp/tests/hdlc_tests.c | 180 +- libs/spandsp/tests/ima_adpcm_tests.c | 8 +- libs/spandsp/tests/image_translate_tests.c | 325 ++- libs/spandsp/tests/line_model_tests.c | 4 +- libs/spandsp/tests/logging_tests.c | 16 +- libs/spandsp/tests/lpc10_tests.c | 22 +- .../spandsp/tests/modem_connect_tones_tests.c | 167 +- libs/spandsp/tests/modem_echo_tests.c | 14 +- .../tests/msvc/complex_tests.2012.vcxproj | 109 + .../msvc/complex_tests.2012.vcxproj.filters | 33 + .../complex_vector_float_tests.2012.vcxproj | 109 + ...ex_vector_float_tests.2012.vcxproj.filters | 33 + .../complex_vector_int_tests.2012.vcxproj | 109 + ...plex_vector_int_tests.2012.vcxproj.filters | 33 + .../tests/msvc/dtmf_rx_tests.2012.vcxproj | 103 + .../msvc/dtmf_rx_tests.2012.vcxproj.filters | 33 + .../tests/msvc/dtmf_tx_tests.2012.vcxproj | 103 + .../msvc/dtmf_tx_tests.2012.vcxproj.filters | 33 + .../tests/msvc/queue_tests.2012.vcxproj | 103 + .../msvc/queue_tests.2012.vcxproj.filters | 33 + .../tests/msvc/t38_core_tests.2012.vcxproj | 109 + .../msvc/t38_core_tests.2012.vcxproj.filters | 33 + .../t38_non_ecm_buffer_tests.2012.vcxproj | 109 + ..._non_ecm_buffer_tests.2012.vcxproj.filters | 33 + .../tests/msvc/v22bis_tests.2012.vcxproj | 103 + .../msvc/v22bis_tests.2012.vcxproj.filters | 33 + .../spandsp/tests/msvc/v29_tests.2012.vcxproj | 103 + .../tests/msvc/v29_tests.2012.vcxproj.filters | 33 + .../spandsp/tests/msvc/v80_tests.2012.vcxproj | 103 + .../tests/msvc/v80_tests.2012.vcxproj.filters | 33 + libs/spandsp/tests/msvc/v8_tests.2012.vcxproj | 103 + .../tests/msvc/v8_tests.2012.vcxproj.filters | 33 + .../msvc/vector_float_tests.2012.vcxproj | 109 + .../vector_float_tests.2012.vcxproj.filters | 33 + .../tests/msvc/vector_int_tests.2012.vcxproj | 109 + .../vector_int_tests.2012.vcxproj.filters | 33 + libs/spandsp/tests/oki_adpcm_tests.c | 6 +- libs/spandsp/tests/plc_tests.c | 14 +- libs/spandsp/tests/power_meter_tests.c | 18 +- libs/spandsp/tests/pseudo_terminal_tests.c | 150 + libs/spandsp/tests/pseudo_terminals.c | 5 +- libs/spandsp/tests/queue_tests.c | 12 +- libs/spandsp/tests/r2_mf_rx_tests.c | 16 +- libs/spandsp/tests/r2_mf_tx_tests.c | 4 +- libs/spandsp/tests/regression_tests.sh | 9 + libs/spandsp/tests/rfc2198_sim_tests.c | 4 +- libs/spandsp/tests/sig_tone_tests.c | 6 +- libs/spandsp/tests/super_tone_tx_tests.c | 1 - libs/spandsp/tests/swept_tone_tests.c | 2 +- .../spandsp/tests/t31_pseudo_terminal_tests.c | 56 +- libs/spandsp/tests/t31_tests.c | 89 +- libs/spandsp/tests/t35_tests.c | 6 +- libs/spandsp/tests/t38_core_tests.c | 18 +- libs/spandsp/tests/t38_decode.c | 94 +- libs/spandsp/tests/t38_non_ecm_buffer_tests.c | 14 +- libs/spandsp/tests/t42_tests.c | 55 +- libs/spandsp/tests/t43_tests.c | 1403 +++++++++ libs/spandsp/tests/t4_t6_tests.c | 24 +- libs/spandsp/tests/t4_tests.c | 397 +-- .../tests/t81_t82_arith_coding_tests.c | 19 +- libs/spandsp/tests/t85_tests.c | 3 - libs/spandsp/tests/time_scale_tests.c | 6 +- libs/spandsp/tests/timezone_tests.c | 8 - libs/spandsp/tests/tone_generate_tests.c | 16 +- libs/spandsp/tests/tsb85_extra_tests.sh | 2 +- libs/spandsp/tests/tsb85_tests.c | 216 +- libs/spandsp/tests/udptl.c | 43 +- libs/spandsp/tests/v17_tests.c | 22 +- libs/spandsp/tests/v18_tests.c | 1692 +++++++---- libs/spandsp/tests/v22bis_tests.c | 10 +- libs/spandsp/tests/v27ter_tests.c | 20 +- libs/spandsp/tests/v29_tests.c | 20 +- libs/spandsp/tests/v42_tests.c | 20 +- libs/spandsp/tests/v42bis_tests.c | 16 +- libs/spandsp/tests/v8_tests.c | 33 +- libs/spandsp/tests/vector_float_tests.c | 9 +- libs/spandsp/yum-prepare.sh | 26 + 311 files changed, 19380 insertions(+), 8449 deletions(-) create mode 100644 libs/spandsp/src/alloc.c create mode 100644 libs/spandsp/src/libspandsp.2012.sln create mode 100644 libs/spandsp/src/make_t43_gray_code_tables.c create mode 100644 libs/spandsp/src/msvc/make_t43_gray_code_tables.2010.vcxproj create mode 100644 libs/spandsp/src/msvc/make_t43_gray_code_tables.2010.vcxproj.filters create mode 100644 libs/spandsp/src/msvc/make_t43_gray_code_tables.2012.vcxproj create mode 100644 libs/spandsp/src/msvc/make_t43_gray_code_tables.2012.vcxproj.filters create mode 100644 libs/spandsp/src/spandsp/alloc.h create mode 100644 libs/spandsp/src/spandsp/private/playout.h create mode 100644 libs/spandsp/src/spandsp/private/plc.h create mode 100644 libs/spandsp/src/spandsp/private/power_meter.h create mode 100644 libs/spandsp/src/spandsp/private/t43.h create mode 100644 libs/spandsp/src/spandsp/stdbool.h create mode 100644 libs/spandsp/src/spandsp/t43.h create mode 100644 libs/spandsp/src/t43.c create mode 100644 libs/spandsp/test-data/local/lenna-colour-bilevel.tif create mode 100644 libs/spandsp/tests/alloc_tests.c create mode 100644 libs/spandsp/tests/msvc/complex_tests.2012.vcxproj create mode 100644 libs/spandsp/tests/msvc/complex_tests.2012.vcxproj.filters create mode 100644 libs/spandsp/tests/msvc/complex_vector_float_tests.2012.vcxproj create mode 100644 libs/spandsp/tests/msvc/complex_vector_float_tests.2012.vcxproj.filters create mode 100644 libs/spandsp/tests/msvc/complex_vector_int_tests.2012.vcxproj create mode 100644 libs/spandsp/tests/msvc/complex_vector_int_tests.2012.vcxproj.filters create mode 100644 libs/spandsp/tests/msvc/dtmf_rx_tests.2012.vcxproj create mode 100644 libs/spandsp/tests/msvc/dtmf_rx_tests.2012.vcxproj.filters create mode 100644 libs/spandsp/tests/msvc/dtmf_tx_tests.2012.vcxproj create mode 100644 libs/spandsp/tests/msvc/dtmf_tx_tests.2012.vcxproj.filters create mode 100644 libs/spandsp/tests/msvc/queue_tests.2012.vcxproj create mode 100644 libs/spandsp/tests/msvc/queue_tests.2012.vcxproj.filters create mode 100644 libs/spandsp/tests/msvc/t38_core_tests.2012.vcxproj create mode 100644 libs/spandsp/tests/msvc/t38_core_tests.2012.vcxproj.filters create mode 100644 libs/spandsp/tests/msvc/t38_non_ecm_buffer_tests.2012.vcxproj create mode 100644 libs/spandsp/tests/msvc/t38_non_ecm_buffer_tests.2012.vcxproj.filters create mode 100644 libs/spandsp/tests/msvc/v22bis_tests.2012.vcxproj create mode 100644 libs/spandsp/tests/msvc/v22bis_tests.2012.vcxproj.filters create mode 100644 libs/spandsp/tests/msvc/v29_tests.2012.vcxproj create mode 100644 libs/spandsp/tests/msvc/v29_tests.2012.vcxproj.filters create mode 100644 libs/spandsp/tests/msvc/v80_tests.2012.vcxproj create mode 100644 libs/spandsp/tests/msvc/v80_tests.2012.vcxproj.filters create mode 100644 libs/spandsp/tests/msvc/v8_tests.2012.vcxproj create mode 100644 libs/spandsp/tests/msvc/v8_tests.2012.vcxproj.filters create mode 100644 libs/spandsp/tests/msvc/vector_float_tests.2012.vcxproj create mode 100644 libs/spandsp/tests/msvc/vector_float_tests.2012.vcxproj.filters create mode 100644 libs/spandsp/tests/msvc/vector_int_tests.2012.vcxproj create mode 100644 libs/spandsp/tests/msvc/vector_int_tests.2012.vcxproj.filters create mode 100644 libs/spandsp/tests/pseudo_terminal_tests.c create mode 100644 libs/spandsp/tests/t43_tests.c create mode 100644 libs/spandsp/yum-prepare.sh diff --git a/libs/spandsp/.update b/libs/spandsp/.update index 8822907a94..26b36ceacc 100644 --- a/libs/spandsp/.update +++ b/libs/spandsp/.update @@ -1 +1 @@ -Tue Dec 6 17:55:59 CST 2011 +Thu Dec 5 22:57:57 CDT 2013 diff --git a/libs/spandsp/INSTALL b/libs/spandsp/INSTALL index 2abc70492a..007e9396d0 100644 --- a/libs/spandsp/INSTALL +++ b/libs/spandsp/INSTALL @@ -1,121 +1,80 @@ -Building and installing spandsp -=============================== - -A number of distributions include spandsp, but they usually use older versions -of the library, which lack a lot of the features of the current version. Before -installing spandsp, make sure there are no older versions already on your -machine. Make sure libtiff is installed on your machine. Versions 3.5.7, -3.6.0, 3.7.1 and 3.8.2 seem to work OK. There have been several bugs related -to FAX document handling in some versions of libtiff. Also, some people have -had trouble using spandsp because they had more than one version of libtiff -on their machine. Take care with this. If you are using an RPM based system, -such as RedHat or Fedora, you will need the libtiff and libtiff-devel RPMs -installed to be able to build spandsp. - -You can use the usual: - - ./configure - make - make install - -process to build the spandsp library. Note that if you use configure in this -way, the software will be installed in /usr/local. In this case make sure your -/etc/ld.so.conf file has an entry for /usr/local/lib. If you wish the software -to be installed in /usr, you should build it with the commands. - - ./configure --prefix=/usr - make - make install - - -Building the programming documentation -====================================== - -If you wish to build the programming documentation for spandsp, configure -spandsp with: - - ./configure --enable-doc - -You need doxygen installed on your machine. - - -Building the test suite -======================= - -Most sections of the spandsp library have an accompanying test program in the -test directory. If you wish to build these test programs, configure spandsp -with: - - ./configure --enable-tests - -To build these tests you will need libaudiofile installed on your machine. To -build the modem tests, with the GUI monitoring feature you will need Fltk 1.1.4 -or later, an audio meter module and a cartesian plotting module. Fltk may be -obtained from http://www.fltk.org. The audio meter module may be obtained from -http://www.soft-switch.org/downloads/Fl_Audio_Meter.tgz . The cartesian plotting -module may be obtained from http://134.226.68.29/fltk. However, there is no -suitable makefile supplied with that. You can find a version at -http://www.soft-switch.org/downloads/Fl_Cartesian.tgz which will build as a -Linux library. The actual code in both these versions is identical. -You need to have Fltk 1.1.4 or later installed before building the plotting -library. - - -Applications -============ - -Applications support for spandsp is built into packages such as Callweaver, -FreeSwitch and iaxmodem. Code to add spandsp based FAX support to Asterisk may -be found at http://sourceforge.net/projects/agx-ast-addons. - +Installation Instructions +************************* +Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation, +Inc. + Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. This file is offered as-is, +without warranty of any kind. Basic Installation ================== - These are generic installation instructions. + Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. Some packages provide this +`INSTALL' file but do not implement all of the features documented +below. The lack of an optional feature in a given package is not +necessarily a bug. More recommendations for GNU packages can be found +in *note Makefile Conventions: (standards)Makefile Conventions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that -you can run in the future to recreate the current configuration, a file -`config.cache' that saves the results of its tests to speed up -reconfiguring, and a file `config.log' containing compiler output -(useful mainly for debugging `configure'). +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can -be considered for the next release. If at some point `config.cache' -contains results you don't want to keep, you may remove or edit it. +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. - The file `configure.ac' is used to create `configure' by a program -called `autoconf'. You only need `configure.ac' if you want to change -it or regenerate `configure' using a newer version of `autoconf'. + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. -The simplest way to compile this package is: + The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type - `./configure' to configure the package for your system. If you're - using `csh' on an old version of System V, you might need to type - `sh ./configure' instead to prevent `csh' from trying to execute - `configure' itself. + `./configure' to configure the package for your system. - Running `configure' takes awhile. While running, it prints some - messages telling which features it is checking for. + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with - the package. + the package, generally using the just-built uninstalled binaries. 4. Type `make install' to install the programs and any data files and - documentation. + documentation. When installing into a prefix owned by root, it is + recommended that the package be configured and built as a regular + user, and only the `make install' phase executed with root + privileges. - 5. You can remove the program binaries and object files from the + 5. Optionally, type `make installcheck' to repeat any self-tests, but + this time using the binaries in their final installed location. + This target does not install anything. Running this target as a + regular user, particularly if the prior `make install' required + root privileges, verifies that the installation completed + correctly. + + 6. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is @@ -124,62 +83,119 @@ The simplest way to compile this package is: all sorts of other programs in order to regenerate files that came with the distribution. + 7. Often, you can also type `make uninstall' to remove the installed + files again. In practice, not all packages have tested that + uninstallation works correctly, even though it is required by the + GNU Coding Standards. + + 8. Some packages, particularly those that use Automake, provide `make + distcheck', which can by used by developers to test that all other + targets like `make install' and `make uninstall' work correctly. + This target is generally not run by end users. + Compilers and Options ===================== Some systems require unusual options for compilation or linking that -the `configure' script does not know about. You can give `configure' -initial values for variables by setting them in the environment. Using -a Bourne-compatible shell, you can do that on the command line like -this: - CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. -Or on systems that have the `env' program, you can do it like this: - env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their -own directory. To do this, you must use a version of `make' that -supports the `VPATH' variable, such as GNU `make'. `cd' to the +own directory. To do this, you can use GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the -source code in the directory that `configure' is in and in `..'. +source code in the directory that `configure' is in and in `..'. This +is known as a "VPATH" build. - If you have to use a `make' that does not supports the `VPATH' -variable, you have to compile the package for one architecture at a time -in the source code directory. After you have installed the package for -one architecture, use `make distclean' before reconfiguring for another -architecture. + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + + On MacOS X 10.5 and later systems, you can create libraries and +executables that work on multiple system types--known as "fat" or +"universal" binaries--by specifying multiple `-arch' options to the +compiler but only a single `-arch' option to the preprocessor. Like +this: + + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CPP="gcc -E" CXXCPP="g++ -E" + + This is not guaranteed to produce working output in all cases, you +may have to build one architecture at a time and combine the results +using the `lipo' tool if you have problems. Installation Names ================== - By default, `make install' will install the package's files in -`/usr/local/bin', `/usr/local/man', etc. You can specify an -installation prefix other than `/usr/local' by giving `configure' the -option `--prefix=PATH'. + By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX', where PREFIX must be an +absolute file name. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you -give `configure' the option `--exec-prefix=PATH', the package will use -PATH as the prefix for installing programs and libraries. -Documentation and other data files will still use the regular prefix. +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give -options like `--bindir=PATH' to specify different values for particular +options like `--bindir=DIR' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories -you can set and what kinds of files go in them. +you can set and what kinds of files go in them. In general, the +default for these options is expressed in terms of `${prefix}', so that +specifying just `--prefix' will affect all of the other directory +specifications that were not explicitly provided. + + The most portable way to affect installation locations is to pass the +correct locations to `configure'; however, many packages provide one or +both of the following shortcuts of passing variable assignments to the +`make install' command line to change installation locations without +having to reconfigure or recompile. + + The first method involves providing an override variable for each +affected directory. For example, `make install +prefix=/alternate/directory' will choose an alternate location for all +directory configuration variables that were expressed in terms of +`${prefix}'. Any directories that were specified during `configure', +but not in terms of `${prefix}', must each be overridden at install +time for the entire installation to be relocated. The approach of +makefile variable overrides for each directory variable is required by +the GNU Coding Standards, and ideally causes no recompilation. +However, some platforms have known limitations with the semantics of +shared libraries that end up requiring recompilation when using this +method, particularly noticeable in packages that use GNU Libtool. + + The second method involves providing the `DESTDIR' variable. For +example, `make install DESTDIR=/alternate/directory' will prepend +`/alternate/directory' before all installation names. The approach of +`DESTDIR' overrides is not required by the GNU Coding Standards, and +does not work on platforms that have drive letters. On the other hand, +it does better at avoiding recompilation issues, and works well even +when some directory options were not specified in terms of `${prefix}' +at `configure' time. + +Optional Features +================= If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. -Optional Features -================= - Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE @@ -192,25 +208,80 @@ find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. + Some packages offer the ability to configure how verbose the +execution of `make' will be. For these packages, running `./configure +--enable-silent-rules' sets the default to minimal output, which can be +overridden with `make V=1'; while running `./configure +--disable-silent-rules' sets the default to verbose, which can be +overridden with `make V=0'. + +Particular systems +================== + + On HP-UX, the default C compiler is not ANSI C compatible. If GNU +CC is not installed, it is recommended to use the following options in +order to use an ANSI C compiler: + + ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" + +and if that doesn't work, install pre-built binaries of GCC for HP-UX. + + HP-UX `make' updates targets which have the same time stamps as +their prerequisites, which makes it generally unusable when shipped +generated files such as `configure' are involved. Use GNU `make' +instead. + + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot +parse its `' header file. The option `-nodtk' can be used as +a workaround. If GNU CC is not installed, it is therefore recommended +to try + + ./configure CC="cc" + +and if that doesn't work, try + + ./configure CC="cc -nodtk" + + On Solaris, don't put `/usr/ucb' early in your `PATH'. This +directory contains several dysfunctional programs; working variants of +these programs are available in `/usr/bin'. So, if you need `/usr/ucb' +in your `PATH', put it _after_ `/usr/bin'. + + On Haiku, software installed for all users goes in `/boot/common', +not `/usr/local'. It is recommended to use the following options: + + ./configure --prefix=/boot/common + Specifying the System Type ========================== - There may be some features `configure' can not figure out -automatically, but needs to determine by the type of host the package -will run on. Usually `configure' can figure that out, but if it prints -a message saying it can not guess the host type, give it the -`--host=TYPE' option. TYPE can either be a short name for the system -type, such as `sun4', or a canonical name with three fields: + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + CPU-COMPANY-SYSTEM -See the file `config.sub' for the possible values of each field. If -`config.sub' isn't included in this package, then this package doesn't -need to know the host type. +where SYSTEM can have one of these forms: - If you are building compiler tools for cross-compiling, you can also -use the `--target=TYPE' option to select the type of system they will -produce code for and the `--build=TYPE' option to select the type of -system on which you are compiling the package. + OS + KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. Sharing Defaults ================ @@ -223,19 +294,56 @@ default values for variables like `CC', `cache_file', and `prefix'. `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. -Operation Controls +Defining Variables ================== + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf limitation. Until the limitation is lifted, you can use +this workaround: + + CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + `configure' recognizes the following options to control how it operates. -`--cache-file=FILE' - Use and save the results of the tests in FILE instead of - `./config.cache'. Set FILE to `/dev/null' to disable caching, for - debugging `configure'. - `--help' - Print a summary of the options to `configure', and exit. +`-h' + Print a summary of all of the options to `configure', and exit. + +`--help=short' +`--help=recursive' + Print a summary of the options unique to this package's + `configure', and exit. The `short' variant lists options used + only in the top level, while the `recursive' variant lists options + also present in any nested packages. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. `--quiet' `--silent' @@ -248,8 +356,15 @@ operates. Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. -`--version' - Print the version of Autoconf used to generate the `configure' - script, and exit. +`--prefix=DIR' + Use DIR as the installation prefix. *note Installation Names:: + for more details, including other options available for fine-tuning + the installation locations. -`configure' also accepts some other, not widely useful, options. +`--no-create' +`-n' + Run the configure checks, but stop before creating any output + files. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. diff --git a/libs/spandsp/Makefile.am b/libs/spandsp/Makefile.am index 3eaddfc7a1..6902c867c5 100644 --- a/libs/spandsp/Makefile.am +++ b/libs/spandsp/Makefile.am @@ -47,7 +47,8 @@ EXTRA_DIST = autogen.sh \ unpack_g726_data.sh \ unpack_gsm0610_data.sh \ unpack_v56ter_data.sh \ - wrapper.xsl + wrapper.xsl \ + yum-prepare.sh if COND_DOC MAYBE_DOC=doc diff --git a/libs/spandsp/README b/libs/spandsp/README index 093960b429..3e900525e8 100644 --- a/libs/spandsp/README +++ b/libs/spandsp/README @@ -1,4 +1,4 @@ -spandsp 0.0.5 - A DSP library for telephony +spandsp 0.0.6 - A DSP library for telephony ------------------------------------------- SpanDSP is a library of DSP functions for telephony, in the 8000 sample per diff --git a/libs/spandsp/configure.ac b/libs/spandsp/configure.ac index ad379aecbe..423513100c 100644 --- a/libs/spandsp/configure.ac +++ b/libs/spandsp/configure.ac @@ -19,7 +19,7 @@ # @start 1 AC_PREREQ([2.59]) -AC_INIT([spandsp], [0.0.7]) +AC_INIT([spandsp], [1.99.0]) SPANDSP_LT_CURRENT=3 SPANDSP_LT_REVISION=0 @@ -125,6 +125,9 @@ AC_TYPE_SIGNAL AC_ARG_ENABLE(doc, [ --enable-doc Build the documentation]) AC_ARG_ENABLE(tests, [ --enable-tests Build the test programs]) +AC_ARG_ENABLE(t43, [ --enable-t43 Enable T.43 support]) +AC_ARG_ENABLE(v32bis, [ --enable-v32bis Enable V.32bis support]) +AC_ARG_ENABLE(v34, [ --enable-v34 Enable V.34 support]) AC_ARG_ENABLE(mmx, [ --enable-mmx Enable MMX support]) AC_ARG_ENABLE(sse, [ --enable-sse Enable SSE support]) AC_ARG_ENABLE(sse2, [ --enable-sse2 Enable SSE2 support]) @@ -135,8 +138,10 @@ AC_ARG_ENABLE(sse4_2, [ --enable-sse4-2 Enable SSE4.2 support]) AC_ARG_ENABLE(sse4a, [ --enable-sse4a Enable SSE4A support]) AC_ARG_ENABLE(sse5, [ --enable-sse5 Enable SSE5 support]) AC_ARG_ENABLE(avx, [ --enable-avx Enable AVX support]) +AC_ARG_ENABLE(avx2, [ --enable-avx2 Enable AVX2 support]) AC_ARG_ENABLE(neon, [ --enable-neon Enable NEON support]) AC_ARG_ENABLE(fixed_point, [ --enable-fixed-point Enable fixed point support]) + # The following is for MSVC, where we may be using a local copy of libtiff, built alongside spandsp AC_ARG_ENABLE(builtin_tiff, [AC_HELP_STRING([--enable-builtin-tiff],[build with builtin libtiff])],[enable_builtin_tiff="$enableval"],[enable_builtin_tiff="no"]) @@ -162,6 +167,9 @@ fi AX_C99_FLEXIBLE_ARRAY +AC_CHECK_FUNCS([aligned_alloc]) +AC_CHECK_FUNCS([memalign]) +AC_CHECK_FUNCS([posix_memalign]) AC_CHECK_FUNCS([memmove]) AC_CHECK_FUNCS([memset]) AC_CHECK_FUNCS([select]) @@ -182,6 +190,9 @@ AC_HEADER_TIME AC_CHECK_HEADERS([socket.h]) AC_CHECK_HEADERS([inttypes.h], [INSERT_INTTYPES_HEADER="#include "]) AC_CHECK_HEADERS([stdint.h], [INSERT_STDINT_HEADER="#include "]) +AC_CHECK_HEADERS([stdatomic.h]) +AC_CHECK_HEADERS([stdbool.h], [INSERT_STDBOOL_HEADER="#include "], [INSERT_STDBOOL_HEADER="#include "]) +AC_CHECK_HEADERS([stdfix.h]) AC_CHECK_HEADERS([unistd.h]) AC_CHECK_HEADERS([stdlib.h]) AC_CHECK_HEADERS([string.h]) @@ -257,13 +268,6 @@ then esac fi -#AC_DEFINE([SPANDSP_SUPPORT_T42], [1], [Support T.42 JPEG compression]) -SPANDSP_SUPPORT_T42="#undef SPANDSP_SUPPORT_T42" -#AC_DEFINE([SPANDSP_SUPPORT_T43], [1], [Support T.43 JBIG gray and colour compression]) -SPANDSP_SUPPORT_T43="#undef SPANDSP_SUPPORT_T43" -#AC_DEFINE([SPANDSP_SUPPORT_V34], [1], [Support the V.34 FAX modem]) -SPANDSP_SUPPORT_V34="#undef SPANDSP_SUPPORT_V34" - AC_CHECK_LIB([m], [cos]) # Some platforms still seem to lack the basic single precision trig and power related functions. AC_SEARCH_LIBS([sinf], [m], AC_DEFINE([HAVE_SINF], [1], [Define to 1 if you have the sinf() function.])) @@ -320,9 +324,11 @@ AX_CHECK_EXPORT_CAPABILITY([$host], saved_CFLAGS="$CFLAGS" AC_CACHE_CHECK([whether compiler supports -Wunused-but-set-variable], [ac_cv_gcc_unused_but_set_variable], [ -CFLAGS="$CFLAGS -Wunused-but-set-variable" -AC_TRY_COMPILE([],[return 0;],[ac_cv_gcc_unused_but_set_variable=yes],[ac_cv_gcc_unused_but_set_variable=no]) -]) + # We need to add -Werror here or clang doesn't fail (it just warns), even though it doesn't understand the + # -Wunused-but-set-variable tag + CFLAGS="$CFLAGS -Werror -Wunused-but-set-variable" + AC_TRY_COMPILE([],[return 0;],[ac_cv_gcc_unused_but_set_variable=yes],[ac_cv_gcc_unused_but_set_variable=no]) + ]) AC_MSG_RESULT($ac_cv_gcc_unused_but_set_variable) CFLAGS="$saved_CFLAGS" @@ -337,6 +343,9 @@ gnu) if test "$enable_neon" = "yes" ; then COMP_VENDOR_CFLAGS="-mfpu=neon $COMP_VENDOR_CFLAGS" fi + if test "$enable_avx2" = "yes" ; then + COMP_VENDOR_CFLAGS="-mavx2 $COMP_VENDOR_CFLAGS" + fi if test "$enable_avx" = "yes" ; then COMP_VENDOR_CFLAGS="-mavx $COMP_VENDOR_CFLAGS" fi @@ -401,6 +410,9 @@ intel) if test x"$ac_cv_gcc_unused_but_set_variable" = xyes ; then COMP_VENDOR_CFLAGS="-Wunused-but-set-variable $COMP_VENDOR_CFLAGS" fi + if test "$enable_avx2" = "yes" ; then + COMP_VENDOR_CFLAGS="-mavx2 $COMP_VENDOR_CFLAGS" + fi if test "$enable_avx" = "yes" ; then COMP_VENDOR_CFLAGS="-mavx $COMP_VENDOR_CFLAGS" fi @@ -462,6 +474,10 @@ armv7[bl] | armv7-*) fi ;; x86_64-* | i386-* | i686-*) + if test "$enable_avx2" = "yes" ; then + AC_DEFINE([SPANDSP_USE_AVX2], [1], [Use the AVX2 instruction set (i386 and x86_64 only).]) + enable_avx="yes" + fi if test "$enable_avx" = "yes" ; then AC_DEFINE([SPANDSP_USE_AVX], [1], [Use the AVX instruction set (i386 and x86_64 only).]) enable_sse5="yes" @@ -504,20 +520,6 @@ x86_64-* | i386-* | i686-*) ;; esac -AM_CONDITIONAL([COND_DOC], [test "$enable_doc" = yes]) -AM_CONDITIONAL([COND_TESTS], [test "$enable_tests" = yes]) -AM_CONDITIONAL([COND_MMX], [test "$enable_mmx" = yes]) -AM_CONDITIONAL([COND_SSE], [test "$enable_sse" = yes]) -AM_CONDITIONAL([COND_SSE2], [test "$enable_sse2" = yes]) -AM_CONDITIONAL([COND_SSE3], [test "$enable_sse3" = yes]) -AM_CONDITIONAL([COND_SSSE3], [test "$enable_ssse3" = yes]) -AM_CONDITIONAL([COND_SSE4_1], [test "$enable_sse4_1" = yes]) -AM_CONDITIONAL([COND_SSE4_2], [test "$enable_sse4_2" = yes]) -AM_CONDITIONAL([COND_SSE4A], [test "$enable_sse4a" = yes]) -AM_CONDITIONAL([COND_SSE5], [test "$enable_sse5" = yes]) -AM_CONDITIONAL([COND_AVX], [test "$enable_avx" = yes]) -AM_CONDITIONAL([COND_NEON], [test "$enable_neon" = yes]) - if test "$enable_builtin_tiff" = "yes" ; then abs_tiffdir="`cd $srcdir/../tiff-4.0.2/ && pwd`" save_CFLAGS=$CFLAGS @@ -532,9 +534,7 @@ if test "$enable_builtin_tiff" = "yes" ; then AC_DEFINE([HAVE_LIBTIFF], [1], [Define to 1 if you have the `tiff' library (-ltiff).]) else AC_CHECK_HEADERS([tiffio.h]) - AC_CHECK_HEADERS([tif_dir.h], [], [], [#include -]) - AC_CHECK_LIB([tiff], [TIFFOpen], [TIFF_LIBS="-ltiff"], AC_MSG_ERROR("Cannot build without libtiff (does your system require a libtiff-devel package?)"), -lm) + AC_CHECK_LIB([tiff], [TIFFOpen], , AC_MSG_ERROR("Cannot build without libtiff (does your system require a libtiff-devel package?)"), -lm) fi AC_CHECK_LIB([tiff], [TIFFCreateCustomDirectory], [ @@ -553,6 +553,45 @@ LIBS="$LIBS $TIFF_LIBS $JPEG_LIBS" TESTLIBS="$SIMLIBS $TESTLIBS" +if test "$enable_t43" = "yes" ; then + AC_DEFINE([SPANDSP_SUPPORT_T43], [1], [Support T.43 JBIG gray and colour compression]) + SPANDSP_SUPPORT_T43="#define SPANDSP_SUPPORT_T43 1" +else + SPANDSP_SUPPORT_T43="#undef SPANDSP_SUPPORT_T43" +fi + +if test "$enable_v32bis" = "yes" ; then + AC_DEFINE([SPANDSP_SUPPORT_V32BIS], [1], [Support the V.32bis modem]) + SPANDSP_SUPPORT_V32BIS="#define SPANDSP_SUPPORT_V32BIS 1" +else + SPANDSP_SUPPORT_V32BIS="#undef SPANDSP_SUPPORT_V32BIS" +fi + +if test "$enable_v34" = "yes" ; then + AC_DEFINE([SPANDSP_SUPPORT_V34], [1], [Support the V.34 FAX modem]) + SPANDSP_SUPPORT_V34="#define SPANDSP_SUPPORT_V34 1" +else + SPANDSP_SUPPORT_V34="#undef SPANDSP_SUPPORT_V34" +fi + +AM_CONDITIONAL([COND_DOC], [test "$enable_doc" = yes]) +AM_CONDITIONAL([COND_TESTS], [test "$enable_tests" = yes]) +AM_CONDITIONAL([COND_MMX], [test "$enable_mmx" = yes]) +AM_CONDITIONAL([COND_SSE], [test "$enable_sse" = yes]) +AM_CONDITIONAL([COND_SSE2], [test "$enable_sse2" = yes]) +AM_CONDITIONAL([COND_SSE3], [test "$enable_sse3" = yes]) +AM_CONDITIONAL([COND_SSSE3], [test "$enable_ssse3" = yes]) +AM_CONDITIONAL([COND_SSE4_1], [test "$enable_sse4_1" = yes]) +AM_CONDITIONAL([COND_SSE4_2], [test "$enable_sse4_2" = yes]) +AM_CONDITIONAL([COND_SSE4A], [test "$enable_sse4a" = yes]) +AM_CONDITIONAL([COND_SSE5], [test "$enable_sse5" = yes]) +AM_CONDITIONAL([COND_AVX], [test "$enable_avx" = yes]) +AM_CONDITIONAL([COND_AVX2], [test "$enable_avx2" = yes]) +AM_CONDITIONAL([COND_NEON], [test "$enable_neon" = yes]) + +AM_CONDITIONAL([COND_V32BIS], [test yes = xyes]) +AM_CONDITIONAL([COND_V34], [test yes = xyes]) + AC_SUBST(SPANDSP_LT_CURRENT) AC_SUBST(SPANDSP_LT_REVISION) AC_SUBST(SPANDSP_LT_AGE) @@ -565,14 +604,15 @@ AC_SUBST(TESTLIBS) AC_SUBST(SPANDSP_USE_FIXED_POINT) AC_SUBST(SPANDSP_MISALIGNED_ACCESS_FAILS) AC_SUBST(SPANDSP_USE_EXPORT_CAPABILITY) -AC_SUBST(SPANDSP_SUPPORT_T42) AC_SUBST(SPANDSP_SUPPORT_T43) +AC_SUBST(SPANDSP_SUPPORT_V32BIS) AC_SUBST(SPANDSP_SUPPORT_V34) AC_SUBST(SPANDSP_SUPPORT_TIFF_FX) AC_SUBST(INSERT_INTTYPES_HEADER) AC_SUBST(INSERT_STDINT_HEADER) AC_SUBST(INSERT_TGMATH_HEADER) AC_SUBST(INSERT_MATH_HEADER) +AC_SUBST(INSERT_STDBOOL_HEADER) AC_CONFIG_FILES([Makefile doc/Makefile diff --git a/libs/spandsp/m4/ax_check_arm_neon.m4 b/libs/spandsp/m4/ax_check_arm_neon.m4 index 80e0fc0605..1e972686ef 100644 --- a/libs/spandsp/m4/ax_check_arm_neon.m4 +++ b/libs/spandsp/m4/ax_check_arm_neon.m4 @@ -23,19 +23,21 @@ gnu) CFLAGS="${CFLAGS} -mfpu=neon" AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( - [#include - int32x4_t testfunc(int16_t *a, int16_t *b) - { - return vmull_s16(vld1_s16(a), vld1_s16(b)); - } - int main(int argc, char *argv[]) - { + [ + #include + #include + + int32x4_t testfunc(int16_t *a, int16_t *b) + { + return vmull_s16(vld1_s16(a), vld1_s16(b)); + } + ], + [ int32x4_t z; - int16_t x[8]; - int16_t y[8]; + int16_t x[[8]]; + int16_t y[[8]]; z = testfunc(x, y); - }], - [;] + ] )], [AC_MSG_RESULT([yes]) diff --git a/libs/spandsp/spandsp-sim/Makefile.am b/libs/spandsp/spandsp-sim/Makefile.am index d33575a55c..4eb86c4b49 100644 --- a/libs/spandsp/spandsp-sim/Makefile.am +++ b/libs/spandsp/spandsp-sim/Makefile.am @@ -34,7 +34,7 @@ EXTRA_DIST = libspandsp_sim.dsp \ msvc/vc9proj.head \ msvc/vc9proj.foot -INCLUDES = -I$(top_builddir) -I$(top_builddir)/src -DDATADIR="\"$(pkgdatadir)\"" +AM_CPPFLAGS = -I$(top_builddir) -I$(top_builddir)/src -DDATADIR="\"$(pkgdatadir)\"" noinst_PROGRAMS = make_line_models diff --git a/libs/spandsp/spandsp.spec b/libs/spandsp/spandsp.spec index 40ca9ddce3..d248ac71fb 100644 --- a/libs/spandsp/spandsp.spec +++ b/libs/spandsp/spandsp.spec @@ -2,12 +2,12 @@ Summary: A DSP library for telephony. Name: spandsp -Version: 0.0.7 +Version: 1.99.0 Release: 1 License: LGPLv2 and GPLv2 Group: System Environment/Libraries URL: http://www.soft-switch.org/spandsp -Source: http://www.soft-switch.org/downloads/spandsp/spandsp-0.0.7.tar.gz +Source: http://www.soft-switch.org/downloads/spandsp/spandsp-1.99.0.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: libtiff-devel%{?_isa} diff --git a/libs/spandsp/spandsp/fax-tests.xml b/libs/spandsp/spandsp/fax-tests.xml index e770e244b8..23f333a396 100644 --- a/libs/spandsp/spandsp/fax-tests.xml +++ b/libs/spandsp/spandsp/fax-tests.xml @@ -87,6 +87,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/spandsp/spandsp/global-tones.xml b/libs/spandsp/spandsp/global-tones.xml index 466dae5d2f..5b376d1e86 100644 --- a/libs/spandsp/spandsp/global-tones.xml +++ b/libs/spandsp/spandsp/global-tones.xml @@ -5,12 +5,12 @@ - + - + @@ -25,12 +25,12 @@ - + - + @@ -42,12 +42,12 @@ - + - + @@ -82,12 +82,12 @@ - + - + @@ -142,12 +142,12 @@ - + - + @@ -180,12 +180,12 @@ - + - + @@ -230,12 +230,12 @@ - + - + @@ -273,12 +273,12 @@ - + - + @@ -306,14 +306,14 @@ - + - + @@ -377,12 +377,12 @@ - + - + @@ -448,12 +448,12 @@ - + - + @@ -469,14 +469,14 @@ - + - + @@ -533,12 +533,12 @@ - + - + @@ -553,12 +553,12 @@ - + - + @@ -575,12 +575,12 @@ - + - + @@ -601,12 +601,12 @@ - + - + @@ -618,12 +618,12 @@ - + - + @@ -655,14 +655,14 @@ - + - + @@ -689,14 +689,14 @@ - + - + @@ -735,12 +735,12 @@ - + - + @@ -784,12 +784,12 @@ - + - + @@ -841,14 +841,14 @@ - + - + @@ -907,24 +907,24 @@ - + - - + + - - + + - + @@ -995,18 +995,18 @@ - + - - + + - + @@ -1038,12 +1038,12 @@ - + - + @@ -1067,12 +1067,12 @@ - + - + @@ -1096,18 +1096,18 @@ - + - - + + - + @@ -1141,12 +1141,12 @@ - + - + @@ -1173,12 +1173,12 @@ - + - + @@ -1211,14 +1211,14 @@ - + - + @@ -1255,12 +1255,12 @@ - + - + @@ -1310,12 +1310,12 @@ - + - + @@ -1364,12 +1364,12 @@ - + - + @@ -1385,12 +1385,12 @@ - + - + @@ -1409,12 +1409,12 @@ - + - + @@ -1483,24 +1483,24 @@ - + - - + + - - + + - + @@ -1537,20 +1537,20 @@ - + - - + + - + @@ -1604,12 +1604,12 @@ - + - + @@ -1658,12 +1658,12 @@ - + - + @@ -1717,12 +1717,12 @@ - + - + @@ -1733,12 +1733,12 @@ - + - + @@ -1761,12 +1761,12 @@ - + - + @@ -1818,14 +1818,14 @@ - + - + @@ -1860,12 +1860,12 @@ - + - + @@ -1884,12 +1884,12 @@ - + - + @@ -1922,12 +1922,12 @@ - + - + @@ -1939,12 +1939,12 @@ - + - + @@ -1980,12 +1980,12 @@ - + - + @@ -2011,12 +2011,12 @@ - + - + @@ -2050,12 +2050,12 @@ - + - + @@ -2083,22 +2083,22 @@ - + - - + + - + @@ -2146,12 +2146,12 @@ - + - + @@ -2195,12 +2195,12 @@ - + - + @@ -2225,12 +2225,12 @@ - + - + @@ -2260,18 +2260,18 @@ - + - - + + - + @@ -2303,12 +2303,12 @@ - + - + @@ -2323,7 +2323,7 @@ - + @@ -2332,8 +2332,8 @@ - - + + @@ -2342,19 +2342,19 @@ - - + + - - + + - + @@ -2435,12 +2435,12 @@ - + - + @@ -2482,14 +2482,14 @@ - + - + @@ -2531,12 +2531,12 @@ - + - + @@ -2591,12 +2591,12 @@ - + - + @@ -2630,12 +2630,12 @@ - + - + @@ -2652,12 +2652,12 @@ - + - + @@ -2681,12 +2681,12 @@ - + - + @@ -2707,12 +2707,12 @@ - + - + @@ -2727,12 +2727,12 @@ - + - + @@ -2758,14 +2758,14 @@ - + - + @@ -2796,14 +2796,14 @@ - + - + @@ -2839,12 +2839,12 @@ - + - + @@ -2898,12 +2898,12 @@ - + - + @@ -2938,22 +2938,22 @@ - + - - + + - + @@ -2982,12 +2982,12 @@ - + - + @@ -3037,12 +3037,12 @@ - + - + @@ -3096,11 +3096,11 @@ - + - + @@ -3112,14 +3112,14 @@ - + - + @@ -3172,12 +3172,12 @@ - + - + @@ -3249,12 +3249,12 @@ - + - + @@ -3267,12 +3267,12 @@ - + - + @@ -3289,32 +3289,32 @@ - + - - + + - - + + - - + + - + @@ -3381,18 +3381,18 @@ - + - - + + - + @@ -3450,20 +3450,20 @@ - + - - + + - + @@ -3526,7 +3526,7 @@ - + @@ -3537,7 +3537,7 @@ - + @@ -3583,14 +3583,14 @@ - + - + @@ -3628,12 +3628,12 @@ - + - + @@ -3682,18 +3682,18 @@ - + - - + + - + @@ -3742,12 +3742,12 @@ - + - + @@ -3775,12 +3775,12 @@ - + - + @@ -3808,12 +3808,12 @@ - + - + @@ -3825,12 +3825,12 @@ - + - + @@ -3852,12 +3852,12 @@ - + - + @@ -3875,12 +3875,12 @@ - + - + @@ -3924,12 +3924,12 @@ - + - + @@ -3960,12 +3960,12 @@ - + - + @@ -3981,20 +3981,20 @@ - + - - + + - + @@ -4034,14 +4034,14 @@ - + - + @@ -4098,14 +4098,14 @@ - + - + @@ -4139,12 +4139,12 @@ - + - + @@ -4166,14 +4166,14 @@ - + - + @@ -4203,12 +4203,12 @@ - + - + @@ -4232,12 +4232,12 @@ - + - + @@ -4253,12 +4253,12 @@ - + - + @@ -4274,12 +4274,12 @@ - + - + @@ -4303,12 +4303,12 @@ - + - + @@ -4329,12 +4329,12 @@ - + - + @@ -4359,12 +4359,12 @@ - + - + @@ -4419,12 +4419,12 @@ - + - + @@ -4437,12 +4437,12 @@ - + - + @@ -4460,14 +4460,14 @@ - + - + @@ -4517,20 +4517,20 @@ - + - - + + - + @@ -4562,12 +4562,12 @@ - + - + @@ -4595,12 +4595,12 @@ - + - + @@ -4645,12 +4645,12 @@ - + - + @@ -4674,14 +4674,14 @@ - + - + @@ -4752,12 +4752,12 @@ - + - + @@ -4785,12 +4785,12 @@ - + - + @@ -4832,18 +4832,18 @@ - + - - + + - + @@ -4885,14 +4885,14 @@ - + - + @@ -4927,20 +4927,20 @@ - + - - + + - + @@ -4960,12 +4960,12 @@ - + - + @@ -5002,14 +5002,14 @@ - + - + @@ -5074,12 +5074,12 @@ - + - + @@ -5123,18 +5123,18 @@ - + - - + + - + @@ -5167,12 +5167,12 @@ - + - + @@ -5213,18 +5213,18 @@ - + - - + + - + @@ -5281,22 +5281,22 @@ - + - - + + - + @@ -5327,12 +5327,12 @@ - + - + @@ -5356,12 +5356,12 @@ - + - + @@ -5380,12 +5380,12 @@ - + - + @@ -5408,12 +5408,12 @@ - + - + @@ -5438,12 +5438,12 @@ - + - + @@ -5477,12 +5477,12 @@ - + - + @@ -5531,14 +5531,14 @@ - + - + @@ -5576,12 +5576,12 @@ - + - + @@ -5605,12 +5605,12 @@ - + - + @@ -5633,12 +5633,12 @@ - + - + @@ -5650,12 +5650,12 @@ - + - + @@ -5679,12 +5679,12 @@ - + - + @@ -5724,12 +5724,12 @@ - + - + @@ -5745,14 +5745,14 @@ - + - + @@ -5777,12 +5777,12 @@ - + - + @@ -5809,14 +5809,14 @@ - + - + @@ -5874,12 +5874,12 @@ - + - + @@ -5932,12 +5932,12 @@ - + - + @@ -5961,12 +5961,12 @@ - + - + @@ -6005,14 +6005,14 @@ - + - + @@ -6090,12 +6090,12 @@ - + - + @@ -6176,12 +6176,12 @@ - + - + @@ -6214,12 +6214,12 @@ - + - + @@ -6242,14 +6242,14 @@ - + - + @@ -6297,18 +6297,18 @@ - + - - + + - + @@ -6389,12 +6389,12 @@ - + - + @@ -6450,18 +6450,18 @@ - + - - + + - + @@ -6504,12 +6504,12 @@ - + - + @@ -6527,15 +6527,15 @@ - + - - + + - + @@ -6559,12 +6559,12 @@ - + - + @@ -6603,12 +6603,12 @@ - + - + @@ -6619,14 +6619,14 @@ - + - - + + - + @@ -6636,12 +6636,12 @@ - + - + @@ -6672,12 +6672,12 @@ - + - + @@ -6736,12 +6736,12 @@ - + - + @@ -6776,12 +6776,12 @@ - + - + @@ -6829,14 +6829,14 @@ - + - + @@ -6865,14 +6865,14 @@ - + - + @@ -6897,14 +6897,14 @@ - + - + @@ -6957,18 +6957,18 @@ - + - - + + - + @@ -7069,12 +7069,12 @@ - + - + @@ -7126,20 +7126,20 @@ - + - - + + - + @@ -7187,12 +7187,12 @@ - + - + @@ -7216,14 +7216,14 @@ - + - + @@ -7244,18 +7244,18 @@ - + - - + + - + @@ -7280,12 +7280,12 @@ - + - + @@ -7329,14 +7329,14 @@ - + - + diff --git a/libs/spandsp/spandsp/tones.dtd b/libs/spandsp/spandsp/tones.dtd index 023f8d0783..b751d2387d 100644 --- a/libs/spandsp/spandsp/tones.dtd +++ b/libs/spandsp/spandsp/tones.dtd @@ -1,21 +1,64 @@ - - + + - - + + + + + + + + - - - - - - - - - - - - - + + + + - + @@ -2534,7 +2534,7 @@ - + @@ -6123,7 +6123,7 @@ - + diff --git a/libs/spandsp/src/Makefile.am b/libs/spandsp/src/Makefile.am index aad3b91dd7..9f60205f07 100644 --- a/libs/spandsp/src/Makefile.am +++ b/libs/spandsp/src/Makefile.am @@ -22,39 +22,29 @@ AM_LDFLAGS = $(COMP_VENDOR_LDFLAGS) DISTCLEANFILES = $(srcdir)/at_interpreter_dictionary.h \ $(srcdir)/cielab_luts.h \ $(srcdir)/math_fixed_tables.h \ - $(srcdir)/v17_v32bis_rx_fixed_rrc.h \ - $(srcdir)/v17_v32bis_rx_floating_rrc.h \ - $(srcdir)/v17_v32bis_tx_fixed_rrc.h \ - $(srcdir)/v17_v32bis_tx_floating_rrc.h \ - $(srcdir)/v22bis_rx_1200_fixed_rrc.h \ - $(srcdir)/v22bis_rx_2400_fixed_rrc.h \ - $(srcdir)/v22bis_rx_1200_floating_rrc.h \ - $(srcdir)/v22bis_rx_2400_floating_rrc.h \ - $(srcdir)/v22bis_tx_fixed_rrc.h \ - $(srcdir)/v22bis_tx_floating_rrc.h \ - $(srcdir)/v27ter_rx_2400_fixed_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 + $(srcdir)/v17_v32bis_rx_rrc.h \ + $(srcdir)/v17_v32bis_tx_rrc.h \ + $(srcdir)/v22bis_rx_1200_rrc.h \ + $(srcdir)/v22bis_rx_2400_rrc.h \ + $(srcdir)/v22bis_tx_rrc.h \ + $(srcdir)/v27ter_rx_2400_rrc.h \ + $(srcdir)/v27ter_rx_4800_rrc.h \ + $(srcdir)/v27ter_tx_2400_rrc.h \ + $(srcdir)/v27ter_tx_4800_rrc.h \ + $(srcdir)/v29rx_rrc.h \ + $(srcdir)/v29tx_rrc.h CLEANFILES = ${DISTCLEANFILES} MOSTLYCLEANFILES = ${DISTCLEANFILES} MAINTAINERCLEANFILES = ${DISTCLEANFILES} EXTRA_DIST = floating_fudge.h \ - libspandsp.dsp \ libspandsp.2005.sln \ libspandsp.2008.sln \ libspandsp.2005.vcproj \ libspandsp.2008.vcproj \ + libspandsp.2010.vcproj \ + libspandsp.2012.vcproj \ libtiff.2005.vcproj \ libtiff.2008.vcproj \ filter_tools.c \ @@ -62,6 +52,7 @@ EXTRA_DIST = floating_fudge.h \ make_cielab_luts.c \ make_math_fixed_tables.c \ make_modem_filter.c \ + make_t43_gray_code_tables.c \ msvc/config.h \ msvc/Download_TIFF.2005.vcproj \ msvc/Download_TIFF.2008.vcproj \ @@ -87,12 +78,23 @@ EXTRA_DIST = floating_fudge.h \ spandsp/private/README \ spandsp/version.h.in -INCLUDES = -I$(top_builddir) +AM_CPPFLAGS = -I$(top_builddir) lib_LTLIBRARIES = libspandsp.la +if COND_V32BIS +V32BIS_SOURCES = v32bis.c +endif + +if COND_V34 +V34_SOURCES = v34rx.c \ + v34tx.c \ + v34_logging.c +endif + libspandsp_la_SOURCES = ademco_contactid.c \ adsi.c \ + alloc.c \ async.c \ at_interpreter.c \ awgn.c \ @@ -159,6 +161,7 @@ libspandsp_la_SOURCES = ademco_contactid.c \ t4_rx.c \ t4_tx.c \ t42.c \ + t43.c \ t81_t82_arith_coding.c \ t85_decode.c \ t85_encode.c \ @@ -180,12 +183,15 @@ libspandsp_la_SOURCES = ademco_contactid.c \ v42bis.c \ v8.c \ vector_float.c \ - vector_int.c + vector_int.c \ + $(V32BIS_SOURCES) \ + $(V34_SOURCES) libspandsp_la_LDFLAGS = -version-info @SPANDSP_LT_CURRENT@:@SPANDSP_LT_REVISION@:@SPANDSP_LT_AGE@ $(COMP_VENDOR_LDFLAGS) nobase_include_HEADERS = spandsp/ademco_contactid.h \ spandsp/adsi.h \ + spandsp/alloc.h \ spandsp/async.h \ spandsp/arctan2.h \ spandsp/at_interpreter.h \ @@ -230,6 +236,7 @@ nobase_include_HEADERS = spandsp/ademco_contactid.h \ spandsp/queue.h \ spandsp/saturated.h \ spandsp/schedule.h \ + spandsp/stdbool.h \ spandsp/sig_tone.h \ spandsp/silence_gen.h \ spandsp/super_tone_rx.h \ @@ -250,6 +257,7 @@ nobase_include_HEADERS = spandsp/ademco_contactid.h \ spandsp/t4_t6_decode.h \ spandsp/t4_t6_encode.h \ spandsp/t42.h \ + spandsp/t43.h \ spandsp/t81_t82_arith_coding.h \ spandsp/t85.h \ spandsp/telephony.h \ @@ -298,6 +306,9 @@ nobase_include_HEADERS = spandsp/ademco_contactid.h \ spandsp/private/modem_echo.h \ spandsp/private/noise.h \ spandsp/private/oki_adpcm.h \ + spandsp/private/playout.h \ + spandsp/private/plc.h \ + spandsp/private/power_meter.h \ spandsp/private/queue.h \ spandsp/private/schedule.h \ spandsp/private/sig_tone.h \ @@ -317,6 +328,7 @@ nobase_include_HEADERS = spandsp/ademco_contactid.h \ spandsp/private/t4_t6_decode.h \ spandsp/private/t4_t6_encode.h \ spandsp/private/t42.h \ + spandsp/private/t43.h \ spandsp/private/t81_t82_arith_coding.h \ spandsp/private/t85.h \ spandsp/private/time_scale.h \ @@ -363,6 +375,9 @@ make_math_fixed_tables$(EXEEXT): $(top_srcdir)/src/make_math_fixed_tables.c make_modem_filter$(EXEEXT): $(top_srcdir)/src/make_modem_filter.c $(top_srcdir)/src/filter_tools.c $(CC_FOR_BUILD) -o make_modem_filter$(EXEEXT) $(top_srcdir)/src/make_modem_filter.c $(top_srcdir)/src/filter_tools.c -DHAVE_CONFIG_H -I$(top_builddir)/src -lm +make_t43_gray_code_tables$(EXEEXT): $(top_srcdir)/src/make_t43_gray_code_tables.c + $(CC_FOR_BUILD) -o make_t43_gray_code_tables$(EXEEXT) $(top_srcdir)/src/make_t43_gray_code_tables.c -DHAVE_CONFIG_H -I$(top_builddir)/src -lm + # We need to run make_at_dictionary, so it generates the # at_interpreter_dictionary.h file @@ -391,6 +406,11 @@ t42.lo: cielab_luts.h cielab_luts.h: make_cielab_luts$(EXEEXT) ./make_cielab_luts$(EXEEXT) >cielab_luts.h +t43.lo: t43_gray_code_tables.h + +t43_gray_code_tables.h: make_t43_gray_code_tables$(EXEEXT) + ./make_t43_gray_code_tables$(EXEEXT) >t43_gray_code_tables.h + V17_V32BIS_RX_INCL = v17_v32bis_rx_rrc.h v17rx.$(OBJEXT): ${V17_V32BIS_RX_INCL} @@ -475,37 +495,18 @@ v29tx.lo: ${V29_TX_INCL} v29tx_rrc.h: make_modem_filter$(EXEEXT) ./make_modem_filter$(EXEEXT) -m V.29 -t >v29tx_rrc.h -DSP = libspandsp.dsp VCPROJ8 = libspandsp.2005.vcproj VCPROJ9 = libspandsp.2008.vcproj +VCPROJ10 = libspandsp.2010.vcproj +VCPROJ12 = libspandsp.2012.vcproj WIN32SOURCES = $(libspandsp_la_SOURCES) .\\msvc\\gettimeofday.c WIN32HEADERS = $(nobase_include_HEADERS) spandsp.h -DSPOUT = | awk '{printf("%s\r\n", $$0)}' >> $(DSP) VCPROJOUT8 = | awk '{printf("%s\r\n", $$0)}' >> $(VCPROJ8) VCPROJOUT9 = | awk '{printf("%s\r\n", $$0)}' >> $(VCPROJ9) - -$(DSP): msvc/msvcproj.head msvc/msvcproj.foot Makefile.am - echo "creating $(DSP)" - @(cp $(srcdir)/msvc/msvcproj.head $(DSP); \ - echo "# Begin Group \"Source Files\"" $(DSPOUT); \ - for file in $(WIN32SOURCES); do \ - echo "# Begin Source File" $(DSPOUT); \ - echo "" $(DSPOUT); \ - echo "SOURCE=.\\"$$file $(DSPOUT); \ - echo "# End Source File" $(DSPOUT); \ - done; \ - echo "# End Group" $(DSPOUT); \ - echo "# Begin Group \"Header Files\"" $(DSPOUT); \ - for file in $(WIN32HEADERS); do \ - echo "# Begin Source File" $(DSPOUT); \ - echo "" $(DSPOUT); \ - echo "SOURCE=.\\"$$file $(DSPOUT); \ - echo "# End Source File" $(DSPOUT); \ - done; \ - echo "# End Group" $(DSPOUT); \ - cat $(srcdir)/msvc/msvcproj.foot $(DSPOUT) ) +VCPROJOUT10 = | awk '{printf("%s\r\n", $$0)}' >> $(VCPROJ10) +VCPROJOUT12 = | awk '{printf("%s\r\n", $$0)}' >> $(VCPROJ12) $(VCPROJ8): msvc/vc8proj.head msvc/vc8proj.foot Makefile.am echo "creating $(VCPROJ8)" @@ -531,6 +532,30 @@ $(VCPROJ9): msvc/vc9proj.head msvc/vc9proj.foot Makefile.am done; \ cat $(srcdir)/msvc/vc9proj.foot $(VCPROJOUT9) ) +$(VCPROJ10): msvc/vc10proj.head msvc/vc10proj.foot Makefile.am + echo "creating $(VCPROJ10)" + @(cp $(srcdir)/msvc/vc10proj.head $(VCPROJ10); \ + for file in $(WIN32SOURCES); do \ + echo "" $(VCPROJOUT10); \ + done; \ + echo "" $(VCPROJOUT10); \ + for file in $(WIN32HEADERS); do \ + echo "" $(VCPROJOUT10); \ + done; \ + cat $(srcdir)/msvc/vc10proj.foot $(VCPROJOUT10) ) + +$(VCPROJ12): msvc/vc12proj.head msvc/vc12proj.foot Makefile.am + echo "creating $(VCPROJ12)" + @(cp $(srcdir)/msvc/vc12proj.head $(VCPROJ12); \ + for file in $(WIN32SOURCES); do \ + echo "" $(VCPROJOUT12); \ + done; \ + echo "" $(VCPROJOUT12); \ + for file in $(WIN32HEADERS); do \ + echo "" $(VCPROJOUT12); \ + done; \ + cat $(srcdir)/msvc/vc12proj.foot $(VCPROJOUT12) ) + $(srcdir)/msvc/spandsp.h: spandsp.h.in echo "creating $(srcdir)/msvc/spandsp.h" @sed -e "s/#define _SPANDSP_H_/#define _SPANDSP_H_\n\n#define __inline__ __inline\n#pragma warning(disable:4200)/" \ diff --git a/libs/spandsp/src/ademco_contactid.c b/libs/spandsp/src/ademco_contactid.c index 6862567184..453ccc0394 100644 --- a/libs/spandsp/src/ademco_contactid.c +++ b/libs/spandsp/src/ademco_contactid.c @@ -39,6 +39,11 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include #include @@ -46,6 +51,7 @@ #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/fast_convert.h" #include "spandsp/logging.h" #include "spandsp/queue.h" @@ -437,18 +443,17 @@ static const struct ademco_code_s ademco_codes[] = {-1, "???"} }; +#define GOERTZEL_SAMPLES_PER_BLOCK 55 /* We need to detect over a +-5% range */ + #if defined(SPANDSP_USE_FIXED_POINT) -#define GOERTZEL_SAMPLES_PER_BLOCK 55 /* We need to detect over a +-5% range */ -#define DETECTION_THRESHOLD 16439 /* -42dBm0 [((GOERTZEL_SAMPLES_PER_BLOCK*GOERTZEL_SAMPLES_PER_BLOCK*32768.0/(1.4142*128.0))*10^((-42 - DBM0_MAX_SINE_POWER)/20.0))^2] */ -#define TONE_TWIST 4 /* 6dB */ -#define TONE_TO_TOTAL_ENERGY 64 /* -3dB */ +#define DETECTION_THRESHOLD 3035 /* -42dBm0 */ +#define TONE_TO_TOTAL_ENERGY 45.2233f /* -0.85dB */ #else -#define GOERTZEL_SAMPLES_PER_BLOCK 55 /* We need to detect over a +-5% range */ -#define DETECTION_THRESHOLD 2104205.6f /* -42dBm0 [((GOERTZEL_SAMPLES_PER_BLOCK*GOERTZEL_SAMPLES_PER_BLOCK*32768.0/1.4142)*10^((-42 - DBM0_MAX_SINE_POWER)/20.0))^2] */ -#define TONE_TWIST 3.981f /* 6dB */ -#define TONE_TO_TOTAL_ENERGY 1.995f /* 3dB */ +#define DETECTION_THRESHOLD 49728296.6f /* -42dBm0 [((GOERTZEL_SAMPLES_PER_BLOCK*32768.0/1.4142)*10^((-42 - DBM0_MAX_SINE_POWER)/20.0))^2] */ +#define TONE_TO_TOTAL_ENERGY 45.2233f /* -0.85dB [GOERTZEL_SAMPLES_PER_BLOCK*10^(-0.85/10.0)] */ #endif +static int tone_rx_init = false; static goertzel_descriptor_t tone_1400_desc; static goertzel_descriptor_t tone_2300_desc; @@ -750,7 +755,7 @@ SPAN_DECLARE(ademco_contactid_receiver_state_t *) ademco_contactid_receiver_init { if (s == NULL) { - if ((s = (ademco_contactid_receiver_state_t *) malloc(sizeof (*s))) == NULL) + if ((s = (ademco_contactid_receiver_state_t *) span_alloc(sizeof (*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -777,7 +782,7 @@ SPAN_DECLARE(int) ademco_contactid_receiver_release(ademco_contactid_receiver_st SPAN_DECLARE(int) ademco_contactid_receiver_free(ademco_contactid_receiver_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ @@ -794,7 +799,7 @@ SPAN_DECLARE(int) ademco_contactid_sender_tx(ademco_contactid_sender_state_t *s, case 0: if (!s->clear_to_send) return 0; - s->clear_to_send = FALSE; + s->clear_to_send = false; s->step++; s->remaining_samples = ms_to_samples(250); /* Fall through */ @@ -811,7 +816,7 @@ SPAN_DECLARE(int) ademco_contactid_sender_tx(ademco_contactid_sender_state_t *s, samples = dtmf_tx(&s->dtmf, &[sample], max_samples - sample); if (samples == 0) { - s->clear_to_send = FALSE; + s->clear_to_send = false; s->step = 0; return sample; } @@ -948,7 +953,7 @@ SPAN_DECLARE(int) ademco_contactid_sender_rx(ademco_contactid_sender_state_t *s, s->callback(s->callback_user_data, -1, 0, 0); s->tone_state = 4; /* Release the transmit side, and it will time the 250ms post tone delay */ - s->clear_to_send = TRUE; + s->clear_to_send = true; s->tries = 0; if (s->tx_digits_len) s->timer = ms_to_samples(3000); @@ -969,7 +974,7 @@ SPAN_DECLARE(int) ademco_contactid_sender_rx(ademco_contactid_sender_state_t *s, case 5: if (hit == 0) { - s->busy = FALSE; + s->busy = false; if (s->duration < ms_to_samples(400) || s->duration > ms_to_samples(1500)) { span_log(&s->logging, SPAN_LOG_FLOW, "Bad kissoff duration %d\n", s->duration); @@ -983,18 +988,18 @@ SPAN_DECLARE(int) ademco_contactid_sender_rx(ademco_contactid_sender_state_t *s, { s->timer = 0; if (s->callback) - s->callback(s->callback_user_data, FALSE, 0, 0); + s->callback(s->callback_user_data, false, 0, 0); } } else { span_log(&s->logging, SPAN_LOG_FLOW, "Received good kissoff\n"); - s->clear_to_send = TRUE; + s->clear_to_send = true; s->tx_digits_len = 0; if (s->callback) - s->callback(s->callback_user_data, TRUE, 0, 0); + s->callback(s->callback_user_data, true, 0, 0); s->tone_state = 4; - s->clear_to_send = TRUE; + s->clear_to_send = true; s->tries = 0; if (s->tx_digits_len) s->timer = ms_to_samples(3000); @@ -1024,7 +1029,7 @@ SPAN_DECLARE(int) ademco_contactid_sender_rx(ademco_contactid_sender_state_t *s, { s->timer = 0; if (s->callback) - s->callback(s->callback_user_data, FALSE, 0, 0); + s->callback(s->callback_user_data, false, 0, 0); } } } @@ -1059,7 +1064,7 @@ SPAN_DECLARE(int) ademco_contactid_sender_put(ademco_contactid_sender_state_t *s return -1; if ((s->tx_digits_len = encode_msg(s->tx_digits, report)) < 0) return -1; - s->busy = TRUE; + s->busy = true; return dtmf_tx_put(&s->dtmf, s->tx_digits, s->tx_digits_len); } /*- End of function --------------------------------------------------------*/ @@ -1083,21 +1088,20 @@ SPAN_DECLARE(ademco_contactid_sender_state_t *) ademco_contactid_sender_init(ade tone_report_func_t callback, void *user_data) { - static int initialised = FALSE; - if (s == NULL) { - if ((s = (ademco_contactid_sender_state_t *) malloc(sizeof (*s))) == NULL) + if ((s = (ademco_contactid_sender_state_t *) span_alloc(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, "Ademco"); - if (!initialised) + if (!tone_rx_init) { make_goertzel_descriptor(&tone_1400_desc, 1400.0f, GOERTZEL_SAMPLES_PER_BLOCK); make_goertzel_descriptor(&tone_2300_desc, 2300.0f, GOERTZEL_SAMPLES_PER_BLOCK); + tone_rx_init = true; } goertzel_init(&s->tone_1400, &tone_1400_desc); goertzel_init(&s->tone_2300, &tone_2300_desc); @@ -1123,7 +1127,7 @@ SPAN_DECLARE(int) ademco_contactid_sender_release(ademco_contactid_sender_state_ SPAN_DECLARE(int) ademco_contactid_sender_free(ademco_contactid_sender_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/adsi.c b/libs/spandsp/src/adsi.c index 44add41be0..1f711bf44f 100644 --- a/libs/spandsp/src/adsi.c +++ b/libs/spandsp/src/adsi.c @@ -40,10 +40,16 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/fast_convert.h" #include "spandsp/logging.h" #include "spandsp/queue.h" @@ -63,6 +69,7 @@ #include "spandsp/private/queue.h" #include "spandsp/private/tone_generate.h" #include "spandsp/private/async.h" +#include "spandsp/private/power_meter.h" #include "spandsp/private/fsk.h" #include "spandsp/private/dtmf.h" #include "spandsp/private/adsi.h" @@ -150,7 +157,7 @@ static int adsi_tx_get_bit(void *user_data) if (s->tx_signal_on) { /* The FSK should now be switched off. */ - s->tx_signal_on = FALSE; + s->tx_signal_on = false; s->msg_len = 0; } } @@ -169,7 +176,7 @@ static int adsi_tdd_get_async_byte(void *user_data) if (s->tx_signal_on) { /* The FSK should now be switched off. */ - s->tx_signal_on = FALSE; + s->tx_signal_on = false; s->msg_len = 0; } return 0x1F; @@ -384,13 +391,13 @@ static void start_tx(adsi_tx_state_t *s) dtmf_tx_init(&s->dtmftx, NULL, NULL); break; case ADSI_STANDARD_TDD: - fsk_tx_init(&s->fsktx, &preset_fsk_specs[FSK_WEITBRECHT], async_tx_get_bit, &s->asynctx); - async_tx_init(&s->asynctx, 5, ASYNC_PARITY_NONE, 2, FALSE, adsi_tdd_get_async_byte, s); + fsk_tx_init(&s->fsktx, &preset_fsk_specs[FSK_WEITBRECHT_4545], async_tx_get_bit, &s->asynctx); + async_tx_init(&s->asynctx, 5, ASYNC_PARITY_NONE, 2, false, adsi_tdd_get_async_byte, s); /* Schedule an explicit shift at the start of baudot transmission */ s->baudot_shift = 2; break; } - s->tx_signal_on = TRUE; + s->tx_signal_on = true; } /*- End of function --------------------------------------------------------*/ @@ -426,7 +433,7 @@ SPAN_DECLARE(adsi_rx_state_t *) adsi_rx_init(adsi_rx_state_t *s, { if (s == NULL) { - if ((s = (adsi_rx_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (adsi_rx_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -448,7 +455,7 @@ SPAN_DECLARE(adsi_rx_state_t *) adsi_rx_init(adsi_rx_state_t *s, case ADSI_STANDARD_TDD: /* TDD uses 5 bit data, no parity and 1.5 stop bits. We scan for the first stop bit, and ride over the fraction. */ - fsk_rx_init(&s->fskrx, &preset_fsk_specs[FSK_WEITBRECHT], FSK_FRAME_MODE_5N1_FRAMES, adsi_tdd_put_async_byte, s); + fsk_rx_init(&s->fskrx, &preset_fsk_specs[FSK_WEITBRECHT_4545], FSK_FRAME_MODE_5N1_FRAMES, adsi_tdd_put_async_byte, s); break; } s->standard = standard; @@ -465,7 +472,7 @@ SPAN_DECLARE(int) adsi_rx_release(adsi_rx_state_t *s) SPAN_DECLARE(int) adsi_rx_free(adsi_rx_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ @@ -488,7 +495,7 @@ SPAN_DECLARE(int) adsi_tx(adsi_tx_state_t *s, int16_t amp[], int max_len) if (len < max_len) { if ((lenx = fsk_tx(&s->fsktx, amp + len, max_len - len)) <= 0) - s->tx_signal_on = FALSE; + s->tx_signal_on = false; len += lenx; } break; @@ -658,7 +665,7 @@ SPAN_DECLARE(adsi_tx_state_t *) adsi_tx_init(adsi_tx_state_t *s, int standard) { if (s == NULL) { - if ((s = (adsi_tx_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (adsi_tx_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -671,7 +678,7 @@ SPAN_DECLARE(adsi_tx_state_t *) adsi_tx_init(adsi_tx_state_t *s, int standard) 60, 0, 0, - FALSE); + false); s->standard = standard; adsi_tx_set_preamble(s, -1, -1, -1, -1); span_log_init(&s->logging, SPAN_LOG_NONE, NULL); @@ -688,7 +695,7 @@ SPAN_DECLARE(int) adsi_tx_release(adsi_tx_state_t *s) SPAN_DECLARE(int) adsi_tx_free(adsi_tx_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/alloc.c b/libs/spandsp/src/alloc.c new file mode 100644 index 0000000000..b79aa166e7 --- /dev/null +++ b/libs/spandsp/src/alloc.c @@ -0,0 +1,171 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * alloc.c - memory allocation handling. + * + * Written by Steve Underwood + * + * Copyright (C) 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 +#include +#include +#include +#if !defined(__USE_ISOC11) +#define __USE_ISOC11 +#endif +#include +#if defined(HAVE_MALLOC_H) +#include +#endif +#include +#include +#include +#include +#include +#include + +#include "spandsp/telephony.h" +#include "spandsp/alloc.h" + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4232) /* address of dllimport is not static, identity not guaranteed */ +#endif + +#if defined(HAVE_ALIGNED_ALLOC) +static span_aligned_alloc_t __span_aligned_alloc = aligned_alloc; +static span_aligned_free_t __span_aligned_free = free; +#elif defined(HAVE_MEMALIGN) +static span_aligned_alloc_t __span_aligned_alloc = memalign; +static span_aligned_free_t __span_aligned_free = free; +#elif defined(__MSVC__) +static void *fake_aligned_alloc(size_t alignment, size_t size); +static span_aligned_alloc_t __span_aligned_alloc = fake_aligned_alloc; +static span_aligned_free_t __span_aligned_free = _aligned_free; +#else +static void *fake_aligned_alloc(size_t alignment, size_t size); +static span_aligned_alloc_t __span_aligned_alloc = fake_aligned_alloc; +static span_aligned_free_t __span_aligned_free = free; +#endif +static span_alloc_t __span_alloc = malloc; +static span_realloc_t __span_realloc = realloc; +static span_free_t __span_free = free; + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#if defined(HAVE_ALIGNED_ALLOC) +#elif defined(HAVE_MEMALIGN) +#elif defined(__MSVC__) +static void *fake_aligned_alloc(size_t alignment, size_t size) +{ + /* Make Microsoft's _aligned_malloc() look like the C11 aligned_alloc */ + return _aligned_malloc(size, alignment); +} +/*- End of function --------------------------------------------------------*/ +#elif defined(HAVE_POSIX_MEMALIGN) +static void *fake_aligned_alloc(size_t alignment, size_t size) +{ + void *ptr; + + /* Make posix_memalign() look like the C11 aligned_alloc */ + posix_memalign(&ptr, alignment, size); + return ptr; +} +/*- End of function --------------------------------------------------------*/ +#else +static void *fake_aligned_alloc(size_t alignment, size_t size) +{ + return malloc(size); +} +/*- End of function --------------------------------------------------------*/ +#endif + +SPAN_DECLARE(void *) span_alloc(size_t size) +{ + return __span_alloc(size); +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(void *) span_realloc(void *ptr, size_t size) +{ + return __span_realloc(ptr, size); +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(void) span_free(void *ptr) +{ + __span_free(ptr); +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(void *) span_aligned_alloc(size_t alignment, size_t size) +{ + return __span_aligned_alloc(alignment, size); +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(void) span_aligned_free(void *ptr) +{ + __span_aligned_free(ptr); +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) span_mem_allocators(span_alloc_t custom_alloc, + span_realloc_t custom_realloc, + span_free_t custom_free, + span_aligned_alloc_t custom_aligned_alloc, + span_aligned_free_t custom_aligned_free) +{ + __span_alloc = (custom_alloc) ? custom_alloc : malloc; + __span_realloc = (custom_realloc) ? custom_realloc : realloc; + __span_free = (custom_free) ? custom_free : free; + + __span_aligned_alloc = (custom_aligned_alloc) + ? + custom_aligned_alloc + : +#if defined(HAVE_ALIGNED_ALLOC) + aligned_alloc; +#elif defined(HAVE_MEMALIGN) + memalign; +#else + fake_aligned_alloc; +#endif + __span_aligned_free = (custom_aligned_free) + ? + custom_aligned_free + : +#if defined(__MSVC__) + _aligned_free; +#else + free; +#endif + return 0; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/async.c b/libs/spandsp/src/async.c index fb381bb7bc..d1bf5bda5b 100644 --- a/libs/spandsp/src/async.c +++ b/libs/spandsp/src/async.c @@ -33,8 +33,14 @@ #include #include #include +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/bit_operations.h" #include "spandsp/async.h" @@ -168,13 +174,13 @@ SPAN_DECLARE(async_rx_state_t *) async_rx_init(async_rx_state_t *s, int data_bits, int parity, int stop_bits, - int use_v14, + bool use_v14, put_byte_func_t put_byte, void *user_data) { if (s == NULL) { - if ((s = (async_rx_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (async_rx_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } s->data_bits = data_bits; @@ -203,7 +209,7 @@ SPAN_DECLARE(int) async_rx_release(async_rx_state_t *s) SPAN_DECLARE(int) async_rx_free(async_rx_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ @@ -268,13 +274,13 @@ SPAN_DECLARE(async_tx_state_t *) async_tx_init(async_tx_state_t *s, int data_bits, int parity, int stop_bits, - int use_v14, + bool use_v14, get_byte_func_t get_byte, void *user_data) { if (s == NULL) { - if ((s = (async_tx_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (async_tx_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } /* We have a use_v14 parameter for completeness, but right now V.14 only @@ -304,7 +310,7 @@ SPAN_DECLARE(int) async_tx_release(async_tx_state_t *s) SPAN_DECLARE(int) async_tx_free(async_tx_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/at_interpreter.c b/libs/spandsp/src/at_interpreter.c index 1878ab2ed6..d43ffb3671 100644 --- a/libs/spandsp/src/at_interpreter.c +++ b/libs/spandsp/src/at_interpreter.c @@ -43,9 +43,15 @@ #include #include #include +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/queue.h" #include "spandsp/power_meter.h" @@ -77,20 +83,20 @@ static at_profile_t profiles[3] = { { #if defined(_MSC_VER) || defined(__sunos) || defined(__solaris) || defined(__sun) - /*.echo =*/ TRUE, - /*.verbose =*/ TRUE, + /*.echo =*/ true, + /*.verbose =*/ true, /*.result_code_format =*/ ASCII_RESULT_CODES, - /*.pulse_dial =*/ FALSE, - /*.double_escape =*/ FALSE, - /*.adaptive_receive =*/ FALSE, + /*.pulse_dial =*/ false, + /*.double_escape =*/ false, + /*.adaptive_receive =*/ false, /*.s_regs[100] =*/ {0, 0, 0, '\r', '\n', '\b', 1, 60, 5, 0, 0} #else - .echo = TRUE, - .verbose = TRUE, + .echo = true, + .verbose = true, .result_code_format = ASCII_RESULT_CODES, - .pulse_dial = FALSE, - .double_escape = FALSE, - .adaptive_receive = FALSE, + .pulse_dial = false, + .double_escape = false, + .adaptive_receive = false, .s_regs[0] = 0, .s_regs[3] = '\r', .s_regs[4] = '\n', @@ -255,11 +261,11 @@ SPAN_DECLARE(void) at_put_response_code(at_state_t *s, int code) static int answer_call(at_state_t *s) { if (at_modem_control(s, AT_MODEM_CONTROL_ANSWER, NULL) < 0) - return FALSE; + return false; /* Answering should now be in progress. No AT response should be issued at this point. */ - s->do_hangup = FALSE; - return TRUE; + s->do_hangup = false; + return true; } /*- End of function --------------------------------------------------------*/ @@ -318,7 +324,7 @@ SPAN_DECLARE(void) at_call_event(at_state_t *s, int event) at_modem_control(s, AT_MODEM_CONTROL_RESTART, (void *) FAX_MODEM_NOCNG_TONE_TX); else at_modem_control(s, AT_MODEM_CONTROL_RESTART, (void *) FAX_MODEM_CNG_TONE_TX); - s->dte_is_waiting = TRUE; + s->dte_is_waiting = true; } } break; @@ -342,13 +348,13 @@ SPAN_DECLARE(void) at_call_event(at_state_t *s, int event) if (s->ok_is_pending) { at_put_response_code(s, AT_RESPONSE_CODE_OK); - s->ok_is_pending = FALSE; + s->ok_is_pending = false; } else { at_put_response_code(s, AT_RESPONSE_CODE_NO_CARRIER); } - s->dte_is_waiting = FALSE; + s->dte_is_waiting = false; at_set_at_rx_mode(s, AT_MODE_ONHOOK_COMMAND); } else if (s->fclass_mode && s->rx_signal_present) @@ -360,7 +366,7 @@ SPAN_DECLARE(void) at_call_event(at_state_t *s, int event) } if (s->at_rx_mode != AT_MODE_OFFHOOK_COMMAND && s->at_rx_mode != AT_MODE_ONHOOK_COMMAND) at_put_response_code(s, AT_RESPONSE_CODE_NO_CARRIER); - s->rx_signal_present = FALSE; + s->rx_signal_present = false; at_modem_control(s, AT_MODEM_CONTROL_RNG, (void *) 0); at_set_at_rx_mode(s, AT_MODE_ONHOOK_COMMAND); break; @@ -379,11 +385,11 @@ SPAN_DECLARE(void) at_reset_call_info(at_state_t *s) for (call_id = s->call_id; call_id; call_id = next) { next = call_id->next; - free(call_id); + span_free(call_id); } s->call_id = NULL; s->rings_indicated = 0; - s->call_info_displayed = FALSE; + s->call_info_displayed = false; } /*- End of function --------------------------------------------------------*/ @@ -392,8 +398,8 @@ SPAN_DECLARE(void) at_set_call_info(at_state_t *s, char const *id, char const *v at_call_id_t *new_call_id; at_call_id_t *call_id; - /* TODO: We should really not merely ignore a failure to malloc */ - if ((new_call_id = (at_call_id_t *) malloc(sizeof(*new_call_id))) == NULL) + /* TODO: We should really not merely ignore a failure to allocate */ + if ((new_call_id = (at_call_id_t *) span_alloc(sizeof(*new_call_id))) == NULL) return; call_id = s->call_id; /* If these strdups fail its pretty harmless. We just appear to not @@ -430,7 +436,7 @@ SPAN_DECLARE(void) at_display_call_info(at_state_t *s) at_put_response(s, buf); call_id = call_id->next; } - s->call_info_displayed = TRUE; + s->call_info_displayed = true; } /*- End of function --------------------------------------------------------*/ @@ -525,7 +531,7 @@ static int parse_out(at_state_t *s, const char **t, int *target, int max_value, default: /* Set value */ if ((val = parse_num(t, max_value)) < 0) - return FALSE; + return false; if (target) *target = val; break; @@ -538,9 +544,9 @@ static int parse_out(at_state_t *s, const char **t, int *target, int max_value, at_put_response(s, buf); break; default: - return FALSE; + return false; } - return TRUE; + return true; } /*- End of function --------------------------------------------------------*/ @@ -564,14 +570,14 @@ static int parse_2_out(at_state_t *s, const char **t, int *target1, int max_valu default: /* Set value */ if ((val1 = parse_num(t, max_value1)) < 0) - return FALSE; + return false; if (target1) *target1 = val1; if (**t == ',') { (*t)++; if ((val2 = parse_num(t, max_value2)) < 0) - return FALSE; + return false; if (target2) *target2 = val2; } @@ -586,9 +592,9 @@ static int parse_2_out(at_state_t *s, const char **t, int *target1, int max_valu at_put_response(s, buf); break; default: - return FALSE; + return false; } - return TRUE; + return true; } /*- End of function --------------------------------------------------------*/ @@ -621,7 +627,7 @@ static int parse_n_out(at_state_t *s, for (i = 0; i < entries; i++) { if ((val = parse_num(t, max_values[i])) < 0) - return FALSE; + return false; if (targets[i]) *targets[i] = val; if (**t != ',') @@ -644,9 +650,9 @@ static int parse_n_out(at_state_t *s, at_put_response(s, buf); break; default: - return FALSE; + return false; } - return TRUE; + return true; } /*- End of function --------------------------------------------------------*/ @@ -669,7 +675,7 @@ static int parse_hex_out(at_state_t *s, const char **t, int *target, int max_val default: /* Set value */ if ((val = parse_hex_num(t, max_value)) < 0) - return FALSE; + return false; if (target) *target = val; break; @@ -682,9 +688,9 @@ static int parse_hex_out(at_state_t *s, const char **t, int *target, int max_val at_put_response(s, buf); break; default: - return FALSE; + return false; } - return TRUE; + return true; } /*- End of function --------------------------------------------------------*/ @@ -709,7 +715,7 @@ static int parse_string_list_out(at_state_t *s, const char **t, int *target, int default: /* Set value */ if ((val = match_element(t, def)) < 0) - return FALSE; + return false; if (target) *target = val; break; @@ -728,9 +734,9 @@ static int parse_string_list_out(at_state_t *s, const char **t, int *target, int at_put_response(s, buf); break; default: - return FALSE; + return false; } - return TRUE; + return true; } /*- End of function --------------------------------------------------------*/ @@ -752,7 +758,7 @@ static int parse_string_out(at_state_t *s, const char **t, char **target, const default: /* Set value */ if (*target) - free(*target); + span_free(*target); /* If this strdup fails, it should be harmless */ *target = strdup(*t); break; @@ -763,11 +769,11 @@ static int parse_string_out(at_state_t *s, const char **t, char **target, const at_put_response(s, (*target) ? *target : ""); break; default: - return FALSE; + return false; } while (*t) t++; - return TRUE; + return true; } /*- End of function --------------------------------------------------------*/ @@ -862,18 +868,18 @@ static int process_class1_cmd(at_state_t *s, const char **t) val = -1; if (!parse_out(s, t, &val, 255, NULL, allowed)) - return TRUE; + return true; if (val < 0) { /* It was just a query */ - return TRUE; + return true; } /* All class 1 FAX commands are supposed to give an ERROR response, if the phone is on-hook. */ if (s->at_rx_mode == AT_MODE_ONHOOK_COMMAND) - return FALSE; + return false; - result = TRUE; + result = true; if (s->class1_handler) result = s->class1_handler(s, s->class1_user_data, direction, operation, val); switch (result) @@ -881,11 +887,11 @@ static int process_class1_cmd(at_state_t *s, const char **t) case 0: /* Inhibit an immediate response. (These commands should not be part of a multi-command entry.) */ *t = (const char *) -1; - return TRUE; + return true; case -1: - return FALSE; + return false; } - return TRUE; + return true; } /*- End of function --------------------------------------------------------*/ @@ -915,11 +921,11 @@ static const char *at_cmd_D(at_state_t *s, const char *t) /* V.250 6.3.1 - Dial (abortable) */ at_reset_call_info(s); - s->do_hangup = FALSE; - s->silent_dial = FALSE; - s->command_dial = FALSE; + s->do_hangup = false; + s->silent_dial = false; + s->command_dial = false; t += 1; - ok = FALSE; + ok = false; /* There are a numbers of options in a dial command string. Many are completely irrelevant in this application. */ u = num; @@ -961,11 +967,11 @@ static const char *at_cmd_D(at_state_t *s, const char *t) break; case 'T': /* V.250 6.3.1.3 Tone dial */ - s->p.pulse_dial = FALSE; + s->p.pulse_dial = false; break; case 'P': /* V.250 6.3.1.4 Pulse dial */ - s->p.pulse_dial = TRUE; + s->p.pulse_dial = true; break; case '!': /* V.250 6.3.1.5 Hook flash, register recall */ @@ -977,7 +983,7 @@ static const char *at_cmd_D(at_state_t *s, const char *t) break; case '@': /* V.250 6.3.1.7 Wait for quiet answer */ - s->silent_dial = TRUE; + s->silent_dial = true; break; case 'S': /* V.250 6.3.1.8 Invoke stored string */ @@ -998,7 +1004,7 @@ static const char *at_cmd_D(at_state_t *s, const char *t) break; case ';': /* V.250 6.3.1 - Dial string terminator - make voice call and remain in command mode */ - s->command_dial = TRUE; + s->command_dial = true; break; case '>': /* GSM07.07 6.2 - Direct dialling from phone book supplementary service subscription @@ -1054,7 +1060,7 @@ static const char *at_cmd_H(at_state_t *s, const char *t) { /* Push out the last of the audio (probably by sending a short silence). */ at_modem_control(s, AT_MODEM_CONTROL_RESTART, (void *) FAX_MODEM_FLUSH); - s->do_hangup = TRUE; + s->do_hangup = true; at_set_at_rx_mode(s, AT_MODE_CONNECTED); return (const char *) -1; } @@ -1137,7 +1143,7 @@ static const char *at_cmd_P(at_state_t *s, const char *t) { /* V.250 6.3.3 - Select pulse dialling (command) */ t += 1; - s->p.pulse_dial = TRUE; + s->p.pulse_dial = true; return t; } /*- End of function --------------------------------------------------------*/ @@ -1231,7 +1237,7 @@ static const char *at_cmd_T(at_state_t *s, const char *t) { /* V.250 6.3.2 - Select tone dialling (command) */ t += 1; - s->p.pulse_dial = FALSE; + s->p.pulse_dial = false; return t; } /*- End of function --------------------------------------------------------*/ @@ -5527,6 +5533,9 @@ SPAN_DECLARE(void) at_interpreter(at_state_t *s, const char *cmd, int len) { if ((entry = command_search(t, &matched)) <= 0) break; + /* The following test shouldn't be needed, but let's keep it here for completeness. */ + if (entry > sizeof(at_commands)/sizeof(at_commands[0])) + break; if ((t = at_commands[entry - 1](s, t)) == NULL) break; if (t == (const char *) -1) @@ -5587,7 +5596,7 @@ SPAN_DECLARE(at_state_t *) at_init(at_state_t *s, { if (s == NULL) { - if ((s = (at_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (at_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, '\0', sizeof(*s)); @@ -5612,7 +5621,7 @@ SPAN_DECLARE(int) at_release(at_state_t *s) { at_reset_call_info(s); if (s->local_id) - free(s->local_id); + span_free(s->local_id); return 0; } /*- End of function --------------------------------------------------------*/ @@ -5622,7 +5631,7 @@ SPAN_DECLARE(int) at_free(at_state_t *s) int ret; ret = at_release(s); - free(s); + span_free(s); return ret; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/awgn.c b/libs/spandsp/src/awgn.c index 582959cc93..fa33b1b4c5 100644 --- a/libs/spandsp/src/awgn.c +++ b/libs/spandsp/src/awgn.c @@ -55,6 +55,7 @@ #include "floating_fudge.h" #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/fast_convert.h" #include "spandsp/saturated.h" #include "spandsp/awgn.h" @@ -100,7 +101,7 @@ SPAN_DECLARE(awgn_state_t *) awgn_init_dbov(awgn_state_t *s, int idum, float lev if (s == NULL) { - if ((s = (awgn_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (awgn_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } if (idum < 0) @@ -140,7 +141,7 @@ SPAN_DECLARE(int) awgn_release(awgn_state_t *s) SPAN_DECLARE(int) awgn_free(awgn_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/bell_r2_mf.c b/libs/spandsp/src/bell_r2_mf.c index dba407cddd..8f74b7a86a 100644 --- a/libs/spandsp/src/bell_r2_mf.c +++ b/libs/spandsp/src/bell_r2_mf.c @@ -40,9 +40,15 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/fast_convert.h" #include "spandsp/queue.h" @@ -77,10 +83,10 @@ typedef struct uint8_t off_time; /* Minimum post tone silence (ms) */ } mf_digit_tones_t; -int bell_mf_gen_inited = FALSE; +int bell_mf_gen_inited = false; tone_gen_descriptor_t bell_mf_digit_tones[15]; -int r2_mf_gen_inited = FALSE; +int r2_mf_gen_inited = false; tone_gen_descriptor_t r2_mf_fwd_digit_tones[15]; tone_gen_descriptor_t r2_mf_back_digit_tones[15]; @@ -270,10 +276,10 @@ static void bell_mf_gen_init(void) tones->off_time, 0, 0, - FALSE); + false); tones++; } - bell_mf_gen_inited = TRUE; + bell_mf_gen_inited = true; } /*- End of function --------------------------------------------------------*/ @@ -325,7 +331,7 @@ SPAN_DECLARE(bell_mf_tx_state_t *) bell_mf_tx_init(bell_mf_tx_state_t *s) { if (s == NULL) { - if ((s = (bell_mf_tx_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (bell_mf_tx_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -348,7 +354,7 @@ SPAN_DECLARE(int) bell_mf_tx_release(bell_mf_tx_state_t *s) SPAN_DECLARE(int) bell_mf_tx_free(bell_mf_tx_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ @@ -390,14 +396,14 @@ SPAN_DECLARE(int) r2_mf_tx_put(r2_mf_tx_state_t *s, char digit) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(r2_mf_tx_state_t *) r2_mf_tx_init(r2_mf_tx_state_t *s, int fwd) +SPAN_DECLARE(r2_mf_tx_state_t *) r2_mf_tx_init(r2_mf_tx_state_t *s, bool fwd) { int i; const mf_digit_tones_t *tones; if (s == NULL) { - if ((s = (r2_mf_tx_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (r2_mf_tx_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -436,7 +442,7 @@ SPAN_DECLARE(r2_mf_tx_state_t *) r2_mf_tx_init(r2_mf_tx_state_t *s, int fwd) (tones->off_time == 0)); tones++; } - r2_mf_gen_inited = TRUE; + r2_mf_gen_inited = true; } s->fwd = fwd; return s; @@ -451,7 +457,7 @@ SPAN_DECLARE(int) r2_mf_tx_release(r2_mf_tx_state_t *s) SPAN_DECLARE(int) r2_mf_tx_free(r2_mf_tx_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ @@ -629,11 +635,11 @@ SPAN_DECLARE(bell_mf_rx_state_t *) bell_mf_rx_init(bell_mf_rx_state_t *s, void *user_data) { int i; - static int initialised = FALSE; + static int initialised = false; if (s == NULL) { - if ((s = (bell_mf_rx_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (bell_mf_rx_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -642,7 +648,7 @@ SPAN_DECLARE(bell_mf_rx_state_t *) bell_mf_rx_init(bell_mf_rx_state_t *s, { for (i = 0; i < 6; i++) make_goertzel_descriptor(&bell_mf_detect_desc[i], (float) bell_mf_frequencies[i], BELL_MF_SAMPLES_PER_BLOCK); - initialised = TRUE; + initialised = true; } s->digits_callback = callback; s->digits_callback_data = user_data; @@ -671,7 +677,7 @@ SPAN_DECLARE(int) bell_mf_rx_release(bell_mf_rx_state_t *s) SPAN_DECLARE(int) bell_mf_rx_free(bell_mf_rx_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ @@ -745,7 +751,7 @@ SPAN_DECLARE(int) r2_mf_rx(r2_mf_rx_state_t *s, const int16_t amp[], int samples } } /* Basic signal level and twist tests */ - hit = FALSE; + hit = false; if (energy[best] >= R2_MF_THRESHOLD && energy[second_best] >= R2_MF_THRESHOLD @@ -755,7 +761,7 @@ SPAN_DECLARE(int) r2_mf_rx(r2_mf_rx_state_t *s, const int16_t amp[], int samples energy[best]*R2_MF_TWIST > energy[second_best]) { /* Relative peak test */ - hit = TRUE; + hit = true; for (i = 0; i < 6; i++) { if (i != best && i != second_best) @@ -763,7 +769,7 @@ SPAN_DECLARE(int) r2_mf_rx(r2_mf_rx_state_t *s, const int16_t amp[], int samples if (energy[i]*R2_MF_RELATIVE_PEAK >= energy[second_best]) { /* The best two are not clearly the best */ - hit = FALSE; + hit = false; break; } } @@ -804,16 +810,16 @@ SPAN_DECLARE(int) r2_mf_rx_get(r2_mf_rx_state_t *s) /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(r2_mf_rx_state_t *) r2_mf_rx_init(r2_mf_rx_state_t *s, - int fwd, + bool fwd, tone_report_func_t callback, void *user_data) { int i; - static int initialised = FALSE; + static int initialised = false; if (s == NULL) { - if ((s = (r2_mf_rx_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (r2_mf_rx_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -827,7 +833,7 @@ SPAN_DECLARE(r2_mf_rx_state_t *) r2_mf_rx_init(r2_mf_rx_state_t *s, make_goertzel_descriptor(&mf_fwd_detect_desc[i], (float) r2_mf_fwd_frequencies[i], R2_MF_SAMPLES_PER_BLOCK); make_goertzel_descriptor(&mf_back_detect_desc[i], (float) r2_mf_back_frequencies[i], R2_MF_SAMPLES_PER_BLOCK); } - initialised = TRUE; + initialised = true; } if (fwd) { @@ -855,7 +861,7 @@ SPAN_DECLARE(int) r2_mf_rx_release(r2_mf_rx_state_t *s) SPAN_DECLARE(int) r2_mf_rx_free(r2_mf_rx_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/bert.c b/libs/spandsp/src/bert.c index a8ad5ad6b7..728476d65e 100644 --- a/libs/spandsp/src/bert.c +++ b/libs/spandsp/src/bert.c @@ -33,8 +33,14 @@ #include #include #include +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/async.h" #include "spandsp/bert.h" @@ -136,14 +142,14 @@ static void assess_error_rate(bert_state_t *s) int i; int j; int sum; - int test; + bool test; /* We assess the error rate in decadic steps. For each decade we assess the error over 10 times the number of bits, to smooth the result. This means we assess the 1 in 100 rate based on 1000 bits (i.e. we look for >=10 errors in 1000 bits). We make an assessment every 100 bits, using a sliding window over the last 1000 bits. We assess the 1 in 1000 rate over 10000 bits in a similar way, and so on for the lower error rates. */ - test = TRUE; + test = false; for (i = 2; i <= 7; i++) { if (++s->decade_ptr[i] < 10) @@ -156,7 +162,7 @@ static void assess_error_rate(bert_state_t *s) if (test && sum > 10) { /* We overflow into the next decade */ - test = FALSE; + test = false; if (s->error_rate != i && s->reporter) s->reporter(s->user_data, BERT_REPORT_GT_10_2 + i - 2, &s->results); s->error_rate = i; @@ -350,7 +356,7 @@ SPAN_DECLARE(bert_state_t *) bert_init(bert_state_t *s, int limit, int pattern, if (s == NULL) { - if ((s = (bert_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (bert_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -503,7 +509,7 @@ SPAN_DECLARE(int) bert_release(bert_state_t *s) SPAN_DECLARE(int) bert_free(bert_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/bitstream.c b/libs/spandsp/src/bitstream.c index 9a8c0bc9dd..6c0b9dde4b 100644 --- a/libs/spandsp/src/bitstream.c +++ b/libs/spandsp/src/bitstream.c @@ -33,8 +33,14 @@ #include #include #include +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/bitstream.h" #include "spandsp/private/bitstream.h" @@ -132,7 +138,7 @@ SPAN_DECLARE(bitstream_state_t *) bitstream_init(bitstream_state_t *s, int lsb_f { if (s == NULL) { - if ((s = (bitstream_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (bitstream_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } s->bitstream = 0; @@ -151,7 +157,7 @@ SPAN_DECLARE(int) bitstream_release(bitstream_state_t *s) SPAN_DECLARE(int) bitstream_free(bitstream_state_t *s) { if (s) - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/complex_filters.c b/libs/spandsp/src/complex_filters.c index d54e55818a..22cf4ac9b8 100644 --- a/libs/spandsp/src/complex_filters.c +++ b/libs/spandsp/src/complex_filters.c @@ -32,6 +32,7 @@ #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/complex.h" #include "spandsp/complex_filters.h" @@ -40,7 +41,7 @@ SPAN_DECLARE(filter_t *) filter_create(fspec_t *fs) int i; filter_t *fi; - if ((fi = (filter_t *) malloc(sizeof(*fi) + sizeof(float)*(fs->np + 1)))) + if ((fi = (filter_t *) span_alloc(sizeof(*fi) + sizeof(float)*(fs->np + 1)))) { fi->fs = fs; fi->sum = 0.0; @@ -56,7 +57,7 @@ SPAN_DECLARE(filter_t *) filter_create(fspec_t *fs) SPAN_DECLARE(void) filter_delete(filter_t *fi) { if (fi) - free(fi); + span_free(fi); } /*- End of function --------------------------------------------------------*/ @@ -70,17 +71,17 @@ SPAN_DECLARE(cfilter_t *) cfilter_create(fspec_t *fs) { cfilter_t *cfi; - if ((cfi = (cfilter_t *) malloc(sizeof(*cfi)))) + if ((cfi = (cfilter_t *) span_alloc(sizeof(*cfi)))) { if ((cfi->ref = filter_create(fs)) == NULL) { - free(cfi); + span_free(cfi); return NULL; } if ((cfi->imf = filter_create(fs)) == NULL) { - free(cfi->ref); - free(cfi); + span_free(cfi->ref); + span_free(cfi); return NULL; } } diff --git a/libs/spandsp/src/complex_vector_float.c b/libs/spandsp/src/complex_vector_float.c index ebb6accba4..710cbef435 100644 --- a/libs/spandsp/src/complex_vector_float.c +++ b/libs/spandsp/src/complex_vector_float.c @@ -39,6 +39,11 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include #include "floating_fudge.h" diff --git a/libs/spandsp/src/complex_vector_int.c b/libs/spandsp/src/complex_vector_int.c index 0bf7eb8a98..66a0cd62cd 100644 --- a/libs/spandsp/src/complex_vector_int.c +++ b/libs/spandsp/src/complex_vector_int.c @@ -39,6 +39,11 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include #include "floating_fudge.h" diff --git a/libs/spandsp/src/crc.c b/libs/spandsp/src/crc.c index f7407eda1f..cf4dd0cd0f 100644 --- a/libs/spandsp/src/crc.c +++ b/libs/spandsp/src/crc.c @@ -32,6 +32,11 @@ #include #include #include +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "spandsp/telephony.h" #include "spandsp/crc.h" @@ -102,7 +107,7 @@ SPAN_DECLARE(int) crc_itu32_append(uint8_t *buf, int len) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) crc_itu32_check(const uint8_t *buf, int len) +SPAN_DECLARE(bool) crc_itu32_check(const uint8_t *buf, int len) { uint32_t crc; int i; @@ -193,7 +198,7 @@ SPAN_DECLARE(int) crc_itu16_append(uint8_t *buf, int len) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) crc_itu16_check(const uint8_t *buf, int len) +SPAN_DECLARE(bool) crc_itu16_check(const uint8_t *buf, int len) { uint16_t crc; int i; diff --git a/libs/spandsp/src/dtmf.c b/libs/spandsp/src/dtmf.c index 6884d2b770..39c475a554 100644 --- a/libs/spandsp/src/dtmf.c +++ b/libs/spandsp/src/dtmf.c @@ -31,18 +31,24 @@ #include #include +#include +#include +#include #if defined(HAVE_TGMATH_H) #include #endif #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" -#include -#include -#include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/fast_convert.h" #include "spandsp/queue.h" @@ -62,24 +68,27 @@ #define DEFAULT_DTMF_TX_ON_TIME 50 #define DEFAULT_DTMF_TX_OFF_TIME 55 +#define DTMF_SAMPLES_PER_BLOCK 102 + #if defined(SPANDSP_USE_FIXED_POINT) -#define DTMF_THRESHOLD 10438 /* -42dBm0 */ -#define DTMF_NORMAL_TWIST 6.309f /* 8dB */ -#define DTMF_REVERSE_TWIST 2.512f /* 4dB */ -#define DTMF_RELATIVE_PEAK_ROW 6.309f /* 8dB */ -#define DTMF_RELATIVE_PEAK_COL 6.309f /* 8dB */ -#define DTMF_TO_TOTAL_ENERGY 83.868f /* -0.85dB */ -#define DTMF_POWER_OFFSET 68.251f /* 10*log(256.0*256.0*DTMF_SAMPLES_PER_BLOCK) */ -#define DTMF_SAMPLES_PER_BLOCK 102 -#else -#define DTMF_THRESHOLD 171032462.0f /* -42dBm0 [((DTMF_SAMPLES_PER_BLOCK*32768.0/1.4142)*10^((-42 - DBM0_MAX_SINE_POWER)/20.0))^2 => 171032462.0] */ -#define DTMF_NORMAL_TWIST 6.309f /* 8dB [10^(8/10) => 6.309] */ -#define DTMF_REVERSE_TWIST 2.512f /* 4dB */ -#define DTMF_RELATIVE_PEAK_ROW 6.309f /* 8dB */ -#define DTMF_RELATIVE_PEAK_COL 6.309f /* 8dB */ +/* The fixed point version scales the 16 bit signal down by 7 bits, so the Goertzels will fit in a 32 bit word */ +#define FP_SCALE(x) ((int16_t) (x/128.0 + ((x >= 0.0) ? 0.5 : -0.5))) +#define DTMF_THRESHOLD 10438 /* -42dBm0 [((DTMF_SAMPLES_PER_BLOCK*32768.0/1.4142)*10^((-42 - DBM0_MAX_SINE_POWER)/20.0)/128.0)^2]*/ +#define DTMF_NORMAL_TWIST 6.309f /* 8dB [10.0^(8.0/10.0)] */ +#define DTMF_REVERSE_TWIST 2.512f /* 4dB [10.0^(4.0/10.0)] */ +#define DTMF_RELATIVE_PEAK_ROW 6.309f /* 8dB [10.0^(8.0/10.0)] */ +#define DTMF_RELATIVE_PEAK_COL 6.309f /* 8dB [10.0^(8.0/10.0)] */ #define DTMF_TO_TOTAL_ENERGY 83.868f /* -0.85dB [DTMF_SAMPLES_PER_BLOCK*10^(-0.85/10.0)] */ -#define DTMF_POWER_OFFSET 110.395f /* 10*log(32768.0*32768.0*DTMF_SAMPLES_PER_BLOCK) */ -#define DTMF_SAMPLES_PER_BLOCK 102 +#define DTMF_POWER_OFFSET 68.251f /* 10*log(((32768.0/128.0)^2)*DTMF_SAMPLES_PER_BLOCK) */ +#else +#define FP_SCALE(x) (x) +#define DTMF_THRESHOLD 171032462.0f /* -42dBm0 [((DTMF_SAMPLES_PER_BLOCK*32768.0/1.4142)*10^((-42 - DBM0_MAX_SINE_POWER)/20.0))^2] */ +#define DTMF_NORMAL_TWIST 6.309f /* 8dB [10.0^(8.0/10.0)] */ +#define DTMF_REVERSE_TWIST 2.512f /* 4dB [10.0^(4.0/10.0)] */ +#define DTMF_RELATIVE_PEAK_ROW 6.309f /* 8dB [10.0^(8.0/10.0)] */ +#define DTMF_RELATIVE_PEAK_COL 6.309f /* 8dB [10.0^(8.0/10.0)] */ +#define DTMF_TO_TOTAL_ENERGY 83.868f /* -0.85dB [DTMF_SAMPLES_PER_BLOCK*10^(-0.85/10.0)] */ +#define DTMF_POWER_OFFSET 110.395f /* 10*log((32768.0^2)*DTMF_SAMPLES_PER_BLOCK) */ #endif static const float dtmf_row[] = @@ -93,10 +102,11 @@ static const float dtmf_col[] = static const char dtmf_positions[] = "123A" "456B" "789C" "*0#D"; +static bool dtmf_rx_inited = false; static goertzel_descriptor_t dtmf_detect_row[4]; static goertzel_descriptor_t dtmf_detect_col[4]; -static int dtmf_tx_inited = FALSE; +static bool dtmf_tx_inited = false; static tone_gen_descriptor_t dtmf_digit_tones[16]; SPAN_DECLARE(int) dtmf_rx(dtmf_rx_state_t *s, const int16_t amp[], int samples) @@ -296,11 +306,7 @@ SPAN_DECLARE(int) dtmf_rx(dtmf_rx_state_t *s, const int16_t amp[], int samples) s->in_digit = hit; } s->last_hit = hit; -#if defined(SPANDSP_USE_FIXED_POINT) - s->energy = 0; -#else - s->energy = 0.0f; -#endif + s->energy = FP_SCALE(0.0f); s->current_sample = 0; } if (s->current_digits && s->digits_callback) @@ -323,11 +329,7 @@ SPAN_DECLARE(int) dtmf_rx_fillin(dtmf_rx_state_t *s, int samples) goertzel_reset(&s->row_out[i]); goertzel_reset(&s->col_out[i]); } -#if defined(SPANDSP_USE_FIXED_POINT) - s->energy = 0; -#else - s->energy = 0.0f; -#endif + s->energy = FP_SCALE(0.0f); s->current_sample = 0; /* Don't update the hit detection. Pretend it never happened. */ /* TODO: Surely we can be cleverer than this. */ @@ -392,7 +394,11 @@ SPAN_DECLARE(void) dtmf_rx_parms(dtmf_rx_state_t *s, s->reverse_twist = powf(10.0f, reverse_twist/10.0f); if (threshold > -99) { +#if defined(SPANDSP_USE_FIXED_POINT) + x = (DTMF_SAMPLES_PER_BLOCK*32768.0f/(128.0f*1.4142f))*powf(10.0f, (threshold - DBM0_MAX_SINE_POWER)/20.0f); +#else x = (DTMF_SAMPLES_PER_BLOCK*32768.0f/1.4142f)*powf(10.0f, (threshold - DBM0_MAX_SINE_POWER)/20.0f); +#endif s->threshold = x*x; } } @@ -409,11 +415,10 @@ SPAN_DECLARE(dtmf_rx_state_t *) dtmf_rx_init(dtmf_rx_state_t *s, void *user_data) { int i; - static int initialised = FALSE; if (s == NULL) { - if ((s = (dtmf_rx_state_t *) malloc(sizeof (*s))) == NULL) + if ((s = (dtmf_rx_state_t *) span_alloc(sizeof (*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -423,7 +428,7 @@ SPAN_DECLARE(dtmf_rx_state_t *) dtmf_rx_init(dtmf_rx_state_t *s, s->digits_callback_data = user_data; s->realtime_callback = NULL; s->realtime_callback_data = NULL; - s->filter_dialtone = FALSE; + s->filter_dialtone = false; s->normal_twist = DTMF_NORMAL_TWIST; s->reverse_twist = DTMF_REVERSE_TWIST; s->threshold = DTMF_THRESHOLD; @@ -431,25 +436,21 @@ SPAN_DECLARE(dtmf_rx_state_t *) dtmf_rx_init(dtmf_rx_state_t *s, s->in_digit = 0; s->last_hit = 0; - if (!initialised) + if (!dtmf_rx_inited) { for (i = 0; i < 4; i++) { make_goertzel_descriptor(&dtmf_detect_row[i], dtmf_row[i], DTMF_SAMPLES_PER_BLOCK); make_goertzel_descriptor(&dtmf_detect_col[i], dtmf_col[i], DTMF_SAMPLES_PER_BLOCK); } - initialised = TRUE; + dtmf_rx_inited = true; } for (i = 0; i < 4; i++) { goertzel_init(&s->row_out[i], &dtmf_detect_row[i]); goertzel_init(&s->col_out[i], &dtmf_detect_col[i]); } -#if defined(SPANDSP_USE_FIXED_POINT) - s->energy = 0; -#else - s->energy = 0.0f; -#endif + s->energy = FP_SCALE(0.0f); s->current_sample = 0; s->lost_digits = 0; s->current_digits = 0; @@ -466,7 +467,7 @@ SPAN_DECLARE(int) dtmf_rx_release(dtmf_rx_state_t *s) SPAN_DECLARE(int) dtmf_rx_free(dtmf_rx_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ @@ -491,10 +492,10 @@ static void dtmf_tx_initialise(void) DEFAULT_DTMF_TX_OFF_TIME, 0, 0, - FALSE); + false); } } - dtmf_tx_inited = TRUE; + dtmf_tx_inited = true; } /*- End of function --------------------------------------------------------*/ @@ -578,7 +579,7 @@ SPAN_DECLARE(dtmf_tx_state_t *) dtmf_tx_init(dtmf_tx_state_t *s, { if (s == NULL) { - if ((s = (dtmf_tx_state_t *) malloc(sizeof (*s))) == NULL) + if ((s = (dtmf_tx_state_t *) span_alloc(sizeof (*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -603,7 +604,7 @@ SPAN_DECLARE(int) dtmf_tx_release(dtmf_tx_state_t *s) SPAN_DECLARE(int) dtmf_tx_free(dtmf_tx_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/echo.c b/libs/spandsp/src/echo.c index 84926fa3c4..5d6a1cadd2 100644 --- a/libs/spandsp/src/echo.c +++ b/libs/spandsp/src/echo.c @@ -88,11 +88,17 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/fast_convert.h" #include "spandsp/logging.h" #include "spandsp/saturated.h" @@ -105,12 +111,6 @@ #if !defined(NULL) #define NULL (void *) 0 #endif -#if !defined(FALSE) -#define FALSE 0 -#endif -#if !defined(TRUE) -#define TRUE (!FALSE) -#endif #define NONUPDATE_DWELL_TIME 600 /* 600 samples, or 75ms */ @@ -244,26 +244,26 @@ SPAN_DECLARE(echo_can_state_t *) echo_can_init(int len, int adaption_mode) int i; int j; - if ((ec = (echo_can_state_t *) malloc(sizeof(*ec))) == NULL) + if ((ec = (echo_can_state_t *) span_alloc(sizeof(*ec))) == NULL) return NULL; memset(ec, 0, sizeof(*ec)); ec->taps = len; ec->curr_pos = ec->taps - 1; ec->tap_mask = ec->taps - 1; - if ((ec->fir_taps32 = (int32_t *) malloc(ec->taps*sizeof(int32_t))) == NULL) + if ((ec->fir_taps32 = (int32_t *) span_alloc(ec->taps*sizeof(int32_t))) == NULL) { - free(ec); + span_free(ec); return NULL; } memset(ec->fir_taps32, 0, ec->taps*sizeof(int32_t)); for (i = 0; i < 4; i++) { - if ((ec->fir_taps16[i] = (int16_t *) malloc(ec->taps*sizeof(int16_t))) == NULL) + if ((ec->fir_taps16[i] = (int16_t *) span_alloc(ec->taps*sizeof(int16_t))) == NULL) { for (j = 0; j < i; j++) - free(ec->fir_taps16[j]); - free(ec->fir_taps32); - free(ec); + span_free(ec->fir_taps16[j]); + span_free(ec->fir_taps32); + span_free(ec); return NULL; } memset(ec->fir_taps16[i], 0, ec->taps*sizeof(int16_t)); @@ -274,7 +274,7 @@ SPAN_DECLARE(echo_can_state_t *) echo_can_init(int len, int adaption_mode) ec->rx_power_threshold = 10000000; ec->geigel_max = 0; ec->geigel_lag = 0; - ec->dtd_onset = FALSE; + ec->dtd_onset = false; ec->tap_set = 0; ec->tap_rotate_counter = 1600; ec->cng_level = 1000; @@ -294,10 +294,10 @@ SPAN_DECLARE(int) echo_can_free(echo_can_state_t *ec) int i; fir16_free(&ec->fir_state); - free(ec->fir_taps32); + span_free(ec->fir_taps32); for (i = 0; i < 4; i++) - free(ec->fir_taps16[i]); - free(ec); + span_free(ec->fir_taps16[i]); + span_free(ec); return 0; } /*- End of function --------------------------------------------------------*/ @@ -337,7 +337,7 @@ SPAN_DECLARE(void) echo_can_flush(echo_can_state_t *ec) ec->geigel_max = 0; ec->geigel_lag = 0; - ec->dtd_onset = FALSE; + ec->dtd_onset = false; ec->tap_set = 0; ec->tap_rotate_counter = 1600; @@ -485,7 +485,7 @@ printf("Revert to %d at %d\n", (ec->tap_set + 1)%3, sample_no); ec->narrowband_score = 0; } } - ec->dtd_onset = FALSE; + ec->dtd_onset = false; if (--ec->tap_rotate_counter <= 0) { printf("Rotate to %d at %d\n", ec->tap_set, sample_no); @@ -532,7 +532,7 @@ printf("Revert to %d at %d\n", (ec->tap_set + 1)%3, sample_no); for (i = 0; i < ec->taps; i++) ec->fir_taps32[i] = ec->fir_taps16[(ec->tap_set + 1)%3][i] << 15; ec->tap_rotate_counter = 1600; - ec->dtd_onset = TRUE; + ec->dtd_onset = true; } ec->nonupdate_dwell = NONUPDATE_DWELL_TIME; } @@ -575,7 +575,7 @@ printf("Revert to %d at %d\n", (ec->tap_set + 1)%3, sample_no); if (!ec->cng) { ec->cng_level = ec->clean_rx_power; - ec->cng = TRUE; + ec->cng = true; } if ((ec->adaption_mode & ECHO_CAN_USE_CNG)) { @@ -594,12 +594,12 @@ printf("Revert to %d at %d\n", (ec->tap_set + 1)%3, sample_no); } else { - ec->cng = FALSE; + ec->cng = false; } } else { - ec->cng = FALSE; + ec->cng = false; } printf("Narrowband score %4d %5d at %d\n", ec->narrowband_score, score, sample_no); diff --git a/libs/spandsp/src/fax.c b/libs/spandsp/src/fax.c index ef7e33433a..196c9ab0d3 100644 --- a/libs/spandsp/src/fax.c +++ b/libs/spandsp/src/fax.c @@ -40,6 +40,11 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include #include @@ -50,6 +55,7 @@ #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/queue.h" #include "spandsp/dc_restore.h" @@ -71,6 +77,10 @@ #include "spandsp/v27ter_rx.h" #include "spandsp/v17tx.h" #include "spandsp/v17rx.h" +#if defined(SPANDSP_SUPPORT_V34) +#include "spandsp/bitstream.h" +#include "spandsp/v34.h" +#endif #include "spandsp/timezone.h" #include "spandsp/t4_rx.h" #include "spandsp/t4_tx.h" @@ -78,9 +88,7 @@ #include "spandsp/t81_t82_arith_coding.h" #include "spandsp/t85.h" #include "spandsp/t42.h" -#if defined(SPANDSP_SUPPORT_T43) #include "spandsp/t43.h" -#endif #include "spandsp/t4_t6_decode.h" #include "spandsp/t4_t6_encode.h" @@ -95,9 +103,14 @@ #include "spandsp/private/logging.h" #include "spandsp/private/silence_gen.h" +#include "spandsp/private/power_meter.h" #include "spandsp/private/fsk.h" #include "spandsp/private/modem_connect_tones.h" #include "spandsp/private/v8.h" +#if defined(SPANDSP_SUPPORT_V34) +#include "spandsp/private/bitstream.h" +#include "spandsp/private/v34.h" +#endif #include "spandsp/private/v17tx.h" #include "spandsp/private/v17rx.h" #include "spandsp/private/v27ter_tx.h" @@ -110,9 +123,7 @@ #include "spandsp/private/t81_t82_arith_coding.h" #include "spandsp/private/t85.h" #include "spandsp/private/t42.h" -#if defined(SPANDSP_SUPPORT_T43) #include "spandsp/private/t43.h" -#endif #include "spandsp/private/t4_t6_decode.h" #include "spandsp/private/t4_t6_encode.h" #include "spandsp/private/image_translate.h" @@ -160,7 +171,8 @@ SPAN_DECLARE_NONSTD(int) fax_rx(fax_state_t *s, int16_t *amp, int len) #endif for (i = 0; i < len; i++) amp[i] = dc_restore(&s->modems.dc_restore, amp[i]); - s->modems.rx_handler(s->modems.rx_user_data, amp, len); + if (s->modems.rx_handler) + s->modems.rx_handler(s->modems.rx_user_data, amp, len); t30_timer_update(&s->t30, len); return 0; } @@ -194,26 +206,6 @@ SPAN_DECLARE_NONSTD(int) fax_rx_fillin(fax_state_t *s, int len) } /*- End of function --------------------------------------------------------*/ -static int set_next_tx_type(fax_state_t *s) -{ - fax_modems_state_t *t; - - t = &s->modems; - if (t->next_tx_handler) - { - fax_modems_set_tx_handler(t, t->next_tx_handler, t->next_tx_user_data); - t->next_tx_handler = NULL; - return 0; - } - /* If there is nothing else to change to, so use zero length silence */ - silence_gen_alter(&t->silence_gen, 0); - fax_modems_set_tx_handler(t, (span_tx_handler_t) &silence_gen, &t->silence_gen); - fax_modems_set_next_tx_handler(t, (span_tx_handler_t) NULL, NULL); - t->transmit = FALSE; - return -1; -} -/*- End of function --------------------------------------------------------*/ - SPAN_DECLARE_NONSTD(int) fax_tx(fax_state_t *s, int16_t *amp, int max_len) { int len; @@ -223,41 +215,30 @@ SPAN_DECLARE_NONSTD(int) fax_tx(fax_state_t *s, int16_t *amp, int max_len) required_len = max_len; #endif len = 0; - if (s->modems.transmit) + while (s->modems.transmit && (len += s->modems.tx_handler(s->modems.tx_user_data, &[len], max_len - len)) < max_len) { - while ((len += s->modems.tx_handler(s->modems.tx_user_data, amp + len, max_len - len)) < max_len) - { - /* Allow for a change of tx handler within a block */ - if (set_next_tx_type(s) && s->modems.current_tx_type != T30_MODEM_NONE && s->modems.current_tx_type != T30_MODEM_DONE) - t30_front_end_status(&s->t30, T30_FRONT_END_SEND_STEP_COMPLETE); - if (!s->modems.transmit) - { - if (s->modems.transmit_on_idle) - { - /* Pad to the requested length with silence */ - memset(amp + len, 0, (max_len - len)*sizeof(int16_t)); - len = max_len; - } - break; - } - } + /* Allow for a change of tx handler within a block */ + if (fax_modems_set_next_tx_type(&s->modems) && s->modems.current_tx_type != T30_MODEM_NONE && s->modems.current_tx_type != T30_MODEM_DONE) + t30_front_end_status(&s->t30, T30_FRONT_END_SEND_STEP_COMPLETE); + /*endif*/ } - else + /*endwhile*/ + if (s->modems.transmit_on_idle) { - if (s->modems.transmit_on_idle) - { - /* Pad to the requested length with silence */ - memset(amp, 0, max_len*sizeof(int16_t)); - len = max_len; - } + /* Pad to the requested length with silence */ + memset(&[len], 0, (max_len - len)*sizeof(int16_t)); + len = max_len; } + /*endif*/ #if defined(LOG_FAX_AUDIO) if (s->modems.audio_tx_log >= 0) { if (len < required_len) - memset(amp + len, 0, (required_len - len)*sizeof(int16_t)); + memset(&[len], 0, (required_len - len)*sizeof(int16_t)); + /*endif*/ write(s->modems.audio_tx_log, amp, required_len*sizeof(int16_t)); } + /*endif*/ #endif return len; } @@ -275,14 +256,12 @@ static void fax_set_rx_type(void *user_data, int type, int bit_rate, int short_t return; t->current_rx_type = type; t->rx_bit_rate = bit_rate; - if (use_hdlc) - hdlc_rx_init(&t->hdlc_rx, FALSE, TRUE, HDLC_FRAMING_OK_THRESHOLD, t30_hdlc_accept, &s->t30); + hdlc_rx_init(&t->hdlc_rx, false, true, HDLC_FRAMING_OK_THRESHOLD, fax_modems_hdlc_accept, t); switch (type) { case T30_MODEM_V21: fax_modems_start_slow_modem(t, FAX_MODEM_V21_RX); - fax_modems_set_rx_handler(t, (span_rx_handler_t) &fsk_rx, &t->v21_rx, (span_rx_fillin_handler_t) &fsk_rx_fillin, &t->v21_rx); break; case T30_MODEM_V17: fax_modems_start_fast_modem(t, FAX_MODEM_V17_RX, bit_rate, short_train, use_hdlc); @@ -313,20 +292,21 @@ static void fax_set_tx_type(void *user_data, int type, int bit_rate, int short_t span_log(&s->logging, SPAN_LOG_FLOW, "Set tx type %d\n", type); if (t->current_tx_type == type) return; + switch (type) { case T30_MODEM_PAUSE: silence_gen_alter(&t->silence_gen, ms_to_samples(short_train)); fax_modems_set_tx_handler(t, (span_tx_handler_t) &silence_gen, &t->silence_gen); fax_modems_set_next_tx_handler(t, (span_tx_handler_t) NULL, NULL); - t->transmit = TRUE; + t->transmit = true; break; case T30_MODEM_CED: case T30_MODEM_CNG: tone = (type == T30_MODEM_CED) ? FAX_MODEM_CED_TONE_TX : FAX_MODEM_CNG_TONE_TX; fax_modems_start_slow_modem(t, tone); fax_modems_set_next_tx_handler(t, (span_tx_handler_t) NULL, NULL); - t->transmit = TRUE; + t->transmit = true; break; case T30_MODEM_V21: fax_modems_start_slow_modem(t, FAX_MODEM_V21_TX); @@ -339,7 +319,7 @@ static void fax_set_tx_type(void *user_data, int type, int bit_rate, int short_t silence_gen_alter(&t->silence_gen, ms_to_samples(75)); fax_modems_set_tx_handler(t, (span_tx_handler_t) &silence_gen, &t->silence_gen); fax_modems_set_next_tx_handler(t, (span_tx_handler_t) &fsk_tx, &t->v21_tx); - t->transmit = TRUE; + t->transmit = true; break; case T30_MODEM_V17: silence_gen_alter(&t->silence_gen, ms_to_samples(75)); @@ -348,7 +328,7 @@ static void fax_set_tx_type(void *user_data, int type, int bit_rate, int short_t fax_modems_start_fast_modem(t, FAX_MODEM_V17_TX, bit_rate, short_train, use_hdlc); fax_modems_set_tx_handler(t, (span_tx_handler_t) &silence_gen, &t->silence_gen); fax_modems_set_next_tx_handler(t, (span_tx_handler_t) &v17_tx, &t->fast_modems.v17_tx); - t->transmit = TRUE; + t->transmit = true; break; case T30_MODEM_V27TER: silence_gen_alter(&t->silence_gen, ms_to_samples(75)); @@ -357,7 +337,7 @@ static void fax_set_tx_type(void *user_data, int type, int bit_rate, int short_t fax_modems_start_fast_modem(t, FAX_MODEM_V27TER_TX, bit_rate, short_train, use_hdlc); fax_modems_set_tx_handler(t, (span_tx_handler_t) &silence_gen, &t->silence_gen); fax_modems_set_next_tx_handler(t, (span_tx_handler_t) &v27ter_tx, &t->fast_modems.v27ter_tx); - t->transmit = TRUE; + t->transmit = true; break; case T30_MODEM_V29: silence_gen_alter(&t->silence_gen, ms_to_samples(75)); @@ -366,7 +346,7 @@ static void fax_set_tx_type(void *user_data, int type, int bit_rate, int short_t fax_modems_start_fast_modem(t, FAX_MODEM_V29_TX, bit_rate, short_train, use_hdlc); fax_modems_set_tx_handler(t, (span_tx_handler_t) &silence_gen, &t->silence_gen); fax_modems_set_next_tx_handler(t, (span_tx_handler_t) &v29_tx, &t->fast_modems.v29_tx); - t->transmit = TRUE; + t->transmit = true; break; case T30_MODEM_DONE: span_log(&s->logging, SPAN_LOG_FLOW, "FAX exchange complete\n"); @@ -375,7 +355,7 @@ static void fax_set_tx_type(void *user_data, int type, int bit_rate, int short_t silence_gen_alter(&t->silence_gen, 0); fax_modems_set_tx_handler(t, (span_tx_handler_t) &silence_gen, &t->silence_gen); fax_modems_set_next_tx_handler(t, (span_tx_handler_t) NULL, NULL); - t->transmit = FALSE; + t->transmit = false; break; } t->tx_bit_rate = bit_rate; @@ -470,14 +450,14 @@ SPAN_DECLARE(fax_state_t *) fax_init(fax_state_t *s, int calling_party) if (s == NULL) { - if ((s = (fax_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (fax_state_t *) span_alloc(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, "FAX"); fax_modems_init(&s->modems, - FALSE, + false, t30_hdlc_accept, hdlc_underflow_handler, t30_non_ecm_put_bit, @@ -525,7 +505,7 @@ SPAN_DECLARE(int) fax_release(fax_state_t *s) SPAN_DECLARE(int) fax_free(fax_state_t *s) { t30_release(&s->t30); - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/fax_modems.c b/libs/spandsp/src/fax_modems.c index eaf6653b5a..74d71ecc29 100644 --- a/libs/spandsp/src/fax_modems.c +++ b/libs/spandsp/src/fax_modems.c @@ -5,7 +5,7 @@ * * Written by Steve Underwood * - * Copyright (C) 2003, 2005, 2006, 2008 Steve Underwood + * Copyright (C) 2003, 2005, 2006, 2008, 2013 Steve Underwood * * All rights reserved. * @@ -39,6 +39,11 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include #include @@ -48,8 +53,10 @@ #endif #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/bit_operations.h" +#include "spandsp/bitstream.h" #include "spandsp/dc_restore.h" #include "spandsp/queue.h" #include "spandsp/power_meter.h" @@ -67,13 +74,21 @@ #include "spandsp/v27ter_rx.h" #include "spandsp/v17tx.h" #include "spandsp/v17rx.h" +#if defined(SPANDSP_SUPPORT_V34) +#include "spandsp/v34.h" +#endif #include "spandsp/super_tone_rx.h" #include "spandsp/modem_connect_tones.h" #include "spandsp/fax_modems.h" #include "spandsp/private/logging.h" +#include "spandsp/private/bitstream.h" #include "spandsp/private/silence_gen.h" +#include "spandsp/private/power_meter.h" #include "spandsp/private/fsk.h" +#if defined(SPANDSP_SUPPORT_V34) +#include "spandsp/private/v34.h" +#endif #include "spandsp/private/v17tx.h" #include "spandsp/private/v17rx.h" #include "spandsp/private/v27ter_tx.h" @@ -86,13 +101,64 @@ #define HDLC_FRAMING_OK_THRESHOLD 5 -static void fax_modems_hdlc_accept(void *user_data, const uint8_t *msg, int len, int ok) +SPAN_DECLARE(const char *) fax_modem_to_str(int modem) +{ + switch (modem) + { + case FAX_MODEM_NONE: + return "None"; + case FAX_MODEM_FLUSH: + return "Flush"; + case FAX_MODEM_SILENCE_TX: + return "Silence Tx"; + case FAX_MODEM_SILENCE_RX: + return "Silence Rx"; + case FAX_MODEM_CED_TONE_TX: + return "CED Tx"; + case FAX_MODEM_CNG_TONE_TX: + return "CNG Tx"; + case FAX_MODEM_NOCNG_TONE_TX: + return "No CNG Tx"; + case FAX_MODEM_CED_TONE_RX: + return "CED Rx"; + case FAX_MODEM_CNG_TONE_RX: + return "CNG Rx"; + case FAX_MODEM_V21_TX: + return "V.21 Tx"; + case FAX_MODEM_V17_TX: + return "V.17 Tx"; + case FAX_MODEM_V27TER_TX: + return "V.27ter Tx"; + case FAX_MODEM_V29_TX: + return "V.29 Tx"; + case FAX_MODEM_V21_RX: + return "V.21 Rx"; + case FAX_MODEM_V17_RX: + return "V.17 Rx"; + case FAX_MODEM_V27TER_RX: + return "V.27ter Rx"; + case FAX_MODEM_V29_RX: + return "V.29 Rx"; +#if defined(SPANDSP_SUPPORT_V34) + case FAX_MODEM_V34_TX: + return "V.34 HDX Tx"; + case FAX_MODEM_V34_RX: + return "V.34 HDX Rx"; +#endif + } + /*endswitch*/ + return "???"; +} +/*- End of function --------------------------------------------------------*/ + +//static void fax_modems_hdlc_accept(void *user_data, const uint8_t *msg, int len, int ok) +SPAN_DECLARE(void) fax_modems_hdlc_accept(void *user_data, const uint8_t *msg, int len, int ok) { fax_modems_state_t *s; s = (fax_modems_state_t *) user_data; - if (ok) - s->rx_frame_received = TRUE; + if (len >= 0 && ok) + s->rx_frame_received = true; if (s->hdlc_accept) s->hdlc_accept(s->hdlc_accept_user_data, msg, len, ok); } @@ -263,7 +329,7 @@ SPAN_DECLARE(void) fax_modems_start_slow_modem(fax_modems_state_t *s, int which) fsk_rx_init(&s->v21_rx, &preset_fsk_specs[FSK_V21CH2], FSK_FRAME_MODE_SYNC, (put_bit_func_t) hdlc_rx_put_bit, &s->hdlc_rx); fax_modems_set_rx_handler(s, (span_rx_handler_t) &fsk_rx, &s->v21_rx, (span_rx_fillin_handler_t) &fsk_rx_fillin, &s->v21_rx); fsk_rx_signal_cutoff(&s->v21_rx, -39.09f); - s->rx_frame_received = FALSE; + //hdlc_rx_init(&s->hdlc_rx, false, true, HDLC_FRAMING_OK_THRESHOLD, fax_modems_hdlc_accept, s); break; case FAX_MODEM_CED_TONE_RX: modem_connect_tones_rx_init(&s->connect_rx, MODEM_CONNECT_TONES_FAX_CED, s->tone_callback, s->tone_callback_user_data); @@ -289,6 +355,8 @@ SPAN_DECLARE(void) fax_modems_start_slow_modem(fax_modems_state_t *s, int which) fax_modems_set_next_tx_handler(s, (span_tx_handler_t) NULL, NULL); break; } + /*endswitch*/ + s->rx_frame_received = false; } /*- End of function --------------------------------------------------------*/ @@ -306,6 +374,7 @@ SPAN_DECLARE(void) fax_modems_start_fast_modem(fax_modems_state_t *s, int which, get_bit_user_data = (void *) &s->hdlc_tx; put_bit = (put_bit_func_t) hdlc_rx_put_bit; put_bit_user_data = (void *) &s->hdlc_rx; + //hdlc_rx_init(&s->hdlc_rx, false, true, HDLC_FRAMING_OK_THRESHOLD, fax_modems_hdlc_accept, s); } else { @@ -321,10 +390,8 @@ SPAN_DECLARE(void) fax_modems_start_fast_modem(fax_modems_state_t *s, int which, if (s->fast_modem != which) { s->current_rx_type = which; - s->short_train = FALSE; + s->short_train = false; s->fast_modem = which; - if (hdlc_mode) - s->rx_frame_received = FALSE; switch (s->fast_modem) { case FAX_MODEM_V27TER_RX: @@ -358,6 +425,18 @@ SPAN_DECLARE(void) fax_modems_start_fast_modem(fax_modems_state_t *s, int which, fax_modems_set_tx_handler(s, (span_tx_handler_t) &v17_tx, &s->fast_modems.v17_tx); fax_modems_set_next_tx_handler(s, (span_tx_handler_t) NULL, NULL); break; +#if defined(SPANDSP_SUPPORT_V34) + case FAX_MODEM_V34_RX: + v34_init(&s->fast_modems.v34, 2400, s->bit_rate, true, false, NULL, NULL, put_bit, put_bit_user_data); + //fax_modems_set_tx_handler(s, (span_tx_handler_t) &v34_rx, &s->fast_modems.v34_rx); + fax_modems_set_next_tx_handler(s, (span_tx_handler_t) NULL, NULL); + break; + case FAX_MODEM_V34_TX: + v34_init(&s->fast_modems.v34, 2400, s->bit_rate, true, false, get_bit, get_bit_user_data, NULL, NULL); + //fax_modems_set_tx_handler(s, (span_tx_handler_t) &v34_tx, &s->fast_modems.v34_tx); + fax_modems_set_next_tx_handler(s, (span_tx_handler_t) NULL, NULL); + break; +#endif } /*endswitch*/ } @@ -367,13 +446,13 @@ SPAN_DECLARE(void) fax_modems_start_fast_modem(fax_modems_state_t *s, int which, switch (s->fast_modem) { case FAX_MODEM_V27TER_RX: - v27ter_rx_restart(&s->fast_modems.v27ter_rx, s->bit_rate, FALSE); + v27ter_rx_restart(&s->fast_modems.v27ter_rx, s->bit_rate, false); v27ter_rx_set_put_bit(&s->fast_modems.v27ter_rx, put_bit, put_bit_user_data); v27ter_rx_set_modem_status_handler(&s->fast_modems.v27ter_rx, v27ter_rx_status_handler, s); fax_modems_set_rx_handler(s, (span_rx_handler_t) &fax_modems_v27ter_v21_rx, s, (span_rx_fillin_handler_t) &fax_modems_v27ter_v21_rx_fillin, s); break; case FAX_MODEM_V29_RX: - v29_rx_restart(&s->fast_modems.v29_rx, s->bit_rate, FALSE); + v29_rx_restart(&s->fast_modems.v29_rx, s->bit_rate, false); v29_rx_set_put_bit(&s->fast_modems.v29_rx, put_bit, put_bit_user_data); v29_rx_set_modem_status_handler(&s->fast_modems.v29_rx, v29_rx_status_handler, s); fax_modems_set_rx_handler(s, (span_rx_handler_t) &fax_modems_v29_v21_rx, s, (span_rx_fillin_handler_t) &fax_modems_v29_v21_rx_fillin, s); @@ -402,10 +481,23 @@ SPAN_DECLARE(void) fax_modems_start_fast_modem(fax_modems_state_t *s, int which, fax_modems_set_tx_handler(s, (span_tx_handler_t) &v17_tx, &s->fast_modems.v17_tx); fax_modems_set_next_tx_handler(s, (span_tx_handler_t) NULL, NULL); break; +#if defined(SPANDSP_SUPPORT_V34) + case FAX_MODEM_V34_RX: + v34_restart(&s->fast_modems.v34, 2400, s->bit_rate, false); + //fax_modems_set_tx_handler(s, (span_tx_handler_t) &v34_rx, &s->fast_modems.v34_rx); + fax_modems_set_next_tx_handler(s, (span_tx_handler_t) NULL, NULL); + break; + case FAX_MODEM_V34_TX: + v34_restart(&s->fast_modems.v34, 2400, s->bit_rate, false); + //fax_modems_set_tx_handler(s, (span_tx_handler_t) &v34_tx, &s->fast_modems.v34_tx); + fax_modems_set_next_tx_handler(s, (span_tx_handler_t) NULL, NULL); + break; +#endif } /*endswitch*/ } /*endif*/ + s->rx_frame_received = false; } /*- End of function --------------------------------------------------------*/ @@ -474,6 +566,23 @@ SPAN_DECLARE(void) fax_modems_set_next_tx_handler(fax_modems_state_t *s, span_tx } /*- End of function --------------------------------------------------------*/ +SPAN_DECLARE(int) fax_modems_set_next_tx_type(fax_modems_state_t *s) +{ + if (s->next_tx_handler) + { + fax_modems_set_tx_handler(s, s->next_tx_handler, s->next_tx_user_data); + fax_modems_set_next_tx_handler(s, (span_tx_handler_t) NULL, NULL); + return 0; + } + /* There is nothing else to change to, so use zero length silence */ + silence_gen_alter(&s->silence_gen, 0); + fax_modems_set_tx_handler(s, (span_tx_handler_t) &silence_gen, &s->silence_gen); + fax_modems_set_next_tx_handler(s, (span_tx_handler_t) NULL, NULL); + s->transmit = false; + return -1; +} +/*- End of function --------------------------------------------------------*/ + SPAN_DECLARE(void) fax_modems_set_tep_mode(fax_modems_state_t *s, int use_tep) { s->use_tep = use_tep; @@ -503,7 +612,7 @@ SPAN_DECLARE(fax_modems_state_t *) fax_modems_init(fax_modems_state_t *s, { if (s == NULL) { - if ((s = (fax_modems_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (fax_modems_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } /*endif*/ @@ -511,6 +620,9 @@ SPAN_DECLARE(fax_modems_state_t *) fax_modems_init(fax_modems_state_t *s, s->use_tep = use_tep; 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_user_data = user_data; if (tone_callback) @@ -521,9 +633,6 @@ SPAN_DECLARE(fax_modems_state_t *) fax_modems_init(fax_modems_state_t *s, s->tone_callback_user_data); } /*endif*/ - span_log_init(&s->logging, SPAN_LOG_NONE, NULL); - span_log_set_protocol(&s->logging, "FAX modems"); - dc_restore_init(&s->dc_restore); s->get_bit = non_ecm_get_bit; @@ -534,15 +643,15 @@ SPAN_DECLARE(fax_modems_state_t *) fax_modems_init(fax_modems_state_t *s, s->hdlc_accept = hdlc_accept; s->hdlc_accept_user_data = user_data; - hdlc_rx_init(&s->hdlc_rx, FALSE, FALSE, HDLC_FRAMING_OK_THRESHOLD, fax_modems_hdlc_accept, s); - hdlc_tx_init(&s->hdlc_tx, FALSE, 2, FALSE, hdlc_tx_underflow, user_data); + hdlc_rx_init(&s->hdlc_rx, false, false, HDLC_FRAMING_OK_THRESHOLD, fax_modems_hdlc_accept, s); + hdlc_tx_init(&s->hdlc_tx, false, 2, false, hdlc_tx_underflow, user_data); fax_modems_start_slow_modem(s, FAX_MODEM_V21_RX); fsk_tx_init(&s->v21_tx, &preset_fsk_specs[FSK_V21CH2], (get_bit_func_t) hdlc_tx_get_bit, &s->hdlc_tx); silence_gen_init(&s->silence_gen, 0); - s->rx_signal_present = FALSE; + s->rx_signal_present = false; s->rx_handler = (span_rx_handler_t) &span_dummy_rx; s->rx_fillin_handler = (span_rx_fillin_handler_t) &span_dummy_rx; s->rx_user_data = NULL; @@ -562,7 +671,7 @@ SPAN_DECLARE(int) fax_modems_release(fax_modems_state_t *s) SPAN_DECLARE(int) fax_modems_free(fax_modems_state_t *s) { if (s) - free(s); + span_free(s); /*endif*/ return 0; } diff --git a/libs/spandsp/src/filter_tools.c b/libs/spandsp/src/filter_tools.c index 88967e93ed..ff625bb13d 100644 --- a/libs/spandsp/src/filter_tools.c +++ b/libs/spandsp/src/filter_tools.c @@ -32,29 +32,27 @@ #include #include +#include +#include +#include +#include #if defined(HAVE_TGMATH_H) #include #endif #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" -#include -#include -#include -#include #include "spandsp/telephony.h" #include "spandsp/complex.h" #include "filter_tools.h" -#if !defined(FALSE) -#define FALSE 0 -#endif -#if !defined(TRUE) -#define TRUE (!FALSE) -#endif - #define MAXPZ 8192 #define SEQ_LEN 8192 #define MAX_FFT_LEN SEQ_LEN diff --git a/libs/spandsp/src/fsk.c b/libs/spandsp/src/fsk.c index 56f155169e..29b32c65ea 100644 --- a/libs/spandsp/src/fsk.c +++ b/libs/spandsp/src/fsk.c @@ -38,16 +38,23 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/complex.h" #include "spandsp/dds.h" #include "spandsp/power_meter.h" #include "spandsp/async.h" #include "spandsp/fsk.h" +#include "spandsp/private/power_meter.h" #include "spandsp/private/fsk.h" const fsk_spec_t preset_fsk_specs[] = @@ -69,6 +76,7 @@ const fsk_spec_t preset_fsk_specs[] = 300*100 }, { + /* This is mode 2 of the V.23 spec. Mode 1 (the 600baud mode) is not defined here */ "V23 ch 1", 1700 + 400, 1700 - 400, @@ -124,6 +132,14 @@ const fsk_spec_t preset_fsk_specs[] = -30, 50*100 }, + { + "Weitbrecht 47.6", /* Used for V.18 probing */ + 1600 + 200, + 1600 - 200, + -14, + -30, + 4760 + }, { "V21 (110bps) ch 1", 1080 + 100, @@ -145,7 +161,7 @@ SPAN_DECLARE(int) fsk_tx_restart(fsk_tx_state_t *s, const fsk_spec_t *spec) s->baud_frac = 0; s->current_phase_rate = s->phase_rates[1]; - s->shutdown = FALSE; + s->shutdown = false; return 0; } /*- End of function --------------------------------------------------------*/ @@ -157,7 +173,7 @@ SPAN_DECLARE(fsk_tx_state_t *) fsk_tx_init(fsk_tx_state_t *s, { if (s == NULL) { - if ((s = (fsk_tx_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (fsk_tx_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -177,7 +193,7 @@ SPAN_DECLARE(int) fsk_tx_release(fsk_tx_state_t *s) SPAN_DECLARE(int) fsk_tx_free(fsk_tx_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ @@ -204,7 +220,7 @@ SPAN_DECLARE_NONSTD(int) fsk_tx(fsk_tx_state_t *s, int16_t amp[], int len) s->status_handler(s->status_user_data, SIG_STATUS_END_OF_DATA); if (s->status_handler) s->status_handler(s->status_user_data, SIG_STATUS_SHUTDOWN_COMPLETE); - s->shutdown = TRUE; + s->shutdown = true; break; } s->current_phase_rate = s->phase_rates[bit & 1]; @@ -319,7 +335,7 @@ SPAN_DECLARE(fsk_rx_state_t *) fsk_rx_init(fsk_rx_state_t *s, { if (s == NULL) { - if ((s = (fsk_rx_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (fsk_rx_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -339,7 +355,7 @@ SPAN_DECLARE(int) fsk_rx_release(fsk_rx_state_t *s) SPAN_DECLARE(int) fsk_rx_free(fsk_rx_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/g711.c b/libs/spandsp/src/g711.c index 173bd2ae53..edccd27bb1 100644 --- a/libs/spandsp/src/g711.c +++ b/libs/spandsp/src/g711.c @@ -35,6 +35,7 @@ #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/bit_operations.h" #include "spandsp/g711.h" #include "spandsp/private/g711.h" @@ -171,7 +172,7 @@ SPAN_DECLARE(g711_state_t *) g711_init(g711_state_t *s, int mode) { if (s == NULL) { - if ((s = (g711_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (g711_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } s->mode = mode; @@ -187,7 +188,7 @@ SPAN_DECLARE(int) g711_release(g711_state_t *s) SPAN_DECLARE(int) g711_free(g711_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/g722.c b/libs/spandsp/src/g722.c index f223592dc8..2f11715c10 100644 --- a/libs/spandsp/src/g722.c +++ b/libs/spandsp/src/g722.c @@ -21,12 +21,6 @@ * 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. - * - * Based in part on a single channel G.722 codec which is: - * - * Copyright (c) CMU 1993 - * Computer Science, Speech Group - * Chengxiang Lu and Alex Hauptmann */ /*! \file */ @@ -44,9 +38,15 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/fast_convert.h" #include "spandsp/saturated.h" #include "spandsp/vector_int.h" @@ -257,7 +257,7 @@ SPAN_DECLARE(g722_decode_state_t *) g722_decode_init(g722_decode_state_t *s, int { if (s == NULL) { - if ((s = (g722_decode_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (g722_decode_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -268,11 +268,11 @@ SPAN_DECLARE(g722_decode_state_t *) g722_decode_init(g722_decode_state_t *s, int else s->bits_per_sample = 8; if ((options & G722_SAMPLE_RATE_8000)) - s->eight_k = TRUE; + s->eight_k = true; if ((options & G722_PACKED) && s->bits_per_sample != 8) - s->packed = TRUE; + s->packed = true; else - s->packed = FALSE; + s->packed = false; s->band[0].det = 32; s->band[1].det = 8; return s; @@ -287,7 +287,7 @@ SPAN_DECLARE(int) g722_decode_release(g722_decode_state_t *s) SPAN_DECLARE(int) g722_decode_free(g722_decode_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ @@ -438,7 +438,7 @@ SPAN_DECLARE(g722_encode_state_t *) g722_encode_init(g722_encode_state_t *s, int { if (s == NULL) { - if ((s = (g722_encode_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (g722_encode_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -449,11 +449,11 @@ SPAN_DECLARE(g722_encode_state_t *) g722_encode_init(g722_encode_state_t *s, int else s->bits_per_sample = 8; if ((options & G722_SAMPLE_RATE_8000)) - s->eight_k = TRUE; + s->eight_k = true; if ((options & G722_PACKED) && s->bits_per_sample != 8) - s->packed = TRUE; + s->packed = true; else - s->packed = FALSE; + s->packed = false; s->band[0].det = 32; s->band[1].det = 8; return s; @@ -468,7 +468,7 @@ SPAN_DECLARE(int) g722_encode_release(g722_encode_state_t *s) SPAN_DECLARE(int) g722_encode_free(g722_encode_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/g726.c b/libs/spandsp/src/g726.c index 6be385fc5f..4f3bea3b6b 100644 --- a/libs/spandsp/src/g726.c +++ b/libs/spandsp/src/g726.c @@ -64,9 +64,15 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/bitstream.h" #include "spandsp/bit_operations.h" #include "spandsp/g711.h" @@ -393,7 +399,7 @@ static void update(g726_state_t *s, int16_t thr; int16_t pk0; int i; - int tr; + bool tr; a2p = 0; /* Needed in updating predictor poles */ @@ -408,11 +414,11 @@ static void update(g726_state_t *s, thr = (ylint > 9) ? (31 << 10) : ((32 + ylfrac) << ylint); dqthr = (thr + (thr >> 1)) >> 1; /* dqthr = 0.75 * thr */ if (!s->td) /* signal supposed voice */ - tr = FALSE; + tr = false; else if (mag <= dqthr) /* supposed data, but small mag */ - tr = FALSE; /* treated as voice */ + tr = false; /* treated as voice */ else /* signal is data (modem) */ - tr = TRUE; + tr = true; /* * Quantizer scale factor adaptation. @@ -563,11 +569,11 @@ static void update(g726_state_t *s, /* TONE */ if (tr) /* this sample has been treated as data */ - s->td = FALSE; /* next one will be treated as voice */ + s->td = false; /* next one will be treated as voice */ else if (a2p < -11776) /* small sample-to-sample correlation */ - s->td = TRUE; /* signal may be data */ + s->td = true; /* signal may be data */ else /* signal is voice */ - s->td = FALSE; + s->td = false; /* Adaptation speed control. */ /* FILTA */ @@ -1002,7 +1008,7 @@ SPAN_DECLARE(g726_state_t *) g726_init(g726_state_t *s, int bit_rate, int ext_co return NULL; if (s == NULL) { - if ((s = (g726_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (g726_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } s->yl = 34816; @@ -1024,7 +1030,7 @@ SPAN_DECLARE(g726_state_t *) g726_init(g726_state_t *s, int bit_rate, int ext_co s->b[i] = 0; s->dq[i] = 32; } - s->td = FALSE; + s->td = false; switch (bit_rate) { case 16000: @@ -1062,7 +1068,7 @@ SPAN_DECLARE(int) g726_release(g726_state_t *s) SPAN_DECLARE(int) g726_free(g726_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/gsm0610_encode.c b/libs/spandsp/src/gsm0610_encode.c index 2c359688fe..eeac7d2881 100644 --- a/libs/spandsp/src/gsm0610_encode.c +++ b/libs/spandsp/src/gsm0610_encode.c @@ -45,6 +45,7 @@ #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/fast_convert.h" #include "spandsp/bitstream.h" #include "spandsp/saturated.h" @@ -115,7 +116,7 @@ SPAN_DECLARE(gsm0610_state_t *) gsm0610_init(gsm0610_state_t *s, int packing) { if (s == NULL) { - if ((s = (gsm0610_state_t *) malloc(sizeof (*s))) == NULL) + if ((s = (gsm0610_state_t *) span_alloc(sizeof (*s))) == NULL) return NULL; /*endif*/ } @@ -136,7 +137,7 @@ SPAN_DECLARE(int) gsm0610_release(gsm0610_state_t *s) SPAN_DECLARE(int) gsm0610_free(gsm0610_state_t *s) { if (s) - free(s); + span_free(s); /*endif*/ return 0; } diff --git a/libs/spandsp/src/hdlc.c b/libs/spandsp/src/hdlc.c index 7733aa8280..7a20bf2451 100644 --- a/libs/spandsp/src/hdlc.c +++ b/libs/spandsp/src/hdlc.c @@ -33,8 +33,14 @@ #include #include #include +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/async.h" #include "spandsp/crc.h" #include "spandsp/bit_operations.h" @@ -46,7 +52,7 @@ static void report_status_change(hdlc_rx_state_t *s, int status) if (s->status_handler) s->status_handler(s->status_user_data, status); else if (s->frame_handler) - s->frame_handler(s->frame_user_data, NULL, status, TRUE); + s->frame_handler(s->frame_user_data, NULL, status, true); } /*- End of function --------------------------------------------------------*/ @@ -62,7 +68,7 @@ static void rx_special_condition(hdlc_rx_state_t *s, int status) s->len = 0; s->num_bits = 0; s->flags_seen = 0; - s->framing_ok_announced = FALSE; + s->framing_ok_announced = false; /* Fall through */ case SIG_STATUS_TRAINING_IN_PROGRESS: case SIG_STATUS_TRAINING_FAILED: @@ -94,7 +100,7 @@ static __inline__ void octet_set_and_count(hdlc_rx_state_t *s) } else { - s->octet_counting_mode = TRUE; + s->octet_counting_mode = true; s->octet_count = s->octet_count_report_interval; } } @@ -139,7 +145,7 @@ static void rx_flag_or_abort(hdlc_rx_state_t *s) { /* Hit HDLC flag */ /* A flag clears octet counting */ - s->octet_counting_mode = FALSE; + s->octet_counting_mode = false; if (s->flags_seen >= s->framing_ok_threshold) { /* We may have a frame, or we may have back to back flags */ @@ -155,7 +161,7 @@ static void rx_flag_or_abort(hdlc_rx_state_t *s) s->rx_bytes += s->len - s->crc_bytes; s->len -= s->crc_bytes; if (s->frame_handler) - s->frame_handler(s->frame_user_data, s->buffer, s->len, TRUE); + s->frame_handler(s->frame_user_data, s->buffer, s->len, true); } else { @@ -164,7 +170,7 @@ static void rx_flag_or_abort(hdlc_rx_state_t *s) { s->len -= s->crc_bytes; if (s->frame_handler) - s->frame_handler(s->frame_user_data, s->buffer, s->len, FALSE); + s->frame_handler(s->frame_user_data, s->buffer, s->len, false); } } } @@ -180,7 +186,7 @@ static void rx_flag_or_abort(hdlc_rx_state_t *s) else s->len = 0; if (s->frame_handler) - s->frame_handler(s->frame_user_data, s->buffer, s->len, FALSE); + s->frame_handler(s->frame_user_data, s->buffer, s->len, false); } s->rx_length_errors++; } @@ -205,7 +211,7 @@ static void rx_flag_or_abort(hdlc_rx_state_t *s) if (++s->flags_seen >= s->framing_ok_threshold && !s->framing_ok_announced) { report_status_change(s, SIG_STATUS_FRAMING_OK); - s->framing_ok_announced = TRUE; + s->framing_ok_announced = true; } } } @@ -306,15 +312,15 @@ SPAN_DECLARE(void) hdlc_rx_set_octet_counting_report_interval(hdlc_rx_state_t *s /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(hdlc_rx_state_t *) hdlc_rx_init(hdlc_rx_state_t *s, - int crc32, - int report_bad_frames, + bool crc32, + bool report_bad_frames, int framing_ok_threshold, hdlc_frame_handler_t handler, void *user_data) { if (s == NULL) { - if ((s = (hdlc_rx_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (hdlc_rx_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -350,7 +356,7 @@ SPAN_DECLARE(int) hdlc_rx_release(hdlc_rx_state_t *s) SPAN_DECLARE(int) hdlc_rx_free(hdlc_rx_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ @@ -371,7 +377,7 @@ SPAN_DECLARE(int) hdlc_tx_frame(hdlc_tx_state_t *s, const uint8_t *frame, size_t { if (len <= 0) { - s->tx_end = TRUE; + s->tx_end = true; return 0; } if (s->len + len > s->max_frame_len) @@ -397,7 +403,7 @@ SPAN_DECLARE(int) hdlc_tx_frame(hdlc_tx_state_t *s, const uint8_t *frame, size_t s->len += len; else s->len = len; - s->tx_end = FALSE; + s->tx_end = false; return 0; } /*- End of function --------------------------------------------------------*/ @@ -412,8 +418,8 @@ SPAN_DECLARE(int) hdlc_tx_flags(hdlc_tx_state_t *s, int len) s->flag_octets += -len; else s->flag_octets = len; - s->report_flag_underflow = TRUE; - s->tx_end = FALSE; + s->report_flag_underflow = true; + s->tx_end = false; return 0; } /*- End of function --------------------------------------------------------*/ @@ -452,7 +458,7 @@ SPAN_DECLARE_NONSTD(int) hdlc_tx_get_byte(hdlc_tx_state_t *s) /* We are in a timed flag section (preamble, inter frame gap, etc.) */ if (--s->flag_octets <= 0 && s->report_flag_underflow) { - s->report_flag_underflow = FALSE; + s->report_flag_underflow = false; if (s->len == 0) { /* The timed flags have finished, there is nothing else queued to go, @@ -508,7 +514,7 @@ SPAN_DECLARE_NONSTD(int) hdlc_tx_get_byte(hdlc_tx_state_t *s) s->crc = 0xFFFFFFFF; /* Report the underflow now. If there are timed flags still in progress, loading the next frame right now will be harmless. */ - s->report_flag_underflow = FALSE; + s->report_flag_underflow = false; if (s->underflow_handler) s->underflow_handler(s->user_data); /* Make sure we finish off with at least one flag octet, if the underflow report did not result @@ -539,7 +545,7 @@ SPAN_DECLARE_NONSTD(int) hdlc_tx_get_byte(hdlc_tx_state_t *s) /* Untimed idling on flags */ if (s->tx_end) { - s->tx_end = FALSE; + s->tx_end = false; return SIG_STATUS_END_OF_DATA; } return s->idle_octet; @@ -584,15 +590,15 @@ SPAN_DECLARE(void) hdlc_tx_set_max_frame_len(hdlc_tx_state_t *s, size_t max_len) /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(hdlc_tx_state_t *) hdlc_tx_init(hdlc_tx_state_t *s, - int crc32, + bool crc32, int inter_frame_flags, - int progressive, + bool progressive, hdlc_underflow_handler_t handler, void *user_data) { if (s == NULL) { - if ((s = (hdlc_tx_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (hdlc_tx_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -624,7 +630,7 @@ SPAN_DECLARE(int) hdlc_tx_release(hdlc_tx_state_t *s) SPAN_DECLARE(int) hdlc_tx_free(hdlc_tx_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/ima_adpcm.c b/libs/spandsp/src/ima_adpcm.c index 6c4cc16370..fbd59df621 100644 --- a/libs/spandsp/src/ima_adpcm.c +++ b/libs/spandsp/src/ima_adpcm.c @@ -42,6 +42,7 @@ #include "floating_fudge.h" #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/fast_convert.h" #include "spandsp/saturated.h" #include "spandsp/ima_adpcm.h" @@ -282,7 +283,7 @@ SPAN_DECLARE(ima_adpcm_state_t *) ima_adpcm_init(ima_adpcm_state_t *s, { if (s == NULL) { - if ((s = (ima_adpcm_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (ima_adpcm_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } /*endif*/ @@ -301,7 +302,7 @@ SPAN_DECLARE(int) ima_adpcm_release(ima_adpcm_state_t *s) SPAN_DECLARE(int) ima_adpcm_free(ima_adpcm_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/image_translate.c b/libs/spandsp/src/image_translate.c index 81be68f5db..1768b92138 100644 --- a/libs/spandsp/src/image_translate.c +++ b/libs/spandsp/src/image_translate.c @@ -47,11 +47,17 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/fast_convert.h" #include "spandsp/logging.h" #include "spandsp/saturated.h" @@ -61,9 +67,7 @@ #include "spandsp/t81_t82_arith_coding.h" #include "spandsp/t85.h" #include "spandsp/t42.h" -#if defined(SPANDSP_SUPPORT_T43) #include "spandsp/t43.h" -#endif #include "spandsp/t4_t6_decode.h" #include "spandsp/t4_t6_encode.h" #include "spandsp/image_translate.h" @@ -72,9 +76,7 @@ #include "spandsp/private/t81_t82_arith_coding.h" #include "spandsp/private/t85.h" #include "spandsp/private/t42.h" -#if defined(SPANDSP_SUPPORT_T43) #include "spandsp/private/t43.h" -#endif #include "spandsp/private/t4_t6_decode.h" #include "spandsp/private/t4_t6_encode.h" #include "spandsp/private/image_translate.h" @@ -253,6 +255,7 @@ static int get_and_scrunch_row(image_translate_state_t *s, uint8_t buf[]) case T4_IMAGE_TYPE_COLOUR_12BIT: image_gray16_to_colour16_row((uint16_t *) buf, (uint16_t *) buf, s->input_width); break; + case T4_IMAGE_TYPE_COLOUR_BILEVEL: case T4_IMAGE_TYPE_COLOUR_8BIT: image_gray16_to_colour8_row(buf, (uint16_t *) buf, s->input_width); break; @@ -267,6 +270,7 @@ static int get_and_scrunch_row(image_translate_state_t *s, uint8_t buf[]) case T4_IMAGE_TYPE_COLOUR_12BIT: image_gray8_to_colour16_row((uint16_t *) buf, buf, s->input_width); break; + case T4_IMAGE_TYPE_COLOUR_BILEVEL: case T4_IMAGE_TYPE_COLOUR_8BIT: image_gray8_to_colour8_row(buf, buf, s->input_width); break; @@ -282,11 +286,13 @@ static int get_and_scrunch_row(image_translate_state_t *s, uint8_t buf[]) case T4_IMAGE_TYPE_GRAY_8BIT: image_colour16_to_gray8_row(buf, (uint16_t *) buf, s->input_width); break; + case T4_IMAGE_TYPE_COLOUR_BILEVEL: case T4_IMAGE_TYPE_COLOUR_8BIT: image_colour16_to_colour8_row(buf, (uint16_t *) buf, s->input_width); break; } break; + case T4_IMAGE_TYPE_COLOUR_BILEVEL: case T4_IMAGE_TYPE_COLOUR_8BIT: switch (s->output_format) { @@ -327,6 +333,7 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[]) double int_part; double frac_row; double frac_col; + double width_scaling; #endif uint8_t *row8[2]; uint16_t *row16[2]; @@ -342,17 +349,13 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[]) input_width = s->input_width - 1; input_length = s->input_length - 1; - skip = s->raw_output_row*input_length/output_length; + skip = s->raw_output_row*input_length/output_length + 1; if (skip >= s->raw_input_row) { - skip++; while (skip >= s->raw_input_row) { if (s->raw_input_row >= s->input_length) - { - s->raw_output_row = -1; break; - } row_len = get_and_scrunch_row(s, s->raw_pixel_row[0]); if (row_len != s->output_width) { @@ -370,10 +373,12 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[]) frac_row = ((s->raw_output_row*256*input_length)/output_length) & 0xFF; #else frac_row = modf((double) s->raw_output_row*input_length/output_length, &int_part); + width_scaling = (double) input_width/output_width; #endif switch (s->output_format) { + case T4_IMAGE_TYPE_COLOUR_BILEVEL: case T4_IMAGE_TYPE_COLOUR_8BIT: row8[0] = s->raw_pixel_row[0]; row8[1] = s->raw_pixel_row[1]; @@ -391,7 +396,7 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[]) buf[3*i + j] = saturateu8(c1 + (((c2 - c1)*frac_row) >> 8)); } #else - frac_col = modf((double) i*input_width/output_width, &int_part); + frac_col = modf(width_scaling*i, &int_part); x = 3*int_part; for (j = 0; j < 3; j++) { @@ -420,7 +425,7 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[]) buf16[3*i + j] = saturateu16(c1 + (((c2 - c1)*frac_row) >> 8)); } #else - frac_col = modf((double) i*input_width/output_width, &int_part); + frac_col = modf(width_scaling*i, &int_part); x = 3*int_part; for (j = 0; j < 3; j++) { @@ -445,7 +450,7 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[]) c2 = row8[1][x] + (((row8[1][x + 1] - row8[1][x])*frac_col) >> 8); buf[i] = saturateu8(c1 + (((c2 - c1)*frac_row) >> 8)); #else - frac_col = modf((double) i*input_width/output_width, &int_part); + frac_col = modf(width_scaling*i, &int_part); x = int_part; c1 = row8[0][x] + (row8[0][x + 1] - row8[0][x])*frac_col; c2 = row8[1][x] + (row8[1][x + 1] - row8[1][x])*frac_col; @@ -467,7 +472,7 @@ static int image_resize_row(image_translate_state_t *s, uint8_t buf[]) c2 = row16[1][x] + (((row16[1][x + 1] - row16[1][x])*frac_col) >> 8); buf[i] = saturateu8(c1 + (((c2 - c1)*frac_row) >> 8)); #else - frac_col = modf((double) i*input_width/output_width, &int_part); + frac_col = modf(width_scaling*i, &int_part); x = int_part; c1 = row16[0][x] + (row16[0][x + 1] - row16[0][x])*frac_col; c2 = row16[1][x] + (row16[1][x + 1] - row16[1][x])*frac_col; @@ -611,12 +616,14 @@ SPAN_DECLARE(int) image_translate_row(image_translate_state_t *s, uint8_t buf[], if (s->output_row < 0) return 0; - if (s->output_format == T4_IMAGE_TYPE_BILEVEL) + switch (s->output_format) { + case T4_IMAGE_TYPE_BILEVEL: + case T4_IMAGE_TYPE_COLOUR_BILEVEL: + case T4_IMAGE_TYPE_4COLOUR_BILEVEL: i = floyd_steinberg_dither_row(s, buf); - } - else - { + break; + default: s->output_row++; if (s->resize) { @@ -631,6 +638,7 @@ SPAN_DECLARE(int) image_translate_row(image_translate_state_t *s, uint8_t buf[], if (s->output_row < 0) return 0; i = s->output_width*s->output_bytes_per_pixel; + break; } return i; } @@ -648,84 +656,50 @@ SPAN_DECLARE(int) image_translate_get_output_length(image_translate_state_t *s) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(image_translate_state_t *) image_translate_init(image_translate_state_t *s, - int input_format, - int input_width, - int input_length, - int output_format, - int output_width, - int output_length, - t4_row_read_handler_t row_read_handler, - void *row_read_user_data) +SPAN_DECLARE(int) image_translate_set_row_read_handler(image_translate_state_t *s, t4_row_read_handler_t row_read_handler, void *row_read_user_data) +{ + s->row_read_handler = row_read_handler; + s->row_read_user_data = row_read_user_data; + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int image_format_to_bytes_per_pixel(int image_format) +{ + switch (image_format) + { + default: + case T4_IMAGE_TYPE_BILEVEL: + case T4_IMAGE_TYPE_GRAY_8BIT: + return 1; + case T4_IMAGE_TYPE_GRAY_12BIT: + return 2; + case T4_IMAGE_TYPE_COLOUR_BILEVEL: + case T4_IMAGE_TYPE_COLOUR_8BIT: + return 3; + case T4_IMAGE_TYPE_4COLOUR_BILEVEL: + case T4_IMAGE_TYPE_4COLOUR_8BIT: + return 4; + case T4_IMAGE_TYPE_COLOUR_12BIT: + return 6; + case T4_IMAGE_TYPE_4COLOUR_12BIT: + return 8; + } + return 1; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) image_translate_restart(image_translate_state_t *s, int input_length) { int i; int raw_row_size; int row_size; - if (s == NULL) - { - if ((s = (image_translate_state_t *) malloc(sizeof(*s))) == NULL) - return NULL; - } - memset(s, 0, sizeof(*s)); - - s->input_format = input_format; - s->input_width = input_width; s->input_length = input_length; - - s->output_format = output_format; - - if ((s->resize = (output_width > 0))) - { - s->output_width = output_width; - if (output_length > 0) - s->output_length = output_length; - else - s->output_length = (s->input_length*s->output_width)/s->input_width; - } + if (s->resize) + s->output_length = (s->input_length*s->output_width)/s->input_width; else - { - s->output_width = s->input_width; s->output_length = s->input_length; - } - - switch (s->input_format) - { - case T4_IMAGE_TYPE_GRAY_8BIT: - s->input_bytes_per_pixel = 1; - break; - case T4_IMAGE_TYPE_GRAY_12BIT: - s->input_bytes_per_pixel = 2; - break; - case T4_IMAGE_TYPE_COLOUR_8BIT: - s->input_bytes_per_pixel = 3; - break; - case T4_IMAGE_TYPE_COLOUR_12BIT: - s->input_bytes_per_pixel = 6; - break; - default: - s->input_bytes_per_pixel = 1; - break; - } - - switch (s->output_format) - { - case T4_IMAGE_TYPE_GRAY_8BIT: - s->output_bytes_per_pixel = 1; - break; - case T4_IMAGE_TYPE_GRAY_12BIT: - s->output_bytes_per_pixel = 2; - break; - case T4_IMAGE_TYPE_COLOUR_8BIT: - s->output_bytes_per_pixel = 3; - break; - case T4_IMAGE_TYPE_COLOUR_12BIT: - s->output_bytes_per_pixel = 6; - break; - default: - s->output_bytes_per_pixel = 1; - break; - } /* Allocate the two row buffers we need, using the space requirements we now have */ raw_row_size = s->input_width*s->input_bytes_per_pixel; @@ -736,30 +710,78 @@ SPAN_DECLARE(image_translate_state_t *) image_translate_init(image_translate_sta { for (i = 0; i < 2; i++) { - if ((s->raw_pixel_row[i] = (uint8_t *) malloc(raw_row_size)) == NULL) - return NULL; + if (s->raw_pixel_row[i] == NULL) + { + if ((s->raw_pixel_row[i] = (uint8_t *) span_alloc(raw_row_size)) == NULL) + return -1; + } memset(s->raw_pixel_row[i], 0, raw_row_size); } } - if (s->output_format == T4_IMAGE_TYPE_BILEVEL) + switch (s->output_format) { + case T4_IMAGE_TYPE_BILEVEL: + case T4_IMAGE_TYPE_COLOUR_BILEVEL: + case T4_IMAGE_TYPE_4COLOUR_BILEVEL: if (s->resize) raw_row_size = row_size; for (i = 0; i < 2; i++) { - if ((s->pixel_row[i] = (uint8_t *) malloc(raw_row_size)) == NULL) - return NULL; + if (s->pixel_row[i] == NULL) + { + if ((s->pixel_row[i] = (uint8_t *) span_alloc(raw_row_size)) == NULL) + return -1; + } memset(s->pixel_row[i], 0, raw_row_size); } + break; } - s->row_read_handler = row_read_handler; - s->row_read_user_data = row_read_user_data; - s->raw_input_row = 0; s->raw_output_row = 0; s->output_row = 0; + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(image_translate_state_t *) image_translate_init(image_translate_state_t *s, + int output_format, + int output_width, + int output_length, + int input_format, + int input_width, + int input_length, + t4_row_read_handler_t row_read_handler, + void *row_read_user_data) +{ + if (s == NULL) + { + if ((s = (image_translate_state_t *) span_alloc(sizeof(*s))) == NULL) + return NULL; + } + memset(s, 0, sizeof(*s)); + + s->row_read_handler = row_read_handler; + s->row_read_user_data = row_read_user_data; + + s->input_format = input_format; + s->input_width = input_width; + s->input_length = input_length; + s->input_bytes_per_pixel = image_format_to_bytes_per_pixel(s->input_format); + + s->output_format = output_format; + s->output_bytes_per_pixel = image_format_to_bytes_per_pixel(s->output_format); + + s->resize = (output_width > 0); + if (s->resize) + s->output_width = output_width; + else + s->output_width = s->input_width; + + if (image_translate_restart(s, input_length)) + return NULL; + return s; } /*- End of function --------------------------------------------------------*/ @@ -772,12 +794,12 @@ SPAN_DECLARE(int) image_translate_release(image_translate_state_t *s) { if (s->raw_pixel_row[i]) { - free(s->raw_pixel_row[i]); + span_free(s->raw_pixel_row[i]); s->raw_pixel_row[i] = NULL; } if (s->pixel_row[i]) { - free(s->pixel_row[i]); + span_free(s->pixel_row[i]); s->pixel_row[i] = NULL; } } @@ -790,7 +812,7 @@ SPAN_DECLARE(int) image_translate_free(image_translate_state_t *s) int res; res = image_translate_release(s); - free(s); + span_free(s); return res; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/libspandsp.2010.vcxproj b/libs/spandsp/src/libspandsp.2010.vcxproj index 1697ba19a5..02d6ca77e0 100644 --- a/libs/spandsp/src/libspandsp.2010.vcxproj +++ b/libs/spandsp/src/libspandsp.2010.vcxproj @@ -157,6 +157,7 @@ + @@ -210,6 +211,7 @@ + @@ -293,6 +295,7 @@ + @@ -304,6 +307,7 @@ + @@ -437,6 +441,10 @@ {329a6fa0-0fcc-4435-a950-e670aefa9838} false + + {eddb8ab9-c53e-44c0-a620-0e86c2cbd5d5} + false + diff --git a/libs/spandsp/src/libspandsp.2010.vcxproj.filters b/libs/spandsp/src/libspandsp.2010.vcxproj.filters index 05763b180c..dea495c328 100644 --- a/libs/spandsp/src/libspandsp.2010.vcxproj.filters +++ b/libs/spandsp/src/libspandsp.2010.vcxproj.filters @@ -283,6 +283,12 @@ Source Files + + Source Files + + + Source Files + @@ -722,6 +728,12 @@ Header Files + + Header Files + + + Header Files + diff --git a/libs/spandsp/src/libspandsp.2012.sln b/libs/spandsp/src/libspandsp.2012.sln new file mode 100644 index 0000000000..c0cc75f4e3 --- /dev/null +++ b/libs/spandsp/src/libspandsp.2012.sln @@ -0,0 +1,318 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2012 for Windows Desktop +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_at_dictionary", "msvc\make_at_dictionary.2012.vcxproj", "{DEE932AB-5911-4700-9EEB-8C7090A0A330}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_modem_filter", "msvc\make_modem_filter.2012.vcxproj", "{329A6FA0-0FCC-4435-A950-E670AEFA9838}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_t43_gray_code_tables", "msvc\make_t43_gray_code_tables.2012.vcxproj", "{EDDB8AB9-C53E-44C0-A620-0E86C2CBD5D5}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_cielab_luts", "msvc\make_cielab_luts.2012.vcxproj", "{85F0CF8C-C7AB-48F6-BA19-CC94CF87F981}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_math_fixed_tables", "msvc\make_math_fixed_tables.2012.vcxproj", "{2386B892-35F5-46CF-A0F0-10394D2FBF9B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspandsp", "libspandsp.2012.vcxproj", "{1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}" + ProjectSection(ProjectDependencies) = postProject + {329A6FA0-0FCC-4435-A950-E670AEFA9838} = {329A6FA0-0FCC-4435-A950-E670AEFA9838} + {DEE932AB-5911-4700-9EEB-8C7090A0A330} = {DEE932AB-5911-4700-9EEB-8C7090A0A330} + {401A40CD-5DB4-4E34-AC68-FA99E9FAC014} = {401A40CD-5DB4-4E34-AC68-FA99E9FAC014} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_line_models", "..\spandsp-sim\msvc\make_line_models.2012.vcxproj", "{F290BADE-82DE-4037-B49D-D563E43169DA}" + ProjectSection(ProjectDependencies) = postProject + {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5} = {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspandsp_sim", "..\spandsp-sim\libspandsp_sim.2012.vcxproj", "{502F1E51-F0A0-4607-AB7F-05BAB530AAE1}" + ProjectSection(ProjectDependencies) = postProject + {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5} = {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "download libjpeg", "msvc\download_libjpeg.2012.vcxproj", "{652AD5F7-8488-489F-AAD0-7FBE064703B6}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "download libtiff", "msvc\download_libtiff.2012.vcxproj", "{2B8A45C9-FEB4-4734-AB37-8DB9DB899917}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libjpeg", "msvc\libjpeg.2012.vcxproj", "{019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}" + ProjectSection(ProjectDependencies) = postProject + {652AD5F7-8488-489F-AAD0-7FBE064703B6} = {652AD5F7-8488-489F-AAD0-7FBE064703B6} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtiff", "msvc\libtiff.2012.vcxproj", "{401A40CD-5DB4-4E34-AC68-FA99E9FAC014}" + ProjectSection(ProjectDependencies) = postProject + {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1} = {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1} + {652AD5F7-8488-489F-AAD0-7FBE064703B6} = {652AD5F7-8488-489F-AAD0-7FBE064703B6} + {2B8A45C9-FEB4-4734-AB37-8DB9DB899917} = {2B8A45C9-FEB4-4734-AB37-8DB9DB899917} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "t38_core_tests", "..\tests\msvc\t38_core_tests.2012.vcxproj", "{A34A9D0E-A7E2-4A04-B044-7BB2FE709EF3}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "t38_non_ecm_buffer_tests", "..\tests\msvc\t38_non_ecm_buffer_tests.2012.vcxproj", "{80A3D9D9-3846-4DA5-8676-F940D725EA62}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vector_int_tests", "..\tests\msvc\vector_int_tests.2012.vcxproj", "{80A60464-29E8-4EE8-BAFA-8708B7C08CC3}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vector_float_tests", "..\tests\msvc\vector_float_tests.2012.vcxproj", "{EA745FF7-9E4B-4C13-BA19-2EE8165A6245}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "complex_tests", "..\tests\msvc\complex_tests.2012.vcxproj", "{A349379F-0FEA-49C8-9535-05F39663337B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "complex_vector_float_tests", "..\tests\msvc\complex_vector_float_tests.2012.vcxproj", "{2B0D705C-1CF2-401C-BFBC-A43FB806908C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "complex_vector_int_tests", "..\tests\msvc\complex_vector_int_tests.2012.vcxproj", "{C2E8B4D1-A398-4D57-94F8-B61F20C7D514}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "queue_tests", "..\tests\msvc\queue_tests.2012.vcxproj", "{D9C0F575-83E7-4C15-BF71-D7A0D44A26BF}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dtmf_tx_tests", "..\tests\msvc\dtmf_tx_tests.2012.vcxproj", "{1577F41D-9A06-45DD-87D4-9ADCC9CCDAD5}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dtmf_rx_tests", "..\tests\msvc\dtmf_rx_tests.2012.vcxproj", "{24E7EF80-7854-4A21-80FB-31C4E71109DE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "v29_tests", "..\tests\msvc\v29_tests.2012.vcxproj", "{323BD962-4581-4561-8105-8C166A9FA933}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "v80_tests", "..\tests\msvc\v80_tests.2012.vcxproj", "{10263F04-37DD-4E4A-AE4F-0641B018B714}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "v22bis_tests", "..\tests\msvc\v22bis_tests.2012.vcxproj", "{DA4DB99F-E5BA-48BD-BB6B-3595CE24CBAE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "v8_tests", "..\tests\msvc\v8_tests.2012.vcxproj", "{0C69B8C2-0CE1-4CD4-870C-1C13FB3F9B34}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C84E437E-9D4C-46C8-9724-DF301C849E61}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + All|Win32 = All|Win32 + All|x64 = All|x64 + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DEE932AB-5911-4700-9EEB-8C7090A0A330}.All|Win32.ActiveCfg = All|Win32 + {DEE932AB-5911-4700-9EEB-8C7090A0A330}.All|Win32.Build.0 = All|Win32 + {DEE932AB-5911-4700-9EEB-8C7090A0A330}.All|x64.ActiveCfg = All|Win32 + {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Debug|Win32.ActiveCfg = All|Win32 + {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Debug|Win32.Build.0 = All|Win32 + {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Debug|x64.ActiveCfg = All|Win32 + {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Release|Win32.ActiveCfg = All|Win32 + {DEE932AB-5911-4700-9EEB-8C7090A0A330}.Release|x64.ActiveCfg = All|Win32 + {329A6FA0-0FCC-4435-A950-E670AEFA9838}.All|Win32.ActiveCfg = All|Win32 + {329A6FA0-0FCC-4435-A950-E670AEFA9838}.All|Win32.Build.0 = All|Win32 + {329A6FA0-0FCC-4435-A950-E670AEFA9838}.All|x64.ActiveCfg = All|Win32 + {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Debug|Win32.ActiveCfg = All|Win32 + {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Debug|Win32.Build.0 = All|Win32 + {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Debug|x64.ActiveCfg = All|Win32 + {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Release|Win32.ActiveCfg = All|Win32 + {329A6FA0-0FCC-4435-A950-E670AEFA9838}.Release|x64.ActiveCfg = All|Win32 + {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.All|Win32.ActiveCfg = Release|x64 + {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.All|x64.ActiveCfg = Release|x64 + {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.All|x64.Build.0 = Release|x64 + {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Debug|Win32.ActiveCfg = Debug|Win32 + {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Debug|Win32.Build.0 = Debug|Win32 + {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Debug|x64.ActiveCfg = Debug|x64 + {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Debug|x64.Build.0 = Debug|x64 + {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Release|Win32.ActiveCfg = Release|Win32 + {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Release|Win32.Build.0 = Release|Win32 + {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Release|x64.ActiveCfg = Release|x64 + {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5}.Release|x64.Build.0 = Release|x64 + {F290BADE-82DE-4037-B49D-D563E43169DA}.All|Win32.ActiveCfg = All|Win32 + {F290BADE-82DE-4037-B49D-D563E43169DA}.All|Win32.Build.0 = All|Win32 + {F290BADE-82DE-4037-B49D-D563E43169DA}.All|x64.ActiveCfg = All|Win32 + {F290BADE-82DE-4037-B49D-D563E43169DA}.Debug|Win32.ActiveCfg = All|Win32 + {F290BADE-82DE-4037-B49D-D563E43169DA}.Debug|Win32.Build.0 = All|Win32 + {F290BADE-82DE-4037-B49D-D563E43169DA}.Debug|x64.ActiveCfg = All|Win32 + {F290BADE-82DE-4037-B49D-D563E43169DA}.Release|Win32.ActiveCfg = All|Win32 + {F290BADE-82DE-4037-B49D-D563E43169DA}.Release|Win32.Build.0 = All|Win32 + {F290BADE-82DE-4037-B49D-D563E43169DA}.Release|x64.ActiveCfg = All|Win32 + {502F1E51-F0A0-4607-AB7F-05BAB530AAE1}.All|Win32.ActiveCfg = Release|Win32 + {502F1E51-F0A0-4607-AB7F-05BAB530AAE1}.All|Win32.Build.0 = Release|Win32 + {502F1E51-F0A0-4607-AB7F-05BAB530AAE1}.All|x64.ActiveCfg = Release|Win32 + {502F1E51-F0A0-4607-AB7F-05BAB530AAE1}.Debug|Win32.ActiveCfg = Debug|Win32 + {502F1E51-F0A0-4607-AB7F-05BAB530AAE1}.Debug|Win32.Build.0 = Debug|Win32 + {502F1E51-F0A0-4607-AB7F-05BAB530AAE1}.Debug|x64.ActiveCfg = Debug|Win32 + {502F1E51-F0A0-4607-AB7F-05BAB530AAE1}.Release|Win32.ActiveCfg = Release|Win32 + {502F1E51-F0A0-4607-AB7F-05BAB530AAE1}.Release|Win32.Build.0 = Release|Win32 + {502F1E51-F0A0-4607-AB7F-05BAB530AAE1}.Release|x64.ActiveCfg = Release|Win32 + {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.All|Win32.ActiveCfg = Release|x64 + {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.All|x64.ActiveCfg = Release|x64 + {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.All|x64.Build.0 = Release|x64 + {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Debug|Win32.ActiveCfg = Debug|Win32 + {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Debug|Win32.Build.0 = Debug|Win32 + {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Debug|x64.ActiveCfg = Debug|x64 + {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Debug|x64.Build.0 = Debug|x64 + {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Release|Win32.ActiveCfg = Release|Win32 + {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Release|Win32.Build.0 = Release|Win32 + {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Release|x64.ActiveCfg = Release|x64 + {401A40CD-5DB4-4E34-AC68-FA99E9FAC014}.Release|x64.Build.0 = Release|x64 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.All|Win32.ActiveCfg = All|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.All|Win32.Build.0 = All|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.All|x64.ActiveCfg = All|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Debug|Win32.ActiveCfg = All|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Debug|Win32.Build.0 = All|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Debug|x64.ActiveCfg = All|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Release|Win32.ActiveCfg = All|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Release|Win32.Build.0 = All|Win32 + {652AD5F7-8488-489F-AAD0-7FBE064703B6}.Release|x64.ActiveCfg = All|Win32 + {2B8A45C9-FEB4-4734-AB37-8DB9DB899917}.All|Win32.ActiveCfg = All|Win32 + {2B8A45C9-FEB4-4734-AB37-8DB9DB899917}.All|Win32.Build.0 = All|Win32 + {2B8A45C9-FEB4-4734-AB37-8DB9DB899917}.All|x64.ActiveCfg = All|Win32 + {2B8A45C9-FEB4-4734-AB37-8DB9DB899917}.Debug|Win32.ActiveCfg = All|Win32 + {2B8A45C9-FEB4-4734-AB37-8DB9DB899917}.Debug|Win32.Build.0 = All|Win32 + {2B8A45C9-FEB4-4734-AB37-8DB9DB899917}.Debug|x64.ActiveCfg = All|Win32 + {2B8A45C9-FEB4-4734-AB37-8DB9DB899917}.Release|Win32.ActiveCfg = All|Win32 + {2B8A45C9-FEB4-4734-AB37-8DB9DB899917}.Release|Win32.Build.0 = All|Win32 + {2B8A45C9-FEB4-4734-AB37-8DB9DB899917}.Release|x64.ActiveCfg = All|Win32 + {A34A9D0E-A7E2-4A04-B044-7BB2FE709EF3}.All|Win32.ActiveCfg = Release|Win32 + {A34A9D0E-A7E2-4A04-B044-7BB2FE709EF3}.All|Win32.Build.0 = Release|Win32 + {A34A9D0E-A7E2-4A04-B044-7BB2FE709EF3}.All|x64.ActiveCfg = Release|Win32 + {A34A9D0E-A7E2-4A04-B044-7BB2FE709EF3}.Debug|Win32.ActiveCfg = Debug|Win32 + {A34A9D0E-A7E2-4A04-B044-7BB2FE709EF3}.Debug|Win32.Build.0 = Debug|Win32 + {A34A9D0E-A7E2-4A04-B044-7BB2FE709EF3}.Debug|x64.ActiveCfg = Debug|Win32 + {A34A9D0E-A7E2-4A04-B044-7BB2FE709EF3}.Release|Win32.ActiveCfg = Release|Win32 + {A34A9D0E-A7E2-4A04-B044-7BB2FE709EF3}.Release|Win32.Build.0 = Release|Win32 + {A34A9D0E-A7E2-4A04-B044-7BB2FE709EF3}.Release|x64.ActiveCfg = Release|Win32 + {80A3D9D9-3846-4DA5-8676-F940D725EA62}.All|Win32.ActiveCfg = Release|Win32 + {80A3D9D9-3846-4DA5-8676-F940D725EA62}.All|Win32.Build.0 = Release|Win32 + {80A3D9D9-3846-4DA5-8676-F940D725EA62}.All|x64.ActiveCfg = Release|Win32 + {80A3D9D9-3846-4DA5-8676-F940D725EA62}.Debug|Win32.ActiveCfg = Debug|Win32 + {80A3D9D9-3846-4DA5-8676-F940D725EA62}.Debug|Win32.Build.0 = Debug|Win32 + {80A3D9D9-3846-4DA5-8676-F940D725EA62}.Debug|x64.ActiveCfg = Debug|Win32 + {80A3D9D9-3846-4DA5-8676-F940D725EA62}.Release|Win32.ActiveCfg = Release|Win32 + {80A3D9D9-3846-4DA5-8676-F940D725EA62}.Release|Win32.Build.0 = Release|Win32 + {80A3D9D9-3846-4DA5-8676-F940D725EA62}.Release|x64.ActiveCfg = Release|Win32 + {80A60464-29E8-4EE8-BAFA-8708B7C08CC3}.All|Win32.ActiveCfg = Release|Win32 + {80A60464-29E8-4EE8-BAFA-8708B7C08CC3}.All|Win32.Build.0 = Release|Win32 + {80A60464-29E8-4EE8-BAFA-8708B7C08CC3}.All|x64.ActiveCfg = Release|Win32 + {80A60464-29E8-4EE8-BAFA-8708B7C08CC3}.Debug|Win32.ActiveCfg = Debug|Win32 + {80A60464-29E8-4EE8-BAFA-8708B7C08CC3}.Debug|Win32.Build.0 = Debug|Win32 + {80A60464-29E8-4EE8-BAFA-8708B7C08CC3}.Debug|x64.ActiveCfg = Debug|Win32 + {80A60464-29E8-4EE8-BAFA-8708B7C08CC3}.Release|Win32.ActiveCfg = Release|Win32 + {80A60464-29E8-4EE8-BAFA-8708B7C08CC3}.Release|Win32.Build.0 = Release|Win32 + {80A60464-29E8-4EE8-BAFA-8708B7C08CC3}.Release|x64.ActiveCfg = Release|Win32 + {EA745FF7-9E4B-4C13-BA19-2EE8165A6245}.All|Win32.ActiveCfg = Release|Win32 + {EA745FF7-9E4B-4C13-BA19-2EE8165A6245}.All|Win32.Build.0 = Release|Win32 + {EA745FF7-9E4B-4C13-BA19-2EE8165A6245}.All|x64.ActiveCfg = Release|Win32 + {EA745FF7-9E4B-4C13-BA19-2EE8165A6245}.Debug|Win32.ActiveCfg = Debug|Win32 + {EA745FF7-9E4B-4C13-BA19-2EE8165A6245}.Debug|Win32.Build.0 = Debug|Win32 + {EA745FF7-9E4B-4C13-BA19-2EE8165A6245}.Debug|x64.ActiveCfg = Debug|Win32 + {EA745FF7-9E4B-4C13-BA19-2EE8165A6245}.Release|Win32.ActiveCfg = Release|Win32 + {EA745FF7-9E4B-4C13-BA19-2EE8165A6245}.Release|Win32.Build.0 = Release|Win32 + {EA745FF7-9E4B-4C13-BA19-2EE8165A6245}.Release|x64.ActiveCfg = Release|Win32 + {A349379F-0FEA-49C8-9535-05F39663337B}.All|Win32.ActiveCfg = Release|Win32 + {A349379F-0FEA-49C8-9535-05F39663337B}.All|Win32.Build.0 = Release|Win32 + {A349379F-0FEA-49C8-9535-05F39663337B}.All|x64.ActiveCfg = Release|Win32 + {A349379F-0FEA-49C8-9535-05F39663337B}.Debug|Win32.ActiveCfg = Debug|Win32 + {A349379F-0FEA-49C8-9535-05F39663337B}.Debug|Win32.Build.0 = Debug|Win32 + {A349379F-0FEA-49C8-9535-05F39663337B}.Debug|x64.ActiveCfg = Debug|Win32 + {A349379F-0FEA-49C8-9535-05F39663337B}.Release|Win32.ActiveCfg = Release|Win32 + {A349379F-0FEA-49C8-9535-05F39663337B}.Release|Win32.Build.0 = Release|Win32 + {A349379F-0FEA-49C8-9535-05F39663337B}.Release|x64.ActiveCfg = Release|Win32 + {2B0D705C-1CF2-401C-BFBC-A43FB806908C}.All|Win32.ActiveCfg = Release|Win32 + {2B0D705C-1CF2-401C-BFBC-A43FB806908C}.All|Win32.Build.0 = Release|Win32 + {2B0D705C-1CF2-401C-BFBC-A43FB806908C}.All|x64.ActiveCfg = Release|Win32 + {2B0D705C-1CF2-401C-BFBC-A43FB806908C}.Debug|Win32.ActiveCfg = Debug|Win32 + {2B0D705C-1CF2-401C-BFBC-A43FB806908C}.Debug|Win32.Build.0 = Debug|Win32 + {2B0D705C-1CF2-401C-BFBC-A43FB806908C}.Debug|x64.ActiveCfg = Debug|Win32 + {2B0D705C-1CF2-401C-BFBC-A43FB806908C}.Release|Win32.ActiveCfg = Release|Win32 + {2B0D705C-1CF2-401C-BFBC-A43FB806908C}.Release|Win32.Build.0 = Release|Win32 + {2B0D705C-1CF2-401C-BFBC-A43FB806908C}.Release|x64.ActiveCfg = Release|Win32 + {C2E8B4D1-A398-4D57-94F8-B61F20C7D514}.All|Win32.ActiveCfg = Release|Win32 + {C2E8B4D1-A398-4D57-94F8-B61F20C7D514}.All|Win32.Build.0 = Release|Win32 + {C2E8B4D1-A398-4D57-94F8-B61F20C7D514}.All|x64.ActiveCfg = Release|Win32 + {C2E8B4D1-A398-4D57-94F8-B61F20C7D514}.Debug|Win32.ActiveCfg = Debug|Win32 + {C2E8B4D1-A398-4D57-94F8-B61F20C7D514}.Debug|Win32.Build.0 = Debug|Win32 + {C2E8B4D1-A398-4D57-94F8-B61F20C7D514}.Debug|x64.ActiveCfg = Debug|Win32 + {C2E8B4D1-A398-4D57-94F8-B61F20C7D514}.Release|Win32.ActiveCfg = Release|Win32 + {C2E8B4D1-A398-4D57-94F8-B61F20C7D514}.Release|Win32.Build.0 = Release|Win32 + {C2E8B4D1-A398-4D57-94F8-B61F20C7D514}.Release|x64.ActiveCfg = Release|Win32 + {EDDB8AB9-C53E-44C0-A620-0E86C2CBD5D5}.All|Win32.ActiveCfg = All|Win32 + {EDDB8AB9-C53E-44C0-A620-0E86C2CBD5D5}.All|Win32.Build.0 = All|Win32 + {EDDB8AB9-C53E-44C0-A620-0E86C2CBD5D5}.All|x64.ActiveCfg = All|Win32 + {EDDB8AB9-C53E-44C0-A620-0E86C2CBD5D5}.Debug|Win32.ActiveCfg = All|Win32 + {EDDB8AB9-C53E-44C0-A620-0E86C2CBD5D5}.Debug|Win32.Build.0 = All|Win32 + {EDDB8AB9-C53E-44C0-A620-0E86C2CBD5D5}.Debug|x64.ActiveCfg = All|Win32 + {EDDB8AB9-C53E-44C0-A620-0E86C2CBD5D5}.Release|Win32.ActiveCfg = All|Win32 + {EDDB8AB9-C53E-44C0-A620-0E86C2CBD5D5}.Release|Win32.Build.0 = All|Win32 + {EDDB8AB9-C53E-44C0-A620-0E86C2CBD5D5}.Release|x64.ActiveCfg = All|Win32 + {85F0CF8C-C7AB-48F6-BA19-CC94CF87F981}.All|Win32.ActiveCfg = All|Win32 + {85F0CF8C-C7AB-48F6-BA19-CC94CF87F981}.All|Win32.Build.0 = All|Win32 + {85F0CF8C-C7AB-48F6-BA19-CC94CF87F981}.All|x64.ActiveCfg = All|Win32 + {85F0CF8C-C7AB-48F6-BA19-CC94CF87F981}.Debug|Win32.ActiveCfg = All|Win32 + {85F0CF8C-C7AB-48F6-BA19-CC94CF87F981}.Debug|Win32.Build.0 = All|Win32 + {85F0CF8C-C7AB-48F6-BA19-CC94CF87F981}.Debug|x64.ActiveCfg = All|Win32 + {85F0CF8C-C7AB-48F6-BA19-CC94CF87F981}.Release|Win32.ActiveCfg = All|Win32 + {85F0CF8C-C7AB-48F6-BA19-CC94CF87F981}.Release|Win32.Build.0 = All|Win32 + {85F0CF8C-C7AB-48F6-BA19-CC94CF87F981}.Release|x64.ActiveCfg = All|Win32 + {2386B892-35F5-46CF-A0F0-10394D2FBF9B}.All|Win32.ActiveCfg = All|Win32 + {2386B892-35F5-46CF-A0F0-10394D2FBF9B}.All|Win32.Build.0 = All|Win32 + {2386B892-35F5-46CF-A0F0-10394D2FBF9B}.All|x64.ActiveCfg = All|Win32 + {2386B892-35F5-46CF-A0F0-10394D2FBF9B}.Debug|Win32.ActiveCfg = All|Win32 + {2386B892-35F5-46CF-A0F0-10394D2FBF9B}.Debug|Win32.Build.0 = All|Win32 + {2386B892-35F5-46CF-A0F0-10394D2FBF9B}.Debug|x64.ActiveCfg = All|Win32 + {2386B892-35F5-46CF-A0F0-10394D2FBF9B}.Release|Win32.ActiveCfg = All|Win32 + {2386B892-35F5-46CF-A0F0-10394D2FBF9B}.Release|Win32.Build.0 = All|Win32 + {2386B892-35F5-46CF-A0F0-10394D2FBF9B}.Release|x64.ActiveCfg = All|Win32 + {D9C0F575-83E7-4C15-BF71-D7A0D44A26BF}.All|Win32.ActiveCfg = Release|Win32 + {D9C0F575-83E7-4C15-BF71-D7A0D44A26BF}.All|Win32.Build.0 = Release|Win32 + {D9C0F575-83E7-4C15-BF71-D7A0D44A26BF}.All|x64.ActiveCfg = Release|Win32 + {D9C0F575-83E7-4C15-BF71-D7A0D44A26BF}.Debug|Win32.ActiveCfg = Debug|Win32 + {D9C0F575-83E7-4C15-BF71-D7A0D44A26BF}.Debug|Win32.Build.0 = Debug|Win32 + {D9C0F575-83E7-4C15-BF71-D7A0D44A26BF}.Debug|x64.ActiveCfg = Debug|Win32 + {D9C0F575-83E7-4C15-BF71-D7A0D44A26BF}.Release|Win32.ActiveCfg = Release|Win32 + {D9C0F575-83E7-4C15-BF71-D7A0D44A26BF}.Release|Win32.Build.0 = Release|Win32 + {D9C0F575-83E7-4C15-BF71-D7A0D44A26BF}.Release|x64.ActiveCfg = Release|Win32 + {1577F41D-9A06-45DD-87D4-9ADCC9CCDAD5}.All|Win32.ActiveCfg = Release|Win32 + {1577F41D-9A06-45DD-87D4-9ADCC9CCDAD5}.All|Win32.Build.0 = Release|Win32 + {1577F41D-9A06-45DD-87D4-9ADCC9CCDAD5}.All|x64.ActiveCfg = Release|Win32 + {1577F41D-9A06-45DD-87D4-9ADCC9CCDAD5}.Debug|Win32.ActiveCfg = Debug|Win32 + {1577F41D-9A06-45DD-87D4-9ADCC9CCDAD5}.Debug|Win32.Build.0 = Debug|Win32 + {1577F41D-9A06-45DD-87D4-9ADCC9CCDAD5}.Debug|x64.ActiveCfg = Debug|Win32 + {1577F41D-9A06-45DD-87D4-9ADCC9CCDAD5}.Release|Win32.ActiveCfg = Release|Win32 + {1577F41D-9A06-45DD-87D4-9ADCC9CCDAD5}.Release|Win32.Build.0 = Release|Win32 + {1577F41D-9A06-45DD-87D4-9ADCC9CCDAD5}.Release|x64.ActiveCfg = Release|Win32 + {24E7EF80-7854-4A21-80FB-31C4E71109DE}.All|Win32.ActiveCfg = Release|Win32 + {24E7EF80-7854-4A21-80FB-31C4E71109DE}.All|Win32.Build.0 = Release|Win32 + {24E7EF80-7854-4A21-80FB-31C4E71109DE}.All|x64.ActiveCfg = Release|Win32 + {24E7EF80-7854-4A21-80FB-31C4E71109DE}.Debug|Win32.ActiveCfg = Debug|Win32 + {24E7EF80-7854-4A21-80FB-31C4E71109DE}.Debug|Win32.Build.0 = Debug|Win32 + {24E7EF80-7854-4A21-80FB-31C4E71109DE}.Debug|x64.ActiveCfg = Debug|Win32 + {24E7EF80-7854-4A21-80FB-31C4E71109DE}.Release|Win32.ActiveCfg = Release|Win32 + {24E7EF80-7854-4A21-80FB-31C4E71109DE}.Release|Win32.Build.0 = Release|Win32 + {24E7EF80-7854-4A21-80FB-31C4E71109DE}.Release|x64.ActiveCfg = Release|Win32 + {323BD962-4581-4561-8105-8C166A9FA933}.All|Win32.ActiveCfg = Release|Win32 + {323BD962-4581-4561-8105-8C166A9FA933}.All|Win32.Build.0 = Release|Win32 + {323BD962-4581-4561-8105-8C166A9FA933}.All|x64.ActiveCfg = Release|Win32 + {323BD962-4581-4561-8105-8C166A9FA933}.Debug|Win32.ActiveCfg = Debug|Win32 + {323BD962-4581-4561-8105-8C166A9FA933}.Debug|Win32.Build.0 = Debug|Win32 + {323BD962-4581-4561-8105-8C166A9FA933}.Debug|x64.ActiveCfg = Debug|Win32 + {323BD962-4581-4561-8105-8C166A9FA933}.Release|Win32.ActiveCfg = Release|Win32 + {323BD962-4581-4561-8105-8C166A9FA933}.Release|Win32.Build.0 = Release|Win32 + {323BD962-4581-4561-8105-8C166A9FA933}.Release|x64.ActiveCfg = Release|Win32 + {10263F04-37DD-4E4A-AE4F-0641B018B714}.All|Win32.ActiveCfg = Release|Win32 + {10263F04-37DD-4E4A-AE4F-0641B018B714}.All|Win32.Build.0 = Release|Win32 + {10263F04-37DD-4E4A-AE4F-0641B018B714}.All|x64.ActiveCfg = Release|Win32 + {10263F04-37DD-4E4A-AE4F-0641B018B714}.Debug|Win32.ActiveCfg = Debug|Win32 + {10263F04-37DD-4E4A-AE4F-0641B018B714}.Debug|Win32.Build.0 = Debug|Win32 + {10263F04-37DD-4E4A-AE4F-0641B018B714}.Debug|x64.ActiveCfg = Debug|Win32 + {10263F04-37DD-4E4A-AE4F-0641B018B714}.Release|Win32.ActiveCfg = Release|Win32 + {10263F04-37DD-4E4A-AE4F-0641B018B714}.Release|Win32.Build.0 = Release|Win32 + {10263F04-37DD-4E4A-AE4F-0641B018B714}.Release|x64.ActiveCfg = Release|Win32 + {DA4DB99F-E5BA-48BD-BB6B-3595CE24CBAE}.All|Win32.ActiveCfg = Release|Win32 + {DA4DB99F-E5BA-48BD-BB6B-3595CE24CBAE}.All|Win32.Build.0 = Release|Win32 + {DA4DB99F-E5BA-48BD-BB6B-3595CE24CBAE}.All|x64.ActiveCfg = Release|Win32 + {DA4DB99F-E5BA-48BD-BB6B-3595CE24CBAE}.Debug|Win32.ActiveCfg = Debug|Win32 + {DA4DB99F-E5BA-48BD-BB6B-3595CE24CBAE}.Debug|Win32.Build.0 = Debug|Win32 + {DA4DB99F-E5BA-48BD-BB6B-3595CE24CBAE}.Debug|x64.ActiveCfg = Debug|Win32 + {DA4DB99F-E5BA-48BD-BB6B-3595CE24CBAE}.Release|Win32.ActiveCfg = Release|Win32 + {DA4DB99F-E5BA-48BD-BB6B-3595CE24CBAE}.Release|Win32.Build.0 = Release|Win32 + {DA4DB99F-E5BA-48BD-BB6B-3595CE24CBAE}.Release|x64.ActiveCfg = Release|Win32 + {0C69B8C2-0CE1-4CD4-870C-1C13FB3F9B34}.All|Win32.ActiveCfg = Release|Win32 + {0C69B8C2-0CE1-4CD4-870C-1C13FB3F9B34}.All|Win32.Build.0 = Release|Win32 + {0C69B8C2-0CE1-4CD4-870C-1C13FB3F9B34}.All|x64.ActiveCfg = Release|Win32 + {0C69B8C2-0CE1-4CD4-870C-1C13FB3F9B34}.Debug|Win32.ActiveCfg = Debug|Win32 + {0C69B8C2-0CE1-4CD4-870C-1C13FB3F9B34}.Debug|Win32.Build.0 = Debug|Win32 + {0C69B8C2-0CE1-4CD4-870C-1C13FB3F9B34}.Debug|x64.ActiveCfg = Debug|Win32 + {0C69B8C2-0CE1-4CD4-870C-1C13FB3F9B34}.Release|Win32.ActiveCfg = Release|Win32 + {0C69B8C2-0CE1-4CD4-870C-1C13FB3F9B34}.Release|Win32.Build.0 = Release|Win32 + {0C69B8C2-0CE1-4CD4-870C-1C13FB3F9B34}.Release|x64.ActiveCfg = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/libs/spandsp/src/libspandsp.2012.vcxproj b/libs/spandsp/src/libspandsp.2012.vcxproj index 92ddbbe0c9..a73a1b3c88 100644 --- a/libs/spandsp/src/libspandsp.2012.vcxproj +++ b/libs/spandsp/src/libspandsp.2012.vcxproj @@ -161,6 +161,7 @@ + @@ -214,6 +215,7 @@ + @@ -297,6 +299,7 @@ + @@ -308,6 +311,7 @@ + @@ -441,6 +445,10 @@ {329a6fa0-0fcc-4435-a950-e670aefa9838} false + + {eddb8ab9-c53e-44c0-a620-0e86c2cbd5d5} + false + diff --git a/libs/spandsp/src/libspandsp.2012.vcxproj.filters b/libs/spandsp/src/libspandsp.2012.vcxproj.filters index 05763b180c..bc694efb84 100644 --- a/libs/spandsp/src/libspandsp.2012.vcxproj.filters +++ b/libs/spandsp/src/libspandsp.2012.vcxproj.filters @@ -283,6 +283,12 @@ Source Files + + Source Files + + + Source Files + @@ -690,8 +696,12 @@ Header Files - - + + Header Files + + + Header Files + Header Files @@ -722,6 +732,12 @@ Header Files + + Header Files + + + Header Files + diff --git a/libs/spandsp/src/logging.c b/libs/spandsp/src/logging.c index 3f9aa58f17..09bc29b6c6 100644 --- a/libs/spandsp/src/logging.c +++ b/libs/spandsp/src/logging.c @@ -40,8 +40,14 @@ #include #include #include +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/private/logging.h" @@ -73,11 +79,11 @@ static void default_message_handler(void *user_data, int level, const char *text } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) span_log_test(logging_state_t *s, int level) +SPAN_DECLARE(bool) span_log_test(logging_state_t *s, int level) { if (s && (s->level & SPAN_LOG_SEVERITY_MASK) >= (level & SPAN_LOG_SEVERITY_MASK)) - return TRUE; - return FALSE; + return true; + return false; } /*- End of function --------------------------------------------------------*/ @@ -229,7 +235,7 @@ SPAN_DECLARE(logging_state_t *) span_log_init(logging_state_t *s, int level, con { if (s == NULL) { - if ((s = (logging_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (logging_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } s->span_message = __span_message; @@ -252,7 +258,7 @@ SPAN_DECLARE(int) span_log_release(logging_state_t *s) SPAN_DECLARE(int) span_log_free(logging_state_t *s) { if (s) - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/lpc10_analyse.c b/libs/spandsp/src/lpc10_analyse.c index e809d41ec8..082dbbb3ac 100644 --- a/libs/spandsp/src/lpc10_analyse.c +++ b/libs/spandsp/src/lpc10_analyse.c @@ -41,6 +41,11 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include "spandsp/telephony.h" @@ -349,7 +354,7 @@ static void onset(lpc10_encode_state_t *s, osbuf[*osptr - 1] = i - 9; (*osptr)++; } - s->hyst = TRUE; + s->hyst = true; } s->lasti = i; /* After one onset detection, at least OSHYST sample times must go */ @@ -357,7 +362,7 @@ static void onset(lpc10_encode_state_t *s, } else if (s->hyst && i - s->lasti >= 10) { - s->hyst = FALSE; + s->hyst = false; } } } diff --git a/libs/spandsp/src/lpc10_decode.c b/libs/spandsp/src/lpc10_decode.c index 19860e149d..2242133591 100644 --- a/libs/spandsp/src/lpc10_decode.c +++ b/libs/spandsp/src/lpc10_decode.c @@ -34,16 +34,22 @@ #include #include #include +#include #if defined(HAVE_TGMATH_H) #include #endif #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" -#include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/fast_convert.h" #include "spandsp/lpc10.h" #include "spandsp/private/lpc10.h" @@ -279,7 +285,7 @@ static int pitsyn(lpc10_decode_state_t *s, ipiti[i] = *pitch; rmsi[i] = *rms; } - s->first_pitsyn = FALSE; + s->first_pitsyn = false; } else { @@ -406,7 +412,7 @@ static int pitsyn(lpc10_decode_state_t *s, /* NOUT | -- -- -- -- ?? ?? */ /* IVOICE | -- -- -- -- 0 0 */ - /* UVPIT is always 0.0 on the first pass through the DO WHILE (TRUE) + /* UVPIT is always 0.0 on the first pass through the DO WHILE (true) loop below. */ /* The only possible non-0 value of SLOPE (in column 111) is @@ -857,7 +863,7 @@ static void decode(lpc10_decode_state_t *s, /* Skip decoding on first frame because present data not yet available */ if (s->first) { - s->first = FALSE; + s->first = false; /* Assign PITCH a "default" value on the first call, since */ /* otherwise it would be left uninitialized. The two lines */ /* below were copied from above, since it seemed like a */ @@ -1016,7 +1022,7 @@ SPAN_DECLARE(lpc10_decode_state_t *) lpc10_decode_init(lpc10_decode_state_t *s, if (s == NULL) { - if ((s = (lpc10_decode_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (lpc10_decode_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } @@ -1024,7 +1030,7 @@ SPAN_DECLARE(lpc10_decode_state_t *) lpc10_decode_init(lpc10_decode_state_t *s, /* State used by function decode */ s->iptold = 60; - s->first = TRUE; + s->first = true; s->ivp2h = 0; s->iovoic = 0; s->iavgp = 60; @@ -1044,7 +1050,7 @@ SPAN_DECLARE(lpc10_decode_state_t *) lpc10_decode_init(lpc10_decode_state_t *s, /* State used by function pitsyn */ s->rmso = 1.0f; - s->first_pitsyn = TRUE; + s->first_pitsyn = true; /* State used by function bsynz */ s->ipo = 0; @@ -1084,7 +1090,7 @@ SPAN_DECLARE(int) lpc10_decode_release(lpc10_decode_state_t *s) SPAN_DECLARE(int) lpc10_decode_free(lpc10_decode_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/lpc10_encode.c b/libs/spandsp/src/lpc10_encode.c index 739734f866..27bf10c9b1 100644 --- a/libs/spandsp/src/lpc10_encode.c +++ b/libs/spandsp/src/lpc10_encode.c @@ -41,9 +41,15 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/lpc10.h" #include "spandsp/private/lpc10.h" @@ -269,7 +275,7 @@ SPAN_DECLARE(lpc10_encode_state_t *) lpc10_encode_init(lpc10_encode_state_t *s, if (s == NULL) { - if ((s = (lpc10_encode_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (lpc10_encode_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } @@ -321,7 +327,7 @@ SPAN_DECLARE(lpc10_encode_state_t *) lpc10_encode_init(lpc10_encode_state_t *s, s->l2sum1 = 0.0f; s->l2ptr1 = 1; s->l2ptr2 = 9; - s->hyst = FALSE; + s->hyst = false; /* State used by function lpc10_voicing */ s->dither = 20.0f; @@ -367,7 +373,7 @@ SPAN_DECLARE(int) lpc10_encode_release(lpc10_encode_state_t *s) SPAN_DECLARE(int) lpc10_encode_free(lpc10_encode_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/lpc10_placev.c b/libs/spandsp/src/lpc10_placev.c index f728d6fa63..339e241563 100644 --- a/libs/spandsp/src/lpc10_placev.c +++ b/libs/spandsp/src/lpc10_placev.c @@ -41,6 +41,11 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include "spandsp/telephony.h" @@ -67,7 +72,7 @@ void lpc10_placea(int32_t *ipitch, int32_t k; int32_t l; int32_t hrange; - int ephase; + bool ephase; int32_t lrange; lrange = (af - 2)*lframe + 1; @@ -148,14 +153,14 @@ void lpc10_placea(int32_t *ipitch, awin[af - 1][1] += *ipitch; } /* Make energy window be phase-synchronous. */ - ephase = TRUE; + ephase = true; } else { /* Case 3 */ awin[af - 1][0] = vwin[af - 1][0]; awin[af - 1][1] = vwin[af - 1][1]; - ephase = FALSE; + ephase = false; } /* RMS is computed over an integer number of pitch periods in the analysis window. When it is not placed phase-synchronously, it is placed as close @@ -193,7 +198,7 @@ void lpc10_placev(int32_t *osbuf, { int32_t i1; int32_t i2; - int crit; + bool crit; int32_t q; int32_t osptr1; int32_t hrange; @@ -286,12 +291,12 @@ void lpc10_placev(int32_t *osbuf, q++; /* Check for case 2 (placement before onset): */ /* Check for critical region exception: */ - crit = FALSE; + crit = false; for (i = q + 1; i < osptr1; i++) { if (osbuf[i - 1] - osbuf[q - 1] >= minwin) { - crit = TRUE; + crit = true; break; } } diff --git a/libs/spandsp/src/lpc10_voicing.c b/libs/spandsp/src/lpc10_voicing.c index 90891f9cca..fdb1b3f7c5 100644 --- a/libs/spandsp/src/lpc10_voicing.c +++ b/libs/spandsp/src/lpc10_voicing.c @@ -41,6 +41,11 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include "spandsp/telephony.h" diff --git a/libs/spandsp/src/make_at_dictionary.c b/libs/spandsp/src/make_at_dictionary.c index 7f05dd9b14..3a881af992 100644 --- a/libs/spandsp/src/make_at_dictionary.c +++ b/libs/spandsp/src/make_at_dictionary.c @@ -24,10 +24,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - #include #include #include diff --git a/libs/spandsp/src/make_cielab_luts.c b/libs/spandsp/src/make_cielab_luts.c index 5fca6c7236..dc5172817d 100644 --- a/libs/spandsp/src/make_cielab_luts.c +++ b/libs/spandsp/src/make_cielab_luts.c @@ -25,22 +25,13 @@ /*! \file */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - #include #include #include #include #include #include -#if defined(HAVE_TGMATH_H) -#include -#endif -#if defined(HAVE_MATH_H) #include -#endif typedef struct { @@ -81,7 +72,7 @@ int main(int argc, char *argv[]) r = floorf(r*256.0f); - srgb = (r < 0) ? 0 : (r <= 255) ? r : 255; + srgb = (uint8_t) ((r < 0) ? 0 : (r <= 255) ? r : 255); printf((i < 4095) ? " %d,\n" : " %d\n", srgb); } diff --git a/libs/spandsp/src/make_math_fixed_tables.c b/libs/spandsp/src/make_math_fixed_tables.c index 2bddd12ced..8e290b44ce 100644 --- a/libs/spandsp/src/make_math_fixed_tables.c +++ b/libs/spandsp/src/make_math_fixed_tables.c @@ -24,10 +24,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - #include #include #include @@ -46,7 +42,7 @@ int main(int argc, char *argv[]) for (i = 0; i < 129; i++) { val = 32768.0*128.0/(128 + i) + 0.5; - ival = val; + ival = (int) val; if (i < 128) printf(" %6d,\n", ival); else @@ -58,7 +54,7 @@ int main(int argc, char *argv[]) printf("{\n"); for (i = 64; i <= 256; i++) { - ival = sqrt(i/256.0)*65536.0 + 0.5; + ival = (int) (sqrt(i/256.0)*65536.0 + 0.5); if (ival > 65535) ival = 65535; if (i < 256) @@ -72,7 +68,7 @@ int main(int argc, char *argv[]) printf("{\n"); for (i = 128; i <= 256; i++) { - ival = log10(i/256.0)*32768.0 - 0.5; + ival = (int) (log10(i/256.0)*32768.0 - 0.5); if (i <= 255) printf(" %6d,\n", ival); else @@ -85,7 +81,7 @@ int main(int argc, char *argv[]) for (i = 0; i <= 256; i++) { val = sin(i*3.1415926535/512.0)*32768.0; - ival = val + 0.5; + ival = (int) (val + 0.5); if (ival > 32767) ival = 32767; if (i <= 255) @@ -100,7 +96,7 @@ int main(int argc, char *argv[]) for (i = 0; i <= 256; i++) { val = atan(i/256.0)*65536.0/(2.0*3.1415926535); - ival = val + 0.5; + ival = (int) (val + 0.5); /* Nudge the result away from zero, so things sit consistently on the correct side of the axes. */ if (ival == 0) @@ -114,3 +110,5 @@ int main(int argc, char *argv[]) return 0; } +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/make_modem_filter.c b/libs/spandsp/src/make_modem_filter.c index 8ceac8aab9..bd9427e24f 100644 --- a/libs/spandsp/src/make_modem_filter.c +++ b/libs/spandsp/src/make_modem_filter.c @@ -24,39 +24,31 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - #include #include #include -#if defined(HAVE_TGMATH_H) -#include -#endif -#if defined(HAVE_MATH_H) -#include -#endif -#include "floating_fudge.h" #include #include #include #include +#include +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #if defined(__sunos) || defined(__solaris) || defined(__sun) #include #endif +#if defined (_MSC_VER) + #define __inline__ __inline +#endif + #include "spandsp/telephony.h" #include "spandsp/complex.h" #include "filter_tools.h" -#if !defined(FALSE) -#define FALSE 0 -#endif -#if !defined(TRUE) -#define TRUE (!FALSE) -#endif - //#define SAMPLE_RATE 8000.0 #define MAX_COEFFS_PER_FILTER 128 #define MAX_COEFF_SETS 384 @@ -84,7 +76,7 @@ static void make_tx_filter(int coeff_sets, alpha = baud_rate/(2.0*(double) (coeff_sets*baud_rate)); beta = excess_bandwidth; - compute_raised_cosine_filter(coeffs, total_coeffs, TRUE, FALSE, alpha, beta); + compute_raised_cosine_filter(coeffs, total_coeffs, true, false, alpha, beta); /* Find the DC gain of the filter, and adjust the filter to unity gain. */ floating_gain = 0.0; @@ -180,7 +172,7 @@ static void make_rx_filter(int coeff_sets, beta = excess_bandwidth; carrier *= 2.0*3.1415926535/SAMPLE_RATE; - compute_raised_cosine_filter(coeffs, total_coeffs, TRUE, FALSE, alpha, beta); + compute_raised_cosine_filter(coeffs, total_coeffs, true, false, alpha, beta); /* Find the DC gain of the filter, and adjust the filter to unity gain. */ floating_gain = 0.0; @@ -284,7 +276,7 @@ int main(int argc, char **argv) const char *tx_tag; const char *modem; - transmit_modem = FALSE; + transmit_modem = false; modem = ""; while ((opt = getopt(argc, argv, "m:rt")) != -1) { @@ -294,10 +286,10 @@ int main(int argc, char **argv) modem = optarg; break; case 'r': - transmit_modem = FALSE; + transmit_modem = false; break; case 't': - transmit_modem = TRUE; + transmit_modem = true; break; default: usage(); diff --git a/libs/spandsp/src/make_t43_gray_code_tables.c b/libs/spandsp/src/make_t43_gray_code_tables.c new file mode 100644 index 0000000000..90117c5d83 --- /dev/null +++ b/libs/spandsp/src/make_t43_gray_code_tables.c @@ -0,0 +1,101 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * make_t43_gray_code_tables.c - Generate the Gray code tables for T.43 image + * compression. + * + * Written by Steve Underwood + * + * Copyright (C) 2012 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + int i; + int j; + int gray; + int new_gray; + int restore; + + printf("static const int16_t gray_code[4096] =\n{\n"); + for (i = 0; i < 4096; i++) + { + gray = i & 0x800; + restore = i; + for (j = 10; j >= 0; j--) + { + if (((i >> (j + 1)) & 1) ^ ((i >> j) & 1)) + gray |= (1 << j); + } + printf(" 0x%04x, /* 0x%04x */\n", gray, restore); + + /* Now reverse the process and check we get back where we start */ + restore = gray & 0x800; + for (j = 10; j >= 0; j--) + { + if (((restore >> (j + 1)) & 1) ^ ((gray >> j) & 1)) + restore |= (1 << j); + } + + if (i != restore) + { + printf("Ah\n"); + exit(2); + } + } + printf("};\n\n"); + + printf("static const int16_t anti_gray_code[4096] =\n{\n"); + for (i = 0; i < 4096; i++) + { + gray = i; + restore = gray & 0x800; + for (j = 10; j >= 0; j--) + { + if (((restore >> (j + 1)) & 1) ^ ((gray >> j) & 1)) + restore |= (1 << j); + } + printf(" 0x%04x, /* 0x%04x */\n", restore, gray); + + /* Now reverse the process and check we get back where we start */ + new_gray = restore & 0x800; + for (j = 10; j >= 0; j--) + { + if (((restore >> (j + 1)) & 1) ^ ((restore >> j) & 1)) + new_gray |= (1 << j); + } + + if (gray != new_gray) + { + printf("Ah\n"); + exit(2); + } + } + printf("};\n"); + + return 0; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/modem_connect_tones.c b/libs/spandsp/src/modem_connect_tones.c index 76b42a23fc..9c030ad0ed 100644 --- a/libs/spandsp/src/modem_connect_tones.c +++ b/libs/spandsp/src/modem_connect_tones.c @@ -53,10 +53,16 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/fast_convert.h" #include "spandsp/logging.h" #include "spandsp/complex.h" @@ -69,6 +75,7 @@ #include "spandsp/fsk.h" #include "spandsp/modem_connect_tones.h" +#include "spandsp/private/power_meter.h" #include "spandsp/private/fsk.h" #include "spandsp/private/modem_connect_tones.h" @@ -255,12 +262,12 @@ SPAN_DECLARE(modem_connect_tones_tx_state_t *) modem_connect_tones_tx_init(modem { int alloced; - alloced = FALSE; + alloced = false; if (s == NULL) { - if ((s = (modem_connect_tones_tx_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (modem_connect_tones_tx_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; - alloced = TRUE; + alloced = true; } s->tone_type = tone_type; switch (s->tone_type) @@ -341,7 +348,7 @@ SPAN_DECLARE(modem_connect_tones_tx_state_t *) modem_connect_tones_tx_init(modem break; default: if (alloced) - free(s); + span_free(s); return NULL; } return s; @@ -356,7 +363,7 @@ SPAN_DECLARE(int) modem_connect_tones_tx_release(modem_connect_tones_tx_state_t SPAN_DECLARE(int) modem_connect_tones_tx_free(modem_connect_tones_tx_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ @@ -398,7 +405,7 @@ static void v21_put_bit(void *user_data, int bit) s->raw_bit_stream = 0; s->num_bits = 0; s->flags_seen = 0; - s->framing_ok_announced = FALSE; + s->framing_ok_announced = false; break; } return; @@ -429,7 +436,7 @@ static void v21_put_bit(void *user_data, int bit) if (++s->flags_seen >= HDLC_FRAMING_OK_THRESHOLD && !s->framing_ok_announced) { report_tone_state(s, MODEM_CONNECT_TONES_FAX_PREAMBLE, lfastrintf(fsk_rx_signal_power(&(s->v21rx)))); - s->framing_ok_announced = TRUE; + s->framing_ok_announced = true; } } } @@ -441,7 +448,7 @@ static void v21_put_bit(void *user_data, int bit) { if (s->num_bits == 8) { - s->framing_ok_announced = FALSE; + s->framing_ok_announced = false; s->flags_seen = 0; } } @@ -547,7 +554,7 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t * report_tone_state(s, MODEM_CONNECT_TONES_NONE, -99); s->tone_cycle_duration = 0; s->good_cycles = 0; - s->tone_on = FALSE; + s->tone_on = false; continue; } /* There is adequate energy in the channel. Is it mostly at 2100Hz? */ @@ -589,7 +596,7 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t * s->tone_cycle_duration = ms_to_samples(450 + 100); } } - s->tone_on = TRUE; + s->tone_on = true; } else if (s->notch_level*5 > s->channel_level) { @@ -608,7 +615,7 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t * s->good_cycles = 0; } } - s->tone_on = FALSE; + s->tone_on = false; } } break; @@ -716,7 +723,7 @@ SPAN_DECLARE(modem_connect_tones_rx_state_t *) modem_connect_tones_rx_init(modem { if (s == NULL) { - if ((s = (modem_connect_tones_rx_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (modem_connect_tones_rx_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } @@ -742,7 +749,7 @@ SPAN_DECLARE(modem_connect_tones_rx_state_t *) modem_connect_tones_rx_init(modem s->tone_cycle_duration = 0; s->good_cycles = 0; s->hit = MODEM_CONNECT_TONES_NONE; - s->tone_on = FALSE; + s->tone_on = false; s->tone_callback = tone_callback; s->callback_data = user_data; s->znotch_1 = 0.0f; @@ -751,7 +758,7 @@ SPAN_DECLARE(modem_connect_tones_rx_state_t *) modem_connect_tones_rx_init(modem s->z15hz_2 = 0.0f; s->num_bits = 0; s->flags_seen = 0; - s->framing_ok_announced = FALSE; + s->framing_ok_announced = false; s->raw_bit_stream = 0; return s; } @@ -765,7 +772,7 @@ SPAN_DECLARE(int) modem_connect_tones_rx_release(modem_connect_tones_rx_state_t SPAN_DECLARE(int) modem_connect_tones_rx_free(modem_connect_tones_rx_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/modem_echo.c b/libs/spandsp/src/modem_echo.c index 14257c7eb7..622c201279 100644 --- a/libs/spandsp/src/modem_echo.c +++ b/libs/spandsp/src/modem_echo.c @@ -47,6 +47,7 @@ #include "floating_fudge.h" #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/bit_operations.h" #include "spandsp/dc_restore.h" #include "spandsp/modem_echo.h" @@ -56,9 +57,9 @@ SPAN_DECLARE(void) modem_echo_can_free(modem_echo_can_state_t *ec) { fir16_free(&ec->fir_state); - free(ec->fir_taps32); - free(ec->fir_taps16); - free(ec); + span_free(ec->fir_taps32); + span_free(ec->fir_taps16); + span_free(ec); } /*- End of function --------------------------------------------------------*/ @@ -66,29 +67,29 @@ SPAN_DECLARE(modem_echo_can_state_t *) modem_echo_can_init(int len) { modem_echo_can_state_t *ec; - if ((ec = (modem_echo_can_state_t *) malloc(sizeof(*ec))) == NULL) + if ((ec = (modem_echo_can_state_t *) span_alloc(sizeof(*ec))) == NULL) return NULL; memset(ec, 0, sizeof(*ec)); ec->taps = len; ec->curr_pos = ec->taps - 1; - if ((ec->fir_taps32 = (int32_t *) malloc(ec->taps*sizeof(int32_t))) == NULL) + if ((ec->fir_taps32 = (int32_t *) span_alloc(ec->taps*sizeof(int32_t))) == NULL) { - free(ec); + span_free(ec); return NULL; } memset(ec->fir_taps32, 0, ec->taps*sizeof(int32_t)); - if ((ec->fir_taps16 = (int16_t *) malloc(ec->taps*sizeof(int16_t))) == NULL) + if ((ec->fir_taps16 = (int16_t *) span_alloc(ec->taps*sizeof(int16_t))) == NULL) { - free(ec->fir_taps32); - free(ec); + span_free(ec->fir_taps32); + span_free(ec); return NULL; } memset(ec->fir_taps16, 0, ec->taps*sizeof(int16_t)); if (fir16_create(&ec->fir_state, ec->fir_taps16, ec->taps) == NULL) { - free(ec->fir_taps16); - free(ec->fir_taps32); - free(ec); + span_free(ec->fir_taps16); + span_free(ec->fir_taps32); + span_free(ec); return NULL; } return ec; diff --git a/libs/spandsp/src/msvc/config.h b/libs/spandsp/src/msvc/config.h index 876f66f56a..c974d7c7c4 100644 --- a/libs/spandsp/src/msvc/config.h +++ b/libs/spandsp/src/msvc/config.h @@ -74,7 +74,9 @@ #define _MMX_H_ + #if !((defined(WIN32) || defined(_WIN32)) && (_MSC_VER >= 1800)) #define cbrtf(value) pow((float)value, (float).333) + #endif #include // To get alloca diff --git a/libs/spandsp/src/msvc/getopt.c b/libs/spandsp/src/msvc/getopt.c index 2fa9318def..a19bd4b78b 100644 --- a/libs/spandsp/src/msvc/getopt.c +++ b/libs/spandsp/src/msvc/getopt.c @@ -1,177 +1,177 @@ -/***************************************************************************** - * - * MODULE NAME : GETOPT.C - * - * COPYRIGHTS: - * This module contains code made available by IBM - * Corporation on an AS IS basis. Any one receiving the - * module is considered to be licensed under IBM copyrights - * to use the IBM-provided source code in any way he or she - * deems fit, including copying it, compiling it, modifying - * it, and redistributing it, with or without - * modifications. No license under any IBM patents or - * patent applications is to be implied from this copyright - * license. - * - * A user of the module should understand that IBM cannot - * provide technical support for the module and will not be - * responsible for any consequences of use of the program. - * - * Any notices, including this one, are not to be removed - * from the module without the prior written consent of - * IBM. - * - * AUTHOR: Original author: - * G. R. Blair (BOBBLAIR at AUSVM1) - * Internet: bobblair@bobblair.austin.ibm.com - * - * Extensively revised by: - * John Q. Walker II, Ph.D. (JOHHQ at RALVM6) - * Internet: johnq@ralvm6.vnet.ibm.com - * - *****************************************************************************/ - -/****************************************************************************** - * getopt() - * - * The getopt() function is a command line parser. It returns the next - * option character in argv that matches an option character in opstring. - * - * The argv argument points to an array of argc+1 elements containing argc - * pointers to character strings followed by a null pointer. - * - * The opstring argument points to a string of option characters; if an - * option character is followed by a colon, the option is expected to have - * an argument that may or may not be separated from it by white space. - * The external variable optarg is set to point to the start of the option - * argument on return from getopt(). - * - * The getopt() function places in optind the argv index of the next argument - * to be processed. The system initializes the external variable optind to - * 1 before the first call to getopt(). - * - * When all options have been processed (that is, up to the first nonoption - * argument), getopt() returns EOF. The special option "--" may be used to - * delimit the end of the options; EOF will be returned, and "--" will be - * skipped. - * - * The getopt() function returns a question mark (?) when it encounters an - * option character not included in opstring. This error message can be - * disabled by setting opterr to zero. Otherwise, it returns the option - * character that was detected. - * - * If the special option "--" is detected, or all options have been - * processed, EOF is returned. - * - * Options are marked by either a minus sign (-) or a slash (/). - * - * No errors are defined. - *****************************************************************************/ - -#include /* for EOF */ -#include /* for strchr() */ - - -/* static (global) variables that are specified as exported by getopt() */ -char *optarg = NULL; /* pointer to the start of the option argument */ -int optind = 1; /* number of the next argv[] to be evaluated */ -int opterr = 1; /* non-zero if a question mark should be returned - when a non-valid option character is detected */ - -/* handle possible future character set concerns by putting this in a macro */ -#define _next_char(string) (char)(*(string+1)) - -int getopt(int argc, char *argv[], char *opstring) -{ - static char *pIndexPosition = NULL; /* place inside current argv string */ - char *pArgString = NULL; /* where to start from next */ - char *pOptString; /* the string in our program */ - - - if (pIndexPosition != NULL) { - /* we last left off inside an argv string */ - if (*(++pIndexPosition)) { - /* there is more to come in the most recent argv */ - pArgString = pIndexPosition; - } - } - - if (pArgString == NULL) { - /* we didn't leave off in the middle of an argv string */ - if (optind >= argc) { - /* more command-line arguments than the argument count */ - pIndexPosition = NULL; /* not in the middle of anything */ - return EOF; /* used up all command-line arguments */ - } - - /*--------------------------------------------------------------------- - * If the next argv[] is not an option, there can be no more options. - *-------------------------------------------------------------------*/ - pArgString = argv[optind++]; /* set this to the next argument ptr */ - - if (('/' != *pArgString) && /* doesn't start with a slash or a dash? */ - ('-' != *pArgString)) { - --optind; /* point to current arg once we're done */ - optarg = NULL; /* no argument follows the option */ - pIndexPosition = NULL; /* not in the middle of anything */ - return EOF; /* used up all the command-line flags */ - } - - /* check for special end-of-flags markers */ - if ((strcmp(pArgString, "-") == 0) || - (strcmp(pArgString, "--") == 0)) { - optarg = NULL; /* no argument follows the option */ - pIndexPosition = NULL; /* not in the middle of anything */ - return EOF; /* encountered the special flag */ - } - - pArgString++; /* look past the / or - */ - } - - if (':' == *pArgString) { /* is it a colon? */ - /*--------------------------------------------------------------------- - * Rare case: if opterr is non-zero, return a question mark; - * otherwise, just return the colon we're on. - *-------------------------------------------------------------------*/ - return (opterr ? (int)'?' : (int)':'); - } - else if ((pOptString = strchr(opstring, *pArgString)) == 0) { - /*--------------------------------------------------------------------- - * The letter on the command-line wasn't any good. - *-------------------------------------------------------------------*/ - optarg = NULL; /* no argument follows the option */ - pIndexPosition = NULL; /* not in the middle of anything */ - return (opterr ? (int)'?' : (int)*pArgString); - } - else { - /*--------------------------------------------------------------------- - * The letter on the command-line matches one we expect to see - *-------------------------------------------------------------------*/ - if (':' == _next_char(pOptString)) { /* is the next letter a colon? */ - /* It is a colon. Look for an argument string. */ - if ('\0' != _next_char(pArgString)) { /* argument in this argv? */ - optarg = &pArgString[1]; /* Yes, it is */ - } - else { - /*------------------------------------------------------------- - * The argument string must be in the next argv. - * But, what if there is none (bad input from the user)? - * In that case, return the letter, and optarg as NULL. - *-----------------------------------------------------------*/ - if (optind < argc) - optarg = argv[optind++]; - else { - optarg = NULL; - return (opterr ? (int)'?' : (int)*pArgString); - } - } - pIndexPosition = NULL; /* not in the middle of anything */ - } - else { - /* it's not a colon, so just return the letter */ - optarg = NULL; /* no argument follows the option */ - pIndexPosition = pArgString; /* point to the letter we're on */ - } - return (int)*pArgString; /* return the letter that matched */ - } +/***************************************************************************** + * + * MODULE NAME : GETOPT.C + * + * COPYRIGHTS: + * This module contains code made available by IBM + * Corporation on an AS IS basis. Any one receiving the + * module is considered to be licensed under IBM copyrights + * to use the IBM-provided source code in any way he or she + * deems fit, including copying it, compiling it, modifying + * it, and redistributing it, with or without + * modifications. No license under any IBM patents or + * patent applications is to be implied from this copyright + * license. + * + * A user of the module should understand that IBM cannot + * provide technical support for the module and will not be + * responsible for any consequences of use of the program. + * + * Any notices, including this one, are not to be removed + * from the module without the prior written consent of + * IBM. + * + * AUTHOR: Original author: + * G. R. Blair (BOBBLAIR at AUSVM1) + * Internet: bobblair@bobblair.austin.ibm.com + * + * Extensively revised by: + * John Q. Walker II, Ph.D. (JOHHQ at RALVM6) + * Internet: johnq@ralvm6.vnet.ibm.com + * + *****************************************************************************/ + +/****************************************************************************** + * getopt() + * + * The getopt() function is a command line parser. It returns the next + * option character in argv that matches an option character in opstring. + * + * The argv argument points to an array of argc+1 elements containing argc + * pointers to character strings followed by a null pointer. + * + * The opstring argument points to a string of option characters; if an + * option character is followed by a colon, the option is expected to have + * an argument that may or may not be separated from it by white space. + * The external variable optarg is set to point to the start of the option + * argument on return from getopt(). + * + * The getopt() function places in optind the argv index of the next argument + * to be processed. The system initializes the external variable optind to + * 1 before the first call to getopt(). + * + * When all options have been processed (that is, up to the first nonoption + * argument), getopt() returns EOF. The special option "--" may be used to + * delimit the end of the options; EOF will be returned, and "--" will be + * skipped. + * + * The getopt() function returns a question mark (?) when it encounters an + * option character not included in opstring. This error message can be + * disabled by setting opterr to zero. Otherwise, it returns the option + * character that was detected. + * + * If the special option "--" is detected, or all options have been + * processed, EOF is returned. + * + * Options are marked by either a minus sign (-) or a slash (/). + * + * No errors are defined. + *****************************************************************************/ + +#include /* for EOF */ +#include /* for strchr() */ + + +/* static (global) variables that are specified as exported by getopt() */ +char *optarg = NULL; /* pointer to the start of the option argument */ +int optind = 1; /* number of the next argv[] to be evaluated */ +int opterr = 1; /* non-zero if a question mark should be returned + when a non-valid option character is detected */ + +/* handle possible future character set concerns by putting this in a macro */ +#define _next_char(string) (char)(*(string+1)) + +int getopt(int argc, char *argv[], char *opstring) +{ + static char *pIndexPosition = NULL; /* place inside current argv string */ + char *pArgString = NULL; /* where to start from next */ + char *pOptString; /* the string in our program */ + + + if (pIndexPosition != NULL) { + /* we last left off inside an argv string */ + if (*(++pIndexPosition)) { + /* there is more to come in the most recent argv */ + pArgString = pIndexPosition; + } + } + + if (pArgString == NULL) { + /* we didn't leave off in the middle of an argv string */ + if (optind >= argc) { + /* more command-line arguments than the argument count */ + pIndexPosition = NULL; /* not in the middle of anything */ + return EOF; /* used up all command-line arguments */ + } + + /*--------------------------------------------------------------------- + * If the next argv[] is not an option, there can be no more options. + *-------------------------------------------------------------------*/ + pArgString = argv[optind++]; /* set this to the next argument ptr */ + + if (('/' != *pArgString) && /* doesn't start with a slash or a dash? */ + ('-' != *pArgString)) { + --optind; /* point to current arg once we're done */ + optarg = NULL; /* no argument follows the option */ + pIndexPosition = NULL; /* not in the middle of anything */ + return EOF; /* used up all the command-line flags */ + } + + /* check for special end-of-flags markers */ + if ((strcmp(pArgString, "-") == 0) || + (strcmp(pArgString, "--") == 0)) { + optarg = NULL; /* no argument follows the option */ + pIndexPosition = NULL; /* not in the middle of anything */ + return EOF; /* encountered the special flag */ + } + + pArgString++; /* look past the / or - */ + } + + if (':' == *pArgString) { /* is it a colon? */ + /*--------------------------------------------------------------------- + * Rare case: if opterr is non-zero, return a question mark; + * otherwise, just return the colon we're on. + *-------------------------------------------------------------------*/ + return (opterr ? (int)'?' : (int)':'); + } + else if ((pOptString = strchr(opstring, *pArgString)) == 0) { + /*--------------------------------------------------------------------- + * The letter on the command-line wasn't any good. + *-------------------------------------------------------------------*/ + optarg = NULL; /* no argument follows the option */ + pIndexPosition = NULL; /* not in the middle of anything */ + return (opterr ? (int)'?' : (int)*pArgString); + } + else { + /*--------------------------------------------------------------------- + * The letter on the command-line matches one we expect to see + *-------------------------------------------------------------------*/ + if (':' == _next_char(pOptString)) { /* is the next letter a colon? */ + /* It is a colon. Look for an argument string. */ + if ('\0' != _next_char(pArgString)) { /* argument in this argv? */ + optarg = &pArgString[1]; /* Yes, it is */ + } + else { + /*------------------------------------------------------------- + * The argument string must be in the next argv. + * But, what if there is none (bad input from the user)? + * In that case, return the letter, and optarg as NULL. + *-----------------------------------------------------------*/ + if (optind < argc) + optarg = argv[optind++]; + else { + optarg = NULL; + return (opterr ? (int)'?' : (int)*pArgString); + } + } + pIndexPosition = NULL; /* not in the middle of anything */ + } + else { + /* it's not a colon, so just return the letter */ + optarg = NULL; /* no argument follows the option */ + pIndexPosition = pArgString; /* point to the letter we're on */ + } + return (int)*pArgString; /* return the letter that matched */ + } } diff --git a/libs/spandsp/src/msvc/gettimeofday.c b/libs/spandsp/src/msvc/gettimeofday.c index c59f19e0b8..83704180a9 100644 --- a/libs/spandsp/src/msvc/gettimeofday.c +++ b/libs/spandsp/src/msvc/gettimeofday.c @@ -4,11 +4,33 @@ #include "windows.h" +const unsigned long long int DELTA_EPOCH_IN_MICROSECS = 11644473600000000; + void gettimeofday(struct timeval *tv, void *tz) { - long int l = GetTickCount(); - - tv->tv_sec = l / 1000; - tv->tv_usec = (l % 1000) * 1000; - return; -} + FILETIME ft; + unsigned long long int highResolutionTime; + TIME_ZONE_INFORMATION tz_winapi; + int result_tz; + long long int timezone_time_bias_in_minutes; + + ZeroMemory(&ft, sizeof(ft)); + ZeroMemory(&tz_winapi, sizeof(tz_winapi)); + + GetSystemTimeAsFileTime(&ft); + result_tz = GetTimeZoneInformation(&tz_winapi); + timezone_time_bias_in_minutes = tz_winapi.Bias + ((result_tz == TIME_ZONE_ID_DAYLIGHT) ? tz_winapi.DaylightBias : 0); + + highResolutionTime = ft.dwHighDateTime; + highResolutionTime <<= 32; + highResolutionTime |= ft.dwLowDateTime; + + /* Converting file time to unix epoch */ + /* Convert to microseconds */ + highResolutionTime /= 10; + /* Add timezone bias conververt from minutes to microsecond */ + highResolutionTime -= timezone_time_bias_in_minutes*60*1000000; + highResolutionTime -= DELTA_EPOCH_IN_MICROSECS; + tv->tv_sec = (long int) (highResolutionTime/1000000); + tv->tv_usec = (highResolutionTime%1000000); +} diff --git a/libs/spandsp/src/msvc/make_t43_gray_code_tables.2010.vcxproj b/libs/spandsp/src/msvc/make_t43_gray_code_tables.2010.vcxproj new file mode 100644 index 0000000000..1ff1b7ec00 --- /dev/null +++ b/libs/spandsp/src/msvc/make_t43_gray_code_tables.2010.vcxproj @@ -0,0 +1,65 @@ + + + + + All + Win32 + + + + make_t43_gray_code_tables + {EDDB8AB9-C53E-44C0-A620-0E86C2CBD5D5} + make_t43_gray_code_tables + Win32Proj + + + + Application + Unicode + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(PlatformName)\$(Configuration)\ + $(PlatformName)\make_t43_gray_code_tables\$(Configuration)\ + false + + + + $(IntDir)BuildLog $(ProjectName).htm + + + Disabled + .;.\spandsp;.\msvc;..\..\tiff-4.0.2\libtiff;.\generated;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + $(IntDir)$(TargetName).pdb + Level3 + ProgramDatabase + + + true + Console + MachineX86 + + + "$(TargetPath)" >"$(ProjectDir)..\t43_gray_code_tables.h" + + + + + + + + + diff --git a/libs/spandsp/src/msvc/make_t43_gray_code_tables.2010.vcxproj.filters b/libs/spandsp/src/msvc/make_t43_gray_code_tables.2010.vcxproj.filters new file mode 100644 index 0000000000..8ab1316fdc --- /dev/null +++ b/libs/spandsp/src/msvc/make_t43_gray_code_tables.2010.vcxproj.filters @@ -0,0 +1,14 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + + diff --git a/libs/spandsp/src/msvc/make_t43_gray_code_tables.2012.vcxproj b/libs/spandsp/src/msvc/make_t43_gray_code_tables.2012.vcxproj new file mode 100644 index 0000000000..6673241fe6 --- /dev/null +++ b/libs/spandsp/src/msvc/make_t43_gray_code_tables.2012.vcxproj @@ -0,0 +1,66 @@ + + + + + All + Win32 + + + + make_t43_gray_code_tables + {EDDB8AB9-C53E-44C0-A620-0E86C2CBD5D5} + make_t43_gray_code_tables + Win32Proj + + + + Application + Unicode + v110 + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(PlatformName)\$(Configuration)\ + $(PlatformName)\make_t43_gray_code_tables\$(Configuration)\ + false + + + + $(IntDir)BuildLog $(ProjectName).htm + + + Disabled + .;.\spandsp;.\msvc;..\..\tiff-4.0.2\libtiff;.\generated;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + $(IntDir)$(TargetName).pdb + Level3 + ProgramDatabase + + + true + Console + MachineX86 + + + "$(TargetPath)" >"$(ProjectDir)..\t43_gray_code_tables.h" + + + + + + + + + diff --git a/libs/spandsp/src/msvc/make_t43_gray_code_tables.2012.vcxproj.filters b/libs/spandsp/src/msvc/make_t43_gray_code_tables.2012.vcxproj.filters new file mode 100644 index 0000000000..8ab1316fdc --- /dev/null +++ b/libs/spandsp/src/msvc/make_t43_gray_code_tables.2012.vcxproj.filters @@ -0,0 +1,14 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + + diff --git a/libs/spandsp/src/msvc/spandsp.h b/libs/spandsp/src/msvc/spandsp.h index fbdfac8e49..fb7b1431b1 100644 --- a/libs/spandsp/src/msvc/spandsp.h +++ b/libs/spandsp/src/msvc/spandsp.h @@ -36,9 +36,10 @@ #define SPANDSP_USE_EXPORT_CAPABILITY 1 -#undef SPANDSP_SUPPORT_T42 #undef SPANDSP_SUPPORT_T43 +#undef SPANDSP_SUPPORT_V32BIS #undef SPANDSP_SUPPORT_V34 +#undef SPANDSP_SUPPORT_TIFF_FX #include #include @@ -48,6 +49,9 @@ #include #include +#if !defined(__cplusplus) +#include +#endif #include #include #include @@ -114,9 +118,7 @@ #include #include #include -#if defined(SPANDSP_SUPPORT_T43) #include -#endif #include #include #include diff --git a/libs/spandsp/src/noise.c b/libs/spandsp/src/noise.c index 5d7fe23aad..3ad164cf7f 100644 --- a/libs/spandsp/src/noise.c +++ b/libs/spandsp/src/noise.c @@ -43,6 +43,7 @@ #include "floating_fudge.h" #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/fast_convert.h" #include "spandsp/saturated.h" #include "spandsp/noise.h" @@ -84,7 +85,7 @@ SPAN_DECLARE(noise_state_t *) noise_init_dbov(noise_state_t *s, int seed, float if (s == NULL) { - if ((s = (noise_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (noise_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -121,7 +122,7 @@ SPAN_DECLARE(int) noise_release(noise_state_t *s) SPAN_DECLARE(int) noise_free(noise_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/oki_adpcm.c b/libs/spandsp/src/oki_adpcm.c index f6d54b804c..0e5e8f6659 100644 --- a/libs/spandsp/src/oki_adpcm.c +++ b/libs/spandsp/src/oki_adpcm.c @@ -39,6 +39,7 @@ #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/oki_adpcm.h" #include "spandsp/private/oki_adpcm.h" @@ -246,7 +247,7 @@ SPAN_DECLARE(oki_adpcm_state_t *) oki_adpcm_init(oki_adpcm_state_t *s, int bit_r return NULL; if (s == NULL) { - if ((s = (oki_adpcm_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (oki_adpcm_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -264,7 +265,7 @@ SPAN_DECLARE(int) oki_adpcm_release(oki_adpcm_state_t *s) SPAN_DECLARE(int) oki_adpcm_free(oki_adpcm_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/playout.c b/libs/spandsp/src/playout.c index e98e48d70c..9ad0d8dcf2 100644 --- a/libs/spandsp/src/playout.c +++ b/libs/spandsp/src/playout.c @@ -39,10 +39,18 @@ #include #include #include +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/playout.h" +#include "spandsp/private/playout.h" + static playout_frame_t *queue_get(playout_state_t *s, timestamp_t sender_stamp) { playout_frame_t *frame; @@ -120,7 +128,7 @@ SPAN_DECLARE(int) playout_get(playout_state_t *s, playout_frame_t *frameout, tim if (!s->not_first) { /* Prime things the first time through */ - s->not_first = TRUE; + s->not_first = true; s->latest_expected = frame->receiver_stamp + s->min_length; } /* Leaky integrate the rate of occurance of frames received just in time and late */ @@ -236,7 +244,7 @@ SPAN_DECLARE(int) playout_put(playout_state_t *s, void *data, int type, timestam } else { - if ((frame = (playout_frame_t *) malloc(sizeof(*frame))) == NULL) + if ((frame = (playout_frame_t *) span_alloc(sizeof(*frame))) == NULL) return PLAYOUT_ERROR; } @@ -296,7 +304,7 @@ SPAN_DECLARE(int) playout_put(playout_state_t *s, void *data, int type, timestam { s->last_speech_sender_stamp = sender_stamp - sender_len - s->min_length; s->last_speech_sender_len = sender_len; - s->start = FALSE; + s->start = false; } return PLAYOUT_OK; @@ -312,7 +320,7 @@ SPAN_DECLARE(void) playout_restart(playout_state_t *s, int min_length, int max_l for (frame = s->free_frames; frame; frame = next) { next = frame->later; - free(frame); + span_free(frame); } memset(s, 0, sizeof(*s)); @@ -320,7 +328,7 @@ SPAN_DECLARE(void) playout_restart(playout_state_t *s, int min_length, int max_l s->min_length = min_length; s->max_length = (max_length > min_length) ? max_length : min_length; s->dropable_threshold = 1*0x10000000/100; - s->start = TRUE; + s->start = true; s->since_last_step = 0x7FFFFFFF; /* Start with the minimum buffer length allowed, and work from there */ s->actual_buffer_length = @@ -332,7 +340,7 @@ SPAN_DECLARE(playout_state_t *) playout_init(int min_length, int max_length) { playout_state_t *s; - if ((s = (playout_state_t *) malloc(sizeof(playout_state_t))) == NULL) + if ((s = (playout_state_t *) span_alloc(sizeof(playout_state_t))) == NULL) return NULL; memset(s, 0, sizeof(*s)); playout_restart(s, min_length, max_length); @@ -350,13 +358,13 @@ SPAN_DECLARE(int) playout_release(playout_state_t *s) for (frame = s->first_frame; frame; frame = next) { next = frame->later; - free(frame); + span_free(frame); } /* Free all the frames on the free list */ for (frame = s->free_frames; frame; frame = next) { next = frame->later; - free(frame); + span_free(frame); } return 0; } @@ -368,7 +376,7 @@ SPAN_DECLARE(int) playout_free(playout_state_t *s) { playout_release(s); /* Finally, free ourselves! */ - free(s); + span_free(s); } return 0; } diff --git a/libs/spandsp/src/plc.c b/libs/spandsp/src/plc.c index dcb07120e1..7b45dad988 100644 --- a/libs/spandsp/src/plc.c +++ b/libs/spandsp/src/plc.c @@ -43,10 +43,13 @@ #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/fast_convert.h" #include "spandsp/saturated.h" #include "spandsp/plc.h" +#include "spandsp/private/plc.h" + /* We do a straight line fade to zero volume in 50ms when we are filling in for missing data. */ #define ATTENUATION_INCREMENT 0.0025f /* Attenuation per sample */ @@ -234,7 +237,7 @@ SPAN_DECLARE(plc_state_t *) plc_init(plc_state_t *s) { if (s == NULL) { - if ((s = (plc_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (plc_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -251,7 +254,7 @@ SPAN_DECLARE(int) plc_release(plc_state_t *s) SPAN_DECLARE(int) plc_free(plc_state_t *s) { if (s) - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/power_meter.c b/libs/spandsp/src/power_meter.c index f4fb2afa8f..147fb47029 100644 --- a/libs/spandsp/src/power_meter.c +++ b/libs/spandsp/src/power_meter.c @@ -41,17 +41,25 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/power_meter.h" +#include "spandsp/private/power_meter.h" + SPAN_DECLARE(power_meter_t *) power_meter_init(power_meter_t *s, int shift) { if (s == NULL) { - if ((s = (power_meter_t *) malloc(sizeof(*s))) == NULL) + if ((s = (power_meter_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } s->shift = shift; @@ -69,7 +77,7 @@ SPAN_DECLARE(int) power_meter_release(power_meter_t *s) SPAN_DECLARE(int) power_meter_free(power_meter_t *s) { if (s) - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ @@ -147,14 +155,14 @@ SPAN_DECLARE(int32_t) power_surge_detector(power_surge_detector_state_t *s, int1 { if (pow_short <= s->surge*(pow_medium >> 10)) return 0; - s->signal_present = TRUE; + s->signal_present = true; s->medium_term.reading = s->short_term.reading; } else { if (pow_short < s->sag*(pow_medium >> 10)) { - s->signal_present = FALSE; + s->signal_present = false; s->medium_term.reading = s->short_term.reading; return 0; } @@ -181,7 +189,7 @@ SPAN_DECLARE(power_surge_detector_state_t *) power_surge_detector_init(power_sur if (s == NULL) { - if ((s = (power_surge_detector_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (power_surge_detector_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -205,7 +213,7 @@ SPAN_DECLARE(int) power_surge_detector_release(power_surge_detector_state_t *s) SPAN_DECLARE(int) power_surge_detector_free(power_surge_detector_state_t *s) { if (s) - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/queue.c b/libs/spandsp/src/queue.c index 264cee0c87..d569039969 100644 --- a/libs/spandsp/src/queue.c +++ b/libs/spandsp/src/queue.c @@ -35,15 +35,24 @@ #include #include #include +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif +#if defined(HAVE_STDATOMIC_H) +#include +#endif #include #define SPANDSP_FULLY_DEFINE_QUEUE_STATE_T #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/queue.h" #include "spandsp/private/queue.h" -SPAN_DECLARE(int) queue_empty(queue_state_t *s) +SPAN_DECLARE(bool) queue_empty(queue_state_t *s) { return (s->iptr == s->optr); } @@ -395,7 +404,7 @@ SPAN_DECLARE(queue_state_t *) queue_init(queue_state_t *s, int len, int flags) { if (s == NULL) { - if ((s = (queue_state_t *) malloc(sizeof(*s) + len + 1)) == NULL) + if ((s = (queue_state_t *) span_alloc(sizeof(*s) + len + 1)) == NULL) return NULL; } s->iptr = @@ -414,7 +423,7 @@ SPAN_DECLARE(int) queue_release(queue_state_t *s) SPAN_DECLARE(int) queue_free(queue_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/schedule.c b/libs/spandsp/src/schedule.c index 60ba12bc1f..6e38e6bd94 100644 --- a/libs/spandsp/src/schedule.c +++ b/libs/spandsp/src/schedule.c @@ -31,8 +31,14 @@ #include #include #include +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/schedule.h" @@ -53,7 +59,7 @@ SPAN_DECLARE(int) span_schedule_event(span_sched_state_t *s, int us, span_sched_ if (i >= s->allocated) { s->allocated += 5; - s->sched = (span_sched_t *) realloc(s->sched, sizeof(span_sched_t)*s->allocated); + s->sched = (span_sched_t *) span_realloc(s->sched, sizeof(span_sched_t)*s->allocated); } /*endif*/ if (i >= s->max_to_date) @@ -141,7 +147,7 @@ SPAN_DECLARE(int) span_schedule_release(span_sched_state_t *s) { if (s->sched) { - free(s->sched); + span_free(s->sched); s->sched = NULL; } return 0; @@ -152,7 +158,7 @@ SPAN_DECLARE(int) span_schedule_free(span_sched_state_t *s) { span_schedule_release(s); if (s) - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/sig_tone.c b/libs/spandsp/src/sig_tone.c index 5e4e180178..e40d39ac37 100644 --- a/libs/spandsp/src/sig_tone.c +++ b/libs/spandsp/src/sig_tone.c @@ -38,12 +38,18 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include #include #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/fast_convert.h" #include "spandsp/saturated.h" #include "spandsp/vector_int.h" @@ -53,6 +59,7 @@ #include "spandsp/super_tone_rx.h" #include "spandsp/sig_tone.h" +#include "spandsp/private/power_meter.h" #include "spandsp/private/sig_tone.h" /*! PI */ @@ -225,7 +232,7 @@ SPAN_DECLARE(int) sig_tone_tx(sig_tone_tx_state_t *s, int16_t amp[], int len) int k; int n; int16_t tone; - int need_update; + bool need_update; int high_low; for (i = 0; i < len; i += n) @@ -235,19 +242,19 @@ SPAN_DECLARE(int) sig_tone_tx(sig_tone_tx_state_t *s, int16_t amp[], int len) if (s->current_tx_timeout <= len - i) { n = s->current_tx_timeout; - need_update = TRUE; + need_update = true; } else { n = len - i; - need_update = FALSE; + need_update = false; } s->current_tx_timeout -= n; } else { n = len - i; - need_update = FALSE; + need_update = false; } if (!(s->current_tx_tone & SIG_TONE_TX_PASSTHROUGH)) vec_zeroi16(&[i], n); @@ -325,7 +332,7 @@ SPAN_DECLARE(sig_tone_tx_state_t *) sig_tone_tx_init(sig_tone_tx_state_t *s, int if (s == NULL) { - if ((s = (sig_tone_tx_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (sig_tone_tx_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -357,7 +364,7 @@ SPAN_DECLARE(int) sig_tone_tx_release(sig_tone_tx_state_t *s) SPAN_DECLARE(int) sig_tone_tx_free(sig_tone_tx_state_t *s) { if (s) - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ @@ -448,13 +455,13 @@ SPAN_DECLARE(int) sig_tone_rx(sig_tone_rx_state_t *s, int16_t amp[], int len) if ((s->signalling_state & (SIG_TONE_1_PRESENT | SIG_TONE_2_PRESENT))) { if (s->flat_mode_timeout && --s->flat_mode_timeout == 0) - s->flat_mode = TRUE; + s->flat_mode = true; /*endif*/ } else { s->flat_mode_timeout = s->desc->sharp_flat_timeout; - s->flat_mode = FALSE; + s->flat_mode = false; } /*endif*/ @@ -641,7 +648,7 @@ SPAN_DECLARE(sig_tone_rx_state_t *) sig_tone_rx_init(sig_tone_rx_state_t *s, int if (s == NULL) { - if ((s = (sig_tone_rx_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (sig_tone_rx_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -685,7 +692,7 @@ SPAN_DECLARE(int) sig_tone_rx_release(sig_tone_rx_state_t *s) SPAN_DECLARE(int) sig_tone_rx_free(sig_tone_rx_state_t *s) { if (s) - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/silence_gen.c b/libs/spandsp/src/silence_gen.c index ad7d7caed0..7c24f4334e 100644 --- a/libs/spandsp/src/silence_gen.c +++ b/libs/spandsp/src/silence_gen.c @@ -40,11 +40,17 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/async.h" #include "spandsp/silence_gen.h" @@ -119,7 +125,7 @@ SPAN_DECLARE(silence_gen_state_t *) silence_gen_init(silence_gen_state_t *s, int { if (s == NULL) { - if ((s = (silence_gen_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (silence_gen_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -137,7 +143,7 @@ SPAN_DECLARE(int) silence_gen_release(silence_gen_state_t *s) SPAN_DECLARE(int) silence_gen_free(silence_gen_state_t *s) { if (s) - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp.h.in b/libs/spandsp/src/spandsp.h.in index 8dcafa50e8..747f4a432f 100644 --- a/libs/spandsp/src/spandsp.h.in +++ b/libs/spandsp/src/spandsp.h.in @@ -33,8 +33,8 @@ @SPANDSP_USE_EXPORT_CAPABILITY@ -@SPANDSP_SUPPORT_T42@ @SPANDSP_SUPPORT_T43@ +@SPANDSP_SUPPORT_V32BIS@ @SPANDSP_SUPPORT_V34@ @SPANDSP_SUPPORT_TIFF_FX@ @@ -44,9 +44,11 @@ #include #include @INSERT_MATH_HEADER@ +@INSERT_STDBOOL_HEADER@ #include #include +#include #include #include #include @@ -90,17 +92,21 @@ #include #include #include -#include -#include #include #include #include #include -/*#include */ #include #include #include -/*#include */ +#if defined(SPANDSP_SUPPORT_V32BIS) +#include +#endif +#if defined(SPANDSP_SUPPORT_V34) +#include +#endif +#include +#include #include #include #include @@ -111,7 +117,7 @@ #include #include #include -/*#include */ +#include #include #include #include diff --git a/libs/spandsp/src/spandsp/alloc.h b/libs/spandsp/src/spandsp/alloc.h new file mode 100644 index 0000000000..3bb691b05a --- /dev/null +++ b/libs/spandsp/src/spandsp/alloc.h @@ -0,0 +1,77 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * alloc.h - memory allocation handling. + * + * Written by Steve Underwood + * + * Copyright (C) 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(_SPANDSP_ALLOC_H_) +#define _SPANDSP_ALLOC_H_ + +/* Notes: + - Most platforms don't have an aligned realloc function, so we don't try to + support an aligned realloc on any platform. + - Some platforms use a special free function for memory which was allocated + by alligned allocation functions. We use a separate aligned_free function + on all platforms, for compatibility, even though it may simply reduce to + free(). + */ + +typedef void *(*span_aligned_alloc_t)(size_t alignment, size_t size); +typedef void (*span_aligned_free_t)(void *ptr); +typedef void *(*span_alloc_t)(size_t size); +typedef void *(*span_realloc_t)(void *ptr, size_t size); +typedef void (*span_free_t)(void *ptr); + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/* Allocate size bytes allocated to ALIGNMENT bytes. */ +SPAN_DECLARE(void *) span_aligned_alloc(size_t alignment, size_t size); + +/* Free a block allocated by span_aligned_alloc, or span_aligned_realloc. */ +SPAN_DECLARE(void) span_aligned_free(void *ptr); + +/* Allocate size bytes of memory. */ +SPAN_DECLARE(void *) span_alloc(size_t size); + +/* Re-allocate the previously allocated block in ptr, making the new block size bytes long. */ +SPAN_DECLARE(void *) span_realloc(void *ptr, size_t size); + +/* Free a block allocated by span_alloc or span_realloc. */ +SPAN_DECLARE(void) span_free(void *ptr); + +SPAN_DECLARE(int) span_mem_allocators(span_alloc_t custom_alloc, + span_realloc_t custom_realloc, + span_free_t custom_free, + span_aligned_alloc_t custom_aligned_alloc, + span_aligned_free_t custom_aligned_free); + +#if defined(__cplusplus) +} +#endif + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/async.h b/libs/spandsp/src/spandsp/async.h index 1b22cd5caf..eabb41d3f1 100644 --- a/libs/spandsp/src/spandsp/async.h +++ b/libs/spandsp/src/spandsp/async.h @@ -164,7 +164,7 @@ SPAN_DECLARE_NONSTD(void) async_rx_put_bit(void *user_data, int bit); \param data_bits The number of data bits. \param parity_bits The type of parity. \param stop_bits The number of stop bits. - \param use_v14 TRUE if V.14 rate adaption processing should be used. + \param use_v14 True if V.14 rate adaption processing should be used. \param put_byte The callback routine used to put the received data. \param user_data An opaque pointer. \return A pointer to the initialised context, or NULL if there was a problem. */ @@ -172,7 +172,7 @@ SPAN_DECLARE(async_rx_state_t *) async_rx_init(async_rx_state_t *s, int data_bits, int parity_bits, int stop_bits, - int use_v14, + bool use_v14, put_byte_func_t put_byte, void *user_data); @@ -198,7 +198,7 @@ SPAN_DECLARE_NONSTD(int) async_tx_get_bit(void *user_data); \param data_bits The number of data bit. \param parity_bits The type of parity. \param stop_bits The number of stop bits. - \param use_v14 TRUE if V.14 rate adaption processing should be used. + \param use_v14 True if V.14 rate adaption processing should be used. \param get_byte The callback routine used to get the data to be transmitted. \param user_data An opaque pointer. \return A pointer to the initialised context, or NULL if there was a problem. */ @@ -206,7 +206,7 @@ SPAN_DECLARE(async_tx_state_t *) async_tx_init(async_tx_state_t *s, int data_bits, int parity_bits, int stop_bits, - int use_v14, + bool use_v14, get_byte_func_t get_byte, void *user_data); diff --git a/libs/spandsp/src/spandsp/at_interpreter.h b/libs/spandsp/src/spandsp/at_interpreter.h index 7f8ebbb16b..aa390d509b 100644 --- a/libs/spandsp/src/spandsp/at_interpreter.h +++ b/libs/spandsp/src/spandsp/at_interpreter.h @@ -115,14 +115,14 @@ enum */ typedef struct { - /*! TRUE if character echo is enabled */ - int echo; - /*! TRUE if verbose reporting is enabled */ - int verbose; - /*! TRUE if result codes are verbose */ + /*! True if character echo is enabled */ + bool echo; + /*! True if verbose reporting is enabled */ + bool verbose; + /*! Result code format code - numeic or verbose */ int result_code_format; - /*! TRUE if pulse dialling is the default */ - int pulse_dial; + /*! True if pulse dialling is the default */ + bool pulse_dial; /*! ??? */ int double_escape; /*! ??? */ diff --git a/libs/spandsp/src/spandsp/bell_r2_mf.h b/libs/spandsp/src/spandsp/bell_r2_mf.h index 98d9f749e8..2d40848a34 100644 --- a/libs/spandsp/src/spandsp/bell_r2_mf.h +++ b/libs/spandsp/src/spandsp/bell_r2_mf.h @@ -175,10 +175,10 @@ SPAN_DECLARE(int) r2_mf_tx_put(r2_mf_tx_state_t *s, char digit); /*! \brief Initialise an R2 MF tone generator context. \param s The R2 MF generator context. - \param fwd TRUE if the context is for forward signals. FALSE if the + \param fwd True if the context is for forward signals. False if the context is for backward signals. \return A pointer to the MFC/R2 generator context.*/ -SPAN_DECLARE(r2_mf_tx_state_t *) r2_mf_tx_init(r2_mf_tx_state_t *s, int fwd); +SPAN_DECLARE(r2_mf_tx_state_t *) r2_mf_tx_init(r2_mf_tx_state_t *s, bool fwd); /*! \brief Release an R2 MF tone generator context. \param s The R2 MF tone generator context. @@ -242,7 +242,7 @@ SPAN_DECLARE(int) r2_mf_rx_get(r2_mf_rx_state_t *s); /*! \brief Initialise an R2 MF receiver context. \param s The R2 MF receiver context. - \param fwd TRUE if the context is for forward signals. FALSE if the + \param fwd True if the context is for forward signals. False if the context is for backward signals. \param callback An optional callback routine, used to report received digits. If no callback routine is set, digits may be collected, using the r2_mf_rx_get() @@ -251,7 +251,7 @@ SPAN_DECLARE(int) r2_mf_rx_get(r2_mf_rx_state_t *s); and supplied in callbacks. \return A pointer to the R2 MF receiver context. */ SPAN_DECLARE(r2_mf_rx_state_t *) r2_mf_rx_init(r2_mf_rx_state_t *s, - int fwd, + bool fwd, tone_report_func_t callback, void *user_data); diff --git a/libs/spandsp/src/spandsp/bit_operations.h b/libs/spandsp/src/spandsp/bit_operations.h index 2deca2828a..311408123e 100644 --- a/libs/spandsp/src/spandsp/bit_operations.h +++ b/libs/spandsp/src/spandsp/bit_operations.h @@ -42,7 +42,7 @@ extern "C" /*! \brief Find the bit position of the highest set bit in a word \param bits The word to be searched \return The bit number of the highest set bit, or -1 if the word is zero. */ -static __inline__ int top_bit(unsigned int bits) +static __inline__ int top_bit(uint32_t bits) { #if defined(SPANDSP_USE_86_ASM) int res; @@ -141,7 +141,7 @@ static __inline__ int top_bit(unsigned int bits) /*! \brief Find the bit position of the lowest set bit in a word \param bits The word to be searched \return The bit number of the lowest set bit, or -1 if the word is zero. */ -static __inline__ int bottom_bit(unsigned int bits) +static __inline__ int bottom_bit(uint32_t bits) { int res; diff --git a/libs/spandsp/src/spandsp/bitstream.h b/libs/spandsp/src/spandsp/bitstream.h index b55e4afd16..edbaedb48f 100644 --- a/libs/spandsp/src/spandsp/bitstream.h +++ b/libs/spandsp/src/spandsp/bitstream.h @@ -71,7 +71,7 @@ SPAN_DECLARE(void) bitstream_flush(bitstream_state_t *s, uint8_t **c); /*! \brief Initialise a bitstream context. \param s A pointer to the bitstream context. - \param lsb_first TRUE if the bit stream is LSB first, else its MSB first. + \param lsb_first True if the bit stream is LSB first, else its MSB first. \return A pointer to the bitstream context. */ SPAN_DECLARE(bitstream_state_t *) bitstream_init(bitstream_state_t *s, int direction); diff --git a/libs/spandsp/src/spandsp/crc.h b/libs/spandsp/src/spandsp/crc.h index a4d9b8040a..9d02355621 100644 --- a/libs/spandsp/src/spandsp/crc.h +++ b/libs/spandsp/src/spandsp/crc.h @@ -60,9 +60,9 @@ SPAN_DECLARE(int) crc_itu32_append(uint8_t *buf, int len); /*! \brief Check the ITU/CCITT CRC-32 value in a frame. \param buf The buffer containing the frame. \param len The length of the frame. - \return TRUE if the CRC is OK, else FALSE. + \return True if the CRC is OK, else false. */ -SPAN_DECLARE(int) crc_itu32_check(const uint8_t *buf, int len); +SPAN_DECLARE(bool) crc_itu32_check(const uint8_t *buf, int len); /*! \brief Calculate the ITU/CCITT CRC-16 value in buffer by whole bytes. \param buf The buffer containing the data. @@ -93,9 +93,9 @@ SPAN_DECLARE(int) crc_itu16_append(uint8_t *buf, int len); /*! \brief Check the ITU/CCITT CRC-16 value in a frame. \param buf The buffer containing the frame. \param len The length of the frame. - \return TRUE if the CRC is OK, else FALSE. + \return True if the CRC is OK, else false. */ -SPAN_DECLARE(int) crc_itu16_check(const uint8_t *buf, int len); +SPAN_DECLARE(bool) crc_itu16_check(const uint8_t *buf, int len); #if defined(__cplusplus) } diff --git a/libs/spandsp/src/spandsp/dtmf.h b/libs/spandsp/src/spandsp/dtmf.h index df9660feee..15915f75a6 100644 --- a/libs/spandsp/src/spandsp/dtmf.h +++ b/libs/spandsp/src/spandsp/dtmf.h @@ -156,7 +156,7 @@ SPAN_DECLARE(void) dtmf_rx_set_realtime_callback(dtmf_rx_state_t *s, /*! \brief Adjust a DTMF receiver context. \param s The DTMF receiver context. - \param filter_dialtone TRUE to enable filtering of dialtone, FALSE + \param filter_dialtone True to enable filtering of dialtone, false to disable, < 0 to leave unchanged. \param twist Acceptable twist, in dB. < 0.0 to leave unchanged. \param reverse_twist Acceptable reverse twist, in dB. < 0.0 to leave unchanged. diff --git a/libs/spandsp/src/spandsp/expose.h b/libs/spandsp/src/spandsp/expose.h index 2f90c7f2d4..b65a21f1b9 100644 --- a/libs/spandsp/src/spandsp/expose.h +++ b/libs/spandsp/src/spandsp/expose.h @@ -31,6 +31,8 @@ #if !defined(_SPANDSP_EXPOSE_H_) #define _SPANDSP_EXPOSE_H_ +#include + #include #include #include @@ -38,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +50,8 @@ #include #include #include +#include +#include #include #include #include @@ -68,11 +73,16 @@ #include #include #include -/*#include */ -/*#include */ +#if defined(SPANDSP_SUPPORT_V32BIS) +#include +#endif +#if defined(SPANDSP_SUPPORT_V34) +#include +#endif #include #include #include +//#include #include #include #include @@ -81,7 +91,7 @@ #include #include #include -/*#include */ +#include #include #include #include diff --git a/libs/spandsp/src/spandsp/fast_convert.h b/libs/spandsp/src/spandsp/fast_convert.h index e6da451f9c..120050646f 100644 --- a/libs/spandsp/src/spandsp/fast_convert.h +++ b/libs/spandsp/src/spandsp/fast_convert.h @@ -247,6 +247,7 @@ extern "C" * Therefore implement inline versions of these functions here. */ +#if (_MSC_VER < 1800) __inline long int lrint(double x) { long int i; @@ -288,6 +289,7 @@ extern "C" frndint } } +#endif __inline long int lfastrint(double x) { @@ -317,6 +319,7 @@ extern "C" /* x86_64 machines will do best with a simple assignment. */ #include +#if (_MSC_VER < 1800) __inline long int lrint(double x) { return (long int)_mm_cvtsd_si64x( _mm_loadu_pd ((const double*)&x) ); @@ -326,6 +329,7 @@ extern "C" { return _mm_cvt_ss2si( _mm_load_ss((const float*)&x) ); } +#endif __inline long int lfastrint(double x) { diff --git a/libs/spandsp/src/spandsp/fax.h b/libs/spandsp/src/spandsp/fax.h index 9d268770bc..01dbb80d80 100644 --- a/libs/spandsp/src/spandsp/fax.h +++ b/libs/spandsp/src/spandsp/fax.h @@ -75,16 +75,16 @@ SPAN_DECLARE_NONSTD(int) fax_tx(fax_state_t *s, int16_t *amp, int max_len); /*! Select whether silent audio will be sent when FAX transmit is idle. \brief Select whether silent audio will be sent when FAX transmit is idle. \param s The FAX context. - \param transmit_on_idle TRUE if silent audio should be output when the FAX transmitter is - idle. FALSE to transmit zero length audio when the FAX transmitter is idle. The default - behaviour is FALSE. + \param transmit_on_idle True if silent audio should be output when the FAX transmitter is + idle. False to transmit zero length audio when the FAX transmitter is idle. The default + behaviour is false. */ SPAN_DECLARE(void) fax_set_transmit_on_idle(fax_state_t *s, int transmit_on_idle); /*! Select whether talker echo protection tone will be sent for the image modems. \brief Select whether TEP will be sent for the image modems. \param s The FAX context. - \param use_tep TRUE if TEP should be sent. + \param use_tep True if TEP should be sent. */ SPAN_DECLARE(void) fax_set_tep_mode(fax_state_t *s, int use_tep); @@ -105,7 +105,7 @@ SPAN_DECLARE(logging_state_t *) fax_get_logging_state(fax_state_t *s); /*! Restart a FAX context. \brief Restart a FAX context. \param s The FAX context. - \param calling_party TRUE if the context is for a calling party. FALSE if the + \param calling_party True if the context is for a calling party. False if the context is for an answering party. \return 0 for OK, else -1. */ SPAN_DECLARE(int) fax_restart(fax_state_t *s, int calling_party); @@ -113,7 +113,7 @@ SPAN_DECLARE(int) fax_restart(fax_state_t *s, int calling_party); /*! Initialise a FAX context. \brief Initialise a FAX context. \param s The FAX context. - \param calling_party TRUE if the context is for a calling party. FALSE if the + \param calling_party True if the context is for a calling party. False if the context is for an answering party. \return A pointer to the FAX context, or NULL if there was a problem. */ diff --git a/libs/spandsp/src/spandsp/fax_modems.h b/libs/spandsp/src/spandsp/fax_modems.h index 3c76022575..3a6adf28c1 100644 --- a/libs/spandsp/src/spandsp/fax_modems.h +++ b/libs/spandsp/src/spandsp/fax_modems.h @@ -59,6 +59,14 @@ extern "C" { #endif +SPAN_DECLARE(void) fax_modems_hdlc_accept(void *user_data, const uint8_t *msg, int len, int ok); + +/*! Convert a FAX modem type to a short text description. + \brief Convert a FAX modem type to a short text description. + \param modem The modem code. + \return A pointer to the description. */ +SPAN_DECLARE(const char *) fax_modem_to_str(int modem); + /* N.B. the following are currently a work in progress */ SPAN_DECLARE_NONSTD(int) fax_modems_v17_v21_rx(void *user_data, const int16_t amp[], int len); SPAN_DECLARE_NONSTD(int) fax_modems_v27ter_v21_rx(void *user_data, const int16_t amp[], int len); @@ -93,6 +101,8 @@ SPAN_DECLARE(void) fax_modems_set_tx_handler(fax_modems_state_t *s, span_tx_hand SPAN_DECLARE(void) fax_modems_set_next_tx_handler(fax_modems_state_t *s, span_tx_handler_t handler, void *user_data); +SPAN_DECLARE(int) fax_modems_set_next_tx_type(fax_modems_state_t *s); + SPAN_DECLARE(int) fax_modems_restart(fax_modems_state_t *s); /*! Get a pointer to the logging context associated with a FAX modems context. diff --git a/libs/spandsp/src/spandsp/fsk.h b/libs/spandsp/src/spandsp/fsk.h index bcb8df1de7..b65cd7842f 100644 --- a/libs/spandsp/src/spandsp/fsk.h +++ b/libs/spandsp/src/spandsp/fsk.h @@ -109,9 +109,10 @@ enum FSK_BELL103CH1, FSK_BELL103CH2, FSK_BELL202, - FSK_WEITBRECHT, /* 45.45 baud version, used for TDD (Telecom Device for the Deaf) */ - FSK_WEITBRECHT50, /* 50 baud version, used for TDD (Telecom Device for the Deaf) */ - FSK_V21CH1_110 /* 110 bps version of V.21 channel 1, as used by V.18 */ + FSK_WEITBRECHT_4545, /* 45.45 baud version, used for TDD (Telecom Device for the Deaf) */ + FSK_WEITBRECHT_50, /* 50 baud version, used for TDD (Telecom Device for the Deaf) */ + FSK_WEITBRECHT_476, /* 47.6 baud version, used for V.18 probing */ + FSK_V21CH1_110 /* 110 bps version of V.21 channel 1, as used by V.18 */ }; enum diff --git a/libs/spandsp/src/spandsp/g722.h b/libs/spandsp/src/spandsp/g722.h index 1716e0a0db..ee36c456ca 100644 --- a/libs/spandsp/src/spandsp/g722.h +++ b/libs/spandsp/src/spandsp/g722.h @@ -21,15 +21,8 @@ * 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. - * - * Based on a single channel G.722 codec which is: - * - ***** Copyright (c) CMU 1993 ***** - * Computer Science, Speech Group - * Chengxiang Lu and Alex Hauptmann */ - /*! \file */ #if !defined(_SPANDSP_G722_H_) diff --git a/libs/spandsp/src/spandsp/hdlc.h b/libs/spandsp/src/spandsp/hdlc.h index cf5efe4330..a0916d1d5f 100644 --- a/libs/spandsp/src/spandsp/hdlc.h +++ b/libs/spandsp/src/spandsp/hdlc.h @@ -83,8 +83,8 @@ extern "C" /*! \brief Initialise an HDLC receiver context. \param s A pointer to an HDLC receiver context. - \param crc32 TRUE to use ITU CRC32. FALSE to use ITU CRC16. - \param report_bad_frames TRUE to request the reporting of bad frames. + \param crc32 True to use ITU CRC32. False to use ITU CRC16. + \param report_bad_frames True to request the reporting of bad frames. \param framing_ok_threshold The number of back-to-back flags needed to start the framing OK condition. This may be used where a series of flag octets is used as a preamble, such as in the T.30 protocol. @@ -93,8 +93,8 @@ extern "C" \return A pointer to the HDLC receiver context. */ SPAN_DECLARE(hdlc_rx_state_t *) hdlc_rx_init(hdlc_rx_state_t *s, - int crc32, - int report_bad_frames, + bool crc32, + bool report_bad_frames, int framing_ok_threshold, hdlc_frame_handler_t handler, void *user_data); @@ -169,17 +169,17 @@ SPAN_DECLARE_NONSTD(void) hdlc_rx_put(hdlc_rx_state_t *s, const uint8_t buf[], i /*! \brief Initialise an HDLC transmitter context. \param s A pointer to an HDLC transmitter context. - \param crc32 TRUE to use ITU CRC32. FALSE to use ITU CRC16. + \param crc32 True to use ITU CRC32. False to use ITU CRC16. \param inter_frame_flags The minimum flag octets to insert between frames (usually one). - \param progressive TRUE if frame creation works in progressive mode. + \param progressive True if frame creation works in progressive mode. \param handler The callback function called when the HDLC transmitter underflows. \param user_data An opaque parameter for the callback routine. \return A pointer to the HDLC transmitter context. */ SPAN_DECLARE(hdlc_tx_state_t *) hdlc_tx_init(hdlc_tx_state_t *s, - int crc32, + bool crc32, int inter_frame_flags, - int progressive, + bool progressive, hdlc_underflow_handler_t handler, void *user_data); diff --git a/libs/spandsp/src/spandsp/image_translate.h b/libs/spandsp/src/spandsp/image_translate.h index d98848f369..087ef3f583 100644 --- a/libs/spandsp/src/spandsp/image_translate.h +++ b/libs/spandsp/src/spandsp/image_translate.h @@ -66,29 +66,39 @@ SPAN_DECLARE(int) image_translate_get_output_width(image_translate_state_t *s); \return The length of the output image, in pixel. */ SPAN_DECLARE(int) image_translate_get_output_length(image_translate_state_t *s); +/*! \brief Set the row read callback routine for an image translation context. + \param s The image translation context. + \param row_read_handler A callback routine used to pull rows of pixels from the source image + into the translation process. + \param row_read_user_data An opaque pointer passed to read_row_handler + \return 0 for success, else -1. */ +SPAN_DECLARE(int) image_translate_set_row_read_handler(image_translate_state_t *s, t4_row_read_handler_t row_read_handler, void *row_read_user_data); + +SPAN_DECLARE(int) image_translate_restart(image_translate_state_t *s, int input_length); + /*! \brief Initialise an image translation context for rescaling and squashing a gray scale or colour image to a bi-level FAX type image. \param s The image translation context. - \param input_format x - \param input_width The width of the source image, in pixels. - \param input_length The length of the source image, in pixels. - \param output_format x + \param output_format The type of output image \param output_width The width of the output image, in pixels. If this is set <= 0 the image will not be resized. \param output_length The length of the output image, in pixels. If this is set to <= 0 the output length will be derived automatically from the width, to maintain the geometry of the original image. + \param input_format The type of source image + \param input_width The width of the source image, in pixels. + \param input_length The length of the source image, in pixels. \param row_read_handler A callback routine used to pull rows of pixels from the source image into the translation process. - \param row_read_user_data An opaque point passed to read_row_handler + \param row_read_user_data An opaque pointer passed to read_row_handler \return A pointer to the context, or NULL if there was a problem. */ SPAN_DECLARE(image_translate_state_t *) image_translate_init(image_translate_state_t *s, - int input_format, - int input_width, - int input_length, int output_format, int output_width, int output_length, + int input_format, + int input_width, + int input_length, t4_row_read_handler_t row_read_handler, void *row_read_user_data); diff --git a/libs/spandsp/src/spandsp/logging.h b/libs/spandsp/src/spandsp/logging.h index 2de8eb8767..78db086ef0 100644 --- a/libs/spandsp/src/spandsp/logging.h +++ b/libs/spandsp/src/spandsp/logging.h @@ -80,9 +80,9 @@ extern "C" \brief Test if logging of a specified severity level is enabled. \param s The logging context. \param level The severity level to be tested. - \return TRUE if logging is enable, else FALSE. + \return True if logging is enable. */ -SPAN_DECLARE(int) span_log_test(logging_state_t *s, int level); +SPAN_DECLARE(bool) span_log_test(logging_state_t *s, int level); /*! Generate a log entry. \brief Generate a log entry. diff --git a/libs/spandsp/src/spandsp/modem_connect_tones.h b/libs/spandsp/src/spandsp/modem_connect_tones.h index 7c2b980753..713f813bbb 100644 --- a/libs/spandsp/src/spandsp/modem_connect_tones.h +++ b/libs/spandsp/src/spandsp/modem_connect_tones.h @@ -153,7 +153,7 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx_fillin(modem_connect_tones_rx_st /*! \brief Test if a modem_connect tone has been detected. \param s The context. - \return TRUE if tone is detected, else FALSE. + \return The code for the detected tone. */ SPAN_DECLARE(int) modem_connect_tones_rx_get(modem_connect_tones_rx_state_t *s); diff --git a/libs/spandsp/src/spandsp/playout.h b/libs/spandsp/src/spandsp/playout.h index 582fcb2c51..8e038086df 100644 --- a/libs/spandsp/src/spandsp/playout.h +++ b/libs/spandsp/src/spandsp/playout.h @@ -56,80 +56,13 @@ enum typedef int timestamp_t; -typedef struct playout_frame_s -{ - /*! The actual frame data */ - void *data; - /*! The type of frame */ - int type; - /*! The timestamp assigned by the sending end */ - timestamp_t sender_stamp; - /*! The timespan covered by the data in this frame */ - timestamp_t sender_len; - /*! The timestamp assigned by the receiving end */ - timestamp_t receiver_stamp; - /*! Pointer to the next earlier frame */ - struct playout_frame_s *earlier; - /*! Pointer to the next later frame */ - struct playout_frame_s *later; -} playout_frame_t; +typedef struct playout_frame_s playout_frame_t; /*! Playout (jitter buffer) descriptor. This defines the working state for a single instance of playout buffering. */ -typedef struct -{ - /*! TRUE if the buffer is dynamically sized */ - int dynamic; - /*! The minimum length (dynamic) or fixed length (static) of the buffer */ - int min_length; - /*! The maximum length (dynamic) or fixed length (static) of the buffer */ - int max_length; - /*! The target filter threshold for adjusting dynamic buffering. */ - int dropable_threshold; - - int start; - - /*! The queued frame list */ - playout_frame_t *first_frame; - playout_frame_t *last_frame; - /*! The free frame pool */ - playout_frame_t *free_frames; - - /*! The total frames input to the buffer, to date. */ - int frames_in; - /*! The total frames output from the buffer, to date. */ - int frames_out; - /*! The number of frames received out of sequence. */ - int frames_oos; - /*! The number of frames which were discarded, due to late arrival. */ - int frames_late; - /*! The number of frames which were never received. */ - int frames_missing; - /*! The number of frames trimmed from the stream, due to buffer shrinkage. */ - int frames_trimmed; - - timestamp_t latest_expected; - /*! The present jitter adjustment */ - timestamp_t current; - /*! The sender_stamp of the last speech frame */ - timestamp_t last_speech_sender_stamp; - /*! The duration of the last speech frame */ - timestamp_t last_speech_sender_len; - - int not_first; - /*! The time since the target buffer length was last changed. */ - timestamp_t since_last_step; - /*! Filter state for tracking the packets arriving just in time */ - int32_t state_just_in_time; - /*! Filter state for tracking the packets arriving late */ - int32_t state_late; - /*! The current target length of the buffer */ - int target_buffer_length; - /*! The current actual length of the buffer, which may lag behind the target value */ - int actual_buffer_length; -} playout_state_t; +typedef struct playout_state_s playout_state_t; #if defined(__cplusplus) extern "C" diff --git a/libs/spandsp/src/spandsp/plc.h b/libs/spandsp/src/spandsp/plc.h index 801c6ac65f..6d5c301073 100644 --- a/libs/spandsp/src/spandsp/plc.h +++ b/libs/spandsp/src/spandsp/plc.h @@ -109,21 +109,7 @@ That's it! /*! The generic packet loss concealer context. */ -typedef struct -{ - /*! Consecutive erased samples */ - int missing_samples; - /*! Current offset into pitch period */ - int pitch_offset; - /*! Pitch estimate */ - int pitch; - /*! Buffer for a cycle of speech */ - float pitchbuf[PLC_PITCH_MIN]; - /*! History buffer */ - int16_t history[PLC_HISTORY_LEN]; - /*! Current pointer into the history buffer */ - int buf_ptr; -} plc_state_t; +typedef struct plc_state_s plc_state_t; #if defined(__cplusplus) diff --git a/libs/spandsp/src/spandsp/power_meter.h b/libs/spandsp/src/spandsp/power_meter.h index 5eff21fccd..e949858607 100644 --- a/libs/spandsp/src/spandsp/power_meter.h +++ b/libs/spandsp/src/spandsp/power_meter.h @@ -23,8 +23,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if !defined(_POWER_METER_H_) -#define _POWER_METER_H_ +#if !defined(_SPANDSP_POWER_METER_H_) +#define _SPANDSP_POWER_METER_H_ /*! \page power_meter_page Power metering @@ -45,24 +45,9 @@ values +/-8031, and this square wave represents 0dBov. This translates into 6.1 Power meter descriptor. This defines the working state for a single instance of a power measurement device. */ -typedef struct -{ - /*! The shift factor, which controls the damping of the power meter. */ - int shift; +typedef struct power_meter_s power_meter_t; - /*! The current power reading. */ - int32_t reading; -} power_meter_t; - -typedef struct -{ - power_meter_t short_term; - power_meter_t medium_term; - int signal_present; - int32_t surge; - int32_t sag; - int32_t min; -} power_surge_detector_state_t; +typedef struct power_surge_detector_state_s power_surge_detector_state_t; #if defined(__cplusplus) extern "C" diff --git a/libs/spandsp/src/spandsp/private/async.h b/libs/spandsp/src/spandsp/private/async.h index 39bb1d4a44..1c9c926595 100644 --- a/libs/spandsp/src/spandsp/private/async.h +++ b/libs/spandsp/src/spandsp/private/async.h @@ -69,8 +69,8 @@ struct async_rx_state_s int parity; /*! \brief The number of stop bits per character. */ int stop_bits; - /*! \brief TRUE if V.14 rate adaption processing should be performed. */ - int use_v14; + /*! \brief True if V.14 rate adaption processing should be performed. */ + bool use_v14; /*! \brief A pointer to the callback routine used to handle received characters. */ put_byte_func_t put_byte; /*! \brief An opaque pointer passed when calling put_byte. */ diff --git a/libs/spandsp/src/spandsp/private/at_interpreter.h b/libs/spandsp/src/spandsp/private/at_interpreter.h index a60a9aa46e..3ddade99c5 100644 --- a/libs/spandsp/src/spandsp/private/at_interpreter.h +++ b/libs/spandsp/src/spandsp/private/at_interpreter.h @@ -106,10 +106,10 @@ struct at_state_s int command_dial; int ok_is_pending; int dte_is_waiting; - /*! \brief TRUE if a carrier is presnt. Otherwise FALSE. */ - int rx_signal_present; - /*! \brief TRUE if a modem has trained, Otherwise FALSE. */ - int rx_trained; + /*! \brief True if a carrier is presnt. Otherwise false. */ + bool rx_signal_present; + /*! \brief True if a modem has trained, Otherwise false. */ + bool rx_trained; int transmit; char line[256]; diff --git a/libs/spandsp/src/spandsp/private/bell_r2_mf.h b/libs/spandsp/src/spandsp/private/bell_r2_mf.h index 234e4c9ba0..d0681be23f 100644 --- a/libs/spandsp/src/spandsp/private/bell_r2_mf.h +++ b/libs/spandsp/src/spandsp/private/bell_r2_mf.h @@ -73,8 +73,8 @@ struct r2_mf_tx_state_s { /*! The tone generator. */ tone_gen_state_t tone; - /*! TRUE if generating forward tones, otherwise generating reverse tones. */ - int fwd; + /*! True if generating forward tones, otherwise generating reverse tones. */ + bool fwd; /*! The current digit being generated. */ int digit; }; @@ -88,8 +88,8 @@ struct r2_mf_rx_state_s tone_report_func_t callback; /*! An opaque pointer passed to the callback function. */ void *callback_data; - /*! TRUE is we are detecting forward tones. FALSE if we are detecting backward tones */ - int fwd; + /*! Tue is we are detecting forward tones. False if we are detecting backward tones */ + bool fwd; /*! Tone detector working states */ goertzel_state_t out[6]; /*! The current sample number within a processing block. */ diff --git a/libs/spandsp/src/spandsp/private/bitstream.h b/libs/spandsp/src/spandsp/private/bitstream.h index aec8d5e124..e957eabd61 100644 --- a/libs/spandsp/src/spandsp/private/bitstream.h +++ b/libs/spandsp/src/spandsp/private/bitstream.h @@ -33,8 +33,8 @@ struct bitstream_state_s uint32_t bitstream; /*! The residual bits in bitstream. */ int residue; - /*! TRUE if the stream is LSB first, else MSB first */ - int lsb_first; + /*! True if the stream is LSB first, else MSB first */ + bool lsb_first; }; diff --git a/libs/spandsp/src/spandsp/private/dtmf.h b/libs/spandsp/src/spandsp/private/dtmf.h index c773ee61ee..37450fdba5 100644 --- a/libs/spandsp/src/spandsp/private/dtmf.h +++ b/libs/spandsp/src/spandsp/private/dtmf.h @@ -61,8 +61,8 @@ struct dtmf_rx_state_s tone_report_func_t realtime_callback; /*! An opaque pointer passed to the real time callback function. */ void *realtime_callback_data; - /*! TRUE if dialtone should be filtered before processing */ - int filter_dialtone; + /*! True if dialtone should be filtered before processing */ + bool filter_dialtone; #if defined(SPANDSP_USE_FIXED_POINT) /*! 350Hz filter state for the optional dialtone filter. */ float z350[2]; diff --git a/libs/spandsp/src/spandsp/private/fax_modems.h b/libs/spandsp/src/spandsp/private/fax_modems.h index d556462a76..373a692994 100644 --- a/libs/spandsp/src/spandsp/private/fax_modems.h +++ b/libs/spandsp/src/spandsp/private/fax_modems.h @@ -33,10 +33,14 @@ */ struct fax_modems_state_s { - /*! TRUE is talker echo protection should be sent for the image modems */ - int use_tep; + /*! True is talker echo protection should be sent for the image modems */ + bool 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 (e.g. the 75ms silence between V.21 and a high speed modem) will alway be transmitted as silent audio. */ @@ -82,11 +86,6 @@ struct fax_modems_state_s /*! \brief */ 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 */ int fast_modem; @@ -111,12 +110,12 @@ struct fax_modems_state_s hdlc_frame_handler_t hdlc_accept; void *hdlc_accept_user_data; - /*! \brief TRUE if a carrier is present. Otherwise FALSE. */ - int rx_signal_present; - /*! \brief TRUE if a modem has trained correctly. */ - int rx_trained; - /*! \brief TRUE if an HDLC frame has been received correctly. */ - int rx_frame_received; + /*! \brief True if a carrier is present. Otherwise false. */ + bool rx_signal_present; + /*! \brief True if a modem has trained correctly. */ + bool rx_trained; + /*! \brief True if an HDLC frame has been received correctly. */ + bool rx_frame_received; int deferred_rx_handler_updates; /*! \brief The current receive signal handler */ @@ -146,8 +145,8 @@ struct fax_modems_state_s /*! \brief The current bit rate of the receiver. */ int rx_bit_rate; - /*! \brief If TRUE, transmission is in progress */ - int transmit; + /*! \brief If True, transmission is in progress */ + bool transmit; /*! \brief Audio logging file handle for received audio. */ int audio_rx_log; /*! \brief Audio logging file handle for transmitted audio. */ diff --git a/libs/spandsp/src/spandsp/private/g722.h b/libs/spandsp/src/spandsp/private/g722.h index 74ee517f3f..47b2abaa2f 100644 --- a/libs/spandsp/src/spandsp/private/g722.h +++ b/libs/spandsp/src/spandsp/private/g722.h @@ -21,15 +21,8 @@ * 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. - * - * Based on a single channel G.722 codec which is: - * - ***** Copyright (c) CMU 1993 ***** - * Computer Science, Speech Group - * Chengxiang Lu and Alex Hauptmann */ - /*! \file */ #if !defined(_SPANDSP_PRIVATE_G722_H_) @@ -54,13 +47,13 @@ typedef struct */ struct g722_encode_state_s { - /*! TRUE if the operating in the special ITU test mode, with the band split filters + /*! True if the operating in the special ITU test mode, with the band split filters disabled. */ - int itu_test_mode; - /*! TRUE if the G.722 data is packed */ - int packed; - /*! TRUE if encode from 8k samples/second */ - int eight_k; + bool itu_test_mode; + /*! True if the G.722 data is packed */ + bool packed; + /*! True if encode from 8k samples/second */ + bool eight_k; /*! 6 for 48000kbps, 7 for 56000kbps, or 8 for 64000kbps. */ int bits_per_sample; @@ -82,13 +75,13 @@ struct g722_encode_state_s */ struct g722_decode_state_s { - /*! TRUE if the operating in the special ITU test mode, with the band split filters + /*! True if the operating in the special ITU test mode, with the band split filters disabled. */ - int itu_test_mode; - /*! TRUE if the G.722 data is packed */ - int packed; - /*! TRUE if decode to 8k samples/second */ - int eight_k; + bool itu_test_mode; + /*! True if the G.722 data is packed */ + bool packed; + /*! True if decode to 8k samples/second */ + bool eight_k; /*! 6 for 48000kbps, 7 for 56000kbps, or 8 for 64000kbps. */ int bits_per_sample; diff --git a/libs/spandsp/src/spandsp/private/hdlc.h b/libs/spandsp/src/spandsp/private/hdlc.h index de87394daf..6390a52f08 100644 --- a/libs/spandsp/src/spandsp/private/hdlc.h +++ b/libs/spandsp/src/spandsp/private/hdlc.h @@ -43,24 +43,24 @@ struct hdlc_rx_state_s modem_status_func_t status_handler; /*! \brief An opaque parameter passed to the status callback routine. */ void *status_user_data; - /*! \brief TRUE if bad frames are to be reported. */ - int report_bad_frames; + /*! \brief True if bad frames are to be reported. */ + bool report_bad_frames; /*! \brief The number of consecutive flags which must be seen before framing is declared OK. */ int framing_ok_threshold; - /*! \brief TRUE if framing OK has been announced. */ - int framing_ok_announced; + /*! \brief True if framing OK has been announced. */ + bool framing_ok_announced; /*! \brief Number of consecutive flags seen so far. */ int flags_seen; /*! \brief The raw (stuffed) bit stream buffer. */ - unsigned int raw_bit_stream; + uint32_t raw_bit_stream; /*! \brief The destuffed bit stream buffer. */ - unsigned int byte_in_progress; + uint32_t byte_in_progress; /*! \brief The current number of bits in byte_in_progress. */ int num_bits; - /*! \brief TRUE if in octet counting mode (e.g. for MTP). */ - int octet_counting_mode; + /*! \brief True if in octet counting mode (e.g. for MTP). */ + bool octet_counting_mode; /*! \brief Octet count, to achieve the functionality needed for things like MTP. */ int octet_count; @@ -98,8 +98,8 @@ struct hdlc_tx_state_s void *user_data; /*! \brief The minimum flag octets to insert between frames. */ int inter_frame_flags; - /*! \brief TRUE if frame creation works in progressive mode. */ - int progressive; + /*! \brief True if frame creation works in progressive mode. */ + bool progressive; /*! \brief Maximum permitted frame length. */ size_t max_frame_len; @@ -113,8 +113,8 @@ struct hdlc_tx_state_s int flag_octets; /*! \brief The number of abort octets to send for a timed burst of aborts. */ int abort_octets; - /*! \brief TRUE if the next underflow of timed flag octets should be reported */ - int report_flag_underflow; + /*! \brief True if the next underflow of timed flag octets should be reported */ + bool report_flag_underflow; /*! \brief The current message being transmitted, with its CRC attached. */ uint8_t buffer[HDLC_MAXFRAME_LEN + 4]; @@ -130,8 +130,8 @@ struct hdlc_tx_state_s /*! \brief The number of bits remaining in byte. */ int bits; - /*! \brief TRUE if transmission should end on buffer underflow .*/ - int tx_end; + /*! \brief True if transmission should end on buffer underflow .*/ + bool tx_end; }; #endif diff --git a/libs/spandsp/src/spandsp/private/lpc10.h b/libs/spandsp/src/spandsp/private/lpc10.h index b61893637c..e02096e6d5 100644 --- a/libs/spandsp/src/spandsp/private/lpc10.h +++ b/libs/spandsp/src/spandsp/private/lpc10.h @@ -92,8 +92,8 @@ struct lpc10_encode_state_s int32_t l2ptr2; /*! \brief No initial value necessary */ int32_t lasti; - /*! \brief Initial value FALSE */ - int hyst; + /*! \brief Initial value false */ + bool hyst; /* State used by function lpc10_voicing */ /*! \brief Initial value 20.0f */ @@ -148,8 +148,8 @@ struct lpc10_decode_state_s /* State used by function decode */ /*! \brief Initial value 60 */ int32_t iptold; - /*! \brief Initial value TRUE */ - int first; + /*! \brief Initial value true */ + bool first; /*! \brief ??? */ int32_t ivp2h; /*! \brief ??? */ @@ -172,18 +172,18 @@ struct lpc10_decode_state_s int32_t buflen; /* State used by function pitsyn */ - /*! \brief No initial value necessary as long as first_pitsyn is initially TRUE */ + /*! \brief No initial value necessary as long as first_pitsyn is initially true */ int32_t ivoico; - /*! \brief No initial value necessary as long as first_pitsyn is initially TRUE */ + /*! \brief No initial value necessary as long as first_pitsyn is initially true */ int32_t ipito; /*! \brief Initial value 1.0f */ float rmso; - /*! \brief No initial value necessary as long as first_pitsyn is initially TRUE */ + /*! \brief No initial value necessary as long as first_pitsyn is initially true */ float rco[10]; - /*! \brief No initial value necessary as long as first_pitsyn is initially TRUE */ + /*! \brief No initial value necessary as long as first_pitsyn is initially true */ int32_t jsamp; - /*! \brief Initial value TRUE */ - int first_pitsyn; + /*! \brief Initial value true */ + bool first_pitsyn; /* State used by function bsynz */ /*! \brief ??? */ diff --git a/libs/spandsp/src/spandsp/private/modem_connect_tones.h b/libs/spandsp/src/spandsp/private/modem_connect_tones.h index c1c33d25a4..d76faf1de3 100644 --- a/libs/spandsp/src/spandsp/private/modem_connect_tones.h +++ b/libs/spandsp/src/spandsp/private/modem_connect_tones.h @@ -77,7 +77,7 @@ struct modem_connect_tones_rx_state_s int32_t am_level; /*! \brief Sample counter for the small chunks of samples, after which a test is conducted. */ int chunk_remainder; - /*! \brief TRUE is the tone is currently confirmed present in the audio. */ + /*! \brief The code for the tone currently confirmed present in the audio. */ int tone_present; /*! \brief */ int tone_on; @@ -85,7 +85,7 @@ struct modem_connect_tones_rx_state_s int tone_cycle_duration; /*! \brief A count of the number of good cycles of tone reversal seen. */ int good_cycles; - /*! \brief TRUE if the tone has been seen since the last time the user tested for it */ + /*! \brief The confirmed tone code. */ int hit; /*! \brief A V.21 FSK modem context used when searching for FAX preamble. */ fsk_rx_state_t v21rx; @@ -95,8 +95,8 @@ struct modem_connect_tones_rx_state_s int num_bits; /*! \brief Number of consecutive flags seen so far. */ int flags_seen; - /*! \brief TRUE if framing OK has been announced. */ - int framing_ok_announced; + /*! \brief True if framing OK has been announced. */ + bool framing_ok_announced; }; #endif diff --git a/libs/spandsp/src/spandsp/private/playout.h b/libs/spandsp/src/spandsp/private/playout.h new file mode 100644 index 0000000000..dd8c9a53e9 --- /dev/null +++ b/libs/spandsp/src/spandsp/private/playout.h @@ -0,0 +1,105 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * private/playout.h + * + * Written by Steve Underwood + * + * Copyright (C) 2005 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_PLAYOUT_H_) +#define _SPANDSP_PRIVATE_PLAYOUT_H_ + +struct playout_frame_s +{ + /*! The actual frame data */ + void *data; + /*! The type of frame */ + int type; + /*! The timestamp assigned by the sending end */ + timestamp_t sender_stamp; + /*! The timespan covered by the data in this frame */ + timestamp_t sender_len; + /*! The timestamp assigned by the receiving end */ + timestamp_t receiver_stamp; + /*! Pointer to the next earlier frame */ + struct playout_frame_s *earlier; + /*! Pointer to the next later frame */ + struct playout_frame_s *later; +}; + +/*! + Playout (jitter buffer) descriptor. This defines the working state + for a single instance of playout buffering. +*/ +struct playout_state_s +{ + /*! True if the buffer is dynamically sized */ + bool dynamic; + /*! The minimum length (dynamic) or fixed length (static) of the buffer */ + int min_length; + /*! The maximum length (dynamic) or fixed length (static) of the buffer */ + int max_length; + /*! The target filter threshold for adjusting dynamic buffering. */ + int dropable_threshold; + + int start; + + /*! The queued frame list */ + playout_frame_t *first_frame; + playout_frame_t *last_frame; + /*! The free frame pool */ + playout_frame_t *free_frames; + + /*! The total frames input to the buffer, to date. */ + int frames_in; + /*! The total frames output from the buffer, to date. */ + int frames_out; + /*! The number of frames received out of sequence. */ + int frames_oos; + /*! The number of frames which were discarded, due to late arrival. */ + int frames_late; + /*! The number of frames which were never received. */ + int frames_missing; + /*! The number of frames trimmed from the stream, due to buffer shrinkage. */ + int frames_trimmed; + + timestamp_t latest_expected; + /*! The present jitter adjustment */ + timestamp_t current; + /*! The sender_stamp of the last speech frame */ + timestamp_t last_speech_sender_stamp; + /*! The duration of the last speech frame */ + timestamp_t last_speech_sender_len; + + int not_first; + /*! The time since the target buffer length was last changed. */ + timestamp_t since_last_step; + /*! Filter state for tracking the packets arriving just in time */ + int32_t state_just_in_time; + /*! Filter state for tracking the packets arriving late */ + int32_t state_late; + /*! The current target length of the buffer */ + int target_buffer_length; + /*! The current actual length of the buffer, which may lag behind the target value */ + int actual_buffer_length; +}; + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/plc.h b/libs/spandsp/src/spandsp/private/plc.h new file mode 100644 index 0000000000..79975b02f1 --- /dev/null +++ b/libs/spandsp/src/spandsp/private/plc.h @@ -0,0 +1,64 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * private/plc.h + * + * Written by Steve Underwood + * + * Copyright (C) 2004 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_PRIVATE_PLC_H_) +#define _SPANDSP_PRIVATE_PLC_H_ + +/*! Minimum allowed pitch (66 Hz) */ +#define PLC_PITCH_MIN 120 +/*! Maximum allowed pitch (200 Hz) */ +#define PLC_PITCH_MAX 40 +/*! Maximum pitch OLA window */ +#define PLC_PITCH_OVERLAP_MAX (PLC_PITCH_MIN >> 2) +/*! The length over which the AMDF function looks for similarity (20 ms) */ +#define CORRELATION_SPAN 160 +/*! History buffer length. The buffer much also be at leat 1.25 times + PLC_PITCH_MIN, but that is much smaller than the buffer needs to be for + the pitch assessment. */ +#define PLC_HISTORY_LEN (CORRELATION_SPAN + PLC_PITCH_MIN) + +/*! + The generic packet loss concealer context. +*/ +struct plc_state_s +{ + /*! Consecutive erased samples */ + int missing_samples; + /*! Current offset into pitch period */ + int pitch_offset; + /*! Pitch estimate */ + int pitch; + /*! Buffer for a cycle of speech */ + float pitchbuf[PLC_PITCH_MIN]; + /*! History buffer */ + int16_t history[PLC_HISTORY_LEN]; + /*! Current pointer into the history buffer */ + int buf_ptr; +}; + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/power_meter.h b/libs/spandsp/src/spandsp/private/power_meter.h new file mode 100644 index 0000000000..64b8ec3f45 --- /dev/null +++ b/libs/spandsp/src/spandsp/private/power_meter.h @@ -0,0 +1,53 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * private/power_meter.h + * + * Written by Steve Underwood + * + * Copyright (C) 2003 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#if !defined(_SPANDSP_PRIVATE_POWER_METER_H_) +#define _SPANDSP_PRIVATE_POWER_METER_H_ + +/*! + Power meter descriptor. This defines the working state for a + single instance of a power measurement device. +*/ +struct power_meter_s +{ + /*! The shift factor, which controls the damping of the power meter. */ + int shift; + + /*! The current power reading. */ + int32_t reading; +}; + +struct power_surge_detector_state_s +{ + power_meter_t short_term; + power_meter_t medium_term; + int signal_present; + int32_t surge; + int32_t sag; + int32_t min; +}; + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/sig_tone.h b/libs/spandsp/src/spandsp/private/sig_tone.h index e7c6217051..3ec02d9bf9 100644 --- a/libs/spandsp/src/spandsp/private/sig_tone.h +++ b/libs/spandsp/src/spandsp/private/sig_tone.h @@ -210,10 +210,10 @@ struct sig_tone_rx_state_s /*! \brief The minimum ratio between notched power and total power for detection */ int32_t detection_ratio; - /*! \brief TRUE if in flat mode. FALSE if in sharp mode. */ - int flat_mode; - /*! \brief TRUE if the notch filter is enabled in the media path */ - int notch_enabled; + /*! \brief True if in flat mode. False if in sharp mode. */ + bool flat_mode; + /*! \brief True if the notch filter is enabled in the media path */ + bool notch_enabled; /*! \brief ??? */ int flat_mode_timeout; /*! \brief ??? */ diff --git a/libs/spandsp/src/spandsp/private/t30.h b/libs/spandsp/src/spandsp/private/t30.h index b1bef5d112..4fe2cc12b9 100644 --- a/libs/spandsp/src/spandsp/private/t30.h +++ b/libs/spandsp/src/spandsp/private/t30.h @@ -43,25 +43,34 @@ struct t30_state_s /*! \brief The type of FAX operation currently in progress */ int operation_in_progress; - /*! \brief TRUE if behaving as the calling party */ - int calling_party; + /*! \brief True if behaving as the calling party */ + bool calling_party; + + /*! \brief True if bad quality pages should be kept */ + bool keep_bad_pages; /*! \brief Internet aware FAX mode bit mask. */ int iaf; /*! \brief A bit mask of the currently supported modem types. */ 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; - /*! \brief A bit mask of the currently supported image resolutions. */ - int supported_resolutions; + /*! \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. */ + int supported_bilevel_resolutions; + /*! \brief A bit mask of the currently supported gray-scale and colour image resolutions. */ + int supported_colour_resolutions; /*! \brief A bit mask of the currently supported image sizes. */ int supported_image_sizes; /*! \brief A bit mask of the currently supported T.30 special features. */ int supported_t30_features; - /*! \brief TRUE is ECM mode handling is enabled. */ - int ecm_allowed; - /*! \brief TRUE if we are capable of retransmitting pages */ - int retransmit_capable; + /*! \brief True is ECM mode handling is enabled. */ + bool ecm_allowed; + /*! \brief True if we are capable of retransmitting pages */ + bool retransmit_capable; /*! \brief The received DCS, formatted as an ASCII string, for inclusion in the TIFF file. */ @@ -69,17 +78,17 @@ struct t30_state_s /*! \brief The text which will be used in FAX page header. No text results in no header line. */ char header_info[T30_MAX_PAGE_HEADER_INFO + 1]; - /*! \brief TRUE for FAX page headers to overlay (i.e. replace) the beginning of the - page image. FALSE for FAX page headers to add to the overall length of + /*! \brief True for FAX page headers to overlay (i.e. replace) the beginning of the + page image. False for FAX page headers to add to the overall length of the page. */ - int header_overlays_image; - /*! \brief Use private timezone if TRUE */ - int use_own_tz; + bool header_overlays_image; + /*! \brief Use private timezone if true */ + bool use_own_tz; /*! \brief Optional per instance time zone for the FAX page header timestamp. */ tz_t tz; - /*! \brief TRUE if remote T.30 procedural interrupts are allowed. */ - int remote_interrupts_allowed; + /*! \brief True if remote T.30 procedural interrupts are allowed. */ + bool remote_interrupts_allowed; /*! \brief The information fields received. */ t30_exchanged_info_t rx_info; @@ -133,6 +142,15 @@ struct t30_state_s /*! \brief An opaque pointer passed to the transmitted HDLC frame handler. */ void *send_hdlc_user_data; + /*! \brief The document send handler. */ + t30_document_get_handler_t document_get_handler; + /*! \brief An opaque pointer passed to the document send handler. */ + void *document_get_user_data; + /*! \brief The document delivery handler. */ + t30_document_put_handler_t document_put_handler; + /*! \brief An opaque pointer passed to the document delivery handler. */ + void *document_put_user_data; + /*! \brief The DIS code for the minimum scan row time we require. This is usually 0ms, but if we are trying to simulate another type of FAX machine, we may need a non-zero value here. */ @@ -157,13 +175,11 @@ struct t30_state_s int local_dis_dtc_len; /*! \brief The last DIS or DTC message received form the far end. */ uint8_t far_dis_dtc_frame[T30_MAX_DIS_DTC_DCS_LEN]; - /*! \brief The length of the last DIS or DTC message received form the far end. */ - int far_dis_dtc_len; - /*! \brief TRUE if a valid DIS has been received from the far end. */ - int dis_received; + /*! \brief True if a valid DIS has been received from the far end. */ + bool dis_received; - /*! \brief TRUE if the short training sequence should be used. */ - int short_train; + /*! \brief True if the short training sequence should be used. */ + bool short_train; /*! \brief A count of the number of bits in the trainability test. This counts down to zero when sending TCF, and counts up when receiving it. */ @@ -177,12 +193,12 @@ struct t30_state_s int current_fallback; /*! \brief The subset of supported modems allowed at the current time, allowing for negotiation. */ int current_permitted_modems; - /*! \brief TRUE if a carrier is present. Otherwise FALSE. */ - int rx_signal_present; - /*! \brief TRUE if a modem has trained correctly. */ - int rx_trained; - /*! \brief TRUE if a valid HDLC frame has been received in the current reception period. */ - int rx_frame_received; + /*! \brief True if a carrier is present. Otherwise false. */ + bool rx_signal_present; + /*! \brief True if a modem has trained correctly. */ + bool rx_trained; + /*! \brief True if a valid HDLC frame has been received in the current reception period. */ + bool rx_frame_received; /*! \brief Current reception mode. */ int current_rx_type; @@ -210,32 +226,42 @@ struct t30_state_s /*! \brief This is only used in full duplex (e.g. ISDN) modes. */ int timer_t8; - /*! \brief TRUE once the far end FAX entity has been detected. */ - int far_end_detected; + /*! \brief True once the far end FAX entity has been detected. */ + bool far_end_detected; - /*! \brief TRUE once the end of procedure condition has been detected. */ - int end_of_procedure_detected; + /*! \brief True once the end of procedure condition has been detected. */ + bool end_of_procedure_detected; - /*! \brief TRUE if a local T.30 interrupt is pending. */ - int local_interrupt_pending; - /*! \brief The image coding to be used on the line for non-bilevel images. */ - int multilevel_line_encoding; + /*! \brief True if a local T.30 interrupt is pending. */ + bool local_interrupt_pending; + /*! \brief The common ground in compression schemes between the local and far ends. */ + int mutual_compressions; + /*! \brief The common group of supported bi-level image resolutions. */ + int mutual_bilevel_resolutions; + /*! \brief The common group of supported colour image resolutions. */ + int mutual_colour_resolutions; + /*! \brief The common group of supported image sizes. */ + int mutual_image_sizes; /*! \brief The image coding being used on the line. */ - int line_encoding; - /*! \brief The image coding being used for output files. */ - int output_encoding; + int line_compression; + /*! \brief The image type being used on the line. */ + int line_image_type; + /*! \brief The width code for the image on the line. */ + int line_width_code; /*! \brief The current DCS message minimum scan time code. */ uint8_t min_scan_time_code; /*! \brief The X direction resolution of the current image, in pixels per metre. */ int x_resolution; /*! \brief The Y direction resolution of the current image, in pixels per metre. */ int y_resolution; + /*! \brief The resolution code for the current page. */ + int current_page_resolution; /*! \brief The width of the current image, in pixels. */ t4_image_width_t image_width; /*! \brief Current number of retries of the action in progress. */ int retries; - /*! \brief TRUE if error correcting mode is used. */ - int error_correcting_mode; + /*! \brief True if error correcting mode is used. */ + bool error_correcting_mode; /*! \brief The number of HDLC frame retries, if error correcting mode is used. */ int error_correcting_mode_retries; /*! \brief The current count of consecutive T30_PPR messages. */ @@ -263,9 +289,9 @@ struct t30_state_s int ecm_frames_this_tx_burst; /*! \brief The current ECM frame, during ECM transmission. */ int ecm_current_tx_frame; - /*! \brief TRUE if we are at the end of an ECM page to se sent - i.e. there are no more + /*! \brief True if we are at the end of an ECM page to se sent - i.e. there are no more partial pages still to come. */ - int ecm_at_page_end; + bool ecm_at_page_end; /*! \brief The transmission step queued to follow the one in progress. */ int next_tx_step; @@ -291,8 +317,8 @@ struct t30_state_s /*! \brief the FCF2 field of the last PPS message we received. */ uint8_t last_pps_fcf2; - /*! \brief TRUE if all frames of the current received ECM block are now OK */ - int rx_ecm_block_ok; + /*! \brief True if all frames of the current received ECM block are now OK */ + bool rx_ecm_block_ok; /*! \brief A count of successfully received ECM frames, to assess progress as a basis for deciding whether to continue error correction when PPRs keep repeating. */ int ecm_progress; diff --git a/libs/spandsp/src/spandsp/private/t30_dis_dtc_dcs_bits.h b/libs/spandsp/src/spandsp/private/t30_dis_dtc_dcs_bits.h index 9ec15f5f27..d41132cb3f 100644 --- a/libs/spandsp/src/spandsp/private/t30_dis_dtc_dcs_bits.h +++ b/libs/spandsp/src/spandsp/private/t30_dis_dtc_dcs_bits.h @@ -34,6 +34,8 @@ #define T30_DIS_BIT_T37 1 #define T30_DCS_BIT_T37 1 +/* Bit 2 in a DIS, DTC, or DCS is "reserved", so it should be set to zero */ + /* Indicates that the terminal has the capability to communicate using ITU-T Rec. T.38. Internet address signals CIA, TSA or CSA can be sent and received. The recipient terminal may process or ignore this signal. */ @@ -45,15 +47,22 @@ #define T30_DIS_BIT_3G_MOBILE 4 #define T30_DCS_BIT_3G_MOBILE 4 +/* Bit 5 in a DIS, DTC, or DCS is "reserved", so it should be set to zero */ + /* When ISDN mode is used, in DIS/DTC bit 6 shall be set to "0". */ #define T30_DIS_BIT_V8_CAPABILITY 6 +/* Bit 6 in a DCS is "invalid", and should be set to zero */ /* When ISDN mode is used, in DIS/DTC bit 7 shall be set to "0". */ #define T30_DIS_BIT_64_OCTET_ECM_FRAMES_PREFERRED 7 +/* Bit 7 in a DCS is "invalid", and should be set to zero */ + +/* Bit 8 in a DIS, DTC, or DCS is "reserved", so it should be set to zero */ /* Bit 9 indicates that there is a facsimile document ready to be polled from the answering terrminal. It is not an indication of a capability. */ #define T30_DIS_BIT_READY_TO_TRANSMIT_FAX_DOCUMENT 9 +/* Bit 9 in a DCS should be set to zero */ /* In DIS/DTC bit 10 indicates that the answering terminal has receiving capabilities. In DCS it is a command to the receiving terminal to set itself in the receive mode. */ @@ -61,6 +70,14 @@ #define T30_DCS_BIT_RECEIVE_FAX_DOCUMENT 10 /* Bits 11, 12, 13, 14 - modem type */ +#define T30_DIS_BIT_MODEM_TYPE_1 11 +#define T30_DCS_BIT_MODEM_TYPE_1 11 +#define T30_DIS_BIT_MODEM_TYPE_2 12 +#define T30_DCS_BIT_MODEM_TYPE_2 12 +#define T30_DIS_BIT_MODEM_TYPE_3 13 +#define T30_DCS_BIT_MODEM_TYPE_3 13 +#define T30_DIS_BIT_MODEM_TYPE_4 14 +#define T30_DCS_BIT_MODEM_TYPE_4 14 #define T30_DIS_BIT_200_200_CAPABLE 15 #define T30_DCS_BIT_200_200 15 @@ -71,34 +88,62 @@ /* Standard facsimile terminals conforming to ITU-T Rec. T.4 must have the following capability: Paper length = 297 mm. */ -/* Bits 17, 18 - recording width */ +#define T30_DIS_BIT_215MM_255MM_WIDTH_CAPABLE 17 +#define T30_DCS_BIT_255MM_WIDTH 17 -/* Bits 19, 20 - paper length */ +#define T30_DIS_BIT_215MM_255MM_303MM_WIDTH_CAPABLE 18 +#define T30_DCS_BIT_303MM_WIDTH 18 + +#define T30_DIS_BIT_A4_B4_LENGTH_CAPABLE 19 +#define T30_DCS_BIT_B4_LENGTH 19 + +#define T30_DIS_BIT_UNLIMITED_LENGTH_CAPABLE 20 +#define T30_DCS_BIT_UNLIMITED_LENGTH 20 /* Bits 21, 22, 23 - min scan line time */ - /* When ISDN mode is used, in DIS/DTC bits 21 to 23 shall be set to "1". */ +#define T30_DIS_BIT_MIN_SCAN_LINE_TIME_CAPABILITY_1 21 +#define T30_DCS_BIT_MIN_SCAN_LINE_TIME_1 21 +#define T30_DIS_BIT_MIN_SCAN_LINE_TIME_CAPABILITY_2 22 +#define T30_DCS_BIT_MIN_SCAN_LINE_TIME_2 22 +#define T30_DIS_BIT_MIN_SCAN_LINE_TIME_CAPABILITY_3 23 +#define T30_DCS_BIT_MIN_SCAN_LINE_TIME_3 23 +#define T30_DIS_BIT_MIN_SCAN_LINE_TIME_CAPABILITY_4 24 +#define T30_DCS_BIT_MIN_SCAN_LINE_TIME_4 24 + +/* Bit 24 is an extension bit */ + +/* Bit 25 in a DIS, DTC, or DCS is "reserved", so it should be set to zero */ #define T30_DIS_BIT_UNCOMPRESSED_CAPABLE 26 #define T30_DCS_BIT_UNCOMPRESSED_MODE 26 /* When ISDN mode is used, in DIS/DTC bit 27 shall be set to "1". */ #define T30_DIS_BIT_ECM_CAPABLE 27 -#define T30_DCS_BIT_ECM 27 +#define T30_DCS_BIT_ECM_MODE 27 -/* The value of bit 28 in the DCS command is only valid when ECM is selected. */ +/* Bit 28 in a DIS or DTC should be set to zero */ +/* (T.30 note 7) The value of bit 28 in the DCS command is only valid when ECM is selected. */ #define T30_DCS_BIT_64_OCTET_ECM_FRAMES 28 -/* The value of bit 31 in the DCS command is only valid when ECM is selected. */ +/* Bit 29 in a DIS, DTC, or DCS is "reserved", so it should be set to zero */ + +/* Bit 30 in a DIS, DTC, or DCS is "reserved", so it should be set to zero */ + +/* (T.30 note 9) The value of bit 31 in the DCS command is only valid when ECM is selected. */ #define T30_DIS_BIT_T6_CAPABLE 31 #define T30_DCS_BIT_T6_MODE 31 +/* Bit 32 is an extension bit */ + #define T30_DIS_BIT_FNV_CAPABLE 33 #define T30_DCS_BIT_FNV_CAPABLE 33 #define T30_DIS_BIT_MULTIPLE_SELECTIVE_POLLING_CAPABLE 34 +/* Bit 34 in a DCS should be set to zero */ #define T30_DIS_BIT_POLLED_SUBADDRESSING_CAPABLE 35 +/* Bit 35 in a DCS should be set to zero */ #define T30_DIS_BIT_T43_CAPABLE 36 #define T30_DCS_BIT_T43_MODE 36 @@ -109,33 +154,44 @@ #define T30_DIS_BIT_G726_CAPABLE 38 #define T30_DCS_BIT_G726 38 +/* Bit 39 in a DIS, DTC, or DCS is "reserved for extended voice coding", so it should be set to zero */ + +/* Bit 40 is an extension bit */ + +/* This also enables R8 x 15.4/mm mode */ #define T30_DIS_BIT_200_400_CAPABLE 41 #define T30_DCS_BIT_200_400 41 #define T30_DIS_BIT_300_300_CAPABLE 42 #define T30_DCS_BIT_300_300 42 +/* This also enables R16 x 15.4/mm mode */ #define T30_DIS_BIT_400_400_CAPABLE 43 #define T30_DCS_BIT_400_400 43 -/* Bits 44 and 45 are used only in conjunction with bits 15 and 43. Bit 44 in DCS, when used, - shall correctly indicate the resolution of the transmitted document, which means that bit 44 in DCS may - not always match the indication of bits 44 and 45 in DIS/DTC. Cross selection will cause the distortion - and reduction of reproducible area. +/* Bits 44 and 45 are used only in conjunction with bits 15 and 43. Bit 44 in DCS, when used, shall correctly + indicate the resolution of the transmitted document, which means that bit 44 in DCS may not always match the + indication of bits 44 and 45 in DIS/DTC. Cross selection will cause the distortion and reduction of reproducible + area. If a receiver indicates in DIS that it prefers to receive metric-based information, but the transmitter has only the equivalent inch-based information (or vice versa), then communication shall still take place. - Bits 44 and 45 do not require the provision of any additional features on the terminal to - indicate to the sending or receiving user whether the information was transmitted or received on a metric-metric, - inch-inch, metric-inch, inch-metric basis. */ + Bits 44 and 45 do not require the provision of any additional features on the terminal to indicate to the + sending or receiving user whether the information was transmitted or received on a metric-metric, inch-inch, + metric-inch, inch-metric basis. */ #define T30_DIS_BIT_INCH_RESOLUTION_PREFERRED 44 #define T30_DCS_BIT_INCH_RESOLUTION 44 #define T30_DIS_BIT_METRIC_RESOLUTION_PREFERRED 45 +/* Bit 45 in a DCS is "don't care", so it should be set to zero */ #define T30_DIS_BIT_MIN_SCAN_TIME_HALVES 46 +/* Bit 46 in a DCS is "don't care", so it should be set to zero */ #define T30_DIS_BIT_SELECTIVE_POLLING_CAPABLE 47 +/* Bit 47 in a DCS should be set to zero */ + +/* Bit 48 is an extension bit */ #define T30_DIS_BIT_SUBADDRESSING_CAPABLE 49 #define T30_DCS_BIT_SUBADDRESS_TRANSMISSION 49 @@ -146,6 +202,9 @@ /* Bit 51 indicates that there is a data file ready to be polled from the answering terminal. It is not an indication of a capability. This bit is used in conjunction with bits 53, 54, 55 and 57. */ #define T30_DIS_BIT_READY_TO_TRANSMIT_DATA_FILE 51 +/* Bit 51 in a DCS should be set to zero */ + +/* Bit 52 in a DIS, DTC, or DCS is "reserved", so it should be set to zero */ /* The binary file transfer protocol is described in ITU-T Rec. T.434. */ #define T30_DIS_BIT_BFT_CAPABLE 53 @@ -157,21 +216,33 @@ #define T30_DIS_BIT_EDI_CAPABLE 55 #define T30_DCS_BIT_EDI 55 +/* Bit 56 is an extension bit */ + #define T30_DIS_BIT_BTM_CAPABLE 57 #define T30_DCS_BIT_BTM 57 +/* Bit 58 in a DIS, DTC, or DCS is "reserved", so it should be set to zero */ + /* Bit 59 indicates that there is a character-coded or mixed-mode document ready to be polled from the answering terminal. It is not an indication of a capability. This bit is used in conjunction with bits 60, 62 and 65. */ #define T30_DIS_BIT_READY_TO_TRANSMIT_MIXED_MODE_DOCUMENT 59 +/* Bit 59 in a DCS should be set to zero */ -#define T30_DIS_BIT_CHARACTER_MODE 60 +#define T30_DIS_BIT_CHARACTER_MODE_CAPABLE 60 #define T30_DCS_BIT_CHARACTER_MODE 60 +/* Bit 61 in a DIS, DTC, or DCS is "reserved", so it should be set to zero */ + #define T30_DIS_BIT_MIXED_MODE 62 #define T30_DCS_BIT_MIXED_MODE 62 +/* Bit 63 in a DIS, DTC, or DCS is "reserved", so it should be set to zero */ + +/* Bit 64 is an extension bit */ + #define T30_DIS_BIT_PROCESSABLE_MODE_26 65 +/* Bit 65 in a DCS should be set to zero */ #define T30_DIS_BIT_DIGITAL_NETWORK_CAPABLE 66 #define T30_DCS_BIT_DIGITAL_NETWORK_CAPABLE 66 @@ -180,11 +251,14 @@ #define T30_DCS_BIT_DUPLEX_CAPABLE 67 #define T30_DIS_BIT_T81_CAPABLE 68 -#define T30_DCS_BIT_FULL_COLOUR_MODEX 68 +#define T30_DCS_BIT_T81_MODE 68 #define T30_DIS_BIT_FULL_COLOUR_CAPABLE 69 #define T30_DCS_BIT_FULL_COLOUR_MODE 69 +/* Bit 70 in a DCS should be set to zero */ +#define T30_DCS_BIT_PREFERRED_HUFFMAN_TABLES 70 + /* In a DIS/DTC frame, setting bit 71 to "0" indicates that the called terminal can only accept image data which has been digitized to 8 bits/pel/component for JPEG mode. This is also true for T.43 mode if bit 36 is also set to "1". Setting bit 71 to "1" indicates that the called terminal can also accept @@ -197,6 +271,8 @@ #define T30_DIS_BIT_12BIT_CAPABLE 71 #define T30_DCS_BIT_12BIT_COMPONENT 71 +/* Bit 72 is an extension bit */ + #define T30_DIS_BIT_NO_SUBSAMPLING 73 #define T30_DCS_BIT_NO_SUBSAMPLING 73 @@ -215,9 +291,50 @@ #define T30_DIS_BIT_T85_CAPABLE 78 #define T30_DCS_BIT_T85_MODE 78 +/* (T.30 note 30) This capability should only be set if T30_DIS_BIT_T85_CAPABLE is also set */ #define T30_DIS_BIT_T85_L0_CAPABLE 79 #define T30_DCS_BIT_T85_L0_MODE 79 +/* Bit 80 is an extension bit */ + +#define T30_DIS_BIT_HKM_KEY_MANAGEMENT_CAPABLE 81 +#define T30_DCS_BIT_HKM_KEY_MANAGEMENT_MODE 81 + +#define T30_DIS_BIT_RSA_KEY_MANAGEMENT_CAPABLE 82 +#define T30_DCS_BIT_RSA_KEY_MANAGEMENT_MODE 82 + +#define T30_DIS_BIT_OVERRIDE_CAPABLE 83 +#define T30_DCS_BIT_OVERRIDE_MODE 83 + +#define T30_DIS_BIT_HFX40_CIPHER_CAPABLE 84 +#define T30_DCS_BIT_HFX40_CIPHER_MODE 84 + +#define T30_DIS_BIT_ALTERNATIVE_CIPHER_2_CAPABLE 85 +#define T30_DCS_BIT_ALTERNATIVE_CIPHER_2_MODE 85 + +#define T30_DIS_BIT_ALTERNATIVE_CIPHER_3_CAPABLE 86 +#define T30_DCS_BIT_ALTERNATIVE_CIPHER_3_MODE 86 + +#define T30_DIS_BIT_HFX40_I_HASHING_CAPABLE 87 +#define T30_DCS_BIT_HFX40_I_HASHING_MODE 87 + +/* Bit 88 is an extension bit */ + +#define T30_DIS_BIT_ALTERNATIVE_HASHING_2_CAPABLE 89 +#define T30_DCS_BIT_ALTERNATIVE_HASHING_2_MODE 89 + +#define T30_DIS_BIT_ALTERNATIVE_HASHING_3_CAPABLE 90 +#define T30_DCS_BIT_ALTERNATIVE_HASHING_3_MODE 90 + +/* Bit 91 in a DIS, DTC, or DCS is "reserved for suture security features", so it should be set to zero */ + +/* Bits 92 to 94 specify the mixed raster content mode. */ + +#define T30_DIS_BIT_T44_PAGE_LENGTH 95 +#define T30_DCS_BIT_T44_PAGE_LENGTH 95 + +/* Bit 96 is an extension bit */ + /* In a DIS/DTC frame, setting bit 97 to "0" indicates that the called terminal does not have the capability to accept 300 pels/25.4 mm x 300 lines/25.4 mm or 400 pels/25.4 mm x 400 lines/25.4 mm resolutions for colour/gray-scale images or T.44 Mixed Raster Content (MRC) mask layer. @@ -252,8 +369,8 @@ 1 1 1 yes yes yes yes "yes" means that the called terminal has the corresponding capability. "no" means that the called terminal does not have the corresponding capability. */ -#define T30_DIS_BIT_COLOUR_GREY_300_300_400_400_CAPABLE 97 -#define T30_DCS_BIT_COLOUR_GREY_300_300_400_400 97 +#define T30_DIS_BIT_COLOUR_GRAY_300_300_400_400_CAPABLE 97 +#define T30_DCS_BIT_COLOUR_GRAY_300_300_400_400 97 /* In a DIS/DTC frame, setting bit 98 to "0" indicates that the called terminal does not have the capability to accept 100 pels/25.4 mm x 100 lines/25.4 mm spatial resolution for colour or gray-scale @@ -263,27 +380,39 @@ not use 100 pels/25.4 mm x 100 lines/25.4 mm spatial resolution for colour or gray-scale images. Setting bit 98 to "1" indicates that the calling terminal uses 100 pels/25.4 mm x 100 lines/25.4 mm spatial resolution for colour or gray-scale images. */ -#define T30_DIS_BIT_COLOUR_GREY_100_100_CAPABLE 98 -#define T30_DCS_BIT_COLOUR_GREY_100_100 98 +#define T30_DIS_BIT_COLOUR_GRAY_100_100_CAPABLE 98 +#define T30_DCS_BIT_COLOUR_GRAY_100_100 98 + +#define T30_DIS_BIT_SIMPLE_PHASE_C_BFT_NEGOTIATIONS_CAPABLE 99 +#define T30_DCS_BIT_SIMPLE_PHASE_C_BFT_NEGOTIATIONS_CAPABLE 99 + +#define T30_DIS_BIT_EXTENDED_BFT_NEGOTIATIONS_CAPABLE 100 +/* Bit 100 in a DCS should be set to zero */ /* To provide an error recovery mechanism, when PWD/SEP/SUB/SID/PSA/IRA/ISP frames are sent with DCS or DTC, bits 49, 102 and 50 in DCS or bits 47, 101, 50 and 35 in DTC shall be set to "1" with the following meaning: + Bit DIS DTC DCS - 35 Polled SubAddress capability Polled SubAddress transmission Not allowed - set to "0" + 35 Polled sub-address capability Polled sub-address transmission Not allowed - set to "0" 47 Selective polling capability Selective polling transmission Not allowed - set to "0" - 49 Subaddressing capability Not allowed (Set to "0") Subaddressing transmission - 50 Password Password transmission Sender Identification transmission - 101 Internet Selective Polling Address capability Internet Selective Polling Address transmission Not allowed - set to "0" - 102 Internet Routing Address capability Not allowed (Set to "0") Internet Routing Address transmission + 49 Sub-addressing capability Not allowed (Set to "0") Sub-addressing transmission + 50 Password Password transmission Sender identification transmission + 101 Internet selective polling address capability Internet selective polling address transmission Not allowed - set to "0" + 102 Internet routing address capability Not allowed (Set to "0") Internet routing address transmission Terminals conforming to the 1993 version of T.30 may set the above bits to "0" even though PWD/SEP/SUB frames are transmitted. */ #define T30_DIS_BIT_INTERNET_SELECTIVE_POLLING_ADDRESS 101 +/* Bit 101 in a DCS should be set to zero */ #define T30_DIS_BIT_INTERNET_ROUTING_ADDRESS 102 #define T30_DCS_BIT_INTERNET_ROUTING_ADDRESS_TRANSMISSION 102 +/* Bit 103 in a DIS, DTC, or DCS is "reserved", so it should be set to zero */ + +/* Bit 104 is an extension bit */ + #define T30_DIS_BIT_600_600_CAPABLE 105 #define T30_DCS_BIT_600_600 105 @@ -299,11 +428,15 @@ #define T30_DIS_BIT_600_1200_CAPABLE 109 #define T30_DCS_BIT_600_1200 109 -#define T30_DIS_BIT_COLOUR_GREY_600_600_CAPABLE 110 -#define T30_DCS_BIT_COLOUR_GREY_600_600 110 +/* This requires that bit 105 is also set */ +#define T30_DIS_BIT_COLOUR_GRAY_600_600_CAPABLE 110 +#define T30_DCS_BIT_COLOUR_GRAY_600_600 110 -#define T30_DIS_BIT_COLOUR_GREY_1200_1200_CAPABLE 111 -#define T30_DCS_BIT_COLOUR_GREY_1200_1200 111 +/* This requires that bit 106 is also set */ +#define T30_DIS_BIT_COLOUR_GRAY_1200_1200_CAPABLE 111 +#define T30_DCS_BIT_COLOUR_GRAY_1200_1200 111 + +/* Bit 112 is an extension bit */ #define T30_DIS_BIT_ALTERNATE_DOUBLE_SIDED_CAPABLE 113 #define T30_DCS_BIT_ALTERNATE_DOUBLE_SIDED_CAPABLE 113 @@ -312,10 +445,13 @@ #define T30_DCS_BIT_CONTINUOUS_DOUBLE_SIDED_CAPABLE 114 #define T30_DIS_BIT_BLACK_AND_WHITE_MRC 115 +/* Bit 115 in a DCS should be set to zero */ #define T30_DIS_BIT_T45_CAPABLE 116 #define T30_DCS_BIT_T45_MODE 116 +/* Bits 117 to 118 specify the shared memory capability */ + /* This bit defines the available colour space, when bit 92, 93 or 94 is set to "1". Available colour space for all combinations of bits 92, 93, 94 and 119 are shown in the following table. It should be noted that terminals which conform to the 2003 and earlier versions of this Recommendation @@ -345,6 +481,8 @@ #define T30_DIS_BIT_T44_COLOUR_SPACE 119 #define T30_DCS_BIT_T44_COLOUR_SPACE 119 +/* Bit 120 is an extension bit */ + /* Can only be set in the communication through the T.38 gateway, to cope with delay of network. T.x timer (12+-1s) should be used after emitting RNR or TNR. However, after receiving PPS signal in ECM mode, T.5 timer should be used. */ @@ -366,6 +504,14 @@ When this bit is set to "1", the data signal rate of the modem (bits 11-14) should be set to "0". */ #define T30_DCS_BIT_T38_FAX_MODE 123 +/* 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 set to "1", ECM must be used. If the value of bit field 92 to 94 is non-zero, then ECM must be used. diff --git a/libs/spandsp/src/spandsp/private/t31.h b/libs/spandsp/src/spandsp/private/t31.h index 2686b5f503..1f7de41f99 100644 --- a/libs/spandsp/src/spandsp/private/t31.h +++ b/libs/spandsp/src/spandsp/private/t31.h @@ -108,8 +108,8 @@ typedef struct /*! \brief The current transmit step being timed */ int timed_step; - /*! \brief TRUE is there has been some T.38 data missed */ - int rx_data_missing; + /*! \brief True is there has been some T.38 data missed */ + bool rx_data_missing; /*! \brief The number of octets to send in each image packet (non-ECM or ECM) at the current rate and the current specified packet interval. */ @@ -138,9 +138,9 @@ typedef struct t31_hdlc_state_t hdlc_from_t31; - /*! \brief TRUE if we are using ECM mode. This is used to select HDLC faking, necessary + /*! \brief True if we are using ECM mode. This is used to select HDLC faking, necessary with clunky class 1 modems. */ - int ecm_mode; + bool ecm_mode; /*! \brief Counter for trailing non-ECM bytes, used to flush out the far end's modem. */ int non_ecm_trailer_bytes; @@ -179,8 +179,8 @@ struct t31_state_s t31_audio_front_end_state_t audio; t31_t38_front_end_state_t t38_fe; - /*! TRUE if working in T.38 mode. */ - int t38_mode; + /*! True if working in T.38 mode. */ + bool t38_mode; /*! HDLC buffer, for composing an HDLC frame from the computer to the channel. */ struct @@ -189,8 +189,8 @@ struct t31_state_s uint8_t buf[T31_MAX_HDLC_LEN]; int len; int ptr; - /*! \brief TRUE when the end of HDLC data from the computer has been detected. */ - int final; + /*! \brief True when the end of HDLC data from the computer has been detected. */ + bool final; } hdlc_tx; /*! Buffer for data from the computer to the channel. */ struct @@ -201,24 +201,24 @@ struct t31_state_s int in_bytes; /*! \brief The number of bytes sent from the transmit buffer. */ int out_bytes; - /*! \brief TRUE if the flow of real data has started. */ - int data_started; - /*! \brief TRUE if holding up further data into the buffer, for flow control. */ - int holding; - /*! \brief TRUE when the end of non-ECM data from the computer has been detected. */ - int final; + /*! \brief True if the flow of real data has started. */ + bool data_started; + /*! \brief True if holding up further data into the buffer, for flow control. */ + bool holding; + /*! \brief True when the end of non-ECM data from the computer has been detected. */ + bool final; } non_ecm_tx; - /*! TRUE if DLE prefix just used */ - int dled; + /*! True if DLE prefix just used */ + bool dled; /*! \brief Samples of silence awaited, as specified in a "wait for silence" command */ int silence_awaited; /*! \brief The current bit rate for the FAX fast message transfer modem. */ int bit_rate; - /*! \brief TRUE if a valid HDLC frame has been received in the current reception period. */ - int rx_frame_received; + /*! \brief True if a valid HDLC frame has been received in the current reception period. */ + bool rx_frame_received; /*! \brief Samples elapsed in the current call */ int64_t call_samples; @@ -226,8 +226,8 @@ struct t31_state_s /*! \brief The currently queued modem type. */ int modem; - /*! \brief TRUE when short training mode has been selected by the computer. */ - int short_train; + /*! \brief True when short training mode has been selected by the computer. */ + bool short_train; queue_state_t *rx_queue; /*! \brief Error and flow logging control */ diff --git a/libs/spandsp/src/spandsp/private/t38_core.h b/libs/spandsp/src/spandsp/private/t38_core.h index 40123128af..6d29957067 100644 --- a/libs/spandsp/src/spandsp/private/t38_core.h +++ b/libs/spandsp/src/spandsp/private/t38_core.h @@ -98,9 +98,9 @@ struct t38_core_state_s /*! \brief Pace transmission */ int pace_transmission; - /*! \brief TRUE if IFP packet sequence numbers are relevant. For some transports, like TPKT + /*! \brief True if IFP packet sequence numbers are relevant. For some transports, like TPKT over TCP they are not relevent. */ - int check_sequence_numbers; + bool check_sequence_numbers; /*! \brief The number of times each packet type will be sent (low byte). The depth of redundancy (2nd byte). Higher numbers may increase reliability diff --git a/libs/spandsp/src/spandsp/private/t38_gateway.h b/libs/spandsp/src/spandsp/private/t38_gateway.h index e8e74c2af9..23c6dd59bf 100644 --- a/libs/spandsp/src/spandsp/private/t38_gateway.h +++ b/libs/spandsp/src/spandsp/private/t38_gateway.h @@ -43,12 +43,12 @@ typedef struct /*! \brief Core T.38 IFP support */ t38_core_state_t t38; - /*! \brief TRUE if the NSF, NSC, and NSS are to be suppressed by altering - their contents to something the far end will not recognise. */ + /*! \brief If NSF, NSC, and NSS are to be suppressed by altering their contents to + something the far end will not recognise, this is the amount to overwrite. */ int suppress_nsx_len[2]; - /*! \brief TRUE if we need to corrupt the HDLC frame in progress, so the receiver cannot + /*! \brief True if we need to corrupt the HDLC frame in progress, so the receiver cannot interpret it. The two values are for the two directions. */ - int corrupt_current_frame[2]; + bool corrupt_current_frame[2]; /*! \brief the current class of field being received - i.e. none, non-ECM or HDLC */ int current_rx_field_class; @@ -66,10 +66,6 @@ typedef struct { /*! \brief The FAX modem set for the audio side fo the gateway. */ 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; /*! @@ -91,8 +87,8 @@ typedef struct int bit_no; /*! \brief Progressively calculated CRC for HDLC messages received from a modem. */ uint16_t crc; - /*! \brief TRUE if non-ECM fill bits are to be stripped when sending image data. */ - int fill_bit_removal; + /*! \brief True if non-ECM fill bits are to be stripped when sending image data. */ + bool fill_bit_removal; /*! \brief The number of octets to send in each image packet (non-ECM or ECM) at the current rate and the current specified packet interval. */ int octets_per_data_packet; @@ -138,27 +134,27 @@ typedef struct { /*! \brief A bit mask of the currently supported modem types. */ int supported_modems; - /*! \brief TRUE if ECM FAX mode is allowed through the gateway. */ - int ecm_allowed; + /*! \brief True if ECM FAX mode is allowed through the gateway. */ + bool ecm_allowed; /*! \brief Required time between T.38 transmissions, in ms. */ int ms_per_tx_chunk; - /*! \brief TRUE if in image data modem is to use short training. This usually + /*! \brief True if in image data modem is to use short training. This usually follows image_data_mode, but in ECM mode T.30 defines recovery conditions in which long training is used for image data. */ - int short_train; - /*! \brief TRUE if in image data mode, as opposed to TCF mode. */ - int image_data_mode; + bool short_train; + /*! \brief True if in image data mode, as opposed to TCF mode. */ + bool image_data_mode; /*! \brief The minimum permitted bits per FAX scan line row. */ int min_row_bits; - /*! \brief TRUE if we should count the next MCF as a page end, else FALSE */ - int count_page_on_mcf; + /*! \brief True if we should count the next MCF as a page end, else false */ + bool count_page_on_mcf; /*! \brief The number of pages for which a confirm (MCF) message was returned. */ int pages_confirmed; - /*! \brief TRUE if we are in error correcting (ECM) mode */ - int ecm_mode; + /*! \brief True if we are in error correcting (ECM) mode */ + bool ecm_mode; /*! \brief The current bit rate for the fast modem. */ int fast_bit_rate; /*! \brief The current fast receive modem type. */ diff --git a/libs/spandsp/src/spandsp/private/t38_non_ecm_buffer.h b/libs/spandsp/src/spandsp/private/t38_non_ecm_buffer.h index 78604420a9..9220f78af1 100644 --- a/libs/spandsp/src/spandsp/private/t38_non_ecm_buffer.h +++ b/libs/spandsp/src/spandsp/private/t38_non_ecm_buffer.h @@ -55,14 +55,14 @@ struct t38_non_ecm_buffer_state_s uint8_t flow_control_fill_octet; /*! \brief A code for the phase of input buffering, from initial all ones to completion. */ int input_phase; - /*! \brief TRUE is the end of non-ECM data indication has been received. */ - int data_finished; + /*! \brief True is the end of non-ECM data indication has been received. */ + bool data_finished; /*! \brief The current octet being transmitted from the buffer. */ unsigned int octet; /*! \brief The current bit number in the current non-ECM octet. */ int bit_no; - /*! \brief TRUE if in image data mode, as opposed to TCF mode. */ - int image_data_mode; + /*! \brief True if in image data mode, as opposed to TCF mode. */ + bool image_data_mode; /*! \brief The number of octets input to the buffer. */ int in_octets; diff --git a/libs/spandsp/src/spandsp/private/t38_terminal.h b/libs/spandsp/src/spandsp/private/t38_terminal.h index 0bd75a6cfb..219b1e3cf7 100644 --- a/libs/spandsp/src/spandsp/private/t38_terminal.h +++ b/libs/spandsp/src/spandsp/private/t38_terminal.h @@ -46,9 +46,9 @@ typedef struct /*! \brief The timed step to go to when we reach idle from the current timed step */ int queued_timed_step; - /*! \brief TRUE is there has been some T.38 data missed (i.e. lost packets) in the current + /*! \brief True is there has been some T.38 data missed (i.e. lost packets) in the current reception period. */ - int rx_data_missing; + bool rx_data_missing; /*! \brief The number of octets to send in each image packet (non-ECM or ECM) at the current rate and the current specified packet interval. */ @@ -84,8 +84,8 @@ typedef struct /*! \brief The current T.38 data type being transmitted. */ int current_tx_data_type; - /*! \brief TRUE if a carrier is present. Otherwise FALSE. */ - int rx_signal_present; + /*! \brief True if a carrier is present. Otherwise false. */ + bool rx_signal_present; /*! \brief The current operating mode of the receiver. */ int current_rx_type; diff --git a/libs/spandsp/src/spandsp/private/t42.h b/libs/spandsp/src/spandsp/private/t42.h index bfdae884eb..e151afc6fc 100644 --- a/libs/spandsp/src/spandsp/private/t42.h +++ b/libs/spandsp/src/spandsp/private/t42.h @@ -26,6 +26,9 @@ #if !defined(_SPANDSP_PRIVATE_T42_H_) #define _SPANDSP_PRIVATE_T42_H_ +#include +#include + struct lab_params_s { /* Lab gamut */ @@ -37,10 +40,13 @@ struct lab_params_s float offset_b; int ab_are_signed; - /* Illuminant */ + /* Illuminant, forward and reverse */ float x_n; float y_n; float z_n; + float x_rn; + float y_rn; + float z_rn; }; /* State of a working instance of the T.42 JPEG FAX encoder */ @@ -50,11 +56,39 @@ struct t42_encode_state_s t4_row_read_handler_t row_read_handler; /*! \brief Opaque pointer passed to row_read_handler. */ void *row_read_user_data; + uint32_t image_width; + uint32_t image_length; + uint16_t samples_per_pixel; + int image_type; + int no_subsampling; + int itu_ycc; + int quality; - lab_params_t lab_params; + /* The X or Y direction resolution, in pixels per inch */ + int spatial_resolution; + + lab_params_t lab; + + uint8_t illuminant_code[4]; + int illuminant_colour_temperature; /*! \brief The size of the compressed image, in bytes. */ int compressed_image_size; + int compressed_image_ptr; + + int buf_size; + uint8_t *compressed_buf; + + FILE *out; +#if defined(HAVE_OPEN_MEMSTREAM) + size_t outsize; +#endif + jmp_buf escape; + char error_message[JMSG_LENGTH_MAX]; + struct jpeg_compress_struct compressor; + + JSAMPROW scan_line_out; + JSAMPROW scan_line_in; /*! \brief Error and flow logging control */ logging_state_t logging; @@ -73,8 +107,19 @@ struct t42_decode_state_s void *comment_user_data; /*! The maximum length of comment to be passed to the comment handler */ uint32_t max_comment_len; + uint32_t image_width; + uint32_t image_length; + uint16_t samples_per_pixel; + int image_type; + int itu_ycc; - lab_params_t lab_params; + /* The X or Y direction resolution, in pixels per inch */ + int spatial_resolution; + + lab_params_t lab; + + uint8_t illuminant_code[4]; + int illuminant_colour_temperature; /*! The contents for a COMMENT marker segment, to be added to the image at the next opportunity. This is set to NULL when nothing is @@ -89,6 +134,17 @@ struct t42_decode_state_s int buf_size; uint8_t *compressed_buf; + FILE *in; + jmp_buf escape; + char error_message[JMSG_LENGTH_MAX]; + struct jpeg_decompress_struct decompressor; + + /*! Flag that the data to be decoded has run out. */ + int end_of_data; + + JSAMPROW scan_line_out; + JSAMPROW scan_line_in; + /*! \brief Error and flow logging control */ logging_state_t logging; }; diff --git a/libs/spandsp/src/spandsp/private/t43.h b/libs/spandsp/src/spandsp/private/t43.h new file mode 100644 index 0000000000..59746b3bc6 --- /dev/null +++ b/libs/spandsp/src/spandsp/private/t43.h @@ -0,0 +1,96 @@ +/* + * 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 + * + * 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 image_type; + int bit_planes[4]; + + int colour_map_entries; + uint8_t colour_map[3*256]; + + uint8_t illuminant_code[4]; + int illuminant_colour_temperature; + + /*! The width of the full image, in pixels */ + uint32_t xd; + /*! The height of the full image, in pixels */ + uint32_t yd; + /* The X or Y direction resolution, in pixels per inch */ + int spatial_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 image_type; + 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]; + + uint8_t illuminant_code[4]; + int illuminant_colour_temperature; + + /* The X or Y direction resolution, in pixels per inch */ + int spatial_resolution; + int samples_per_pixel; + + uint8_t *buf; + int ptr; + int row; + + /*! \brief Error and flow logging control */ + logging_state_t logging; +}; + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/private/t4_rx.h b/libs/spandsp/src/spandsp/private/t4_rx.h index 58b30e86e9..3f89e1d38b 100644 --- a/libs/spandsp/src/spandsp/private/t4_rx.h +++ b/libs/spandsp/src/spandsp/private/t4_rx.h @@ -26,6 +26,8 @@ #if !defined(_SPANDSP_PRIVATE_T4_RX_H_) #define _SPANDSP_PRIVATE_T4_RX_H_ +typedef int (*t4_image_put_handler_t)(void *user_data, const uint8_t buf[], size_t len); + /*! TIFF specific state information to go with T.4 compression or decompression handling. */ @@ -39,7 +41,7 @@ typedef struct /*! Image type - bilevel, gray, colour */ int image_type; /*! \brief The compression type for output to the TIFF file. */ - int output_encoding; + int compression; /*! \brief The TIFF photometric setting for the current page. */ uint16_t photo_metric; /*! \brief The TIFF fill order setting for the current page. */ @@ -65,6 +67,12 @@ typedef struct */ typedef struct { + /*! \brief The type of compression used on the wire. */ + int compression; + /*! \brief The width of the current page, in pixels. */ + uint32_t image_width; + /*! \brief The length of the current page, in pixels. */ + uint32_t image_length; /*! \brief Column-to-column (X) resolution in pixels per metre. */ int x_resolution; /*! \brief Row-to-row (Y) resolution in pixels per metre. */ @@ -83,6 +91,13 @@ typedef struct const char *dcs; } t4_rx_metadata_t; +typedef struct +{ + uint8_t *buf; + int buf_len; + int buf_ptr; +} no_decoder_state_t; + /*! T.4 FAX decompression descriptor. This defines the working state for a single instance of a T.4 FAX decompression channel. @@ -94,30 +109,35 @@ struct t4_rx_state_s /*! \brief Opaque pointer passed to row_write_handler. */ 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. */ int current_page; /*! \brief The size of the compressed image on the line side, in bits. */ int line_image_size; - /*! \brief The type of compression used between the FAX machines. */ - int line_encoding; - - /*! \brief The width of the current page, in pixels. */ - uint32_t image_width; - /*! \brief The length of the current page, in pixels. */ - uint32_t image_length; - union { + no_decoder_state_t no_decoder; t4_t6_decode_state_t t4_t6; - t42_decode_state_t t42; -#if defined(SPANDSP_SUPPORT_T43) - t43_decode_state_t t43; -#endif t85_decode_state_t t85; +#if defined(SPANDSP_SUPPORT_T88) + t88_decode_state_t t88; +#endif + t42_decode_state_t t42; + t43_decode_state_t t43; +#if defined(SPANDSP_SUPPORT_T45) + t45_decode_state_t t45; +#endif } decoder; + t4_image_put_handler_t image_put_handler; + + int current_decoder; + /* Supporting information, like resolutions, which the backend may want. */ t4_rx_metadata_t metadata; diff --git a/libs/spandsp/src/spandsp/private/t4_t6_decode.h b/libs/spandsp/src/spandsp/private/t4_t6_decode.h index 90b4e72d66..616e1be879 100644 --- a/libs/spandsp/src/spandsp/private/t4_t6_decode.h +++ b/libs/spandsp/src/spandsp/private/t4_t6_decode.h @@ -81,8 +81,8 @@ struct t4_t6_decode_state_s int run_length; /*! \brief 2D horizontal mode control. */ int black_white; - /*! \brief TRUE if the current run is black */ - int in_black; + /*! \brief True if the current run is black */ + bool in_black; /*! \brief The current step into the current row run-lengths buffer. */ int a_cursor; diff --git a/libs/spandsp/src/spandsp/private/t4_t6_encode.h b/libs/spandsp/src/spandsp/private/t4_t6_encode.h index ea080109aa..4ac35f76a9 100644 --- a/libs/spandsp/src/spandsp/private/t4_t6_encode.h +++ b/libs/spandsp/src/spandsp/private/t4_t6_encode.h @@ -59,7 +59,7 @@ struct t4_t6_encode_state_s /*! \brief This variable is set if we are treating the current row as a 2D encoded one. */ - int row_is_2d; + bool row_is_2d; /*! \brief Encoded data bits buffer. */ uint32_t tx_bitstream; diff --git a/libs/spandsp/src/spandsp/private/t4_tx.h b/libs/spandsp/src/spandsp/private/t4_tx.h index 6f2fd12349..009152d9e2 100644 --- a/libs/spandsp/src/spandsp/private/t4_tx.h +++ b/libs/spandsp/src/spandsp/private/t4_tx.h @@ -26,6 +26,8 @@ #if !defined(_SPANDSP_PRIVATE_T4_TX_H_) #define _SPANDSP_PRIVATE_T4_TX_H_ +typedef int (*t4_image_get_handler_t)(void *user_data, uint8_t buf[], size_t len); + /*! TIFF specific state information to go with T.4 compression or decompression handling. */ @@ -45,6 +47,17 @@ typedef struct /*! \brief The TIFF fill order setting for the current page. */ uint16_t fill_order; + /*! \brief Width of the image in the file. */ + uint32_t image_width; + /*! \brief Length of the image in the file. */ + uint32_t image_length; + /*! \brief Column-to-column (X) resolution in pixels per metre of the image in the file. */ + int x_resolution; + /*! \brief Row-to-row (Y) resolution in pixels per metre of the image in the file. */ + int y_resolution; + /*! \brief Code for the combined X and Y resolution of the image in the file. */ + int resolution_code; + /*! \brief The number of pages in the current image file. */ int pages_in_file; @@ -56,16 +69,6 @@ typedef struct int image_buffer_size; /*! \brief Row counter for playing out the rows of the image. */ int row; - - /*! \brief Width of the image in the file. */ - int image_width; - /*! \brief Length of the image in the file. */ - int image_length; - /*! \brief Column-to-column (X) resolution in pixels per metre of the image in the file. */ - int image_x_resolution; - /*! \brief Row-to-row (Y) resolution in pixels per metre of the image in the file. */ - int image_y_resolution; - /*! \brief Row counter used when the image is resized or dithered flat. */ int raw_row; } t4_tx_tiff_state_t; @@ -78,12 +81,33 @@ typedef struct */ typedef struct { + /*! \brief The type of compression used on the wire. */ + int compression; + /*! \brief Image type - bi-level, gray, colour, etc. */ + int image_type; + /*! \brief The width code for the image on the line side. */ + int width_code; + + /*! \brief The width of the current page on the wire, in pixels. */ + uint32_t image_width; + /*! \brief The length of the current page on the wire, in pixels. */ + uint32_t image_length; /*! \brief Column-to-column (X) resolution in pixels per metre on the wire. */ int x_resolution; /*! \brief Row-to-row (Y) resolution in pixels per metre on the wire. */ int y_resolution; + /*! \brief Code for the combined X and Y resolution on the wire. */ + int resolution_code; } t4_tx_metadata_t; +typedef struct +{ + uint8_t *buf; + int buf_len; + int buf_ptr; + int bit; +} no_encoder_state_t; + /*! T.4 FAX compression descriptor. This defines the working state for a single instance of a T.4 FAX compression channel. @@ -95,23 +119,11 @@ struct t4_tx_state_s /*! \brief Opaque pointer passed to row_read_handler. */ void *row_handler_user_data; - /*! \brief The type of compression used between the FAX machines. */ - int line_encoding; - - int line_encoding_bilevel; - int line_encoding_gray; - int line_encoding_colour; - /*! \brief When superfine and fine resolution images need to be squahed vertically to a lower resolution, this value sets the number of source rows which must be squashed to form each row on the wire. */ int row_squashing_ratio; - /*! \brief The width of the current page, in pixels. */ - uint32_t image_width; - /*! \brief The length of the current page, in pixels. */ - uint32_t image_length; - /*! \brief The size of the compressed image on the line side, in bits. */ int line_image_size; @@ -120,10 +132,10 @@ struct t4_tx_state_s /*! \brief The last page to transfer. -1 to continue to the end of the file. */ int stop_page; - /*! \brief TRUE for FAX page headers to overlay (i.e. replace) the beginning of the - page image. FALSE for FAX page headers to add to the overall length of + /*! \brief True for FAX page headers to overlay (i.e. replace) the beginning of the + page image. False for FAX page headers to add to the overall length of the page. */ - int header_overlays_image; + bool header_overlays_image; /*! \brief The text which will be used in FAX page header. No text results in no header line. */ const char *header_info; @@ -145,22 +157,35 @@ struct t4_tx_state_s union { + no_encoder_state_t no_encoder; t4_t6_encode_state_t t4_t6; - t42_encode_state_t t42; -#if defined(SPANDSP_SUPPORT_T43) - t43_encode_state_t t43; -#endif t85_encode_state_t t85; +#if defined(SPANDSP_SUPPORT_T88) + t88_encode_state_t t88; +#endif + t42_encode_state_t t42; + t43_encode_state_t t43; +#if defined(SPANDSP_SUPPORT_T45) + t45_encode_state_t t45; +#endif } encoder; - image_translate_state_t translator; + t4_image_get_handler_t image_get_handler; int apply_lab; lab_params_t lab_params; uint8_t *colour_map; int colour_map_entries; - /* Supporting information, like resolutions, which the backend may want. */ + image_translate_state_t translator; + uint8_t *pack_buf; + int pack_ptr; + int pack_row; + int pack_bit_mask; + + no_encoder_state_t no_encoder; + + /*! \brief Supporting information, like resolutions, which the backend may want. */ t4_tx_metadata_t metadata; /*! \brief All TIFF file specific state information for the T.4 context. */ diff --git a/libs/spandsp/src/spandsp/private/t85.h b/libs/spandsp/src/spandsp/private/t85.h index 586a5cc22f..5eb2b50676 100644 --- a/libs/spandsp/src/spandsp/private/t85.h +++ b/libs/spandsp/src/spandsp/private/t85.h @@ -89,8 +89,8 @@ struct t85_encode_state_s uint32_t c[128]; /*! New TX value, or <0 for analysis in progress */ int32_t new_tx; - /*! TRUE if previous row was typical */ - int prev_ltp; + /*! True if previous row was typical */ + bool prev_ltp; /*! Pointers to the 3 row buffers */ uint8_t *prev_row[3]; /*! Pointer to a block of allocated memory 3 rows long, which diff --git a/libs/spandsp/src/spandsp/private/timezone.h b/libs/spandsp/src/spandsp/private/timezone.h index 9f28cc3d2b..87c67978a7 100644 --- a/libs/spandsp/src/spandsp/private/timezone.h +++ b/libs/spandsp/src/spandsp/private/timezone.h @@ -54,8 +54,8 @@ struct tz_ttinfo_s int32_t gmtoff; /* UTC offset in seconds */ int isdst; /* Used to set tm_isdst */ int abbrind; /* Abbreviation list index */ - int ttisstd; /* TRUE if transition is std time */ - int ttisgmt; /* TRUE if transition is UTC */ + bool ttisstd; /* True if transition is std time */ + bool ttisgmt; /* True if transition is UTC */ }; /* Leap second information */ diff --git a/libs/spandsp/src/spandsp/private/v17rx.h b/libs/spandsp/src/spandsp/private/v17rx.h index 2082722fd6..f6f847c553 100644 --- a/libs/spandsp/src/spandsp/private/v17rx.h +++ b/libs/spandsp/src/spandsp/private/v17rx.h @@ -156,8 +156,8 @@ struct v17_rx_state_s /*! \brief Scrambler tap */ int scrambler_tap; - /*! \brief TRUE if the short training sequence is to be used. */ - int short_train; + /*! \brief True if the short training sequence is to be used. */ + bool short_train; /*! \brief The section of the training data we are currently in. */ int training_stage; /*! \brief A count of how far through the current training step we are. */ diff --git a/libs/spandsp/src/spandsp/private/v17tx.h b/libs/spandsp/src/spandsp/private/v17tx.h index 3e2fff6d2c..acf2819371 100644 --- a/libs/spandsp/src/spandsp/private/v17tx.h +++ b/libs/spandsp/src/spandsp/private/v17tx.h @@ -81,10 +81,10 @@ struct v17_tx_state_s uint32_t scramble_reg; /*! \brief Scrambler tap */ int scrambler_tap; - /*! \brief TRUE if transmitting the training sequence. FALSE if transmitting user data. */ - int in_training; - /*! \brief TRUE if the short training sequence is to be used. */ - int short_train; + /*! \brief True if transmitting the training sequence. False if transmitting user data. */ + bool in_training; + /*! \brief True if the short training sequence is to be used. */ + bool short_train; /*! \brief A counter used to track progress through sending the training sequence. */ int training_step; diff --git a/libs/spandsp/src/spandsp/private/v18.h b/libs/spandsp/src/spandsp/private/v18.h index 086262c720..a7575b870b 100644 --- a/libs/spandsp/src/spandsp/private/v18.h +++ b/libs/spandsp/src/spandsp/private/v18.h @@ -28,11 +28,13 @@ struct v18_state_s { - /*! \brief TRUE if we are the calling modem */ - int calling_party; + /*! \brief True if we are the calling modem */ + bool calling_party; int mode; + int nation; put_msg_func_t put_msg; void *user_data; + int repeat_shifts; union { @@ -41,22 +43,22 @@ struct v18_state_s } queue; tone_gen_descriptor_t alert_tone_desc; tone_gen_state_t alert_tone_gen; - fsk_tx_state_t fsktx; - dtmf_tx_state_t dtmftx; - async_tx_state_t asynctx; + fsk_tx_state_t fsk_tx; + dtmf_tx_state_t dtmf_tx; + async_tx_state_t async_tx; int baudot_tx_shift; int tx_signal_on; - int byte_no; + uint8_t next_byte; - fsk_rx_state_t fskrx; - dtmf_rx_state_t dtmfrx; + fsk_rx_state_t fsk_rx; + dtmf_rx_state_t dtmf_rx; int baudot_rx_shift; int consecutive_ones; uint8_t rx_msg[256 + 1]; int rx_msg_len; int bit_pos; int in_progress; - int repeat_shifts; + int rx_suppression; /*! \brief Error and flow logging control */ logging_state_t logging; diff --git a/libs/spandsp/src/spandsp/private/v22bis.h b/libs/spandsp/src/spandsp/private/v22bis.h index c0da6b0aa6..dac5becb68 100644 --- a/libs/spandsp/src/spandsp/private/v22bis.h +++ b/libs/spandsp/src/spandsp/private/v22bis.h @@ -79,8 +79,8 @@ struct v22bis_state_s { /*! \brief The maximum permitted bit rate of the modem. Valid values are 1200 and 2400. */ int bit_rate; - /*! \brief TRUE is this is the calling side modem. */ - int calling_party; + /*! \brief True is this is the calling side modem. */ + bool calling_party; /*! \brief The callback function used to get the next bit to be transmitted. */ get_bit_func_t get_bit; /*! \brief A user specified opaque pointer passed to the get_bit callback routine. */ diff --git a/libs/spandsp/src/spandsp/private/v27ter_rx.h b/libs/spandsp/src/spandsp/private/v27ter_rx.h index fbec14c5ed..fc7912febc 100644 --- a/libs/spandsp/src/spandsp/private/v27ter_rx.h +++ b/libs/spandsp/src/spandsp/private/v27ter_rx.h @@ -130,8 +130,8 @@ struct v27ter_rx_state_s int scrambler_pattern_count; /*! \brief The current step in the table of BC constellation positions. */ int training_bc; - /*! \brief TRUE if the previous trained values are to be reused. */ - int old_train; + /*! \brief True if the previous trained values are to be reused. */ + bool old_train; /*! \brief The section of the training data we are currently in. */ int training_stage; /*! \brief A count of how far through the current training step we are. */ diff --git a/libs/spandsp/src/spandsp/private/v27ter_tx.h b/libs/spandsp/src/spandsp/private/v27ter_tx.h index ba9ab8b5aa..add5b36979 100644 --- a/libs/spandsp/src/spandsp/private/v27ter_tx.h +++ b/libs/spandsp/src/spandsp/private/v27ter_tx.h @@ -73,9 +73,9 @@ struct v27ter_tx_state_s /*! \brief A counter for the number of consecutive bits of repeating pattern through the scrambler. */ int scrambler_pattern_count; - /*! \brief TRUE if transmitting the training sequence, or shutting down transmission. - FALSE if transmitting user data. */ - int in_training; + /*! \brief True if transmitting the training sequence, or shutting down transmission. + False if transmitting user data. */ + bool in_training; /*! \brief A counter used to track progress through sending the training sequence. */ int training_step; diff --git a/libs/spandsp/src/spandsp/private/v29rx.h b/libs/spandsp/src/spandsp/private/v29rx.h index fd931af0f8..8b38b467bf 100644 --- a/libs/spandsp/src/spandsp/private/v29rx.h +++ b/libs/spandsp/src/spandsp/private/v29rx.h @@ -139,8 +139,8 @@ struct v29_rx_state_s uint8_t training_scramble_reg; /*! \brief The current step in the table of CD constellation positions. */ int training_cd; - /*! \brief TRUE if the previous trained values are to be reused. */ - int old_train; + /*! \brief True if the previous trained values are to be reused. */ + bool old_train; /*! \brief The section of the training data we are currently in. */ int training_stage; /*! \brief A count of how far through the current training step we are. */ diff --git a/libs/spandsp/src/spandsp/private/v29tx.h b/libs/spandsp/src/spandsp/private/v29tx.h index 67c2b7098d..58f86a2af7 100644 --- a/libs/spandsp/src/spandsp/private/v29tx.h +++ b/libs/spandsp/src/spandsp/private/v29tx.h @@ -76,9 +76,9 @@ struct v29_tx_state_s uint32_t scramble_reg; /*! \brief The register for the training scrambler. */ uint8_t training_scramble_reg; - /*! \brief TRUE if transmitting the training sequence, or shutting down transmission. - FALSE if transmitting user data. */ - int in_training; + /*! \brief True if transmitting the training sequence, or shutting down transmission. + False if transmitting user data. */ + bool in_training; /*! \brief A counter used to track progress through sending the training sequence. */ int training_step; /*! \brief An offset value into the table of training parameters, used to match the diff --git a/libs/spandsp/src/spandsp/private/v42.h b/libs/spandsp/src/spandsp/private/v42.h index b45b716349..5eac89f873 100644 --- a/libs/spandsp/src/spandsp/private/v42.h +++ b/libs/spandsp/src/spandsp/private/v42.h @@ -92,9 +92,9 @@ typedef struct uint8_t vr; int state; int configuring; - int local_busy; - int far_busy; - int rejected; + bool local_busy; + bool far_busy; + bool rejected; int retry_count; /* The control frame buffer, and its pointers */ @@ -131,11 +131,11 @@ typedef struct */ struct v42_state_s { - /*! TRUE if we are the calling party, otherwise FALSE. */ - int calling_party; - /*! TRUE if we should detect whether the far end is V.42 capable. FALSE if we go + /*! True if we are the calling party, otherwise false. */ + bool calling_party; + /*! True if we should detect whether the far end is V.42 capable. false if we go directly to protocol establishment. */ - int detect; + bool detect; /*! The bit rate, used to time events */ int tx_bit_rate; diff --git a/libs/spandsp/src/spandsp/private/v42bis.h b/libs/spandsp/src/spandsp/private/v42bis.h index 967b1fd909..216199d79b 100644 --- a/libs/spandsp/src/spandsp/private/v42bis.h +++ b/libs/spandsp/src/spandsp/private/v42bis.h @@ -60,8 +60,8 @@ typedef struct /*! \brief The maximum amount to be passed to the data handler. */ int max_output_len; - /*! \brief TRUE if we are in transparent (i.e. uncompressable) mode */ - int transparent; + /*! \brief True if we are in transparent (i.e. uncompressable) mode */ + bool transparent; /*! \brief Next empty dictionary entry */ uint16_t v42bis_parm_c1; /*! \brief Current codeword size */ @@ -104,8 +104,8 @@ typedef struct /*! \brief The current value of the escape code */ uint8_t escape_code; - /*! \brief TRUE if we just hit an escape code, and are waiting for the following octet */ - int escaped; + /*! \brief True if we just hit an escape code, and are waiting for the following octet */ + bool escaped; } v42bis_comp_state_t; /*! diff --git a/libs/spandsp/src/spandsp/private/v8.h b/libs/spandsp/src/spandsp/private/v8.h index 213d445f52..3c07b0e3bc 100644 --- a/libs/spandsp/src/spandsp/private/v8.h +++ b/libs/spandsp/src/spandsp/private/v8.h @@ -28,8 +28,8 @@ struct v8_state_s { - /*! \brief TRUE if we are the calling party */ - int calling_party; + /*! \brief True if we are the calling party */ + bool calling_party; /*! \brief A handler to process the V.8 signals */ v8_result_handler_t result_handler; @@ -38,7 +38,7 @@ struct v8_state_s /*! \brief The current state of the V.8 protocol */ int state; - int fsk_tx_on; + bool fsk_tx_on; int modem_connect_tone_tx_on; int negotiation_timer; int ci_timer; @@ -67,8 +67,8 @@ struct v8_state_s testing for matches. */ uint8_t cm_jm_data[64]; int cm_jm_len; - int got_cm_jm; - int got_cj; + bool got_cm_jm; + bool got_cj; int zero_byte_count; /*! \brief Error and flow logging control */ logging_state_t logging; diff --git a/libs/spandsp/src/spandsp/queue.h b/libs/spandsp/src/spandsp/queue.h index cbb4357916..7e56a59fc7 100644 --- a/libs/spandsp/src/spandsp/queue.h +++ b/libs/spandsp/src/spandsp/queue.h @@ -63,8 +63,8 @@ extern "C" /*! Check if a queue is empty. \brief Check if a queue is empty. \param s The queue context. - \return TRUE if empty, else FALSE. */ -SPAN_DECLARE(int) queue_empty(queue_state_t *s); + \return True if empty, else false. */ +SPAN_DECLARE(bool) queue_empty(queue_state_t *s); /*! Check the available free space in a queue's buffer. \brief Check available free space. diff --git a/libs/spandsp/src/spandsp/stdbool.h b/libs/spandsp/src/spandsp/stdbool.h new file mode 100644 index 0000000000..8c722fad17 --- /dev/null +++ b/libs/spandsp/src/spandsp/stdbool.h @@ -0,0 +1,55 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * stdbool.h - A version for systems which lack their own stdbool.h + * + * Written by Steve Underwood + * + * Copyright (C) 2003 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/*! \file */ + + +/* + * ISO C Standard: 7.16 Boolean type and values + */ + +#if !defined(_STDBOOL_H) +#define _STDBOOL_H + +#if !defined(__cplusplus) + +#define _Bool int +#define bool int +#define false 0 +#define true (!false) + +#else + +#define _Bool bool +#define bool bool +#define false false +#define true true + +#endif + +/* Signal that all the definitions are present. */ +#define __bool_true_false_are_defined 1 + +#endif diff --git a/libs/spandsp/src/spandsp/t30.h b/libs/spandsp/src/spandsp/t30.h index 241df11d9e..6d43383eed 100644 --- a/libs/spandsp/src/spandsp/t30.h +++ b/libs/spandsp/src/spandsp/t30.h @@ -32,7 +32,7 @@ \section t30_page_sec_1 What does it do? The T.30 protocol is the core protocol used for FAX transmission. This module -implements most of its key featrues. It does not interface to the outside work. +implements most of its key features. It does not interface to the outside work. Seperate modules do that for T.38, analogue line, and other forms of FAX communication. @@ -184,13 +184,13 @@ typedef void (*t30_phase_e_handler_t)(t30_state_t *s, void *user_data, int compl \brief T.30 real time frame handler. \param s The T.30 context. \param user_data An opaque pointer. - \param direction TRUE for incoming, FALSE for outgoing. + \param incoming True for incoming, false for outgoing. \param msg The HDLC message. \param len The length of the message. */ typedef void (*t30_real_time_frame_handler_t)(t30_state_t *s, void *user_data, - int direction, + bool direction, const uint8_t msg[], int len); @@ -209,8 +209,8 @@ typedef int (*t30_document_handler_t)(t30_state_t *s, void *user_data, int statu \param user_data An opaque pointer. \param type The modem, tone or silence to be sent or received. \param bit_rate The bit rate of the modem to be sent or received. - \param short_train TRUE if the short training sequence should be used (where one exists). - \param use_hdlc FALSE for bit stream, TRUE for HDLC framing. + \param short_train True if the short training sequence should be used (where one exists). + \param use_hdlc False for bit stream, true for HDLC framing. */ typedef void (*t30_set_handler_t)(void *user_data, int type, int bit_rate, int short_train, int use_hdlc); @@ -223,6 +223,26 @@ typedef void (*t30_set_handler_t)(void *user_data, int type, int bit_rate, int s */ typedef void (*t30_send_hdlc_handler_t)(void *user_data, const uint8_t msg[], int len); +/*! + T.30 send document handler. + \brief T.30 send document handler. + \param user_data An opaque pointer. + \param msg The document chunk. + \param len The length of the chunk. + \return The actual length of the chunk. +*/ +typedef int (*t30_document_get_handler_t)(void *user_data, uint8_t msg[], int len); + +/*! + T.30 deliver document handler. + \brief T.30 deliver handler. + \param user_data An opaque pointer. + \param msg The document chunk. + \param len The length of the chunk. + \return The delivery status. +*/ +typedef int (*t30_document_put_handler_t)(void *user_data, const uint8_t msg[], int len); + /*! T.30 protocol completion codes, at phase E. */ @@ -323,19 +343,6 @@ enum T30_MODEM_DONE }; -enum -{ - T30_FRONT_END_SEND_STEP_COMPLETE = 0, - /*! The current receive has completed. This is only needed to report an - unexpected end of the receive operation, as might happen with T.38 - dying. */ - T30_FRONT_END_RECEIVE_COMPLETE, - T30_FRONT_END_SIGNAL_PRESENT, - T30_FRONT_END_SIGNAL_ABSENT, - T30_FRONT_END_CED_PRESENT, - T30_FRONT_END_CNG_PRESENT -}; - enum { /*! Support the V.27ter modem (2400, and 4800bps) for image transfer. */ @@ -352,77 +359,15 @@ enum enum { - /*! No compression */ - T30_SUPPORT_NO_COMPRESSION = 0x01, - /*! T.1 1D compression */ - T30_SUPPORT_T4_1D_COMPRESSION = 0x02, - /*! T.4 2D compression */ - T30_SUPPORT_T4_2D_COMPRESSION = 0x04, - /*! T.6 2D compression */ - T30_SUPPORT_T6_COMPRESSION = 0x08, - /*! T.85 monochrome JBIG compression, with fixed L0 */ - T30_SUPPORT_T85_COMPRESSION = 0x10, - /*! T.85 monochrome JBIG compression, with variable L0 */ - T30_SUPPORT_T85_L0_COMPRESSION = 0x20, - /*! T.43 colour JBIG compression */ - T30_SUPPORT_T43_COMPRESSION = 0x40, - /*! T.45 run length colour compression */ - T30_SUPPORT_T45_COMPRESSION = 0x80, - /*! T.81 + T.30 Annex E colour JPEG compression */ - T30_SUPPORT_T81_COMPRESSION = 0x100, - /*! T.81 + T.30 Annex K colour sYCC-JPEG compression */ - T30_SUPPORT_SYCC_T81_COMPRESSION = 0x200, - /*! T.88 monochrome JBIG2 compression */ - T30_SUPPORT_T88_COMPRESSION = 0x400, - /*! Dither a gray scale image down a simple bilevel image, with rescaling to fit a FAX page */ - T30_SUPPORT_GRAY_TO_BILEVEL = 0x10000000, - /*! Dither a colour image down a simple bilevel image, with rescaling to fit a FAX page */ - T30_SUPPORT_COLOUR_TO_BILEVEL = 0x20000000 -}; - -enum -{ - /*! Support standard FAX Y-resolution 98/100dpi */ - T30_SUPPORT_STANDARD_RESOLUTION = 0x01, - /*! Support fine FAX Y-resolution 196/200dpi */ - T30_SUPPORT_FINE_RESOLUTION = 0x02, - /*! Support super-fine FAX Y-resolution 392/400dpi */ - T30_SUPPORT_SUPERFINE_RESOLUTION = 0x04, - - /*! Support half FAX X-resolution 100/102dpi */ - T30_SUPPORT_R4_RESOLUTION = 0x10000, - /*! Support standard FAX X-resolution 200/204dpi */ - T30_SUPPORT_R8_RESOLUTION = 0x20000, - /*! Support double FAX X-resolution 400dpi */ - T30_SUPPORT_R16_RESOLUTION = 0x40000, - - /*! Support 300dpi x 300 dpi */ - T30_SUPPORT_300_300_RESOLUTION = 0x100000, - /*! Support 400dpi x 400 dpi */ - T30_SUPPORT_400_400_RESOLUTION = 0x200000, - /*! Support 600dpi x 600 dpi */ - T30_SUPPORT_600_600_RESOLUTION = 0x400000, - /*! Support 1200dpi x 1200 dpi */ - T30_SUPPORT_1200_1200_RESOLUTION = 0x800000, - /*! Support 300dpi x 600 dpi */ - T30_SUPPORT_300_600_RESOLUTION = 0x1000000, - /*! Support 400dpi x 800 dpi */ - T30_SUPPORT_400_800_RESOLUTION = 0x2000000, - /*! Support 600dpi x 1200 dpi */ - T30_SUPPORT_600_1200_RESOLUTION = 0x4000000 -}; - -enum -{ - T30_SUPPORT_215MM_WIDTH = 0x01, - T30_SUPPORT_255MM_WIDTH = 0x02, - T30_SUPPORT_303MM_WIDTH = 0x04, - - T30_SUPPORT_UNLIMITED_LENGTH = 0x10000, - T30_SUPPORT_A4_LENGTH = 0x20000, - T30_SUPPORT_B4_LENGTH = 0x40000, - T30_SUPPORT_US_LETTER_LENGTH = 0x80000, - T30_SUPPORT_US_LEGAL_LENGTH = 0x100000 + T30_FRONT_END_SEND_STEP_COMPLETE = 0, + /*! The current receive has completed. This is only needed to report an + unexpected end of the receive operation, as might happen with T.38 + dying. */ + T30_FRONT_END_RECEIVE_COMPLETE, + T30_FRONT_END_SIGNAL_PRESENT, + T30_FRONT_END_SIGNAL_ABSENT, + T30_FRONT_END_CED_PRESENT, + T30_FRONT_END_CNG_PRESENT }; enum @@ -523,7 +468,7 @@ typedef struct { /*! \brief The current bit rate for image transfer. */ int bit_rate; - /*! \brief TRUE if error correcting mode is used. */ + /*! \brief True if error correcting mode is used. */ int error_correcting_mode; /*! \brief The number of pages sent so far. */ int pages_tx; @@ -554,7 +499,7 @@ typedef struct /*! \brief The size of the image, in bytes */ int image_size; /*! \brief The type of compression used between the FAX machines */ - int encoding; + int compression; /*! \brief The number of bad pixel rows in the most recent page. */ int bad_rows; /*! \brief The largest number of bad pixel rows in a block in the most recent page. */ @@ -577,7 +522,7 @@ extern "C" /*! Initialise a T.30 context. \brief Initialise a T.30 context. \param s The T.30 context. - \param calling_party TRUE if the context is for a calling party. FALSE if the + \param calling_party True if the context is for a calling party. False if the context is for an answering party. \param set_rx_type_handler \param set_rx_type_user_data @@ -617,7 +562,7 @@ SPAN_DECLARE(int) t30_restart(t30_state_t *s); if the job has finished. \brief Check if a T.30 call is still active. \param s The T.30 context. - \return TRUE for call still active, or FALSE for call completed. */ + \return True for call still active, or false for call completed. */ SPAN_DECLARE(int) t30_call_active(t30_state_t *s); /*! Cleanup a T.30 context if the call terminates. @@ -663,7 +608,7 @@ SPAN_DECLARE(void) t30_non_ecm_put(void *user_data, const uint8_t buf[], int len \param user_data The T.30 context. \param msg The HDLC message. \param len The length of the message, in octets. - \param ok TRUE if the frame was received without error. */ + \param ok True if the frame was received without error. */ SPAN_DECLARE_NONSTD(void) t30_hdlc_accept(void *user_data, const uint8_t msg[], int len, int ok); /*! Report the passage of time to the T.30 engine. @@ -681,13 +626,13 @@ SPAN_DECLARE(void) t30_get_transfer_statistics(t30_state_t *s, t30_stats_t *t); /*! Request a local interrupt of FAX exchange. \brief Request a local interrupt of FAX exchange. \param s The T.30 context. - \param state TRUE to enable interrupt request, else FALSE. */ + \param state True to enable interrupt request, else false. */ SPAN_DECLARE(void) t30_local_interrupt_request(t30_state_t *s, int state); /*! Allow remote interrupts of FAX exchange. \brief Allow remote interrupts of FAX exchange. \param s The T.30 context. - \param state TRUE to allow interruptd, else FALSE. */ + \param state True to allow interruptd, else false. */ SPAN_DECLARE(void) t30_remote_interrupts_allowed(t30_state_t *s, int state); #if defined(__cplusplus) diff --git a/libs/spandsp/src/spandsp/t30_api.h b/libs/spandsp/src/spandsp/t30_api.h index 08a0383634..90cefc4f58 100644 --- a/libs/spandsp/src/spandsp/t30_api.h +++ b/libs/spandsp/src/spandsp/t30_api.h @@ -225,6 +225,12 @@ SPAN_DECLARE(const char *) t30_get_tx_password(t30_state_t *s); \return A pointer to the password. */ SPAN_DECLARE(const char *) t30_get_rx_password(t30_state_t *s); +/*! Set the save bad quality pages handling associated with a T.30 context. + \brief Set the save bad quality pages handling associated with a T.30 context. + \param s The T.30 context. + \param keep_bad_pages True to save bad quality pages. */ +SPAN_DECLARE(void) t30_set_keep_bad_quality_pages(t30_state_t *s, bool keep_bad_pages); + /*! Set the transmitted TSA (i.e. the one we will send to the far end) associated with a T.30 context. \brief Set the transmitted TSA associated with a T.30 context. @@ -363,8 +369,8 @@ SPAN_DECLARE(size_t) t30_get_rx_csa(t30_state_t *s, int *type, const char *addre /*! Set page header extends or overlays the image mode. \brief Set page header overlay mode. \param s The T.30 context. - \param header_overlays_image TRUE for overlay, or FALSE for extend the page. */ -SPAN_DECLARE(int) t30_set_tx_page_header_overlays_image(t30_state_t *s, int header_overlays_image); + \param header_overlays_image True for overlay, or false for extend the page. */ +SPAN_DECLARE(int) t30_set_tx_page_header_overlays_image(t30_state_t *s, bool header_overlays_image); /*! Set the transmitted header information associated with a T.30 context. \brief Set the transmitted header information associated with a T.30 context. @@ -426,25 +432,23 @@ SPAN_DECLARE(void) t30_set_tx_file(t30_state_t *s, const char *file, int start_p /*! Set Internet aware FAX (IAF) mode. \brief Set Internet aware FAX (IAF) mode. \param s The T.30 context. - \param iaf TRUE for IAF, or FALSE for non-IAF. */ -SPAN_DECLARE(void) t30_set_iaf_mode(t30_state_t *s, int iaf); + \param iaf True for IAF, or false for non-IAF. */ +SPAN_DECLARE(void) t30_set_iaf_mode(t30_state_t *s, bool iaf); /*! Specify if error correction mode (ECM) is allowed by a T.30 context. \brief Select ECM capability. \param s The T.30 context. - \param enabled TRUE for ECM capable, FALSE for not ECM capable. + \param enabled True for ECM capable, or false for not ECM capable. \return 0 if OK, else -1. */ -SPAN_DECLARE(int) t30_set_ecm_capability(t30_state_t *s, int enabled); +SPAN_DECLARE(int) t30_set_ecm_capability(t30_state_t *s, bool enabled); /*! 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 encoding The coding required. The options are T4_COMPRESSION_ITU_T4_1D, - T4_COMPRESSION_ITU_T4_2D, T4_COMPRESSION_ITU_T6. T6 is usually the - densest option, but support for it is broken in a number of software - packages. + \param supported_compressions Bit field list of the supported compression types, for + output of received page images. \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. \brief Specify minimum scan line time. @@ -467,12 +471,19 @@ SPAN_DECLARE(int) t30_set_supported_modems(t30_state_t *s, int supported_modems) \return 0 if OK, else -1. */ SPAN_DECLARE(int) t30_set_supported_compressions(t30_state_t *s, int supported_compressions); -/*! Specify which resolutions are supported by a T.30 context. - \brief Specify supported resolutions. +/*! Specify which bi-level resolutions are supported by a T.30 context. + \brief Specify supported bi-level resolutions. \param s The T.30 context. \param supported_resolutions Bit field list of the supported resolutions. \return 0 if OK, else -1. */ -SPAN_DECLARE(int) t30_set_supported_resolutions(t30_state_t *s, int supported_resolutions); +SPAN_DECLARE(int) t30_set_supported_bilevel_resolutions(t30_state_t *s, int supported_resolutions); + +/*! Specify which colour resolutions are supported by a T.30 context. + \brief Specify supported colour resolutions. + \param s The T.30 context. + \param supported_resolutions Bit field list of the supported resolutions. + \return 0 if OK, else -1. */ +SPAN_DECLARE(int) t30_set_supported_colour_resolutions(t30_state_t *s, int supported_resolutions); /*! Specify which images sizes are supported by a T.30 context. \brief Specify supported image sizes. @@ -538,6 +549,10 @@ SPAN_DECLARE(void) t30_set_document_handler(t30_state_t *s, t30_document_handler \param user_data An opaque pointer passed to the callback function. */ SPAN_DECLARE(void) t30_set_real_time_frame_handler(t30_state_t *s, t30_real_time_frame_handler_t handler, void *user_data); +SPAN_DECLARE(void) t30_set_document_get_handler(t30_state_t *s, t30_document_get_handler_t handler, void *user_data); + +SPAN_DECLARE(void) t30_set_document_put_handler(t30_state_t *s, t30_document_put_handler_t handler, void *user_data); + /*! Get a pointer to the logging context associated with a T.30 context. \brief Get a pointer to the logging context associated with a T.30 context. \param s The T.30 context. diff --git a/libs/spandsp/src/spandsp/t30_logging.h b/libs/spandsp/src/spandsp/t30_logging.h index 2dc9bb321c..7122b1c6eb 100644 --- a/libs/spandsp/src/spandsp/t30_logging.h +++ b/libs/spandsp/src/spandsp/t30_logging.h @@ -53,6 +53,12 @@ SPAN_DECLARE(void) t30_decode_dis_dtc_dcs(t30_state_t *s, const uint8_t *dis, in \return A pointer to the description. */ SPAN_DECLARE(const char *) t30_completion_code_to_str(int result); +/*! Convert a T.30 modem type to a short text description. + \brief Convert a T.30 modem type to a short text description. + \param modem The modem code. + \return A pointer to the description. */ +SPAN_DECLARE(const char *) t30_modem_to_str(int modem); + #if defined(__cplusplus) } #endif diff --git a/libs/spandsp/src/spandsp/t31.h b/libs/spandsp/src/spandsp/t31.h index 4e8452e497..b61a4142f9 100644 --- a/libs/spandsp/src/spandsp/t31.h +++ b/libs/spandsp/src/spandsp/t31.h @@ -89,33 +89,33 @@ SPAN_DECLARE(int) t31_t38_send_timeout(t31_state_t *s, int samples); /*! Select whether silent audio will be sent when transmit is idle. \brief Select whether silent audio will be sent when transmit is idle. \param s The T.31 modem context. - \param transmit_on_idle TRUE if silent audio should be output when the transmitter is - idle. FALSE to transmit zero length audio when the transmitter is idle. The default - behaviour is FALSE. + \param transmit_on_idle True if silent audio should be output when the transmitter is + idle. False to transmit zero length audio when the transmitter is idle. The default + behaviour is false. */ -SPAN_DECLARE(void) t31_set_transmit_on_idle(t31_state_t *s, int transmit_on_idle); +SPAN_DECLARE(void) t31_set_transmit_on_idle(t31_state_t *s, bool transmit_on_idle); /*! Select whether TEP mode will be used (or time allowed for it (when transmitting). \brief Select whether TEP mode will be used. \param s The T.31 modem context. - \param use_tep TRUE if TEP is to be ised. + \param use_tep True if TEP is to be used. */ -SPAN_DECLARE(void) t31_set_tep_mode(t31_state_t *s, int use_tep); +SPAN_DECLARE(void) t31_set_tep_mode(t31_state_t *s, bool use_tep); /*! Select whether T.38 data will be paced as it is transmitted. \brief Select whether T.38 data will be paced. \param s The T.31 modem context. - \param without_pacing TRUE if data is to be sent as fast as possible. FALSE if it is + \param without_pacing True if data is to be sent as fast as possible. False if it is to be paced. */ -SPAN_DECLARE(void) t31_set_t38_config(t31_state_t *s, int without_pacing); +SPAN_DECLARE(void) t31_set_t38_config(t31_state_t *s, bool without_pacing); /*! Set audio or T.38 mode. \brief Set audio or T.38 mode. \param s The T.31 modem context. - \param t38_mode TRUE for T.38 mode operation. FALSE for audio mode operation. + \param t38_mode True for T.38 mode operation. False for audio mode operation. */ -SPAN_DECLARE(void) t31_set_mode(t31_state_t *s, int t38_mode); +SPAN_DECLARE(void) t31_set_mode(t31_state_t *s, bool t38_mode); /*! Get a pointer to the logging context associated with a T.31 context. \brief Get a pointer to the logging context associated with a T.31 context. diff --git a/libs/spandsp/src/spandsp/t35.h b/libs/spandsp/src/spandsp/t35.h index efd644b390..fdef41fdf2 100644 --- a/libs/spandsp/src/spandsp/t35.h +++ b/libs/spandsp/src/spandsp/t35.h @@ -83,9 +83,9 @@ SPAN_DECLARE(const char *) t35_vendor_to_str(const uint8_t *msg, int len); \param model A pointer which will be pointed to the identified model. If a NULL pointer is given, the model will not be returned. If the model is not identified, NULL will be returned. - \return TRUE if the machine was identified, otherwise FALSE. + \return True if the machine was identified. */ -SPAN_DECLARE(int) t35_decode(const uint8_t *msg, int len, const char **country, const char **vendor, const char **model); +SPAN_DECLARE(bool) t35_decode(const uint8_t *msg, int len, const char **country, const char **vendor, const char **model); #if defined(__cplusplus) } diff --git a/libs/spandsp/src/spandsp/t38_core.h b/libs/spandsp/src/spandsp/t38_core.h index 662cf8d37e..86e45089ac 100644 --- a/libs/spandsp/src/spandsp/t38_core.h +++ b/libs/spandsp/src/spandsp/t38_core.h @@ -312,21 +312,21 @@ SPAN_DECLARE(void) t38_set_data_transport_protocol(t38_core_state_t *s, int data /*! Set the non-ECM fill bit removal mode. \param s The T.38 context. - \param fill_bit_removal TRUE to remove fill bits across the T.38 link, else FALSE. + \param fill_bit_removal True to remove fill bits across the T.38 link. */ -SPAN_DECLARE(void) t38_set_fill_bit_removal(t38_core_state_t *s, int fill_bit_removal); +SPAN_DECLARE(void) t38_set_fill_bit_removal(t38_core_state_t *s, bool fill_bit_removal); /*! Set the MMR transcoding mode. \param s The T.38 context. - \param mmr_transcoding TRUE to transcode to MMR across the T.38 link, else FALSE. + \param mmr_transcoding True to transcode to MMR across the T.38 link. */ -SPAN_DECLARE(void) t38_set_mmr_transcoding(t38_core_state_t *s, int mmr_transcoding); +SPAN_DECLARE(void) t38_set_mmr_transcoding(t38_core_state_t *s, bool mmr_transcoding); /*! Set the JBIG transcoding mode. \param s The T.38 context. - \param jbig_transcoding TRUE to transcode to JBIG across the T.38 link, else FALSE. + \param jbig_transcoding True to transcode to JBIG across the T.38 link. */ -SPAN_DECLARE(void) t38_set_jbig_transcoding(t38_core_state_t *s, int jbig_transcoding); +SPAN_DECLARE(void) t38_set_jbig_transcoding(t38_core_state_t *s, bool jbig_transcoding); /*! Set the maximum buffer size for received data at the far end. \param s The T.38 context. @@ -363,16 +363,16 @@ SPAN_DECLARE(void) t38_set_t38_version(t38_core_state_t *s, int t38_version); /*! Set the sequence number handling option. \param s The T.38 context. - \param check TRUE to check sequence numbers, and handle gaps reasonably. FALSE + \param check True to check sequence numbers, and handle gaps reasonably. False for no sequence number processing (e.g. for TPKT over TCP transport). */ -SPAN_DECLARE(void) t38_set_sequence_number_handling(t38_core_state_t *s, int check); +SPAN_DECLARE(void) t38_set_sequence_number_handling(t38_core_state_t *s, bool check); /*! Set the TEP handling option. \param s The T.38 context. - \param allow_for_tep TRUE to allow for TEP playout, else FALSE. + \param allow_for_tep True to allow for TEP playout. */ -SPAN_DECLARE(void) t38_set_tep_handling(t38_core_state_t *s, int allow_for_tep); +SPAN_DECLARE(void) t38_set_tep_handling(t38_core_state_t *s, bool allow_for_tep); /*! Get a pointer to the logging context associated with a T.38 context. \brief Get a pointer to the logging context associated with a T.38 context. diff --git a/libs/spandsp/src/spandsp/t38_gateway.h b/libs/spandsp/src/spandsp/t38_gateway.h index 4971e8d4bf..89bd9b116d 100644 --- a/libs/spandsp/src/spandsp/t38_gateway.h +++ b/libs/spandsp/src/spandsp/t38_gateway.h @@ -45,13 +45,13 @@ typedef struct t38_gateway_state_s t38_gateway_state_t; \brief T.30 real time frame handler. \param s The T.30 context. \param user_data An opaque pointer. - \param direction TRUE for incoming, FALSE for outgoing. + \param incoming True for incoming, false for outgoing. \param msg The HDLC message. \param len The length of the message. */ typedef void (*t38_gateway_real_time_frame_handler_t)(t38_gateway_state_t *s, void *user_data, - int direction, + bool incoming, const uint8_t *msg, int len); @@ -62,8 +62,8 @@ typedef struct { /*! \brief The current bit rate for image transfer. */ int bit_rate; - /*! \brief TRUE if error correcting mode is used. */ - int error_correcting_mode; + /*! \brief True if error correcting mode is used. */ + bool error_correcting_mode; /*! \brief The number of pages transferred so far. */ int pages_transferred; } t38_stats_t; @@ -124,18 +124,18 @@ SPAN_DECLARE_NONSTD(int) t38_gateway_tx(t38_gateway_state_t *s, int16_t amp[], i /*! Control whether error correcting mode (ECM) is allowed. \brief Control whether error correcting mode (ECM) is allowed. \param s The T.38 context. - \param ecm_allowed TRUE is ECM is to be allowed. + \param ecm_allowed True is ECM is to be allowed. */ -SPAN_DECLARE(void) t38_gateway_set_ecm_capability(t38_gateway_state_t *s, int ecm_allowed); +SPAN_DECLARE(void) t38_gateway_set_ecm_capability(t38_gateway_state_t *s, bool ecm_allowed); /*! Select whether silent audio will be sent when transmit is idle. \brief Select whether silent audio will be sent when transmit is idle. \param s The T.38 context. - \param transmit_on_idle TRUE if silent audio should be output when the FAX transmitter is - idle. FALSE to transmit zero length audio when the FAX transmitter is idle. The default - behaviour is FALSE. + \param transmit_on_idle True if silent audio should be output when the FAX transmitter is + idle. False to transmit zero length audio when the FAX transmitter is idle. The default + behaviour is false. */ -SPAN_DECLARE(void) t38_gateway_set_transmit_on_idle(t38_gateway_state_t *s, int transmit_on_idle); +SPAN_DECLARE(void) t38_gateway_set_transmit_on_idle(t38_gateway_state_t *s, bool transmit_on_idle); /*! Specify which modem types are supported by a T.30 context. \brief Specify supported modems. @@ -165,16 +165,16 @@ SPAN_DECLARE(void) t38_gateway_set_nsx_suppression(t38_gateway_state_t *s, /*! Select whether talker echo protection tone will be sent for the image modems. \brief Select whether TEP will be sent for the image modems. \param s The T.38 context. - \param use_tep TRUE if TEP should be sent. + \param use_tep True if TEP should be sent. */ -SPAN_DECLARE(void) t38_gateway_set_tep_mode(t38_gateway_state_t *s, int use_tep); +SPAN_DECLARE(void) t38_gateway_set_tep_mode(t38_gateway_state_t *s, bool use_tep); /*! Select whether non-ECM fill bits are to be removed during transmission. \brief Select whether non-ECM fill bits are to be removed during transmission. \param s The T.38 context. - \param remove TRUE if fill bits are to be removed. + \param remove True if fill bits are to be removed. */ -SPAN_DECLARE(void) t38_gateway_set_fill_bit_removal(t38_gateway_state_t *s, int remove); +SPAN_DECLARE(void) t38_gateway_set_fill_bit_removal(t38_gateway_state_t *s, bool remove); /*! Get the current transfer statistics for the current T.38 session. \brief Get the current transfer statistics. diff --git a/libs/spandsp/src/spandsp/t38_non_ecm_buffer.h b/libs/spandsp/src/spandsp/t38_non_ecm_buffer.h index 0b1bee6af6..3ca28c3d12 100644 --- a/libs/spandsp/src/spandsp/t38_non_ecm_buffer.h +++ b/libs/spandsp/src/spandsp/t38_non_ecm_buffer.h @@ -83,10 +83,10 @@ extern "C" /*! \brief Initialise a T.38 rate adapting non-ECM buffer context. \param s The buffer context. - \param mode TRUE for image data mode, or FALSE for TCF mode. + \param image_mode True for image data mode, or false for TCF mode. \param bits The minimum number of bits per FAX image row. \return A pointer to the buffer context, or NULL if there was a problem. */ -SPAN_DECLARE(t38_non_ecm_buffer_state_t *) t38_non_ecm_buffer_init(t38_non_ecm_buffer_state_t *s, int mode, int min_row_bits); +SPAN_DECLARE(t38_non_ecm_buffer_state_t *) t38_non_ecm_buffer_init(t38_non_ecm_buffer_state_t *s, bool image_mode, int min_row_bits); SPAN_DECLARE(int) t38_non_ecm_buffer_release(t38_non_ecm_buffer_state_t *s); @@ -94,9 +94,9 @@ SPAN_DECLARE(int) t38_non_ecm_buffer_free(t38_non_ecm_buffer_state_t *s); /*! \brief Set the mode of a T.38 rate adapting non-ECM buffer context. \param s The buffer context. - \param mode TRUE for image data mode, or FALSE for TCF mode. + \param mode True for image data mode, or false for TCF mode. \param bits The minimum number of bits per FAX image row. */ -SPAN_DECLARE(void) t38_non_ecm_buffer_set_mode(t38_non_ecm_buffer_state_t *s, int mode, int min_row_bits); +SPAN_DECLARE(void) t38_non_ecm_buffer_set_mode(t38_non_ecm_buffer_state_t *s, bool image_mode, int min_row_bits); /*! \brief Inject data to T.38 rate adapting non-ECM buffer context. \param s The buffer context. diff --git a/libs/spandsp/src/spandsp/t38_terminal.h b/libs/spandsp/src/spandsp/t38_terminal.h index dbf0dca9cb..630fbb80bc 100644 --- a/libs/spandsp/src/spandsp/t38_terminal.h +++ b/libs/spandsp/src/spandsp/t38_terminal.h @@ -72,16 +72,16 @@ SPAN_DECLARE(void) t38_terminal_set_config(t38_terminal_state_t *s, int config); /*! Select whether the time for talker echo protection tone will be allowed for when sending. \brief Select whether TEP time will be allowed for. \param s The T.38 context. - \param use_tep TRUE if TEP should be allowed for. + \param use_tep True if TEP should be allowed for. */ -SPAN_DECLARE(void) t38_terminal_set_tep_mode(t38_terminal_state_t *s, int use_tep); +SPAN_DECLARE(void) t38_terminal_set_tep_mode(t38_terminal_state_t *s, bool use_tep); /*! Select whether non-ECM fill bits are to be removed during transmission. \brief Select whether non-ECM fill bits are to be removed during transmission. \param s The T.38 context. - \param remove TRUE if fill bits are to be removed. + \param remove True if fill bits are to be removed. */ -SPAN_DECLARE(void) t38_terminal_set_fill_bit_removal(t38_terminal_state_t *s, int remove); +SPAN_DECLARE(void) t38_terminal_set_fill_bit_removal(t38_terminal_state_t *s, bool remove); /*! Get a pointer to the T.30 engine associated with a termination mode T.38 context. \brief Get a pointer to the T.30 engine associated with a T.38 context. @@ -108,21 +108,21 @@ SPAN_DECLARE(logging_state_t *) t38_terminal_get_logging_state(t38_terminal_stat /*! \brief Reinitialise a termination mode T.38 context. \param s The T.38 context. - \param calling_party TRUE if the context is for a calling party. FALSE if the + \param calling_party True if the context is for a calling party. False if the context is for an answering party. \return 0 for OK, else -1. */ SPAN_DECLARE(int) t38_terminal_restart(t38_terminal_state_t *s, - int calling_party); + bool calling_party); /*! \brief Initialise a termination mode T.38 context. \param s The T.38 context. - \param calling_party TRUE if the context is for a calling party. FALSE if the + \param calling_party True if the context is for a calling party. False if the context is for an answering party. \param tx_packet_handler A callback routine to encapsulate and transmit T.38 packets. \param tx_packet_user_data An opaque pointer passed to the tx_packet_handler routine. \return A pointer to the termination mode T.38 context, or NULL if there was a problem. */ SPAN_DECLARE(t38_terminal_state_t *) t38_terminal_init(t38_terminal_state_t *s, - int calling_party, + bool calling_party, t38_tx_packet_handler_t tx_packet_handler, void *tx_packet_user_data); diff --git a/libs/spandsp/src/spandsp/t42.h b/libs/spandsp/src/spandsp/t42.h index b864b17536..26c4b8e299 100644 --- a/libs/spandsp/src/spandsp/t42.h +++ b/libs/spandsp/src/spandsp/t42.h @@ -48,8 +48,24 @@ extern "C" { #endif +/*! \brief Convert an X0, Y0, Z0 coordinate to a colour tempature */ +SPAN_DECLARE(int) xyz_to_corrected_color_temp(float *temp, float xyz[3]); + +/*! \brief Convert a colour temperature to an X0, Y0, Z0 coordinate */ +SPAN_DECLARE(int) colour_temp_to_xyz(float xyz[3], float temp); + +/*! \brief Convert a row of 8 bit pixels from Lab to sRGB + \param s The Lab parameters context. + \param lab The output pixels + \param srgb The input pixels + \param pixel The number of pixels in the row. */ SPAN_DECLARE(void) srgb_to_lab(lab_params_t *s, uint8_t lab[], const uint8_t srgb[], int pixels); +/*! \brief Convert a row of 8 bit pixels from sRGB to Lab + \param s The Lab parameters context. + \param srgb The output pixels + \param lab The input pixels + \param pixel The number of pixels in the row. */ SPAN_DECLARE(void) lab_to_srgb(lab_params_t *s, uint8_t srgb[], const uint8_t lab[], int pixels); SPAN_DECLARE(void) set_lab_illuminant(lab_params_t *s, float new_xn, float new_yn, float new_zn); @@ -58,25 +74,18 @@ SPAN_DECLARE(void) set_lab_gamut(lab_params_t *s, int L_min, int L_max, int a_mi SPAN_DECLARE(void) set_lab_gamut2(lab_params_t *s, int L_P, int L_Q, int a_P, int a_Q, int b_P, int b_Q); -SPAN_DECLARE(int) t42_itulab_to_itulab(logging_state_t *logging, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t width, uint32_t height); +SPAN_DECLARE(void) get_lab_gamut2(lab_params_t *s, int *L_P, int *L_Q, int *a_P, int *a_Q, int *b_P, int *b_Q); -SPAN_DECLARE(int) t42_itulab_to_jpeg(logging_state_t *logging, lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen); +SPAN_DECLARE(bool) t42_analyse_header(uint32_t *width, uint32_t *length, const uint8_t data[], size_t len); -SPAN_DECLARE(int) t42_jpeg_to_itulab(logging_state_t *logging, lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen); - -SPAN_DECLARE(int) t42_srgb_to_itulab(logging_state_t *logging, lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t width, uint32_t height); - -SPAN_DECLARE(int) t42_itulab_to_srgb(logging_state_t *logging, lab_params_t *s, tdata_t dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t *width, uint32_t *height); - -SPAN_DECLARE(void) t42_encode_set_options(t42_encode_state_t *s, - uint32_t l0, - int mx, - int options); +SPAN_DECLARE(void) t42_encode_set_options(t42_encode_state_t *s, uint32_t l0, int quality, int options); SPAN_DECLARE(int) t42_encode_set_image_width(t42_encode_state_t *s, uint32_t image_width); SPAN_DECLARE(int) t42_encode_set_image_length(t42_encode_state_t *s, uint32_t length); +SPAN_DECLARE(int) t42_encode_set_image_type(t42_encode_state_t *s, int image_type); + SPAN_DECLARE(void) t42_encode_abort(t42_encode_state_t *s); SPAN_DECLARE(void) t42_encode_comment(t42_encode_state_t *s, const uint8_t comment[], size_t len); @@ -92,11 +101,12 @@ SPAN_DECLARE(uint32_t) t42_encode_get_image_width(t42_encode_state_t *s); SPAN_DECLARE(uint32_t) t42_encode_get_image_length(t42_encode_state_t *s); +/*! \brief Get the size of the compressed image in bits. + \param s The T.42 context. + \return The size of the image, in bits. */ SPAN_DECLARE(int) t42_encode_get_compressed_image_size(t42_encode_state_t *s); -SPAN_DECLARE(int) t42_encode_set_row_read_handler(t42_encode_state_t *s, - t4_row_read_handler_t handler, - void *user_data); +SPAN_DECLARE(int) t42_encode_set_row_read_handler(t42_encode_state_t *s, t4_row_read_handler_t handler, void *user_data); /*! Get the logging context associated with a T.42 encode context. \brief Get the logging context associated with a T.42 encode context. @@ -163,6 +173,14 @@ SPAN_DECLARE(int) t42_decode_set_comment_handler(t42_decode_state_t *s, t4_row_write_handler_t handler, void *user_data); +/*! A maliciously constructed T.42 image could consume too much memory, and constitute + a denial of service attack on the system. This function allows constraints to be + applied. + \brief Set constraints on the received image size. + \param s The T.42 context. + \param max_xd The maximum permitted width of the full image, in pixels + \param max_yd The maximum permitted height of the full image, in pixels + \return 0 for OK */ SPAN_DECLARE(int) t42_decode_set_image_size_constraints(t42_decode_state_t *s, uint32_t max_xd, uint32_t max_yd); @@ -177,6 +195,9 @@ SPAN_DECLARE(uint32_t) t42_decode_get_image_width(t42_decode_state_t *s); \return The length of the image, in pixels. */ SPAN_DECLARE(uint32_t) t42_decode_get_image_length(t42_decode_state_t *s); +/*! \brief Get the size of the compressed image in bits. + \param s The T.42 context. + \return The size of the image, in bits. */ SPAN_DECLARE(int) t42_decode_get_compressed_image_size(t42_decode_state_t *s); /*! Get the logging context associated with a T.42 decode context. @@ -185,6 +206,8 @@ SPAN_DECLARE(int) t42_decode_get_compressed_image_size(t42_decode_state_t *s); \return A pointer to the logging context */ SPAN_DECLARE(logging_state_t *) t42_decode_get_logging_state(t42_decode_state_t *s); +/*! \brief Restart a T.42 decode context. + \param s The T.42 context. */ SPAN_DECLARE(int) t42_decode_restart(t42_decode_state_t *s); /*! \brief Prepare to decode an image in T.42 format. diff --git a/libs/spandsp/src/spandsp/t43.h b/libs/spandsp/src/spandsp/t43.h new file mode 100644 index 0000000000..ecc0f2a224 --- /dev/null +++ b/libs/spandsp/src/spandsp/t43.h @@ -0,0 +1,207 @@ +/* + * 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 + * + * 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; + +enum +{ + T43_IMAGE_TYPE_RGB_BILEVEL = 0, + T43_IMAGE_TYPE_CMY_BILEVEL = 1, + T43_IMAGE_TYPE_CMYK_BILEVEL = 2, + T43_IMAGE_TYPE_8BIT_COLOUR_PALETTE = 16, + T43_IMAGE_TYPE_12BIT_COLOUR_PALETTE = 17, + T43_IMAGE_TYPE_GRAY = 32, + T43_IMAGE_TYPE_COLOUR = 48 +}; + +#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(int) t43_encode_set_image_type(t43_encode_state_t *s, int image_type); + +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(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 ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/spandsp/t4_rx.h b/libs/spandsp/src/spandsp/t4_rx.h index 3b359c7d79..de6698517e 100644 --- a/libs/spandsp/src/spandsp/t4_rx.h +++ b/libs/spandsp/src/spandsp/t4_rx.h @@ -49,47 +49,85 @@ typedef int (*t4_row_write_handler_t)(void *user_data, const uint8_t buf[], size typedef enum { /*! No compression */ - T4_COMPRESSION_NONE = 0, - /*! T.1 1D compression */ - T4_COMPRESSION_ITU_T4_1D = 1, + T4_COMPRESSION_NONE = 0x01, + /*! T.4 1D compression */ + T4_COMPRESSION_T4_1D = 0x02, /*! T.4 2D compression */ - T4_COMPRESSION_ITU_T4_2D = 2, + T4_COMPRESSION_T4_2D = 0x04, /*! T.6 2D compression */ - T4_COMPRESSION_ITU_T6 = 3, + T4_COMPRESSION_T6 = 0x08, /*! T.85 monochrome JBIG coding with L0 fixed. */ - T4_COMPRESSION_ITU_T85 = 4, + T4_COMPRESSION_T85 = 0x10, /*! T.85 monochrome JBIG coding with L0 variable. */ - T4_COMPRESSION_ITU_T85_L0 = 5, - /*! T.43 colour JBIG coding */ - T4_COMPRESSION_ITU_T43 = 6, + T4_COMPRESSION_T85_L0 = 0x20, + /*! T.43 gray-scale/colour JBIG coding */ + T4_COMPRESSION_T43 = 0x40, /*! T.45 run length colour compression */ - T4_COMPRESSION_ITU_T45 = 7, + T4_COMPRESSION_T45 = 0x80, /*! T.42 + T.81 + T.30 Annex E colour JPEG coding */ - T4_COMPRESSION_ITU_T42 = 8, + T4_COMPRESSION_T42_T81 = 0x100, /*! T.42 + T.81 + T.30 Annex K colour sYCC-JPEG coding */ - T4_COMPRESSION_ITU_SYCC_T42 = 9 + T4_COMPRESSION_SYCC_T81 = 0x200, + /*! T.88 monochrome JBIG2 compression */ + T4_COMPRESSION_T88 = 0x400, + /*! Uncompressed image. This compression cannot be used for FAXes. It is provided for specifying + output formats for received images. */ + T4_COMPRESSION_UNCOMPRESSED = 0x1000, + /*! Conventional JPEG. This compression cannot be used for FAXes. It is provided for specifying + output formats for received images. */ + T4_COMPRESSION_JPEG = 0x2000, + /*! Support solour compression without sub-sampling */ + T4_COMPRESSION_NO_SUBSAMPLING = 0x800000, + /*! Gray-scale support by multi-level codecs */ + T4_COMPRESSION_GRAYSCALE = 0x1000000, + /*! Colour support by multi-level codecs */ + T4_COMPRESSION_COLOUR = 0x2000000, + /*! 12 bit mode for gray-scale and colour */ + T4_COMPRESSION_12BIT = 0x4000000, + /*! Convert a colour image to a gray-scale one */ + T4_COMPRESSION_COLOUR_TO_GRAY = 0x8000000, + /*! Dither a gray-scale image down a simple bilevel image, with rescaling to fit a FAX page */ + T4_COMPRESSION_GRAY_TO_BILEVEL = 0x10000000, + /*! Dither a colour image down a simple bilevel image, with rescaling to fit a FAX page */ + T4_COMPRESSION_COLOUR_TO_BILEVEL = 0x20000000, + /*! Rescale an image (except a bi-level image) to fit a permitted FAX width when necessary */ + T4_COMPRESSION_RESCALING = 0x40000000 } t4_image_compression_t; /*! Image type */ typedef enum { + /* Traditional black and white FAX */ T4_IMAGE_TYPE_BILEVEL = 0, + /* RGB or CMY image */ T4_IMAGE_TYPE_COLOUR_BILEVEL = 1, - T4_IMAGE_TYPE_GRAY_8BIT = 2, - T4_IMAGE_TYPE_GRAY_12BIT = 3, - T4_IMAGE_TYPE_COLOUR_8BIT = 4, - T4_IMAGE_TYPE_COLOUR_12BIT = 5 + /* CMYK image */ + T4_IMAGE_TYPE_4COLOUR_BILEVEL = 2, + /* 2 to 8 bits per pixel gray-scale image */ + T4_IMAGE_TYPE_GRAY_8BIT = 3, + /* 9 to 12 bits per pixel gray-scale image */ + T4_IMAGE_TYPE_GRAY_12BIT = 4, + /* 2 to 8 bits per pixel RGB or CMY colour image */ + T4_IMAGE_TYPE_COLOUR_8BIT = 5, + /* 2 to 8 bits per pixel CMYK colour image */ + T4_IMAGE_TYPE_4COLOUR_8BIT = 6, + /* 9 to 12 bits per pixel RGB or CMY colour image */ + T4_IMAGE_TYPE_COLOUR_12BIT = 7, + /* 9 to 12 bits per pixel CMYK colour image */ + T4_IMAGE_TYPE_4COLOUR_12BIT = 8 } t4_image_types_t; /*! Supported X resolutions, in pixels per metre. */ typedef enum { - T4_X_RESOLUTION_R4 = 4016, - T4_X_RESOLUTION_R8 = 8031, + T4_X_RESOLUTION_100 = 3937, + T4_X_RESOLUTION_R4 = 4020, + T4_X_RESOLUTION_200 = 7874, + T4_X_RESOLUTION_R8 = 8040, T4_X_RESOLUTION_300 = 11811, - T4_X_RESOLUTION_R16 = 16063, + T4_X_RESOLUTION_400 = 15748, + T4_X_RESOLUTION_R16 = 16080, T4_X_RESOLUTION_600 = 23622, - T4_X_RESOLUTION_800 = 31496, T4_X_RESOLUTION_1200 = 47244 } t4_image_x_resolution_t; @@ -97,14 +135,54 @@ typedef enum typedef enum { T4_Y_RESOLUTION_STANDARD = 3850, + T4_Y_RESOLUTION_100 = 3937, T4_Y_RESOLUTION_FINE = 7700, + T4_Y_RESOLUTION_200 = 7874, T4_Y_RESOLUTION_300 = 11811, - T4_Y_RESOLUTION_SUPERFINE = 15400, /* 400 is 15748 */ + T4_Y_RESOLUTION_SUPERFINE = 15400, + T4_Y_RESOLUTION_400 = 15748, T4_Y_RESOLUTION_600 = 23622, T4_Y_RESOLUTION_800 = 31496, T4_Y_RESOLUTION_1200 = 47244 } t4_image_y_resolution_t; +/* Only the symmetric resolutions are valid for gray-scale and colour use. The asymmetric + ones are bi-level only. */ +enum +{ + /*! Standard FAX resolution 204dpi x 98dpi - bi-level only */ + T4_RESOLUTION_R8_STANDARD = 0x1, + /*! Fine FAX resolution 204dpi x 196dpi - bi-level only */ + T4_RESOLUTION_R8_FINE = 0x2, + /*! Super-fine FAX resolution 204dpi x 391dpi - bi-level only */ + T4_RESOLUTION_R8_SUPERFINE = 0x4, + /*! Double FAX resolution 408dpi x 391dpi - bi-level only */ + T4_RESOLUTION_R16_SUPERFINE = 0x8, + + /*! 100dpi x 100dpi - gray-scale and colour only */ + T4_RESOLUTION_100_100 = 0x10, + /*! 200dpi x 100dpi - bi-level only */ + T4_RESOLUTION_200_100 = 0x20, + /*! 200dpi x 200dpi */ + T4_RESOLUTION_200_200 = 0x40, + /*! 200dpi x 400dpi - bi-level only */ + T4_RESOLUTION_200_400 = 0x80, + /*! 300dpi x 300dpi */ + T4_RESOLUTION_300_300 = 0x100, + /*! 300dpi x 600dpi - bi-level only */ + T4_RESOLUTION_300_600 = 0x200, + /*! 400dpi x 400dpi */ + T4_RESOLUTION_400_400 = 0x400, + /*! 400dpi x 800dpi - bi-level only */ + T4_RESOLUTION_400_800 = 0x800, + /*! 600dpi x 600dpi */ + T4_RESOLUTION_600_600 = 0x1000, + /*! 600dpi x 1200dpi - bi-level only */ + T4_RESOLUTION_600_1200 = 0x2000, + /*! 1200dpi x 1200dpi */ + T4_RESOLUTION_1200_1200 = 0x4000 +}; + /*! Exact widths in PELs for the difference resolutions, and page widths. Note: @@ -112,30 +190,53 @@ typedef enum The R4 resolution widths are not supported in recent versions of T.30 Only images of exactly these widths are acceptable for FAX transmisson. - R4 864 pels/215mm for ISO A4, North American Letter and Legal - R4 1024 pels/255mm for ISO B4 - R4 1216 pels/303mm for ISO A3 - R8 1728 pels/215mm for ISO A4, North American Letter and Legal - R8 2048 pels/255mm for ISO B4 - R8 2432 pels/303mm for ISO A3 - R16 3456 pels/215mm for ISO A4, North American Letter and Legal - R16 4096 pels/255mm for ISO B4 - R16 4864 pels/303mm for ISO A3 + R4 864 pels/215mm for ISO A4, North American Letter and Legal + R4 1024 pels/255mm for ISO B4 + R4 1216 pels/303mm for ISO A3 + R8 1728 pels/215mm for ISO A4, North American Letter and Legal + R8 2048 pels/255mm for ISO B4 + R8 2432 pels/303mm for ISO A3 + R16 3456 pels/215mm for ISO A4, North American Letter and Legal + R16 4096 pels/255mm for ISO B4 + R16 4864 pels/303mm for ISO A3 + + 100 864 pels/219.46mm for ISO A4, North American Letter and Legal + 100 1024 pels/260.10mm for ISO B4 + 100 1216 pels/308.86mm for ISO A3 + 200 1728 pels/219.46mm for ISO A4, North American Letter and Legal + 200 2048 pels/260.10mm for ISO B4 + 200 2432 pels/308.86mm for ISO A3 + 300 2592 pels/219.46mm for ISO A4, North American Letter and Legal + 300 3072 pels/260.10mm for ISO B4 + 300 3648 pels/308.86mm for ISO A3 + 400 3456 pels/219.46mm for ISO A4, North American Letter and Legal + 400 4096 pels/260.10mm for ISO B4 + 400 4864 pels/308.86mm for ISO A3 + 600 5184 pels/219.46mm for ISO A4, North American Letter and Legal + 600 6144 pels/260.10mm for ISO B4 + 600 7296 pels/308.86mm for ISO A3 + 1200 10368 pels/219.46mm for ISO A4, North American Letter and Legal + 1200 12288 pels/260.10mm for ISO B4 + 1200 14592 pels/308.86mm for ISO A3 + + Note that R4, R8 and R16 widths are 5mm wider than the actual paper sizes. + The 100, 200, 300, 400, 600, and 1200 widths are 9.46mm, 10.1mm and 11.86mm + wider than the paper sizes. */ typedef enum { - T4_WIDTH_R4_A4 = 864, - T4_WIDTH_R4_B4 = 1024, - T4_WIDTH_R4_A3 = 1216, - T4_WIDTH_R8_A4 = 1728, - T4_WIDTH_R8_B4 = 2048, - T4_WIDTH_R8_A3 = 2432, + T4_WIDTH_100_A4 = 864, + T4_WIDTH_100_B4 = 1024, + T4_WIDTH_100_A3 = 1216, + T4_WIDTH_200_A4 = 1728, + T4_WIDTH_200_B4 = 2048, + T4_WIDTH_200_A3 = 2432, T4_WIDTH_300_A4 = 2592, T4_WIDTH_300_B4 = 3072, T4_WIDTH_300_A3 = 3648, - T4_WIDTH_R16_A4 = 3456, - T4_WIDTH_R16_B4 = 4096, - T4_WIDTH_R16_A3 = 4864, + T4_WIDTH_400_A4 = 3456, + T4_WIDTH_400_B4 = 4096, + T4_WIDTH_400_A3 = 4864, T4_WIDTH_600_A4 = 5184, T4_WIDTH_600_B4 = 6144, T4_WIDTH_600_A3 = 7296, @@ -144,14 +245,26 @@ typedef enum T4_WIDTH_1200_A3 = 14592 } t4_image_width_t; +#define T4_WIDTH_R4_A4 T4_WIDTH_100_A4 +#define T4_WIDTH_R4_B4 T4_WIDTH_100_B4 +#define T4_WIDTH_R4_A3 T4_WIDTH_100_A3 + +#define T4_WIDTH_R8_A4 T4_WIDTH_200_A4 +#define T4_WIDTH_R8_B4 T4_WIDTH_200_B4 +#define T4_WIDTH_R8_A3 T4_WIDTH_200_A3 + +#define T4_WIDTH_R16_A4 T4_WIDTH_400_A4 +#define T4_WIDTH_R16_B4 T4_WIDTH_400_B4 +#define T4_WIDTH_R16_A3 T4_WIDTH_400_A3 + /*! Length of the various supported paper sizes, in pixels at the various Y resolutions. Paper sizes are - A4 (215mm x 297mm) - B4 (255mm x 364mm) - A3 (303mm x 418.56mm) - North American Letter (215.9mm x 279.4mm) - North American Legal (215.9mm x 355.6mm) + A4 (210mm x 297mm) + B4 (250mm x 353mm) + A3 (297mm x 420mm) + North American Letter (215.9mm x 279.4mm or 8.5"x11") + North American Legal (215.9mm x 355.6mm or 8.4"x14") Unlimited T.4 does not accurately define the maximum number of scan lines in a page. A wide @@ -162,7 +275,7 @@ typedef enum Values seen for standard resolution A4 pages include 1037, 1045, 1109, 1126 and 1143. 1109 seems the most-popular. At fine res 2150, 2196, 2200, 2237, 2252-2262, 2264, 2286, and 2394 are used. 2255 seems the most popular. We try to use balanced choices - here. + here. 1143 pixels at 3.85/mm is 296.9mm, and an A4 page is 297mm long. */ typedef enum { @@ -174,32 +287,53 @@ typedef enum T4_LENGTH_600_A4 = 6998, T4_LENGTH_800_A4 = 9330, T4_LENGTH_1200_A4 = 13996, - /* B4 is 364mm long */ - T4_LENGTH_STANDARD_B4 = 1401, - T4_LENGTH_FINE_B4 = 2802, - T4_LENGTH_300_B4 = 0, - T4_LENGTH_SUPERFINE_B4 = 5605, - T4_LENGTH_600_B4 = 0, - T4_LENGTH_800_B4 = 0, - T4_LENGTH_1200_B4 = 0, + /* B4 is 353mm long */ + T4_LENGTH_STANDARD_B4 = 1359, + T4_LENGTH_FINE_B4 = 2718, + T4_LENGTH_300_B4 = 4169, + T4_LENGTH_SUPERFINE_B4 = 5436, + T4_LENGTH_600_B4 = 8338, + T4_LENGTH_800_B4 = 11118, + T4_LENGTH_1200_B4 = 16677, + /* A3 is 420mm long */ + T4_LENGTH_STANDARD_A3 = 1617, + T4_LENGTH_FINE_A3 = 3234, + T4_LENGTH_300_A3 = 4960, + T4_LENGTH_SUPERFINE_A3 = 6468, + T4_LENGTH_600_A3 = 9921, + T4_LENGTH_800_A3 = 13228, + T4_LENGTH_1200_A3 = 19842, /* North American letter is 279.4mm long */ T4_LENGTH_STANDARD_US_LETTER = 1075, T4_LENGTH_FINE_US_LETTER = 2151, - T4_LENGTH_300_US_LETTER = 0, + T4_LENGTH_300_US_LETTER = 3300, T4_LENGTH_SUPERFINE_US_LETTER = 4302, - T4_LENGTH_600_US_LETTER = 0, - T4_LENGTH_800_US_LETTER = 0, - T4_LENGTH_1200_US_LETTER = 0, + T4_LENGTH_600_US_LETTER = 6700, + T4_LENGTH_800_US_LETTER = 8800, + T4_LENGTH_1200_US_LETTER = 13200, /* North American legal is 355.6mm long */ T4_LENGTH_STANDARD_US_LEGAL = 1369, T4_LENGTH_FINE_US_LEGAL = 2738, - T4_LENGTH_300_US_LEGAL = 0, + T4_LENGTH_300_US_LEGAL = 4200, T4_LENGTH_SUPERFINE_US_LEGAL = 5476, - T4_LENGTH_600_US_LEGAL = 0, - T4_LENGTH_800_US_LEGAL = 0, - T4_LENGTH_1200_US_LEGAL = 0 + T4_LENGTH_600_US_LEGAL = 8400, + T4_LENGTH_800_US_LEGAL = 11200, + T4_LENGTH_1200_US_LEGAL = 16800 } t4_image_length_t; +enum +{ + T4_SUPPORT_WIDTH_215MM = 0x01, + T4_SUPPORT_WIDTH_255MM = 0x02, + T4_SUPPORT_WIDTH_303MM = 0x04, + + T4_SUPPORT_LENGTH_UNLIMITED = 0x10000, + T4_SUPPORT_LENGTH_A4 = 0x20000, + T4_SUPPORT_LENGTH_B4 = 0x40000, + T4_SUPPORT_LENGTH_US_LETTER = 0x80000, + T4_SUPPORT_LENGTH_US_LEGAL = 0x100000 +}; + /*! Return values from the T.85 decoder */ typedef enum { @@ -257,7 +391,7 @@ typedef struct /*! \brief The number of vertical pixels in the exchanged page. */ int length; /*! \brief The type of compression used between the FAX machines */ - int encoding; + int compression; /*! \brief The size of the image on the line, in bytes */ int line_image_size; } t4_stats_t; @@ -266,19 +400,6 @@ typedef struct extern "C" { #endif -/*! Get the logging context associated with a T.4 receive context. - \brief Get the logging context associated with a T.4 receive context. - \param s The T.4 receive context. - \return A pointer to the logging context */ -SPAN_DECLARE(logging_state_t *) t4_rx_get_logging_state(t4_rx_state_t *s); - -/*! \brief Prepare for reception of a document. - \param s The T.4 context. - \param file The name of the file to be received. - \param output_encoding The output encoding. - \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); - /*! \brief Prepare to receive the next page of the current document. \param s The T.4 context. \return zero for success, -1 for failure. */ @@ -287,14 +408,14 @@ SPAN_DECLARE(int) t4_rx_start_page(t4_rx_state_t *s); /*! \brief Put a bit of the current document page. \param s The T.4 context. \param bit The data bit. - \return TRUE when the bit ends the document page, otherwise FALSE. */ + \return Decode status. */ SPAN_DECLARE(int) t4_rx_put_bit(t4_rx_state_t *s, int bit); /*! \brief Put a byte of the current document page. \param s The T.4 context. \param buf The buffer containing the chunk. \param len The length of the chunk. - \return TRUE when the byte ends the document page, otherwise FALSE. */ + \return Decode status. */ SPAN_DECLARE(int) t4_rx_put(t4_rx_state_t *s, const uint8_t buf[], size_t len); /*! \brief Complete the reception of a page. @@ -302,20 +423,6 @@ SPAN_DECLARE(int) t4_rx_put(t4_rx_state_t *s, const uint8_t buf[], size_t len); \return 0 for success, otherwise -1. */ SPAN_DECLARE(int) t4_rx_end_page(t4_rx_state_t *s); -/*! \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. - \param s The T.4 receive context. - \return 0 for success, otherwise -1. */ -SPAN_DECLARE(int) t4_rx_release(t4_rx_state_t *s); - -/*! \brief End reception of a document. Tidy up, close the file and - free the context. This should be used to end T.4 reception - started with t4_rx_init. - \param s The T.4 receive context. - \return 0 for success, otherwise -1. */ -SPAN_DECLARE(int) t4_rx_free(t4_rx_state_t *s); - /*! \brief Set the row write handler for a T.4 receive context. \param s The T.4 receive context. \param handler A pointer to the handler routine. @@ -375,18 +482,50 @@ SPAN_DECLARE(void) t4_rx_set_model(t4_rx_state_t *s, const char *model); \param t A pointer to a statistics structure. */ SPAN_DECLARE(void) t4_rx_get_transfer_statistics(t4_rx_state_t *s, t4_stats_t *t); -/*! Get the short text name of an encoding format. +/*! Get the short text name of a compression format. \brief Get the short text name of an encoding format. - \param encoding The encoding type. + \param compression The compression type. \return A pointer to the string. */ -SPAN_DECLARE(const char *) t4_encoding_to_str(int encoding); +SPAN_DECLARE(const char *) t4_compression_to_str(int compression); /*! Get the short text name of an image format. \brief Get the short text name of an image format. - \param encoding The image format. + \param type The image format. \return A pointer to the string. */ SPAN_DECLARE(const char *) t4_image_type_to_str(int type); +/*! Get the short text name of an image resolution. + \brief Get the short text name of an image resolution. + \param resolution_code The image resolution code. + \return A pointer to the string. */ +SPAN_DECLARE(const char *) t4_image_resolution_to_str(int resolution_code); + +/*! Get the logging context associated with a T.4 receive context. + \brief Get the logging context associated with a T.4 receive context. + \param s The T.4 receive context. + \return A pointer to the logging context */ +SPAN_DECLARE(logging_state_t *) t4_rx_get_logging_state(t4_rx_state_t *s); + +/*! \brief Prepare for reception of a document. + \param s The T.4 context. + \param file The name of the file to be received. + \param supported_output_compressions The compression schemes supported for output to a TIFF file. + \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 supported_output_compressions); + +/*! \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. + \param s The T.4 receive context. + \return 0 for success, otherwise -1. */ +SPAN_DECLARE(int) t4_rx_release(t4_rx_state_t *s); + +/*! \brief End reception of a document. Tidy up, close the file and + free the context. This should be used to end T.4 reception + started with t4_rx_init. + \param s The T.4 receive context. + \return 0 for success, otherwise -1. */ +SPAN_DECLARE(int) t4_rx_free(t4_rx_state_t *s); + #if defined(__cplusplus) } #endif diff --git a/libs/spandsp/src/spandsp/t4_t6_decode.h b/libs/spandsp/src/spandsp/t4_t6_decode.h index 16e2348fbc..aa50e5ee60 100644 --- a/libs/spandsp/src/spandsp/t4_t6_decode.h +++ b/libs/spandsp/src/spandsp/t4_t6_decode.h @@ -48,7 +48,7 @@ extern "C" { /*! \brief Put a bit of the current document page. \param s The T.4/T.6 context. \param bit The data bit. - \return TRUE when the bit ends the document page, otherwise FALSE. */ + \return Decode status. */ SPAN_DECLARE(int) t4_t6_decode_put_bit(t4_t6_decode_state_t *s, int bit); /*! \brief Put a byte of the current document page. diff --git a/libs/spandsp/src/spandsp/t4_t6_encode.h b/libs/spandsp/src/spandsp/t4_t6_encode.h index 7431d64f08..81c6ddb3e4 100644 --- a/libs/spandsp/src/spandsp/t4_t6_encode.h +++ b/libs/spandsp/src/spandsp/t4_t6_encode.h @@ -77,6 +77,12 @@ SPAN_DECLARE(int) t4_t6_encode_set_encoding(t4_t6_encode_state_t *s, int encodin \return 0 for success, otherwise -1. */ SPAN_DECLARE(int) t4_t6_encode_set_image_width(t4_t6_encode_state_t *s, int image_width); +/*! \brief Set the length of the image. + \param s The T.4/T.6 context. + \param image_length The image length, in pixels. + \return 0 for success, otherwise -1. */ +SPAN_DECLARE(int) t4_t6_encode_set_image_length(t4_t6_encode_state_t *s, int image_length); + /*! \brief Get the width of the image. \param s The T.4/T.6 context. \return The width of the image, in pixels. */ @@ -114,20 +120,23 @@ SPAN_DECLARE(logging_state_t *) t4_t6_encode_get_logging_state(t4_t6_encode_stat /*! \brief Restart a T.4 or T.6 encode context. \param s The T.4/T.6 context. - \param image width The image width, in pixels. + \param image_width The image width, in pixels. + \param image_length The image length, in pixels. This can be set to -1, if the length is not known. \return 0 for success, otherwise -1. */ -SPAN_DECLARE(int) t4_t6_encode_restart(t4_t6_encode_state_t *s, int image_width); +SPAN_DECLARE(int) t4_t6_encode_restart(t4_t6_encode_state_t *s, int image_width, int image_length); /*! \brief Prepare to encode an image in T.4 or T.6 format. \param s The T.4/T.6 context. \param encoding The encoding mode. - \param image width The image width, in pixels. + \param image_width The image width, in pixels. + \param image_length The image length, in pixels. This can be set to -1, if the length is not known. \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(t4_t6_encode_state_t *) t4_t6_encode_init(t4_t6_encode_state_t *s, int encoding, int image_width, + int image_length, t4_row_read_handler_t handler, void *user_data); diff --git a/libs/spandsp/src/spandsp/t4_tx.h b/libs/spandsp/src/spandsp/t4_tx.h index 8ee19be591..2e019e9dc5 100644 --- a/libs/spandsp/src/spandsp/t4_tx.h +++ b/libs/spandsp/src/spandsp/t4_tx.h @@ -175,7 +175,8 @@ ImageLayer(34732) LONG */ /* Define the TIFF/FX tags to extend libtiff, when using a version of libtiff where this - stuff has not been merged. */ + stuff has not been merged. We only need to define these things for older versions of + libtiff. */ #if defined(SPANDSP_SUPPORT_TIFF_FX) && !defined(TIFFTAG_FAXPROFILE) #define TIFFTAG_INDEXED 346 #define TIFFTAG_GLOBALPARAMETERSIFD 400 @@ -212,6 +213,14 @@ ImageLayer(34732) LONG #define COMPRESSION_T43 10 #endif +typedef enum +{ + T4_IMAGE_FORMAT_OK = 0, + T4_IMAGE_FORMAT_INCOMPATIBLE = -1, + T4_IMAGE_FORMAT_NOSIZESUPPORT = -2, + T4_IMAGE_FORMAT_NORESSUPPORT = -3 +} t4_image_format_status_t; + #if defined(__cplusplus) extern "C" { #endif @@ -221,20 +230,6 @@ extern "C" { SPAN_DECLARE(void) TIFF_FX_init(void); #endif -/*! Get the logging context associated with a T.4 transmit context. - \brief Get the logging context associated with a T.4 transmit context. - \param s The T.4 transmit context. - \return A pointer to the logging context */ -SPAN_DECLARE(logging_state_t *) t4_tx_get_logging_state(t4_tx_state_t *s); - -/*! \brief Prepare for transmission of a document. - \param s The T.4 context. - \param file The name of the file to be sent. - \param start_page The first page to send. -1 for no restriction. - \param stop_page The last page to send. -1 for no restriction. - \return A pointer to the context, or NULL if there was a problem. */ -SPAN_DECLARE(t4_tx_state_t *) t4_tx_init(t4_tx_state_t *s, const char *file, int start_page, int stop_page); - /*! \brief Prepare to send the next page of the current document. \param s The T.4 context. \return zero for success, -1 for failure. */ @@ -281,24 +276,53 @@ SPAN_DECLARE(int) t4_tx_get_bit(t4_tx_state_t *s); indicates that the end of the document has been reached. */ SPAN_DECLARE(int) t4_tx_get(t4_tx_state_t *s, uint8_t buf[], size_t max_len); -/*! \brief End the transmission of a document. Tidy up and close the file. - This should be used to end T.4 transmission started with t4_tx_init. +/*! \brief Get the compression for the encoded data. \param s The T.4 context. - \return 0 for success, otherwise -1. */ -SPAN_DECLARE(int) t4_tx_release(t4_tx_state_t *s); + \return the chosen compression for success, otherwise -1. */ +SPAN_DECLARE(int) t4_tx_get_tx_compression(t4_tx_state_t *s); -/*! \brief End the transmission of a document. Tidy up, close the file and - free the context. This should be used to end T.4 transmission - started with t4_tx_init. +/*! \brief Get the image type of the encoded data. \param s The T.4 context. - \return 0 for success, otherwise -1. */ -SPAN_DECLARE(int) t4_tx_free(t4_tx_state_t *s); + \return the chosen image type for success, otherwise -1. */ +SPAN_DECLARE(int) t4_tx_get_tx_image_type(t4_tx_state_t *s); -/*! \brief Set the encoding for the encoded data. +/*! \brief Get the X and Y resolution code of the current page. \param s The T.4 context. - \param encoding The encoding. - \return 0 for success, otherwise -1. */ -SPAN_DECLARE(int) t4_tx_set_tx_encoding(t4_tx_state_t *s, int encoding); + \return The resolution code,. */ +SPAN_DECLARE(int) t4_tx_get_tx_resolution(t4_tx_state_t *s); + +/*! \brief Get the column-to-column (x) resolution of the current page. + \param s The T.4 context. + \return The resolution, in pixels per metre. */ +SPAN_DECLARE(int) t4_tx_get_tx_x_resolution(t4_tx_state_t *s); + +/*! \brief Get the row-to-row (y) resolution of the current page. + \param s The T.4 context. + \return The resolution, in pixels per metre. */ +SPAN_DECLARE(int) t4_tx_get_tx_y_resolution(t4_tx_state_t *s); + +/*! \brief Get the width of the encoded data. + \param s The T.4 context. + \return the width, in pixels, for success, otherwise -1. */ +SPAN_DECLARE(int) t4_tx_get_tx_image_width(t4_tx_state_t *s); + +/*! \brief Get the width code of the encoded data. + \param s The T.4 context. + \return the width code, for success, otherwise -1. */ +SPAN_DECLARE(int) t4_tx_get_tx_image_width_code(t4_tx_state_t *s); + +/*! \brief Auto-select the format in which to send the image. + \param s The T.4 context. + \param supported_compressions The set of compressions supported for this transmission + \param supported_image_sizes The set of image sizes supported for this transmission + \param supported_bilevel_resolutions The set of bi-level resolutions supported for this transmission + \param supported_colour_resolutions The set of gray scale and colour resolutions supported for this transmission + \return A t4_image_format_status_t result code */ +SPAN_DECLARE(int) t4_tx_set_tx_image_format(t4_tx_state_t *s, + int supported_compressions, + int supported_image_sizes, + int supported_bilevel_resolutions, + int supported_colour_resolutions); /*! \brief Set the minimum number of encoded bits per row. This allows the makes the encoding process to be set to comply with the minimum row @@ -307,11 +331,6 @@ SPAN_DECLARE(int) t4_tx_set_tx_encoding(t4_tx_state_t *s, int encoding); \param bits The minimum number of bits per row. */ SPAN_DECLARE(void) t4_tx_set_min_bits_per_row(t4_tx_state_t *s, int bits); -/*! \brief Set the width of the image. - \param s The T.4 context. - \param image_width The image width, in pixels. */ -SPAN_DECLARE(void) t4_tx_set_image_width(t4_tx_state_t *s, int image_width); - /*! \brief Set the maximum number of 2D encoded rows between 1D encoded rows. This is only valid for T.4 2D encoding. \param s The T.4 context. @@ -342,8 +361,8 @@ SPAN_DECLARE(void) t4_tx_set_header_tz(t4_tx_state_t *s, tz_t *tz); /*! Set page header extends or overlays the image mode. \brief Set page header overlay mode. \param s The T.4 context. - \param header_overlays_image TRUE for overlay, or FALSE for extend the page. */ -SPAN_DECLARE(void) t4_tx_set_header_overlays_image(t4_tx_state_t *s, int header_overlays_image); + \param header_overlays_image True for overlay, or false to extend the page. */ +SPAN_DECLARE(void) t4_tx_set_header_overlays_image(t4_tx_state_t *s, bool header_overlays_image); /*! \brief Set the row read handler for a T.4 transmit context. \param s The T.4 transmit context. @@ -352,27 +371,6 @@ SPAN_DECLARE(void) t4_tx_set_header_overlays_image(t4_tx_state_t *s, int header_ \return 0 for success, otherwise -1. */ SPAN_DECLARE(int) t4_tx_set_row_read_handler(t4_tx_state_t *s, t4_row_read_handler_t handler, void *user_data); -/*! \brief Set the row squashing ratio, for adjusting row-to-row (y) resolution of bi-level - images for a T.4 transmit context. - \param s The T.4 transmit context. - \param row_squashing_ratio Vertical squashing ratio. */ -SPAN_DECLARE(void) t4_tx_set_row_squashing_ratio(t4_tx_state_t *s, int row_squashing_ratio); - -/*! \brief Get the row-to-row (y) resolution of the current page. - \param s The T.4 context. - \return The resolution, in pixels per metre. */ -SPAN_DECLARE(int) t4_tx_get_y_resolution(t4_tx_state_t *s); - -/*! \brief Get the column-to-column (x) resolution of the current page. - \param s The T.4 context. - \return The resolution, in pixels per metre. */ -SPAN_DECLARE(int) t4_tx_get_x_resolution(t4_tx_state_t *s); - -/*! \brief Get the width of the current page, in pixel columns. - \param s The T.4 context. - \return The number of columns. */ -SPAN_DECLARE(int) t4_tx_get_image_width(t4_tx_state_t *s); - /*! \brief Get the number of pages in the file. \param s The T.4 context. \return The number of pages, or -1 if there is an error. */ @@ -389,6 +387,33 @@ SPAN_DECLARE(int) t4_tx_get_current_page_in_file(t4_tx_state_t *s); \param t A pointer to a statistics structure. */ SPAN_DECLARE(void) t4_tx_get_transfer_statistics(t4_tx_state_t *s, t4_stats_t *t); +/*! Get the logging context associated with a T.4 transmit context. + \brief Get the logging context associated with a T.4 transmit context. + \param s The T.4 transmit context. + \return A pointer to the logging context */ +SPAN_DECLARE(logging_state_t *) t4_tx_get_logging_state(t4_tx_state_t *s); + +/*! \brief Prepare for transmission of a document. + \param s The T.4 context. + \param file The name of the file to be sent. + \param start_page The first page to send. -1 for no restriction. + \param stop_page The last page to send. -1 for no restriction. + \return A pointer to the context, or NULL if there was a problem. */ +SPAN_DECLARE(t4_tx_state_t *) t4_tx_init(t4_tx_state_t *s, const char *file, int start_page, int stop_page); + +/*! \brief End the transmission of a document. Tidy up and close the file. + This should be used to end T.4 transmission started with t4_tx_init. + \param s The T.4 context. + \return 0 for success, otherwise -1. */ +SPAN_DECLARE(int) t4_tx_release(t4_tx_state_t *s); + +/*! \brief End the transmission of a document. Tidy up, close the file and + free the context. This should be used to end T.4 transmission + started with t4_tx_init. + \param s The T.4 context. + \return 0 for success, otherwise -1. */ +SPAN_DECLARE(int) t4_tx_free(t4_tx_state_t *s); + #if defined(__cplusplus) } #endif diff --git a/libs/spandsp/src/spandsp/t85.h b/libs/spandsp/src/spandsp/t85.h index d229026197..c6d6f0b47a 100644 --- a/libs/spandsp/src/spandsp/t85.h +++ b/libs/spandsp/src/spandsp/t85.h @@ -64,6 +64,8 @@ extern "C" { #endif +SPAN_DECLARE(bool) t85_analyse_header(uint32_t *width, uint32_t *length, const uint8_t data[], size_t len); + /*! \brief Check if we are at the end of the current document page. \param s The T.85 context. \return 0 for more data to come. SIG_STATUS_END_OF_DATA for no more data. */ diff --git a/libs/spandsp/src/spandsp/telephony.h b/libs/spandsp/src/spandsp/telephony.h index 132cce9bf8..b32ecfa0f5 100644 --- a/libs/spandsp/src/spandsp/telephony.h +++ b/libs/spandsp/src/spandsp/telephony.h @@ -70,13 +70,6 @@ typedef int (*span_tx_handler_t)(void *s, int16_t amp[], int max_len); #define ms_to_samples(t) ((t)*(SAMPLE_RATE/1000)) #define us_to_samples(t) ((t)/(1000000/SAMPLE_RATE)) -#if !defined(FALSE) -#define FALSE 0 -#endif -#if !defined(TRUE) -#define TRUE (!FALSE) -#endif - /* Fixed point constant macros */ #define FP_Q_9_7(x) ((int16_t) (128.0*x + ((x >= 0.0) ? 0.5 : -0.5))) #define FP_Q_8_8(x) ((int16_t) (256.0*x + ((x >= 0.0) ? 0.5 : -0.5))) diff --git a/libs/spandsp/src/spandsp/v17rx.h b/libs/spandsp/src/spandsp/v17rx.h index 21c34f5b29..74c4b1dd8e 100644 --- a/libs/spandsp/src/spandsp/v17rx.h +++ b/libs/spandsp/src/spandsp/v17rx.h @@ -239,9 +239,9 @@ SPAN_DECLARE(v17_rx_state_t *) v17_rx_init(v17_rx_state_t *s, int bit_rate, put_ \brief Reinitialise an existing V.17 modem receive context. \param s The modem context. \param bit_rate The bit rate of the modem. Valid values are 7200, 9600, 12000 and 14400. - \param short_train TRUE if a short training sequence is expected. + \param short_train True if a short training sequence is expected. \return 0 for OK, -1 for bad parameter */ -SPAN_DECLARE(int) v17_rx_restart(v17_rx_state_t *s, int bit_rate, int short_train); +SPAN_DECLARE(int) v17_rx_restart(v17_rx_state_t *s, int bit_rate, bool short_train); /*! Release a V.17 modem receive context. \brief Release a V.17 modem receive context. diff --git a/libs/spandsp/src/spandsp/v17tx.h b/libs/spandsp/src/spandsp/v17tx.h index 0d98cc7010..02fb7309ad 100644 --- a/libs/spandsp/src/spandsp/v17tx.h +++ b/libs/spandsp/src/spandsp/v17tx.h @@ -101,20 +101,20 @@ SPAN_DECLARE(void) v17_tx_power(v17_tx_state_t *s, float power); \brief Initialise a V.17 modem transmit context. \param s The modem context. \param bit_rate The bit rate of the modem. Valid values are 7200, 9600, 12000 and 14400. - \param tep TRUE is the optional TEP tone is to be transmitted. + \param tep True is the optional TEP tone is to be transmitted. \param get_bit The callback routine used to get the data to be transmitted. \param user_data An opaque pointer. \return A pointer to the modem context, or NULL if there was a problem. */ -SPAN_DECLARE(v17_tx_state_t *) v17_tx_init(v17_tx_state_t *s, int bit_rate, int tep, get_bit_func_t get_bit, void *user_data); +SPAN_DECLARE(v17_tx_state_t *) v17_tx_init(v17_tx_state_t *s, int bit_rate, bool tep, get_bit_func_t get_bit, void *user_data); /*! Reinitialise an existing V.17 modem transmit context, so it may be reused. \brief Reinitialise an existing V.17 modem transmit context. \param s The modem context. \param bit_rate The bit rate of the modem. Valid values are 7200, 9600, 12000 and 14400. - \param tep TRUE is the optional TEP tone is to be transmitted. - \param short_train TRUE if the short training sequence should be used. + \param tep True is the optional TEP tone is to be transmitted. + \param short_train True if the short training sequence should be used. \return 0 for OK, -1 for parameter error. */ -SPAN_DECLARE(int) v17_tx_restart(v17_tx_state_t *s, int bit_rate, int tep, int short_train); +SPAN_DECLARE(int) v17_tx_restart(v17_tx_state_t *s, int bit_rate, bool tep, bool short_train); /*! Release a V.17 modem transmit context. \brief Release a V.17 modem transmit context. diff --git a/libs/spandsp/src/spandsp/v18.h b/libs/spandsp/src/spandsp/v18.h index fbd4994a59..04c0db7c15 100644 --- a/libs/spandsp/src/spandsp/v18.h +++ b/libs/spandsp/src/spandsp/v18.h @@ -38,28 +38,34 @@ typedef struct v18_state_s v18_state_t; enum { - V18_MODE_NONE = 0, + V18_MODE_NONE = 0x0001, /* V.18 Annex A - Weitbrecht TDD at 45.45bps (US TTY), half-duplex, 5 bit baudot (USA). */ - V18_MODE_5BIT_45 = 1, + V18_MODE_5BIT_4545 = 0x0002, /* V.18 Annex A - Weitbrecht TDD at 50bps (International TTY), half-duplex, 5 bit baudot (UK, Australia and others). */ - V18_MODE_5BIT_50 = 2, + V18_MODE_5BIT_50 = 0x0004, /* V.18 Annex B - DTMF encoding of ASCII (Denmark, Holland and others). */ - V18_MODE_DTMF = 3, + V18_MODE_DTMF = 0x0008, /* V.18 Annex C - EDT (European Deaf Telephone) 110bps, V.21, half-duplex, ASCII (Germany, Austria, Switzerland and others). */ - V18_MODE_EDT = 4, + V18_MODE_EDT = 0x0010, /* V.18 Annex D - 300bps, Bell 103, duplex, ASCII (USA). */ - V18_MODE_BELL103 = 5, + V18_MODE_BELL103 = 0x0020, /* V.18 Annex E - 1200bps Videotex terminals, ASCII (France). */ - V18_MODE_V23VIDEOTEX = 6, + V18_MODE_V23VIDEOTEX = 0x0040, /* V.18 Annex F - V.21 text telephone, V.21, duplex, ASCII (Sweden, Norway and Finland). */ - V18_MODE_V21TEXTPHONE = 7, + V18_MODE_V21TEXTPHONE = 0x0080, /* V.18 Annex G - V.18 text telephone mode. */ - V18_MODE_V18TEXTPHONE = 8 + V18_MODE_V18TEXTPHONE = 0x0100, + /* V.18 Annex A - Used during probing. */ + V18_MODE_5BIT_476 = 0x0200, + /* Use repetitive shift characters where character set shifts are used */ + V18_MODE_REPETITIVE_SHIFTS_OPTION = 0x1000 }; /* Automoding sequences for different countries */ enum { + V18_AUTOMODING_GLOBAL = 0, + /* 5-bit, V.21, V.23, EDT, DTMF, Bell 103 */ V18_AUTOMODING_AUSTRALIA, V18_AUTOMODING_IRELAND, @@ -89,7 +95,9 @@ enum /* V.23, EDT, DTMF, 5-bit, V.21, Bell 103 */ V18_AUTOMODING_FRANCE, - V18_AUTOMODING_BELGIUM + V18_AUTOMODING_BELGIUM, + + V18_AUTOMODING_END }; #if defined(__cplusplus) @@ -102,15 +110,17 @@ SPAN_DECLARE(logging_state_t *) v18_get_logging_state(v18_state_t *s); /*! Initialise a V.18 context. \brief Initialise a V.18 context. \param s The V.18 context. - \param calling_party TRUE if caller mode, else answerer mode. + \param calling_party True if caller mode, else answerer mode. \param mode Mode of operation. + \param nation National variant for automoding. \param put_msg A callback routine called to deliver the received text to the application. \param user_data An opaque pointer for the callback routine. \return A pointer to the V.18 context, or NULL if there was a problem. */ SPAN_DECLARE(v18_state_t *) v18_init(v18_state_t *s, - int calling_party, + bool calling_party, int mode, + int nation, put_msg_func_t put_msg, void *user_data); @@ -163,28 +173,6 @@ SPAN_DECLARE_NONSTD(int) v18_rx_fillin(v18_state_t *s, int len); invalid, this function will return -1. */ SPAN_DECLARE(int) v18_put(v18_state_t *s, const char msg[], int len); -/*! Convert a text string to a V.18 DTMF string. - \brief Convert a text string to a V.18 DTMF string. - \param s The V.18 context. - \param dtmf The resulting DTMF string. - \param msg The text string to be converted. - \return The length of the DTMF string. -*/ -SPAN_DECLARE(int) v18_encode_dtmf(v18_state_t *s, char dtmf[], const char msg[]); - -/*! Convert a V.18 DTMF string to a text string. - \brief Convert a V.18 DTMF string to a text string. - \param s The V.18 context. - \param msg The resulting test string. - \param dtmf The DTMF string to be converted. - \return The length of the text string. -*/ -SPAN_DECLARE(int) v18_decode_dtmf(v18_state_t *s, char msg[], const char dtmf[]); - -SPAN_DECLARE(uint16_t) v18_encode_baudot(v18_state_t *s, uint8_t ch); - -SPAN_DECLARE(uint8_t) v18_decode_baudot(v18_state_t *s, uint8_t ch); - /*! \brief Return a short name for an V.18 mode \param mode The code for the V.18 mode. \return A pointer to the name. diff --git a/libs/spandsp/src/spandsp/v22bis.h b/libs/spandsp/src/spandsp/v22bis.h index 6361c05841..f20656919f 100644 --- a/libs/spandsp/src/spandsp/v22bis.h +++ b/libs/spandsp/src/spandsp/v22bis.h @@ -155,9 +155,9 @@ SPAN_DECLARE(int) v22bis_request_retrain(v22bis_state_t *s, int bit_rate); /*! Request a loopback 2 for a V.22bis modem context. \brief Request a loopback 2 for a V.22bis modem context. \param s The modem context. - \param enable TRUE to enable loopback, or FALSE to disable it. + \param enable True to enable loopback, or false to disable it. \return 0 for OK, -1 for request reject. */ -SPAN_DECLARE(int) v22bis_remote_loopback(v22bis_state_t *s, int enable); +SPAN_DECLARE(int) v22bis_remote_loopback(v22bis_state_t *s, bool enable); /*! Report the current operating bit rate of a V.22bis modem context. \brief Report the current operating bit rate of a V.22bis modem context @@ -170,7 +170,7 @@ SPAN_DECLARE(int) v22bis_get_current_bit_rate(v22bis_state_t *s); \param s The modem context. \param bit_rate The bit rate of the modem. Valid values are 1200 and 2400. \param guard The guard tone option. 0 = none, 1 = 550Hz, 2 = 1800Hz. - \param calling_party TRUE if this is the calling modem. + \param calling_party True if this is the calling modem. \param get_bit The callback routine used to get the data to be transmitted. \param put_bit The callback routine used to get the data to be transmitted. \param user_data An opaque pointer, passed in calls to the get and put routines. @@ -178,7 +178,7 @@ SPAN_DECLARE(int) v22bis_get_current_bit_rate(v22bis_state_t *s); SPAN_DECLARE(v22bis_state_t *) v22bis_init(v22bis_state_t *s, int bit_rate, int guard, - int calling_party, + bool calling_party, get_bit_func_t get_bit, void *get_bit_user_data, put_bit_func_t put_bit, diff --git a/libs/spandsp/src/spandsp/v27ter_rx.h b/libs/spandsp/src/spandsp/v27ter_rx.h index 5881f4cf02..80fdb3655f 100644 --- a/libs/spandsp/src/spandsp/v27ter_rx.h +++ b/libs/spandsp/src/spandsp/v27ter_rx.h @@ -74,9 +74,9 @@ SPAN_DECLARE(v27ter_rx_state_t *) v27ter_rx_init(v27ter_rx_state_t *s, int bit_r \brief Reinitialise an existing V.27ter modem receive context. \param s The modem context. \param bit_rate The bit rate of the modem. Valid values are 2400 and 4800. - \param old_train TRUE if a previous trained values are to be reused. + \param old_train True if a previous trained values are to be reused. \return 0 for OK, -1 for bad parameter */ -SPAN_DECLARE(int) v27ter_rx_restart(v27ter_rx_state_t *s, int bit_rate, int old_train); +SPAN_DECLARE(int) v27ter_rx_restart(v27ter_rx_state_t *s, int bit_rate, bool old_train); /*! Release a V.27ter modem receive context. \brief Release a V.27ter modem receive context. diff --git a/libs/spandsp/src/spandsp/v27ter_tx.h b/libs/spandsp/src/spandsp/v27ter_tx.h index e785c889ec..fba064fea0 100644 --- a/libs/spandsp/src/spandsp/v27ter_tx.h +++ b/libs/spandsp/src/spandsp/v27ter_tx.h @@ -83,19 +83,19 @@ SPAN_DECLARE(void) v27ter_tx_power(v27ter_tx_state_t *s, float power); \brief Initialise a V.27ter modem transmit context. \param s The modem context. \param bit_rate The bit rate of the modem. Valid values are 2400 and 4800. - \param tep TRUE is the optional TEP tone is to be transmitted. + \param tep True is the optional TEP tone is to be transmitted. \param get_bit The callback routine used to get the data to be transmitted. \param user_data An opaque pointer. \return A pointer to the modem context, or NULL if there was a problem. */ -SPAN_DECLARE(v27ter_tx_state_t *) v27ter_tx_init(v27ter_tx_state_t *s, int bit_rate, int tep, get_bit_func_t get_bit, void *user_data); +SPAN_DECLARE(v27ter_tx_state_t *) v27ter_tx_init(v27ter_tx_state_t *s, int bit_rate, bool tep, get_bit_func_t get_bit, void *user_data); /*! Reinitialise an existing V.27ter modem transmit context, so it may be reused. \brief Reinitialise an existing V.27ter modem transmit context. \param s The modem context. \param bit_rate The bit rate of the modem. Valid values are 2400 and 4800. - \param tep TRUE is the optional TEP tone is to be transmitted. + \param tep True is the optional TEP tone is to be transmitted. \return 0 for OK, -1 for bad parameter */ -SPAN_DECLARE(int) v27ter_tx_restart(v27ter_tx_state_t *s, int bit_rate, int tep); +SPAN_DECLARE(int) v27ter_tx_restart(v27ter_tx_state_t *s, int bit_rate, bool tep); /*! Release a V.27ter modem transmit context. \brief Release a V.27ter modem transmit context. diff --git a/libs/spandsp/src/spandsp/v29rx.h b/libs/spandsp/src/spandsp/v29rx.h index ec3a945ad4..378d4fe955 100644 --- a/libs/spandsp/src/spandsp/v29rx.h +++ b/libs/spandsp/src/spandsp/v29rx.h @@ -154,9 +154,9 @@ SPAN_DECLARE(v29_rx_state_t *) v29_rx_init(v29_rx_state_t *s, int bit_rate, put_ \brief Reinitialise an existing V.29 modem receive context. \param s The modem context. \param bit_rate The bit rate of the modem. Valid values are 4800, 7200 and 9600. - \param old_train TRUE if a previous trained values are to be reused. + \param old_train True if a previous trained values are to be reused. \return 0 for OK, -1 for bad parameter */ -SPAN_DECLARE(int) v29_rx_restart(v29_rx_state_t *s, int bit_rate, int old_train); +SPAN_DECLARE(int) v29_rx_restart(v29_rx_state_t *s, int bit_rate, bool old_train); /*! Release a V.29 modem receive context. \brief Release a V.29 modem receive context. diff --git a/libs/spandsp/src/spandsp/v29tx.h b/libs/spandsp/src/spandsp/v29tx.h index 86737d1ba3..18bcf66b6a 100644 --- a/libs/spandsp/src/spandsp/v29tx.h +++ b/libs/spandsp/src/spandsp/v29tx.h @@ -114,19 +114,19 @@ SPAN_DECLARE(void) v29_tx_power(v29_tx_state_t *s, float power); \brief Initialise a V.29 modem transmit context. \param s The modem context. \param bit_rate The bit rate of the modem. Valid values are 4800, 7200 and 9600. - \param tep TRUE is the optional TEP tone is to be transmitted. + \param tep True is the optional TEP tone is to be transmitted. \param get_bit The callback routine used to get the data to be transmitted. \param user_data An opaque pointer. \return A pointer to the modem context, or NULL if there was a problem. */ -SPAN_DECLARE(v29_tx_state_t *) v29_tx_init(v29_tx_state_t *s, int bit_rate, int tep, get_bit_func_t get_bit, void *user_data); +SPAN_DECLARE(v29_tx_state_t *) v29_tx_init(v29_tx_state_t *s, int bit_rate, bool tep, get_bit_func_t get_bit, void *user_data); /*! Reinitialise an existing V.29 modem transmit context, so it may be reused. \brief Reinitialise an existing V.29 modem transmit context. \param s The modem context. \param bit_rate The bit rate of the modem. Valid values are 4800, 7200 and 9600. - \param tep TRUE is the optional TEP tone is to be transmitted. + \param tep True is the optional TEP tone is to be transmitted. \return 0 for OK, -1 for bad parameter */ -SPAN_DECLARE(int) v29_tx_restart(v29_tx_state_t *s, int bit_rate, int tep); +SPAN_DECLARE(int) v29_tx_restart(v29_tx_state_t *s, int bit_rate, bool tep); /*! Release a V.29 modem transmit context. \brief Release a V.29 modem transmit context. diff --git a/libs/spandsp/src/spandsp/v42.h b/libs/spandsp/src/spandsp/v42.h index 6332e5cd61..8002d43eed 100644 --- a/libs/spandsp/src/spandsp/v42.h +++ b/libs/spandsp/src/spandsp/v42.h @@ -78,16 +78,16 @@ SPAN_DECLARE(logging_state_t *) v42_get_logging_state(v42_state_t *s); /*! Initialise a V.42 context. \param s The V.42 context. - \param calling_party TRUE if caller mode, else answerer mode. - \param detect TRUE to perform the V.42 detection, else go straight into LAP.M + \param calling_party True if caller mode, else answerer mode. + \param detect True to perform the V.42 detection, else go straight into LAP.M \param iframe_get A callback function to handle received frames of data. \param iframe_put A callback function to get frames of data for transmission. \param user_data An opaque pointer passed to the frame handler routines. \return ??? */ SPAN_DECLARE(v42_state_t *) v42_init(v42_state_t *s, - int calling_party, - int detect, + bool calling_party, + bool detect, get_msg_func_t iframe_get, put_msg_func_t iframe_put, void *user_data); diff --git a/libs/spandsp/src/spandsp/v8.h b/libs/spandsp/src/spandsp/v8.h index 0c1924c1e8..9ded271aec 100644 --- a/libs/spandsp/src/spandsp/v8.h +++ b/libs/spandsp/src/spandsp/v8.h @@ -135,19 +135,19 @@ extern "C" #endif SPAN_DECLARE(int) v8_restart(v8_state_t *s, - int calling_party, + bool calling_party, v8_parms_t *parms); /*! Initialise a V.8 context. \brief Initialise a V.8 context. \param s The V.8 context. - \param calling_party TRUE if caller mode, else answerer mode. + \param calling_party True if caller mode, else answerer mode. \param parms The allowed parameters for the call. \param result_handler The callback routine used to handle the results of negotiation. \param user_data An opaque pointer passed to the result_handler routine. \return A pointer to the V.8 context, or NULL if there was a problem. */ SPAN_DECLARE(v8_state_t *) v8_init(v8_state_t *s, - int calling_party, + bool calling_party, v8_parms_t *parms, v8_result_handler_t result_handler, void *user_data); diff --git a/libs/spandsp/src/super_tone_rx.c b/libs/spandsp/src/super_tone_rx.c index e46faa8148..eabebe6a30 100644 --- a/libs/spandsp/src/super_tone_rx.c +++ b/libs/spandsp/src/super_tone_rx.c @@ -45,6 +45,7 @@ #include "floating_fudge.h" #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/fast_convert.h" #include "spandsp/complex.h" #include "spandsp/vector_float.h" @@ -95,7 +96,7 @@ static int add_super_tone_freq(super_tone_rx_descriptor_t *desc, int freq) desc->pitches[i][1] = desc->monitored_frequencies; if (desc->monitored_frequencies%5 == 0) { - desc->desc = (goertzel_descriptor_t *) realloc(desc->desc, (desc->monitored_frequencies + 5)*sizeof(goertzel_descriptor_t)); + desc->desc = (goertzel_descriptor_t *) span_realloc(desc->desc, (desc->monitored_frequencies + 5)*sizeof(goertzel_descriptor_t)); } make_goertzel_descriptor(&desc->desc[desc->monitored_frequencies++], (float) freq, SUPER_TONE_BINS); desc->used_frequencies++; @@ -107,8 +108,8 @@ SPAN_DECLARE(int) super_tone_rx_add_tone(super_tone_rx_descriptor_t *desc) { if (desc->tones%5 == 0) { - desc->tone_list = (super_tone_rx_segment_t **) realloc(desc->tone_list, (desc->tones + 5)*sizeof(super_tone_rx_segment_t *)); - desc->tone_segs = (int *) realloc(desc->tone_segs, (desc->tones + 5)*sizeof(int)); + desc->tone_list = (super_tone_rx_segment_t **) span_realloc(desc->tone_list, (desc->tones + 5)*sizeof(super_tone_rx_segment_t *)); + desc->tone_segs = (int *) span_realloc(desc->tone_segs, (desc->tones + 5)*sizeof(int)); } desc->tone_list[desc->tones] = NULL; desc->tone_segs[desc->tones] = 0; @@ -129,7 +130,7 @@ SPAN_DECLARE(int) super_tone_rx_add_element(super_tone_rx_descriptor_t *desc, step = desc->tone_segs[tone]; if (step%5 == 0) { - desc->tone_list[tone] = (super_tone_rx_segment_t *) realloc(desc->tone_list[tone], (step + 5)*sizeof(super_tone_rx_segment_t)); + desc->tone_list[tone] = (super_tone_rx_segment_t *) span_realloc(desc->tone_list[tone], (step + 5)*sizeof(super_tone_rx_segment_t)); } desc->tone_list[tone][step].f1 = add_super_tone_freq(desc, f1); desc->tone_list[tone][step].f2 = add_super_tone_freq(desc, f2); @@ -199,7 +200,7 @@ SPAN_DECLARE(super_tone_rx_descriptor_t *) super_tone_rx_make_descriptor(super_t { if (desc == NULL) { - if ((desc = (super_tone_rx_descriptor_t *) malloc(sizeof(*desc))) == NULL) + if ((desc = (super_tone_rx_descriptor_t *) span_alloc(sizeof(*desc))) == NULL) return NULL; } desc->tone_list = NULL; @@ -222,15 +223,15 @@ SPAN_DECLARE(int) super_tone_rx_free_descriptor(super_tone_rx_descriptor_t *desc for (i = 0; i < desc->tones; i++) { if (desc->tone_list[i]) - free(desc->tone_list[i]); + span_free(desc->tone_list[i]); } if (desc->tone_list) - free(desc->tone_list); + span_free(desc->tone_list); if (desc->tone_segs) - free(desc->tone_segs); + span_free(desc->tone_segs); if (desc->desc) - free(desc->desc); - free(desc); + span_free(desc->desc); + span_free(desc); } return 0; } @@ -265,7 +266,7 @@ SPAN_DECLARE(super_tone_rx_state_t *) super_tone_rx_init(super_tone_rx_state_t * return NULL; if (s == NULL) { - if ((s = (super_tone_rx_state_t *) malloc(sizeof(*s) + desc->monitored_frequencies*sizeof(goertzel_state_t))) == NULL) + if ((s = (super_tone_rx_state_t *) span_alloc(sizeof(*s) + desc->monitored_frequencies*sizeof(goertzel_state_t))) == NULL) return NULL; } @@ -301,7 +302,7 @@ SPAN_DECLARE(int) super_tone_rx_release(super_tone_rx_state_t *s) SPAN_DECLARE(int) super_tone_rx_free(super_tone_rx_state_t *s) { if (s) - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/super_tone_tx.c b/libs/spandsp/src/super_tone_tx.c index 3809bb4bf8..5b8ab4303d 100644 --- a/libs/spandsp/src/super_tone_tx.c +++ b/libs/spandsp/src/super_tone_tx.c @@ -45,6 +45,7 @@ #include "floating_fudge.h" #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/fast_convert.h" #include "spandsp/complex.h" #include "spandsp/dds.h" @@ -78,7 +79,7 @@ SPAN_DECLARE(super_tone_tx_step_t *) super_tone_tx_make_step(super_tone_tx_step_ { if (s == NULL) { - if ((s = (super_tone_tx_step_t *) malloc(sizeof(*s))) == NULL) + if ((s = (super_tone_tx_step_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } if (f1 >= 1.0f) @@ -121,7 +122,7 @@ SPAN_DECLARE(int) super_tone_tx_free_tone(super_tone_tx_step_t *s) super_tone_tx_free_tone(s->nest); t = s; s = s->next; - free(t); + span_free(t); } return 0; } @@ -133,7 +134,7 @@ SPAN_DECLARE(super_tone_tx_state_t *) super_tone_tx_init(super_tone_tx_state_t * return NULL; if (s == NULL) { - if ((s = (super_tone_tx_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (super_tone_tx_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -155,7 +156,7 @@ SPAN_DECLARE(int) super_tone_tx_release(super_tone_tx_state_t *s) SPAN_DECLARE(int) super_tone_tx_free(super_tone_tx_state_t *s) { if (s) - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/swept_tone.c b/libs/spandsp/src/swept_tone.c index f5ccc9bed8..d371bb2828 100644 --- a/libs/spandsp/src/swept_tone.c +++ b/libs/spandsp/src/swept_tone.c @@ -39,9 +39,15 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/complex.h" #include "spandsp/vector_float.h" @@ -59,7 +65,7 @@ SPAN_DECLARE(swept_tone_state_t *) swept_tone_init(swept_tone_state_t *s, float { if (s == NULL) { - if ((s = (swept_tone_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (swept_tone_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -119,7 +125,7 @@ SPAN_DECLARE(int) swept_tone_release(swept_tone_state_t *s) SPAN_DECLARE(int) swept_tone_free(swept_tone_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/t30.c b/libs/spandsp/src/t30.c index a8ed266f94..de71d91067 100644 --- a/libs/spandsp/src/t30.c +++ b/libs/spandsp/src/t30.c @@ -30,8 +30,8 @@ #endif #include -#include #include +#include #include #include #include @@ -41,10 +41,16 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/bit_operations.h" #include "spandsp/queue.h" @@ -65,9 +71,7 @@ #include "spandsp/t81_t82_arith_coding.h" #include "spandsp/t85.h" #include "spandsp/t42.h" -#if defined(SPANDSP_SUPPORT_T43) #include "spandsp/t43.h" -#endif #include "spandsp/t4_t6_decode.h" #include "spandsp/t4_t6_encode.h" #include "spandsp/t30_fcf.h" @@ -81,9 +85,7 @@ #include "spandsp/private/t81_t82_arith_coding.h" #include "spandsp/private/t85.h" #include "spandsp/private/t42.h" -#if defined(SPANDSP_SUPPORT_T43) #include "spandsp/private/t43.h" -#endif #include "spandsp/private/t4_t6_decode.h" #include "spandsp/private/t4_t6_encode.h" #include "spandsp/private/image_translate.h" @@ -419,7 +421,7 @@ static const struct { 7200, T30_MODEM_V29, T30_SUPPORT_V29, (DISBIT4 | DISBIT3)}, { 4800, T30_MODEM_V27TER, T30_SUPPORT_V27TER, DISBIT4}, { 2400, T30_MODEM_V27TER, T30_SUPPORT_V27TER, 0}, - { 0, 0, 0, 0} + { 0, 0, 0, 0} }; static void queue_phase(t30_state_t *s, int phase); @@ -434,8 +436,8 @@ static void disconnect(t30_state_t *s); static void decode_20digit_msg(t30_state_t *s, char *msg, const uint8_t *pkt, int len); static void decode_url_msg(t30_state_t *s, char *msg, const uint8_t *pkt, int len); static int decode_nsf_nss_nsc(t30_state_t *s, uint8_t *msg[], const uint8_t *pkt, int len); -static int set_min_scan_time_code(t30_state_t *s); -static int send_cfr_sequence(t30_state_t *s, int start); +static void set_min_scan_time(t30_state_t *s); +static int build_dcs(t30_state_t *s); static void timer_t2_start(t30_state_t *s); static void timer_t2a_start(t30_state_t *s); static void timer_t2b_start(t30_state_t *s); @@ -453,6 +455,43 @@ static void timer_t2_t4_stop(t30_state_t *s); /*! Clear a specified bit within a DIS, DTC or DCS frame */ #define clr_ctrl_bit(s,bit) (s)[3 + ((bit - 1)/8)] &= ~(1 << ((bit - 1)%8)) +static int find_fallback_entry(int dcs_code) +{ + int i; + + /* The table is short, and not searched often, so a brain-dead linear scan seems OK */ + for (i = 0; fallback_sequence[i].bit_rate; i++) + { + if (fallback_sequence[i].dcs_code == dcs_code) + break; + } + if (fallback_sequence[i].bit_rate == 0) + return -1; + return i; +} +/*- End of function --------------------------------------------------------*/ + +static int step_fallback_entry(t30_state_t *s) +{ + while (fallback_sequence[++s->current_fallback].bit_rate) + { + if ((fallback_sequence[s->current_fallback].which & s->current_permitted_modems)) + break; + } + if (fallback_sequence[s->current_fallback].bit_rate == 0) + { + /* Reset the fallback sequence */ + s->current_fallback = 0; + return -1; + } + /* We need to update the minimum scan time, in case we are in non-ECM mode. */ + set_min_scan_time(s); + /* Now we need to rebuild the DCS message we will send. */ + build_dcs(s); + return s->current_fallback; +} +/*- End of function --------------------------------------------------------*/ + static int terminate_operation_in_progress(t30_state_t *s) { /* Make sure any FAX in progress is tidied up. If the tidying up has @@ -509,7 +548,7 @@ static int rx_start_page(t30_state_t *s) t4_rx_set_vendor(&s->t4.rx, s->vendor); t4_rx_set_model(&s->t4.rx, s->model); - t4_rx_set_rx_encoding(&s->t4.rx, s->line_encoding); + t4_rx_set_rx_encoding(&s->t4.rx, s->line_compression); t4_rx_set_x_resolution(&s->t4.rx, s->x_resolution); t4_rx_set_y_resolution(&s->t4.rx, s->y_resolution); @@ -547,7 +586,7 @@ static void report_rx_ecm_page_result(t30_state_t *s) span_log(&s->logging, SPAN_LOG_FLOW, "Page no = %d\n", stats.pages_transferred); span_log(&s->logging, SPAN_LOG_FLOW, "Image size = %d x %d pixels\n", stats.width, stats.length); span_log(&s->logging, SPAN_LOG_FLOW, "Image resolution = %d/m x %d/m\n", stats.x_resolution, stats.y_resolution); - span_log(&s->logging, SPAN_LOG_FLOW, "Compression = %s (%d)\n", t4_encoding_to_str(stats.encoding), stats.encoding); + span_log(&s->logging, SPAN_LOG_FLOW, "Compression = %s (%d)\n", t4_compression_to_str(stats.compression), stats.compression); span_log(&s->logging, SPAN_LOG_FLOW, "Compressed image size = %d bytes\n", stats.line_image_size); } /*- End of function --------------------------------------------------------*/ @@ -571,7 +610,7 @@ static int copy_quality(t30_state_t *s) span_log(&s->logging, SPAN_LOG_FLOW, "Page no = %d\n", stats.pages_transferred + 1); span_log(&s->logging, SPAN_LOG_FLOW, "Image size = %d x %d pixels\n", stats.width, stats.length); span_log(&s->logging, SPAN_LOG_FLOW, "Image resolution = %d/m x %d/m\n", stats.x_resolution, stats.y_resolution); - span_log(&s->logging, SPAN_LOG_FLOW, "Compression = %s (%d)\n", t4_encoding_to_str(stats.encoding), stats.encoding); + span_log(&s->logging, SPAN_LOG_FLOW, "Compression = %s (%d)\n", t4_compression_to_str(stats.compression), stats.compression); span_log(&s->logging, SPAN_LOG_FLOW, "Compressed image size = %d bytes\n", stats.line_image_size); span_log(&s->logging, SPAN_LOG_FLOW, "Bad rows = %d\n", stats.bad_rows); span_log(&s->logging, SPAN_LOG_FLOW, "Longest bad row run = %d\n", stats.longest_bad_row_run); @@ -621,89 +660,89 @@ static void release_resources(t30_state_t *s) { if (s->tx_info.nsf) { - free(s->tx_info.nsf); + span_free(s->tx_info.nsf); s->tx_info.nsf = NULL; } s->tx_info.nsf_len = 0; if (s->tx_info.nsc) { - free(s->tx_info.nsc); + span_free(s->tx_info.nsc); s->tx_info.nsc = NULL; } s->tx_info.nsc_len = 0; if (s->tx_info.nss) { - free(s->tx_info.nss); + span_free(s->tx_info.nss); s->tx_info.nss = NULL; } s->tx_info.nss_len = 0; if (s->tx_info.tsa) { - free(s->tx_info.tsa); + span_free(s->tx_info.tsa); s->tx_info.tsa = NULL; } if (s->tx_info.ira) { - free(s->tx_info.ira); + span_free(s->tx_info.ira); s->tx_info.ira = NULL; } if (s->tx_info.cia) { - free(s->tx_info.cia); + span_free(s->tx_info.cia); s->tx_info.cia = NULL; } if (s->tx_info.isp) { - free(s->tx_info.isp); + span_free(s->tx_info.isp); s->tx_info.isp = NULL; } if (s->tx_info.csa) { - free(s->tx_info.csa); + span_free(s->tx_info.csa); s->tx_info.csa = NULL; } if (s->rx_info.nsf) { - free(s->rx_info.nsf); + span_free(s->rx_info.nsf); s->rx_info.nsf = NULL; } s->rx_info.nsf_len = 0; if (s->rx_info.nsc) { - free(s->rx_info.nsc); + span_free(s->rx_info.nsc); s->rx_info.nsc = NULL; } s->rx_info.nsc_len = 0; if (s->rx_info.nss) { - free(s->rx_info.nss); + span_free(s->rx_info.nss); s->rx_info.nss = NULL; } s->rx_info.nss_len = 0; if (s->rx_info.tsa) { - free(s->rx_info.tsa); + span_free(s->rx_info.tsa); s->rx_info.tsa = NULL; } if (s->rx_info.ira) { - free(s->rx_info.ira); + span_free(s->rx_info.ira); s->rx_info.ira = NULL; } if (s->rx_info.cia) { - free(s->rx_info.cia); + span_free(s->rx_info.cia); s->rx_info.cia = NULL; } if (s->rx_info.isp) { - free(s->rx_info.isp); + span_free(s->rx_info.isp); s->rx_info.isp = NULL; } if (s->rx_info.csa) { - free(s->rx_info.csa); + span_free(s->rx_info.csa); s->rx_info.csa = NULL; } } @@ -732,13 +771,15 @@ static uint8_t check_next_tx_step(t30_state_t *s) if (s->document_handler) more = s->document_handler(s, s->document_user_data, 0); else - more = FALSE; + more = false; if (more) { + span_log(&s->logging, SPAN_LOG_FLOW, "Another document to send\n"); //if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_MULTIPLE_SELECTIVE_POLLING_CAPABLE)) // return T30_EOS; return (s->local_interrupt_pending) ? T30_PRI_EOM : T30_EOM; } + span_log(&s->logging, SPAN_LOG_FLOW, "No more pages to send\n"); return (s->local_interrupt_pending) ? T30_PRI_EOP : T30_EOP; } /*- End of function --------------------------------------------------------*/ @@ -766,9 +807,13 @@ static int get_partial_ecm_page(t30_state_t *s) /* These frames contain a frame sequence number within the partial page (one octet) followed by some image data. */ s->ecm_data[i][3] = (uint8_t) i; - if ((len = t4_tx_get(&s->t4.tx, &s->ecm_data[i][4], s->octets_per_ecm_frame)) < s->octets_per_ecm_frame) + if (s->document_get_handler) + len = s->document_get_handler(s->document_get_user_data, &s->ecm_data[i][4], s->octets_per_ecm_frame); + else + len = t4_tx_get(&s->t4.tx, &s->ecm_data[i][4], s->octets_per_ecm_frame); + if (len < s->octets_per_ecm_frame) { - /* The image is not big enough to fill the entire buffer */ + /* The document is not big enough to fill the entire buffer */ /* We need to pad to a full frame, as most receivers expect that. */ if (len > 0) { @@ -776,8 +821,8 @@ static int get_partial_ecm_page(t30_state_t *s) s->ecm_len[i++] = (int16_t) (s->octets_per_ecm_frame + 4); } s->ecm_frames = i; - span_log(&s->logging, SPAN_LOG_FLOW, "Partial page buffer contains %d frames (%d per frame)\n", i, s->octets_per_ecm_frame); - s->ecm_at_page_end = TRUE; + span_log(&s->logging, SPAN_LOG_FLOW, "Partial document buffer contains %d frames (%d per frame)\n", i, s->octets_per_ecm_frame); + s->ecm_at_page_end = true; return i; } s->ecm_len[i] = (int16_t) (4 + len); @@ -826,7 +871,7 @@ static int send_next_ecm_frame(t30_state_t *s) send_frame(s, frame, 3); /* In case we are just after a CTC/CTR exchange, which kicked us back to long training */ - s->short_train = TRUE; + s->short_train = true; return 0; } return -1; @@ -874,7 +919,7 @@ static void send_frame(t30_state_t *s, const uint8_t *msg, int len) print_frame(s, "Tx: ", msg, len); if (s->real_time_frame_handler) - s->real_time_frame_handler(s, s->real_time_frame_user_data, FALSE, msg, len); + s->real_time_frame_handler(s, s->real_time_frame_user_data, false, msg, len); if (s->send_hdlc_handler) s->send_hdlc_handler(s->send_hdlc_user_data, msg, len); } @@ -921,9 +966,9 @@ static int send_nsf_frame(t30_state_t *s) s->tx_info.nsf[1] = CONTROL_FIELD_NON_FINAL_FRAME; s->tx_info.nsf[2] = (uint8_t) (T30_NSF | s->dis_received); send_frame(s, s->tx_info.nsf, s->tx_info.nsf_len + 3); - return TRUE; + return true; } - return FALSE; + return false; } /*- End of function --------------------------------------------------------*/ @@ -937,9 +982,9 @@ static int send_nss_frame(t30_state_t *s) s->tx_info.nss[1] = CONTROL_FIELD_NON_FINAL_FRAME; s->tx_info.nss[2] = (uint8_t) (T30_NSS | s->dis_received); send_frame(s, s->tx_info.nss, s->tx_info.nss_len + 3); - return TRUE; + return true; } - return FALSE; + return false; } /*- End of function --------------------------------------------------------*/ @@ -953,9 +998,9 @@ static int send_nsc_frame(t30_state_t *s) s->tx_info.nsc[1] = CONTROL_FIELD_NON_FINAL_FRAME; s->tx_info.nsc[2] = (uint8_t) (T30_NSC | s->dis_received); send_frame(s, s->tx_info.nsc, s->tx_info.nsc_len + 3); - return TRUE; + return true; } - return FALSE; + return false; } /*- End of function --------------------------------------------------------*/ @@ -966,9 +1011,9 @@ static int send_ident_frame(t30_state_t *s, uint8_t cmd) span_log(&s->logging, SPAN_LOG_FLOW, "Sending ident '%s'\n", s->tx_info.ident); /* 'cmd' should be T30_TSI, T30_CIG or T30_CSI */ send_20digit_msg_frame(s, cmd, s->tx_info.ident); - return TRUE; + return true; } - return FALSE; + return false; } /*- End of function --------------------------------------------------------*/ @@ -979,10 +1024,10 @@ static int send_psa_frame(t30_state_t *s) span_log(&s->logging, SPAN_LOG_FLOW, "Sending polled sub-address '%s'\n", s->tx_info.polled_sub_address); send_20digit_msg_frame(s, T30_PSA, s->tx_info.polled_sub_address); set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_POLLED_SUBADDRESSING_CAPABLE); - return TRUE; + return true; } clr_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_POLLED_SUBADDRESSING_CAPABLE); - return FALSE; + return false; } /*- End of function --------------------------------------------------------*/ @@ -993,10 +1038,10 @@ static int send_sep_frame(t30_state_t *s) span_log(&s->logging, SPAN_LOG_FLOW, "Sending selective polling address '%s'\n", s->tx_info.selective_polling_address); send_20digit_msg_frame(s, T30_SEP, s->tx_info.selective_polling_address); set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_SELECTIVE_POLLING_CAPABLE); - return TRUE; + return true; } clr_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_SELECTIVE_POLLING_CAPABLE); - return FALSE; + return false; } /*- End of function --------------------------------------------------------*/ @@ -1008,10 +1053,10 @@ static int send_sid_frame(t30_state_t *s) span_log(&s->logging, SPAN_LOG_FLOW, "Sending sender identification '%s'\n", s->tx_info.sender_ident); send_20digit_msg_frame(s, T30_SID, s->tx_info.sender_ident); set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_SENDER_ID_TRANSMISSION); - return TRUE; + return true; } clr_ctrl_bit(s->dcs_frame, T30_DCS_BIT_SENDER_ID_TRANSMISSION); - return FALSE; + return false; } /*- End of function --------------------------------------------------------*/ @@ -1023,10 +1068,10 @@ static int send_pwd_frame(t30_state_t *s) span_log(&s->logging, SPAN_LOG_FLOW, "Sending password '%s'\n", s->tx_info.password); send_20digit_msg_frame(s, T30_PWD, s->tx_info.password); set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_PASSWORD); - return TRUE; + return true; } clr_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_PASSWORD); - return FALSE; + return false; } /*- End of function --------------------------------------------------------*/ @@ -1038,10 +1083,10 @@ static int send_sub_frame(t30_state_t *s) span_log(&s->logging, SPAN_LOG_FLOW, "Sending sub-address '%s'\n", s->tx_info.sub_address); send_20digit_msg_frame(s, T30_SUB, s->tx_info.sub_address); set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_SUBADDRESS_TRANSMISSION); - return TRUE; + return true; } clr_ctrl_bit(s->dcs_frame, T30_DCS_BIT_SUBADDRESS_TRANSMISSION); - return FALSE; + return false; } /*- End of function --------------------------------------------------------*/ @@ -1050,9 +1095,9 @@ static int send_tsa_frame(t30_state_t *s) if ((test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T37) || test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T38)) && 0) { span_log(&s->logging, SPAN_LOG_FLOW, "Sending transmitting subscriber internet address '%s'\n", ""); - return TRUE; + return true; } - return FALSE; + return false; } /*- End of function --------------------------------------------------------*/ @@ -1062,10 +1107,10 @@ static int send_ira_frame(t30_state_t *s) { span_log(&s->logging, SPAN_LOG_FLOW, "Sending internet routing address '%s'\n", ""); set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INTERNET_ROUTING_ADDRESS_TRANSMISSION); - return TRUE; + return true; } clr_ctrl_bit(s->dcs_frame, T30_DCS_BIT_INTERNET_ROUTING_ADDRESS_TRANSMISSION); - return FALSE; + return false; } /*- End of function --------------------------------------------------------*/ @@ -1074,9 +1119,9 @@ static int send_cia_frame(t30_state_t *s) if ((test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T37) || test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T38)) && 0) { span_log(&s->logging, SPAN_LOG_FLOW, "Sending calling subscriber internet address '%s'\n", ""); - return TRUE; + return true; } - return FALSE; + return false; } /*- End of function --------------------------------------------------------*/ @@ -1086,27 +1131,25 @@ static int send_isp_frame(t30_state_t *s) { span_log(&s->logging, SPAN_LOG_FLOW, "Sending internet selective polling address '%s'\n", ""); set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_INTERNET_SELECTIVE_POLLING_ADDRESS); - return TRUE; + return true; } clr_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_INTERNET_SELECTIVE_POLLING_ADDRESS); - return FALSE; + return false; } /*- End of function --------------------------------------------------------*/ -#if 0 static int send_csa_frame(t30_state_t *s) { #if 0 if (("in T.37 mode" || "in T.38 mode") && 0) { span_log(&s->logging, SPAN_LOG_FLOW, "Sending called subscriber internet address '%s'\n", ""); - return TRUE; + return true; } #endif - return FALSE; + return false; } /*- End of function --------------------------------------------------------*/ -#endif static int send_pps_frame(t30_state_t *s) { @@ -1125,6 +1168,243 @@ static int send_pps_frame(t30_state_t *s) } /*- End of function --------------------------------------------------------*/ +int t30_build_dis_or_dtc(t30_state_t *s) +{ + int i; + + /* Build a skeleton for the DIS and DTC messages. This will be edited for + the dynamically changing capabilities (e.g. can receive) just before + it is sent. It might also be edited if the application changes our + capabilities (e.g. disabling fine mode). Right now we set up all the + unchanging stuff about what we are capable of doing. */ + s->local_dis_dtc_frame[0] = ADDRESS_FIELD; + s->local_dis_dtc_frame[1] = CONTROL_FIELD_FINAL_FRAME; + s->local_dis_dtc_frame[2] = (uint8_t) (T30_DIS | s->dis_received); + for (i = 3; i < T30_MAX_DIS_DTC_DCS_LEN; i++) + s->local_dis_dtc_frame[i] = 0x00; + + /* Always say 256 octets per ECM frame preferred, as 64 is never used in the + real world. */ + if ((s->iaf & T30_IAF_MODE_T37)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T37); + if ((s->iaf & T30_IAF_MODE_T38)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T38); + /* No 3G mobile */ + /* No V.8 */ + /* 256 octets preferred - don't bother making this optional, as everything uses 256 */ + /* Ready to transmit a fax (polling) will be determined separately, and this message edited. */ + /* Ready to receive a fax will be determined separately, and this message edited. */ + /* With no modems set we are actually selecting V.27ter fallback at 2400bps */ + if ((s->supported_modems & T30_SUPPORT_V27TER)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_MODEM_TYPE_2); + if ((s->supported_modems & T30_SUPPORT_V29)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_MODEM_TYPE_1); + /* V.17 is only valid when combined with V.29 and V.27ter, so if we enable V.17 we force the others too. */ + if ((s->supported_modems & T30_SUPPORT_V17)) + s->local_dis_dtc_frame[4] |= (DISBIT6 | DISBIT4 | DISBIT3); + + /* 215mm wide is always supported */ + if ((s->supported_image_sizes & T4_SUPPORT_WIDTH_303MM)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_215MM_255MM_303MM_WIDTH_CAPABLE); + else if ((s->supported_image_sizes & T4_SUPPORT_WIDTH_255MM)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_215MM_255MM_WIDTH_CAPABLE); + + /* A4 is always supported. */ + if ((s->supported_image_sizes & T4_SUPPORT_LENGTH_UNLIMITED)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_UNLIMITED_LENGTH_CAPABLE); + else if ((s->supported_image_sizes & T4_SUPPORT_LENGTH_B4)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_A4_B4_LENGTH_CAPABLE); + if ((s->supported_image_sizes & T4_SUPPORT_LENGTH_US_LETTER)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NORTH_AMERICAN_LETTER_CAPABLE); + if ((s->supported_image_sizes & T4_SUPPORT_LENGTH_US_LEGAL)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NORTH_AMERICAN_LEGAL_CAPABLE); + + /* 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); + + if ((s->supported_compressions & T4_COMPRESSION_T4_2D)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_2D_CAPABLE); + if ((s->supported_compressions & T4_COMPRESSION_NONE)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_UNCOMPRESSED_CAPABLE); + if (s->ecm_allowed) + { + /* ECM allowed */ + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_ECM_CAPABLE); + + /* Only offer the option of fancy compression schemes, if we are + also offering the ECM option needed to support them. */ + if ((s->supported_compressions & T4_COMPRESSION_T6)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T6_CAPABLE); + if ((s->supported_compressions & T4_COMPRESSION_T85)) + { + 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 + support here. */ + if ((s->supported_compressions & T4_COMPRESSION_T85_L0)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T85_L0_CAPABLE); + } + + //if ((s->supported_compressions & T4_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_2); + // set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T88_CAPABILITY_3); + //} + + if ((s->supported_compressions & (T4_COMPRESSION_COLOUR | T4_COMPRESSION_GRAYSCALE))) + { + if ((s->supported_compressions & T4_COMPRESSION_COLOUR)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_FULL_COLOUR_CAPABLE); + + if ((s->supported_compressions & T4_COMPRESSION_T42_T81)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T81_CAPABLE); + if ((s->supported_compressions & T4_COMPRESSION_T43)) + { + /* Note 25 of table 2/T.30 */ + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T81_CAPABLE); + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T43_CAPABLE); + /* No plane interleave */ + } + if ((s->supported_compressions & T4_COMPRESSION_T45)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T45_CAPABLE); + if ((s->supported_compressions & T4_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_SYCC_T81_CAPABLE); + } + + if ((s->supported_compressions & T4_COMPRESSION_12BIT)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_12BIT_CAPABLE); + + if ((s->supported_compressions & T4_COMPRESSION_NO_SUBSAMPLING)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NO_SUBSAMPLING); + + /* No custom illuminant */ + /* No custom gamut range */ + } + } + if ((s->supported_t30_features & T30_SUPPORT_FIELD_NOT_VALID)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_FNV_CAPABLE); + if ((s->supported_t30_features & T30_SUPPORT_MULTIPLE_SELECTIVE_POLLING)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_MULTIPLE_SELECTIVE_POLLING_CAPABLE); + if ((s->supported_t30_features & T30_SUPPORT_POLLED_SUB_ADDRESSING)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_POLLED_SUBADDRESSING_CAPABLE); + if ((s->supported_t30_features & T30_SUPPORT_SELECTIVE_POLLING)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_SELECTIVE_POLLING_CAPABLE); + if ((s->supported_t30_features & T30_SUPPORT_SUB_ADDRESSING)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_SUBADDRESSING_CAPABLE); + if ((s->supported_t30_features & T30_SUPPORT_IDENTIFICATION)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_PASSWORD); + + /* No G.726 */ + /* No extended voice coding */ + /* Superfine minimum scan line time pattern follows fine */ + + /* Ready to transmit a data file (polling) */ + if (s->tx_file[0]) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_READY_TO_TRANSMIT_DATA_FILE); + + /* No simple phase C BFT negotiations */ + /* No extended BFT negotiations */ + /* No Binary file transfer (BFT) */ + /* No Document transfer mode (DTM) */ + /* No Electronic data interchange (EDI) */ + /* No Basic transfer mode (BTM) */ + + /* No mixed mode (polling) */ + /* No character mode */ + /* No mixed mode (T.4/Annex E) */ + /* No mode 26 (T.505) */ + /* No digital network capability */ + /* No duplex operation */ + + /* No HKM key management */ + /* No RSA key management */ + /* No override */ + /* No HFX40 cipher */ + /* No alternative cipher number 2 */ + /* No alternative cipher number 3 */ + /* No HFX40-I hashing */ + /* No alternative hashing system number 2 */ + /* No alternative hashing system number 3 */ + + /* No T.44 (mixed raster content) */ + /* No page length maximum strip size for T.44 (mixed raster content) */ + + if ((s->supported_t30_features & T30_SUPPORT_INTERNET_SELECTIVE_POLLING_ADDRESS)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_INTERNET_SELECTIVE_POLLING_ADDRESS); + if ((s->supported_t30_features & T30_SUPPORT_INTERNET_ROUTING_ADDRESS)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_INTERNET_ROUTING_ADDRESS); + + if ((s->supported_bilevel_resolutions & T4_RESOLUTION_1200_1200)) + { + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_1200_1200_CAPABLE); + if ((s->supported_colour_resolutions & T4_RESOLUTION_1200_1200)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_COLOUR_GRAY_1200_1200_CAPABLE); + } + if ((s->supported_bilevel_resolutions & T4_RESOLUTION_600_1200)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_600_1200_CAPABLE); + if ((s->supported_bilevel_resolutions & T4_RESOLUTION_600_600)) + { + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_600_600_CAPABLE); + if ((s->supported_colour_resolutions & T4_RESOLUTION_600_600)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_COLOUR_GRAY_600_600_CAPABLE); + } + if ((s->supported_bilevel_resolutions & T4_RESOLUTION_400_800)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_400_800_CAPABLE); + if ((s->supported_bilevel_resolutions & T4_RESOLUTION_R16_SUPERFINE)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_400_400_CAPABLE); + if ((s->supported_bilevel_resolutions & T4_RESOLUTION_400_400)) + { + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_400_400_CAPABLE); + if ((s->supported_colour_resolutions & T4_RESOLUTION_400_400)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_COLOUR_GRAY_300_300_400_400_CAPABLE); + } + if ((s->supported_bilevel_resolutions & T4_RESOLUTION_300_600)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_300_600_CAPABLE); + if ((s->supported_bilevel_resolutions & T4_RESOLUTION_300_300)) + { + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_300_300_CAPABLE); + if ((s->supported_colour_resolutions & T4_RESOLUTION_300_300)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_COLOUR_GRAY_300_300_400_400_CAPABLE); + } + if ((s->supported_bilevel_resolutions & (T4_RESOLUTION_200_400 | T4_RESOLUTION_R8_SUPERFINE))) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_200_400_CAPABLE); + if ((s->supported_bilevel_resolutions & T4_RESOLUTION_R8_FINE)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_200_200_CAPABLE); + if ((s->supported_bilevel_resolutions & T4_RESOLUTION_200_200)) + { + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_200_200_CAPABLE); + if ((s->supported_colour_resolutions & T4_RESOLUTION_200_200)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_FULL_COLOUR_CAPABLE); + } + /* Standard FAX resolution bi-level image support goes without saying */ + if ((s->supported_colour_resolutions & T4_RESOLUTION_100_100)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_COLOUR_GRAY_100_100_CAPABLE); + + if ((s->supported_bilevel_resolutions & (T4_RESOLUTION_R8_STANDARD | T4_RESOLUTION_R8_FINE | T4_RESOLUTION_R8_SUPERFINE | T4_RESOLUTION_R16_SUPERFINE))) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_METRIC_RESOLUTION_PREFERRED); + if ((s->supported_bilevel_resolutions & (T4_RESOLUTION_200_100 | T4_RESOLUTION_200_200 | T4_RESOLUTION_200_400 | T4_RESOLUTION_300_300 | T4_RESOLUTION_300_600 | T4_RESOLUTION_400_400 | T4_RESOLUTION_400_800 | T4_RESOLUTION_600_600 | T4_RESOLUTION_600_1200 | T4_RESOLUTION_1200_1200))) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_INCH_RESOLUTION_PREFERRED); + + /* No double sided printing (alternate mode) */ + /* No double sided printing (continuous mode) */ + + /* No black and white mixed raster content profile */ + /* No shared data memory */ + /* No T.44 colour space */ + + if ((s->iaf & T30_IAF_MODE_FLOW_CONTROL)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T38_FLOW_CONTROL_CAPABLE); + /* No k > 4 */ + if ((s->iaf & T30_IAF_MODE_CONTINUOUS_FLOW)) + set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T38_FAX_CAPABLE); + /* No T.88/T.89 profile */ + s->local_dis_dtc_len = 19; + return 0; +} +/*- End of function --------------------------------------------------------*/ + static int set_dis_or_dtc(t30_state_t *s) { /* Whether we use a DIS or a DTC is determined by whether we have received a DIS. @@ -1144,186 +1424,12 @@ static int set_dis_or_dtc(t30_state_t *s) } /*- End of function --------------------------------------------------------*/ -int t30_build_dis_or_dtc(t30_state_t *s) -{ - int i; - - /* Build a skeleton for the DIS and DTC messages. This will be edited for - the dynamically changing capabilities (e.g. can receive) just before - it is sent. It might also be edited if the application changes our - capabilities (e.g. disabling fine mode). Right now we set up all the - unchanging stuff about what we are capable of doing. */ - s->local_dis_dtc_frame[0] = ADDRESS_FIELD; - s->local_dis_dtc_frame[1] = CONTROL_FIELD_FINAL_FRAME; - s->local_dis_dtc_frame[2] = (uint8_t) (T30_DIS | s->dis_received); - for (i = 3; i < 19; i++) - s->local_dis_dtc_frame[i] = 0x00; - - /* Always say 256 octets per ECM frame preferred, as 64 is never used in the - real world. */ - if ((s->iaf & T30_IAF_MODE_T37)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T37); - if ((s->iaf & T30_IAF_MODE_T38)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T38); - /* No 3G mobile */ - /* No V.8 */ - /* 256 octets preferred - don't bother making this optional, as everything uses 256 */ - /* Ready to transmit a fax (polling) will be determined separately, and this message edited. */ - /* Ready to receive a fax will be determined separately, and this message edited. */ - /* With no modems set we are actually selecting V.27ter fallback at 2400bps */ - if ((s->supported_modems & T30_SUPPORT_V27TER)) - set_ctrl_bit(s->local_dis_dtc_frame, 12); - if ((s->supported_modems & T30_SUPPORT_V29)) - set_ctrl_bit(s->local_dis_dtc_frame, 11); - /* V.17 is only valid when combined with V.29 and V.27ter, so if we enable V.17 we force the others too. */ - if ((s->supported_modems & T30_SUPPORT_V17)) - s->local_dis_dtc_frame[4] |= (DISBIT6 | DISBIT4 | DISBIT3); - if ((s->supported_resolutions & T30_SUPPORT_FINE_RESOLUTION)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_200_200_CAPABLE); - if ((s->supported_compressions & T30_SUPPORT_T4_2D_COMPRESSION)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_2D_CAPABLE); - /* 215mm wide is always supported */ - if ((s->supported_image_sizes & T30_SUPPORT_303MM_WIDTH)) - set_ctrl_bit(s->local_dis_dtc_frame, 18); - else if ((s->supported_image_sizes & T30_SUPPORT_255MM_WIDTH)) - set_ctrl_bit(s->local_dis_dtc_frame, 17); - /* A4 is always supported. */ - if ((s->supported_image_sizes & T30_SUPPORT_UNLIMITED_LENGTH)) - set_ctrl_bit(s->local_dis_dtc_frame, 20); - else if ((s->supported_image_sizes & T30_SUPPORT_B4_LENGTH)) - set_ctrl_bit(s->local_dis_dtc_frame, 19); - /* 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, 21); - if ((s->supported_compressions & T30_SUPPORT_NO_COMPRESSION)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_UNCOMPRESSED_CAPABLE); - if (s->ecm_allowed) - { - /* ECM allowed */ - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_ECM_CAPABLE); - /* Only offer the option of fancy compression schemes, if we are - also offering the ECM option needed to support them. */ - if ((s->supported_compressions & T30_SUPPORT_T6_COMPRESSION)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T6_CAPABLE); - if ((s->supported_compressions & T30_SUPPORT_T43_COMPRESSION)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T43_CAPABLE); - if ((s->supported_compressions & T30_SUPPORT_T45_COMPRESSION)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T45_CAPABLE); - if ((s->supported_compressions & T30_SUPPORT_T81_COMPRESSION)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T81_CAPABLE); - if ((s->supported_compressions & T30_SUPPORT_SYCC_T81_COMPRESSION)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_SYCC_T81_CAPABLE); - if ((s->supported_compressions & T30_SUPPORT_T85_COMPRESSION)) - { - /* Bit 79 set with bit 78 clear is invalid, so only check for L0 - support here. */ - if ((s->supported_compressions & T30_SUPPORT_T85_L0_COMPRESSION)) - 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_CAPABLE); - } - //if ((s->supported_compressions & T30_SUPPORT_T89_COMPRESSION)) - // set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T89_CAPABLE); - } - if ((s->supported_t30_features & T30_SUPPORT_FIELD_NOT_VALID)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_FNV_CAPABLE); - if ((s->supported_t30_features & T30_SUPPORT_MULTIPLE_SELECTIVE_POLLING)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_MULTIPLE_SELECTIVE_POLLING_CAPABLE); - if ((s->supported_t30_features & T30_SUPPORT_POLLED_SUB_ADDRESSING)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_POLLED_SUBADDRESSING_CAPABLE); - /* No plane interleave */ - /* No G.726 */ - /* No extended voice coding */ - if ((s->supported_resolutions & T30_SUPPORT_SUPERFINE_RESOLUTION)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_200_400_CAPABLE); - if ((s->supported_resolutions & T30_SUPPORT_300_300_RESOLUTION)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_300_300_CAPABLE); - if ((s->supported_resolutions & (T30_SUPPORT_400_400_RESOLUTION | T30_SUPPORT_R16_RESOLUTION))) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_400_400_CAPABLE); - /* Metric */ - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_METRIC_RESOLUTION_PREFERRED); - /* Superfine minimum scan line time pattern follows fine */ - if ((s->supported_t30_features & T30_SUPPORT_SELECTIVE_POLLING)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_SELECTIVE_POLLING_CAPABLE); - if ((s->supported_t30_features & T30_SUPPORT_SUB_ADDRESSING)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_SUBADDRESSING_CAPABLE); - if ((s->supported_t30_features & T30_SUPPORT_IDENTIFICATION)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_PASSWORD); - /* Ready to transmit a data file (polling) */ - if (s->tx_file[0]) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_READY_TO_TRANSMIT_DATA_FILE); - /* No Binary file transfer (BFT) */ - /* No Document transfer mode (DTM) */ - /* No Electronic data interchange (EDI) */ - /* No Basic transfer mode (BTM) */ - /* No mixed mode (polling) */ - /* No character mode */ - /* No mixed mode (T.4/Annex E) */ - /* No mode 26 (T.505) */ - /* No digital network capability */ - /* No duplex operation */ - /* No JPEG */ - /* No full colour */ - /* No 12bits/pel */ - /* No sub-sampling (1:1:1) */ - /* No custom illuminant */ - /* No custom gamut range */ - if ((s->supported_image_sizes & T30_SUPPORT_US_LETTER_LENGTH)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NORTH_AMERICAN_LETTER_CAPABLE); - if ((s->supported_image_sizes & T30_SUPPORT_US_LEGAL_LENGTH)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_NORTH_AMERICAN_LEGAL_CAPABLE); - /* No HKM key management */ - /* No RSA key management */ - /* No override */ - /* No HFX40 cipher */ - /* No alternative cipher number 2 */ - /* No alternative cipher number 3 */ - /* No HFX40-I hashing */ - /* No alternative hashing system number 2 */ - /* No alternative hashing system number 3 */ - /* No T.44 (mixed raster content) */ - /* No page length maximum strip size for T.44 (mixed raster content) */ - /* No colour/grey scale 300x300 or 400x400 */ - /* No colour/grey scale 100x100 */ - /* No simple phase C BFT negotiations */ - /* No extended BFT negotiations */ - if ((s->supported_t30_features & T30_SUPPORT_INTERNET_SELECTIVE_POLLING_ADDRESS)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_INTERNET_SELECTIVE_POLLING_ADDRESS); - if ((s->supported_t30_features & T30_SUPPORT_INTERNET_ROUTING_ADDRESS)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_INTERNET_ROUTING_ADDRESS); - if ((s->supported_resolutions & T30_SUPPORT_600_600_RESOLUTION)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_600_600_CAPABLE); - if ((s->supported_resolutions & T30_SUPPORT_1200_1200_RESOLUTION)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_1200_1200_CAPABLE); - if ((s->supported_resolutions & T30_SUPPORT_300_600_RESOLUTION)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_300_600_CAPABLE); - if ((s->supported_resolutions & T30_SUPPORT_400_800_RESOLUTION)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_400_800_CAPABLE); - if ((s->supported_resolutions & T30_SUPPORT_600_1200_RESOLUTION)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_600_1200_CAPABLE); - /* No colour/grey scale 600x600 */ - /* No colour/grey scale 1200x1200 */ - /* No double sided printing (alternate mode) */ - /* No double sided printing (continuous mode) */ - /* No black and white mixed raster content profile */ - /* No shared data memory */ - /* No T.44 colour space */ - if ((s->iaf & T30_IAF_MODE_FLOW_CONTROL)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T38_FLOW_CONTROL_CAPABLE); - /* No k > 4 */ - if ((s->iaf & T30_IAF_MODE_CONTINUOUS_FLOW)) - set_ctrl_bit(s->local_dis_dtc_frame, T30_DIS_BIT_T38_FAX_CAPABLE); - /* No T.88/T.89 profile */ - s->local_dis_dtc_len = 19; - //t30_decode_dis_dtc_dcs(s, s->local_dis_dtc_frame, s->local_dis_dtc_len); - return 0; -} -/*- End of function --------------------------------------------------------*/ - static int prune_dis_dtc(t30_state_t *s) { int i; /* Find the last octet that is really needed, set the extension bits, and trim the message length */ - for (i = 18; i >= 6; i--) + for (i = T30_MAX_DIS_DTC_DCS_LEN - 1; i >= 6; i--) { /* Strip the top bit */ s->local_dis_dtc_frame[i] &= (DISBIT1 | DISBIT2 | DISBIT3 | DISBIT4 | DISBIT5 | DISBIT6 | DISBIT7); @@ -1344,23 +1450,33 @@ static int prune_dis_dtc(t30_state_t *s) static int build_dcs(t30_state_t *s) { int i; - int bad; - int row_squashing_ratio; + int use_bilevel; + int image_type; - /* 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. */ + /* Reacquire page information, in case the image was resized, flattened, etc. */ + s->current_page_resolution = t4_tx_get_tx_resolution(&s->t4.tx); + s->x_resolution = t4_tx_get_tx_x_resolution(&s->t4.tx); + s->y_resolution = t4_tx_get_tx_y_resolution(&s->t4.tx); + s->image_width = t4_tx_get_tx_image_width(&s->t4.tx); + image_type = t4_tx_get_tx_image_type(&s->t4.tx); + + /* 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. */ s->dcs_frame[0] = ADDRESS_FIELD; s->dcs_frame[1] = CONTROL_FIELD_FINAL_FRAME; s->dcs_frame[2] = (uint8_t) (T30_DCS | s->dis_received); - for (i = 3; i < 19; i++) + for (i = 3; i < T30_MAX_DIS_DTC_DCS_LEN; i++) s->dcs_frame[i] = 0x00; + /* We have a file to send, so tell the far end to go into receive mode. */ + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_RECEIVE_FAX_DOCUMENT); + #if 0 /* Check for T.37 simple mode. */ - if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T37)) + if ((s->iaf & T30_IAF_MODE_T37) && test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T37)) set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T37); /* Check for T.38 mode. */ - if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T38)) + if ((s->iaf & T30_IAF_MODE_T38) && test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T38)) set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T38); #endif @@ -1368,267 +1484,182 @@ static int build_dcs(t30_state_t *s) s->dcs_frame[4] |= fallback_sequence[s->current_fallback].dcs_code; /* Select the compression to use. */ - switch (s->line_encoding) + use_bilevel = true; + set_ctrl_bits(s->dcs_frame, s->min_scan_time_code, T30_DCS_BIT_MIN_SCAN_LINE_TIME_1); + switch (s->line_compression) { - case T4_COMPRESSION_ITU_T42: - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_FULL_COLOUR_MODE); - set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, 21); + case T4_COMPRESSION_T4_1D: + /* There is nothing to set to select this encoding. */ break; -#if defined(SPANDSP_SUPPORT_T43) - case T4_COMPRESSION_ITU_T43: - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T43_MODE); - set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, 21); + case T4_COMPRESSION_T4_2D: + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_2D_MODE); + break; + case T4_COMPRESSION_T6: + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T6_MODE); + break; + case T4_COMPRESSION_T85: + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T85_MODE); + break; + case T4_COMPRESSION_T85_L0: + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T85_L0_MODE); + break; +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: break; #endif - case T4_COMPRESSION_ITU_T85_L0: - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T85_L0_MODE); - set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, 21); + case T4_COMPRESSION_T42_T81: + 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) + 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) + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_12BIT_COMPONENT); + //if (???????? & T4_COMPRESSION_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); + use_bilevel = false; break; - case T4_COMPRESSION_ITU_T85: - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T85_MODE); - set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, 21); + case T4_COMPRESSION_T43: + 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) + 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) + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_12BIT_COMPONENT); + set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, T30_DCS_BIT_MIN_SCAN_LINE_TIME_1); + use_bilevel = false; break; - case T4_COMPRESSION_ITU_T6: - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T6_MODE); - set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, 21); +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + use_bilevel = false; break; - case T4_COMPRESSION_ITU_T4_2D: - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_2D_MODE); - set_ctrl_bits(s->dcs_frame, s->min_scan_time_code, 21); - break; - case T4_COMPRESSION_ITU_T4_1D: - set_ctrl_bits(s->dcs_frame, s->min_scan_time_code, 21); +#endif +#if defined(SPANDSP_SUPPORT_SYCC_T81) + case T4_COMPRESSION_SYCC_T81: + use_bilevel = false; break; +#endif default: - set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, 21); + set_ctrl_bits(s->dcs_frame, T30_MIN_SCAN_0MS, T30_DCS_BIT_MIN_SCAN_LINE_TIME_1); break; } - /* We have a file to send, so tell the far end to go into receive mode. */ - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_RECEIVE_FAX_DOCUMENT); - /* Set the Y resolution bits */ - bad = T30_ERR_NORESSUPPORT; - row_squashing_ratio = 1; - switch (s->y_resolution) - { - case T4_Y_RESOLUTION_1200: - switch (s->x_resolution) - { - case T4_X_RESOLUTION_600: - if ((s->supported_resolutions & T30_SUPPORT_600_1200_RESOLUTION) && test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_600_1200_CAPABLE)) - { - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_600_1200); - bad = T30_ERR_OK; - } - break; - case T4_X_RESOLUTION_1200: - if ((s->supported_resolutions & T30_SUPPORT_1200_1200_RESOLUTION) && test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_1200_1200_CAPABLE)) - { - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_1200_1200); - bad = T30_ERR_OK; - } - break; - } - break; - case T4_Y_RESOLUTION_800: - switch (s->x_resolution) - { - case T4_X_RESOLUTION_R16: - if ((s->supported_resolutions & T30_SUPPORT_400_800_RESOLUTION) && test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_400_800_CAPABLE)) - { - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_400_800); - bad = T30_ERR_OK; - } - break; - } - break; - case T4_Y_RESOLUTION_600: - switch (s->x_resolution) - { - case T4_X_RESOLUTION_300: - if ((s->supported_resolutions & T30_SUPPORT_300_600_RESOLUTION) && test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_300_600_CAPABLE)) - { - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_300_600); - bad = T30_ERR_OK; - } - break; - case T4_X_RESOLUTION_600: - if ((s->supported_resolutions & T30_SUPPORT_600_600_RESOLUTION) && test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_600_600_CAPABLE)) - { - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_600_600); - bad = T30_ERR_OK; - } - break; - } - break; - case T4_Y_RESOLUTION_300: - switch (s->x_resolution) - { - case T4_X_RESOLUTION_300: - if ((s->supported_resolutions & T30_SUPPORT_300_300_RESOLUTION) && test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_300_300_CAPABLE)) - { - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_300_300); - bad = T30_ERR_OK; - } - break; - } - break; - case T4_Y_RESOLUTION_SUPERFINE: - if ((s->supported_resolutions & T30_SUPPORT_SUPERFINE_RESOLUTION)) - { - if (s->x_resolution == T4_X_RESOLUTION_R16 && test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_400_400_CAPABLE)) - { - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_400_400); - bad = T30_ERR_OK; - break; - } - if (s->x_resolution == T4_X_RESOLUTION_R8 && test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_200_400_CAPABLE)) - { - 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: - if ((s->supported_resolutions & T30_SUPPORT_FINE_RESOLUTION) && test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_200_200_CAPABLE)) - { - switch (s->x_resolution) - { - case T4_X_RESOLUTION_R8: - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_200_200); - bad = T30_ERR_OK; - break; - } - break; - } - row_squashing_ratio <<= 1; - /* Fall through */ - default: - case T4_Y_RESOLUTION_STANDARD: - switch (s->x_resolution) - { - case T4_X_RESOLUTION_R8: - /* No bits to set for this */ - bad = T30_ERR_OK; - break; - } - break; - } - t4_tx_set_row_squashing_ratio(&s->t4.tx, row_squashing_ratio); - if (bad != T30_ERR_OK) - { - t30_set_status(s, bad); - span_log(&s->logging, SPAN_LOG_FLOW, "Image resolution (%d x %d) not acceptable\n", s->x_resolution, s->y_resolution); - return -1; - } - /* Deal with the image width. */ - /* Low (R4) res widths are not supported in recent versions of T.30 */ - bad = T30_ERR_OK; - /* The following treats a width field of 11 like 10, which does what note 6 of Table 2/T.30 - says we should do with the invalid value 11. */ - if (((s->image_width == T4_WIDTH_R8_A4) && (s->x_resolution == T4_X_RESOLUTION_R8)) - || - ((s->image_width == T4_WIDTH_300_A4) && (s->x_resolution == T4_X_RESOLUTION_300)) - || - ((s->image_width == T4_WIDTH_R16_A4) && (s->x_resolution == T4_X_RESOLUTION_R16)) - || - ((s->image_width == T4_WIDTH_600_A4) && (s->x_resolution == T4_X_RESOLUTION_600)) - || - ((s->image_width == T4_WIDTH_1200_A4) && (s->x_resolution == T4_X_RESOLUTION_1200))) + /* Set the image width */ + switch (s->line_width_code) { - span_log(&s->logging, SPAN_LOG_FLOW, "Image width is A4\n"); + case T4_SUPPORT_WIDTH_215MM: + span_log(&s->logging, SPAN_LOG_FLOW, "Image width is A4 at %ddpm x %ddpm\n", s->x_resolution, s->y_resolution); /* No width related bits need to be set. */ - } - else if (((s->image_width == T4_WIDTH_R8_B4) && (s->x_resolution == T4_X_RESOLUTION_R8)) - || - ((s->image_width == T4_WIDTH_300_B4) && (s->x_resolution == T4_X_RESOLUTION_300)) - || - ((s->image_width == T4_WIDTH_R16_B4) && (s->x_resolution == T4_X_RESOLUTION_R16)) - || - ((s->image_width == T4_WIDTH_600_B4) && (s->x_resolution == T4_X_RESOLUTION_600)) - || - ((s->image_width == T4_WIDTH_1200_B4) && (s->x_resolution == T4_X_RESOLUTION_1200))) - { - if (((s->far_dis_dtc_frame[5] & (DISBIT2 | DISBIT1)) >= 1) - && - (s->supported_image_sizes & T30_SUPPORT_255MM_WIDTH)) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Image width is B4\n"); - set_ctrl_bit(s->dcs_frame, 17); - } - else - { - /* We do not support this width and resolution combination */ - bad = T30_ERR_NOSIZESUPPORT; - } - } - else if (((s->image_width == T4_WIDTH_R8_A3) && (s->x_resolution == T4_X_RESOLUTION_R8)) - || - ((s->image_width == T4_WIDTH_300_A3) && (s->x_resolution == T4_X_RESOLUTION_300)) - || - ((s->image_width == T4_WIDTH_R16_A3) && (s->x_resolution == T4_X_RESOLUTION_R16)) - || - ((s->image_width == T4_WIDTH_600_A3) && (s->x_resolution == T4_X_RESOLUTION_600)) - || - ((s->image_width == T4_WIDTH_1200_A3) && (s->x_resolution == T4_X_RESOLUTION_1200))) - { - if (((s->far_dis_dtc_frame[5] & (DISBIT2 | DISBIT1)) >= 2) - && - (s->supported_image_sizes & T30_SUPPORT_303MM_WIDTH)) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Image width is A3\n"); - set_ctrl_bit(s->dcs_frame, 18); - } - else - { - /* We do not support this width and resolution combination */ - bad = T30_ERR_NOSIZESUPPORT; - } - } - else - { - /* We do not support this width and resolution combination */ - bad = T30_ERR_NOSIZESUPPORT; + break; + case T4_SUPPORT_WIDTH_255MM: + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_255MM_WIDTH); + span_log(&s->logging, SPAN_LOG_FLOW, "Image width is B4 at %ddpm x %ddpm\n", s->x_resolution, s->y_resolution); + break; + case T4_SUPPORT_WIDTH_303MM: + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_303MM_WIDTH); + span_log(&s->logging, SPAN_LOG_FLOW, "Image width is A3 at %ddpm x %ddpm\n", s->x_resolution, s->y_resolution); + break; } - if (bad != T30_ERR_OK) - { - t30_set_status(s, bad); - span_log(&s->logging, - SPAN_LOG_FLOW, - "Image width (%d pixels) and resolution (%d x %d) is not an acceptable\n", - s->image_width, - s->x_resolution, - s->y_resolution); - return -1; - } - - /* Deal with the image length */ + /* Set the image length */ /* 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. */ - if (test_ctrl_bit(s->far_dis_dtc_frame, 20)) - set_ctrl_bit(s->dcs_frame, 20); - else if (test_ctrl_bit(s->far_dis_dtc_frame, 19)) - set_ctrl_bit(s->dcs_frame, 19); + if ((s->mutual_image_sizes & T4_SUPPORT_LENGTH_UNLIMITED)) + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_UNLIMITED_LENGTH); + else if ((s->mutual_image_sizes & T4_SUPPORT_LENGTH_B4)) + 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); + + /* Set the Y resolution bits */ + switch (s->current_page_resolution) + { + case T4_RESOLUTION_1200_1200: + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_1200_1200); + 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_1200_1200); + break; + case T4_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); + break; + case T4_RESOLUTION_600_600: + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_600_600); + 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_600_600); + break; + case T4_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); + break; + case T4_RESOLUTION_400_400: + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_400_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; + } if (s->error_correcting_mode) - set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_ECM); + set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_ECM_MODE); if ((s->iaf & T30_IAF_MODE_FLOW_CONTROL) && test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T38_FLOW_CONTROL_CAPABLE)) set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T38_FLOW_CONTROL_CAPABLE); + if ((s->iaf & T30_IAF_MODE_CONTINUOUS_FLOW) && test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T38_FAX_CAPABLE)) { /* Clear the modem type bits, in accordance with note 77 of Table 2/T.30 */ - clr_ctrl_bit(s->local_dis_dtc_frame, 11); - clr_ctrl_bit(s->local_dis_dtc_frame, 12); - clr_ctrl_bit(s->local_dis_dtc_frame, 13); - clr_ctrl_bit(s->local_dis_dtc_frame, 14); + clr_ctrl_bit(s->local_dis_dtc_frame, T30_DCS_BIT_MODEM_TYPE_1); + clr_ctrl_bit(s->local_dis_dtc_frame, T30_DCS_BIT_MODEM_TYPE_2); + clr_ctrl_bit(s->local_dis_dtc_frame, T30_DCS_BIT_MODEM_TYPE_3); + clr_ctrl_bit(s->local_dis_dtc_frame, T30_DCS_BIT_MODEM_TYPE_4); set_ctrl_bit(s->dcs_frame, T30_DCS_BIT_T38_FAX_MODE); } s->dcs_len = 19; - //t30_decode_dis_dtc_dcs(s, s->dcs_frame, s->dcs_len); return 0; } /*- End of function --------------------------------------------------------*/ @@ -1638,7 +1669,7 @@ static int prune_dcs(t30_state_t *s) int i; /* Find the last octet that is really needed, set the extension bits, and trim the message length */ - for (i = 18; i >= 6; i--) + for (i = T30_MAX_DIS_DTC_DCS_LEN - 1; i >= 6; i--) { /* Strip the top bit */ s->dcs_frame[i] &= (DISBIT1 | DISBIT2 | DISBIT3 | DISBIT4 | DISBIT5 | DISBIT6 | DISBIT7); @@ -1656,41 +1687,580 @@ static int prune_dcs(t30_state_t *s) } /*- End of function --------------------------------------------------------*/ -static int step_fallback_entry(t30_state_t *s) +static int analyze_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len) { - int min_row_bits; - - while (fallback_sequence[++s->current_fallback].which) + t30_decode_dis_dtc_dcs(s, msg, len); + if (len < 6) { - if ((fallback_sequence[s->current_fallback].which & s->current_permitted_modems)) - break; - } - if (fallback_sequence[s->current_fallback].which == 0) + span_log(&s->logging, SPAN_LOG_FLOW, "Short DIS/DTC frame\n"); return -1; - /* TODO: This only sets the minimum row time for future pages. It doesn't fix up the - current page, though it is benign - fallback will only result in an excessive - minimum. */ - min_row_bits = set_min_scan_time_code(s); - t4_tx_set_min_bits_per_row(&s->t4.tx, min_row_bits); - /* We need to rebuild the DCS message we will send. */ - build_dcs(s); - return s->current_fallback; + } + + if (msg[2] == T30_DIS) + s->dis_received = true; + + /* Make a local copy of the message, padded to the maximum possible length with zeros. This allows + us to simply pick out the bits, without worrying about whether they were set from the remote side. */ + if (len > T30_MAX_DIS_DTC_DCS_LEN) + len = T30_MAX_DIS_DTC_DCS_LEN; + memcpy(s->far_dis_dtc_frame, msg, len); + if (len < T30_MAX_DIS_DTC_DCS_LEN) + memset(s->far_dis_dtc_frame + len, 0, T30_MAX_DIS_DTC_DCS_LEN - len); + + s->error_correcting_mode = (s->ecm_allowed && test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_ECM_CAPABLE)); + /* Always use 256 octets per ECM frame, whatever the other end says it is capable of */ + s->octets_per_ecm_frame = 256; + + /* Now we know if we are going to use ECM, select the compressions which we can use. */ + s->mutual_compressions = s->supported_compressions; + if (!s->error_correcting_mode) + { + /* Remove any compression schemes which need error correction to work. */ + s->mutual_compressions &= (0xFF800000 | T4_COMPRESSION_NONE | T4_COMPRESSION_T4_1D | T4_COMPRESSION_T4_2D); + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_2D_CAPABLE)) + s->mutual_compressions &= ~T4_COMPRESSION_T4_2D; + } + else + { + /* Check the bi-level capabilities */ + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_2D_CAPABLE)) + s->mutual_compressions &= ~T4_COMPRESSION_T4_2D; + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T6_CAPABLE)) + s->mutual_compressions &= ~T4_COMPRESSION_T6; + /* 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. */ + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T85_CAPABLE)) + s->mutual_compressions &= ~(T4_COMPRESSION_T85 | T4_COMPRESSION_T85_L0); + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T85_L0_CAPABLE)) + s->mutual_compressions &= ~T4_COMPRESSION_T85_L0; + + /* 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)) + s->mutual_compressions &= ~T4_COMPRESSION_COLOUR; + + /* Check the colour capabilities */ + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T81_CAPABLE)) + s->mutual_compressions &= ~T4_COMPRESSION_T42_T81; + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_SYCC_T81_CAPABLE)) + s->mutual_compressions &= ~T4_COMPRESSION_SYCC_T81; + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T43_CAPABLE)) + s->mutual_compressions &= ~T4_COMPRESSION_T43; + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T45_CAPABLE)) + s->mutual_compressions &= ~T4_COMPRESSION_T45; + + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_12BIT_CAPABLE)) + s->mutual_compressions &= ~T4_COMPRESSION_12BIT; + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_NO_SUBSAMPLING)) + s->mutual_compressions &= ~T4_COMPRESSION_NO_SUBSAMPLING; + + /* bit74 custom illuminant */ + /* bit75 custom gamut range */ + } + + s->mutual_bilevel_resolutions = s->supported_bilevel_resolutions; + s->mutual_colour_resolutions = s->supported_colour_resolutions; + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_1200_1200_CAPABLE)) + { + s->mutual_bilevel_resolutions &= ~T4_RESOLUTION_1200_1200; + s->mutual_colour_resolutions &= ~T4_RESOLUTION_1200_1200; + } + else + { + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_COLOUR_GRAY_1200_1200_CAPABLE)) + s->mutual_colour_resolutions &= ~T4_RESOLUTION_1200_1200; + } + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_600_1200_CAPABLE)) + s->mutual_bilevel_resolutions &= ~T4_RESOLUTION_600_1200; + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_600_600_CAPABLE)) + { + s->mutual_bilevel_resolutions &= ~T4_RESOLUTION_600_600; + s->mutual_colour_resolutions &= ~T4_RESOLUTION_600_600; + } + else + { + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_COLOUR_GRAY_600_600_CAPABLE)) + s->mutual_colour_resolutions &= ~T4_RESOLUTION_600_600; + } + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_400_800_CAPABLE)) + s->mutual_bilevel_resolutions &= ~T4_RESOLUTION_400_800; + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_400_400_CAPABLE)) + { + s->mutual_bilevel_resolutions &= ~(T4_RESOLUTION_400_400 | T4_RESOLUTION_R16_SUPERFINE); + s->mutual_colour_resolutions &= ~T4_RESOLUTION_400_400; + } + else + { + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_COLOUR_GRAY_300_300_400_400_CAPABLE)) + s->mutual_colour_resolutions &= ~T4_RESOLUTION_400_400; + } + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_300_600_CAPABLE)) + s->mutual_bilevel_resolutions &= ~T4_RESOLUTION_300_600; + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_300_300_CAPABLE)) + { + s->mutual_bilevel_resolutions &= ~T4_RESOLUTION_300_300; + s->mutual_colour_resolutions &= ~T4_RESOLUTION_300_300; + } + else + { + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_COLOUR_GRAY_300_300_400_400_CAPABLE)) + s->mutual_colour_resolutions &= ~T4_RESOLUTION_300_300; + } + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_200_400_CAPABLE)) + s->mutual_bilevel_resolutions &= ~(T4_RESOLUTION_200_400 | T4_RESOLUTION_R8_SUPERFINE); + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_200_200_CAPABLE)) + { + s->mutual_bilevel_resolutions &= ~(T4_RESOLUTION_200_200 | T4_RESOLUTION_R8_FINE); + s->mutual_colour_resolutions &= ~T4_RESOLUTION_200_200; + } + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_INCH_RESOLUTION_PREFERRED)) + s->mutual_bilevel_resolutions &= ~T4_RESOLUTION_200_100; + /* Never suppress T4_RESOLUTION_R8_STANDARD */ + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_COLOUR_GRAY_100_100_CAPABLE)) + s->mutual_colour_resolutions &= ~T4_RESOLUTION_100_100; + + s->mutual_image_sizes = s->supported_image_sizes; + /* 215mm wide is always supported */ + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_215MM_255MM_303MM_WIDTH_CAPABLE)) + { + s->mutual_image_sizes &= ~T4_SUPPORT_WIDTH_303MM; + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_215MM_255MM_WIDTH_CAPABLE)) + s->mutual_image_sizes &= ~T4_SUPPORT_WIDTH_255MM; + } + /* A4 is always supported. */ + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_UNLIMITED_LENGTH_CAPABLE)) + { + s->mutual_image_sizes &= ~T4_SUPPORT_LENGTH_UNLIMITED; + if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_A4_B4_LENGTH_CAPABLE)) + s->mutual_image_sizes &= ~T4_SUPPORT_LENGTH_B4; + } + 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; + 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; + + switch (s->far_dis_dtc_frame[4] & (DISBIT6 | DISBIT5 | DISBIT4 | DISBIT3)) + { + case (DISBIT6 | DISBIT4 | DISBIT3): + if ((s->supported_modems & T30_SUPPORT_V17)) + { + s->current_permitted_modems = T30_SUPPORT_V17 | T30_SUPPORT_V29 | T30_SUPPORT_V27TER; + s->current_fallback = T30_V17_FALLBACK_START; + break; + } + /* Fall through */ + case (DISBIT4 | DISBIT3): + if ((s->supported_modems & T30_SUPPORT_V29)) + { + s->current_permitted_modems = T30_SUPPORT_V29 | T30_SUPPORT_V27TER; + s->current_fallback = T30_V29_FALLBACK_START; + break; + } + /* Fall through */ + case DISBIT4: + s->current_permitted_modems = T30_SUPPORT_V27TER; + s->current_fallback = T30_V27TER_FALLBACK_START; + break; + case 0: + s->current_permitted_modems = T30_SUPPORT_V27TER; + s->current_fallback = T30_V27TER_FALLBACK_START + 1; + break; + case DISBIT3: + if ((s->supported_modems & T30_SUPPORT_V29)) + { + /* TODO: this doesn't allow for skipping the V.27ter modes */ + s->current_permitted_modems = T30_SUPPORT_V29; + s->current_fallback = T30_V29_FALLBACK_START; + break; + } + /* Fall through */ + default: + span_log(&s->logging, SPAN_LOG_FLOW, "Remote does not support a compatible modem\n"); + /* We cannot talk to this machine! */ + t30_set_status(s, T30_ERR_INCOMPATIBLE); + return -1; + } + return 0; } /*- End of function --------------------------------------------------------*/ -static int find_fallback_entry(int dcs_code) +static int analyze_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) { - int i; - - /* The table is short, and not searched often, so a brain-dead linear scan seems OK */ - for (i = 0; fallback_sequence[i].bit_rate; i++) + /* The following treats a width field of 11 like 10, which does what note 6 of Table 2/T.30 + says we should do with the invalid value 11. */ + static const int widths[6][4] = { - if (fallback_sequence[i].dcs_code == dcs_code) - break; - } - if (fallback_sequence[i].bit_rate == 0) + { T4_WIDTH_100_A4, T4_WIDTH_100_B4, T4_WIDTH_100_A3, T4_WIDTH_100_A3}, /* 100/inch */ + { T4_WIDTH_200_A4, T4_WIDTH_200_B4, T4_WIDTH_200_A3, T4_WIDTH_200_A3}, /* 200/inch / R8 resolution */ + { T4_WIDTH_300_A4, T4_WIDTH_300_B4, T4_WIDTH_300_A3, T4_WIDTH_300_A3}, /* 300/inch resolution */ + { T4_WIDTH_400_A4, T4_WIDTH_400_B4, T4_WIDTH_400_A3, T4_WIDTH_400_A3}, /* 400/inch / R16 resolution */ + { T4_WIDTH_600_A4, T4_WIDTH_600_B4, T4_WIDTH_600_A3, T4_WIDTH_600_A3}, /* 600/inch resolution */ + {T4_WIDTH_1200_A4, T4_WIDTH_1200_B4, T4_WIDTH_1200_A3, T4_WIDTH_1200_A3} /* 1200/inch resolution */ + }; + uint8_t dcs_frame[T30_MAX_DIS_DTC_DCS_LEN]; + int i; + int x; + + t30_decode_dis_dtc_dcs(s, msg, len); + if (len < 6) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Short DCS frame\n"); return -1; - return i; + } + + /* Make an ASCII string format copy of the message, for logging in the + received file. This string does not include the frame header octets. */ + sprintf(s->rx_dcs_string, "%02X", bit_reverse8(msg[3])); + for (i = 4; i < len; i++) + sprintf(s->rx_dcs_string + 3*i - 10, " %02X", bit_reverse8(msg[i])); + + /* Make a local copy of the message, padded to the maximum possible length with zeros. This allows + us to simply pick out the bits, without worrying about whether they were set from the remote side. */ + if (len > T30_MAX_DIS_DTC_DCS_LEN) + len = T30_MAX_DIS_DTC_DCS_LEN; + memcpy(dcs_frame, msg, len); + if (len < T30_MAX_DIS_DTC_DCS_LEN) + memset(dcs_frame + len, 0, T30_MAX_DIS_DTC_DCS_LEN - len); + + s->error_correcting_mode = (test_ctrl_bit(dcs_frame, T30_DCS_BIT_ECM_MODE) != 0); + s->octets_per_ecm_frame = test_ctrl_bit(dcs_frame, T30_DCS_BIT_64_OCTET_ECM_FRAMES) ? 256 : 64; + + s->x_resolution = -1; + s->y_resolution = -1; + s->current_page_resolution = 0; + s->line_compression = -1; + x = -1; + if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T81_MODE) + || + test_ctrl_bit(dcs_frame, T30_DCS_BIT_T43_MODE) + || + test_ctrl_bit(dcs_frame, T30_DCS_BIT_T45_MODE) + || + test_ctrl_bit(dcs_frame, T30_DCS_BIT_SYCC_T81_MODE)) + { + /* Gray scale or colour image */ + + /* Note 35 of Table 2/T.30 */ + if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_FULL_COLOUR_MODE)) + { + if ((s->supported_colour_resolutions & T4_COMPRESSION_COLOUR)) + { + /* We are going to work in full colour mode */ + } + } + + if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_12BIT_COMPONENT)) + { + if ((s->supported_colour_resolutions & T4_COMPRESSION_12BIT)) + { + /* We are going to work in 12 bit mode */ + } + } + + if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_NO_SUBSAMPLING)) + { + //???? = T4_COMPRESSION_NO_SUBSAMPLING; + } + + if (!test_ctrl_bit(dcs_frame, T30_DCS_BIT_PREFERRED_HUFFMAN_TABLES)) + { + //???? = T4_COMPRESSION_T42_T81_HUFFMAN; + } + + if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_COLOUR_GRAY_1200_1200)) + { + if ((s->supported_colour_resolutions & T4_RESOLUTION_1200_1200)) + { + s->x_resolution = T4_X_RESOLUTION_1200; + s->y_resolution = T4_Y_RESOLUTION_1200; + s->current_page_resolution = T4_RESOLUTION_1200_1200; + x = 5; + } + } + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_COLOUR_GRAY_600_600)) + { + if ((s->supported_colour_resolutions & T4_RESOLUTION_600_600)) + { + s->x_resolution = T4_X_RESOLUTION_600; + s->y_resolution = T4_Y_RESOLUTION_600; + s->current_page_resolution = T4_RESOLUTION_600_600; + x = 4; + } + } + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_400_400)) + { + if ((s->supported_colour_resolutions & T4_RESOLUTION_400_400)) + { + s->x_resolution = T4_X_RESOLUTION_400; + s->y_resolution = T4_Y_RESOLUTION_400; + s->current_page_resolution = T4_RESOLUTION_400_400; + x = 3; + } + } + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_300_300)) + { + if ((s->supported_colour_resolutions & T4_RESOLUTION_300_300)) + { + s->x_resolution = T4_X_RESOLUTION_300; + s->y_resolution = T4_Y_RESOLUTION_300; + s->current_page_resolution = T4_RESOLUTION_300_300; + x = 2; + } + } + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_200_200)) + { + if ((s->supported_colour_resolutions & T4_RESOLUTION_200_200)) + { + s->x_resolution = T4_X_RESOLUTION_200; + s->y_resolution = T4_Y_RESOLUTION_200; + s->current_page_resolution = T4_RESOLUTION_200_200; + x = 1; + } + } + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_COLOUR_GRAY_100_100)) + { + if ((s->supported_colour_resolutions & T4_RESOLUTION_100_100)) + { + s->x_resolution = T4_X_RESOLUTION_100; + s->y_resolution = T4_Y_RESOLUTION_100; + s->current_page_resolution = T4_RESOLUTION_100_100; + 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_COMPRESSION_T42_T81)) + s->line_compression = T4_COMPRESSION_T42_T81; + } + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T43_MODE)) + { + if ((s->supported_compressions & T4_COMPRESSION_T43)) + s->line_compression = T4_COMPRESSION_T43; + } + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T45_MODE)) + { + if ((s->supported_compressions & T4_COMPRESSION_T45)) + s->line_compression = T4_COMPRESSION_T45; + } + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_SYCC_T81_MODE)) + { + if ((s->supported_compressions & T4_COMPRESSION_SYCC_T81)) + s->line_compression = T4_COMPRESSION_SYCC_T81; + } + } + else + { + /* Bi-level image */ + if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_1200_1200)) + { + if ((s->supported_bilevel_resolutions & T4_RESOLUTION_1200_1200)) + { + s->x_resolution = T4_X_RESOLUTION_1200; + s->y_resolution = T4_Y_RESOLUTION_1200; + s->current_page_resolution = T4_RESOLUTION_1200_1200; + x = 5; + } + } + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_600_1200)) + { + if ((s->supported_bilevel_resolutions & T4_RESOLUTION_600_1200)) + { + s->x_resolution = T4_X_RESOLUTION_600; + s->y_resolution = T4_Y_RESOLUTION_1200; + s->current_page_resolution = T4_RESOLUTION_600_1200; + x = 4; + } + } + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_600_600)) + { + if ((s->supported_bilevel_resolutions & T4_RESOLUTION_600_600)) + { + s->x_resolution = T4_X_RESOLUTION_600; + s->y_resolution = T4_Y_RESOLUTION_600; + s->current_page_resolution = T4_RESOLUTION_600_600; + x = 4; + } + } + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_400_800)) + { + if ((s->supported_bilevel_resolutions & T4_RESOLUTION_400_800)) + { + s->x_resolution = T4_X_RESOLUTION_400; + s->y_resolution = T4_Y_RESOLUTION_800; + s->current_page_resolution = T4_RESOLUTION_400_800; + x = 3; + } + } + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_400_400)) + { + if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_INCH_RESOLUTION)) + { + if ((s->supported_bilevel_resolutions & T4_RESOLUTION_400_400)) + { + s->x_resolution = T4_X_RESOLUTION_400; + s->y_resolution = T4_Y_RESOLUTION_400; + s->current_page_resolution = T4_RESOLUTION_400_400; + x = 3; + } + } + else + { + if ((s->supported_bilevel_resolutions & T4_RESOLUTION_R16_SUPERFINE)) + { + s->x_resolution = T4_X_RESOLUTION_R16; + s->y_resolution = T4_Y_RESOLUTION_SUPERFINE; + s->current_page_resolution = T4_RESOLUTION_R16_SUPERFINE; + x = 3; + } + } + } + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_300_600)) + { + if ((s->supported_bilevel_resolutions & T4_RESOLUTION_300_600)) + { + s->x_resolution = T4_X_RESOLUTION_300; + s->y_resolution = T4_Y_RESOLUTION_600; + s->current_page_resolution = T4_RESOLUTION_300_600; + x = 2; + } + } + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_300_300)) + { + if ((s->supported_bilevel_resolutions & T4_RESOLUTION_300_300)) + { + s->x_resolution = T4_X_RESOLUTION_300; + s->y_resolution = T4_Y_RESOLUTION_300; + s->current_page_resolution = T4_RESOLUTION_300_300; + x = 2; + } + } + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_200_400)) + { + if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_INCH_RESOLUTION)) + { + if ((s->supported_bilevel_resolutions & T4_RESOLUTION_200_400)) + { + s->x_resolution = T4_X_RESOLUTION_200; + s->y_resolution = T4_Y_RESOLUTION_400; + s->current_page_resolution = T4_RESOLUTION_200_400; + x = 1; + } + } + else + { + if ((s->supported_bilevel_resolutions & T4_RESOLUTION_R8_SUPERFINE)) + { + s->x_resolution = T4_X_RESOLUTION_R8; + s->y_resolution = T4_Y_RESOLUTION_SUPERFINE; + s->current_page_resolution = T4_RESOLUTION_R8_SUPERFINE; + x = 1; + } + } + } + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_200_200)) + { + if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_INCH_RESOLUTION)) + { + if ((s->supported_bilevel_resolutions & T4_RESOLUTION_200_200)) + { + s->x_resolution = T4_X_RESOLUTION_200; + s->y_resolution = T4_Y_RESOLUTION_200; + s->current_page_resolution = T4_RESOLUTION_200_200; + x = 1; + } + } + else + { + if ((s->supported_bilevel_resolutions & T4_RESOLUTION_R8_FINE)) + { + s->x_resolution = T4_X_RESOLUTION_R8; + s->y_resolution = T4_Y_RESOLUTION_FINE; + s->current_page_resolution = T4_RESOLUTION_R8_FINE; + x = 1; + } + } + } + else + { + if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_INCH_RESOLUTION)) + { + s->x_resolution = T4_X_RESOLUTION_200; + s->y_resolution = T4_Y_RESOLUTION_100; + s->current_page_resolution = T4_RESOLUTION_200_100; + x = 1; + } + else + { + s->x_resolution = T4_X_RESOLUTION_R8; + s->y_resolution = T4_Y_RESOLUTION_STANDARD; + s->current_page_resolution = T4_RESOLUTION_R8_STANDARD; + 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_COMPRESSION_T88)) + s->line_compression = T4_COMPRESSION_T88; + } + if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T85_L0_MODE)) + { + if ((s->supported_compressions & T4_COMPRESSION_T85_L0)) + s->line_compression = T4_COMPRESSION_T85_L0; + } + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T85_MODE)) + { + if ((s->supported_compressions & T4_COMPRESSION_T85)) + s->line_compression = T4_COMPRESSION_T85; + } + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T6_MODE)) + { + if ((s->supported_compressions & T4_COMPRESSION_T6)) + s->line_compression = T4_COMPRESSION_T6; + } + else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_2D_MODE)) + { + if ((s->supported_compressions & T4_COMPRESSION_T4_2D)) + s->line_compression = T4_COMPRESSION_T4_2D; + } + else + { + if ((s->supported_compressions & T4_COMPRESSION_T4_1D)) + s->line_compression = T4_COMPRESSION_T4_1D; + } + } + + if (s->line_compression == -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_compression_to_str(s->line_compression), s->line_compression); + + if (x < 0) + { + t30_set_status(s, T30_ERR_NORESSUPPORT); + return -1; + } + + 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 */ + + 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"); + + if ((s->current_fallback = find_fallback_entry(dcs_frame[4] & (DISBIT6 | DISBIT5 | DISBIT4 | DISBIT3))) < 0) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Remote asked for a modem standard we do not support\n"); + return -1; + } + return 0; } /*- End of function --------------------------------------------------------*/ @@ -1705,27 +2275,10 @@ static void send_dcn(t30_state_t *s) static void return_to_phase_b(t30_state_t *s, int with_fallback) { /* This is what we do after things like T30_EOM is exchanged. */ -#if 0 - if (step_fallback_entry(s) < 0) - { - /* We have fallen back as far as we can go. Give up. */ - s->current_fallback = 0; - t30_set_status(s, T30_ERR_CANNOT_TRAIN); - send_dcn(s); - } - else - { - if (s->calling_party) - set_state(s, T30_STATE_T); - else - set_state(s, T30_STATE_R); - } -#else if (s->calling_party) set_state(s, T30_STATE_T); else set_state(s, T30_STATE_R); -#endif } /*- End of function --------------------------------------------------------*/ @@ -1830,7 +2383,6 @@ static int send_dcs_sequence(t30_state_t *s, int start) /* Schedule training after the messages */ if (start) { - prune_dcs(s); set_state(s, T30_STATE_D); s->step = 0; } @@ -1887,7 +2439,28 @@ static int send_cfr_sequence(t30_state_t *s, int start) /* (CSA) CFR */ /* CFR is usually a simple frame, but can become a sequence with Internet FAXing. */ - send_simple_frame(s, T30_CFR); + if (start) + { + s->step = 0; + } + switch (s->step) + { + case 0: + s->step++; + if (send_csa_frame(s)) + break; + /* Fall through */ + case 1: + s->step++; + send_simple_frame(s, T30_CFR); + break; + case 2: + s->step++; + shut_down_hdlc_tx(s); + break; + default: + return -1; + } return 0; } /*- End of function --------------------------------------------------------*/ @@ -1907,7 +2480,7 @@ static void disconnect(t30_state_t *s) } /*- End of function --------------------------------------------------------*/ -static int set_min_scan_time_code(t30_state_t *s) +static void set_min_scan_time(t30_state_t *s) { /* Translation between the codes for the minimum scan times the other end needs, and the codes for what we say will be used. We need 0 minimum. */ @@ -1923,6 +2496,7 @@ static int set_min_scan_time_code(t30_state_t *s) 20, 5, 10, 0, 40, 0, 0, 0 }; int min_bits_field; + int min_row_bits; /* Set the minimum scan time bits */ if (s->error_correcting_mode) @@ -1932,35 +2506,33 @@ static int set_min_scan_time_code(t30_state_t *s) switch (s->y_resolution) { case T4_Y_RESOLUTION_SUPERFINE: - if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_200_400_CAPABLE)) - { - s->min_scan_time_code = translate_min_scan_time[(test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_MIN_SCAN_TIME_HALVES)) ? 2 : 1][min_bits_field]; - break; - } - span_log(&s->logging, SPAN_LOG_FLOW, "Remote FAX does not support super-fine resolution. Squashing image.\n"); - /* Fall through */ + case T4_Y_RESOLUTION_400: + s->min_scan_time_code = translate_min_scan_time[(test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_MIN_SCAN_TIME_HALVES)) ? 2 : 1][min_bits_field]; + break; case T4_Y_RESOLUTION_FINE: - if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_200_200_CAPABLE)) - { - s->min_scan_time_code = translate_min_scan_time[1][min_bits_field]; - break; - } - span_log(&s->logging, SPAN_LOG_FLOW, "Remote FAX does not support fine resolution. Squashing image.\n"); - /* Fall through */ - default: + case T4_Y_RESOLUTION_200: + s->min_scan_time_code = translate_min_scan_time[1][min_bits_field]; + break; case T4_Y_RESOLUTION_STANDARD: + case T4_Y_RESOLUTION_100: s->min_scan_time_code = translate_min_scan_time[0][min_bits_field]; break; + default: + s->min_scan_time_code = T30_MIN_SCAN_0MS; + break; } - if (!s->error_correcting_mode && (s->iaf & T30_IAF_MODE_NO_FILL_BITS)) - return 0; - return fallback_sequence[s->current_fallback].bit_rate*min_scan_times[s->min_scan_time_code]/1000; + if ((s->iaf & T30_IAF_MODE_NO_FILL_BITS)) + min_row_bits = 0; + else + min_row_bits = (fallback_sequence[s->current_fallback].bit_rate*min_scan_times[s->min_scan_time_code])/1000; + span_log(&s->logging, SPAN_LOG_FLOW, "Minimum bits per row will be %d\n", min_row_bits); + t4_tx_set_min_bits_per_row(&s->t4.tx, min_row_bits); } /*- End of function --------------------------------------------------------*/ static int start_sending_document(t30_state_t *s) { - int min_row_bits; + int res; if (s->tx_file[0] == '\0') { @@ -1976,28 +2548,67 @@ static int start_sending_document(t30_state_t *s) return -1; } s->operation_in_progress = OPERATION_IN_PROGRESS_T4_TX; - t4_tx_get_pages_in_file(&s->t4.tx); - t4_tx_set_tx_encoding(&s->t4.tx, s->line_encoding); + t4_tx_set_local_ident(&s->t4.tx, s->tx_info.ident); t4_tx_set_header_info(&s->t4.tx, s->header_info); if (s->use_own_tz) t4_tx_set_header_tz(&s->t4.tx, &s->tz); - if (tx_start_page(s)) - return -1; + t4_tx_get_pages_in_file(&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->image_width = t4_tx_get_image_width(&s->t4.tx); - /* The minimum scan time to be used can't be evaluated until we know the Y resolution, and - must be evaluated before the minimum scan row bits can be evaluated. */ - if ((min_row_bits = set_min_scan_time_code(s)) < 0) + if ((res = t4_tx_set_tx_image_format(&s->t4.tx, + s->mutual_compressions, + s->mutual_image_sizes, + s->mutual_bilevel_resolutions, + s->mutual_colour_resolutions)) < 0) { - terminate_operation_in_progress(s); + switch (res) + { + case T4_IMAGE_FORMAT_INCOMPATIBLE: + span_log(&s->logging, SPAN_LOG_WARNING, "Cannot negotiate an image format\n"); + t30_set_status(s, T30_ERR_BADTIFFHDR); + break; + case T4_IMAGE_FORMAT_NOSIZESUPPORT: + span_log(&s->logging, SPAN_LOG_WARNING, "Cannot negotiate an image size\n"); + t30_set_status(s, T30_ERR_NOSIZESUPPORT); + break; + case T4_IMAGE_FORMAT_NORESSUPPORT: + span_log(&s->logging, SPAN_LOG_WARNING, "Cannot negotiate an image resolution\n"); + t30_set_status(s, T30_ERR_NORESSUPPORT); + break; + default: + span_log(&s->logging, SPAN_LOG_WARNING, "Cannot negotiate an image mode\n"); + t30_set_status(s, T30_ERR_BADTIFF); + break; + } + return -1; + } + s->line_image_type = t4_tx_get_tx_image_type(&s->t4.tx); + s->line_compression = t4_tx_get_tx_compression(&s->t4.tx); + s->image_width = t4_tx_get_tx_image_width(&s->t4.tx); + s->line_width_code = t4_tx_get_tx_image_width_code(&s->t4.tx); + + s->x_resolution = t4_tx_get_tx_x_resolution(&s->t4.tx); + s->y_resolution = t4_tx_get_tx_y_resolution(&s->t4.tx); + s->current_page_resolution = t4_tx_get_tx_resolution(&s->t4.tx); + + span_log(&s->logging, + SPAN_LOG_FLOW, + "Choose image type %s (%d), compression %s (%d)\n", + t4_image_type_to_str(s->line_image_type), + s->line_image_type, + t4_compression_to_str(s->line_compression), + s->line_compression); + + /* The minimum scan time to be used can't be evaluated until we know the Y resolution. */ + set_min_scan_time(s); + + if (tx_start_page(s)) + { + span_log(&s->logging, SPAN_LOG_WARNING, "Something seems to be wrong in the file\n"); + t30_set_status(s, T30_ERR_BADTIFFHDR); return -1; } - span_log(&s->logging, SPAN_LOG_FLOW, "Minimum bits per row will be %d\n", min_row_bits); - t4_tx_set_min_bits_per_row(&s->t4.tx, min_row_bits); if (s->error_correcting_mode) { @@ -2013,7 +2624,7 @@ static int restart_sending_document(t30_state_t *s) t4_tx_restart_page(&s->t4.tx); s->retries = 0; s->ecm_block = 0; - send_dcs_sequence(s, TRUE); + send_dcs_sequence(s, true); return 0; } /*- End of function --------------------------------------------------------*/ @@ -2029,7 +2640,7 @@ static int start_receiving_document(t30_state_t *s) span_log(&s->logging, SPAN_LOG_FLOW, "Start receiving document\n"); queue_phase(s, T30_PHASE_B_TX); s->ecm_block = 0; - send_dis_or_dtc_sequence(s, TRUE); + send_dis_or_dtc_sequence(s, true); return 0; } /*- End of function --------------------------------------------------------*/ @@ -2064,120 +2675,10 @@ static int process_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len) { int new_status; - t30_decode_dis_dtc_dcs(s, msg, len); - if (len < 6) + queue_phase(s, T30_PHASE_B_TX); + if (analyze_rx_dis_dtc(s, msg, len) < 0) { - span_log(&s->logging, SPAN_LOG_FLOW, "Short DIS/DTC frame\n"); - return -1; - } - - if (msg[2] == T30_DIS) - s->dis_received = TRUE; - /* Make a local copy of the message, padded to the maximum possible length with zeros. This allows - us to simply pick out the bits, without worrying about whether they were set from the remote side. */ - s->far_dis_dtc_len = (len > T30_MAX_DIS_DTC_DCS_LEN) ? T30_MAX_DIS_DTC_DCS_LEN : len; - memcpy(s->far_dis_dtc_frame, msg, s->far_dis_dtc_len); - if (s->far_dis_dtc_len < T30_MAX_DIS_DTC_DCS_LEN) - memset(s->far_dis_dtc_frame + s->far_dis_dtc_len, 0, T30_MAX_DIS_DTC_DCS_LEN - s->far_dis_dtc_len); - s->error_correcting_mode = (s->ecm_allowed && (s->far_dis_dtc_frame[6] & DISBIT3) != 0); - /* 256 octets per ECM frame */ - s->octets_per_ecm_frame = 256; - /* Now we know if we are going to use ECM, select the compression to use. */ - if (!s->error_correcting_mode) - { - /* Without error correction our choices are very limited */ - if ((s->supported_compressions & T30_SUPPORT_T4_2D_COMPRESSION) - && - test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_2D_CAPABLE)) - { - s->line_encoding = T4_COMPRESSION_ITU_T4_2D; - } - else - { - s->line_encoding = T4_COMPRESSION_ITU_T4_1D; - } - } - else - { -#if defined(SPANDSP_SUPPORT_T42x) || defined(SPANDSP_SUPPORT_T43) - /* With error correction colour may be possible/required */ - if ((0 & (T30_SUPPORT_T43_COMPRESSION | T30_SUPPORT_T45_COMPRESSION | T30_SUPPORT_T81_COMPRESSION | T30_SUPPORT_SYCC_T81_COMPRESSION))) - { - s->line_encoding = T4_COMPRESSION_ITU_T85_L0; - } - else -#endif - { - if ((s->supported_compressions & T30_SUPPORT_T85_L0_COMPRESSION) - && - test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T85_L0_CAPABLE)) - { - s->line_encoding = T4_COMPRESSION_ITU_T85_L0; - } - else if ((s->supported_compressions & T30_SUPPORT_T85_COMPRESSION) - && - test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T85_CAPABLE)) - { - s->line_encoding = T4_COMPRESSION_ITU_T85; - } - else if ((s->supported_compressions & T30_SUPPORT_T6_COMPRESSION) - && - test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T6_CAPABLE)) - { - s->line_encoding = T4_COMPRESSION_ITU_T6; - } - else if ((s->supported_compressions & T30_SUPPORT_T4_2D_COMPRESSION) - && - test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_2D_CAPABLE)) - { - s->line_encoding = T4_COMPRESSION_ITU_T4_2D; - } - else - { - s->line_encoding = T4_COMPRESSION_ITU_T4_1D; - } - } - } - span_log(&s->logging, SPAN_LOG_FLOW, "Choose compression %s (%d)\n", t4_encoding_to_str(s->line_encoding), s->line_encoding); - switch (s->far_dis_dtc_frame[4] & (DISBIT6 | DISBIT5 | DISBIT4 | DISBIT3)) - { - case (DISBIT6 | DISBIT4 | DISBIT3): - if ((s->supported_modems & T30_SUPPORT_V17)) - { - s->current_permitted_modems = T30_SUPPORT_V17 | T30_SUPPORT_V29 | T30_SUPPORT_V27TER; - s->current_fallback = T30_V17_FALLBACK_START; - break; - } - /* Fall through */ - case (DISBIT4 | DISBIT3): - if ((s->supported_modems & T30_SUPPORT_V29)) - { - s->current_permitted_modems = T30_SUPPORT_V29 | T30_SUPPORT_V27TER; - s->current_fallback = T30_V29_FALLBACK_START; - break; - } - /* Fall through */ - case DISBIT4: - s->current_permitted_modems = T30_SUPPORT_V27TER; - s->current_fallback = T30_V27TER_FALLBACK_START; - break; - case 0: - s->current_permitted_modems = T30_SUPPORT_V27TER; - s->current_fallback = T30_V27TER_FALLBACK_START + 1; - break; - case DISBIT3: - if ((s->supported_modems & T30_SUPPORT_V29)) - { - /* TODO: this doesn't allow for skipping the V.27ter modes */ - s->current_permitted_modems = T30_SUPPORT_V29; - s->current_fallback = T30_V29_FALLBACK_START; - break; - } - /* Fall through */ - default: - span_log(&s->logging, SPAN_LOG_FLOW, "Remote does not support a compatible modem\n"); - /* We cannot talk to this machine! */ - t30_set_status(s, T30_ERR_INCOMPATIBLE); + send_dcn(s); return -1; } if (s->phase_b_handler) @@ -2192,61 +2693,6 @@ static int process_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len) return -1; } } -#if 0 - /* T.4 1D is always available */ - bi_level_support = T30_SUPPORT_T4_1D_COMPRESSION; - if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_2D_CAPABLE)) - bi_level_support |= T30_SUPPORT_T4_2D_COMPRESSION; - if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T6_CAPABLE)) - bi_level_support |= T30_SUPPORT_T6_COMPRESSION; - /* Bit 79 set with bit 78 clear is invalid, so let's completely ignore 79 - if 78 is clear. */ - if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T85_CAPABLE)) - { - bi_level_support |= T30_SUPPORT_T85_COMPRESSION; - if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T85_L0_CAPABLE) - bi_level_support |= T30_SUPPORT_T85_L0_COMPRESSION; - } - - gray_support = 0; - colour_support = 0; - if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_200_200_CAPABLE) && test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T81_CAPABLE)) - { - /* Multi-level coding available */ - gray_support |= T30_SUPPORT_T81_COMPRESSION; - if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_12BIT_CAPABLE)) - gray_support |= T30_SUPPORT_T81_12BIT_COMPRESSION; - if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T43_CAPABLE)) - { - gray_support |= T30_SUPPORT_T43_COMPRESSION; - if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_12BIT_CAPABLE)) - gray_support |= T30_SUPPORT_T43_COMPRESSION_12BIT; - } - - if (test_ctrl_bit(s->far_dis_dtc_frame, bit69)) - { - /* Colour coding available */ - colour_support |= T30_SUPPORT_T81_COMPRESSION; - if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_12BIT_CAPABLE)) - colour_support |= T30_SUPPORT_T81_12BIT_COMPRESSION; - if (!test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_NO_SUBSAMPLING)) - { - colour_support |= T30_SUPPORT_T81_SUBSAMPLING_COMPRESSION; - if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_12BIT_CAPABLE)) - colour_support |= T30_SUPPORT_T81_SUBSAMPLING_COMPRESSION_12BIT; - } - if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_T43_CAPABLE)) - { - colour_support |= T30_SUPPORT_T43_COMPRESSION; - if (test_ctrl_bit(s->far_dis_dtc_frame, T30_DIS_BIT_12BIT_CAPABLE)) - colour_support |= T30_SUPPORT_T43_12BIT_COMPRESSION; - } - } - /* bit74 custom illuminant */ - /* bit75 custom gamut range */ - } -#endif - queue_phase(s, T30_PHASE_B_TX); /* Try to send something */ if (s->tx_file[0]) { @@ -2256,6 +2702,7 @@ static int process_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len) span_log(&s->logging, SPAN_LOG_FLOW, "%s far end cannot receive\n", t30_frametype(msg[2])); t30_set_status(s, T30_ERR_RX_INCAPABLE); send_dcn(s); + return -1; } if (start_sending_document(s)) { @@ -2268,8 +2715,15 @@ static int process_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len) send_dcn(s); return -1; } + /* Start document transmission */ + span_log(&s->logging, + SPAN_LOG_FLOW, + "Put document with modem (%d) %s at %dbps\n", + fallback_sequence[s->current_fallback].modem_type, + t30_modem_to_str(fallback_sequence[s->current_fallback].modem_type), + fallback_sequence[s->current_fallback].bit_rate); s->retries = 0; - send_dcs_sequence(s, TRUE); + send_dcs_sequence(s, true); return 0; } span_log(&s->logging, SPAN_LOG_FLOW, "%s nothing to send\n", t30_frametype(msg[2])); @@ -2296,7 +2750,7 @@ static int process_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len) return -1; } s->retries = 0; - send_dis_or_dtc_sequence(s, TRUE); + send_dis_or_dtc_sequence(s, true); return 0; } span_log(&s->logging, SPAN_LOG_FLOW, "%s nothing to receive\n", t30_frametype(msg[2])); @@ -2308,194 +2762,14 @@ static int process_rx_dis_dtc(t30_state_t *s, const uint8_t *msg, int len) static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) { - static const int widths[6][4] = - { - { T4_WIDTH_R4_A4, T4_WIDTH_R4_B4, T4_WIDTH_R4_A3, -1}, /* R4 resolution - no longer used in recent versions of T.30 */ - { T4_WIDTH_R8_A4, T4_WIDTH_R8_B4, T4_WIDTH_R8_A3, -1}, /* R8 resolution */ - { T4_WIDTH_300_A4, T4_WIDTH_300_B4, T4_WIDTH_300_A3, -1}, /* 300/inch resolution */ - { T4_WIDTH_R16_A4, T4_WIDTH_R16_B4, T4_WIDTH_R16_A3, -1}, /* R16 resolution */ - { T4_WIDTH_600_A4, T4_WIDTH_600_B4, T4_WIDTH_600_A3, -1}, /* 600/inch resolution */ - {T4_WIDTH_1200_A4, T4_WIDTH_1200_B4, T4_WIDTH_1200_A3, -1} /* 1200/inch resolution */ - }; - uint8_t dcs_frame[T30_MAX_DIS_DTC_DCS_LEN]; - int i; - int x; int new_status; - t30_decode_dis_dtc_dcs(s, msg, len); - - /* Check DCS frame from remote */ - if (len < 6) + if (analyze_rx_dcs(s, msg, len) < 0) { - span_log(&s->logging, SPAN_LOG_FLOW, "Short DCS frame\n"); + send_dcn(s); return -1; } - /* Make an ASCII string format copy of the message, for logging in the - received file. This string does not include the frame header octets. */ - sprintf(s->rx_dcs_string, "%02X", bit_reverse8(msg[3])); - for (i = 4; i < len; i++) - sprintf(s->rx_dcs_string + 3*i - 10, " %02X", bit_reverse8(msg[i])); - /* Make a local copy of the message, padded to the maximum possible length with zeros. This allows - us to simply pick out the bits, without worrying about whether they were set from the remote side. */ - if (len > T30_MAX_DIS_DTC_DCS_LEN) - { - memcpy(dcs_frame, msg, T30_MAX_DIS_DTC_DCS_LEN); - } - else - { - memcpy(dcs_frame, msg, len); - if (len < T30_MAX_DIS_DTC_DCS_LEN) - memset(dcs_frame + len, 0, T30_MAX_DIS_DTC_DCS_LEN - len); - } - - s->octets_per_ecm_frame = test_ctrl_bit(dcs_frame, T30_DCS_BIT_64_OCTET_ECM_FRAMES) ? 256 : 64; - - s->x_resolution = -1; - s->y_resolution = -1; - x = -1; - if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_1200_1200)) - { - if ((s->supported_resolutions & T30_SUPPORT_1200_1200_RESOLUTION)) - { - s->x_resolution = T4_X_RESOLUTION_1200; - s->y_resolution = T4_Y_RESOLUTION_1200; - x = 5; - } - } - else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_600_1200)) - { - if ((s->supported_resolutions & T30_SUPPORT_600_1200_RESOLUTION)) - { - s->x_resolution = T4_X_RESOLUTION_600; - s->y_resolution = T4_Y_RESOLUTION_1200; - x = 4; - } - } - else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_600_600)) - { - if ((s->supported_resolutions & T30_SUPPORT_600_600_RESOLUTION)) - { - s->x_resolution = T4_X_RESOLUTION_600; - s->y_resolution = T4_Y_RESOLUTION_600; - x = 4; - } - } - else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_400_800)) - { - if ((s->supported_resolutions & T30_SUPPORT_400_800_RESOLUTION)) - { - s->x_resolution = T4_X_RESOLUTION_R16; - s->y_resolution = T4_Y_RESOLUTION_800; - x = 3; - } - } - else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_400_400)) - { - if ((s->supported_resolutions & T30_SUPPORT_400_400_RESOLUTION)) - { - s->x_resolution = T4_X_RESOLUTION_R16; - s->y_resolution = T4_Y_RESOLUTION_SUPERFINE; - x = 3; - } - } - else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_300_600)) - { - if ((s->supported_resolutions & T30_SUPPORT_300_600_RESOLUTION)) - { - s->x_resolution = T4_X_RESOLUTION_300; - s->y_resolution = T4_Y_RESOLUTION_600; - x = 2; - } - } - else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_300_300)) - { - if ((s->supported_resolutions & T30_SUPPORT_300_300_RESOLUTION)) - { - s->x_resolution = T4_X_RESOLUTION_300; - s->y_resolution = T4_Y_RESOLUTION_300; - x = 2; - } - } - else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_200_400)) - { - if ((s->supported_resolutions & T30_SUPPORT_SUPERFINE_RESOLUTION)) - { - s->x_resolution = T4_X_RESOLUTION_R8; - s->y_resolution = T4_Y_RESOLUTION_SUPERFINE; - x = 1; - } - } - else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_200_200)) - { - if ((s->supported_resolutions & T30_SUPPORT_FINE_RESOLUTION)) - { - s->x_resolution = T4_X_RESOLUTION_R8; - s->y_resolution = T4_Y_RESOLUTION_FINE; - x = 1; - } - } - else - { - s->x_resolution = T4_X_RESOLUTION_R8; - s->y_resolution = T4_Y_RESOLUTION_STANDARD; - x = 1; - } - - if (x < 0) - { - t30_set_status(s, T30_ERR_NORESSUPPORT); - return -1; - } - - s->image_width = widths[x][dcs_frame[5] & (DISBIT2 | DISBIT1)]; - - /* Check which compression the far end has decided to use. */ -#if defined(SPANDSP_SUPPORT_T42) - if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_FULL_COLOUR_MODE)) - { - s->line_encoding = T4_COMPRESSION_ITU_T42; - } - else -#endif -#if defined(SPANDSP_SUPPORT_T43) - if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T43_MODE)) - { - s->line_encoding = T4_COMPRESSION_ITU_T43; - } - else -#endif - if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T85_L0_MODE)) - { - s->line_encoding = T4_COMPRESSION_ITU_T85_L0; - } - else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T85_MODE)) - { - s->line_encoding = T4_COMPRESSION_ITU_T85; - } - else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_T6_MODE)) - { - s->line_encoding = T4_COMPRESSION_ITU_T6; - } - else if (test_ctrl_bit(dcs_frame, T30_DCS_BIT_2D_MODE)) - { - s->line_encoding = T4_COMPRESSION_ITU_T4_2D; - } - else - { - s->line_encoding = T4_COMPRESSION_ITU_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)) - span_log(&s->logging, SPAN_LOG_PROTOCOL_WARNING, "Remote is not requesting receive in DCS\n"); - - if ((s->current_fallback = find_fallback_entry(dcs_frame[4] & (DISBIT6 | DISBIT5 | DISBIT4 | DISBIT3))) < 0) - { - span_log(&s->logging, SPAN_LOG_FLOW, "Remote asked for a modem standard we do not support\n"); - return -1; - } - s->error_correcting_mode = (test_ctrl_bit(dcs_frame, T30_DCS_BIT_ECM) != 0); - if (s->phase_b_handler) { new_status = s->phase_b_handler(s, s->phase_b_user_data, msg[2]); @@ -2511,9 +2785,10 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) /* Start document reception */ span_log(&s->logging, SPAN_LOG_FLOW, - "Get document at %dbps, modem %d\n", - fallback_sequence[s->current_fallback].bit_rate, - fallback_sequence[s->current_fallback].modem_type); + "Get document with modem (%d) %s at %dbps\n", + fallback_sequence[s->current_fallback].modem_type, + t30_modem_to_str(fallback_sequence[s->current_fallback].modem_type), + fallback_sequence[s->current_fallback].bit_rate); if (s->rx_file[0] == '\0') { span_log(&s->logging, SPAN_LOG_FLOW, "No document to receive\n"); @@ -2523,7 +2798,7 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) } if (s->operation_in_progress != OPERATION_IN_PROGRESS_T4_RX) { - if (t4_rx_init(&s->t4.rx, s->rx_file, s->output_encoding) == NULL) + if (t4_rx_init(&s->t4.rx, s->rx_file, s->supported_output_compressions) == NULL) { span_log(&s->logging, SPAN_LOG_WARNING, "Cannot open target TIFF file '%s'\n", s->rx_file); t30_set_status(s, T30_ERR_FILEERROR); @@ -2535,7 +2810,7 @@ static int process_rx_dcs(t30_state_t *s, const uint8_t *msg, int len) if (!(s->iaf & T30_IAF_MODE_NO_TCF)) { /* TCF is always sent with long training */ - s->short_train = FALSE; + s->short_train = false; set_state(s, T30_STATE_F_TCF); queue_phase(s, T30_PHASE_C_NON_ECM_RX); timer_t2_start(s); @@ -2551,7 +2826,7 @@ static int send_response_to_pps(t30_state_t *s) { set_state(s, T30_STATE_F_POST_RCP_MCF); send_simple_frame(s, T30_MCF); - return TRUE; + return true; } /* We need to send the PPR frame we have created, to try to fill in the missing/bad data. */ set_state(s, T30_STATE_F_POST_RCP_PPR); @@ -2559,7 +2834,7 @@ static int send_response_to_pps(t30_state_t *s) s->ecm_frame_map[1] = CONTROL_FIELD_FINAL_FRAME; s->ecm_frame_map[2] = (uint8_t) (T30_PPR | s->dis_received); send_frame(s, s->ecm_frame_map, 3 + 32); - return FALSE; + return false; } /*- End of function --------------------------------------------------------*/ @@ -2574,6 +2849,7 @@ static int process_rx_pps(t30_state_t *s, const uint8_t *msg, int len) int first_bad_frame; int first; int expected_len; + int res; if (len < 7) { @@ -2656,7 +2932,7 @@ static int process_rx_pps(t30_state_t *s, const uint8_t *msg, int len) /* Build a bit map of which frames we now have stored OK */ first_bad_frame = 256; - first = TRUE; + first = true; expected_len = 256; for (i = 0; i < 32; i++) { @@ -2683,7 +2959,7 @@ static int process_rx_pps(t30_state_t *s, const uint8_t *msg, int len) /* Use the length of the first frame as our model for what the length should be */ if (s->ecm_len[frame_no] == 64) expected_len = 64; - first = FALSE; + first = false; } /* Check the length is consistent with the first frame */ if (s->ecm_len[frame_no] != expected_len) @@ -2707,11 +2983,18 @@ static int process_rx_pps(t30_state_t *s, const uint8_t *msg, int len) if (s->rx_ecm_block_ok) { span_log(&s->logging, SPAN_LOG_FLOW, "Partial page OK - committing block %d, %d frames\n", s->ecm_block, s->ecm_frames); + /* Deliver the ECM data */ for (i = 0; i < s->ecm_frames; i++) { - if (t4_rx_put(&s->t4.rx, s->ecm_data[i], s->ecm_len[i])) + if (s->document_put_handler) + res = s->document_put_handler(s->document_put_user_data, s->ecm_data[i], s->ecm_len[i]); + else + res = t4_rx_put(&s->t4.rx, s->ecm_data[i], s->ecm_len[i]); + if (res != T4_DECODE_MORE_DATA) { /* This is the end of the document */ + if (res != T4_DECODE_OK) + span_log(&s->logging, SPAN_LOG_FLOW, "Document ended with status %d\n", res); break; } } @@ -2768,7 +3051,7 @@ static int process_rx_pps(t30_state_t *s, const uint8_t *msg, int len) case T30_PRI_EOP: case T30_EOP: span_log(&s->logging, SPAN_LOG_FLOW, "End of procedure detected\n"); - s->end_of_procedure_detected = TRUE; + s->end_of_procedure_detected = true; break; } } @@ -2883,7 +3166,7 @@ static void process_rx_fcd(t30_state_t *s, const uint8_t *msg, int len) memcpy(&s->ecm_data[frame_no][0], &msg[4], len - 4); s->ecm_len[frame_no] = (int16_t) (len - 4); /* In case we are just after a CTC/CTR exchange, which kicked us back to long training */ - s->short_train = TRUE; + s->short_train = true; } /* We have received something, so any missing carrier status is out of date */ if (s->current_status == T30_ERR_RX_NOCARRIER) @@ -3148,7 +3431,7 @@ static void process_state_d_post_tcf(t30_state_t *s, const uint8_t *msg, int len /* Trainability test succeeded. Send the document. */ span_log(&s->logging, SPAN_LOG_FLOW, "Trainability test succeeded\n"); s->retries = 0; - s->short_train = TRUE; + s->short_train = true; if (s->error_correcting_mode) { set_state(s, T30_STATE_IV); @@ -3165,17 +3448,16 @@ static void process_state_d_post_tcf(t30_state_t *s, const uint8_t *msg, int len /* Trainability test failed. Try again. */ span_log(&s->logging, SPAN_LOG_FLOW, "Trainability test failed\n"); s->retries = 0; - s->short_train = FALSE; + s->short_train = false; if (step_fallback_entry(s) < 0) { /* We have fallen back as far as we can go. Give up. */ - s->current_fallback = 0; t30_set_status(s, T30_ERR_CANNOT_TRAIN); send_dcn(s); break; } queue_phase(s, T30_PHASE_B_TX); - send_dcs_sequence(s, TRUE); + send_dcs_sequence(s, true); break; case T30_DIS: /* It appears they didn't see what we sent - retry the TCF */ @@ -3189,7 +3471,7 @@ static void process_state_d_post_tcf(t30_state_t *s, const uint8_t *msg, int len span_log(&s->logging, SPAN_LOG_FLOW, "Retry number %d\n", s->retries); queue_phase(s, T30_PHASE_B_TX); /* TODO: should we reassess the new DIS message, and possibly adjust the DCS we use? */ - send_dcs_sequence(s, TRUE); + send_dcs_sequence(s, true); break; case T30_DCN: t30_set_status(s, T30_ERR_TX_BADDCS); @@ -3363,6 +3645,53 @@ static void process_state_f_doc_non_ecm(t30_state_t *s, const uint8_t *msg, int } /*- End of function --------------------------------------------------------*/ +static void assess_copy_quality(t30_state_t *s, uint8_t fcf) +{ + int quality; + + quality = copy_quality(s); + switch (quality) + { + case T30_COPY_QUALITY_PERFECT: + case T30_COPY_QUALITY_GOOD: + rx_end_page(s); + break; + case T30_COPY_QUALITY_POOR: + rx_end_page(s); + break; + case T30_COPY_QUALITY_BAD: + /* Some people want to keep even the bad pages */ + if (s->keep_bad_pages) + rx_end_page(s); + break; + } + + if (s->phase_d_handler) + s->phase_d_handler(s, s->phase_d_user_data, fcf); + if (fcf == T30_EOP) + terminate_operation_in_progress(s); + else + rx_start_page(s); + + switch (quality) + { + case T30_COPY_QUALITY_PERFECT: + case T30_COPY_QUALITY_GOOD: + set_state(s, T30_STATE_III_Q_MCF); + send_simple_frame(s, T30_MCF); + break; + case T30_COPY_QUALITY_POOR: + set_state(s, T30_STATE_III_Q_RTP); + send_simple_frame(s, T30_RTP); + break; + case T30_COPY_QUALITY_BAD: + set_state(s, T30_STATE_III_Q_RTN); + send_simple_frame(s, T30_RTN); + break; + } +} +/*- End of function --------------------------------------------------------*/ + static void process_state_f_post_doc_non_ecm(t30_state_t *s, const uint8_t *msg, int len) { uint8_t fcf; @@ -3378,33 +3707,7 @@ static void process_state_f_post_doc_non_ecm(t30_state_t *s, const uint8_t *msg, case T30_MPS: s->next_rx_step = fcf; queue_phase(s, T30_PHASE_D_TX); - switch (copy_quality(s)) - { - case T30_COPY_QUALITY_PERFECT: - case T30_COPY_QUALITY_GOOD: - rx_end_page(s); - if (s->phase_d_handler) - s->phase_d_handler(s, s->phase_d_user_data, fcf); - rx_start_page(s); - set_state(s, T30_STATE_III_Q_MCF); - send_simple_frame(s, T30_MCF); - break; - case T30_COPY_QUALITY_POOR: - rx_end_page(s); - if (s->phase_d_handler) - s->phase_d_handler(s, s->phase_d_user_data, fcf); - rx_start_page(s); - set_state(s, T30_STATE_III_Q_RTP); - send_simple_frame(s, T30_RTP); - break; - case T30_COPY_QUALITY_BAD: - if (s->phase_d_handler) - s->phase_d_handler(s, s->phase_d_user_data, fcf); - rx_start_page(s); - set_state(s, T30_STATE_III_Q_RTN); - send_simple_frame(s, T30_RTN); - break; - } + assess_copy_quality(s, fcf); break; case T30_PRI_EOM: if (s->remote_interrupts_allowed) @@ -3416,33 +3719,7 @@ static void process_state_f_post_doc_non_ecm(t30_state_t *s, const uint8_t *msg, s->next_rx_step = fcf; /* Return to phase B */ queue_phase(s, T30_PHASE_B_TX); - switch (copy_quality(s)) - { - case T30_COPY_QUALITY_PERFECT: - case T30_COPY_QUALITY_GOOD: - rx_end_page(s); - if (s->phase_d_handler) - s->phase_d_handler(s, s->phase_d_user_data, fcf); - rx_start_page(s); - set_state(s, T30_STATE_III_Q_MCF); - send_simple_frame(s, T30_MCF); - break; - case T30_COPY_QUALITY_POOR: - rx_end_page(s); - if (s->phase_d_handler) - s->phase_d_handler(s, s->phase_d_user_data, fcf); - rx_start_page(s); - set_state(s, T30_STATE_III_Q_RTP); - send_simple_frame(s, T30_RTP); - break; - case T30_COPY_QUALITY_BAD: - if (s->phase_d_handler) - s->phase_d_handler(s, s->phase_d_user_data, fcf); - rx_start_page(s); - set_state(s, T30_STATE_III_Q_RTN); - send_simple_frame(s, T30_RTN); - break; - } + assess_copy_quality(s, fcf); break; case T30_PRI_EOP: if (s->remote_interrupts_allowed) @@ -3451,40 +3728,10 @@ static void process_state_f_post_doc_non_ecm(t30_state_t *s, const uint8_t *msg, /* Fall through */ case T30_EOP: span_log(&s->logging, SPAN_LOG_FLOW, "End of procedure detected\n"); - s->end_of_procedure_detected = TRUE; + s->end_of_procedure_detected = true; s->next_rx_step = fcf; queue_phase(s, T30_PHASE_D_TX); - switch (copy_quality(s)) - { - case T30_COPY_QUALITY_PERFECT: - case T30_COPY_QUALITY_GOOD: - rx_end_page(s); - if (s->phase_d_handler) - s->phase_d_handler(s, s->phase_d_user_data, fcf); - terminate_operation_in_progress(s); - set_state(s, T30_STATE_III_Q_MCF); - send_simple_frame(s, T30_MCF); - break; - case T30_COPY_QUALITY_POOR: - rx_end_page(s); - if (s->phase_d_handler) - s->phase_d_handler(s, s->phase_d_user_data, fcf); - terminate_operation_in_progress(s); - set_state(s, T30_STATE_III_Q_RTP); - send_simple_frame(s, T30_RTP); - break; - case T30_COPY_QUALITY_BAD: -#if 0 - /* Some people want to keep even the bad pages */ - if (s->keep_bad_pages) - rx_end_page(s); -#endif - if (s->phase_d_handler) - s->phase_d_handler(s, s->phase_d_user_data, fcf); - set_state(s, T30_STATE_III_Q_RTN); - send_simple_frame(s, T30_RTN); - break; - } + assess_copy_quality(s, fcf); break; case T30_DCN: t30_set_status(s, T30_ERR_RX_DCNFAX); @@ -3563,7 +3810,7 @@ static void process_state_f_doc_and_post_doc_ecm(t30_state_t *s, const uint8_t * break; case T30_CTC: /* T.30 says we change back to long training here */ - s->short_train = FALSE; + s->short_train = false; queue_phase(s, T30_PHASE_D_TX); set_state(s, T30_STATE_F_DOC_ECM); send_simple_frame(s, T30_CTR); @@ -3659,7 +3906,7 @@ static void process_state_f_post_rcp_rnr(t30_state_t *s, const uint8_t *msg, int case T30_PRI_EOP: case T30_EOP: span_log(&s->logging, SPAN_LOG_FLOW, "End of procedure detected\n"); - s->end_of_procedure_detected = TRUE; + s->end_of_procedure_detected = true; break; } } @@ -3693,8 +3940,8 @@ static void process_state_r(t30_state_t *s, const uint8_t *msg, int len) process_rx_dcs(s, msg, len); break; case T30_DCN: - /* Received a DCN while waiting for a DIS */ - t30_set_status(s, T30_ERR_TX_GOTDCN); + /* Received a DCN while waiting for a DIS or DCN */ + t30_set_status(s, T30_ERR_RX_DCNWHY); disconnect(s); break; case T30_CRP: @@ -3722,7 +3969,7 @@ static void process_state_t(t30_state_t *s, const uint8_t *msg, int len) process_rx_dis_dtc(s, msg, len); break; case T30_DCN: - t30_set_status(s, T30_ERR_RX_DCNWHY); + t30_set_status(s, T30_ERR_TX_GOTDCN); disconnect(s); break; case T30_CRP: @@ -3824,8 +4071,8 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); terminate_operation_in_progress(s); - report_tx_result(s, TRUE); - return_to_phase_b(s, FALSE); + report_tx_result(s, true); + return_to_phase_b(s, false); break; case T30_PRI_EOP: case T30_EOP: @@ -3834,7 +4081,7 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) s->phase_d_handler(s, s->phase_d_user_data, fcf); terminate_operation_in_progress(s); send_dcn(s); - report_tx_result(s, TRUE); + report_tx_result(s, true); break; } break; @@ -3856,7 +4103,6 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) if (step_fallback_entry(s) < 0) { /* We have fallen back as far as we can go. Give up. */ - s->current_fallback = 0; t30_set_status(s, T30_ERR_CANNOT_TRAIN); send_dcn(s); break; @@ -3872,7 +4118,7 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) s->phase_d_handler(s, s->phase_d_user_data, fcf); t4_tx_release(&s->t4.tx); /* TODO: should go back to T, and resend */ - return_to_phase_b(s, TRUE); + return_to_phase_b(s, true); break; case T30_PRI_EOP: case T30_EOP: @@ -3917,7 +4163,6 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) if (step_fallback_entry(s) < 0) { /* We have fallen back as far as we can go. Give up. */ - s->current_fallback = 0; t30_set_status(s, T30_ERR_CANNOT_TRAIN); send_dcn(s); break; @@ -3937,7 +4182,7 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) } else { - return_to_phase_b(s, TRUE); + return_to_phase_b(s, true); } break; case T30_PRI_EOP: @@ -3951,7 +4196,6 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) if (step_fallback_entry(s) < 0) { /* We have fallen back as far as we can go. Give up. */ - s->current_fallback = 0; t30_set_status(s, T30_ERR_CANNOT_TRAIN); send_dcn(s); break; @@ -4177,8 +4421,8 @@ static void process_state_iv_pps_null(t30_state_t *s, const uint8_t *msg, int le if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); terminate_operation_in_progress(s); - report_tx_result(s, TRUE); - return_to_phase_b(s, FALSE); + report_tx_result(s, true); + return_to_phase_b(s, false); break; case T30_PRI_EOP: case T30_EOP: @@ -4187,7 +4431,7 @@ static void process_state_iv_pps_null(t30_state_t *s, const uint8_t *msg, int le s->phase_d_handler(s, s->phase_d_user_data, fcf); terminate_operation_in_progress(s); send_dcn(s); - report_tx_result(s, TRUE); + report_tx_result(s, true); break; } } @@ -4281,8 +4525,8 @@ static void process_state_iv_pps_q(t30_state_t *s, const uint8_t *msg, int len) if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); terminate_operation_in_progress(s); - report_tx_result(s, TRUE); - return_to_phase_b(s, FALSE); + report_tx_result(s, true); + return_to_phase_b(s, false); break; case T30_PRI_EOP: case T30_EOP: @@ -4291,7 +4535,7 @@ static void process_state_iv_pps_q(t30_state_t *s, const uint8_t *msg, int len) s->phase_d_handler(s, s->phase_d_user_data, fcf); terminate_operation_in_progress(s); send_dcn(s); - report_tx_result(s, TRUE); + report_tx_result(s, true); break; } } @@ -4396,8 +4640,8 @@ static void process_state_iv_pps_rnr(t30_state_t *s, const uint8_t *msg, int len if (s->phase_d_handler) s->phase_d_handler(s, s->phase_d_user_data, fcf); terminate_operation_in_progress(s); - report_tx_result(s, TRUE); - return_to_phase_b(s, FALSE); + report_tx_result(s, true); + return_to_phase_b(s, false); break; case T30_PRI_EOP: case T30_EOP: @@ -4406,7 +4650,7 @@ static void process_state_iv_pps_rnr(t30_state_t *s, const uint8_t *msg, int len s->phase_d_handler(s, s->phase_d_user_data, fcf); terminate_operation_in_progress(s); send_dcn(s); - report_tx_result(s, TRUE); + report_tx_result(s, true); break; } } @@ -4457,7 +4701,7 @@ static void process_state_iv_ctc(t30_state_t *s, const uint8_t *msg, int len) case T30_CTR: /* Valid response to a CTC received */ /* T.30 says we change back to long training here */ - s->short_train = FALSE; + s->short_train = false; /* Initiate resending of the remainder of the frames. */ set_state(s, T30_STATE_IV); queue_phase(s, T30_PHASE_C_ECM_TX); @@ -4583,7 +4827,7 @@ static void process_rx_control_msg(t30_state_t *s, const uint8_t *msg, int len) /* We should only get good frames here. */ print_frame(s, "Rx: ", msg, len); if (s->real_time_frame_handler) - s->real_time_frame_handler(s, s->real_time_frame_user_data, TRUE, msg, len); + s->real_time_frame_handler(s, s->real_time_frame_user_data, true, msg, len); if ((msg[1] & 0x10) == 0) { @@ -4884,42 +5128,42 @@ static void set_phase(t30_state_t *s, int phase) signal. Force the signal present indicator to off, because the receiver will never be able to. */ if (s->phase != T30_PHASE_A_CED && s->phase != T30_PHASE_A_CNG) - s->rx_signal_present = FALSE; - s->rx_trained = FALSE; - s->rx_frame_received = FALSE; + s->rx_signal_present = false; + s->rx_trained = false; + s->rx_frame_received = false; s->phase = phase; switch (phase) { case T30_PHASE_A_CED: if (s->set_rx_type_handler) - s->set_rx_type_handler(s->set_rx_type_user_data, T30_MODEM_V21, 300, FALSE, TRUE); + s->set_rx_type_handler(s->set_rx_type_user_data, T30_MODEM_V21, 300, false, true); if (s->set_tx_type_handler) - s->set_tx_type_handler(s->set_tx_type_user_data, T30_MODEM_CED, 0, FALSE, FALSE); + s->set_tx_type_handler(s->set_tx_type_user_data, T30_MODEM_CED, 0, false, false); break; case T30_PHASE_A_CNG: if (s->set_rx_type_handler) - s->set_rx_type_handler(s->set_rx_type_user_data, T30_MODEM_V21, 300, FALSE, TRUE); + s->set_rx_type_handler(s->set_rx_type_user_data, T30_MODEM_V21, 300, false, true); if (s->set_tx_type_handler) - s->set_tx_type_handler(s->set_tx_type_user_data, T30_MODEM_CNG, 0, FALSE, FALSE); + s->set_tx_type_handler(s->set_tx_type_user_data, T30_MODEM_CNG, 0, false, false); break; case T30_PHASE_B_RX: case T30_PHASE_D_RX: if (s->set_rx_type_handler) - s->set_rx_type_handler(s->set_rx_type_user_data, T30_MODEM_V21, 300, FALSE, TRUE); + s->set_rx_type_handler(s->set_rx_type_user_data, T30_MODEM_V21, 300, false, true); if (s->set_tx_type_handler) - s->set_tx_type_handler(s->set_tx_type_user_data, T30_MODEM_NONE, 0, FALSE, FALSE); + s->set_tx_type_handler(s->set_tx_type_user_data, T30_MODEM_NONE, 0, false, false); break; case T30_PHASE_B_TX: case T30_PHASE_D_TX: if (!s->far_end_detected && s->timer_t0_t1 > 0) { s->timer_t0_t1 = ms_to_samples(DEFAULT_TIMER_T1); - s->far_end_detected = TRUE; + s->far_end_detected = true; } if (s->set_rx_type_handler) - s->set_rx_type_handler(s->set_rx_type_user_data, T30_MODEM_NONE, 0, FALSE, FALSE); + s->set_rx_type_handler(s->set_rx_type_user_data, T30_MODEM_NONE, 0, false, false); if (s->set_tx_type_handler) - s->set_tx_type_handler(s->set_tx_type_user_data, T30_MODEM_V21, 300, FALSE, TRUE); + s->set_tx_type_handler(s->set_tx_type_user_data, T30_MODEM_V21, 300, false, true); break; case T30_PHASE_C_NON_ECM_RX: if (s->set_rx_type_handler) @@ -4927,11 +5171,11 @@ static void set_phase(t30_state_t *s, int phase) /* Momentarily stop the receive modem, so the next change is forced to happen. If we don't do this an HDLC message on the slow modem, which has disabled the fast modem, will prevent the same fast modem from restarting. */ - s->set_rx_type_handler(s->set_rx_type_user_data, T30_MODEM_NONE, 0, FALSE, FALSE); - s->set_rx_type_handler(s->set_rx_type_user_data, fallback_sequence[s->current_fallback].modem_type, fallback_sequence[s->current_fallback].bit_rate, s->short_train, FALSE); + s->set_rx_type_handler(s->set_rx_type_user_data, T30_MODEM_NONE, 0, false, false); + s->set_rx_type_handler(s->set_rx_type_user_data, fallback_sequence[s->current_fallback].modem_type, fallback_sequence[s->current_fallback].bit_rate, s->short_train, false); } if (s->set_tx_type_handler) - s->set_tx_type_handler(s->set_tx_type_user_data, T30_MODEM_NONE, 0, FALSE, FALSE); + s->set_tx_type_handler(s->set_tx_type_user_data, T30_MODEM_NONE, 0, false, false); break; case T30_PHASE_C_NON_ECM_TX: /* Pause before switching from anything to phase C */ @@ -4943,24 +5187,24 @@ static void set_phase(t30_state_t *s, int phase) /* Momentarily stop the receive modem, so the next change is forced to happen. If we don't do this an HDLC message on the slow modem, which has disabled the fast modem, will prevent the same fast modem from restarting. */ - s->set_rx_type_handler(s->set_rx_type_user_data, T30_MODEM_NONE, 0, FALSE, FALSE); - s->set_rx_type_handler(s->set_rx_type_user_data, T30_MODEM_NONE, 0, FALSE, FALSE); + s->set_rx_type_handler(s->set_rx_type_user_data, T30_MODEM_NONE, 0, false, false); + s->set_rx_type_handler(s->set_rx_type_user_data, T30_MODEM_NONE, 0, false, false); } if (s->set_tx_type_handler) - s->set_tx_type_handler(s->set_tx_type_user_data, fallback_sequence[s->current_fallback].modem_type, fallback_sequence[s->current_fallback].bit_rate, s->short_train, FALSE); + s->set_tx_type_handler(s->set_tx_type_user_data, fallback_sequence[s->current_fallback].modem_type, fallback_sequence[s->current_fallback].bit_rate, s->short_train, false); break; case T30_PHASE_C_ECM_RX: if (s->set_rx_type_handler) - s->set_rx_type_handler(s->set_rx_type_user_data, fallback_sequence[s->current_fallback].modem_type, fallback_sequence[s->current_fallback].bit_rate, s->short_train, TRUE); + s->set_rx_type_handler(s->set_rx_type_user_data, fallback_sequence[s->current_fallback].modem_type, fallback_sequence[s->current_fallback].bit_rate, s->short_train, true); if (s->set_tx_type_handler) - s->set_tx_type_handler(s->set_tx_type_user_data, T30_MODEM_NONE, 0, FALSE, FALSE); + s->set_tx_type_handler(s->set_tx_type_user_data, T30_MODEM_NONE, 0, false, false); break; case T30_PHASE_C_ECM_TX: /* Pause before switching from anything to phase C */ if (s->set_rx_type_handler) - s->set_rx_type_handler(s->set_rx_type_user_data, T30_MODEM_NONE, 0, FALSE, FALSE); + s->set_rx_type_handler(s->set_rx_type_user_data, T30_MODEM_NONE, 0, false, false); if (s->set_tx_type_handler) - s->set_tx_type_handler(s->set_tx_type_user_data, fallback_sequence[s->current_fallback].modem_type, fallback_sequence[s->current_fallback].bit_rate, s->short_train, TRUE); + s->set_tx_type_handler(s->set_tx_type_user_data, fallback_sequence[s->current_fallback].modem_type, fallback_sequence[s->current_fallback].bit_rate, s->short_train, true); break; case T30_PHASE_E: /* Send a little silence before ending things, to ensure the @@ -4970,15 +5214,15 @@ static void set_phase(t30_state_t *s, int phase) s->tcf_current_zeros = 0; s->tcf_most_zeros = 0; if (s->set_rx_type_handler) - s->set_rx_type_handler(s->set_rx_type_user_data, T30_MODEM_NONE, 0, FALSE, FALSE); + s->set_rx_type_handler(s->set_rx_type_user_data, T30_MODEM_NONE, 0, false, false); if (s->set_tx_type_handler) - s->set_tx_type_handler(s->set_tx_type_user_data, T30_MODEM_PAUSE, 0, FINAL_FLUSH_TIME, FALSE); + s->set_tx_type_handler(s->set_tx_type_user_data, T30_MODEM_PAUSE, 0, FINAL_FLUSH_TIME, false); break; case T30_PHASE_CALL_FINISHED: if (s->set_rx_type_handler) - s->set_rx_type_handler(s->set_rx_type_user_data, T30_MODEM_DONE, 0, FALSE, FALSE); + s->set_rx_type_handler(s->set_rx_type_user_data, T30_MODEM_DONE, 0, false, false); if (s->set_tx_type_handler) - s->set_tx_type_handler(s->set_tx_type_user_data, T30_MODEM_DONE, 0, FALSE, FALSE); + s->set_tx_type_handler(s->set_tx_type_user_data, T30_MODEM_DONE, 0, false, false); break; } } @@ -5025,9 +5269,9 @@ static void repeat_last_command(t30_state_t *s) switch (s->state) { case T30_STATE_R: - s->dis_received = FALSE; + s->dis_received = false; queue_phase(s, T30_PHASE_B_TX); - send_dis_or_dtc_sequence(s, TRUE); + send_dis_or_dtc_sequence(s, true); break; case T30_STATE_III_Q_MCF: queue_phase(s, T30_PHASE_D_TX); @@ -5057,7 +5301,7 @@ static void repeat_last_command(t30_state_t *s) break; case T30_STATE_D: queue_phase(s, T30_PHASE_B_TX); - send_dcs_sequence(s, TRUE); + send_dcs_sequence(s, true); break; case T30_STATE_F_FTT: queue_phase(s, T30_PHASE_B_TX); @@ -5065,13 +5309,13 @@ static void repeat_last_command(t30_state_t *s) break; case T30_STATE_F_CFR: queue_phase(s, T30_PHASE_B_TX); - send_cfr_sequence(s, TRUE); + send_cfr_sequence(s, true); break; case T30_STATE_D_POST_TCF: /* Need to send the whole training thing again */ - s->short_train = FALSE; + s->short_train = false; queue_phase(s, T30_PHASE_B_TX); - send_dcs_sequence(s, TRUE); + send_dcs_sequence(s, true); break; case T30_STATE_F_POST_RCP_RNR: /* Just ignore */ @@ -5247,8 +5491,8 @@ static void timer_t2_expired(t30_state_t *s) span_log(&s->logging, SPAN_LOG_FLOW, "Returning to phase B after %s\n", t30_frametype(s->next_rx_step)); set_phase(s, T30_PHASE_B_TX); timer_t2_start(s); - s->dis_received = FALSE; - send_dis_or_dtc_sequence(s, TRUE); + s->dis_received = false; + send_dis_or_dtc_sequence(s, true); return; } break; @@ -5434,7 +5678,7 @@ static int decode_nsf_nss_nsc(t30_state_t *s, uint8_t *msg[], const uint8_t *pkt { uint8_t *t; - if ((t = malloc(len - 1)) == NULL) + if ((t = span_alloc(len - 1)) == NULL) return 0; memcpy(t, pkt + 1, len - 1); *msg = t; @@ -5454,7 +5698,7 @@ static void t30_non_ecm_rx_status(void *user_data, int status) case SIG_STATUS_TRAINING_IN_PROGRESS: break; case SIG_STATUS_TRAINING_FAILED: - s->rx_trained = FALSE; + s->rx_trained = false; break; case SIG_STATUS_TRAINING_SUCCEEDED: /* The modem is now trained */ @@ -5462,16 +5706,16 @@ static void t30_non_ecm_rx_status(void *user_data, int status) s->tcf_test_bits = 0; s->tcf_current_zeros = 0; s->tcf_most_zeros = 0; - s->rx_signal_present = TRUE; - s->rx_trained = TRUE; + s->rx_signal_present = true; + s->rx_trained = true; timer_t2_t4_stop(s); break; case SIG_STATUS_CARRIER_UP: break; case SIG_STATUS_CARRIER_DOWN: was_trained = s->rx_trained; - s->rx_signal_present = FALSE; - s->rx_trained = FALSE; + s->rx_signal_present = false; + s->rx_trained = false; switch (s->state) { case T30_STATE_F_TCF: @@ -5499,11 +5743,11 @@ static void t30_non_ecm_rx_status(void *user_data, int status) else { /* The training went OK */ - s->short_train = TRUE; + s->short_train = true; rx_start_page(s); set_phase(s, T30_PHASE_B_TX); set_state(s, T30_STATE_F_CFR); - send_cfr_sequence(s, TRUE); + send_cfr_sequence(s, true); } } break; @@ -5548,6 +5792,7 @@ static void t30_non_ecm_rx_status(void *user_data, int status) SPAN_DECLARE_NONSTD(void) t30_non_ecm_put_bit(void *user_data, int bit) { t30_state_t *s; + int res; if (bit < 0) { @@ -5572,10 +5817,12 @@ SPAN_DECLARE_NONSTD(void) t30_non_ecm_put_bit(void *user_data, int bit) } break; case T30_STATE_F_DOC_NON_ECM: - /* Document transfer */ - if (t4_rx_put_bit(&s->t4.rx, bit) == T4_DECODE_OK) + /* Image transfer */ + if ((res = t4_rx_put_bit(&s->t4.rx, bit)) != T4_DECODE_MORE_DATA) { - /* That is the end of the document */ + /* This is the end of the image */ + if (res != T4_DECODE_OK) + span_log(&s->logging, SPAN_LOG_FLOW, "Page ended with status %d\n", res); set_state(s, T30_STATE_F_POST_DOC_NON_ECM); queue_phase(s, T30_PHASE_D_RX); timer_t2_start(s); @@ -5589,6 +5836,7 @@ SPAN_DECLARE(void) t30_non_ecm_put(void *user_data, const uint8_t buf[], int len { t30_state_t *s; int i; + int res; s = (t30_state_t *) user_data; switch (s->state) @@ -5612,10 +5860,12 @@ SPAN_DECLARE(void) t30_non_ecm_put(void *user_data, const uint8_t buf[], int len } break; case T30_STATE_F_DOC_NON_ECM: - /* Document transfer */ - if (t4_rx_put(&s->t4.rx, buf, len)) + /* Image transfer */ + if ((res = t4_rx_put(&s->t4.rx, buf, len)) != T4_DECODE_MORE_DATA) { - /* That is the end of the document */ + /* This is the end of the image */ + if (res != T4_DECODE_OK) + span_log(&s->logging, SPAN_LOG_FLOW, "Page ended with status %d\n", res); set_state(s, T30_STATE_F_POST_DOC_NON_ECM); queue_phase(s, T30_PHASE_D_RX); timer_t2_start(s); @@ -5707,15 +5957,15 @@ static void t30_hdlc_rx_status(void *user_data, int status) case SIG_STATUS_TRAINING_IN_PROGRESS: break; case SIG_STATUS_TRAINING_FAILED: - s->rx_trained = FALSE; + s->rx_trained = false; break; case SIG_STATUS_TRAINING_SUCCEEDED: /* The modem is now trained */ - s->rx_signal_present = TRUE; - s->rx_trained = TRUE; + s->rx_signal_present = true; + s->rx_trained = true; break; case SIG_STATUS_CARRIER_UP: - s->rx_signal_present = TRUE; + s->rx_signal_present = true; switch (s->timer_t2_t4_is) { case TIMER_IS_T2B: @@ -5730,8 +5980,8 @@ static void t30_hdlc_rx_status(void *user_data, int status) break; case SIG_STATUS_CARRIER_DOWN: was_trained = s->rx_trained; - s->rx_signal_present = FALSE; - s->rx_trained = FALSE; + s->rx_signal_present = false; + s->rx_trained = false; /* If a phase change has been queued to occur after the receive signal drops, its time to change. */ if (s->state == T30_STATE_F_DOC_ECM) @@ -5784,7 +6034,7 @@ static void t30_hdlc_rx_status(void *user_data, int status) if (!s->far_end_detected && s->timer_t0_t1 > 0) { s->timer_t0_t1 = ms_to_samples(DEFAULT_TIMER_T1); - s->far_end_detected = TRUE; + s->far_end_detected = true; if (s->phase == T30_PHASE_A_CED || s->phase == T30_PHASE_A_CNG) set_phase(s, T30_PHASE_B_RX); } @@ -5879,7 +6129,7 @@ SPAN_DECLARE_NONSTD(void) t30_hdlc_accept(void *user_data, const uint8_t *msg, i timer_t2_t4_stop(s); return; } - s->rx_frame_received = TRUE; + s->rx_frame_received = true; /* Cancel the command or response timer (if one is running) */ timer_t2_t4_stop(s); process_rx_control_msg(s, msg, len); @@ -5903,11 +6153,11 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status) span_log(&s->logging, SPAN_LOG_FLOW, "Starting answer mode\n"); set_phase(s, T30_PHASE_B_TX); timer_t2_start(s); - s->dis_received = FALSE; - send_dis_or_dtc_sequence(s, TRUE); + s->dis_received = false; + send_dis_or_dtc_sequence(s, true); break; case T30_STATE_R: - if (send_dis_or_dtc_sequence(s, FALSE)) + if (send_dis_or_dtc_sequence(s, false)) { /* Wait for an acknowledgement. */ set_phase(s, T30_PHASE_B_RX); @@ -5915,12 +6165,7 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status) } break; case T30_STATE_F_CFR: - if (s->step == 0) - { - shut_down_hdlc_tx(s); - s->step++; - } - else + if (send_cfr_sequence(s, false)) { if (s->error_correcting_mode) { @@ -6040,13 +6285,13 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status) } break; case T30_STATE_D: - if (send_dcs_sequence(s, FALSE)) + if (send_dcs_sequence(s, false)) { if ((s->iaf & T30_IAF_MODE_NO_TCF)) { /* Skip the trainability test */ s->retries = 0; - s->short_train = TRUE; + s->short_train = true; if (s->error_correcting_mode) { set_state(s, T30_STATE_IV); @@ -6062,7 +6307,7 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status) { /* Do the trainability test */ /* TCF is always sent with long training */ - s->short_train = FALSE; + s->short_train = false; set_state(s, T30_STATE_D_TCF); set_phase(s, T30_PHASE_C_NON_ECM_TX); } @@ -6096,7 +6341,8 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status) { /* Send the end of page or partial page message */ set_phase(s, T30_PHASE_D_TX); - s->next_tx_step = check_next_tx_step(s); + if (s->ecm_at_page_end) + s->next_tx_step = check_next_tx_step(s); if (send_pps_frame(s) == T30_NULL) set_state(s, T30_STATE_IV_PPS_NULL); else @@ -6165,7 +6411,7 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status) default: /* Cancel any receive timeout, and declare that a receive signal is present, since the front end is explicitly telling us we have seen something. */ - s->rx_signal_present = TRUE; + s->rx_signal_present = true; timer_t2_t4_stop(s); break; } @@ -6328,7 +6574,7 @@ SPAN_DECLARE(void) t30_get_transfer_statistics(t30_state_t *s, t30_stats_t *t) t->width = stats.width; t->length = stats.length; - t->encoding = stats.encoding; + t->compression = stats.compression; t->image_size = stats.line_image_size; t->current_status = s->current_status; t->rtn_events = s->rtn_events; @@ -6359,14 +6605,13 @@ SPAN_DECLARE(int) t30_restart(t30_state_t *s) s->phase = T30_PHASE_IDLE; s->next_phase = T30_PHASE_IDLE; s->current_fallback = 0; - s->rx_signal_present = FALSE; - s->rx_trained = FALSE; - s->rx_frame_received = FALSE; + s->rx_signal_present = false; + s->rx_trained = false; + s->rx_frame_received = false; s->current_status = T30_ERR_OK; s->ppr_count = 0; s->ecm_progress = 0; s->receiver_not_ready_count = 0; - s->far_dis_dtc_len = 0; memset(&s->far_dis_dtc_frame, 0, sizeof(s->far_dis_dtc_frame)); t30_build_dis_or_dtc(s); memset(&s->rx_info, 0, sizeof(s->rx_info)); @@ -6376,9 +6621,9 @@ SPAN_DECLARE(int) t30_restart(t30_state_t *s) s->tx_page_number = 0; s->rtn_events = 0; s->rtp_events = 0; - s->local_interrupt_pending = FALSE; - s->far_end_detected = FALSE; - s->end_of_procedure_detected = FALSE; + s->local_interrupt_pending = false; + s->far_end_detected = false; + s->end_of_procedure_detected = false; s->timer_t0_t1 = ms_to_samples(DEFAULT_TIMER_T0); if (s->calling_party) { @@ -6405,7 +6650,7 @@ SPAN_DECLARE(t30_state_t *) t30_init(t30_state_t *s, { if (s == NULL) { - if ((s = (t30_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (t30_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -6419,18 +6664,22 @@ SPAN_DECLARE(t30_state_t *) t30_init(t30_state_t *s, /* Default to the basic modems. */ s->supported_modems = T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17; - s->supported_compressions = T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION; - s->supported_resolutions = T30_SUPPORT_STANDARD_RESOLUTION - | T30_SUPPORT_FINE_RESOLUTION - | T30_SUPPORT_SUPERFINE_RESOLUTION - | T30_SUPPORT_R8_RESOLUTION; - s->supported_image_sizes = T30_SUPPORT_US_LETTER_LENGTH - | T30_SUPPORT_US_LEGAL_LENGTH - | T30_SUPPORT_UNLIMITED_LENGTH - | T30_SUPPORT_215MM_WIDTH; - /* Set the output encoding to something safe. Most things get 1D and 2D - encoding right. Quite a lot get other things wrong. */ - s->output_encoding = T4_COMPRESSION_ITU_T4_2D; + s->supported_compressions = T4_COMPRESSION_T4_1D | T4_COMPRESSION_T4_2D; + s->supported_bilevel_resolutions = T4_RESOLUTION_R8_STANDARD + | T4_RESOLUTION_R8_FINE + | T4_RESOLUTION_R8_SUPERFINE + | T4_RESOLUTION_200_100 + | T4_RESOLUTION_200_200 + | T4_RESOLUTION_200_400; + s->supported_image_sizes = T4_SUPPORT_WIDTH_215MM + | T4_SUPPORT_LENGTH_US_LETTER + | T4_SUPPORT_LENGTH_US_LEGAL + | T4_SUPPORT_LENGTH_A4 + | T4_SUPPORT_LENGTH_B4 + | T4_SUPPORT_LENGTH_UNLIMITED; + /* Set the output encoding to something safe. For bi-level images most things + get 1D and 2D encoding right. Quite a lot get other things wrong. */ + s->supported_output_compressions = T4_COMPRESSION_T4_2D | T4_COMPRESSION_JPEG; s->local_min_scan_time_code = T30_MIN_SCAN_0MS; span_log_init(&s->logging, SPAN_LOG_NONE, NULL); span_log_set_protocol(&s->logging, "T.30"); @@ -6451,7 +6700,7 @@ SPAN_DECLARE(int) t30_release(t30_state_t *s) SPAN_DECLARE(int) t30_free(t30_state_t *s) { t30_release(s); - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/t30_api.c b/libs/spandsp/src/t30_api.c index e6d157c21e..6d0bca3840 100644 --- a/libs/spandsp/src/t30_api.c +++ b/libs/spandsp/src/t30_api.c @@ -41,10 +41,16 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/bit_operations.h" #include "spandsp/queue.h" @@ -65,9 +71,7 @@ #include "spandsp/t81_t82_arith_coding.h" #include "spandsp/t85.h" #include "spandsp/t42.h" -#if defined(SPANDSP_SUPPORT_T43) #include "spandsp/t43.h" -#endif #include "spandsp/t4_t6_decode.h" #include "spandsp/t4_t6_encode.h" #include "spandsp/t30_fcf.h" @@ -81,9 +85,7 @@ #include "spandsp/private/t81_t82_arith_coding.h" #include "spandsp/private/t85.h" #include "spandsp/private/t42.h" -#if defined(SPANDSP_SUPPORT_T43) #include "spandsp/private/t43.h" -#endif #include "spandsp/private/t4_t6_decode.h" #include "spandsp/private/t4_t6_encode.h" #include "spandsp/private/image_translate.h" @@ -277,8 +279,8 @@ SPAN_DECLARE(const char *) t30_get_rx_password(t30_state_t *s) SPAN_DECLARE(int) t30_set_tx_nsf(t30_state_t *s, const uint8_t *nsf, int len) { if (s->tx_info.nsf) - free(s->tx_info.nsf); - if (nsf && len > 0 && (s->tx_info.nsf = malloc(len + 3))) + span_free(s->tx_info.nsf); + if (nsf && len > 0 && (s->tx_info.nsf = span_alloc(len + 3))) { memcpy(s->tx_info.nsf + 3, nsf, len); s->tx_info.nsf_len = len; @@ -311,8 +313,8 @@ SPAN_DECLARE(size_t) t30_get_rx_nsf(t30_state_t *s, const uint8_t *nsf[]) SPAN_DECLARE(int) t30_set_tx_nsc(t30_state_t *s, const uint8_t *nsc, int len) { if (s->tx_info.nsc) - free(s->tx_info.nsc); - if (nsc && len > 0 && (s->tx_info.nsc = malloc(len + 3))) + span_free(s->tx_info.nsc); + if (nsc && len > 0 && (s->tx_info.nsc = span_alloc(len + 3))) { memcpy(s->tx_info.nsc + 3, nsc, len); s->tx_info.nsc_len = len; @@ -345,8 +347,8 @@ SPAN_DECLARE(size_t) t30_get_rx_nsc(t30_state_t *s, const uint8_t *nsc[]) SPAN_DECLARE(int) t30_set_tx_nss(t30_state_t *s, const uint8_t *nss, int len) { if (s->tx_info.nss) - free(s->tx_info.nss); - if (nss && len > 0 && (s->tx_info.nss = malloc(len + 3))) + span_free(s->tx_info.nss); + if (nss && len > 0 && (s->tx_info.nss = span_alloc(len + 3))) { memcpy(s->tx_info.nss + 3, nss, len); s->tx_info.nss_len = len; @@ -379,7 +381,7 @@ SPAN_DECLARE(size_t) t30_get_rx_nss(t30_state_t *s, const uint8_t *nss[]) SPAN_DECLARE(int) t30_set_tx_tsa(t30_state_t *s, int type, const char *address, int len) { if (s->tx_info.tsa) - free(s->tx_info.tsa); + span_free(s->tx_info.tsa); if (address == NULL || len == 0) { s->tx_info.tsa = NULL; @@ -389,7 +391,7 @@ SPAN_DECLARE(int) t30_set_tx_tsa(t30_state_t *s, int type, const char *address, s->tx_info.tsa_type = type; if (len < 0) len = strlen(address); - if ((s->tx_info.tsa = malloc(len))) + if ((s->tx_info.tsa = span_alloc(len))) { memcpy(s->tx_info.tsa, address, len); s->tx_info.tsa_len = len; @@ -421,7 +423,7 @@ SPAN_DECLARE(size_t) t30_get_rx_tsa(t30_state_t *s, int *type, const char *addre SPAN_DECLARE(int) t30_set_tx_ira(t30_state_t *s, int type, const char *address, int len) { if (s->tx_info.ira) - free(s->tx_info.ira); + span_free(s->tx_info.ira); if (address == NULL) { s->tx_info.ira = NULL; @@ -455,7 +457,7 @@ SPAN_DECLARE(size_t) t30_get_rx_ira(t30_state_t *s, int *type, const char *addre SPAN_DECLARE(int) t30_set_tx_cia(t30_state_t *s, int type, const char *address, int len) { if (s->tx_info.cia) - free(s->tx_info.cia); + span_free(s->tx_info.cia); if (address == NULL) { s->tx_info.cia = NULL; @@ -489,7 +491,7 @@ SPAN_DECLARE(size_t) t30_get_rx_cia(t30_state_t *s, int *type, const char *addre SPAN_DECLARE(int) t30_set_tx_isp(t30_state_t *s, int type, const char *address, int len) { if (s->tx_info.isp) - free(s->tx_info.isp); + span_free(s->tx_info.isp); if (address == NULL) { s->tx_info.isp = NULL; @@ -523,7 +525,7 @@ SPAN_DECLARE(size_t) t30_get_rx_isp(t30_state_t *s, int *type, const char *addre SPAN_DECLARE(int) t30_set_tx_csa(t30_state_t *s, int type, const char *address, int len) { if (s->tx_info.csa) - free(s->tx_info.csa); + span_free(s->tx_info.csa); if (address == NULL) { s->tx_info.csa = NULL; @@ -554,7 +556,7 @@ SPAN_DECLARE(size_t) t30_get_rx_csa(t30_state_t *s, int *type, const char *addre } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) t30_set_tx_page_header_overlays_image(t30_state_t *s, int header_overlays_image) +SPAN_DECLARE(int) t30_set_tx_page_header_overlays_image(t30_state_t *s, bool header_overlays_image) { s->header_overlays_image = header_overlays_image; t4_tx_set_header_overlays_image(&s->t4.tx, s->header_overlays_image); @@ -589,7 +591,7 @@ SPAN_DECLARE(int) t30_set_tx_page_header_tz(t30_state_t *s, const char *tzstring { if (tz_init(&s->tz, tzstring)) { - s->use_own_tz = TRUE; + s->use_own_tz = true; t4_tx_set_header_tz(&s->t4.tx, &s->tz); return 0; } @@ -632,13 +634,13 @@ SPAN_DECLARE(void) t30_set_tx_file(t30_state_t *s, const char *file, int start_p } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) t30_set_iaf_mode(t30_state_t *s, int iaf) +SPAN_DECLARE(void) t30_set_iaf_mode(t30_state_t *s, bool iaf) { s->iaf = iaf; } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) t30_set_ecm_capability(t30_state_t *s, int enabled) +SPAN_DECLARE(int) t30_set_ecm_capability(t30_state_t *s, bool enabled) { s->ecm_allowed = enabled; t30_build_dis_or_dtc(s); @@ -646,19 +648,38 @@ SPAN_DECLARE(int) t30_set_ecm_capability(t30_state_t *s, int enabled) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) t30_set_rx_encoding(t30_state_t *s, int encoding) +SPAN_DECLARE(void) t30_set_keep_bad_quality_pages(t30_state_t *s, bool keep_bad_pages) { - switch (encoding) - { - case T4_COMPRESSION_ITU_T4_1D: - case T4_COMPRESSION_ITU_T4_2D: - case T4_COMPRESSION_ITU_T6: - //case T4_COMPRESSION_ITU_T85: - //case T4_COMPRESSION_ITU_T85_L0: - s->output_encoding = encoding; - return 0; - } - return -1; + s->keep_bad_pages = keep_bad_pages; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t30_set_supported_output_compressions(t30_state_t *s, int supported_compressions) +{ + /* Mask out the ones we actually support today. */ + supported_compressions &= T4_COMPRESSION_T4_1D + | T4_COMPRESSION_T4_2D + | T4_COMPRESSION_T6 + | T4_COMPRESSION_T85 + | T4_COMPRESSION_T85_L0 +#if defined(SPANDSP_SUPPORT_T88) + | T4_COMPRESSION_T88 +#endif + | T4_COMPRESSION_T42_T81 +#if defined(SPANDSP_SUPPORT_SYCC_T81) + | T4_COMPRESSION_SYCC_T81 +#endif +#if defined(SPANDSP_SUPPORT_T43) + | T4_COMPRESSION_T43 +#endif +#if defined(SPANDSP_SUPPORT_T45) + | T4_COMPRESSION_T45 +#endif + | T4_COMPRESSION_UNCOMPRESSED + | T4_COMPRESSION_JPEG + | 0; + s->supported_output_compressions = supported_compressions; + return 0; } /*- End of function --------------------------------------------------------*/ @@ -693,28 +714,77 @@ 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) { - int mask; - /* Mask out the ones we actually support today. */ - mask = T30_SUPPORT_T4_1D_COMPRESSION - | T30_SUPPORT_T4_2D_COMPRESSION - | T30_SUPPORT_T6_COMPRESSION - //| T30_SUPPORT_T81_COMPRESSION -#if defined(SPANDSP_SUPPORT_T43) - | T30_SUPPORT_T43_COMPRESSION + supported_compressions &= T4_COMPRESSION_T4_1D + | T4_COMPRESSION_T4_2D + | T4_COMPRESSION_T6 + | T4_COMPRESSION_T85 + | T4_COMPRESSION_T85_L0 +#if defined(SPANDSP_SUPPORT_T88) + | T4_COMPRESSION_T88 #endif - | T30_SUPPORT_T85_COMPRESSION - | T30_SUPPORT_T85_L0_COMPRESSION - | 0; - s->supported_compressions = supported_compressions & mask; + | T4_COMPRESSION_T42_T81 +#if defined(SPANDSP_SUPPORT_SYCC_T81) + | T4_COMPRESSION_SYCC_T81 +#endif +#if defined(SPANDSP_SUPPORT_T43) + | T4_COMPRESSION_T43 +#endif +#if defined(SPANDSP_SUPPORT_T45) + | T4_COMPRESSION_T45 +#endif + | T4_COMPRESSION_GRAYSCALE + | T4_COMPRESSION_COLOUR + | T4_COMPRESSION_12BIT + | T4_COMPRESSION_COLOUR_TO_GRAY + | T4_COMPRESSION_GRAY_TO_BILEVEL + | T4_COMPRESSION_COLOUR_TO_BILEVEL + | T4_COMPRESSION_RESCALING + | 0; + + s->supported_compressions = supported_compressions; t30_build_dis_or_dtc(s); return 0; } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) t30_set_supported_resolutions(t30_state_t *s, int supported_resolutions) +SPAN_DECLARE(int) t30_set_supported_bilevel_resolutions(t30_state_t *s, int supported_resolutions) { - s->supported_resolutions = supported_resolutions; + supported_resolutions &= T4_RESOLUTION_R8_STANDARD + | T4_RESOLUTION_R8_FINE + | T4_RESOLUTION_R8_SUPERFINE + | T4_RESOLUTION_R16_SUPERFINE + | T4_RESOLUTION_200_100 + | T4_RESOLUTION_200_200 + | T4_RESOLUTION_200_400 + | T4_RESOLUTION_300_300 + | T4_RESOLUTION_300_600 + | T4_RESOLUTION_400_400 + | T4_RESOLUTION_400_800 + | T4_RESOLUTION_600_600 + | T4_RESOLUTION_600_1200 + | T4_RESOLUTION_1200_1200; + /* Make sure anything needed for colour is enabled as a bi-level image, as that is a + rule from T.30. 100x100 is an exception, as it doesn't exist as a bi-level resolution. */ + supported_resolutions |= (s->supported_colour_resolutions & ~T4_RESOLUTION_100_100); + s->supported_bilevel_resolutions = supported_resolutions; + t30_build_dis_or_dtc(s); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t30_set_supported_colour_resolutions(t30_state_t *s, int supported_resolutions) +{ + supported_resolutions &= T4_RESOLUTION_100_100 + | T4_RESOLUTION_200_200 + | T4_RESOLUTION_300_300 + | T4_RESOLUTION_400_400 + | T4_RESOLUTION_600_600 + | T4_RESOLUTION_1200_1200; + s->supported_colour_resolutions = supported_resolutions; + /* Make sure anything needed for colour is enabled as a bi-level image, as that is a + rule from T.30. 100x100 is an exception, as it doesn't exist as a bi-level resolution. */ + s->supported_bilevel_resolutions |= (s->supported_colour_resolutions & ~T4_RESOLUTION_100_100); t30_build_dis_or_dtc(s); return 0; } @@ -722,6 +792,13 @@ SPAN_DECLARE(int) t30_set_supported_resolutions(t30_state_t *s, int supported_re SPAN_DECLARE(int) t30_set_supported_image_sizes(t30_state_t *s, int supported_image_sizes) { + /* Force the sizes which are always available */ + supported_image_sizes |= (T4_SUPPORT_WIDTH_215MM | T4_SUPPORT_LENGTH_A4); + /* Force the sizes which depend on sizes which are supported */ + if ((supported_image_sizes & T4_SUPPORT_LENGTH_UNLIMITED)) + supported_image_sizes |= T4_SUPPORT_LENGTH_B4; + if ((supported_image_sizes & T4_SUPPORT_WIDTH_303MM)) + supported_image_sizes |= T4_SUPPORT_WIDTH_255MM; s->supported_image_sizes = supported_image_sizes; t30_build_dis_or_dtc(s); return 0; @@ -788,6 +865,20 @@ SPAN_DECLARE(void) t30_set_real_time_frame_handler(t30_state_t *s, t30_real_time } /*- End of function --------------------------------------------------------*/ +SPAN_DECLARE(void) t30_set_document_get_handler(t30_state_t *s, t30_document_get_handler_t handler, void *user_data) +{ + s->document_get_handler = handler; + s->document_get_user_data = user_data; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(void) t30_set_document_put_handler(t30_state_t *s, t30_document_put_handler_t handler, void *user_data) +{ + s->document_put_handler = handler; + s->document_put_user_data = user_data; +} +/*- End of function --------------------------------------------------------*/ + SPAN_DECLARE(logging_state_t *) t30_get_logging_state(t30_state_t *s) { return &s->logging; diff --git a/libs/spandsp/src/t30_logging.c b/libs/spandsp/src/t30_logging.c index 33efcb9c03..51739999d1 100644 --- a/libs/spandsp/src/t30_logging.c +++ b/libs/spandsp/src/t30_logging.c @@ -41,6 +41,11 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include @@ -65,9 +70,7 @@ #include "spandsp/t81_t82_arith_coding.h" #include "spandsp/t85.h" #include "spandsp/t42.h" -#if defined(SPANDSP_SUPPORT_T43) #include "spandsp/t43.h" -#endif #include "spandsp/t4_t6_decode.h" #include "spandsp/t4_t6_encode.h" #include "spandsp/t30_fcf.h" @@ -80,9 +83,7 @@ #include "spandsp/private/t81_t82_arith_coding.h" #include "spandsp/private/t85.h" #include "spandsp/private/t42.h" -#if defined(SPANDSP_SUPPORT_T43) #include "spandsp/private/t43.h" -#endif #include "spandsp/private/t4_t6_decode.h" #include "spandsp/private/t4_t6_encode.h" #include "spandsp/private/image_translate.h" @@ -245,6 +246,36 @@ SPAN_DECLARE(const char *) t30_completion_code_to_str(int result) } /*- End of function --------------------------------------------------------*/ +SPAN_DECLARE(const char *) t30_modem_to_str(int modem) +{ + switch (modem) + { + case T30_MODEM_NONE: + return "None"; + case T30_MODEM_PAUSE: + return "Pause"; + case T30_MODEM_CED: + return "CED"; + case T30_MODEM_CNG: + return "CNG"; + case T30_MODEM_V21: + return "V.21"; + case T30_MODEM_V27TER: + return "V.27ter"; + case T30_MODEM_V29: + return "V.29"; + case T30_MODEM_V17: + return "V.17"; + case T30_MODEM_V34HDX: + return "V.34HDX"; + case T30_MODEM_DONE: + return "Done"; + } + /*endswitch*/ + return "???"; +} +/*- End of function --------------------------------------------------------*/ + SPAN_DECLARE(const char *) t30_frametype(uint8_t x) { switch (x) diff --git a/libs/spandsp/src/t31.c b/libs/spandsp/src/t31.c index 6a9f08d382..76aa7e56ab 100644 --- a/libs/spandsp/src/t31.c +++ b/libs/spandsp/src/t31.c @@ -46,11 +46,17 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/bit_operations.h" #include "spandsp/bitstream.h" @@ -93,6 +99,7 @@ #include "spandsp/private/bitstream.h" #include "spandsp/private/t38_core.h" #include "spandsp/private/silence_gen.h" +#include "spandsp/private/power_meter.h" #include "spandsp/private/fsk.h" #include "spandsp/private/modem_connect_tones.h" #include "spandsp/private/v8.h" @@ -215,7 +222,7 @@ static int front_end_status(t31_state_t *s, int status) { at_modem_control(&s->at_state, AT_MODEM_CONTROL_HANGUP, NULL); t31_set_at_rx_mode(s, AT_MODE_ONHOOK_COMMAND); - s->at_state.do_hangup = FALSE; + s->at_state.do_hangup = false; } else { @@ -309,7 +316,7 @@ static int process_rx_missing(t38_core_state_t *t, void *user_data, int rx_seq_n t31_state_t *s; s = (t31_state_t *) user_data; - s->t38_fe.rx_data_missing = TRUE; + s->t38_fe.rx_data_missing = true; return 0; } /*- End of function --------------------------------------------------------*/ @@ -391,7 +398,7 @@ static int process_rx_indicator(t38_core_state_t *t, void *user_data, int indica } /*endswitch*/ fe->hdlc_rx.len = 0; - fe->rx_data_missing = FALSE; + fe->rx_data_missing = false; return 0; } /*- End of function --------------------------------------------------------*/ @@ -405,7 +412,7 @@ static void process_hdlc_data(t31_t38_front_end_state_t *fe, const uint8_t *buf, } else { - fe->rx_data_missing = TRUE; + fe->rx_data_missing = true; } /*endif*/ } @@ -460,7 +467,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, /* All real HDLC messages in the FAX world start with 0xFF. If this one is not starting with 0xFF it would appear some octets must have been missed before this one. */ if (len <= 0 || buf[0] != 0xFF) - fe->rx_data_missing = TRUE; + fe->rx_data_missing = true; /*endif*/ } /*endif*/ @@ -514,7 +521,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, fe->hdlc_rx.len = 0; } /*endif*/ - fe->rx_data_missing = FALSE; + fe->rx_data_missing = false; fe->timeout_rx_samples = fe->samples + ms_to_samples(MID_RX_TIMEOUT); break; case T38_FIELD_HDLC_FCS_BAD: @@ -533,14 +540,14 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, { span_log(&s->logging, SPAN_LOG_FLOW, "Type %s - CRC bad (%s)\n", (fe->hdlc_rx.len >= 3) ? t30_frametype(fe->hdlc_rx.buf[2]) : "???", (fe->rx_data_missing) ? "missing octets" : "clean"); if (data_type == T38_DATA_V21) - hdlc_accept_frame(s, fe->hdlc_rx.buf, fe->hdlc_rx.len, FALSE); + hdlc_accept_frame(s, fe->hdlc_rx.buf, fe->hdlc_rx.len, false); else - hdlc_accept_t38_frame(s, fe->hdlc_rx.buf, fe->hdlc_rx.len, FALSE); + hdlc_accept_t38_frame(s, fe->hdlc_rx.buf, fe->hdlc_rx.len, false); /*endif*/ fe->hdlc_rx.len = 0; } /*endif*/ - fe->rx_data_missing = FALSE; + fe->rx_data_missing = false; fe->timeout_rx_samples = fe->samples + ms_to_samples(MID_RX_TIMEOUT); break; case T38_FIELD_HDLC_FCS_OK_SIG_END: @@ -586,7 +593,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, fe->hdlc_rx.len = 0; } /*endif*/ - fe->rx_data_missing = FALSE; + fe->rx_data_missing = false; if (t->current_rx_data_type != data_type || t->current_rx_field_type != field_type) { if (data_type == T38_DATA_V21) @@ -614,14 +621,14 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, { span_log(&s->logging, SPAN_LOG_FLOW, "Type %s - CRC bad, sig end (%s)\n", (fe->hdlc_rx.len >= 3) ? t30_frametype(fe->hdlc_rx.buf[2]) : "???", (fe->rx_data_missing) ? "missing octets" : "clean"); if (data_type == T38_DATA_V21) - hdlc_accept_frame(s, fe->hdlc_rx.buf, fe->hdlc_rx.len, FALSE); + hdlc_accept_frame(s, fe->hdlc_rx.buf, fe->hdlc_rx.len, false); else - hdlc_accept_t38_frame(s, fe->hdlc_rx.buf, fe->hdlc_rx.len, FALSE); + hdlc_accept_t38_frame(s, fe->hdlc_rx.buf, fe->hdlc_rx.len, false); /*endif*/ fe->hdlc_rx.len = 0; } /*endif*/ - fe->rx_data_missing = FALSE; + fe->rx_data_missing = false; if (t->current_rx_data_type != data_type || t->current_rx_field_type != field_type) { if (data_type == T38_DATA_V21) @@ -653,7 +660,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, i.e. they send T38_FIELD_HDLC_FCS_OK, and then T38_FIELD_HDLC_SIG_END when the carrier actually drops. The other is because the HDLC signal drops unexpectedly - i.e. not just after a final frame. */ fe->hdlc_rx.len = 0; - fe->rx_data_missing = FALSE; + fe->rx_data_missing = false; fe->timeout_rx_samples = 0; if (data_type == T38_DATA_V21) hdlc_rx_status(s, SIG_STATUS_CARRIER_DOWN); @@ -669,7 +676,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, if (!s->at_state.rx_signal_present) { non_ecm_rx_status(s, SIG_STATUS_TRAINING_SUCCEEDED); - s->at_state.rx_signal_present = TRUE; + s->at_state.rx_signal_present = true; } /*endif*/ bit_reverse(buf2, buf, len); @@ -689,7 +696,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, if (!s->at_state.rx_signal_present) { non_ecm_rx_status(s, SIG_STATUS_TRAINING_SUCCEEDED); - s->at_state.rx_signal_present = TRUE; + s->at_state.rx_signal_present = true; } /*endif*/ bit_reverse(buf2, buf, len); @@ -703,7 +710,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, non_ecm_rx_status(s, SIG_STATUS_CARRIER_DOWN); } /*endif*/ - s->at_state.rx_signal_present = FALSE; + s->at_state.rx_signal_present = false; fe->timeout_rx_samples = 0; break; case T38_FIELD_CM_MESSAGE: @@ -1177,7 +1184,7 @@ static int stream_hdlc(t31_state_t *s) else { /* End of transmission */ - s->hdlc_tx.final = FALSE; + s->hdlc_tx.final = false; category = (fe->current_tx_data_type == T38_DATA_V21) ? T38_PACKET_CATEGORY_CONTROL_DATA_END : T38_PACKET_CATEGORY_IMAGE_DATA_END; if ((res = t38_core_send_data(&fe->t38, previous, T38_FIELD_HDLC_FCS_OK_SIG_END, NULL, 0, category)) < 0) return res; @@ -1301,7 +1308,7 @@ SPAN_DECLARE(int) t31_t38_send_timeout(t31_state_t *s, int samples) fe = &s->t38_fe; if (fe->current_rx_type == T30_MODEM_DONE || fe->current_tx_type == T30_MODEM_DONE) - return TRUE; + return true; /*endif*/ fe->samples += samples; @@ -1313,12 +1320,12 @@ SPAN_DECLARE(int) t31_t38_send_timeout(t31_state_t *s, int samples) } /*endif*/ if (fe->timed_step == T38_TIMED_STEP_NONE) - return FALSE; + return false; /*endif*/ /* Wait until the right time comes along, unless we are working in "no delays" mode, while talking to an IAF terminal. */ if (fe->us_per_tx_chunk && fe->samples < fe->next_tx_samples) - return FALSE; + return false; /*endif*/ /* Its time to send something */ delay = 0; @@ -1347,7 +1354,7 @@ SPAN_DECLARE(int) t31_t38_send_timeout(t31_state_t *s, int samples) } /*endswitch*/ fe->next_tx_samples += us_to_samples(delay); - return FALSE; + return false; } /*- End of function --------------------------------------------------------*/ @@ -1369,7 +1376,7 @@ static int t31_modem_control_handler(at_state_t *s, void *user_data, int op, con case AT_MODEM_CONTROL_ONHOOK: if (t->non_ecm_tx.holding) { - t->non_ecm_tx.holding = FALSE; + t->non_ecm_tx.holding = false; /* Tell the application to release further data */ at_modem_control(&t->at_state, AT_MODEM_CONTROL_CTS, (void *) 1); } @@ -1413,15 +1420,15 @@ static void non_ecm_rx_status(void *user_data, int status) case SIG_STATUS_TRAINING_IN_PROGRESS: break; case SIG_STATUS_TRAINING_FAILED: - s->at_state.rx_trained = FALSE; - s->audio.modems.rx_trained = FALSE; + s->at_state.rx_trained = false; + s->audio.modems.rx_trained = false; break; case SIG_STATUS_TRAINING_SUCCEEDED: /* The modem is now trained */ at_put_response_code(&s->at_state, AT_RESPONSE_CODE_CONNECT); - s->at_state.rx_signal_present = TRUE; - s->at_state.rx_trained = TRUE; - s->audio.modems.rx_trained = TRUE; + s->at_state.rx_signal_present = true; + s->at_state.rx_trained = true; + s->audio.modems.rx_trained = true; break; case SIG_STATUS_CARRIER_UP: break; @@ -1439,9 +1446,9 @@ static void non_ecm_rx_status(void *user_data, int status) t31_set_at_rx_mode(s, AT_MODE_OFFHOOK_COMMAND); } /*endif*/ - s->at_state.rx_signal_present = FALSE; - s->at_state.rx_trained = FALSE; - s->audio.modems.rx_trained = FALSE; + s->at_state.rx_signal_present = false; + s->at_state.rx_trained = false; + s->audio.modems.rx_trained = false; break; default: if (s->at_state.p.result_code_format) @@ -1496,7 +1503,7 @@ static void non_ecm_put(void *user_data, const uint8_t buf[], int len) if (!s->at_state.rx_signal_present) { non_ecm_rx_status(s, SIG_STATUS_TRAINING_SUCCEEDED); - s->at_state.rx_signal_present = TRUE; + s->at_state.rx_signal_present = true; } /*endif*/ /* Ignore any fractional bytes which may have accumulated */ @@ -1546,20 +1553,20 @@ static int non_ecm_get_bit(void *user_data) release flow control. */ if (s->non_ecm_tx.out_bytes > T31_TX_BUF_LOW_TIDE) { - s->non_ecm_tx.holding = FALSE; + s->non_ecm_tx.holding = false; /* Tell the application to release further data */ at_modem_control(&s->at_state, AT_MODEM_CONTROL_CTS, (void *) 1); } /*endif*/ } /*endif*/ - s->non_ecm_tx.data_started = TRUE; + s->non_ecm_tx.data_started = true; } else { if (s->non_ecm_tx.final) { - s->non_ecm_tx.final = FALSE; + s->non_ecm_tx.final = false; /* This will put the modem into its shutdown sequence. When it has finally shut down, an OK response will be sent. */ return SIG_STATUS_END_OF_DATA; @@ -1603,20 +1610,20 @@ static int non_ecm_get(void *user_data, uint8_t buf[], int len) /* See if the buffer is approaching empty. It might be time to release flow control. */ if (s->non_ecm_tx.out_bytes > T31_TX_BUF_LOW_TIDE) { - s->non_ecm_tx.holding = FALSE; + s->non_ecm_tx.holding = false; /* Tell the application to release further data */ at_modem_control(&s->at_state, AT_MODEM_CONTROL_CTS, (void *) 1); } /*endif*/ } /*endif*/ - s->non_ecm_tx.data_started = TRUE; + s->non_ecm_tx.data_started = true; } else { if (s->non_ecm_tx.final) { - s->non_ecm_tx.final = FALSE; + s->non_ecm_tx.final = false; /* This will put the modem into its shutdown sequence. When it has finally shut down, an OK response will be sent. */ return i; @@ -1660,7 +1667,7 @@ static void hdlc_tx_underflow(void *user_data) s = (t31_state_t *) user_data; if (s->hdlc_tx.final) { - s->hdlc_tx.final = FALSE; + s->hdlc_tx.final = false; /* Schedule an orderly shutdown of the modem */ hdlc_tx_frame(&s->audio.modems.hdlc_tx, NULL, 0); } @@ -1688,21 +1695,21 @@ static void hdlc_rx_status(void *user_data, int status) case SIG_STATUS_TRAINING_IN_PROGRESS: break; case SIG_STATUS_TRAINING_FAILED: - s->at_state.rx_trained = FALSE; - s->audio.modems.rx_trained = FALSE; + s->at_state.rx_trained = false; + s->audio.modems.rx_trained = false; break; case SIG_STATUS_TRAINING_SUCCEEDED: /* The modem is now trained */ - s->at_state.rx_signal_present = TRUE; - s->at_state.rx_trained = TRUE; - s->audio.modems.rx_trained = TRUE; + s->at_state.rx_signal_present = true; + s->at_state.rx_trained = true; + s->audio.modems.rx_trained = true; break; case SIG_STATUS_CARRIER_UP: if (s->modem == FAX_MODEM_CNG_TONE_TX || s->modem == FAX_MODEM_NOCNG_TONE_TX || s->modem == FAX_MODEM_V21_RX) { - s->at_state.rx_signal_present = TRUE; - s->rx_frame_received = FALSE; - s->audio.modems.rx_frame_received = FALSE; + s->at_state.rx_signal_present = true; + s->rx_frame_received = false; + s->audio.modems.rx_frame_received = false; } /*endif*/ break; @@ -1714,14 +1721,14 @@ static void hdlc_rx_status(void *user_data, int status) if (s->at_state.ok_is_pending) { at_put_response_code(&s->at_state, AT_RESPONSE_CODE_OK); - s->at_state.ok_is_pending = FALSE; + s->at_state.ok_is_pending = false; } else { at_put_response_code(&s->at_state, AT_RESPONSE_CODE_NO_CARRIER); } /*endif*/ - s->at_state.dte_is_waiting = FALSE; + s->at_state.dte_is_waiting = false; t31_set_at_rx_mode(s, AT_MODE_OFFHOOK_COMMAND); } else @@ -1732,9 +1739,9 @@ static void hdlc_rx_status(void *user_data, int status) /*endif*/ } /*endif*/ - s->at_state.rx_signal_present = FALSE; - s->at_state.rx_trained = FALSE; - s->audio.modems.rx_trained = FALSE; + s->at_state.rx_signal_present = false; + s->at_state.rx_trained = false; + s->audio.modems.rx_trained = false; break; case SIG_STATUS_FRAMING_OK: if (s->modem == FAX_MODEM_CNG_TONE_TX || s->modem == FAX_MODEM_NOCNG_TONE_TX) @@ -1742,7 +1749,7 @@ static void hdlc_rx_status(void *user_data, int status) /* Once we get any valid HDLC the CNG tone stops, and we drop to the V.21 receive modem on its own. */ s->modem = FAX_MODEM_V21_RX; - s->at_state.transmit = FALSE; + s->at_state.transmit = false; } /*endif*/ if (s->modem == FAX_MODEM_V17_RX || s->modem == FAX_MODEM_V27TER_RX || s->modem == FAX_MODEM_V29_RX) @@ -1753,12 +1760,12 @@ static void hdlc_rx_status(void *user_data, int status) V.21 receive mode. */ if (s->at_state.p.adaptive_receive) { - s->at_state.rx_signal_present = TRUE; - s->rx_frame_received = TRUE; - s->audio.modems.rx_frame_received = TRUE; + s->at_state.rx_signal_present = true; + s->rx_frame_received = true; + s->audio.modems.rx_frame_received = true; s->modem = FAX_MODEM_V21_RX; - s->at_state.transmit = FALSE; - s->at_state.dte_is_waiting = TRUE; + s->at_state.transmit = false; + s->at_state.dte_is_waiting = true; at_put_response_code(&s->at_state, AT_RESPONSE_CODE_FRH3); at_put_response_code(&s->at_state, AT_RESPONSE_CODE_CONNECT); } @@ -1766,8 +1773,8 @@ static void hdlc_rx_status(void *user_data, int status) { s->modem = FAX_MODEM_SILENCE_TX; t31_set_at_rx_mode(s, AT_MODE_OFFHOOK_COMMAND); - s->rx_frame_received = FALSE; - s->audio.modems.rx_frame_received = FALSE; + s->rx_frame_received = false; + s->audio.modems.rx_frame_received = false; at_put_response_code(&s->at_state, AT_RESPONSE_CODE_FCERROR); } /*endif*/ @@ -1780,8 +1787,8 @@ static void hdlc_rx_status(void *user_data, int status) { /* Report CONNECT as soon as possible to avoid a timeout. */ at_put_response_code(&s->at_state, AT_RESPONSE_CODE_CONNECT); - s->rx_frame_received = TRUE; - s->audio.modems.rx_frame_received = TRUE; + s->rx_frame_received = true; + s->audio.modems.rx_frame_received = true; } else { @@ -1824,8 +1831,8 @@ static void hdlc_accept_frame(void *user_data, const uint8_t *msg, int len, int { /* Report CONNECT as soon as possible to avoid a timeout. */ at_put_response_code(&s->at_state, AT_RESPONSE_CODE_CONNECT); - s->rx_frame_received = TRUE; - s->audio.modems.rx_frame_received = TRUE; + s->rx_frame_received = true; + s->audio.modems.rx_frame_received = true; } else { @@ -1859,14 +1866,14 @@ static void hdlc_accept_frame(void *user_data, const uint8_t *msg, int len, int { /* This is the last frame. We don't send OK until the carrier drops to avoid redetecting it later. */ - s->at_state.ok_is_pending = TRUE; + s->at_state.ok_is_pending = true; } else { at_put_response_code(&s->at_state, (ok) ? AT_RESPONSE_CODE_OK : AT_RESPONSE_CODE_ERROR); - s->at_state.dte_is_waiting = FALSE; - s->rx_frame_received = FALSE; - s->audio.modems.rx_frame_received = FALSE; + s->at_state.dte_is_waiting = false; + s->rx_frame_received = false; + s->audio.modems.rx_frame_received = false; } /*endif*/ } @@ -2014,13 +2021,13 @@ static void hdlc_accept_non_ecm_frame(void *user_data, const uint8_t *msg, int l static void t31_v21_rx(t31_state_t *s) { - s->at_state.ok_is_pending = FALSE; + s->at_state.ok_is_pending = false; s->hdlc_tx.len = 0; - s->hdlc_tx.final = FALSE; - s->dled = FALSE; - hdlc_rx_init(&s->audio.modems.hdlc_rx, FALSE, TRUE, HDLC_FRAMING_OK_THRESHOLD, hdlc_accept_frame, s); + s->hdlc_tx.final = false; + s->dled = false; + hdlc_rx_init(&s->audio.modems.hdlc_rx, false, true, HDLC_FRAMING_OK_THRESHOLD, hdlc_accept_frame, s); fax_modems_start_slow_modem(&s->audio.modems, FAX_MODEM_V21_RX); - s->at_state.transmit = TRUE; + s->at_state.transmit = true; } /*- End of function --------------------------------------------------------*/ @@ -2037,14 +2044,14 @@ static int restart_modem(t31_state_t *s, int new_modem) /*endif*/ queue_flush(s->rx_queue); s->modem = new_modem; - s->non_ecm_tx.final = FALSE; - s->at_state.rx_signal_present = FALSE; - s->at_state.rx_trained = FALSE; - s->audio.modems.rx_trained = FALSE; - s->rx_frame_received = FALSE; - s->audio.modems.rx_frame_received = FALSE; + s->non_ecm_tx.final = false; + s->at_state.rx_signal_present = false; + s->at_state.rx_trained = false; + s->audio.modems.rx_trained = false; + s->rx_frame_received = false; + s->audio.modems.rx_frame_received = false; fax_modems_set_rx_handler(t, (span_rx_handler_t) &span_dummy_rx, NULL, (span_rx_fillin_handler_t) &span_dummy_rx_fillin, NULL); - use_hdlc = FALSE; + use_hdlc = false; switch (s->modem) { case FAX_MODEM_CNG_TONE_TX: @@ -2067,7 +2074,7 @@ static int restart_modem(t31_state_t *s, int new_modem) fax_modems_set_next_tx_handler(t, (span_tx_handler_t) NULL, NULL); } /*endif*/ - s->at_state.transmit = TRUE; + s->at_state.transmit = true; break; case FAX_MODEM_NOCNG_TONE_TX: if (s->t38_mode) @@ -2081,7 +2088,7 @@ static int restart_modem(t31_state_t *s, int new_modem) fax_modems_set_tx_handler(t, (span_tx_handler_t) &silence_gen, &t->silence_gen); } /*endif*/ - s->at_state.transmit = FALSE; + s->at_state.transmit = false; break; case FAX_MODEM_CED_TONE_TX: if (s->t38_mode) @@ -2096,7 +2103,7 @@ static int restart_modem(t31_state_t *s, int new_modem) fax_modems_set_next_tx_handler(t, (span_tx_handler_t) NULL, NULL); } /*endif*/ - s->at_state.transmit = TRUE; + s->at_state.transmit = true; break; case FAX_MODEM_V21_RX: if (s->t38_mode) @@ -2114,13 +2121,13 @@ static int restart_modem(t31_state_t *s, int new_modem) { s->t38_fe.next_tx_indicator = T38_IND_V21_PREAMBLE; s->t38_fe.current_tx_data_type = T38_DATA_V21; - use_hdlc = TRUE; + use_hdlc = true; s->t38_fe.timed_step = (use_hdlc) ? T38_TIMED_STEP_HDLC_MODEM : T38_TIMED_STEP_NON_ECM_MODEM; set_octets_per_data_packet(s, 300); } else { - hdlc_tx_init(&t->hdlc_tx, FALSE, 2, FALSE, hdlc_tx_underflow, s); + hdlc_tx_init(&t->hdlc_tx, false, 2, false, hdlc_tx_underflow, s); /* The spec says 1s +-15% of preamble. So, the minimum is 32 octets. */ hdlc_tx_flags(&t->hdlc_tx, 32); fax_modems_start_slow_modem(t, FAX_MODEM_V21_TX); @@ -2129,9 +2136,9 @@ static int restart_modem(t31_state_t *s, int new_modem) } /*endif*/ s->hdlc_tx.len = 0; - s->hdlc_tx.final = FALSE; - s->dled = FALSE; - s->at_state.transmit = TRUE; + s->hdlc_tx.final = false; + s->dled = false; + s->at_state.transmit = true; break; case FAX_MODEM_V17_RX: case FAX_MODEM_V27TER_RX: @@ -2143,7 +2150,7 @@ static int restart_modem(t31_state_t *s, int new_modem) fax_modems_start_fast_modem(t, s->modem, s->bit_rate, s->short_train, use_hdlc); } /*endif*/ - s->at_state.transmit = FALSE; + s->at_state.transmit = false; break; case FAX_MODEM_V17_TX: if (s->t38_mode) @@ -2177,8 +2184,8 @@ static int restart_modem(t31_state_t *s, int new_modem) } /*endif*/ s->non_ecm_tx.out_bytes = 0; - s->non_ecm_tx.data_started = FALSE; - s->at_state.transmit = TRUE; + s->non_ecm_tx.data_started = false; + s->at_state.transmit = true; break; case FAX_MODEM_V27TER_TX: if (s->t38_mode) @@ -2204,8 +2211,8 @@ static int restart_modem(t31_state_t *s, int new_modem) } /*endif*/ s->non_ecm_tx.out_bytes = 0; - s->non_ecm_tx.data_started = FALSE; - s->at_state.transmit = TRUE; + s->non_ecm_tx.data_started = false; + s->at_state.transmit = true; break; case FAX_MODEM_V29_TX: if (s->t38_mode) @@ -2231,8 +2238,8 @@ static int restart_modem(t31_state_t *s, int new_modem) } /*endif*/ s->non_ecm_tx.out_bytes = 0; - s->non_ecm_tx.data_started = FALSE; - s->at_state.transmit = TRUE; + s->non_ecm_tx.data_started = false; + s->at_state.transmit = true; break; case FAX_MODEM_SILENCE_TX: if (s->t38_mode) @@ -2251,7 +2258,7 @@ static int restart_modem(t31_state_t *s, int new_modem) fax_modems_set_next_tx_handler(t, (span_tx_handler_t) NULL, NULL); } /*endif*/ - s->at_state.transmit = FALSE; + s->at_state.transmit = false; break; case FAX_MODEM_SILENCE_RX: if (!s->t38_mode) @@ -2262,7 +2269,7 @@ static int restart_modem(t31_state_t *s, int new_modem) fax_modems_set_next_tx_handler(t, (span_tx_handler_t) NULL, NULL); } /*endif*/ - s->at_state.transmit = FALSE; + s->at_state.transmit = false; break; case FAX_MODEM_FLUSH: /* Send 200ms of silence to "push" the last audio out */ @@ -2278,7 +2285,7 @@ static int restart_modem(t31_state_t *s, int new_modem) silence_gen_alter(&t->silence_gen, ms_to_samples(200)); fax_modems_set_tx_handler(t, (span_tx_handler_t) &silence_gen, &t->silence_gen); fax_modems_set_next_tx_handler(t, (span_tx_handler_t) NULL, NULL); - s->at_state.transmit = TRUE; + s->at_state.transmit = true; } /*endif*/ break; @@ -2300,7 +2307,7 @@ static __inline__ void dle_unstuff_hdlc(t31_state_t *s, const char *stuffed, int { if (s->dled) { - s->dled = FALSE; + s->dled = false; if (stuffed[i] == ETX) { s->hdlc_tx.final = (s->hdlc_tx.buf[1] & 0x10); @@ -2329,7 +2336,7 @@ static __inline__ void dle_unstuff_hdlc(t31_state_t *s, const char *stuffed, int else { if (stuffed[i] == DLE) - s->dled = TRUE; + s->dled = true; else s->hdlc_tx.buf[s->hdlc_tx.len++] = stuffed[i]; /*endif*/ @@ -2348,10 +2355,10 @@ static __inline__ void dle_unstuff_fake_hdlc(t31_state_t *s, const char *stuffed { if (s->dled) { - s->dled = FALSE; + s->dled = false; if (stuffed[i] == ETX) { - s->non_ecm_tx.final = TRUE; + s->non_ecm_tx.final = true; t31_set_at_rx_mode(s, AT_MODE_OFFHOOK_COMMAND); return; } @@ -2369,7 +2376,7 @@ static __inline__ void dle_unstuff_fake_hdlc(t31_state_t *s, const char *stuffed else { if (stuffed[i] == DLE) - s->dled = TRUE; + s->dled = true; else hdlc_rx_put_byte(&s->t38_fe.hdlc_rx_non_ecm, bit_reverse8(stuffed[i])); /*endif*/ @@ -2388,10 +2395,10 @@ static __inline__ void dle_unstuff(t31_state_t *s, const char *stuffed, int len) { if (s->dled) { - s->dled = FALSE; + s->dled = false; if (stuffed[i] == ETX) { - s->non_ecm_tx.final = TRUE; + s->non_ecm_tx.final = true; t31_set_at_rx_mode(s, AT_MODE_OFFHOOK_COMMAND); return; } @@ -2410,7 +2417,7 @@ static __inline__ void dle_unstuff(t31_state_t *s, const char *stuffed, int len) else { if (stuffed[i] == DLE) - s->dled = TRUE; + s->dled = true; else s->non_ecm_tx.buf[s->non_ecm_tx.in_bytes++] = stuffed[i]; /*endif*/ @@ -2430,7 +2437,7 @@ static __inline__ void dle_unstuff(t31_state_t *s, const char *stuffed, int len) /* See if the buffer is approaching full. We might need to apply flow control. */ if (s->non_ecm_tx.in_bytes > T31_TX_BUF_HIGH_TIDE) { - s->non_ecm_tx.holding = TRUE; + s->non_ecm_tx.holding = true; /* Tell the application to hold further data */ at_modem_control(&s->at_state, AT_MODEM_CONTROL_CTS, (void *) 0); } @@ -2452,7 +2459,7 @@ static int process_class1_cmd(at_state_t *t, void *user_data, int direction, int s = (t31_state_t *) user_data; new_transmit = direction; - immediate_response = TRUE; + immediate_response = true; switch (operation) { case 'S': @@ -2466,7 +2473,7 @@ static int process_class1_cmd(at_state_t *t, void *user_data, int direction, int else silence_gen_alter(&s->audio.modems.silence_gen, ms_to_samples(val*10)); /*endif*/ - s->at_state.transmit = TRUE; + s->at_state.transmit = true; } else { @@ -2486,7 +2493,7 @@ static int process_class1_cmd(at_state_t *t, void *user_data, int direction, int /*endif*/ } /*endif*/ - immediate_response = FALSE; + immediate_response = false; span_log(&s->logging, SPAN_LOG_FLOW, "Silence %dms\n", val*10); break; case 'H': @@ -2494,7 +2501,7 @@ static int process_class1_cmd(at_state_t *t, void *user_data, int direction, int { case 3: new_modem = (new_transmit) ? FAX_MODEM_V21_TX : FAX_MODEM_V21_RX; - s->short_train = FALSE; + s->short_train = false; s->bit_rate = 300; break; default: @@ -2505,7 +2512,7 @@ static int process_class1_cmd(at_state_t *t, void *user_data, int direction, int if (new_modem != s->modem) { restart_modem(s, new_modem); - immediate_response = FALSE; + immediate_response = false; } /*endif*/ s->at_state.transmit = new_transmit; @@ -2520,8 +2527,8 @@ static int process_class1_cmd(at_state_t *t, void *user_data, int direction, int { /* Send straight away, if there is something queued. */ t31_set_at_rx_mode(s, AT_MODE_DELIVERY); - s->rx_frame_received = FALSE; - s->audio.modems.rx_frame_received = FALSE; + s->rx_frame_received = false; + s->audio.modems.rx_frame_received = false; do { if (!queue_empty(s->rx_queue)) @@ -2550,7 +2557,7 @@ static int process_class1_cmd(at_state_t *t, void *user_data, int direction, int } else { - s->at_state.dte_is_waiting = TRUE; + s->at_state.dte_is_waiting = true; break; } /*endif*/ @@ -2558,7 +2565,7 @@ static int process_class1_cmd(at_state_t *t, void *user_data, int direction, int while (msg[0] == AT_RESPONSE_CODE_CONNECT); } /*endif*/ - immediate_response = FALSE; + immediate_response = false; break; default: switch (val) @@ -2567,84 +2574,84 @@ static int process_class1_cmd(at_state_t *t, void *user_data, int direction, int s->t38_fe.next_tx_indicator = T38_IND_V27TER_2400_TRAINING; s->t38_fe.current_tx_data_type = T38_DATA_V27TER_2400; new_modem = (new_transmit) ? FAX_MODEM_V27TER_TX : FAX_MODEM_V27TER_RX; - s->short_train = FALSE; + s->short_train = false; s->bit_rate = 2400; break; case 48: s->t38_fe.next_tx_indicator = T38_IND_V27TER_4800_TRAINING; s->t38_fe.current_tx_data_type = T38_DATA_V27TER_4800; new_modem = (new_transmit) ? FAX_MODEM_V27TER_TX : FAX_MODEM_V27TER_RX; - s->short_train = FALSE; + s->short_train = false; s->bit_rate = 4800; break; case 72: s->t38_fe.next_tx_indicator = T38_IND_V29_7200_TRAINING; s->t38_fe.current_tx_data_type = T38_DATA_V29_7200; new_modem = (new_transmit) ? FAX_MODEM_V29_TX : FAX_MODEM_V29_RX; - s->short_train = FALSE; + s->short_train = false; s->bit_rate = 7200; break; case 96: s->t38_fe.next_tx_indicator = T38_IND_V29_9600_TRAINING; s->t38_fe.current_tx_data_type = T38_DATA_V29_9600; new_modem = (new_transmit) ? FAX_MODEM_V29_TX : FAX_MODEM_V29_RX; - s->short_train = FALSE; + s->short_train = false; s->bit_rate = 9600; break; case 73: s->t38_fe.next_tx_indicator = T38_IND_V17_7200_LONG_TRAINING; s->t38_fe.current_tx_data_type = T38_DATA_V17_7200; new_modem = (new_transmit) ? FAX_MODEM_V17_TX : FAX_MODEM_V17_RX; - s->short_train = FALSE; + s->short_train = false; s->bit_rate = 7200; break; case 74: s->t38_fe.next_tx_indicator = T38_IND_V17_7200_SHORT_TRAINING; s->t38_fe.current_tx_data_type = T38_DATA_V17_7200; new_modem = (new_transmit) ? FAX_MODEM_V17_TX : FAX_MODEM_V17_RX; - s->short_train = TRUE; + s->short_train = true; s->bit_rate = 7200; break; case 97: s->t38_fe.next_tx_indicator = T38_IND_V17_9600_LONG_TRAINING; s->t38_fe.current_tx_data_type = T38_DATA_V17_9600; new_modem = (new_transmit) ? FAX_MODEM_V17_TX : FAX_MODEM_V17_RX; - s->short_train = FALSE; + s->short_train = false; s->bit_rate = 9600; break; case 98: s->t38_fe.next_tx_indicator = T38_IND_V17_9600_SHORT_TRAINING; s->t38_fe.current_tx_data_type = T38_DATA_V17_9600; new_modem = (new_transmit) ? FAX_MODEM_V17_TX : FAX_MODEM_V17_RX; - s->short_train = TRUE; + s->short_train = true; s->bit_rate = 9600; break; case 121: s->t38_fe.next_tx_indicator = T38_IND_V17_12000_LONG_TRAINING; s->t38_fe.current_tx_data_type = T38_DATA_V17_12000; new_modem = (new_transmit) ? FAX_MODEM_V17_TX : FAX_MODEM_V17_RX; - s->short_train = FALSE; + s->short_train = false; s->bit_rate = 12000; break; case 122: s->t38_fe.next_tx_indicator = T38_IND_V17_12000_SHORT_TRAINING; s->t38_fe.current_tx_data_type = T38_DATA_V17_12000; new_modem = (new_transmit) ? FAX_MODEM_V17_TX : FAX_MODEM_V17_RX; - s->short_train = TRUE; + s->short_train = true; s->bit_rate = 12000; break; case 145: s->t38_fe.next_tx_indicator = T38_IND_V17_14400_LONG_TRAINING; s->t38_fe.current_tx_data_type = T38_DATA_V17_14400; new_modem = (new_transmit) ? FAX_MODEM_V17_TX : FAX_MODEM_V17_RX; - s->short_train = FALSE; + s->short_train = false; s->bit_rate = 14400; break; case 146: s->t38_fe.next_tx_indicator = T38_IND_V17_14400_SHORT_TRAINING; s->t38_fe.current_tx_data_type = T38_DATA_V17_14400; new_modem = (new_transmit) ? FAX_MODEM_V17_TX : FAX_MODEM_V17_RX; - s->short_train = TRUE; + s->short_train = true; s->bit_rate = 14400; break; default: @@ -2663,7 +2670,7 @@ static int process_class1_cmd(at_state_t *t, void *user_data, int direction, int } /*endif*/ restart_modem(s, new_modem); - immediate_response = FALSE; + immediate_response = false; break; } /*endswitch*/ @@ -2707,7 +2714,7 @@ SPAN_DECLARE(int) t31_at_rx(t31_state_t *s, const char *t, int len) } /*endif*/ s->at_state.rx_data_bytes = 0; - s->at_state.transmit = FALSE; + s->at_state.transmit = false; s->modem = FAX_MODEM_SILENCE_TX; fax_modems_set_rx_handler(&s->audio.modems, (span_rx_handler_t) &span_dummy_rx, NULL, (span_rx_fillin_handler_t) &span_dummy_rx_fillin, NULL); t31_set_at_rx_mode(s, AT_MODE_OFFHOOK_COMMAND); @@ -2823,7 +2830,8 @@ SPAN_DECLARE_NONSTD(int) t31_rx(t31_state_t *s, int16_t amp[], int len) } /*endif*/ - s->audio.modems.rx_handler(s->audio.modems.rx_user_data, amp, len); + if (s->audio.modems.rx_handler) + s->audio.modems.rx_handler(s->audio.modems.rx_user_data, amp, len); return 0; } /*- End of function --------------------------------------------------------*/ @@ -2854,23 +2862,6 @@ SPAN_DECLARE_NONSTD(int) t31_rx_fillin(t31_state_t *s, int len) } /*- End of function --------------------------------------------------------*/ -static int set_next_tx_type(t31_state_t *s) -{ - if (s->audio.next_tx_handler) - { - fax_modems_set_tx_handler(&s->audio.modems, s->audio.next_tx_handler, s->audio.next_tx_user_data); - fax_modems_set_next_tx_handler(&s->audio.modems, (span_tx_handler_t) NULL, NULL); - return 0; - } - /*endif*/ - /* There is nothing else to change to, so use zero length silence */ - silence_gen_alter(&s->audio.modems.silence_gen, 0); - fax_modems_set_tx_handler(&s->audio.modems, (span_tx_handler_t) &silence_gen, &s->audio.modems.silence_gen); - fax_modems_set_next_tx_handler(&s->audio.modems, (span_tx_handler_t) NULL, NULL); - return -1; -} -/*- End of function --------------------------------------------------------*/ - SPAN_DECLARE_NONSTD(int) t31_tx(t31_state_t *s, int16_t amp[], int max_len) { int len; @@ -2881,8 +2872,8 @@ SPAN_DECLARE_NONSTD(int) t31_tx(t31_state_t *s, int16_t amp[], int max_len) if ((len = s->audio.modems.tx_handler(s->audio.modems.tx_user_data, amp, max_len)) < max_len) { /* Allow for one change of tx handler within a block */ - set_next_tx_type(s); - if ((len += s->audio.modems.tx_handler(s->audio.modems.tx_user_data, amp + len, max_len - len)) < max_len) + fax_modems_set_next_tx_type(&s->audio.modems); + if ((len += s->audio.modems.tx_handler(s->audio.modems.tx_user_data, &[len], max_len - len)) < max_len) front_end_status(s, T30_FRONT_END_SEND_STEP_COMPLETE); /*endif*/ } @@ -2892,7 +2883,7 @@ SPAN_DECLARE_NONSTD(int) t31_tx(t31_state_t *s, int16_t amp[], int max_len) if (s->audio.modems.transmit_on_idle) { /* Pad to the requested length with silence */ - memset(amp + len, 0, (max_len - len)*sizeof(int16_t)); + memset(&[len], 0, (max_len - len)*sizeof(int16_t)); len = max_len; } /*endif*/ @@ -2900,19 +2891,19 @@ SPAN_DECLARE_NONSTD(int) t31_tx(t31_state_t *s, int16_t amp[], int max_len) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) t31_set_transmit_on_idle(t31_state_t *s, int transmit_on_idle) +SPAN_DECLARE(void) t31_set_transmit_on_idle(t31_state_t *s, bool transmit_on_idle) { s->audio.modems.transmit_on_idle = transmit_on_idle; } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) t31_set_tep_mode(t31_state_t *s, int use_tep) +SPAN_DECLARE(void) t31_set_tep_mode(t31_state_t *s, bool use_tep) { s->audio.modems.use_tep = use_tep; } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) t31_set_t38_config(t31_state_t *s, int without_pacing) +SPAN_DECLARE(void) t31_set_t38_config(t31_state_t *s, bool without_pacing) { if (without_pacing) { @@ -2940,7 +2931,7 @@ SPAN_DECLARE(void) t31_set_t38_config(t31_state_t *s, int without_pacing) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) t31_set_mode(t31_state_t *s, int t38_mode) +SPAN_DECLARE(void) t31_set_mode(t31_state_t *s, bool t38_mode) { s->t38_mode = t38_mode; span_log(&s->logging, SPAN_LOG_FLOW, "Mode set to %d\n", s->t38_mode); @@ -2992,8 +2983,8 @@ static int t31_t38_fe_init(t31_state_t *t, t->hdlc_tx.ptr = 0; - hdlc_tx_init(&s->hdlc_tx_non_ecm, FALSE, 1, FALSE, hdlc_tx_underflow2, s); - hdlc_rx_init(&s->hdlc_rx_non_ecm, FALSE, TRUE, 2, hdlc_accept_non_ecm_frame, t); + hdlc_tx_init(&s->hdlc_tx_non_ecm, false, 1, false, hdlc_tx_underflow2, s); + hdlc_rx_init(&s->hdlc_rx_non_ecm, false, true, 2, hdlc_accept_non_ecm_frame, t); return 0; } /*- End of function --------------------------------------------------------*/ @@ -3013,13 +3004,13 @@ SPAN_DECLARE(t31_state_t *) t31_init(t31_state_t *s, return NULL; /*endif*/ - alloced = FALSE; + alloced = false; if (s == NULL) { - if ((s = (t31_state_t *) malloc(sizeof (*s))) == NULL) + if ((s = (t31_state_t *) span_alloc(sizeof (*s))) == NULL) return NULL; /*endif*/ - alloced = TRUE; + alloced = true; } /*endif*/ memset(s, 0, sizeof(*s)); @@ -3029,7 +3020,7 @@ SPAN_DECLARE(t31_state_t *) t31_init(t31_state_t *s, s->modem_control_handler = modem_control_handler; s->modem_control_user_data = modem_control_user_data; fax_modems_init(&s->audio.modems, - FALSE, + false, hdlc_accept_frame, hdlc_tx_underflow, non_ecm_put_bit, @@ -3051,27 +3042,27 @@ SPAN_DECLARE(t31_state_t *) t31_init(t31_state_t *s, v8_parms.pstn_access = 0; v8_parms.nsf = -1; v8_parms.t66 = -1; - v8_init(&s->audio.v8, FALSE, &v8_parms, v8_handler, s); + v8_init(&s->audio.v8, false, &v8_parms, v8_handler, s); power_meter_init(&s->audio.rx_power, 4); s->audio.last_sample = 0; s->audio.silence_threshold_power = power_meter_level_dbm0(-36); - s->at_state.rx_signal_present = FALSE; - s->at_state.rx_trained = FALSE; - s->audio.modems.rx_trained = FALSE; + s->at_state.rx_signal_present = false; + s->at_state.rx_trained = false; + s->audio.modems.rx_trained = false; - s->at_state.do_hangup = FALSE; + s->at_state.do_hangup = false; s->at_state.line_ptr = 0; s->audio.silence_heard = 0; s->silence_awaited = 0; s->call_samples = 0; s->modem = FAX_MODEM_NONE; - s->at_state.transmit = TRUE; + s->at_state.transmit = true; if ((s->rx_queue = queue_init(NULL, 4096, QUEUE_WRITE_ATOMIC | QUEUE_READ_ATOMIC)) == NULL) { if (alloced) - free(s); + span_free(s); /*endif*/ return NULL; } @@ -3082,10 +3073,10 @@ SPAN_DECLARE(t31_state_t *) t31_init(t31_state_t *s, if (tx_t38_packet_handler) { t31_t38_fe_init(s, tx_t38_packet_handler, tx_t38_packet_user_data); - t31_set_t38_config(s, FALSE); + t31_set_t38_config(s, false); } /*endif*/ - s->t38_mode = FALSE; + s->t38_mode = false; return s; } /*- End of function --------------------------------------------------------*/ @@ -3100,7 +3091,7 @@ SPAN_DECLARE(int) t31_release(t31_state_t *s) SPAN_DECLARE(int) t31_free(t31_state_t *s) { t31_release(s); - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/t35.c b/libs/spandsp/src/t35.c index 3e210854ab..ce04a6ce23 100644 --- a/libs/spandsp/src/t35.c +++ b/libs/spandsp/src/t35.c @@ -61,6 +61,11 @@ #include #include #include +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "spandsp/telephony.h" #include "spandsp/bit_operations.h" @@ -86,7 +91,7 @@ typedef struct int vendor_id_len; /*! The vendor's name */ const char *vendor_name; - /*! TRUE if the station ID for this vendor is reversed */ + /*! True if the station ID for this vendor is reversed */ int inverse_station_id_order; /*! A pointer to a list of known models from this vendor */ const model_data_t *known_models; @@ -273,260 +278,260 @@ static const model_data_t Muratec48[] = static const nsf_data_t vendor_00[] = { /* Japan */ - {"\x00\x00", 2, "Unknown - indeterminate", TRUE, NULL}, - {"\x00\x01", 2, "Anritsu", FALSE, NULL}, - {"\x00\x02", 2, "Nippon Telephone", FALSE, NULL}, - {"\x00\x05", 2, "Mitsuba Electric", FALSE, NULL}, - {"\x00\x06", 2, "Master Net", FALSE, NULL}, - {"\x00\x09", 2, "Xerox/Toshiba", TRUE, Xerox}, - {"\x00\x0A", 2, "Kokusai", FALSE, NULL}, - {"\x00\x0D", 2, "Logic System International", FALSE, NULL}, - {"\x00\x0E", 2, "Panasonic", FALSE, Panasonic0E}, - {"\x00\x11", 2, "Canon", FALSE, Canon}, - {"\x00\x15", 2, "Toyotsushen Machinery", FALSE, NULL}, - {"\x00\x16", 2, "System House Mind", FALSE, NULL}, - {"\x00\x19", 2, "Xerox", TRUE, NULL}, - {"\x00\x1D", 2, "Hitachi Software", FALSE, NULL}, - {"\x00\x21", 2, "OKI Electric/Lanier", TRUE, NULL}, - {"\x00\x25", 2, "Ricoh", TRUE, Ricoh}, - {"\x00\x26", 2, "Konica", FALSE, NULL}, - {"\x00\x29", 2, "Japan Wireless", FALSE, NULL}, - {"\x00\x2D", 2, "Sony", FALSE, NULL}, - {"\x00\x31", 2, "Sharp/Olivetti", FALSE, Sharp}, - {"\x00\x35", 2, "Kogyu", FALSE, NULL}, - {"\x00\x36", 2, "Japan Telecom", FALSE, NULL}, - {"\x00\x3D", 2, "IBM Japan", FALSE, NULL}, - {"\x00\x39", 2, "Panasonic", FALSE, NULL}, - {"\x00\x41", 2, "Swasaki Communication", FALSE, NULL}, - {"\x00\x45", 2, "Muratec", FALSE, Muratec45}, - {"\x00\x46", 2, "Pheonix", FALSE, NULL}, - {"\x00\x48", 2, "Muratec", FALSE, Muratec48}, /* Not registered */ - {"\x00\x49", 2, "Japan Electric", FALSE, NULL}, - {"\x00\x4D", 2, "Okura Electric", FALSE, NULL}, - {"\x00\x51", 2, "Sanyo", FALSE, Sanyo}, - {"\x00\x55", 2, "Unknown - Japan 55", FALSE, NULL}, - {"\x00\x56", 2, "Brother", FALSE, Brother}, - {"\x00\x59", 2, "Fujitsu", FALSE, NULL}, - {"\x00\x5D", 2, "Kuoni", FALSE, NULL}, - {"\x00\x61", 2, "Casio", FALSE, NULL}, - {"\x00\x65", 2, "Tateishi Electric", FALSE, NULL}, - {"\x00\x66", 2, "Utax/Mita", TRUE, NULL}, - {"\x00\x69", 2, "Hitachi Production", FALSE, NULL}, - {"\x00\x6D", 2, "Hitachi Telecom", FALSE, NULL}, - {"\x00\x71", 2, "Tamura Electric Works", FALSE, NULL}, - {"\x00\x75", 2, "Tokyo Electric Corp.", FALSE, NULL}, - {"\x00\x76", 2, "Advance", FALSE, NULL}, - {"\x00\x79", 2, "Panasonic", FALSE, Panasonic79}, - {"\x00\x7D", 2, "Seiko", FALSE, NULL}, - {"\x08\x00", 2, "Daiko", FALSE, NULL}, - {"\x10\x00", 2, "Funai Electric", FALSE, NULL}, - {"\x20\x00", 2, "Eagle System", FALSE, NULL}, - {"\x30\x00", 2, "Nippon Business Systems", FALSE, NULL}, - {"\x40\x00", 2, "Comtron", FALSE, NULL}, - {"\x48\x00", 2, "Cosmo Consulting", FALSE, NULL}, - {"\x50\x00", 2, "Orion Electric", FALSE, NULL}, - {"\x60\x00", 2, "Nagano Nippon", FALSE, NULL}, - {"\x70\x00", 2, "Kyocera", FALSE, NULL}, - {"\x80\x00", 2, "Kanda Networks", FALSE, NULL}, - {"\x88\x00", 2, "Soft Front", FALSE, NULL}, - {"\x90\x00", 2, "Arctic", FALSE, NULL}, - {"\xA0\x00", 2, "Nakushima", FALSE, NULL}, - {"\xB0\x00", 2, "Minolta", FALSE, NULL}, - {"\xC0\x00", 2, "Tohoku Pioneer", FALSE, NULL}, - {"\xD0\x00", 2, "USC", FALSE, NULL}, - {"\xE0\x00", 2, "Hiboshi", FALSE, NULL}, - {"\xF0\x00", 2, "Sumitomo Electric", FALSE, NULL}, - {NULL, 0, NULL, FALSE, NULL} + {"\x00\x00", 2, "Unknown - indeterminate", true, NULL}, + {"\x00\x01", 2, "Anritsu", false, NULL}, + {"\x00\x02", 2, "Nippon Telephone", false, NULL}, + {"\x00\x05", 2, "Mitsuba Electric", false, NULL}, + {"\x00\x06", 2, "Master Net", false, NULL}, + {"\x00\x09", 2, "Xerox/Toshiba", true, Xerox}, + {"\x00\x0A", 2, "Kokusai", false, NULL}, + {"\x00\x0D", 2, "Logic System International", false, NULL}, + {"\x00\x0E", 2, "Panasonic", false, Panasonic0E}, + {"\x00\x11", 2, "Canon", false, Canon}, + {"\x00\x15", 2, "Toyotsushen Machinery", false, NULL}, + {"\x00\x16", 2, "System House Mind", false, NULL}, + {"\x00\x19", 2, "Xerox", true, NULL}, + {"\x00\x1D", 2, "Hitachi Software", false, NULL}, + {"\x00\x21", 2, "OKI Electric/Lanier", true, NULL}, + {"\x00\x25", 2, "Ricoh", true, Ricoh}, + {"\x00\x26", 2, "Konica", false, NULL}, + {"\x00\x29", 2, "Japan Wireless", false, NULL}, + {"\x00\x2D", 2, "Sony", false, NULL}, + {"\x00\x31", 2, "Sharp/Olivetti", false, Sharp}, + {"\x00\x35", 2, "Kogyu", false, NULL}, + {"\x00\x36", 2, "Japan Telecom", false, NULL}, + {"\x00\x3D", 2, "IBM Japan", false, NULL}, + {"\x00\x39", 2, "Panasonic", false, NULL}, + {"\x00\x41", 2, "Swasaki Communication", false, NULL}, + {"\x00\x45", 2, "Muratec", false, Muratec45}, + {"\x00\x46", 2, "Pheonix", false, NULL}, + {"\x00\x48", 2, "Muratec", false, Muratec48}, /* Not registered */ + {"\x00\x49", 2, "Japan Electric", false, NULL}, + {"\x00\x4D", 2, "Okura Electric", false, NULL}, + {"\x00\x51", 2, "Sanyo", false, Sanyo}, + {"\x00\x55", 2, "Unknown - Japan 55", false, NULL}, + {"\x00\x56", 2, "Brother", false, Brother}, + {"\x00\x59", 2, "Fujitsu", false, NULL}, + {"\x00\x5D", 2, "Kuoni", false, NULL}, + {"\x00\x61", 2, "Casio", false, NULL}, + {"\x00\x65", 2, "Tateishi Electric", false, NULL}, + {"\x00\x66", 2, "Utax/Mita", true, NULL}, + {"\x00\x69", 2, "Hitachi Production", false, NULL}, + {"\x00\x6D", 2, "Hitachi Telecom", false, NULL}, + {"\x00\x71", 2, "Tamura Electric Works", false, NULL}, + {"\x00\x75", 2, "Tokyo Electric Corp.", false, NULL}, + {"\x00\x76", 2, "Advance", false, NULL}, + {"\x00\x79", 2, "Panasonic", false, Panasonic79}, + {"\x00\x7D", 2, "Seiko", false, NULL}, + {"\x08\x00", 2, "Daiko", false, NULL}, + {"\x10\x00", 2, "Funai Electric", false, NULL}, + {"\x20\x00", 2, "Eagle System", false, NULL}, + {"\x30\x00", 2, "Nippon Business Systems", false, NULL}, + {"\x40\x00", 2, "Comtron", false, NULL}, + {"\x48\x00", 2, "Cosmo Consulting", false, NULL}, + {"\x50\x00", 2, "Orion Electric", false, NULL}, + {"\x60\x00", 2, "Nagano Nippon", false, NULL}, + {"\x70\x00", 2, "Kyocera", false, NULL}, + {"\x80\x00", 2, "Kanda Networks", false, NULL}, + {"\x88\x00", 2, "Soft Front", false, NULL}, + {"\x90\x00", 2, "Arctic", false, NULL}, + {"\xA0\x00", 2, "Nakushima", false, NULL}, + {"\xB0\x00", 2, "Minolta", false, NULL}, + {"\xC0\x00", 2, "Tohoku Pioneer", false, NULL}, + {"\xD0\x00", 2, "USC", false, NULL}, + {"\xE0\x00", 2, "Hiboshi", false, NULL}, + {"\xF0\x00", 2, "Sumitomo Electric", false, NULL}, + {NULL, 0, NULL, false, NULL} }; static const nsf_data_t vendor_20[] = { /* Germany */ - {"\x09", 1, "ITK Institut für Telekommunikation GmbH & Co KG", FALSE, NULL}, - {"\x11", 1, "Dr. Neuhaus Mikroelektronik", FALSE, NULL}, - {"\x21", 1, "ITO Communication", FALSE, NULL}, - {"\x31", 1, "mbp Kommunikationssysteme GmbH", FALSE, NULL}, - {"\x41", 1, "Siemens", FALSE, NULL}, - {"\x42", 1, "Deutsche Telekom AG", FALSE, NULL}, - {"\x51", 1, "mps Software", FALSE, NULL}, - {"\x61", 1, "Hauni Elektronik", FALSE, NULL}, - {"\x71", 1, "Digitronic computersysteme gmbh", FALSE, NULL}, - {"\x81\x00", 2, "Innovaphone GmbH", FALSE, NULL}, - {"\x81\x40", 2, "TEDAS Gesellschaft für Telekommunikations-, Daten- und Audiosysteme mbH", FALSE, NULL}, - {"\x81\x80", 2, "AVM Audiovisuelles Marketing und Computersysteme GmbH", FALSE, NULL}, - {"\x81\xC0", 2, "EICON Technology Research GmbH", FALSE, NULL}, - {"\xB1", 1, "Schneider Rundfunkwerke AG", FALSE, NULL}, - {"\xC2", 1, "Deutsche Telekom AG", FALSE, NULL}, - {"\xD1", 1, "Ferrari electronik GmbH", FALSE, NULL}, - {"\xF1", 1, "DeTeWe - Deutsche Telephonwerke AG & Co", FALSE, NULL}, - {"\xFF", 1, "Germany Regional Code", FALSE, NULL}, - {NULL, 0, NULL, FALSE, NULL} + {"\x09", 1, "ITK Institut für Telekommunikation GmbH & Co KG", false, NULL}, + {"\x11", 1, "Dr. Neuhaus Mikroelektronik", false, NULL}, + {"\x21", 1, "ITO Communication", false, NULL}, + {"\x31", 1, "mbp Kommunikationssysteme GmbH", false, NULL}, + {"\x41", 1, "Siemens", false, NULL}, + {"\x42", 1, "Deutsche Telekom AG", false, NULL}, + {"\x51", 1, "mps Software", false, NULL}, + {"\x61", 1, "Hauni Elektronik", false, NULL}, + {"\x71", 1, "Digitronic computersysteme gmbh", false, NULL}, + {"\x81\x00", 2, "Innovaphone GmbH", false, NULL}, + {"\x81\x40", 2, "TEDAS Gesellschaft für Telekommunikations-, Daten- und Audiosysteme mbH", false, NULL}, + {"\x81\x80", 2, "AVM Audiovisuelles Marketing und Computersysteme GmbH", false, NULL}, + {"\x81\xC0", 2, "EICON Technology Research GmbH", false, NULL}, + {"\xB1", 1, "Schneider Rundfunkwerke AG", false, NULL}, + {"\xC2", 1, "Deutsche Telekom AG", false, NULL}, + {"\xD1", 1, "Ferrari electronik GmbH", false, NULL}, + {"\xF1", 1, "DeTeWe - Deutsche Telephonwerke AG & Co", false, NULL}, + {"\xFF", 1, "Germany Regional Code", false, NULL}, + {NULL, 0, NULL, false, NULL} }; static const nsf_data_t vendor_64[] = { /* China (not Lebanon) */ - {"\x00\x00", 2, "Unknown - China 00 00", FALSE, NULL}, - {"\x01\x00", 2, "Unknown - China 01 00", FALSE, NULL}, - {"\x01\x01", 2, "Unknown - China 01 01", FALSE, NULL}, - {"\x01\x02", 2, "Unknown - China 01 02", FALSE, NULL}, - {NULL, 0, NULL, FALSE, NULL} + {"\x00\x00", 2, "Unknown - China 00 00", false, NULL}, + {"\x01\x00", 2, "Unknown - China 01 00", false, NULL}, + {"\x01\x01", 2, "Unknown - China 01 01", false, NULL}, + {"\x01\x02", 2, "Unknown - China 01 02", false, NULL}, + {NULL, 0, NULL, false, NULL} }; static const nsf_data_t vendor_61[] = { /* Korea */ - {"\x00\x7A", 2, "Xerox", FALSE, NULL}, - {NULL, 0, NULL, FALSE, NULL} + {"\x00\x7A", 2, "Xerox", false, NULL}, + {NULL, 0, NULL, false, NULL} }; static const nsf_data_t vendor_86[] = { /* Korea (not Papua New Guinea) */ - {"\x00\x02", 2, "Unknown - Korea 02", FALSE, NULL}, - {"\x00\x06", 2, "Unknown - Korea 06", FALSE, NULL}, - {"\x00\x08", 2, "Unknown - Korea 08", FALSE, NULL}, - {"\x00\x0A", 2, "Unknown - Korea 0A", FALSE, NULL}, - {"\x00\x0E", 2, "Unknown - Korea 0E", FALSE, NULL}, - {"\x00\x10", 2, "Samsung", FALSE, NULL}, - {"\x00\x11", 2, "Unknown - Korea 11", FALSE, NULL}, - {"\x00\x16", 2, "Samsung", FALSE, Samsung16}, - {"\x00\x1A", 2, "Unknown - Korea 1A", FALSE, NULL}, - {"\x00\x40", 2, "Unknown - Korea 40", FALSE, NULL}, - {"\x00\x48", 2, "Unknown - Korea 48", FALSE, NULL}, - {"\x00\x52", 2, "Unknown - Korea 52", FALSE, NULL}, - {"\x00\x5A", 2, "Samsung", FALSE, Samsung5A}, - {"\x00\x5E", 2, "Unknown - Korea 5E", FALSE, NULL}, - {"\x00\x66", 2, "Unknown - Korea 66", FALSE, NULL}, - {"\x00\x6E", 2, "Unknown - Korea 6E", FALSE, NULL}, - {"\x00\x82", 2, "Unknown - Korea 82", FALSE, NULL}, - {"\x00\x88", 2, "Unknown - Korea 88", FALSE, NULL}, - {"\x00\x8A", 2, "Unknown - Korea 8A", FALSE, NULL}, - {"\x00\x8C", 2, "Samsung", FALSE, Samsung8C}, - {"\x00\x92", 2, "Unknown - Korea 92", FALSE, NULL}, - {"\x00\x98", 2, "Samsung", FALSE, NULL}, - {"\x00\xA2", 2, "Samsung", FALSE, SamsungA2}, - {"\x00\xA4", 2, "Unknown - Korea A4", FALSE, NULL}, - {"\x00\xC2", 2, "Samsung", FALSE, NULL}, - {"\x00\xC9", 2, "Unknown - Korea C9", FALSE, NULL}, - {"\x00\xCC", 2, "Unknown - Korea CC", FALSE, NULL}, - {"\x00\xD2", 2, "Unknown - Korea D2", FALSE, NULL}, - {"\x00\xDA", 2, "Xerox", FALSE, XeroxDA}, - {"\x00\xE2", 2, "Unknown - Korea E2", FALSE, NULL}, - {"\x00\xEC", 2, "Unknown - Korea EC", FALSE, NULL}, - {"\x00\xEE", 2, "Unknown - Korea EE", FALSE, NULL}, - {NULL, 0, NULL, FALSE, NULL} + {"\x00\x02", 2, "Unknown - Korea 02", false, NULL}, + {"\x00\x06", 2, "Unknown - Korea 06", false, NULL}, + {"\x00\x08", 2, "Unknown - Korea 08", false, NULL}, + {"\x00\x0A", 2, "Unknown - Korea 0A", false, NULL}, + {"\x00\x0E", 2, "Unknown - Korea 0E", false, NULL}, + {"\x00\x10", 2, "Samsung", false, NULL}, + {"\x00\x11", 2, "Unknown - Korea 11", false, NULL}, + {"\x00\x16", 2, "Samsung", false, Samsung16}, + {"\x00\x1A", 2, "Unknown - Korea 1A", false, NULL}, + {"\x00\x40", 2, "Unknown - Korea 40", false, NULL}, + {"\x00\x48", 2, "Unknown - Korea 48", false, NULL}, + {"\x00\x52", 2, "Unknown - Korea 52", false, NULL}, + {"\x00\x5A", 2, "Samsung", false, Samsung5A}, + {"\x00\x5E", 2, "Unknown - Korea 5E", false, NULL}, + {"\x00\x66", 2, "Unknown - Korea 66", false, NULL}, + {"\x00\x6E", 2, "Unknown - Korea 6E", false, NULL}, + {"\x00\x82", 2, "Unknown - Korea 82", false, NULL}, + {"\x00\x88", 2, "Unknown - Korea 88", false, NULL}, + {"\x00\x8A", 2, "Unknown - Korea 8A", false, NULL}, + {"\x00\x8C", 2, "Samsung", false, Samsung8C}, + {"\x00\x92", 2, "Unknown - Korea 92", false, NULL}, + {"\x00\x98", 2, "Samsung", false, NULL}, + {"\x00\xA2", 2, "Samsung", false, SamsungA2}, + {"\x00\xA4", 2, "Unknown - Korea A4", false, NULL}, + {"\x00\xC2", 2, "Samsung", false, NULL}, + {"\x00\xC9", 2, "Unknown - Korea C9", false, NULL}, + {"\x00\xCC", 2, "Unknown - Korea CC", false, NULL}, + {"\x00\xD2", 2, "Unknown - Korea D2", false, NULL}, + {"\x00\xDA", 2, "Xerox", false, XeroxDA}, + {"\x00\xE2", 2, "Unknown - Korea E2", false, NULL}, + {"\x00\xEC", 2, "Unknown - Korea EC", false, NULL}, + {"\x00\xEE", 2, "Unknown - Korea EE", false, NULL}, + {NULL, 0, NULL, false, NULL} }; static const nsf_data_t vendor_bc[] = { /* France */ - {"\x53\x01", 2, "Minolta", FALSE, NULL}, - {NULL, 0, NULL, FALSE, NULL} + {"\x53\x01", 2, "Minolta", false, NULL}, + {NULL, 0, NULL, false, NULL} }; static const nsf_data_t vendor_ad[] = { /* United States (not Tunisia) */ - {"\x00\x00", 2, "Pitney Bowes", FALSE, PitneyBowes}, - {"\x00\x0C", 2, "Dialogic", FALSE, NULL}, - {"\x00\x15", 2, "Lexmark", FALSE, Lexmark}, - {"\x00\x16", 2, "JetFax", FALSE, JetFax}, - {"\x00\x24", 2, "Octel", FALSE, NULL}, - {"\x00\x36", 2, "HP", FALSE, HP}, - {"\x00\x42", 2, "FaxTalk", FALSE, NULL}, - {"\x00\x44", 2, NULL, TRUE, NULL}, - {"\x00\x46", 2, "BrookTrout", FALSE, NULL}, - {"\x00\x51", 2, "Telogy Networks", FALSE, NULL}, - {"\x00\x55", 2, "HylaFAX", FALSE, NULL}, - {"\x00\x5C", 2, "IBM", FALSE, NULL}, - {"\x00\x98", 2, "Unknown - USA 98", TRUE, NULL}, - {NULL, 0, NULL, FALSE, NULL} + {"\x00\x00", 2, "Pitney Bowes", false, PitneyBowes}, + {"\x00\x0C", 2, "Dialogic", false, NULL}, + {"\x00\x15", 2, "Lexmark", false, Lexmark}, + {"\x00\x16", 2, "JetFax", false, JetFax}, + {"\x00\x24", 2, "Octel", false, NULL}, + {"\x00\x36", 2, "HP", false, HP}, + {"\x00\x42", 2, "FaxTalk", false, NULL}, + {"\x00\x44", 2, NULL, true, NULL}, + {"\x00\x46", 2, "BrookTrout", false, NULL}, + {"\x00\x51", 2, "Telogy Networks", false, NULL}, + {"\x00\x55", 2, "HylaFAX", false, NULL}, + {"\x00\x5C", 2, "IBM", false, NULL}, + {"\x00\x98", 2, "Unknown - USA 98", true, NULL}, + {NULL, 0, NULL, false, NULL} }; static const nsf_data_t vendor_b4[] = { /* United Kingdom */ - {"\x00\xB0", 2, "DCE", FALSE, NULL}, - {"\x00\xB1", 2, "Hasler", FALSE, NULL}, - {"\x00\xB2", 2, "Interquad", FALSE, NULL}, - {"\x00\xB3", 2, "Comwave", FALSE, NULL}, - {"\x00\xB4", 2, "Iconographic", FALSE, NULL}, - {"\x00\xB5", 2, "Wordcraft", FALSE, NULL}, - {"\x00\xB6", 2, "Acorn", FALSE, NULL}, - {NULL, 0, NULL, FALSE, NULL} + {"\x00\xB0", 2, "DCE", false, NULL}, + {"\x00\xB1", 2, "Hasler", false, NULL}, + {"\x00\xB2", 2, "Interquad", false, NULL}, + {"\x00\xB3", 2, "Comwave", false, NULL}, + {"\x00\xB4", 2, "Iconographic", false, NULL}, + {"\x00\xB5", 2, "Wordcraft", false, NULL}, + {"\x00\xB6", 2, "Acorn", false, NULL}, + {NULL, 0, NULL, false, NULL} }; static const nsf_data_t vendor_b5[] = { /* United States */ - {"\x00\x01", 2, "Picturetel", FALSE, NULL}, - {"\x00\x20", 2, "Conexant", FALSE, NULL}, - {"\x00\x22", 2, "Comsat", FALSE, NULL}, - {"\x00\x24", 2, "Octel", FALSE, NULL}, - {"\x00\x26", 2, "ROLM", FALSE, NULL}, - {"\x00\x28", 2, "SOFNET", FALSE, NULL}, - {"\x00\x29", 2, "TIA TR-29 Committee", FALSE, NULL}, - {"\x00\x2A", 2, "STF Tech", FALSE, NULL}, - {"\x00\x2C", 2, "HKB", FALSE, NULL}, - {"\x00\x2E", 2, "Delrina", FALSE, NULL}, - {"\x00\x30", 2, "Dialogic", FALSE, NULL}, - {"\x00\x32", 2, "Applied Synergy", FALSE, NULL}, - {"\x00\x34", 2, "Syncro Development", FALSE, NULL}, - {"\x00\x36", 2, "Genoa", FALSE, NULL}, - {"\x00\x38", 2, "Texas Instruments", FALSE, NULL}, - {"\x00\x3A", 2, "IBM", FALSE, NULL}, - {"\x00\x3C", 2, "ViaSat", FALSE, NULL}, - {"\x00\x3E", 2, "Ericsson", FALSE, NULL}, - {"\x00\x42", 2, "Bogosian", FALSE, NULL}, - {"\x00\x44", 2, "Adobe", FALSE, NULL}, - {"\x00\x46", 2, "Fremont Communications", FALSE, NULL}, - {"\x00\x48", 2, "Hayes", FALSE, NULL}, - {"\x00\x4A", 2, "Lucent", FALSE, NULL}, - {"\x00\x4C", 2, "Data Race", FALSE, NULL}, - {"\x00\x4E", 2, "TRW", FALSE, NULL}, - {"\x00\x52", 2, "Audiofax", FALSE, NULL}, - {"\x00\x54", 2, "Computer Automation", FALSE, NULL}, - {"\x00\x56", 2, "Serca", FALSE, NULL}, - {"\x00\x58", 2, "Octocom", FALSE, NULL}, - {"\x00\x5C", 2, "Power Solutions", FALSE, NULL}, - {"\x00\x5A", 2, "Digital Sound", FALSE, NULL}, - {"\x00\x5E", 2, "Pacific Data", FALSE, NULL}, - {"\x00\x60", 2, "Commetrex", FALSE, NULL}, - {"\x00\x62", 2, "BrookTrout", FALSE, NULL}, - {"\x00\x64", 2, "Gammalink", FALSE, NULL}, - {"\x00\x66", 2, "Castelle", FALSE, NULL}, - {"\x00\x68", 2, "Hybrid Fax", FALSE, NULL}, - {"\x00\x6A", 2, "Omnifax", FALSE, NULL}, - {"\x00\x6C", 2, "HP", FALSE, NULL}, - {"\x00\x6E", 2, "Microsoft", FALSE, NULL}, - {"\x00\x72", 2, "Speaking Devices", FALSE, NULL}, - {"\x00\x74", 2, "Compaq", FALSE, NULL}, - {"\x00\x76", 2, "Microsoft", FALSE, NULL}, /* uses LSB for country but MSB for manufacturer */ - {"\x00\x78", 2, "Cylink", FALSE, NULL}, - {"\x00\x7A", 2, "Pitney Bowes", FALSE, NULL}, - {"\x00\x7C", 2, "Digiboard", FALSE, NULL}, - {"\x00\x7E", 2, "Codex", FALSE, NULL}, - {"\x00\x82", 2, "Wang Labs", FALSE, NULL}, - {"\x00\x84", 2, "Netexpress Communications", FALSE, NULL}, - {"\x00\x86", 2, "Cable-Sat", FALSE, NULL}, - {"\x00\x88", 2, "MFPA", FALSE, NULL}, - {"\x00\x8A", 2, "Telogy Networks", FALSE, NULL}, - {"\x00\x8E", 2, "Telecom Multimedia Systems", FALSE, NULL}, - {"\x00\x8C", 2, "AT&T", FALSE, NULL}, - {"\x00\x92", 2, "Nuera", FALSE, NULL}, - {"\x00\x94", 2, "K56flex", FALSE, NULL}, - {"\x00\x96", 2, "MiBridge", FALSE, NULL}, - {"\x00\x98", 2, "Xerox", FALSE, NULL}, - {"\x00\x9A", 2, "Fujitsu", FALSE, NULL}, - {"\x00\x9B", 2, "Fujitsu", FALSE, NULL}, - {"\x00\x9C", 2, "Natural Microsystems", FALSE, NULL}, - {"\x00\x9E", 2, "CopyTele", FALSE, NULL}, - {"\x00\xA2", 2, "Murata", FALSE, NULL}, - {"\x00\xA4", 2, "Lanier", FALSE, NULL}, - {"\x00\xA6", 2, "Qualcomm", FALSE, NULL}, - {"\x00\xAA", 2, "HylaFAX", FALSE, NULL}, - {NULL, 0, NULL, FALSE, NULL} + {"\x00\x01", 2, "Picturetel", false, NULL}, + {"\x00\x20", 2, "Conexant", false, NULL}, + {"\x00\x22", 2, "Comsat", false, NULL}, + {"\x00\x24", 2, "Octel", false, NULL}, + {"\x00\x26", 2, "ROLM", false, NULL}, + {"\x00\x28", 2, "SOFNET", false, NULL}, + {"\x00\x29", 2, "TIA TR-29 Committee", false, NULL}, + {"\x00\x2A", 2, "STF Tech", false, NULL}, + {"\x00\x2C", 2, "HKB", false, NULL}, + {"\x00\x2E", 2, "Delrina", false, NULL}, + {"\x00\x30", 2, "Dialogic", false, NULL}, + {"\x00\x32", 2, "Applied Synergy", false, NULL}, + {"\x00\x34", 2, "Syncro Development", false, NULL}, + {"\x00\x36", 2, "Genoa", false, NULL}, + {"\x00\x38", 2, "Texas Instruments", false, NULL}, + {"\x00\x3A", 2, "IBM", false, NULL}, + {"\x00\x3C", 2, "ViaSat", false, NULL}, + {"\x00\x3E", 2, "Ericsson", false, NULL}, + {"\x00\x42", 2, "Bogosian", false, NULL}, + {"\x00\x44", 2, "Adobe", false, NULL}, + {"\x00\x46", 2, "Fremont Communications", false, NULL}, + {"\x00\x48", 2, "Hayes", false, NULL}, + {"\x00\x4A", 2, "Lucent", false, NULL}, + {"\x00\x4C", 2, "Data Race", false, NULL}, + {"\x00\x4E", 2, "TRW", false, NULL}, + {"\x00\x52", 2, "Audiofax", false, NULL}, + {"\x00\x54", 2, "Computer Automation", false, NULL}, + {"\x00\x56", 2, "Serca", false, NULL}, + {"\x00\x58", 2, "Octocom", false, NULL}, + {"\x00\x5C", 2, "Power Solutions", false, NULL}, + {"\x00\x5A", 2, "Digital Sound", false, NULL}, + {"\x00\x5E", 2, "Pacific Data", false, NULL}, + {"\x00\x60", 2, "Commetrex", false, NULL}, + {"\x00\x62", 2, "BrookTrout", false, NULL}, + {"\x00\x64", 2, "Gammalink", false, NULL}, + {"\x00\x66", 2, "Castelle", false, NULL}, + {"\x00\x68", 2, "Hybrid Fax", false, NULL}, + {"\x00\x6A", 2, "Omnifax", false, NULL}, + {"\x00\x6C", 2, "HP", false, NULL}, + {"\x00\x6E", 2, "Microsoft", false, NULL}, + {"\x00\x72", 2, "Speaking Devices", false, NULL}, + {"\x00\x74", 2, "Compaq", false, NULL}, + {"\x00\x76", 2, "Microsoft", false, NULL}, /* uses LSB for country but MSB for manufacturer */ + {"\x00\x78", 2, "Cylink", false, NULL}, + {"\x00\x7A", 2, "Pitney Bowes", false, NULL}, + {"\x00\x7C", 2, "Digiboard", false, NULL}, + {"\x00\x7E", 2, "Codex", false, NULL}, + {"\x00\x82", 2, "Wang Labs", false, NULL}, + {"\x00\x84", 2, "Netexpress Communications", false, NULL}, + {"\x00\x86", 2, "Cable-Sat", false, NULL}, + {"\x00\x88", 2, "MFPA", false, NULL}, + {"\x00\x8A", 2, "Telogy Networks", false, NULL}, + {"\x00\x8E", 2, "Telecom Multimedia Systems", false, NULL}, + {"\x00\x8C", 2, "AT&T", false, NULL}, + {"\x00\x92", 2, "Nuera", false, NULL}, + {"\x00\x94", 2, "K56flex", false, NULL}, + {"\x00\x96", 2, "MiBridge", false, NULL}, + {"\x00\x98", 2, "Xerox", false, NULL}, + {"\x00\x9A", 2, "Fujitsu", false, NULL}, + {"\x00\x9B", 2, "Fujitsu", false, NULL}, + {"\x00\x9C", 2, "Natural Microsystems", false, NULL}, + {"\x00\x9E", 2, "CopyTele", false, NULL}, + {"\x00\xA2", 2, "Murata", false, NULL}, + {"\x00\xA4", 2, "Lanier", false, NULL}, + {"\x00\xA6", 2, "Qualcomm", false, NULL}, + {"\x00\xAA", 2, "HylaFAX", false, NULL}, + {NULL, 0, NULL, false, NULL} }; static const country_code_t t35_country_codes[255] = @@ -904,7 +909,7 @@ SPAN_DECLARE(const char *) t35_vendor_to_str(const uint8_t *msg, int len) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) t35_decode(const uint8_t *msg, int len, const char **country, const char **vendor, const char **model) +SPAN_DECLARE(bool) t35_decode(const uint8_t *msg, int len, const char **country, const char **vendor, const char **model) { const nsf_data_t *p; const model_data_t *pp; @@ -917,7 +922,7 @@ SPAN_DECLARE(int) t35_decode(const uint8_t *msg, int len, const char **country, *model = NULL; if ((p = find_vendor(msg, len)) == NULL) - return FALSE; + return false; if (vendor) *vendor = p->vendor_name; if (model && p->known_models) @@ -933,7 +938,7 @@ SPAN_DECLARE(int) t35_decode(const uint8_t *msg, int len, const char **country, } } } - return TRUE; + return true; } /*- End of function --------------------------------------------------------*/ /*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/t38_core.c b/libs/spandsp/src/t38_core.c index ae6526f7e8..0bbbd18fb6 100644 --- a/libs/spandsp/src/t38_core.c +++ b/libs/spandsp/src/t38_core.c @@ -41,12 +41,18 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include #include #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/bit_operations.h" #include "spandsp/t38_core.h" @@ -455,7 +461,7 @@ SPAN_DECLARE_NONSTD(int) t38_core_rx_ifp_stream(t38_core_state_t *s, const uint8 //printf("Count is %d\n", count); /* Do a dummy run through the fields to check we have a complete and uncorrupted packet. */ prev_ptr = ptr; - other_half = FALSE; + other_half = false; t30_field_type = 0; for (i = 0; i < (int) count; i++) { @@ -472,7 +478,7 @@ SPAN_DECLARE_NONSTD(int) t38_core_rx_ifp_stream(t38_core_state_t *s, const uint8 /* Decode field_type */ t30_field_type = buf[ptr] & 0x7; ptr++; - other_half = FALSE; + other_half = false; } else { @@ -482,7 +488,7 @@ SPAN_DECLARE_NONSTD(int) t38_core_rx_ifp_stream(t38_core_state_t *s, const uint8 if (field_data_present) ptr++; else - other_half = TRUE; + other_half = true; } if (t30_field_type > T38_FIELD_T4_NON_ECM_SIG_END) { @@ -537,7 +543,7 @@ SPAN_DECLARE_NONSTD(int) t38_core_rx_ifp_stream(t38_core_state_t *s, const uint8 /* Things look alright in the data, so lets run through the fields again, actually processing them. There is no need to do all the error checking along the way on this pass. */ ptr = prev_ptr; - other_half = FALSE; + other_half = false; for (i = 0; i < (int) count; i++) { if (s->t38_version == 0) @@ -551,7 +557,7 @@ SPAN_DECLARE_NONSTD(int) t38_core_rx_ifp_stream(t38_core_state_t *s, const uint8 /* Decode field_type */ t30_field_type = buf[ptr] & 0x7; ptr++; - other_half = FALSE; + other_half = false; } else { @@ -561,7 +567,7 @@ SPAN_DECLARE_NONSTD(int) t38_core_rx_ifp_stream(t38_core_state_t *s, const uint8 if (field_data_present) ptr++; else - other_half = TRUE; + other_half = true; } } else @@ -1001,19 +1007,19 @@ SPAN_DECLARE(void) t38_set_data_transport_protocol(t38_core_state_t *s, int data } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) t38_set_fill_bit_removal(t38_core_state_t *s, int fill_bit_removal) +SPAN_DECLARE(void) t38_set_fill_bit_removal(t38_core_state_t *s, bool fill_bit_removal) { s->fill_bit_removal = fill_bit_removal; } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) t38_set_mmr_transcoding(t38_core_state_t *s, int mmr_transcoding) +SPAN_DECLARE(void) t38_set_mmr_transcoding(t38_core_state_t *s, bool mmr_transcoding) { s->mmr_transcoding = mmr_transcoding; } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) t38_set_jbig_transcoding(t38_core_state_t *s, int jbig_transcoding) +SPAN_DECLARE(void) t38_set_jbig_transcoding(t38_core_state_t *s, bool jbig_transcoding) { s->jbig_transcoding = jbig_transcoding; } @@ -1037,7 +1043,7 @@ SPAN_DECLARE(void) t38_set_t38_version(t38_core_state_t *s, int t38_version) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) t38_set_sequence_number_handling(t38_core_state_t *s, int check) +SPAN_DECLARE(void) t38_set_sequence_number_handling(t38_core_state_t *s, bool check) { s->check_sequence_numbers = check; } @@ -1049,7 +1055,7 @@ SPAN_DECLARE(void) t38_set_pace_transmission(t38_core_state_t *s, int pace_trans } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) t38_set_tep_handling(t38_core_state_t *s, int allow_for_tep) +SPAN_DECLARE(void) t38_set_tep_handling(t38_core_state_t *s, bool allow_for_tep) { s->allow_for_tep = allow_for_tep; } @@ -1109,7 +1115,7 @@ SPAN_DECLARE(t38_core_state_t *) t38_core_init(t38_core_state_t *s, { if (s == NULL) { - if ((s = (t38_core_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (t38_core_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -1120,14 +1126,14 @@ SPAN_DECLARE(t38_core_state_t *) t38_core_init(t38_core_state_t *s, T.38 domain - e.g. from SDP data. */ s->data_rate_management_method = T38_DATA_RATE_MANAGEMENT_TRANSFERRED_TCF; s->data_transport_protocol = T38_TRANSPORT_UDPTL; - s->fill_bit_removal = FALSE; - s->mmr_transcoding = FALSE; - s->jbig_transcoding = FALSE; + s->fill_bit_removal = false; + s->mmr_transcoding = false; + s->jbig_transcoding = false; s->max_buffer_size = 400; s->max_datagram_size = 100; s->t38_version = 0; - s->check_sequence_numbers = TRUE; - s->pace_transmission = TRUE; + s->check_sequence_numbers = true; + s->pace_transmission = true; /* Set some defaults */ s->category_control[T38_PACKET_CATEGORY_INDICATOR] = 1; @@ -1157,7 +1163,7 @@ SPAN_DECLARE(int) t38_core_release(t38_core_state_t *s) SPAN_DECLARE(int) t38_core_free(t38_core_state_t *s) { if (s) - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/t38_gateway.c b/libs/spandsp/src/t38_gateway.c index 7656332e80..402c7cded2 100644 --- a/libs/spandsp/src/t38_gateway.c +++ b/libs/spandsp/src/t38_gateway.c @@ -42,6 +42,11 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include #if defined(LOG_FAX_AUDIO) @@ -50,6 +55,7 @@ #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/queue.h" #include "spandsp/dc_restore.h" @@ -69,6 +75,10 @@ #include "spandsp/v27ter_rx.h" #include "spandsp/v17tx.h" #include "spandsp/v17rx.h" +#if defined(SPANDSP_SUPPORT_V34) +#include "spandsp/bitstream.h" +#include "spandsp/v34.h" +#endif #include "spandsp/super_tone_rx.h" #include "spandsp/modem_connect_tones.h" #include "spandsp/timezone.h" @@ -78,9 +88,7 @@ #include "spandsp/t81_t82_arith_coding.h" #include "spandsp/t85.h" #include "spandsp/t42.h" -#if defined(SPANDSP_SUPPORT_T43) #include "spandsp/t43.h" -#endif #include "spandsp/t4_t6_decode.h" #include "spandsp/t4_t6_encode.h" #include "spandsp/t30_fcf.h" @@ -94,7 +102,12 @@ #include "spandsp/private/logging.h" #include "spandsp/private/silence_gen.h" +#include "spandsp/private/power_meter.h" #include "spandsp/private/fsk.h" +#if defined(SPANDSP_SUPPORT_V34) +#include "spandsp/private/bitstream.h" +#include "spandsp/private/v34.h" +#endif #include "spandsp/private/v17tx.h" #include "spandsp/private/v17rx.h" #include "spandsp/private/v27ter_tx.h" @@ -108,9 +121,7 @@ #include "spandsp/private/t81_t82_arith_coding.h" #include "spandsp/private/t85.h" #include "spandsp/private/t42.h" -#if defined(SPANDSP_SUPPORT_T43) #include "spandsp/private/t43.h" -#endif #include "spandsp/private/t4_t6_decode.h" #include "spandsp/private/t4_t6_encode.h" #include "spandsp/private/image_translate.h" @@ -255,7 +266,6 @@ static int set_next_tx_type(t38_gateway_state_t *s) int indicator; fax_modems_state_t *t; t38_gateway_hdlc_state_t *u; - int bit_rate; int short_train; int use_hdlc; @@ -270,22 +280,22 @@ static int set_next_tx_type(t38_gateway_state_t *s) || t->tx_handler == (span_tx_handler_t) &tone_gen) { - fax_modems_set_rx_active(t, TRUE); + fax_modems_set_rx_active(t, true); } else { - fax_modems_set_rx_active(t, FALSE); + fax_modems_set_rx_active(t, false); } /*endif*/ - return TRUE; + return true; } /*endif*/ u = &s->core.hdlc_to_modem; if (u->in == u->out) - return FALSE; + return false; /*endif*/ if ((u->buf[u->out].contents & FLAG_INDICATOR) == 0) - return FALSE; + return false; /*endif*/ indicator = (u->buf[u->out].contents & 0xFF); u->buf[u->out].len = 0; @@ -298,15 +308,15 @@ static int set_next_tx_type(t38_gateway_state_t *s) if (s->core.image_data_mode && s->core.ecm_mode) { span_log(&s->logging, SPAN_LOG_FLOW, "HDLC mode\n"); - hdlc_tx_init(&t->hdlc_tx, FALSE, 2, TRUE, hdlc_underflow_handler, s); + hdlc_tx_init(&t->hdlc_tx, false, 2, true, hdlc_underflow_handler, s); fax_modems_set_get_bit(t, (get_bit_func_t) hdlc_tx_get_bit, &t->hdlc_tx); - use_hdlc = TRUE; + use_hdlc = true; } else { span_log(&s->logging, SPAN_LOG_FLOW, "Non-ECM mode\n"); fax_modems_set_get_bit(t, (get_bit_func_t) t38_non_ecm_buffer_get_bit, &s->core.non_ecm_to_modem); - use_hdlc = FALSE; + use_hdlc = false; } /*endif*/ switch (indicator) @@ -317,51 +327,49 @@ static int set_next_tx_type(t38_gateway_state_t *s) //silence_gen_set(&t->silence_gen, ms_to_samples(75)); fax_modems_set_tx_handler(t, (span_tx_handler_t) &silence_gen, &t->silence_gen); fax_modems_set_next_tx_handler(t, (span_tx_handler_t) NULL, NULL); - fax_modems_set_rx_active(t, TRUE); + fax_modems_set_rx_active(t, true); break; case T38_IND_CNG: t->tx_bit_rate = 0; fax_modems_start_slow_modem(t, FAX_MODEM_CNG_TONE_TX); silence_gen_set(&t->silence_gen, 0); fax_modems_set_next_tx_handler(t, (span_tx_handler_t) &silence_gen, &t->silence_gen); - fax_modems_set_rx_active(t, TRUE); + fax_modems_set_rx_active(t, true); break; case T38_IND_CED: t->tx_bit_rate = 0; fax_modems_start_slow_modem(t, FAX_MODEM_CED_TONE_TX); fax_modems_set_next_tx_handler(t, (span_tx_handler_t) NULL, NULL); - fax_modems_set_rx_active(t, TRUE); + fax_modems_set_rx_active(t, true); break; case T38_IND_V21_PREAMBLE: t->tx_bit_rate = 300; - hdlc_tx_init(&t->hdlc_tx, FALSE, 2, TRUE, hdlc_underflow_handler, s); + hdlc_tx_init(&t->hdlc_tx, false, 2, true, hdlc_underflow_handler, s); hdlc_tx_flags(&t->hdlc_tx, 32); silence_gen_alter(&t->silence_gen, ms_to_samples(75)); u->buf[u->in].len = 0; fax_modems_start_slow_modem(t, FAX_MODEM_V21_TX); fax_modems_set_tx_handler(t, (span_tx_handler_t) &silence_gen, &t->silence_gen); fax_modems_set_next_tx_handler(t, (span_tx_handler_t) &fsk_tx, &t->v21_tx); - fax_modems_set_rx_active(t, TRUE); + fax_modems_set_rx_active(t, true); break; case T38_IND_V27TER_2400_TRAINING: case T38_IND_V27TER_4800_TRAINING: - bit_rate = t->tx_bit_rate = (indicator == T38_IND_V27TER_4800_TRAINING) ? 4800 : 2400; silence_gen_alter(&t->silence_gen, ms_to_samples(75)); - fax_modems_start_fast_modem(t, FAX_MODEM_V27TER_TX, bit_rate, s->core.short_train, use_hdlc); + fax_modems_start_fast_modem(t, FAX_MODEM_V27TER_TX, t->tx_bit_rate, s->core.short_train, use_hdlc); fax_modems_set_tx_handler(t, (span_tx_handler_t) &silence_gen, &t->silence_gen); fax_modems_set_next_tx_handler(t, (span_tx_handler_t) &v27ter_tx, &t->fast_modems.v27ter_tx); - fax_modems_set_rx_active(t, TRUE); + fax_modems_set_rx_active(t, true); break; case T38_IND_V29_7200_TRAINING: case T38_IND_V29_9600_TRAINING: - bit_rate = t->tx_bit_rate = (indicator == T38_IND_V29_9600_TRAINING) ? 9600 : 7200; silence_gen_alter(&t->silence_gen, ms_to_samples(75)); - fax_modems_start_fast_modem(t, FAX_MODEM_V29_TX, bit_rate, s->core.short_train, use_hdlc); + fax_modems_start_fast_modem(t, FAX_MODEM_V29_TX, t->tx_bit_rate, s->core.short_train, use_hdlc); fax_modems_set_tx_handler(t, (span_tx_handler_t) &silence_gen, &t->silence_gen); fax_modems_set_next_tx_handler(t, (span_tx_handler_t) &v29_tx, &t->fast_modems.v29_tx); - fax_modems_set_rx_active(t, TRUE); + fax_modems_set_rx_active(t, true); break; case T38_IND_V17_7200_SHORT_TRAINING: case T38_IND_V17_7200_LONG_TRAINING: @@ -371,45 +379,44 @@ static int set_next_tx_type(t38_gateway_state_t *s) case T38_IND_V17_12000_LONG_TRAINING: case T38_IND_V17_14400_SHORT_TRAINING: case T38_IND_V17_14400_LONG_TRAINING: - short_train = FALSE; + short_train = false; switch (indicator) { case T38_IND_V17_7200_SHORT_TRAINING: - short_train = TRUE; - bit_rate = 7200; + short_train = true; + t->tx_bit_rate = 7200; break; case T38_IND_V17_7200_LONG_TRAINING: - bit_rate = 7200; + t->tx_bit_rate = 7200; break; case T38_IND_V17_9600_SHORT_TRAINING: - short_train = TRUE; - bit_rate = 9600; + short_train = true; + t->tx_bit_rate = 9600; break; case T38_IND_V17_9600_LONG_TRAINING: - bit_rate = 9600; + t->tx_bit_rate = 9600; break; case T38_IND_V17_12000_SHORT_TRAINING: - short_train = TRUE; - bit_rate = 12000; + short_train = true; + t->tx_bit_rate = 12000; break; case T38_IND_V17_12000_LONG_TRAINING: - bit_rate = 12000; + t->tx_bit_rate = 12000; break; case T38_IND_V17_14400_SHORT_TRAINING: - short_train = TRUE; - bit_rate = 14400; + short_train = true; + t->tx_bit_rate = 14400; break; case T38_IND_V17_14400_LONG_TRAINING: - bit_rate = 14400; + t->tx_bit_rate = 14400; break; } /*endswitch*/ - t->tx_bit_rate = bit_rate; silence_gen_alter(&t->silence_gen, ms_to_samples(75)); - fax_modems_start_fast_modem(t, FAX_MODEM_V17_TX, bit_rate, short_train, use_hdlc); + fax_modems_start_fast_modem(t, FAX_MODEM_V17_TX, t->tx_bit_rate, short_train, use_hdlc); fax_modems_set_tx_handler(t, (span_tx_handler_t) &silence_gen, &t->silence_gen); fax_modems_set_next_tx_handler(t, (span_tx_handler_t) &v17_tx, &t->fast_modems.v17_tx); - fax_modems_set_rx_active(t, TRUE); + fax_modems_set_rx_active(t, true); break; case T38_IND_V8_ANSAM: t->tx_bit_rate = 300; @@ -441,7 +448,7 @@ static int set_next_tx_type(t38_gateway_state_t *s) hdlc_tx_flags(&t->hdlc_tx, t->tx_bit_rate/(8*5)); /*endif*/ s->t38x.in_progress_rx_indicator = indicator; - return TRUE; + return true; } /*- End of function --------------------------------------------------------*/ @@ -509,7 +516,7 @@ static void edit_control_messages(t38_gateway_state_t *s, int from_modem, uint8_ processed, 2 machines which recognise each other might do special things we cannot handle as a middle man. */ span_log(&s->logging, SPAN_LOG_FLOW, "Corrupting %s message to prevent recognition\n", t30_frametype(buf[2])); - s->t38x.corrupt_current_frame[from_modem] = TRUE; + s->t38x.corrupt_current_frame[from_modem] = true; } /*endif*/ break; @@ -644,8 +651,8 @@ static void monitor_control_messages(t38_gateway_state_t *s, case T30_CFR: /* We are changing from TCF exchange to image exchange */ /* Successful training means we should change to short training */ - s->core.image_data_mode = TRUE; - s->core.short_train = TRUE; + s->core.image_data_mode = true; + s->core.short_train = true; span_log(&s->logging, SPAN_LOG_FLOW, "CFR - short train = %d, ECM = %d\n", s->core.short_train, s->core.ecm_mode); if (!from_modem) restart_rx_modem(s); @@ -654,14 +661,14 @@ static void monitor_control_messages(t38_gateway_state_t *s, case T30_RTN: case T30_RTP: /* We are going back to the exchange of fresh TCF */ - s->core.image_data_mode = FALSE; - s->core.short_train = FALSE; + s->core.image_data_mode = false; + s->core.short_train = false; break; case T30_CTR: /* T.30 says the first image data after this does full training, yet does not return to TCF. This seems to be the sole case of long training for image data. */ - s->core.short_train = FALSE; + s->core.short_train = false; break; case T30_DTC: case T30_DCS: @@ -670,8 +677,8 @@ static void monitor_control_messages(t38_gateway_state_t *s, correct modem. */ s->core.fast_bit_rate = 0; s->core.fast_rx_modem = FAX_MODEM_NONE; - s->core.image_data_mode = FALSE; - s->core.short_train = FALSE; + s->core.image_data_mode = false; + s->core.short_train = false; if (from_modem) s->core.timed_mode = TIMED_MODE_TCF_PREDICTABLE_MODEM_START_BEGIN; /*endif*/ @@ -721,13 +728,13 @@ static void monitor_control_messages(t38_gateway_state_t *s, the fast modem again, so abandon our idea of it. */ s->core.fast_bit_rate = 0; s->core.fast_rx_modem = FAX_MODEM_NONE; - s->core.image_data_mode = FALSE; - s->core.short_train = FALSE; + s->core.image_data_mode = false; + s->core.short_train = false; #endif /* Fall through */ case T30_MPS: case T30_PRI_MPS: - s->core.count_page_on_mcf = TRUE; + s->core.count_page_on_mcf = true; break; } /*endswitch*/ @@ -747,15 +754,15 @@ static void monitor_control_messages(t38_gateway_state_t *s, the fast modem again, so abandon our idea of it. */ s->core.fast_bit_rate = 0; s->core.fast_rx_modem = FAX_MODEM_NONE; - s->core.image_data_mode = FALSE; - s->core.short_train = FALSE; + s->core.image_data_mode = false; + s->core.short_train = false; #endif /* Fall through */ case T30_MPS: case T30_MPS | 1: case T30_PRI_MPS: case T30_PRI_MPS | 1: - s->core.count_page_on_mcf = TRUE; + s->core.count_page_on_mcf = true; break; case T30_MCF: case T30_MCF | 1: @@ -763,7 +770,7 @@ static void monitor_control_messages(t38_gateway_state_t *s, { s->core.pages_confirmed++; span_log(&s->logging, SPAN_LOG_FLOW, "Pages confirmed = %d\n", s->core.pages_confirmed); - s->core.count_page_on_mcf = FALSE; + s->core.count_page_on_mcf = false; } /*endif*/ break; @@ -1093,9 +1100,9 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, { if ((hdlc_buf->flags & HDLC_FLAG_MISSING_DATA) == 0) { - monitor_control_messages(s, FALSE, hdlc_buf->buf, hdlc_buf->len); + monitor_control_messages(s, false, hdlc_buf->buf, hdlc_buf->len); if (s->core.real_time_frame_handler) - s->core.real_time_frame_handler(s, s->core.real_time_frame_user_data, FALSE, hdlc_buf->buf, hdlc_buf->len); + s->core.real_time_frame_handler(s, s->core.real_time_frame_user_data, false, hdlc_buf->buf, hdlc_buf->len); /*endif*/ } /*endif*/ @@ -1106,11 +1113,11 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, long training. There has to be more than one value HDLC frame in a chunk of image data, so just setting short training mode here should be enough. */ - s->core.short_train = TRUE; + s->core.short_train = true; } /*endif*/ hdlc_buf->contents = (data_type | FLAG_DATA); - finalise_hdlc_frame(s, TRUE); + finalise_hdlc_frame(s, true); } else { @@ -1118,7 +1125,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, hdlc_buf->contents = 0; } /*endif*/ - xx->corrupt_current_frame[0] = FALSE; + xx->corrupt_current_frame[0] = false; break; case T38_FIELD_HDLC_FCS_BAD: xx->current_rx_field_class = T38_FIELD_CLASS_HDLC; @@ -1144,7 +1151,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, } /*endif*/ hdlc_buf->contents = (data_type | FLAG_DATA); - finalise_hdlc_frame(s, FALSE); + finalise_hdlc_frame(s, false); } else { @@ -1152,7 +1159,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, hdlc_buf->contents = 0; } /*endif*/ - xx->corrupt_current_frame[0] = FALSE; + xx->corrupt_current_frame[0] = false; break; case T38_FIELD_HDLC_FCS_OK_SIG_END: xx->current_rx_field_class = T38_FIELD_CLASS_HDLC; @@ -1181,9 +1188,9 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, { if ((hdlc_buf->flags & HDLC_FLAG_MISSING_DATA) == 0) { - monitor_control_messages(s, FALSE, hdlc_buf->buf, hdlc_buf->len); + monitor_control_messages(s, false, hdlc_buf->buf, hdlc_buf->len); if (s->core.real_time_frame_handler) - s->core.real_time_frame_handler(s, s->core.real_time_frame_user_data, FALSE, hdlc_buf->buf, hdlc_buf->len); + s->core.real_time_frame_handler(s, s->core.real_time_frame_user_data, false, hdlc_buf->buf, hdlc_buf->len); /*endif*/ } /*endif*/ @@ -1194,11 +1201,11 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, long training. There has to be more than one value HDLC frame in a chunk of image data, so just setting short training mode here should be enough. */ - s->core.short_train = TRUE; + s->core.short_train = true; } /*endif*/ hdlc_buf->contents = (data_type | FLAG_DATA); - finalise_hdlc_frame(s, TRUE); + finalise_hdlc_frame(s, true); } else { @@ -1212,7 +1219,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, xx->current_rx_field_class = T38_FIELD_CLASS_NONE; } /*endif*/ - xx->corrupt_current_frame[0] = FALSE; + xx->corrupt_current_frame[0] = false; break; case T38_FIELD_HDLC_FCS_BAD_SIG_END: xx->current_rx_field_class = T38_FIELD_CLASS_HDLC; @@ -1238,7 +1245,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, } /*endif*/ hdlc_buf->contents = (data_type | FLAG_DATA); - finalise_hdlc_frame(s, FALSE); + finalise_hdlc_frame(s, false); } else { @@ -1252,7 +1259,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, xx->current_rx_field_class = T38_FIELD_CLASS_NONE; } /*endif*/ - xx->corrupt_current_frame[0] = FALSE; + xx->corrupt_current_frame[0] = false; break; case T38_FIELD_HDLC_SIG_END: hdlc_buf = &s->core.hdlc_to_modem.buf[s->core.hdlc_to_modem.in]; @@ -1298,7 +1305,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, xx->current_rx_field_class = T38_FIELD_CLASS_NONE; } /*endif*/ - xx->corrupt_current_frame[0] = FALSE; + xx->corrupt_current_frame[0] = false; break; case T38_FIELD_T4_NON_ECM_DATA: if (xx->current_rx_field_class == T38_FIELD_CLASS_NONE) @@ -1314,7 +1321,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, if (len > 0) t38_non_ecm_buffer_inject(&s->core.non_ecm_to_modem, buf, len); /*endif*/ - xx->corrupt_current_frame[0] = FALSE; + xx->corrupt_current_frame[0] = false; break; case T38_FIELD_T4_NON_ECM_SIG_END: if (xx->current_rx_field_class == T38_FIELD_CLASS_NONE) @@ -1369,7 +1376,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, xx->current_rx_field_class = T38_FIELD_CLASS_NONE; } /*endif*/ - xx->corrupt_current_frame[0] = FALSE; + xx->corrupt_current_frame[0] = false; break; default: break; @@ -1520,11 +1527,11 @@ static void non_ecm_rx_status(void *user_data, int status) break; case SIG_STATUS_TRAINING_SUCCEEDED: /* The modem is now trained */ - s->audio.modems.rx_signal_present = TRUE; - s->audio.modems.rx_trained = TRUE; + s->audio.modems.rx_signal_present = true; + s->audio.modems.rx_trained = true; s->core.timed_mode = TIMED_MODE_IDLE; s->core.samples_to_timeout = 0; - s->core.short_train = TRUE; + s->core.short_train = true; to_t38_buffer_init(&s->core.to_t38); break; case SIG_STATUS_CARRIER_UP: @@ -1700,11 +1707,11 @@ static void hdlc_rx_status(hdlc_rx_state_t *t, int status) break; case SIG_STATUS_TRAINING_SUCCEEDED: /* The modem is now trained. */ - s->audio.modems.rx_signal_present = TRUE; - s->audio.modems.rx_trained = TRUE; - s->core.short_train = TRUE; + s->audio.modems.rx_signal_present = true; + s->audio.modems.rx_trained = true; + s->core.short_train = true; /* Behave like HDLC preamble has been announced. */ - t->framing_ok_announced = TRUE; + t->framing_ok_announced = true; to_t38_buffer_init(&s->core.to_t38); break; case SIG_STATUS_CARRIER_UP: @@ -1713,7 +1720,7 @@ static void hdlc_rx_status(hdlc_rx_state_t *t, int status) t->len = 0; t->num_bits = 0; t->flags_seen = 0; - t->framing_ok_announced = FALSE; + t->framing_ok_announced = false; to_t38_buffer_init(&s->core.to_t38); break; case SIG_STATUS_CARRIER_DOWN: @@ -1722,7 +1729,7 @@ static void hdlc_rx_status(hdlc_rx_state_t *t, int status) category = (s->t38x.current_tx_data_type == T38_DATA_V21) ? T38_PACKET_CATEGORY_CONTROL_DATA_END : T38_PACKET_CATEGORY_IMAGE_DATA_END; t38_core_send_data(&s->t38x.t38, s->t38x.current_tx_data_type, T38_FIELD_HDLC_SIG_END, NULL, 0, category); t38_core_send_indicator(&s->t38x.t38, T38_IND_NO_SIGNAL); - t->framing_ok_announced = FALSE; + t->framing_ok_announced = false; } /*endif*/ restart_rx_modem(s); @@ -1808,9 +1815,9 @@ static void rx_flag_or_abort(hdlc_rx_state_t *t) span_log(&s->logging, SPAN_LOG_FLOW, "HDLC frame type %s, CRC OK\n", t30_frametype(t->buffer[2])); if (s->t38x.current_tx_data_type == T38_DATA_V21) { - monitor_control_messages(s, TRUE, t->buffer, t->len - 2); + monitor_control_messages(s, true, t->buffer, t->len - 2); if (s->core.real_time_frame_handler) - s->core.real_time_frame_handler(s, s->core.real_time_frame_user_data, TRUE, t->buffer, t->len - 2); + s->core.real_time_frame_handler(s, s->core.real_time_frame_user_data, true, t->buffer, t->len - 2); /*endif*/ } else @@ -1818,7 +1825,7 @@ static void rx_flag_or_abort(hdlc_rx_state_t *t) /* Make sure we go back to short training if CTC/CTR has kicked us into long training. Any successful HDLC frame received at a rate other than V.21 is an adequate indication we should change. */ - s->core.short_train = TRUE; + s->core.short_train = true; } /*endif*/ /* It seems some boxes may not like us sending a _SIG_END here, and then another @@ -1849,13 +1856,13 @@ static void rx_flag_or_abort(hdlc_rx_state_t *t) if (s->t38x.current_tx_data_type == T38_DATA_V21) { t38_core_send_indicator(&s->t38x.t38, set_slow_packetisation(s)); - s->audio.modems.rx_signal_present = TRUE; + s->audio.modems.rx_signal_present = true; } /*endif*/ if (s->t38x.in_progress_rx_indicator == T38_IND_CNG) set_next_tx_type(s); /*endif*/ - t->framing_ok_announced = TRUE; + t->framing_ok_announced = true; } /*endif*/ } @@ -1866,7 +1873,7 @@ static void rx_flag_or_abort(hdlc_rx_state_t *t) t->num_bits = 0; u->crc = 0xFFFF; u->data_ptr = 0; - s->t38x.corrupt_current_frame[1] = FALSE; + s->t38x.corrupt_current_frame[1] = false; } /*- End of function --------------------------------------------------------*/ @@ -1961,9 +1968,9 @@ static int restart_rx_modem(t38_gateway_state_t *s) s->core.ecm_mode); t = &s->audio.modems; - hdlc_rx_init(&t->hdlc_rx, FALSE, TRUE, HDLC_FRAMING_OK_THRESHOLD, NULL, s); - t->rx_signal_present = FALSE; - t->rx_trained = FALSE; + hdlc_rx_init(&t->hdlc_rx, false, true, HDLC_FRAMING_OK_THRESHOLD, NULL, s); + t->rx_signal_present = false; + t->rx_trained = false; /* Default to the transmit data being V.21, unless a faster modem pops up trained. */ s->t38x.current_tx_data_type = T38_DATA_V21; //fax_modems_start_slow_modem(t, FAX_MODEM_V21_RX); @@ -1986,13 +1993,13 @@ static int restart_rx_modem(t38_gateway_state_t *s) /*endif*/ to_t38_buffer_init(&s->core.to_t38); s->core.to_t38.octets_per_data_packet = 1; - t->deferred_rx_handler_updates = TRUE; + t->deferred_rx_handler_updates = true; switch (s->core.fast_rx_modem) { case FAX_MODEM_V27TER_RX: case FAX_MODEM_V29_RX: case FAX_MODEM_V17_RX: - fax_modems_start_fast_modem(t, s->core.fast_rx_modem, s->core.fast_bit_rate, s->core.short_train, FALSE); + fax_modems_start_fast_modem(t, s->core.fast_rx_modem, s->core.fast_bit_rate, s->core.short_train, false); s->core.fast_rx_active = s->core.fast_rx_modem; break; case FAX_MODEM_V21_RX: @@ -2058,7 +2065,8 @@ SPAN_DECLARE_NONSTD(int) t38_gateway_rx(t38_gateway_state_t *s, int16_t amp[], i for (i = 0; i < len; i++) amp[i] = dc_restore(&s->audio.modems.dc_restore, amp[i]); /*endfor*/ - s->audio.modems.rx_handler(s->audio.modems.rx_user_data, amp, len); + if (s->audio.modems.rx_handler) + s->audio.modems.rx_handler(s->audio.modems.rx_user_data, amp, len); return 0; } /*- End of function --------------------------------------------------------*/ @@ -2099,12 +2107,13 @@ SPAN_DECLARE_NONSTD(int) t38_gateway_tx(t38_gateway_state_t *s, int16_t amp[], i required_len = max_len; #endif + len = 0; if ((len = s->audio.modems.tx_handler(s->audio.modems.tx_user_data, amp, max_len)) < max_len) { if (set_next_tx_type(s)) { /* Give the new handler a chance to file the remaining buffer space */ - len += s->audio.modems.tx_handler(s->audio.modems.tx_user_data, amp + len, max_len - len); + len += s->audio.modems.tx_handler(s->audio.modems.tx_user_data, &[len], max_len - len); if (len < max_len) { silence_gen_set(&s->audio.modems.silence_gen, 0); @@ -2118,7 +2127,7 @@ SPAN_DECLARE_NONSTD(int) t38_gateway_tx(t38_gateway_state_t *s, int16_t amp[], i if (s->audio.modems.transmit_on_idle) { /* Pad to the requested length with silence */ - memset(amp + len, 0, (max_len - len)*sizeof(int16_t)); + memset(&[len], 0, (max_len - len)*sizeof(int16_t)); len = max_len; } /*endif*/ @@ -2126,7 +2135,7 @@ SPAN_DECLARE_NONSTD(int) t38_gateway_tx(t38_gateway_state_t *s, int16_t amp[], i if (s->audio.modems.audio_tx_log >= 0) { if (len < required_len) - memset(amp + len, 0, (required_len - len)*sizeof(int16_t)); + memset(&[len], 0, (required_len - len)*sizeof(int16_t)); /*endif*/ write(s->audio.modems.audio_tx_log, amp, required_len*sizeof(int16_t)); } @@ -2157,13 +2166,13 @@ SPAN_DECLARE(logging_state_t *) t38_gateway_get_logging_state(t38_gateway_state_ } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) t38_gateway_set_ecm_capability(t38_gateway_state_t *s, int ecm_allowed) +SPAN_DECLARE(void) t38_gateway_set_ecm_capability(t38_gateway_state_t *s, bool ecm_allowed) { s->core.ecm_allowed = ecm_allowed; } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) t38_gateway_set_transmit_on_idle(t38_gateway_state_t *s, int transmit_on_idle) +SPAN_DECLARE(void) t38_gateway_set_transmit_on_idle(t38_gateway_state_t *s, bool transmit_on_idle) { s->audio.modems.transmit_on_idle = transmit_on_idle; } @@ -2193,13 +2202,13 @@ SPAN_DECLARE(void) t38_gateway_set_nsx_suppression(t38_gateway_state_t *s, } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) t38_gateway_set_tep_mode(t38_gateway_state_t *s, int use_tep) +SPAN_DECLARE(void) t38_gateway_set_tep_mode(t38_gateway_state_t *s, bool use_tep) { fax_modems_set_tep_mode(&s->audio.modems, use_tep); } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) t38_gateway_set_fill_bit_removal(t38_gateway_state_t *s, int remove) +SPAN_DECLARE(void) t38_gateway_set_fill_bit_removal(t38_gateway_state_t *s, bool remove) { s->core.to_t38.fill_bit_removal = remove; } @@ -2217,7 +2226,7 @@ SPAN_DECLARE(void) t38_gateway_set_real_time_frame_handler(t38_gateway_state_t * static int t38_gateway_audio_init(t38_gateway_state_t *s) { fax_modems_init(&s->audio.modems, - FALSE, + false, NULL, hdlc_underflow_handler, non_ecm_put_bit, @@ -2226,7 +2235,7 @@ static int t38_gateway_audio_init(t38_gateway_state_t *s) s); /* We need to use progressive HDLC transmit, and a special HDLC receiver, which is different from the other uses of FAX modems. */ - hdlc_tx_init(&s->audio.modems.hdlc_tx, FALSE, 2, TRUE, hdlc_underflow_handler, s); + hdlc_tx_init(&s->audio.modems.hdlc_tx, false, 2, true, hdlc_underflow_handler, s); fsk_rx_set_put_bit(&s->audio.modems.v21_rx, (put_bit_func_t) t38_hdlc_rx_put_bit, &s->audio.modems.hdlc_rx); /* TODO: Don't use the very low cutoff levels we would like to. We get some quirks if we do. We need to sort this out. */ @@ -2267,7 +2276,7 @@ SPAN_DECLARE(t38_gateway_state_t *) t38_gateway_init(t38_gateway_state_t *s, /*endif*/ if (s == NULL) { - if ((s = (t38_gateway_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (t38_gateway_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; /*endif*/ } @@ -2279,14 +2288,14 @@ SPAN_DECLARE(t38_gateway_state_t *) t38_gateway_init(t38_gateway_state_t *s, t38_gateway_audio_init(s); t38_gateway_t38_init(s, tx_packet_handler, tx_packet_user_data); - fax_modems_set_rx_active(&s->audio.modems, TRUE); + fax_modems_set_rx_active(&s->audio.modems, true); t38_gateway_set_supported_modems(s, T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17); t38_gateway_set_nsx_suppression(s, (const uint8_t *) "\x00\x00\x00", 3, (const uint8_t *) "\x00\x00\x00", 3); s->core.to_t38.octets_per_data_packet = 1; - s->core.ecm_allowed = TRUE; + s->core.ecm_allowed = true; s->core.ms_per_tx_chunk = DEFAULT_MS_PER_TX_CHUNK; - t38_non_ecm_buffer_init(&s->core.non_ecm_to_modem, FALSE, 0); + t38_non_ecm_buffer_init(&s->core.non_ecm_to_modem, false, 0); restart_rx_modem(s); s->core.timed_mode = TIMED_MODE_STARTUP; s->core.samples_to_timeout = 1; @@ -2332,7 +2341,7 @@ SPAN_DECLARE(int) t38_gateway_release(t38_gateway_state_t *s) SPAN_DECLARE(int) t38_gateway_free(t38_gateway_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/t38_non_ecm_buffer.c b/libs/spandsp/src/t38_non_ecm_buffer.c index cc339a0581..b5b2c8244b 100644 --- a/libs/spandsp/src/t38_non_ecm_buffer.c +++ b/libs/spandsp/src/t38_non_ecm_buffer.c @@ -42,10 +42,16 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/queue.h" #include "spandsp/dc_restore.h" @@ -75,7 +81,7 @@ static void restart_buffer(t38_non_ecm_buffer_state_t *s) s->out_ptr = 0; s->in_ptr = 0; s->latest_eol_ptr = 0; - s->data_finished = FALSE; + s->data_finished = false; } /*- End of function --------------------------------------------------------*/ @@ -123,7 +129,7 @@ SPAN_DECLARE(void) t38_non_ecm_buffer_push(t38_non_ecm_buffer_state_t *s) /* Don't flow control the data any more. Just push out the remainder of the data in the buffer as fast as we can, and shut down. */ s->latest_eol_ptr = s->in_ptr; - s->data_finished = TRUE; + s->data_finished = true; } /*- End of function --------------------------------------------------------*/ @@ -340,22 +346,22 @@ SPAN_DECLARE(void) t38_non_ecm_buffer_report_output_status(t38_non_ecm_buffer_st } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) t38_non_ecm_buffer_set_mode(t38_non_ecm_buffer_state_t *s, int mode, int min_bits_per_row) +SPAN_DECLARE(void) t38_non_ecm_buffer_set_mode(t38_non_ecm_buffer_state_t *s, bool image_mode, int min_bits_per_row) { - s->image_data_mode = mode; + s->image_data_mode = image_mode; s->min_bits_per_row = min_bits_per_row; } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(t38_non_ecm_buffer_state_t *) t38_non_ecm_buffer_init(t38_non_ecm_buffer_state_t *s, int mode, int min_bits_per_row) +SPAN_DECLARE(t38_non_ecm_buffer_state_t *) t38_non_ecm_buffer_init(t38_non_ecm_buffer_state_t *s, bool image_mode, int min_bits_per_row) { if (s == NULL) { - if ((s = (t38_non_ecm_buffer_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (t38_non_ecm_buffer_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); - s->image_data_mode = mode; + s->image_data_mode = image_mode; s->min_bits_per_row = min_bits_per_row; restart_buffer(s); return s; @@ -371,7 +377,7 @@ SPAN_DECLARE(int) t38_non_ecm_buffer_release(t38_non_ecm_buffer_state_t *s) SPAN_DECLARE(int) t38_non_ecm_buffer_free(t38_non_ecm_buffer_state_t *s) { if (s) - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/t38_terminal.c b/libs/spandsp/src/t38_terminal.c index 66938d8d24..75d8842d9a 100644 --- a/libs/spandsp/src/t38_terminal.c +++ b/libs/spandsp/src/t38_terminal.c @@ -41,11 +41,17 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/bit_operations.h" #include "spandsp/queue.h" @@ -68,9 +74,7 @@ #include "spandsp/t81_t82_arith_coding.h" #include "spandsp/t85.h" #include "spandsp/t42.h" -#if defined(SPANDSP_SUPPORT_T43) #include "spandsp/t43.h" -#endif #include "spandsp/t4_t6_decode.h" #include "spandsp/t4_t6_encode.h" #include "spandsp/t30_fcf.h" @@ -86,9 +90,7 @@ #include "spandsp/private/t81_t82_arith_coding.h" #include "spandsp/private/t85.h" #include "spandsp/private/t42.h" -#if defined(SPANDSP_SUPPORT_T43) #include "spandsp/private/t43.h" -#endif #include "spandsp/private/t4_t6_decode.h" #include "spandsp/private/t4_t6_encode.h" #include "spandsp/private/image_translate.h" @@ -214,7 +216,7 @@ static int process_rx_missing(t38_core_state_t *t, void *user_data, int rx_seq_n t38_terminal_state_t *s; s = (t38_terminal_state_t *) user_data; - s->t38_fe.rx_data_missing = TRUE; + s->t38_fe.rx_data_missing = true; return 0; } /*- End of function --------------------------------------------------------*/ @@ -250,7 +252,7 @@ static int process_rx_indicator(t38_core_state_t *t, void *user_data, int indica && (fe->current_rx_type == T30_MODEM_V21 || fe->current_rx_type == T30_MODEM_CNG)) { - hdlc_accept_frame(s, NULL, SIG_STATUS_CARRIER_DOWN, TRUE); + hdlc_accept_frame(s, NULL, SIG_STATUS_CARRIER_DOWN, true); } /*endif*/ fe->timeout_rx_samples = 0; @@ -303,7 +305,7 @@ static int process_rx_indicator(t38_core_state_t *t, void *user_data, int indica } /*endswitch*/ fe->hdlc_rx.len = 0; - fe->rx_data_missing = FALSE; + fe->rx_data_missing = false; return 0; } /*- End of function --------------------------------------------------------*/ @@ -327,7 +329,7 @@ static void process_hdlc_data(t38_terminal_front_end_state_t *fe, const uint8_t } else { - fe->rx_data_missing = TRUE; + fe->rx_data_missing = true; } } /*- End of function --------------------------------------------------------*/ @@ -424,7 +426,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, /* All real HDLC messages in the FAX world start with 0xFF. If this one is not starting with 0xFF it would appear some octets must have been missed before this one. */ if (len <= 0 || buf[0] != 0xFF) - fe->rx_data_missing = TRUE; + fe->rx_data_missing = true; /*endif*/ } /*endif*/ @@ -454,7 +456,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, fe->hdlc_rx.len = 0; } /*endif*/ - fe->rx_data_missing = FALSE; + fe->rx_data_missing = false; fe->timeout_rx_samples = fe->samples + ms_to_samples(MID_RX_TIMEOUT); break; case T38_FIELD_HDLC_FCS_BAD: @@ -472,11 +474,11 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, if (fe->hdlc_rx.len > 0) { span_log(&s->logging, SPAN_LOG_FLOW, "Type %s - CRC bad (%s)\n", (fe->hdlc_rx.len >= 3) ? t30_frametype(fe->hdlc_rx.buf[2]) : "???", (fe->rx_data_missing) ? "missing octets" : "clean"); - hdlc_accept_frame(s, fe->hdlc_rx.buf, fe->hdlc_rx.len, FALSE); + hdlc_accept_frame(s, fe->hdlc_rx.buf, fe->hdlc_rx.len, false); fe->hdlc_rx.len = 0; } /*endif*/ - fe->rx_data_missing = FALSE; + fe->rx_data_missing = false; fe->timeout_rx_samples = fe->samples + ms_to_samples(MID_RX_TIMEOUT); break; case T38_FIELD_HDLC_FCS_OK_SIG_END: @@ -498,9 +500,9 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, fe->hdlc_rx.len = 0; } /*endif*/ - fe->rx_data_missing = FALSE; + fe->rx_data_missing = false; if (t->current_rx_data_type != data_type || t->current_rx_field_type != field_type) - hdlc_accept_frame(s, NULL, SIG_STATUS_CARRIER_DOWN, TRUE); + hdlc_accept_frame(s, NULL, SIG_STATUS_CARRIER_DOWN, true); /*endif*/ /* Treat this like a no signal indicator has occurred, so if the no signal indicator is missing, we are still OK */ fake_rx_indicator(t, s, T38_IND_NO_SIGNAL); @@ -520,13 +522,13 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, if (fe->hdlc_rx.len > 0) { span_log(&s->logging, SPAN_LOG_FLOW, "Type %s - CRC bad, sig end (%s)\n", (fe->hdlc_rx.len >= 3) ? t30_frametype(fe->hdlc_rx.buf[2]) : "???", (fe->rx_data_missing) ? "missing octets" : "clean"); - hdlc_accept_frame(s, fe->hdlc_rx.buf, fe->hdlc_rx.len, FALSE); + hdlc_accept_frame(s, fe->hdlc_rx.buf, fe->hdlc_rx.len, false); fe->hdlc_rx.len = 0; } /*endif*/ - fe->rx_data_missing = FALSE; + fe->rx_data_missing = false; if (t->current_rx_data_type != data_type || t->current_rx_field_type != field_type) - hdlc_accept_frame(s, NULL, SIG_STATUS_CARRIER_DOWN, TRUE); + hdlc_accept_frame(s, NULL, SIG_STATUS_CARRIER_DOWN, true); /*endif*/ /* Treat this like a no signal indicator has occurred, so if the no signal indicator is missing, we are still OK */ fake_rx_indicator(t, s, T38_IND_NO_SIGNAL); @@ -551,7 +553,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, i.e. they send T38_FIELD_HDLC_FCS_OK, and then T38_FIELD_HDLC_SIG_END when the carrier actually drops. The other is because the HDLC signal drops unexpectedly - i.e. not just after a final frame. */ fe->hdlc_rx.len = 0; - fe->rx_data_missing = FALSE; + fe->rx_data_missing = false; front_end_status(s, T30_FRONT_END_RECEIVE_COMPLETE); } /*endif*/ @@ -562,7 +564,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, if (!fe->rx_signal_present) { t30_non_ecm_put_bit(&s->t30, SIG_STATUS_TRAINING_SUCCEEDED); - fe->rx_signal_present = TRUE; + fe->rx_signal_present = true; } /*endif*/ if (len > 0) @@ -584,7 +586,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, if (!fe->rx_signal_present) { t30_non_ecm_put_bit(&s->t30, SIG_STATUS_TRAINING_SUCCEEDED); - fe->rx_signal_present = TRUE; + fe->rx_signal_present = true; } /*endif*/ bit_reverse(buf2, buf, len); @@ -598,7 +600,7 @@ static int process_rx_data(t38_core_state_t *t, void *user_data, int data_type, front_end_status(s, T30_FRONT_END_RECEIVE_COMPLETE); } /*endif*/ - fe->rx_signal_present = FALSE; + fe->rx_signal_present = false; /* Treat this like a no signal indicator has occurred, so if the no signal indicator is missing, we are still OK */ fake_rx_indicator(t, s, T38_IND_NO_SIGNAL); break; @@ -1148,7 +1150,7 @@ SPAN_DECLARE(int) t38_terminal_send_timeout(t38_terminal_state_t *s, int samples fe = &s->t38_fe; if (fe->current_rx_type == T30_MODEM_DONE || fe->current_tx_type == T30_MODEM_DONE) - return TRUE; + return true; /*endif*/ fe->samples += samples; @@ -1161,12 +1163,12 @@ SPAN_DECLARE(int) t38_terminal_send_timeout(t38_terminal_state_t *s, int samples } /*endif*/ if (fe->timed_step == T38_TIMED_STEP_NONE) - return FALSE; + return false; /*endif*/ /* Wait until the right time comes along, unless we are working in "no delays" mode, while talking to an IAF terminal. */ if (fe->us_per_tx_chunk && fe->samples < fe->next_tx_samples) - return FALSE; + return false; /*endif*/ /* Its time to send something */ delay = 0; @@ -1197,11 +1199,11 @@ SPAN_DECLARE(int) t38_terminal_send_timeout(t38_terminal_state_t *s, int samples if (delay < 0) { t30_terminate(&s->t30); - return TRUE; + return true; } /*endif*/ fe->next_tx_samples += us_to_samples(delay); - return FALSE; + return false; } /*- End of function --------------------------------------------------------*/ @@ -1364,7 +1366,7 @@ SPAN_DECLARE(void) t38_terminal_set_config(t38_terminal_state_t *s, int config) if ((config & T38_TERMINAL_OPTION_NO_PACING)) { /* Continuous streaming mode, as used for TPKT over TCP transport */ - t38_set_pace_transmission(&s->t38_fe.t38, FALSE); + t38_set_pace_transmission(&s->t38_fe.t38, false); s->t38_fe.hdlc_tx.extra_bits = 0; if ((config & T38_TERMINAL_OPTION_NO_INDICATORS)) t38_set_redundancy_control(&s->t38_fe.t38, T38_PACKET_CATEGORY_INDICATOR, 0); @@ -1382,7 +1384,7 @@ SPAN_DECLARE(void) t38_terminal_set_config(t38_terminal_state_t *s, int config) else { /* Paced streaming mode, as used for UDP transports */ - t38_set_pace_transmission(&s->t38_fe.t38, TRUE); + t38_set_pace_transmission(&s->t38_fe.t38, true); s->t38_fe.hdlc_tx.extra_bits = 0; if ((config & T38_TERMINAL_OPTION_NO_INDICATORS)) t38_set_redundancy_control(&s->t38_fe.t38, T38_PACKET_CATEGORY_INDICATOR, 0); @@ -1410,7 +1412,7 @@ SPAN_DECLARE(void) t38_terminal_set_config(t38_terminal_state_t *s, int config) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) t38_terminal_set_tep_mode(t38_terminal_state_t *s, int use_tep) +SPAN_DECLARE(void) t38_terminal_set_tep_mode(t38_terminal_state_t *s, bool use_tep) { if (use_tep) s->t38_fe.chunking_modes |= T38_CHUNKING_ALLOW_TEP_TIME; @@ -1421,7 +1423,7 @@ SPAN_DECLARE(void) t38_terminal_set_tep_mode(t38_terminal_state_t *s, int use_te } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) t38_terminal_set_fill_bit_removal(t38_terminal_state_t *s, int remove) +SPAN_DECLARE(void) t38_terminal_set_fill_bit_removal(t38_terminal_state_t *s, bool remove) { if (remove) s->t38_fe.iaf |= T30_IAF_MODE_NO_FILL_BITS; @@ -1451,7 +1453,7 @@ static int t38_terminal_t38_fe_restart(t38_terminal_state_t *t) s = &t->t38_fe; t38_core_restart(&s->t38); - s->rx_signal_present = FALSE; + s->rx_signal_present = false; s->timed_step = T38_TIMED_STEP_NONE; //s->iaf = T30_IAF_MODE_T37 | T30_IAF_MODE_T38; s->iaf = T30_IAF_MODE_T38; @@ -1482,7 +1484,7 @@ static int t38_terminal_t38_fe_init(t38_terminal_state_t *t, tx_packet_user_data); t38_set_fastest_image_data_rate(&s->t38, 14400); - s->rx_signal_present = FALSE; + s->rx_signal_present = false; s->timed_step = T38_TIMED_STEP_NONE; s->queued_timed_step = T38_TIMED_STEP_NONE; //s->iaf = T30_IAF_MODE_T37 | T30_IAF_MODE_T38; @@ -1506,7 +1508,7 @@ SPAN_DECLARE(logging_state_t *) t38_terminal_get_logging_state(t38_terminal_stat /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(int) t38_terminal_restart(t38_terminal_state_t *s, - int calling_party) + bool calling_party) { t38_terminal_t38_fe_restart(s); t30_restart(&s->t30); @@ -1515,7 +1517,7 @@ SPAN_DECLARE(int) t38_terminal_restart(t38_terminal_state_t *s, /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(t38_terminal_state_t *) t38_terminal_init(t38_terminal_state_t *s, - int calling_party, + bool calling_party, t38_tx_packet_handler_t tx_packet_handler, void *tx_packet_user_data) { @@ -1525,7 +1527,7 @@ SPAN_DECLARE(t38_terminal_state_t *) t38_terminal_init(t38_terminal_state_t *s, if (s == NULL) { - if ((s = (t38_terminal_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (t38_terminal_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; /*endif*/ } @@ -1564,7 +1566,7 @@ SPAN_DECLARE(int) t38_terminal_release(t38_terminal_state_t *s) SPAN_DECLARE(int) t38_terminal_free(t38_terminal_state_t *s) { t38_terminal_release(s); - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/t42.c b/libs/spandsp/src/t42.c index 3028c03472..37c98e1d95 100644 --- a/libs/spandsp/src/t42.c +++ b/libs/spandsp/src/t42.c @@ -38,19 +38,24 @@ #include #include #include +#include #if defined(HAVE_TGMATH_H) #include #endif #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include #include -#include -#include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/fast_convert.h" #include "spandsp/logging.h" #include "spandsp/saturated.h" @@ -67,6 +72,11 @@ #include "spandsp/private/t85.h" #include "spandsp/private/t42.h" +/* The open_memstream() and fmemopen() in older versions of glibc seem quirky */ +#if defined(__GLIBC__) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 12)) +#undef OPEN_MEMSTREAM +#endif + #define T42_USE_LUTS #include "t42_t43_local.h" @@ -90,37 +100,109 @@ typedef struct float zn; } illuminant_t; -typedef struct -{ - jmp_buf escape; - char error_message[JMSG_LENGTH_MAX]; -} escape_route_t; - static const illuminant_t illuminants[] = { - {"\0D50", "CIE D50/2°", 96.422f, 100.000f, 82.521f}, + {"\0D50", "CIE D50/2°", 96.422f, 100.000f, 82.521f}, /* Horizon Light. ICC profile PCS */ {"", "CIE D50/10°", 96.720f, 100.000f, 81.427f}, - {"", "CIE D55/2°", 95.682f, 100.000f, 92.149f}, + {"", "CIE D55/2°", 95.682f, 100.000f, 92.149f}, /* Mid-morning/mid-afternoon daylight */ {"", "CIE D55/10°", 95.799f, 100.000f, 90.926f}, - {"\0D65", "CIE D65/2°", 95.047f, 100.000f, 108.883f}, + {"\0D65", "CIE D65/2°", 95.047f, 100.000f, 108.883f}, /* Noon daylight, television, sRGB color space */ {"", "CIE D65/10°", 94.811f, 100.000f, 107.304f}, - {"\0D75", "CIE D75/2°", 94.972f, 100.000f, 122.638f}, + {"\0D75", "CIE D75/2°", 94.972f, 100.000f, 122.638f}, /* North sky daylight */ {"", "CIE D75/10°", 94.416f, 100.000f, 120.641f}, - {"\0\0F2", "F02/2°", 99.186f, 100.000f, 67.393f}, + {"\0\0F2", "F02/2°", 99.186f, 100.000f, 67.393f}, /* Cool white fluorescent */ {"", "F02/10°", 103.279f, 100.000f, 69.027f}, - {"\0\0F7", "F07/2°", 95.041f, 100.000f, 108.747f}, + {"\0\0F7", "F07/2°", 95.041f, 100.000f, 108.747f}, /* D65 simulator, daylight simulator */ {"", "F07/10°", 95.792f, 100.000f, 107.686f}, - {"\0F11", "F11/2°", 100.962f, 100.000f, 64.350f}, + {"\0F11", "F11/2°", 100.962f, 100.000f, 64.350f}, /* Philips TL84, Ultralume 40 */ {"", "F11/10°", 103.863f, 100.000f, 65.607f}, - {"\0\0SA", "A/2°", 109.850f, 100.000f, 35.585f}, + {"\0\0SA", "A/2°", 109.850f, 100.000f, 35.585f}, /* Incandescent/tungsten */ {"", "A/10°", 111.144f, 100.000f, 35.200f}, - {"\0\0SC", "C/2°", 98.074f, 100.000f, 118.232f}, + {"\0\0SC", "C/2°", 98.074f, 100.000f, 118.232f}, /* {obsolete} average/north sky daylight */ {"", "C/10°", 97.285f, 100.000f, 116.145f}, {"", "", 0.000f, 0.000f, 0.000f} }; -/* This is the error catcher */ -static struct jpeg_error_mgr error_handler; +/* LERP(a,b,c) = linear interpolation macro, is 'a' when c == 0.0 and 'b' when c == 1.0 */ +#define LERP(a,b,c) (((b) - (a))*(c) + (a)) + +typedef struct UVT +{ + double u; + double v; + double t; +} UVT; + +static const double rt[31] = +{ + /* Reciprocal temperature (K) */ + FLT_MIN, + 10.0e-6, + 20.0e-6, + 30.0e-6, + 40.0e-6, + 50.0e-6, + 60.0e-6, + 70.0e-6, + 80.0e-6, + 90.0e-6, + 100.0e-6, + 125.0e-6, + 150.0e-6, + 175.0e-6, + 200.0e-6, + 225.0e-6, + 250.0e-6, + 275.0e-6, + 300.0e-6, + 325.0e-6, + 350.0e-6, + 375.0e-6, + 400.0e-6, + 425.0e-6, + 450.0e-6, + 475.0e-6, + 500.0e-6, + 525.0e-6, + 550.0e-6, + 575.0e-6, + 600.0e-6 +}; + +static const UVT uvt[31] = +{ + {0.18006, 0.26352, -0.24341}, + {0.18066, 0.26589, -0.25479}, + {0.18133, 0.26846, -0.26876}, + {0.18208, 0.27119, -0.28539}, + {0.18293, 0.27407, -0.30470}, + {0.18388, 0.27709, -0.32675}, + {0.18494, 0.28021, -0.35156}, + {0.18611, 0.28342, -0.37915}, + {0.18740, 0.28668, -0.40955}, + {0.18880, 0.28997, -0.44278}, + {0.19032, 0.29326, -0.47888}, + {0.19462, 0.30141, -0.58204}, + {0.19962, 0.30921, -0.70471}, + {0.20525, 0.31647, -0.84901}, + {0.21142, 0.32312, -1.01820}, + {0.21807, 0.32909, -1.21680}, + {0.22511, 0.33439, -1.45120}, + {0.23247, 0.33904, -1.72980}, + {0.24010, 0.34308, -2.06370}, + {0.24792, 0.34655, -2.46810}, /* Note: 0.24792 is a corrected value for the error found in W&S as 0.24702 */ + {0.25591, 0.34951, -2.96410}, + {0.26400, 0.35200, -3.58140}, + {0.27218, 0.35407, -4.36330}, + {0.28039, 0.35577, -5.37620}, + {0.28863, 0.35714, -6.72620}, + {0.29685, 0.35823, -8.59550}, + {0.30505, 0.35907, -11.3240}, + {0.31320, 0.35968, -15.6280}, + {0.32129, 0.36011, -23.3250}, + {0.32931, 0.36038, -40.7700}, + {0.33724, 0.36051, -116.450} +}; static __inline__ uint16_t pack_16(const uint8_t *s) { @@ -148,88 +230,193 @@ static __inline__ int unpack_16(uint8_t *s, uint16_t value) } /*- End of function --------------------------------------------------------*/ -/* Error handler for IJG library */ -static void jpg_error_exit(j_common_ptr cinfo) +SPAN_DECLARE(bool) t42_analyse_header(uint32_t *width, uint32_t *length, const uint8_t data[], size_t len) { - escape_route_t *escape; + int type; + int seg; + int pos; - escape = (escape_route_t *) cinfo->client_data; - (*cinfo->err->format_message)(cinfo, escape->error_message); - longjmp(escape->escape, 1); + /* Search the image data for its width and length */ + *length = 0; + *width = 0; + + pos = 0; + if (pack_16(&data[pos]) != 0xFFD8) + return false; + pos += 2; + while (pos < len) + { + type = pack_16(&data[pos]); + pos += 2; + seg = pack_16(&data[pos]) - 2; + pos += 2; + if (type == 0xFFC0) + { + *length = pack_16(&data[pos + 1]); + *width = pack_16(&data[pos + 3]); + return true; + } + pos += seg; + } + return false; } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) set_lab_illuminant(lab_params_t *s, float new_xn, float new_yn, float new_zn) +SPAN_DECLARE(int) xyz_to_corrected_color_temp(float *temp, float xyz[3]) +{ + float us; + float vs; + float p; + float di; + float dm; + int i; + + /* Protect against possible divide-by-zero failure */ + if ((xyz[0] < 1.0e-20f) && (xyz[1] < 1.0e-20f) && (xyz[2] < 1.0e-20f)) + return -1; + us = (4.0f*xyz[0])/(xyz[0] + 15.0f*xyz[1] + 3.0f*xyz[2]); + vs = (6.0f*xyz[1])/(xyz[0] + 15.0f*xyz[1] + 3.0f*xyz[2]); + dm = 0.0f; + for (i = 0; i < 31; i++) + { + di = (vs - uvt[i].v) - uvt[i].t*(us - uvt[i].u); + if ((i > 0) && (((di < 0.0f) && (dm >= 0.0f)) || ((di >= 0.0f) && (dm < 0.0f)))) + break; /* found lines bounding (us, vs) : i-1 and i */ + dm = di; + } + if (i == 31) + { + /* Bad XYZ input, color temp would be less than minimum of 1666.7 degrees, or too far towards blue */ + return -1; + } + di = di/sqrtf(1.0f + uvt[i ].t*uvt[i ].t); + dm = dm/sqrtf(1.0f + uvt[i - 1].t*uvt[i - 1].t); + p = dm/(dm - di); /* p = interpolation parameter, 0.0 : i-1, 1.0 : i */ + p = 1.0f/(LERP(rt[i - 1], rt[i], p)); + *temp = p; + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) colour_temp_to_xyz(float xyz[3], float temp) +{ + float x; + float y; + + /* Should be good for 1667K to 25000K according to Wikipedia */ + if (temp < 1667.0f || temp > 25000.0f) + return -1; + + if (temp < 4000.0f) + x = -0.2661239e9f/(temp*temp*temp) - 0.2343580e6f/(temp*temp) + 0.8776956e3f/temp + 0.179910f; + else + x = -3.0258469e9f/(temp*temp*temp) + 2.1070379e6f/(temp*temp) + 0.2226347e3f/temp + 0.240390f; + + if (temp < 2222.0f) + y = -1.1063814f*x*x*x - 1.34811020f*x*x + 2.18555832f*x - 0.20219683f; + else if (temp < 4000.0f) + y = -0.9549476f*x*x*x - 1.37418593f*x*x + 2.09137015f*x - 0.16748867f; + else + y = 3.0817580f*x*x*x - 5.87338670f*x*x + 3.75112997f*x - 0.37001483f; + + xyz[0] = x/y; + xyz[1] = 1.0f; + xyz[2] = (1.0f - x - y)/y; + + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(void) set_lab_illuminant(lab_params_t *lab, float new_xn, float new_yn, float new_zn) { if (new_yn > 10.0f) { - s->x_n = new_xn/100.0f; - s->y_n = new_yn/100.0f; - s->z_n = new_zn/100.0f; + lab->x_n = new_xn/100.0f; + lab->y_n = new_yn/100.0f; + lab->z_n = new_zn/100.0f; } else { - s->x_n = new_xn; - s->y_n = new_yn; - s->z_n = new_zn; + lab->x_n = new_xn; + lab->y_n = new_yn; + lab->z_n = new_zn; } + lab->x_rn = 1.0f/lab->x_n; + lab->y_rn = 1.0f/lab->y_n; + lab->z_rn = 1.0f/lab->z_n; } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) set_lab_gamut(lab_params_t *s, int L_min, int L_max, int a_min, int a_max, int b_min, int b_max, int ab_are_signed) +SPAN_DECLARE(void) set_lab_gamut(lab_params_t *lab, int L_min, int L_max, int a_min, int a_max, int b_min, int b_max, int ab_are_signed) { - s->range_L = L_max - L_min; - s->range_a = a_max - a_min; - s->range_b = b_max - b_min; + lab->range_L = L_max - L_min; + lab->range_a = a_max - a_min; + lab->range_b = b_max - b_min; - s->offset_L = -256.0f*L_min/s->range_L; - s->offset_a = -256.0f*a_min/s->range_a; - s->offset_b = -256.0f*b_min/s->range_b; + lab->offset_L = -256.0f*L_min/lab->range_L; + lab->offset_a = -256.0f*a_min/lab->range_a; + lab->offset_b = -256.0f*b_min/lab->range_b; - s->range_L /= (256.0f - 1.0f); - s->range_a /= (256.0f - 1.0f); - s->range_b /= (256.0f - 1.0f); + lab->range_L /= (256.0f - 1.0f); + lab->range_a /= (256.0f - 1.0f); + lab->range_b /= (256.0f - 1.0f); - s->ab_are_signed = ab_are_signed; + lab->ab_are_signed = ab_are_signed; } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) set_lab_gamut2(lab_params_t *s, int L_P, int L_Q, int a_P, int a_Q, int b_P, int b_Q) +SPAN_DECLARE(void) set_lab_gamut2(lab_params_t *lab, int L_P, int L_Q, int a_P, int a_Q, int b_P, int b_Q) { - s->range_L = L_Q/(256.0f - 1.0f); - s->range_a = a_Q/(256.0f - 1.0f); - s->range_b = b_Q/(256.0f - 1.0f); + lab->range_L = L_Q/(256.0f - 1.0f); + lab->range_a = a_Q/(256.0f - 1.0f); + lab->range_b = b_Q/(256.0f - 1.0f); - s->offset_L = L_P; - s->offset_a = a_P; - s->offset_b = b_P; + lab->offset_L = L_P; + lab->offset_a = a_P; + lab->offset_b = b_P; - s->ab_are_signed = FALSE; + lab->ab_are_signed = false; } /*- End of function --------------------------------------------------------*/ -void set_illuminant_from_code(logging_state_t *logging, lab_params_t *s, const uint8_t code[4]) +SPAN_DECLARE(void) get_lab_gamut2(lab_params_t *lab, int *L_P, int *L_Q, int *a_P, int *a_Q, int *b_P, int *b_Q) +{ + *L_Q = lab->range_L*(256.0f - 1.0f); + *a_Q = lab->range_a*(256.0f - 1.0f); + *b_Q = lab->range_b*(256.0f - 1.0f); + + *L_P = lab->offset_L; + *a_P = lab->offset_a; + *b_P = lab->offset_b; +} +/*- End of function --------------------------------------------------------*/ + +int set_illuminant_from_code(logging_state_t *logging, lab_params_t *lab, const uint8_t code[4]) { int i; int colour_temp; + float xyz[3]; - if (code[0] == 'C' && code[1] == 'T') + if (memcmp(code, "CT", 2) == 0) { colour_temp = pack_16(&code[2]); span_log(logging, SPAN_LOG_FLOW, "Illuminant colour temp %dK\n", colour_temp); - return; + colour_temp_to_xyz(xyz, (float) colour_temp); + set_lab_illuminant(lab, xyz[0], xyz[1], xyz[2]); + return colour_temp; } for (i = 0; illuminants[i].name[0]; i++) { if (memcmp(code, illuminants[i].tag, 4) == 0) { span_log(logging, SPAN_LOG_FLOW, "Illuminant %s\n", illuminants[i].name); - set_lab_illuminant(s, illuminants[i].xn, illuminants[i].yn, illuminants[i].zn); - break; + set_lab_illuminant(lab, illuminants[i].xn, illuminants[i].yn, illuminants[i].zn); + return 0; } } if (illuminants[i].name[0] == '\0') span_log(logging, SPAN_LOG_FLOW, "Unrecognised illuminant 0x%x 0x%x 0x%x 0x%x\n", code[0], code[1], code[2], code[3]); + return -1; } /*- End of function --------------------------------------------------------*/ @@ -253,102 +440,6 @@ void set_gamut_from_code(logging_state_t *logging, lab_params_t *s, const uint8_ } /*- End of function --------------------------------------------------------*/ -static int is_itu_fax(logging_state_t *logging, lab_params_t *s, jpeg_saved_marker_ptr ptr) -{ - const uint8_t *data; - int ok; - int val[2]; - int i; - - ok = FALSE; - while (ptr) - { - if (ptr->marker == (JPEG_APP0 + 1) && ptr->data_length >= 6) - { - /* Markers are: - JPEG_RST0 - JPEG_EOI - JPEG_APP0 - JPEG_COM */ - data = (const uint8_t *) ptr->data; - if (strncmp((const char *) data, "G3FAX", 5) == 0) - { - switch (data[5]) - { - case 0: - for (i = 0; i < 2; i++) - val[i] = pack_16(&data[6 + 2*i]); - span_log(logging, SPAN_LOG_FLOW, "Version %d, resolution %d dpi\n", val[0], val[1]); - ok = TRUE; - break; - case 1: - span_log(logging, SPAN_LOG_FLOW, "Set gamut\n"); - if (ptr->data_length >= 6 + 12) - { - set_gamut_from_code(logging, s, &data[6]); - ok = TRUE; - } - else - { - span_log(logging, SPAN_LOG_FLOW, "Got bad G3FAX1 length - %d\n", ptr->data_length); - } - break; - case 2: - span_log(logging, SPAN_LOG_FLOW, "Set illuminant\n"); - if (ptr->data_length >= 6 + 4) - { - set_illuminant_from_code(logging, s, &data[6]); - ok = TRUE; - } - else - { - span_log(logging, SPAN_LOG_FLOW, "Got bad G3FAX2 length - %d\n", ptr->data_length); - } - break; - case 3: - /* Colour palette table */ - span_log(logging, SPAN_LOG_FLOW, "Set colour palette\n"); - if (ptr->data_length >= 6 + 2) - { - val[0] = pack_16(&data[6]); - span_log(logging, SPAN_LOG_FLOW, "Colour palette %d\n", val[0]); - } - else - { - span_log(logging, SPAN_LOG_FLOW, "Got bad G3FAX3 length - %d\n", ptr->data_length); - } - break; - default: - span_log(logging, SPAN_LOG_FLOW, "Got unexpected G3FAX%d length - %d\n", data[5], ptr->data_length); - break; - } - } - } - else - { - span_log(logging, SPAN_LOG_FLOW, "Got marker 0x%x, length %d\n", ptr->marker, ptr->data_length); - span_log_buf(logging, SPAN_LOG_FLOW, "Got marker", (const uint8_t *) ptr->data, ptr->data_length); - } - ptr = ptr->next; - } - - return ok; -} -/*- End of function --------------------------------------------------------*/ - -static void set_itu_fax(j_compress_ptr cinfo) -{ - uint8_t marker[10] = - { - 'G', '3', 'F', 'A', 'X', '\x00', '\x07', '\xCA', '\x00', '\x00' - }; - - unpack_16(marker + 8, 200); - - jpeg_write_marker(cinfo, (JPEG_APP0 + 1), marker, 10); -} -/*- End of function --------------------------------------------------------*/ - static __inline__ void itu_to_lab(lab_params_t *s, cielab_t *lab, const uint8_t in[3]) { uint8_t a; @@ -419,9 +510,9 @@ SPAN_DECLARE(void) srgb_to_lab(lab_params_t *s, uint8_t lab[], const uint8_t srg z = 0.0193f*r + 0.1192f*g + 0.9505f*b; /* Normalise for the illuminant */ - x /= s->x_n; - y /= s->y_n; - z /= s->z_n; + x *= s->x_rn; + y *= s->y_rn; + z *= s->z_rn; /* XYZ to Lab */ xx = (x <= 0.008856f) ? (7.787f*x + 0.1379f) : cbrtf(x); @@ -496,695 +587,149 @@ SPAN_DECLARE(void) lab_to_srgb(lab_params_t *s, uint8_t srgb[], const uint8_t la } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) t42_itulab_to_jpeg(logging_state_t *logging, lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen) +static int is_itu_fax(t42_decode_state_t *s, jpeg_saved_marker_ptr ptr) { - struct jpeg_decompress_struct decompressor; - struct jpeg_compress_struct compressor; - FILE *in; - FILE *out; - int m; - JSAMPROW scan_line_in; - JSAMPROW scan_line_out; - escape_route_t escape; -#if defined(HAVE_OPEN_MEMSTREAM) - char *outptr; - size_t outsize; -#endif + const uint8_t *data; + int ok; + int val[6]; - escape.error_message[0] = '\0'; - -#if defined(HAVE_OPEN_MEMSTREAM) - if ((in = fmemopen(src, srclen, "r")) == NULL) + ok = false; + for ( ; ptr; ptr = ptr->next) { - span_log(logging, SPAN_LOG_FLOW, "Failed to fmemopen().\n"); - return FALSE; - } - outsize = 0; - if ((out = open_memstream(&outptr, &outsize)) == NULL) - { - span_log(logging, SPAN_LOG_FLOW, "Failed to open_memstream().\n"); - fclose(in); - return FALSE; - } - if (fseek(out, 0, SEEK_SET) != 0) - { - fclose(in); - fclose(out); - return FALSE; - } -#else - if ((in = tmpfile()) == NULL) - { - span_log(logging, SPAN_LOG_FLOW, "Failed to tmpfile().\n"); - return FALSE; - } - if (fwrite(src, 1, srclen, in) != srclen) - { - fclose(in); - return FALSE; - } - if (fseek(in, 0, SEEK_SET) != 0) - { - fclose(in); - return FALSE; - } - if ((out = tmpfile()) == NULL) - { - span_log(logging, SPAN_LOG_FLOW, "Failed to tmpfile().\n"); - fclose(in); - return FALSE; - } -#endif - scan_line_out = NULL; - - if (setjmp(escape.escape)) - { - if (escape.error_message[0]) - span_log(logging, SPAN_LOG_FLOW, "%s\n", escape.error_message); - else - span_log(logging, SPAN_LOG_FLOW, "Unspecified libjpeg error.\n"); - if (scan_line_out) - free(scan_line_out); - fclose(in); - fclose(out); - return FALSE; + if (ptr->marker != (JPEG_APP0 + 1)) + continue; + if (ptr->data_length < 6) + return false; + /* Markers are: + JPEG_RST0 + JPEG_EOI + JPEG_APP0 + JPEG_COM */ + data = (const uint8_t *) ptr->data; + if (strncmp((const char *) data, "G3FAX", 5)) + return false; + switch (data[5]) + { + case 0: + if (ptr->data_length < 6 + 4) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Got bad G3FAX0 length - %d\n", ptr->data_length); + return false; + } + val[0] = pack_16(&data[6]); + s->spatial_resolution = pack_16(&data[6 + 2]); + span_log(&s->logging, SPAN_LOG_FLOW, "Version %d, resolution %ddpi\n", val[0], s->spatial_resolution); + ok = true; + break; + case 1: + span_log(&s->logging, SPAN_LOG_FLOW, "Set gamut\n"); + if (ptr->data_length < 6 + 12) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Got bad G3FAX1 length - %d\n", ptr->data_length); + return false; + } + set_gamut_from_code(&s->logging, &s->lab, &data[6]); + break; + case 2: + span_log(&s->logging, SPAN_LOG_FLOW, "Set illuminant\n"); + if (ptr->data_length < 6 + 4) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Got bad G3FAX2 length - %d\n", ptr->data_length); + return false; + } + s->illuminant_colour_temperature = set_illuminant_from_code(&s->logging, &s->lab, &data[6]); + break; + default: + span_log(&s->logging, SPAN_LOG_FLOW, "Got unexpected G3FAX%d length - %d\n", data[5], ptr->data_length); + return false; + } } - /* Create input decompressor. */ - decompressor.err = jpeg_std_error(&error_handler); - decompressor.client_data = (void *) &escape; - error_handler.error_exit = jpg_error_exit; - error_handler.output_message = jpg_error_exit; - - jpeg_create_decompress(&decompressor); - jpeg_stdio_src(&decompressor, in); - - /* Needed in the case of ITU Lab input */ - for (m = 0; m < 16; m++) - jpeg_save_markers(&decompressor, JPEG_APP0 + m, 0xFFFF); - - /* Rewind the file */ - if (fseek(in, 0, SEEK_SET) != 0) - return FALSE; - - /* Take the header */ - jpeg_read_header(&decompressor, TRUE); - - /* Now we can force the input colour space. For ITULab, we use YCbCr as a "don't touch" marker */ - decompressor.out_color_space = JCS_YCbCr; - - /* Sanity check and parameter check */ - if (!is_itu_fax(logging, s, decompressor.marker_list)) - { - span_log(logging, SPAN_LOG_FLOW, "Is not an ITU FAX.\n"); - return FALSE; - } - - /* Create compressor */ - compressor.err = jpeg_std_error(&error_handler); - compressor.client_data = (void *) &escape; - error_handler.error_exit = jpg_error_exit; - error_handler.output_message = jpg_error_exit; - - jpeg_create_compress(&compressor); - jpeg_stdio_dest(&compressor, out); - - /* Force the destination colour space */ - compressor.in_color_space = JCS_RGB; - compressor.input_components = 3; - - jpeg_set_defaults(&compressor); - /* Limit to baseline-JPEG values */ - //jpeg_set_quality(&compressor, quality, TRUE); - - /* Copy size, resolution, etc */ - jpeg_copy_critical_parameters(&decompressor, &compressor); - - /* We need to keep these */ - compressor.density_unit = decompressor.density_unit; - compressor.X_density = decompressor.X_density; - compressor.Y_density = decompressor.Y_density; - - jpeg_start_decompress(&decompressor); - jpeg_start_compress(&compressor, TRUE); - - if ((scan_line_in = (JSAMPROW) malloc(decompressor.output_width*decompressor.num_components)) == NULL) - return FALSE; - - if ((scan_line_out = (JSAMPROW) malloc(compressor.image_width*compressor.num_components)) == NULL) - { - free(scan_line_in); - return FALSE; - } - - while (decompressor.output_scanline < decompressor.output_height) - { - jpeg_read_scanlines(&decompressor, &scan_line_in, 1); - lab_to_srgb(s, scan_line_out, scan_line_in, decompressor.output_width); - jpeg_write_scanlines(&compressor, &scan_line_out, 1); - } - free(scan_line_in); - free(scan_line_out); - jpeg_finish_decompress(&decompressor); - jpeg_finish_compress(&compressor); - jpeg_destroy_decompress(&decompressor); - jpeg_destroy_compress(&compressor); - fclose(in); - -#if defined(HAVE_OPEN_MEMSTREAM) - fclose(out); - *dst = outptr; - *dstlen = outsize; -#else - *dstlen = ftell(out); - *dst = malloc(*dstlen); - if (fseek(out, 0, SEEK_SET) != 0) - { - fclose(out); - return FALSE; - } - if (fread(*dst, 1, *dstlen, out) != *dstlen) - { - free(*dst); - fclose(out); - return FALSE; - } - fclose(out); -#endif - - return TRUE; + return ok; } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) t42_jpeg_to_itulab(logging_state_t *logging, lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen) +static void set_itu_fax(t42_encode_state_t *s) { - struct jpeg_decompress_struct decompressor; - struct jpeg_compress_struct compressor; - FILE *in; - FILE *out; - int m; - JSAMPROW scan_line_in; - JSAMPROW scan_line_out; - escape_route_t escape; -#if defined(HAVE_OPEN_MEMSTREAM) - char *outptr; - size_t outsize; -#endif + uint8_t data[50]; + int val[6]; - escape.error_message[0] = '\0'; + memcpy(data, "G3FAX\0", 6); + unpack_16(&data[6 + 0], 1994); + unpack_16(&data[6 + 2], s->spatial_resolution); + jpeg_write_marker(&s->compressor, (JPEG_APP0 + 1), data, 6 + 4); -#if defined(HAVE_OPEN_MEMSTREAM) - if ((in = fmemopen(src, srclen, "r")) == NULL) + 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(logging, SPAN_LOG_FLOW, "Failed to fmemopen().\n"); - return FALSE; + span_log(&s->logging, SPAN_LOG_FLOW, "Putting G3FAX1\n"); + memcpy(data, "G3FAX\1", 6); + get_lab_gamut2(&s->lab, &val[0], &val[1], &val[2], &val[3], &val[4], &val[5]); + unpack_16(&data[6 + 0], val[0]); + unpack_16(&data[6 + 2], val[1]); + unpack_16(&data[6 + 4], val[2]); + unpack_16(&data[6 + 6], val[3]); + unpack_16(&data[6 + 8], val[4]); + unpack_16(&data[6 + 10], val[5]); + jpeg_write_marker(&s->compressor, (JPEG_APP0 + 1), data, 6 + 12); } - outsize = 0; - if ((out = open_memstream(&outptr, &outsize)) == NULL) - { - span_log(logging, SPAN_LOG_FLOW, "Failed to open_memstream().\n"); - fclose(in); - return FALSE; - } - if (fseek(out, 0, SEEK_SET) != 0) - { - fclose(in); - fclose(out); - return FALSE; - } -#else - if ((in = tmpfile()) == NULL) - { - span_log(logging, SPAN_LOG_FLOW, "Failed to tmpfile().\n"); - return FALSE; - } - if (fwrite(src, 1, srclen, in) != srclen) - { - fclose(in); - return FALSE; - } - if (fseek(in, 0, SEEK_SET) != 0) - { - fclose(in); - return FALSE; - } - if ((out = tmpfile()) == NULL) - { - span_log(logging, SPAN_LOG_FLOW, "Failed to tmpfile().\n"); - fclose(in); - return FALSE; - } -#endif - scan_line_out = NULL; - if (setjmp(escape.escape)) + if (memcmp(s->illuminant_code, "\0\0\0\0", 4) != 0 + || + s->illuminant_colour_temperature > 0) { - if (escape.error_message[0]) - span_log(logging, SPAN_LOG_FLOW, "%s\n", escape.error_message); + span_log(&s->logging, SPAN_LOG_FLOW, "Putting G3FAX2\n"); + memcpy(data, "G3FAX\2", 6); + if (memcmp(s->illuminant_code, "\0\0\0\0", 4) != 0) + { + memcpy(&data[6], s->illuminant_code, 4); + } else - span_log(logging, SPAN_LOG_FLOW, "Unspecified libjpeg error.\n"); - if (scan_line_out) - free(scan_line_out); - fclose(in); - fclose(out); - return FALSE; + { + memcpy(&data[6 + 0], "CT", 2); + unpack_16(&data[6 + 2], s->illuminant_colour_temperature); + } + jpeg_write_marker(&s->compressor, (JPEG_APP0 + 1), data, 6 + 4); } - /* Create input decompressor. */ - decompressor.err = jpeg_std_error(&error_handler); - decompressor.client_data = (void *) &escape; - error_handler.error_exit = jpg_error_exit; - error_handler.output_message = jpg_error_exit; - - jpeg_create_decompress(&decompressor); - jpeg_stdio_src(&decompressor, in); - - /* Needed in the case of ITU Lab input */ - for (m = 0; m < 16; m++) - jpeg_save_markers(&decompressor, JPEG_APP0 + m, 0xFFFF); - - /* Rewind the file */ - if (fseek(in, 0, SEEK_SET) != 0) - return FALSE; - - /* Take the header */ - jpeg_read_header(&decompressor, TRUE); - - /* Now we can force the input colour space. For ITULab, we use YCbCr as a "don't touch" marker */ - decompressor.out_color_space = JCS_RGB; - - compressor.err = jpeg_std_error(&error_handler); - compressor.client_data = (void *) &escape; - error_handler.error_exit = jpg_error_exit; - error_handler.output_message = jpg_error_exit; - - jpeg_create_compress(&compressor); - jpeg_stdio_dest(&compressor, out); - - /* Force the destination colour space */ - compressor.in_color_space = JCS_YCbCr; - compressor.input_components = 3; - - jpeg_set_defaults(&compressor); - /* Limit to baseline-JPEG values */ - //jpeg_set_quality(&compressor, quality, TRUE); - - jpeg_copy_critical_parameters(&decompressor, &compressor); - - /* We need to keep these */ - compressor.density_unit = decompressor.density_unit; - compressor.X_density = decompressor.X_density; - compressor.Y_density = decompressor.Y_density; - - jpeg_start_decompress(&decompressor); - jpeg_start_compress(&compressor, TRUE); - - set_itu_fax(&compressor); - - if ((scan_line_in = (JSAMPROW) malloc(decompressor.output_width*decompressor.num_components)) == NULL) - return FALSE; - - if ((scan_line_out = (JSAMPROW) malloc(compressor.image_width*compressor.num_components)) == NULL) - { - free(scan_line_in); - return FALSE; - } - - while (decompressor.output_scanline < decompressor.output_height) - { - jpeg_read_scanlines(&decompressor, &scan_line_in, 1); - srgb_to_lab(s, scan_line_out, scan_line_in, decompressor.output_width); - jpeg_write_scanlines(&compressor, &scan_line_out, 1); - } - - free(scan_line_in); - free(scan_line_out); - jpeg_finish_decompress(&decompressor); - jpeg_finish_compress(&compressor); - jpeg_destroy_decompress(&decompressor); - jpeg_destroy_compress(&compressor); - fclose(in); - -#if defined(HAVE_OPEN_MEMSTREAM) - fclose(out); - *dst = outptr; - *dstlen = outsize; -#else - *dstlen = ftell(out); - *dst = malloc(*dstlen); - if (fseek(out, 0, SEEK_SET) != 0) - { - fclose(out); - return FALSE; - } - if (fread(*dst, 1, *dstlen, out) != *dstlen) - { - free(*dst); - fclose(out); - return FALSE; - } - fclose(out); -#endif - - return TRUE; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t42_srgb_to_itulab(logging_state_t *logging, lab_params_t *s, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t width, uint32_t height) -{ - struct jpeg_compress_struct compressor; - FILE *out; - JSAMPROW scan_line_out; - JSAMPROW scan_line_in; - tsize_t pos; - escape_route_t escape; -#if defined(HAVE_OPEN_MEMSTREAM) - char *outptr; - size_t outsize; -#endif - - escape.error_message[0] = '\0'; - -#if defined(HAVE_OPEN_MEMSTREAM) - outsize = 0; - if ((out = open_memstream(&outptr, &outsize)) == NULL) - { - span_log(logging, SPAN_LOG_FLOW, "Failed to open_memstream().\n"); - return FALSE; - } - if (fseek(out, 0, SEEK_SET) != 0) - { - fclose(out); - return FALSE; - } -#else - if ((out = tmpfile()) == NULL) - { - span_log(logging, SPAN_LOG_FLOW, "Failed to tmpfile().\n"); - return FALSE; - } -#endif - scan_line_out = NULL; - - if (setjmp(escape.escape)) - { - if (escape.error_message[0]) - span_log(logging, SPAN_LOG_FLOW, "%s\n", escape.error_message); - else - span_log(logging, SPAN_LOG_FLOW, "Unspecified libjpeg error.\n"); - if (scan_line_out) - free(scan_line_out); - fclose(out); - return FALSE; - } - - compressor.err = jpeg_std_error(&error_handler); - compressor.client_data = (void *) &escape; - error_handler.error_exit = jpg_error_exit; - error_handler.output_message = jpg_error_exit; - - jpeg_create_compress(&compressor); - jpeg_stdio_dest(&compressor, out); - - /* Force the destination colour space */ - compressor.in_color_space = JCS_YCbCr; - compressor.input_components = 3; - - jpeg_set_defaults(&compressor); - /* Limit to baseline-JPEG values */ - //jpeg_set_quality(&compressor, quality, TRUE); - - /* Size, resolution, etc */ - compressor.image_width = width; - compressor.image_height = height; - - jpeg_start_compress(&compressor, TRUE); - - set_itu_fax(&compressor); - - if ((scan_line_out = (JSAMPROW) malloc(compressor.image_width*compressor.num_components)) == NULL) - return FALSE; - - for (pos = 0; pos < srclen; pos += compressor.image_width*compressor.num_components) - { - scan_line_in = (JSAMPROW) src + pos; - srgb_to_lab(s, scan_line_out, scan_line_in, compressor.image_width); - jpeg_write_scanlines(&compressor, &scan_line_out, 1); - } - - free(scan_line_out); - jpeg_finish_compress(&compressor); - jpeg_destroy_compress(&compressor); - -#if defined(HAVE_OPEN_MEMSTREAM) - fclose(out); - *dst = outptr; - *dstlen = outsize; -#else - *dstlen = ftell(out); - *dst = malloc(*dstlen); - if (fseek(out, 0, SEEK_SET) != 0) - { - fclose(out); - return FALSE; - } - if (fread(*dst, 1, *dstlen, out) != *dstlen) - { - free(*dst); - fclose(out); - return FALSE; - } - fclose(out); -#endif - - return TRUE; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t42_itulab_to_itulab(logging_state_t *logging, tdata_t *dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t width, uint32_t height) -{ - struct jpeg_compress_struct compressor; - FILE *out; - JSAMPROW scan_line_in; - tsize_t pos; - escape_route_t escape; -#if defined(HAVE_OPEN_MEMSTREAM) - char *outptr; - size_t outsize; -#endif - - escape.error_message[0] = '\0'; - -#if defined(HAVE_OPEN_MEMSTREAM) - outsize = 0; - if ((out = open_memstream(&outptr, &outsize)) == NULL) - { - span_log(logging, SPAN_LOG_FLOW, "Failed to open_memstream().\n"); - return FALSE; - } - if (fseek(out, 0, SEEK_SET) != 0) - { - fclose(out); - return FALSE; - } -#else - if ((out = tmpfile()) == NULL) - { - span_log(logging, SPAN_LOG_FLOW, "Failed to tmpfile().\n"); - return FALSE; - } -#endif - - if (setjmp(escape.escape)) - { - if (escape.error_message[0]) - span_log(logging, SPAN_LOG_FLOW, "%s\n", escape.error_message); - else - span_log(logging, SPAN_LOG_FLOW, "Unspecified libjpeg error.\n"); - fclose(out); - return FALSE; - } - - compressor.err = jpeg_std_error(&error_handler); - compressor.client_data = (void *) &escape; - error_handler.error_exit = jpg_error_exit; - error_handler.output_message = jpg_error_exit; - - jpeg_create_compress(&compressor); - jpeg_stdio_dest(&compressor, out); - - /* Force the destination colour space */ - compressor.in_color_space = JCS_YCbCr; - compressor.input_components = 3; - - jpeg_set_defaults(&compressor); - /* Limit to baseline-JPEG values */ - //jpeg_set_quality(&compressor, quality, TRUE); - - /* Size, resolution, etc */ - compressor.image_width = width; - compressor.image_height = height; - - jpeg_start_compress(&compressor, TRUE); - - set_itu_fax(&compressor); - - for (pos = 0; pos < srclen; pos += compressor.image_width*compressor.num_components) - { - scan_line_in = (JSAMPROW) src + pos; - jpeg_write_scanlines(&compressor, &scan_line_in, 1); - } - - jpeg_finish_compress(&compressor); - jpeg_destroy_compress(&compressor); - -#if defined(HAVE_OPEN_MEMSTREAM) - fclose(out); - *dst = outptr; - *dstlen = outsize; -#else - *dstlen = ftell(out); - *dst = malloc(*dstlen); - if (fseek(out, 0, SEEK_SET) != 0) - { - fclose(out); - return FALSE; - } - if (fread(*dst, 1, *dstlen, out) != *dstlen) - { - free(*dst); - fclose(out); - return FALSE; - } - fclose(out); -#endif - - return TRUE; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t42_itulab_to_srgb(logging_state_t *logging, lab_params_t *s, tdata_t dst, tsize_t *dstlen, tdata_t src, tsize_t srclen, uint32_t *width, uint32_t *height) -{ - struct jpeg_decompress_struct decompressor; - JSAMPROW scan_line_out; - JSAMPROW scan_line_in; - tsize_t pos; - FILE *in; - int m; - escape_route_t escape; - - escape.error_message[0] = '\0'; - -#if defined(HAVE_OPEN_MEMSTREAM) - if ((in = fmemopen(src, srclen, "r")) == NULL) - { - span_log(logging, SPAN_LOG_FLOW, "Failed to fmemopen().\n"); - return FALSE; - } -#else - if ((in = tmpfile()) == NULL) - { - span_log(logging, SPAN_LOG_FLOW, "Failed to tmpfile().\n"); - return FALSE; - } - if (fwrite(src, 1, srclen, in) != srclen) - { - fclose(in); - return FALSE; - } - if (fseek(in, 0, SEEK_SET) != 0) - { - fclose(in); - return FALSE; - } -#endif - scan_line_out = NULL; - - if (setjmp(escape.escape)) - { - if (escape.error_message[0]) - span_log(logging, SPAN_LOG_FLOW, "%s\n", escape.error_message); - else - span_log(logging, SPAN_LOG_FLOW, "Unspecified libjpeg error.\n"); -printf("Error %s.\n", escape.error_message); - if (scan_line_out) - free(scan_line_out); - fclose(in); - return FALSE; - } - /* Create input decompressor. */ - decompressor.err = jpeg_std_error(&error_handler); - decompressor.client_data = (void *) &escape; - error_handler.error_exit = jpg_error_exit; - error_handler.output_message = jpg_error_exit; - - jpeg_create_decompress(&decompressor); - jpeg_stdio_src(&decompressor, in); - - /* Needed in the case of ITU Lab input */ - for (m = 0; m < 16; m++) - jpeg_save_markers(&decompressor, JPEG_APP0 + m, 0xFFFF); - - /* Rewind the file */ - if (fseek(in, 0, SEEK_SET) != 0) - return FALSE; - /* Take the header */ - jpeg_read_header(&decompressor, FALSE); - /* Now we can force the input colour space. For ITULab, we use YCbCr as a "don't touch" marker */ - decompressor.out_color_space = JCS_YCbCr; - /* Sanity check and parameter check */ - if (!is_itu_fax(logging, s, decompressor.marker_list)) - { - span_log(logging, SPAN_LOG_FLOW, "Is not an ITU FAX.\n"); -printf("Is not an ITU FAX 1.\n"); - //return FALSE; - } - /* Copy size, resolution, etc */ - *width = decompressor.image_width; - *height = decompressor.image_height; -printf("Is %d x %d\n", decompressor.image_width, decompressor.image_height); - - jpeg_start_decompress(&decompressor); - -printf("Is %d x %d x %d.\n", decompressor.output_width, decompressor.output_height, decompressor.num_components); - if ((scan_line_in = (JSAMPROW) malloc(decompressor.output_width*decompressor.num_components)) == NULL) - return FALSE; - - for (pos = 0; decompressor.output_scanline < decompressor.output_height; pos += decompressor.output_width*decompressor.num_components) - { - scan_line_out = (JSAMPROW) dst + pos; - jpeg_read_scanlines(&decompressor, &scan_line_in, 1); - lab_to_srgb(s, scan_line_out, scan_line_in, decompressor.output_width); - } -printf("Next %d\n", decompressor.output_scanline); - - free(scan_line_in); - jpeg_finish_decompress(&decompressor); - jpeg_destroy_decompress(&decompressor); - fclose(in); - - *dstlen = pos; - -printf("Next2 %d\n", decompressor.output_scanline); - return TRUE; } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(void) t42_encode_set_options(t42_encode_state_t *s, uint32_t l0, - int mx, + int quality, int options) { + s->quality = quality; + s->no_subsampling = (options & 1); } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(int) t42_encode_set_image_width(t42_encode_state_t *s, uint32_t image_width) { + s->image_width = image_width; return 0; } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) t42_encode_set_image_length(t42_encode_state_t *s, uint32_t length) +SPAN_DECLARE(int) t42_encode_set_image_length(t42_encode_state_t *s, uint32_t image_length) { + s->image_length = image_length; + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t42_encode_set_image_type(t42_encode_state_t *s, int image_type) +{ + s->image_type = image_type; return 0; } /*- End of function --------------------------------------------------------*/ @@ -1201,25 +746,207 @@ SPAN_DECLARE(void) t42_encode_comment(t42_encode_state_t *s, const uint8_t comme SPAN_DECLARE(int) t42_encode_image_complete(t42_encode_state_t *s) { + //if (????) + // return SIG_STATUS_END_OF_DATA; + return 0; +} +/*- End of function --------------------------------------------------------*/ + +/* Error handler for IJG library */ +static void jpg_encode_error_exit(j_common_ptr cinfo) +{ + t42_encode_state_t *s; + + s = (t42_encode_state_t *) cinfo->client_data; + (*cinfo->err->format_message)(cinfo, s->error_message); + longjmp(s->escape, 1); +} +/*- End of function --------------------------------------------------------*/ + +/* This is the error catcher */ +static struct jpeg_error_mgr encode_error_handler = +{ +#if defined(_MSC_VER) || defined(__sunos) || defined(__solaris) || defined(__sun) + jpg_encode_error_exit, + 0, + jpg_encode_error_exit +#else + .error_exit = jpg_encode_error_exit, + .output_message = jpg_encode_error_exit +#endif +}; + +static int t42_srgb_to_itulab_jpeg(t42_encode_state_t *s) +{ + int i; + + if (setjmp(s->escape)) + { + if (s->error_message[0]) + span_log(&s->logging, SPAN_LOG_FLOW, "%s\n", s->error_message); + else + span_log(&s->logging, SPAN_LOG_FLOW, "Unspecified libjpeg error.\n"); + if (s->scan_line_out) + { + span_free(s->scan_line_out); + s->scan_line_out = NULL; + } + if (s->out) + { + fclose(s->out); + s->out = NULL; + } + return -1; + } + + s->compressor.err = jpeg_std_error(&encode_error_handler); + s->compressor.client_data = (void *) s; + + jpeg_create_compress(&s->compressor); + jpeg_stdio_dest(&s->compressor, s->out); + + /* Force the destination colour space */ + if (s->image_type == T4_IMAGE_TYPE_COLOUR_8BIT) + { + s->samples_per_pixel = 3; + s->compressor.in_color_space = JCS_YCbCr; + s->compressor.input_components = s->samples_per_pixel; + } + else + { + s->samples_per_pixel = 1; + s->compressor.in_color_space = JCS_GRAYSCALE; + s->compressor.input_components = s->samples_per_pixel; + } + + jpeg_set_defaults(&s->compressor); + /* Limit to baseline-JPEG values */ + //jpeg_set_quality(&s->compressor, s->quality, true); + + if (s->no_subsampling) + { + /* Set 1:1:1 */ + s->compressor.comp_info[0].h_samp_factor = 1; + s->compressor.comp_info[0].v_samp_factor = 1; + } + else + { + /* Set 4:1:1 */ + s->compressor.comp_info[0].h_samp_factor = 2; + s->compressor.comp_info[0].v_samp_factor = 2; + } + s->compressor.comp_info[1].h_samp_factor = 1; + s->compressor.comp_info[1].v_samp_factor = 1; + s->compressor.comp_info[2].h_samp_factor = 1; + s->compressor.comp_info[2].v_samp_factor = 1; + + /* Size, resolution, etc */ + s->compressor.image_width = s->image_width; + s->compressor.image_height = s->image_length; + + jpeg_start_compress(&s->compressor, true); + + set_itu_fax(s); + + if ((s->scan_line_in = (JSAMPROW) span_alloc(s->samples_per_pixel*s->image_width)) == NULL) + return -1; + + if (s->image_type == T4_IMAGE_TYPE_COLOUR_8BIT) + { + if ((s->scan_line_out = (JSAMPROW) span_alloc(s->samples_per_pixel*s->image_width)) == NULL) + return -1; + + for (i = 0; i < s->compressor.image_height; i++) + { + s->row_read_handler(s->row_read_user_data, s->scan_line_in, s->samples_per_pixel*s->image_width); + srgb_to_lab(&s->lab, s->scan_line_out, s->scan_line_in, s->image_width); + jpeg_write_scanlines(&s->compressor, &s->scan_line_out, 1); + } + } + else + { + for (i = 0; i < s->compressor.image_height; i++) + { + s->row_read_handler(s->row_read_user_data, s->scan_line_in, s->image_width); + jpeg_write_scanlines(&s->compressor, &s->scan_line_in, 1); + } + } + + if (s->scan_line_out) + { + span_free(s->scan_line_out); + s->scan_line_out = NULL; + } + jpeg_finish_compress(&s->compressor); + jpeg_destroy_compress(&s->compressor); + +#if defined(HAVE_OPEN_MEMSTREAM) + fclose(s->out); + s->buf_size = + s->compressed_image_size = s->outsize; +#else + s->buf_size = + s->compressed_image_size = ftell(s->out); + if ((s->compressed_buf = span_alloc(s->compressed_image_size)) == NULL) + return -1; + if (fseek(s->out, 0, SEEK_SET) != 0) + { + fclose(s->out); + s->out = NULL; + span_free(s->compressed_buf); + s->compressed_buf = NULL; + return -1; + } + if (fread(s->compressed_buf, 1, s->compressed_image_size, s->out) != s->compressed_image_size) + { + fclose(s->out); + s->out = NULL; + span_free(s->compressed_buf); + s->compressed_buf = NULL; + return -1; + } + if (s->out) + { + fclose(s->out); + s->out = NULL; + } +#endif + return 0; } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(int) t42_encode_get(t42_encode_state_t *s, uint8_t buf[], size_t max_len) { - return 0; + int len; + + if (s->compressed_image_size == 0) + { + if (t42_srgb_to_itulab_jpeg(s)) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Failed to convert to ITULAB.\n"); + return -1; + } + } + if (s->compressed_image_size >= s->compressed_image_ptr + max_len) + len = max_len; + else + len = s->compressed_image_size - s->compressed_image_ptr; + memcpy(buf, &s->compressed_buf[s->compressed_image_ptr], len); + s->compressed_image_ptr += len; + return len; } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(uint32_t) t42_encode_get_image_width(t42_encode_state_t *s) { - return 0; + return s->image_width; } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(uint32_t) t42_encode_get_image_length(t42_encode_state_t *s) { - return 0; + return s->image_length; } /*- End of function --------------------------------------------------------*/ @@ -1233,6 +960,8 @@ SPAN_DECLARE(int) t42_encode_set_row_read_handler(t42_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 --------------------------------------------------------*/ @@ -1245,9 +974,48 @@ SPAN_DECLARE(logging_state_t *) t42_encode_get_logging_state(t42_encode_state_t SPAN_DECLARE(int) t42_encode_restart(t42_encode_state_t *s, uint32_t image_width, uint32_t image_length) { - //s->image_width = image_width; - //s->image_length = image_length; + s->image_width = image_width; + s->image_length = image_length; + + if (s->itu_ycc) + { + /* ITU-YCC */ + /* Illuminant D65 */ + //set_lab_illuminant(&s->lab, 95.047f, 100.000f, 108.883f); + set_lab_illuminant(&s->lab, 100.0f, 100.0f, 100.0f); + set_lab_gamut(&s->lab, 0, 100, -127, 127, -127, 127, false); + } + else + { + /* ITULAB */ + /* Illuminant D50 */ + //set_lab_illuminant(&s->lab, 96.422f, 100.000f, 82.521f); + set_lab_illuminant(&s->lab, 100.0f, 100.0f, 100.0f); + set_lab_gamut(&s->lab, 0, 100, -85, 85, -75, 125, false); + } s->compressed_image_size = 0; + s->compressed_image_ptr = 0; + + s->spatial_resolution = 200; + + s->error_message[0] = '\0'; + +#if defined(HAVE_OPEN_MEMSTREAM) + s->outsize = 0; + if ((s->out = open_memstream((char **) &s->compressed_buf, &s->outsize)) == NULL) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Failed to open_memstream().\n"); + return -1; + } +#else + if ((s->out = tmpfile()) == NULL) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Failed to tmpfile().\n"); + return -1; + } +#endif + s->scan_line_out = NULL; + return 0; } /*- End of function --------------------------------------------------------*/ @@ -1260,15 +1028,19 @@ SPAN_DECLARE(t42_encode_state_t *) t42_encode_init(t42_encode_state_t *s, { if (s == NULL) { - if ((s = (t42_encode_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (t42_encode_state_t *) span_alloc(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.42"); + s->quality = 90; + s->image_type = T4_IMAGE_TYPE_COLOUR_8BIT; + s->row_read_handler = handler; s->row_read_user_data = user_data; + t42_encode_restart(s, image_width, image_length); return s; @@ -1286,13 +1058,205 @@ SPAN_DECLARE(int) t42_encode_free(t42_encode_state_t *s) int ret; ret = t42_encode_release(s); - free(s); + span_free(s); return ret; } /*- End of function --------------------------------------------------------*/ +/* Error handler for IJG library */ +static void jpg_decode_error_exit(j_common_ptr cinfo) +{ + t42_decode_state_t *s; + + s = (t42_decode_state_t *) cinfo->client_data; + (*cinfo->err->format_message)(cinfo, s->error_message); + longjmp(s->escape, 1); +} +/*- End of function --------------------------------------------------------*/ + +/* This is the error catcher */ +static struct jpeg_error_mgr decode_error_handler = +{ +#if defined(_MSC_VER) || defined(__sunos) || defined(__solaris) || defined(__sun) + jpg_decode_error_exit, + 0, + jpg_decode_error_exit +#else + .error_exit = jpg_decode_error_exit, + .output_message = jpg_decode_error_exit +#endif +}; + +static int t42_itulab_jpeg_to_srgb(t42_decode_state_t *s) +{ + int i; + + if (s->compressed_buf == NULL) + return -1; + +#if defined(HAVE_OPEN_MEMSTREAM) + if ((s->in = fmemopen(s->compressed_buf, s->compressed_image_size, "r")) == NULL) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Failed to fmemopen().\n"); + return -1; + } +#else + if ((s->in = tmpfile()) == NULL) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Failed to tmpfile().\n"); + return -1; + } + if (fwrite(s->compressed_buf, 1, s->compressed_image_size, s->in) != s->compressed_image_size) + { + fclose(s->in); + s->in = NULL; + return -1; + } + if (fseek(s->in, 0, SEEK_SET) != 0) + { + fclose(s->in); + s->in = NULL; + return -1; + } +#endif + s->scan_line_out = NULL; + + if (setjmp(s->escape)) + { + if (s->error_message[0]) + span_log(&s->logging, SPAN_LOG_FLOW, "%s\n", s->error_message); + else + span_log(&s->logging, SPAN_LOG_FLOW, "Unspecified libjpeg error.\n"); + if (s->scan_line_out) + { + span_free(s->scan_line_out); + s->scan_line_out = NULL; + } + if (s->in) + { + fclose(s->in); + s->in = NULL; + } + return -1; + } + /* Create input decompressor. */ + s->decompressor.err = jpeg_std_error(&decode_error_handler); + s->decompressor.client_data = (void *) s; + + jpeg_create_decompress(&s->decompressor); + jpeg_stdio_src(&s->decompressor, s->in); + + /* Get the FAX tags */ + for (i = 0; i < 16; i++) + jpeg_save_markers(&s->decompressor, JPEG_APP0 + i, 0xFFFF); + + /* Take the header */ + jpeg_read_header(&s->decompressor, false); + /* Sanity check and parameter check */ + if (!is_itu_fax(s, s->decompressor.marker_list)) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Is not an ITU FAX.\n"); + return -1; + } + /* Copy size, resolution, etc */ + s->image_width = s->decompressor.image_width; + s->image_length = s->decompressor.image_height; + s->samples_per_pixel = s->decompressor.num_components; + + if (s->samples_per_pixel == 3) + { + /* Now we can force the input colour space. For ITULab, we use YCbCr as a "don't touch" marker */ + s->decompressor.out_color_space = JCS_YCbCr; + span_log(&s->logging, + SPAN_LOG_FLOW, + "Sampling %d %d %d %d %d %d\n", + s->decompressor.comp_info[0].h_samp_factor, + s->decompressor.comp_info[0].v_samp_factor, + s->decompressor.comp_info[1].h_samp_factor, + s->decompressor.comp_info[1].v_samp_factor, + s->decompressor.comp_info[2].h_samp_factor, + s->decompressor.comp_info[2].v_samp_factor); + } + else + { + s->decompressor.out_color_space = JCS_GRAYSCALE; + span_log(&s->logging, + SPAN_LOG_FLOW, + "Sampling %d %d\n", + s->decompressor.comp_info[0].h_samp_factor, + s->decompressor.comp_info[0].v_samp_factor); + } + + jpeg_start_decompress(&s->decompressor); + + if ((s->scan_line_in = span_alloc(s->samples_per_pixel*s->image_width)) == NULL) + return -1; + + if (s->samples_per_pixel == 3) + { + if ((s->scan_line_out = span_alloc(s->samples_per_pixel*s->image_width)) == NULL) + return -1; + + while (s->decompressor.output_scanline < s->image_length) + { + jpeg_read_scanlines(&s->decompressor, &s->scan_line_in, 1); + lab_to_srgb(&s->lab, s->scan_line_out, s->scan_line_in, s->image_width); + s->row_write_handler(s->row_write_user_data, s->scan_line_out, s->samples_per_pixel*s->image_width); + } + } + else + { + while (s->decompressor.output_scanline < s->image_length) + { + jpeg_read_scanlines(&s->decompressor, &s->scan_line_in, 1); + s->row_write_handler(s->row_write_user_data, s->scan_line_in, s->image_width); + } + } + + if (s->scan_line_in) + { + span_free(s->scan_line_in); + s->scan_line_in = NULL; + } + if (s->scan_line_out) + { + span_free(s->scan_line_out); + s->scan_line_out = NULL; + } + jpeg_finish_decompress(&s->decompressor); + jpeg_destroy_decompress(&s->decompressor); + fclose(s->in); + s->in = NULL; + + return 0; +} +/*- End of function --------------------------------------------------------*/ + SPAN_DECLARE(void) t42_decode_rx_status(t42_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 */ + if (!s->end_of_data) + { + if (t42_itulab_jpeg_to_srgb(s)) + span_log(&s->logging, SPAN_LOG_FLOW, "Failed to convert from ITULAB.\n"); + s->end_of_data = true; + } + break; + default: + span_log(&s->logging, SPAN_LOG_WARNING, "Unexpected rx status - %d!\n", status); + break; + } } /*- End of function --------------------------------------------------------*/ @@ -1300,11 +1264,22 @@ SPAN_DECLARE(int) t42_decode_put(t42_decode_state_t *s, const uint8_t data[], si { uint8_t *buf; + if (len == 0) + { + if (!s->end_of_data) + { + if (t42_itulab_jpeg_to_srgb(s)) + span_log(&s->logging, SPAN_LOG_FLOW, "Failed to convert from ITULAB.\n"); + s->end_of_data = true; + } + return T4_DECODE_OK; + } + if (s->compressed_image_size + len > s->buf_size) { - if ((buf = (uint8_t *) realloc(s->compressed_buf, s->compressed_image_size + 1000)) == NULL) + if ((buf = (uint8_t *) span_realloc(s->compressed_buf, s->compressed_image_size + len + 10000)) == NULL) return -1; - s->buf_size = s->compressed_image_size + 1000; + s->buf_size = s->compressed_image_size + len + 10000; s->compressed_buf = buf; } memcpy(&s->compressed_buf[s->compressed_image_size], data, len); @@ -1345,13 +1320,13 @@ SPAN_DECLARE(int) t42_decode_set_image_size_constraints(t42_decode_state_t *s, SPAN_DECLARE(uint32_t) t42_decode_get_image_width(t42_decode_state_t *s) { - return 0; + return s->image_width; } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(uint32_t) t42_decode_get_image_length(t42_decode_state_t *s) { - return 0; + return s->image_length; } /*- End of function --------------------------------------------------------*/ @@ -1369,7 +1344,28 @@ SPAN_DECLARE(logging_state_t *) t42_decode_get_logging_state(t42_decode_state_t SPAN_DECLARE(int) t42_decode_restart(t42_decode_state_t *s) { + if (s->itu_ycc) + { + /* ITU-YCC */ + /* Illuminant D65 */ + //set_lab_illuminant(&s->lab, 95.047f, 100.000f, 108.883f); + set_lab_illuminant(&s->lab, 100.0f, 100.0f, 100.0f); + set_lab_gamut(&s->lab, 0, 100, -127, 127, -127, 127, false); + } + else + { + /* ITULAB */ + /* Illuminant D50 */ + //set_lab_illuminant(&s->lab, 96.422f, 100.000f, 82.521f); + set_lab_illuminant(&s->lab, 100.0f, 100.0f, 100.0f); + set_lab_gamut(&s->lab, 0, 100, -85, 85, -75, 125, false); + } + + s->end_of_data = false; s->compressed_image_size = 0; + + s->error_message[0] = '\0'; + return 0; } /*- End of function --------------------------------------------------------*/ @@ -1380,7 +1376,7 @@ SPAN_DECLARE(t42_decode_state_t *) t42_decode_init(t42_decode_state_t *s, { if (s == NULL) { - if ((s = (t42_decode_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (t42_decode_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -1401,9 +1397,25 @@ SPAN_DECLARE(t42_decode_state_t *) t42_decode_init(t42_decode_state_t *s, SPAN_DECLARE(int) t42_decode_release(t42_decode_state_t *s) { + if (s->scan_line_in) + { + span_free(s->scan_line_in); + s->scan_line_in = NULL; + } + if (s->scan_line_out) + { + span_free(s->scan_line_out); + s->scan_line_out = NULL; + } + jpeg_destroy_decompress(&s->decompressor); + if (s->in) + { + fclose(s->in); + s->in = NULL; + } if (s->comment) { - free(s->comment); + span_free(s->comment); s->comment = NULL; } return 0; @@ -1415,7 +1427,7 @@ SPAN_DECLARE(int) t42_decode_free(t42_decode_state_t *s) int ret; ret = t42_decode_release(s); - free(s); + span_free(s); return ret; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/t42_t43_local.h b/libs/spandsp/src/t42_t43_local.h index 6eec67c6b9..45230e57d3 100644 --- a/libs/spandsp/src/t42_t43_local.h +++ b/libs/spandsp/src/t42_t43_local.h @@ -33,7 +33,8 @@ extern "C" { #endif -void set_illuminant_from_code(logging_state_t *logging, lab_params_t *s, const uint8_t code[4]); +int set_illuminant_from_code(logging_state_t *logging, lab_params_t *s, const uint8_t code[4]); + void set_gamut_from_code(logging_state_t *logging, lab_params_t *s, const uint8_t code[12]); #if defined(__cplusplus) diff --git a/libs/spandsp/src/t43.c b/libs/spandsp/src/t43.c new file mode 100644 index 0000000000..b4d8b2b86b --- /dev/null +++ b/libs/spandsp/src/t43.c @@ -0,0 +1,934 @@ +/* + * 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 + * + * 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 +#include +#include +#include +#if defined(HAVE_TGMATH_H) +#include +#endif +#if defined(HAVE_MATH_H) +#include +#endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif +#include +#include "floating_fudge.h" +#include + +#include "spandsp/telephony.h" +#include "spandsp/alloc.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 "t43_gray_code_tables.h" +#include "t42_t43_local.h" + +SPAN_DECLARE(const char *) t43_image_type_to_str(int type) +{ + switch (type) + { + case T43_IMAGE_TYPE_RGB_BILEVEL: + return "1 bit/colour image (RGB primaries)"; + case T43_IMAGE_TYPE_CMY_BILEVEL: + return "1 bit/colour image (CMY primaries)"; + case T43_IMAGE_TYPE_CMYK_BILEVEL: + return "1 bit/colour image (CMYK primaries)"; + case T43_IMAGE_TYPE_8BIT_COLOUR_PALETTE: + return "Palettized colour image (CIELAB 8 bits/component precision table)"; + case T43_IMAGE_TYPE_12BIT_COLOUR_PALETTE: + return "Palettized colour image (CIELAB 12 bits/component precision table)"; + case T43_IMAGE_TYPE_GRAY: + return "Gray-scale image (using L*)"; + case T43_IMAGE_TYPE_COLOUR: + 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 --------------------------------------------------------*/ + +static int t43_create_header(t43_encode_state_t *s, uint8_t data[], size_t len) +{ + int pos; + int val[6]; +#if 0 + int bytes_per_entry; +#endif + + 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->spatial_resolution); + pos += 2; + /* JBIG coding method (0) is the only possible value here */ + data[pos] = 0; + pos += 1; + data[pos] = s->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; + get_lab_gamut2(&s->lab, &val[0], &val[1], &val[2], &val[3], &val[4], &val[5]); + unpack_16(&data[pos + 0], val[0]); + unpack_16(&data[pos + 2], val[1]); + unpack_16(&data[pos + 4], val[2]); + unpack_16(&data[pos + 6], val[3]); + unpack_16(&data[pos + 8], val[4]); + unpack_16(&data[pos + 10], val[5]); + pos += 12; + } + + if (memcmp(s->illuminant_code, "\0\0\0\0", 4) != 0 + || + s->illuminant_colour_temperature > 0) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Putting G3FAX2\n"); + unpack_16(&data[pos], 0xFFE1); + pos += 2; + unpack_16(&data[pos], 2 + 6 + 4); + pos += 2; + memcpy(&data[pos], "G3FAX\2", 6); + pos += 6; + if (memcmp(s->illuminant_code, "\0\0\0\0", 4) != 0) + { + memcpy(&data[pos], s->illuminant_code, 4); + } + else + { + memcpy(&data[pos], "CT", 2); + unpack_16(&data[pos + 2], s->illuminant_colour_temperature); + } + pos += 4; + } + +#if 0 + if (s->colour_map) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Putting G3FAX3\n"); + bytes_per_entry = (table_id == 0) ? 1 : 2; + unpack_16(&data[pos], 0xFFE3); + pos += 2; + unpack_32(&data[pos], 2 + 6 + 2 + 4 + 3*s->colour_map_entries*bytes_per_entry); + 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*bytes_per_entry; + } +#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(int) t43_encode_set_image_type(t43_encode_state_t *s, int image_type) +{ + return 0; +} +/*- 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 *) span_alloc(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); + + s->image_type = T43_IMAGE_TYPE_8BIT_COLOUR_PALETTE; + + 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); + span_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) +{ + int i; + + switch (code) + { + case T43_IMAGE_TYPE_RGB_BILEVEL: + /* 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 T43_IMAGE_TYPE_CMY_BILEVEL: + /* 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 T43_IMAGE_TYPE_CMYK_BILEVEL: + /* 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 T43_IMAGE_TYPE_8BIT_COLOUR_PALETTE: + /* Palettized colour image (using CIELAB 8 bits/component precision table) */ + for (i = 0; i < 3*256; i += 3) + { + s->colour_map[i + 0] = i; + s->colour_map[i + 1] = i; + s->colour_map[i + 2] = i; + } + s->colour_map_entries = 256; + break; + case T43_IMAGE_TYPE_12BIT_COLOUR_PALETTE: + /* Palettized colour image (using CIELAB 12 bits/component precision table) */ + break; + case T43_IMAGE_TYPE_GRAY: + /* Gray-scale image (using L*) */ + for (i = 0; i < 256; i++) + s->colour_map[i] = i; + s->colour_map_entries = 256; + break; + case T43_IMAGE_TYPE_COLOUR: + /* 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; + + 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) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Got bad G3FAX0 length - %d\n", seg); + } + else + { + val[0] = pack_16(&data[pos + 6 + 0]); + s->spatial_resolution = pack_16(&data[pos + 6 + 2]); + val[2] = data[pos + 6 + 4]; + s->image_type = 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]; + if (s->image_type == T43_IMAGE_TYPE_GRAY) + { + s->samples_per_pixel = 1; + } + else if (s->image_type == T43_IMAGE_TYPE_CMYK_BILEVEL) + { + s->samples_per_pixel = 4; + } + else + { + s->samples_per_pixel = 3; + } + span_log(&s->logging, + SPAN_LOG_FLOW, + "Version %d, resolution %ddpi, coding method %d, type %s (%d), bit planes %d,%d,%d,%d\n", + val[0], + s->spatial_resolution, + val[2], + t43_image_type_to_str(s->image_type), + s->image_type, + s->bit_planes[0], + s->bit_planes[1], + s->bit_planes[2], + s->bit_planes[3]); + set_simple_colour_map(s, s->image_type); + } + break; + case 1: + span_log(&s->logging, SPAN_LOG_FLOW, "Set gamut\n"); + if (seg < 6 + 12) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Got bad G3FAX1 length - %d\n", seg); + } + else + { + set_gamut_from_code(&s->logging, &s->lab, &data[pos + 6]); + } + break; + case 2: + span_log(&s->logging, SPAN_LOG_FLOW, "Set illuminant\n"); + if (seg < 6 + 4) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Got bad G3FAX2 length - %d\n", seg); + } + else + { + s->illuminant_colour_temperature = set_illuminant_from_code(&s->logging, &s->lab, &data[pos + 6]); + } + 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 (len %d)\n", s->colour_map_entries, seg); + 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 = s->samples_per_pixel*s->t85.xd*s->t85.yd; + if ((s->buf = span_alloc(image_size)) == NULL) + return -1; + memset(s->buf, 0, image_size); + } + + for (i = 0; i < len; i++) + { + mask = 0x80; + if (s->samples_per_pixel == 1) + { + for (j = 0; j < 8; j += s->samples_per_pixel) + { + if ((buf[i] & mask)) + s->buf[s->ptr + j] |= s->bit_plane_mask; + mask >>= 1; + } + } + else + { + for (j = 0; j < s->samples_per_pixel*8; j += s->samples_per_pixel) + { + if ((buf[i] & mask)) + s->buf[s->ptr + j] |= s->bit_plane_mask; + mask >>= 1; + } + } + s->ptr += s->samples_per_pixel*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. */ + total_len = 0; + result = 0; + 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 */ + if (s->samples_per_pixel == 1) + { + for (j = 0; j < total_len; j += s->samples_per_pixel) + s->buf[j] = s->colour_map[s->buf[j]]; + } + else + { + for (j = 0; j < total_len; j += s->samples_per_pixel) + { + 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*s->samples_per_pixel*s->t85.xd], s->samples_per_pixel*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) +{ + /* ITULAB */ + /* Illuminant D50 */ + //set_lab_illuminant(&s->lab, 96.422f, 100.000f, 82.521f); + set_lab_illuminant(&s->lab, 100.0f, 100.0f, 100.0f); + set_lab_gamut(&s->lab, 0, 100, -85, 85, -75, 125, false); + + s->t85.min_bit_planes = 1; + s->t85.max_bit_planes = 8; + s->bit_plane_mask = 0x80; + s->current_bit_plane = -1; + s->image_type = T43_IMAGE_TYPE_8BIT_COLOUR_PALETTE; + + 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 *) span_alloc(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); + + /* ITULAB */ + /* Illuminant D50 */ + //set_lab_illuminant(&s->lab, 96.422f, 100.000f, 82.521f); + set_lab_illuminant(&s->lab, 100.0f, 100.0f, 100.0f); + set_lab_gamut(&s->lab, 0, 100, -85, 85, -75, 125, false); + + s->t85.min_bit_planes = 1; + s->t85.max_bit_planes = 8; + s->bit_plane_mask = 0x80; + s->current_bit_plane = -1; + s->image_type = T43_IMAGE_TYPE_8BIT_COLOUR_PALETTE; + + 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); + span_free(s); + return ret; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/src/t4_rx.c b/libs/spandsp/src/t4_rx.c index 0d6950e278..f14521b5f0 100644 --- a/libs/spandsp/src/t4_rx.c +++ b/libs/spandsp/src/t4_rx.c @@ -44,10 +44,16 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/bit_operations.h" #include "spandsp/async.h" @@ -58,9 +64,7 @@ #include "spandsp/t81_t82_arith_coding.h" #include "spandsp/t85.h" #include "spandsp/t42.h" -#if defined(SPANDSP_SUPPORT_T43) #include "spandsp/t43.h" -#endif #include "spandsp/t4_t6_decode.h" #include "spandsp/t4_t6_encode.h" #include "spandsp/version.h" @@ -69,9 +73,7 @@ #include "spandsp/private/t81_t82_arith_coding.h" #include "spandsp/private/t85.h" #include "spandsp/private/t42.h" -#if defined(SPANDSP_SUPPORT_T43) #include "spandsp/private/t43.h" -#endif #include "spandsp/private/t4_t6_decode.h" #include "spandsp/private/t4_t6_encode.h" #include "spandsp/private/image_translate.h" @@ -81,34 +83,49 @@ /*! The number of centimetres in one inch */ #define CM_PER_INCH 2.54f +typedef struct +{ + uint8_t *buf; + int ptr; +} packer_t; + #if defined(SPANDSP_SUPPORT_TIFF_FX) +#if TIFFLIB_VERSION >= 20120615 extern TIFFFieldArray tiff_fx_field_array; #endif +#endif -SPAN_DECLARE(const char *) t4_encoding_to_str(int encoding) +SPAN_DECLARE(const char *) t4_compression_to_str(int compression) { - switch (encoding) + switch (compression) { case T4_COMPRESSION_NONE: return "None"; - case T4_COMPRESSION_ITU_T4_1D: + case T4_COMPRESSION_T4_1D: return "T.4 1-D"; - case T4_COMPRESSION_ITU_T4_2D: + case T4_COMPRESSION_T4_2D: return "T.4 2-D"; - case T4_COMPRESSION_ITU_T6: + case T4_COMPRESSION_T6: return "T.6"; - case T4_COMPRESSION_ITU_T42: - return "T.42"; - case T4_COMPRESSION_ITU_SYCC_T42: - return "sYCC T.42"; - case T4_COMPRESSION_ITU_T43: - return "T.43"; - case T4_COMPRESSION_ITU_T45: - return "T.45"; - case T4_COMPRESSION_ITU_T85: + case T4_COMPRESSION_T85: return "T.85"; - case T4_COMPRESSION_ITU_T85_L0: + case T4_COMPRESSION_T85_L0: return "T.85(L0)"; + case T4_COMPRESSION_T88: + return "T.88"; + case T4_COMPRESSION_T42_T81: + return "T.81+T.42"; + case T4_COMPRESSION_SYCC_T81: + return "T.81+sYCC"; + case T4_COMPRESSION_T43: + return "T.43"; + case T4_COMPRESSION_T45: + return "T.45"; + /* Compressions which can only be used in TIFF files */ + case T4_COMPRESSION_UNCOMPRESSED: + return "Uncompressed"; + case T4_COMPRESSION_JPEG: + return "JPEG"; } return "???"; } @@ -122,14 +139,59 @@ SPAN_DECLARE(const char *) t4_image_type_to_str(int type) return "bi-level"; case T4_IMAGE_TYPE_COLOUR_BILEVEL: return "bi-level colour"; + case T4_IMAGE_TYPE_4COLOUR_BILEVEL: + return "CMYK bi-level colour"; case T4_IMAGE_TYPE_GRAY_8BIT: return "8-bit gray scale"; case T4_IMAGE_TYPE_GRAY_12BIT: return "12-bit gray scale"; case T4_IMAGE_TYPE_COLOUR_8BIT: return "8-bit colour"; + case T4_IMAGE_TYPE_4COLOUR_8BIT: + return "CMYK 8-bit colour"; case T4_IMAGE_TYPE_COLOUR_12BIT: return "12-bit colour"; + case T4_IMAGE_TYPE_4COLOUR_12BIT: + return "CMYK 12-bit colour"; + } + return "???"; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(const char *) t4_image_resolution_to_str(int resolution_code) +{ + switch (resolution_code) + { + case T4_RESOLUTION_R8_STANDARD: + return "204dpi x 98dpi"; + case T4_RESOLUTION_R8_FINE: + return "204dpi x 196dpi"; + case T4_RESOLUTION_R8_SUPERFINE: + return "204dpi x 391dpi"; + case T4_RESOLUTION_R16_SUPERFINE: + return "408dpi x 391dpi"; + case T4_RESOLUTION_100_100: + return "100dpi x 100dpi"; + case T4_RESOLUTION_200_100: + return "200dpi x 100dpi"; + case T4_RESOLUTION_200_200: + return "200dpi x 200dpi"; + case T4_RESOLUTION_200_400: + return "200dpi x 400dpi"; + case T4_RESOLUTION_300_300: + return "300dpi x 300dpi"; + case T4_RESOLUTION_300_600: + return "300dpi x 600dpi"; + case T4_RESOLUTION_400_400: + return "400dpi x 400dpi"; + case T4_RESOLUTION_400_800: + return "400dpi x 800dpi"; + case T4_RESOLUTION_600_600: + return "600dpi x 600dpi"; + case T4_RESOLUTION_600_1200: + return "600dpi x 1200dpi"; + case T4_RESOLUTION_1200_1200: + return "1200dpi x 1200dpi"; } return "???"; } @@ -149,47 +211,94 @@ static int set_tiff_directory_info(t4_rx_state_t *s) int bits_per_sample; int samples_per_pixel; int photometric; - int image_length; + uint32_t width; + uint32_t length; t = &s->tiff; /* Prepare the directory entry fully before writing the image, or libtiff complains */ bits_per_sample = 1; samples_per_pixel = 1; photometric = PHOTOMETRIC_MINISWHITE; - switch (t->output_encoding) + output_t4_options = 0; + switch (t->compression) { - case T4_COMPRESSION_ITU_T4_1D: + case T4_COMPRESSION_T4_1D: default: output_compression = COMPRESSION_CCITT_T4; output_t4_options = GROUP3OPT_FILLBITS; break; - case T4_COMPRESSION_ITU_T4_2D: + case T4_COMPRESSION_T4_2D: output_compression = COMPRESSION_CCITT_T4; output_t4_options = GROUP3OPT_FILLBITS | GROUP3OPT_2DENCODING; break; - case T4_COMPRESSION_ITU_T6: + case T4_COMPRESSION_T6: output_compression = COMPRESSION_CCITT_T6; break; -#if defined(SPANDSP_SUPPORT_T42) - case T4_COMPRESSION_ITU_T42: - output_compression = COMPRESSION_JPEG; - bits_per_sample = 8; - samples_per_pixel = 3; - photometric = PHOTOMETRIC_ITULAB; + case T4_COMPRESSION_T85: + case T4_COMPRESSION_T85_L0: + output_compression = COMPRESSION_T85; + break; +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + output_compression = COMPRESSION_T88; break; #endif -#if defined(SPANDSP_SUPPORT_T43) - case T4_COMPRESSION_ITU_T43: + case T4_COMPRESSION_JPEG: + output_compression = COMPRESSION_JPEG; + bits_per_sample = 8; + if (t->image_type == T4_IMAGE_TYPE_COLOUR_8BIT) + { + samples_per_pixel = 3; + photometric = PHOTOMETRIC_YCBCR; + } + else + { + samples_per_pixel = 1; + photometric = PHOTOMETRIC_MINISBLACK; + } + break; + case T4_COMPRESSION_T42_T81: + output_compression = COMPRESSION_JPEG; + bits_per_sample = 8; + if (t->image_type == T4_IMAGE_TYPE_COLOUR_8BIT) + { + samples_per_pixel = 3; + photometric = PHOTOMETRIC_ITULAB; + } + else + { + samples_per_pixel = 1; + photometric = PHOTOMETRIC_MINISBLACK; + } + break; + case T4_COMPRESSION_SYCC_T81: + output_compression = COMPRESSION_JPEG; + bits_per_sample = 8; + if (t->image_type == T4_IMAGE_TYPE_COLOUR_8BIT) + { + samples_per_pixel = 3; + photometric = PHOTOMETRIC_YCBCR; + } + else + { + samples_per_pixel = 1; + photometric = PHOTOMETRIC_MINISBLACK; + } + break; + case T4_COMPRESSION_T43: output_compression = COMPRESSION_T43; bits_per_sample = 8; samples_per_pixel = 3; photometric = PHOTOMETRIC_ITULAB; break; -#endif - case T4_COMPRESSION_ITU_T85: - case T4_COMPRESSION_ITU_T85_L0: - output_compression = COMPRESSION_T85; +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + output_compression = COMPRESSION_T45; + bits_per_sample = 8; + samples_per_pixel = 3; + photometric = PHOTOMETRIC_ITULAB; break; +#endif } TIFFSetField(t->tiff_file, TIFFTAG_COMPRESSION, output_compression); @@ -203,17 +312,15 @@ static int set_tiff_directory_info(t4_rx_state_t *s) TIFFSetField(t->tiff_file, TIFFTAG_T6OPTIONS, 0); TIFFSetField(t->tiff_file, TIFFTAG_FAXMODE, FAXMODE_CLASSF); break; + case COMPRESSION_T85: + TIFFSetField(t->tiff_file, TIFFTAG_FAXMODE, FAXMODE_CLASSF); + break; case COMPRESSION_JPEG: TIFFSetField(t->tiff_file, TIFFTAG_FAXMODE, FAXMODE_CLASSF); break; -#if defined(SPANDSP_SUPPORT_T43) case COMPRESSION_T43: TIFFSetField(t->tiff_file, TIFFTAG_FAXMODE, FAXMODE_CLASSF); break; -#endif - case COMPRESSION_T85: - TIFFSetField(t->tiff_file, TIFFTAG_FAXMODE, FAXMODE_CLASSF); - break; } TIFFSetField(t->tiff_file, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(t->tiff_file, TIFFTAG_BITSPERSAMPLE, bits_per_sample); @@ -221,6 +328,21 @@ static int set_tiff_directory_info(t4_rx_state_t *s) TIFFSetField(t->tiff_file, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(t->tiff_file, TIFFTAG_PHOTOMETRIC, photometric); TIFFSetField(t->tiff_file, TIFFTAG_FILLORDER, FILLORDER_LSB2MSB); + switch (t->compression) + { + case T4_COMPRESSION_JPEG: + TIFFSetField(t->tiff_file, TIFFTAG_YCBCRSUBSAMPLING, 2, 2); + //TIFFSetField(t->tiff_file, TIFFTAG_YCBCRSUBSAMPLING, 1, 1); + TIFFSetField(t->tiff_file, TIFFTAG_JPEGQUALITY, 75); + TIFFSetField(t->tiff_file, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB); + break; + case T4_COMPRESSION_T42_T81: + TIFFSetField(t->tiff_file, TIFFTAG_YCBCRSUBSAMPLING, 2, 2); + //TIFFSetField(t->tiff_file, TIFFTAG_YCBCRSUBSAMPLING, 1, 1); + TIFFSetField(t->tiff_file, TIFFTAG_JPEGQUALITY, 75); + TIFFSetField(t->tiff_file, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB); + break; + } /* TIFFTAG_STRIPBYTECOUNTS and TIFFTAG_STRIPOFFSETS are added automatically */ x_resolution = s->metadata.x_resolution/100.0f; @@ -268,7 +390,7 @@ static int set_tiff_directory_info(t4_rx_state_t *s) TIFFSetField(t->tiff_file, TIFFTAG_DATETIME, buf); TIFFSetField(t->tiff_file, TIFFTAG_FAXRECVTIME, now - s->tiff.page_start_time); - TIFFSetField(t->tiff_file, TIFFTAG_IMAGEWIDTH, s->image_width); + TIFFSetField(t->tiff_file, TIFFTAG_IMAGEWIDTH, s->metadata.image_width); /* Set the total pages to 1. For any one page document we will get this right. For multi-page documents we will need to come back and fill in the right answer when we know it. */ @@ -276,44 +398,68 @@ static int set_tiff_directory_info(t4_rx_state_t *s) /* TIFF page numbers start from zero, so the number of pages in the file is always one greater than the highest page number in the file. */ s->tiff.pages_in_file = s->current_page + 1; - image_length = 0; - switch (s->line_encoding) + s->metadata.image_length = 0; + switch (s->current_decoder) { - case T4_COMPRESSION_ITU_T4_1D: - case T4_COMPRESSION_ITU_T4_2D: - /* We only get bad row info from pages received in non-ECM mode. */ - if (output_compression == COMPRESSION_CCITT_T4) + case 0: + switch (t->compression) { - if (s->decoder.t4_t6.bad_rows) + case T4_COMPRESSION_T42_T81: + case T4_COMPRESSION_SYCC_T81: + t42_analyse_header(&width, &length, s->decoder.no_decoder.buf, s->decoder.no_decoder.buf_ptr); + s->metadata.image_width = width; + s->metadata.image_length = length; + break; + case T4_COMPRESSION_T85: + case T4_COMPRESSION_T85_L0: + t85_analyse_header(&width, &length, s->decoder.no_decoder.buf, s->decoder.no_decoder.buf_ptr); + s->metadata.image_width = width; + s->metadata.image_length = length; + break; + } + break; + case T4_COMPRESSION_T4_1D | T4_COMPRESSION_T4_2D | T4_COMPRESSION_T6: + if ((s->metadata.compression & (T4_COMPRESSION_T4_1D | T4_COMPRESSION_T4_2D))) + { + /* We only get bad row info from pages received in non-ECM mode. */ + if (output_compression == COMPRESSION_CCITT_T4) { - TIFFSetField(t->tiff_file, TIFFTAG_BADFAXLINES, s->decoder.t4_t6.bad_rows); - TIFFSetField(t->tiff_file, TIFFTAG_CONSECUTIVEBADFAXLINES, s->decoder.t4_t6.longest_bad_row_run); - TIFFSetField(t->tiff_file, TIFFTAG_CLEANFAXDATA, CLEANFAXDATA_REGENERATED); - } - else - { - TIFFSetField(t->tiff_file, TIFFTAG_CLEANFAXDATA, CLEANFAXDATA_CLEAN); + if (s->decoder.t4_t6.bad_rows) + { + TIFFSetField(t->tiff_file, TIFFTAG_BADFAXLINES, s->decoder.t4_t6.bad_rows); + TIFFSetField(t->tiff_file, TIFFTAG_CONSECUTIVEBADFAXLINES, s->decoder.t4_t6.longest_bad_row_run); + TIFFSetField(t->tiff_file, TIFFTAG_CLEANFAXDATA, CLEANFAXDATA_REGENERATED); + } + else + { + TIFFSetField(t->tiff_file, TIFFTAG_CLEANFAXDATA, CLEANFAXDATA_CLEAN); + } } } - /* Fall through */ - case T4_COMPRESSION_ITU_T6: - image_length = t4_t6_decode_get_image_length(&s->decoder.t4_t6); + s->metadata.image_length = t4_t6_decode_get_image_length(&s->decoder.t4_t6); break; - case T4_COMPRESSION_ITU_T42: - image_length = t42_decode_get_image_length(&s->decoder.t42); + case T4_COMPRESSION_T85 | T4_COMPRESSION_T85_L0: + s->metadata.image_length = t85_decode_get_image_length(&s->decoder.t85); break; -#if defined(SPANDSP_SUPPORT_T43) - case T4_COMPRESSION_ITU_T43: - image_length = t43_decode_get_image_length(&s->decoder.t43); +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + s->metadata.image_length = t88_decode_get_image_length(&s->decoder.t88); break; #endif - case T4_COMPRESSION_ITU_T85: - case T4_COMPRESSION_ITU_T85_L0: - image_length = t85_decode_get_image_length(&s->decoder.t85); + case T4_COMPRESSION_T42_T81: + s->metadata.image_length = t42_decode_get_image_length(&s->decoder.t42); break; + case T4_COMPRESSION_T43: + s->metadata.image_length = t43_decode_get_image_length(&s->decoder.t43); + break; +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + s->metadata.image_length = t45_decode_get_image_length(&s->decoder.t45); + break; +#endif } - TIFFSetField(t->tiff_file, TIFFTAG_IMAGELENGTH, image_length); - TIFFSetField(t->tiff_file, TIFFTAG_ROWSPERSTRIP, image_length); + TIFFSetField(t->tiff_file, TIFFTAG_IMAGELENGTH, s->metadata.image_length); + TIFFSetField(t->tiff_file, TIFFTAG_ROWSPERSTRIP, s->metadata.image_length); #if defined(SPANDSP_SUPPORT_TIFF_FX) TIFFSetField(t->tiff_file, TIFFTAG_PROFILETYPE, PROFILETYPE_G3_FAX); TIFFSetField(t->tiff_file, TIFFTAG_FAXPROFILE, FAXPROFILE_S); @@ -324,6 +470,34 @@ static int set_tiff_directory_info(t4_rx_state_t *s) /* Create a placeholder for the global parameters IFD, to be filled in later */ TIFFSetField(t->tiff_file, TIFFTAG_GLOBALPARAMETERSIFD, 0); } + +#if 0 + /* Paletised image? */ + TIFFSetField(t->tiff_file, TIFFTAG_INDEXED, 1); + /* T.44 mode */ + TIFFSetField(t->tiff_file, TIFFTAG_MODENUMBER, 0); + span_log(&s->logging, SPAN_LOG_FLOW, "TIFF/FX stuff 2\n"); + { + float xxx[] = {20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0}; + TIFFSetField(t->tiff_file, TIFFTAG_DECODE, (uint16) 2*samples_per_pixel, xxx); + } + span_log(&s->logging, SPAN_LOG_FLOW, "TIFF/FX stuff 3\n"); + { + uint16_t xxx[] = {12, 34, 45, 67}; + TIFFSetField(t->tiff_file, TIFFTAG_IMAGEBASECOLOR, (uint16_t) samples_per_pixel, xxx); + } + span_log(&s->logging, SPAN_LOG_FLOW, "TIFF/FX stuff 4\n"); + TIFFSetField(t->tiff_file, TIFFTAG_T82OPTIONS, 0); + { + uint32_t xxx[] = {34, 56, 78, 90}; + TIFFSetField(t->tiff_file, TIFFTAG_STRIPROWCOUNTS, (uint16_t) 5, xxx); + } + span_log(&s->logging, SPAN_LOG_FLOW, "TIFF/FX stuff 5\n"); + { + uint32_t xxx[] = {2, 3}; + TIFFSetField(t->tiff_file, TIFFTAG_IMAGELAYER, xxx); + } +#endif #endif return 0; } @@ -337,6 +511,107 @@ static int open_tiff_output_file(t4_rx_state_t *s, const char *file) } /*- End of function --------------------------------------------------------*/ +static int row_read_handler(void *user_data, uint8_t row[], size_t len) +{ + packer_t *s; + + s = (packer_t *) user_data; + memcpy(row, &s->buf[s->ptr], len); + s->ptr += len; + return len; +} +/*- End of function --------------------------------------------------------*/ + +static int write_tiff_t85_image(t4_rx_state_t *s) +{ + uint8_t *buf; + uint8_t *buf2; + int buf_len; + int len; + int image_len; + t85_encode_state_t t85; + packer_t packer; + + /* We need to perform this compression here, as libtiff does not understand it. */ + packer.buf = s->tiff.image_buffer; + packer.ptr = 0; + if (t85_encode_init(&t85, s->metadata.image_width, s->metadata.image_length, row_read_handler, &packer) == NULL) + return -1; + //if (t->compression == T4_COMPRESSION_T85_L0) + // t85_encode_set_options(&t85, 256, -1, -1); + buf = NULL; + buf_len = 0; + image_len = 0; + do + { + if (buf_len < image_len + 65536) + { + buf_len += 65536; + if ((buf2 = span_realloc(buf, buf_len)) == NULL) + { + if (buf) + span_free(buf); + return -1; + } + buf = buf2; + } + len = t85_encode_get(&t85, &buf[image_len], buf_len - image_len); + image_len += len; + } + while (len > 0); + if (TIFFWriteRawStrip(s->tiff.tiff_file, 0, buf, image_len) < 0) + { + span_log(&s->logging, SPAN_LOG_WARNING, "%s: Error writing TIFF strip.\n", s->tiff.file); + return -1; + } + t85_encode_release(&t85); + span_free(buf); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int write_tiff_t43_image(t4_rx_state_t *s) +{ + uint8_t *buf; + uint8_t *buf2; + int buf_len; + int len; + int image_len; + t43_encode_state_t t43; + packer_t packer; + + packer.buf = s->tiff.image_buffer; + packer.ptr = 0; + if (t43_encode_init(&t43, s->metadata.image_width, s->metadata.image_length, row_read_handler, &packer) == NULL) + return -1; + buf = NULL; + buf_len = 0; + image_len = 0; + do + { + if (buf_len < image_len + 65536) + { + buf_len += 65536; + if ((buf2 = span_realloc(buf, buf_len)) == NULL) + { + if (buf) + span_free(buf); + return -1; + } + buf = buf2; + } + len = t43_encode_get(&t43, &buf[image_len], buf_len - image_len); + image_len += len; + } + while (len > 0); + if (TIFFWriteRawStrip(s->tiff.tiff_file, 0, buf, image_len) < 0) + span_log(&s->logging, SPAN_LOG_WARNING, "%s: Error writing TIFF strip.\n", s->tiff.file); + t43_encode_release(&t43); + span_free(buf); + return 0; +} +/*- End of function --------------------------------------------------------*/ + static int write_tiff_image(t4_rx_state_t *s) { t4_rx_tiff_state_t *t; @@ -345,38 +620,81 @@ static int write_tiff_image(t4_rx_state_t *s) #endif t = &s->tiff; - if (t->image_buffer == NULL || t->image_size <= 0) + if (s->decoder.no_decoder.buf_ptr <= 0 && (t->image_buffer == NULL || t->image_size <= 0)) return -1; /* Set up the TIFF directory info... */ set_tiff_directory_info(s); /* ...Put the directory in the file before the image data, to get them in the order specified for TIFF/F files... */ - if (!TIFFCheckpointDirectory(t->tiff_file)) - span_log(&s->logging, SPAN_LOG_WARNING, "%s: Failed to checkpoint directory for page %d.\n", t->file, s->current_page); + //if (!TIFFCheckpointDirectory(t->tiff_file)) + // span_log(&s->logging, SPAN_LOG_WARNING, "%s: Failed to checkpoint directory for page %d.\n", t->file, s->current_page); /* ...and write out the image... */ - if (TIFFWriteEncodedStrip(t->tiff_file, 0, t->image_buffer, t->image_size) < 0) - span_log(&s->logging, SPAN_LOG_WARNING, "%s: Error writing TIFF strip.\n", t->file); + if (s->current_decoder == 0) + { + if (TIFFWriteRawStrip(s->tiff.tiff_file, 0, s->decoder.no_decoder.buf, s->decoder.no_decoder.buf_ptr) < 0) + span_log(&s->logging, SPAN_LOG_WARNING, "%s: Error writing TIFF strip.\n", s->tiff.file); + } + else + { + switch (t->compression) + { + case T4_COMPRESSION_T85: + case T4_COMPRESSION_T85_L0: + /* We need to perform this compression here, as libtiff does not understand it. */ + if (write_tiff_t85_image(s) < 0) + return -1; + break; +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + /* We need to perform this compression here, as libtiff does not understand it. */ + if (write_tiff_t88_image(s) < 0) + return -1; + break; +#endif + case T4_COMPRESSION_T43: + /* We need to perform this compression here, as libtiff does not understand it. */ + if (write_tiff_t43_image(s) < 0) + return -1; + break; +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + /* We need to perform this compression here, as libtiff does not understand it. */ + if (write_tiff_t45_image(s) < 0) + return -1; + break; +#endif + default: + /* Let libtiff do the compression */ + if (TIFFWriteEncodedStrip(t->tiff_file, 0, t->image_buffer, t->image_size) < 0) + span_log(&s->logging, SPAN_LOG_WARNING, "%s: Error writing TIFF strip.\n", t->file); + break; + } + } /* ...then finalise the directory entry, and libtiff is happy. */ if (!TIFFWriteDirectory(t->tiff_file)) span_log(&s->logging, SPAN_LOG_WARNING, "%s: Failed to write directory for page %d.\n", t->file, s->current_page); #if defined(SPANDSP_SUPPORT_TIFF_FX) + /* According to the TIFF/FX spec, a global parameters IFD should only be inserted into + the first page in the file */ if (s->current_page == 0) { if (!TIFFCreateCustomDirectory(t->tiff_file, &tiff_fx_field_array)) { TIFFSetField(t->tiff_file, TIFFTAG_FAXPROFILE, PROFILETYPE_G3_FAX); TIFFSetField(t->tiff_file, TIFFTAG_PROFILETYPE, FAXPROFILE_F); + TIFFSetField(t->tiff_file, TIFFTAG_CODINGMETHODS, CODINGMETHODS_T4_1D | CODINGMETHODS_T4_2D | CODINGMETHODS_T6); TIFFSetField(t->tiff_file, TIFFTAG_VERSIONYEAR, "1998"); + TIFFSetField(t->tiff_file, TIFFTAG_MODENUMBER, 3); offset = 0; if (!TIFFWriteCustomDirectory(t->tiff_file, &offset)) - printf("Failed to write custom directory.\n"); + span_log(&s->logging, SPAN_LOG_WARNING, "Failed to write custom directory.\n"); /* Now go back and patch in the pointer to the new IFD */ if (!TIFFSetDirectory(t->tiff_file, s->current_page)) - printf("Failed to set directory.\n"); + span_log(&s->logging, SPAN_LOG_WARNING, "Failed to set directory.\n"); if (!TIFFSetField(t->tiff_file, TIFFTAG_GLOBALPARAMETERSIFD, offset)) - printf("Failed to set field.\n"); + span_log(&s->logging, SPAN_LOG_WARNING, "Failed to set field.\n"); if (!TIFFWriteDirectory(t->tiff_file)) span_log(&s->logging, SPAN_LOG_WARNING, "%s: Failed to write directory for page %d.\n", t->file, s->current_page); } @@ -416,7 +734,7 @@ static int close_tiff_output_file(t4_rx_state_t *s) put in it. */ if (s->current_page == 0) remove(s->tiff.file); - free((char *) s->tiff.file); + span_free((char *) s->tiff.file); } s->tiff.file = NULL; return 0; @@ -429,7 +747,7 @@ static void tiff_rx_release(t4_rx_state_t *s) close_tiff_output_file(s); if (s->tiff.image_buffer) { - free(s->tiff.image_buffer); + span_free(s->tiff.image_buffer); s->tiff.image_buffer = NULL; s->tiff.image_size = 0; s->tiff.image_buffer_size = 0; @@ -445,25 +763,60 @@ SPAN_DECLARE(int) t4_rx_put_bit(t4_rx_state_t *s, int bit) } /*- End of function --------------------------------------------------------*/ +static void pre_encoded_restart(no_decoder_state_t *s) +{ + s->buf_ptr = 0; +} +/*- End of function --------------------------------------------------------*/ + +static void pre_encoded_init(no_decoder_state_t *s) +{ + s->buf = NULL; + s->buf_len = 0; + s->buf_ptr = 0; +} +/*- End of function --------------------------------------------------------*/ + +static int pre_encoded_release(no_decoder_state_t *s) +{ + if (s->buf) + span_free(s->buf); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int pre_encoded_put(no_decoder_state_t *s, const uint8_t data[], size_t len) +{ + uint8_t *buf; + + if (s->buf_len < s->buf_ptr + len) + { + s->buf_len += 65536; + if ((buf = span_realloc(s->buf, s->buf_len)) == NULL) + { + if (s->buf) + { + span_free(s->buf); + s->buf = NULL; + s->buf_len = 0; + } + return -1; + } + s->buf = buf; + } + memcpy(&s->buf[s->buf_ptr], data, len); + s->buf_ptr += len; + return T4_DECODE_MORE_DATA; +} +/*- End of function --------------------------------------------------------*/ + SPAN_DECLARE(int) t4_rx_put(t4_rx_state_t *s, const uint8_t buf[], size_t len) { s->line_image_size += 8*len; - switch (s->line_encoding) - { - case T4_COMPRESSION_ITU_T4_1D: - case T4_COMPRESSION_ITU_T4_2D: - case T4_COMPRESSION_ITU_T6: - return t4_t6_decode_put(&s->decoder.t4_t6, buf, len); - case T4_COMPRESSION_ITU_T42: - return t42_decode_put(&s->decoder.t42, buf, len); -#if defined(SPANDSP_SUPPORT_T43) - case T4_COMPRESSION_ITU_T43: - return t43_decode_put(&s->decoder.t43, buf, len); -#endif - case T4_COMPRESSION_ITU_T85: - case T4_COMPRESSION_ITU_T85_L0: - return t85_decode_put(&s->decoder.t85, buf, len); - } + + if (s->image_put_handler) + return s->image_put_handler((void *) &s->decoder, buf, len); + return T4_DECODE_OK; } /*- End of function --------------------------------------------------------*/ @@ -510,82 +863,229 @@ SPAN_DECLARE(void) t4_rx_set_model(t4_rx_state_t *s, const char *model) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) t4_rx_set_rx_encoding(t4_rx_state_t *s, int encoding) +static bool select_tiff_compression(t4_rx_state_t *s, int output_image_type) { - switch (encoding) + s->tiff.image_type = output_image_type; + /* The only compression schemes where we can really avoid decoding and + recoding the images are those where the width an length of the image + can be readily extracted from the image data (e.g. from its header) */ + if ((s->metadata.compression & (s->supported_tiff_compressions & (T4_COMPRESSION_T85 | T4_COMPRESSION_T85_L0 | T4_COMPRESSION_T42_T81 | T4_COMPRESSION_SYCC_T81)))) { - case T4_COMPRESSION_ITU_T4_1D: - case T4_COMPRESSION_ITU_T4_2D: - case T4_COMPRESSION_ITU_T6: - switch (s->line_encoding) - { - case T4_COMPRESSION_ITU_T4_1D: - case T4_COMPRESSION_ITU_T4_2D: - case T4_COMPRESSION_ITU_T6: - break; - default: - t4_t6_decode_init(&s->decoder.t4_t6, encoding, s->image_width, s->row_handler, s->row_handler_user_data); - break; - } - s->line_encoding = encoding; - return t4_t6_decode_set_encoding(&s->decoder.t4_t6, encoding); - case T4_COMPRESSION_ITU_T42: - switch (s->line_encoding) - { - case T4_COMPRESSION_ITU_T42: - break; - default: - t42_decode_init(&s->decoder.t42, s->row_handler, s->row_handler_user_data); - /* Constrain received images to the maximum width of any FAX. This will - avoid one potential cause of trouble, where a bad received image has - a gigantic dimension that sucks our memory dry. */ - t42_decode_set_image_size_constraints(&s->decoder.t42, T4_WIDTH_1200_A3, 0); - break; - } - s->line_encoding = encoding; - return 0; -#if defined(SPANDSP_SUPPORT_T43) - case T4_COMPRESSION_ITU_T43: - switch (s->line_encoding) - { - case T4_COMPRESSION_ITU_T43: - break; - default: - t43_decode_init(&s->decoder.t43, s->row_handler, s->row_handler_user_data); - /* Constrain received images to the maximum width of any FAX. This will - avoid one potential cause of trouble, where a bad received image has - a gigantic dimension that sucks our memory dry. */ - t43_decode_set_image_size_constraints(&s->decoder.t43, T4_WIDTH_1200_A3, 0); - break; - } - s->line_encoding = encoding; - return 0; + span_log(&s->logging, SPAN_LOG_FLOW, "Image can be written without recoding\n"); + s->tiff.compression = s->metadata.compression; + return false; + } + + if (output_image_type == T4_IMAGE_TYPE_BILEVEL) + { + /* Only provide for one form of coding throughout the file, even though the + coding on the wire could change between pages. */ + if ((s->supported_tiff_compressions & T4_COMPRESSION_T88)) + s->tiff.compression = T4_COMPRESSION_T88; + else if ((s->supported_tiff_compressions & T4_COMPRESSION_T85)) + s->tiff.compression = T4_COMPRESSION_T85; + else if ((s->supported_tiff_compressions & T4_COMPRESSION_T6)) + s->tiff.compression = T4_COMPRESSION_T6; + else if ((s->supported_tiff_compressions & T4_COMPRESSION_T4_2D)) + s->tiff.compression = T4_COMPRESSION_T4_2D; + else if ((s->supported_tiff_compressions & T4_COMPRESSION_T4_1D)) + s->tiff.compression = T4_COMPRESSION_T4_1D; + } + else + { + if ((s->supported_tiff_compressions & T4_COMPRESSION_JPEG)) + s->tiff.compression = T4_COMPRESSION_JPEG; + else if ((s->supported_tiff_compressions & T4_COMPRESSION_T42_T81)) + s->tiff.compression = T4_COMPRESSION_T42_T81; + else if ((s->supported_tiff_compressions & T4_COMPRESSION_T43)) + s->tiff.compression = T4_COMPRESSION_T43; + else if ((s->supported_tiff_compressions & T4_COMPRESSION_T45)) + s->tiff.compression = T4_COMPRESSION_T45; + else if ((s->supported_tiff_compressions & T4_COMPRESSION_UNCOMPRESSED)) + s->tiff.compression = T4_COMPRESSION_UNCOMPRESSED; + } + return true; +} +/*- End of function --------------------------------------------------------*/ + +static int release_current_decoder(t4_rx_state_t *s) +{ + switch (s->current_decoder) + { + case 0: + return pre_encoded_release(&s->decoder.no_decoder); + case T4_COMPRESSION_T4_1D | T4_COMPRESSION_T4_2D | T4_COMPRESSION_T6: + return t4_t6_decode_release(&s->decoder.t4_t6); + case T4_COMPRESSION_T85 | T4_COMPRESSION_T85_L0: + return t85_decode_release(&s->decoder.t85); +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + return t88_decode_release(&s->decoder.t88); #endif - case T4_COMPRESSION_ITU_T85: - case T4_COMPRESSION_ITU_T85_L0: - switch (s->line_encoding) + case T4_COMPRESSION_T42_T81: + return t42_decode_release(&s->decoder.t42); + case T4_COMPRESSION_T43: + return t43_decode_release(&s->decoder.t43); +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + return t45_decode_release(&s->decoder.t45); +#endif + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_rx_set_rx_encoding(t4_rx_state_t *s, int compression) +{ + switch (compression) + { + case T4_COMPRESSION_T4_1D: + case T4_COMPRESSION_T4_2D: + case T4_COMPRESSION_T6: + switch (s->metadata.compression) { - case T4_COMPRESSION_ITU_T85: - case T4_COMPRESSION_ITU_T85_L0: + case T4_COMPRESSION_T4_1D: + case T4_COMPRESSION_T4_2D: + case T4_COMPRESSION_T6: break; default: + release_current_decoder(s); + t4_t6_decode_init(&s->decoder.t4_t6, compression, s->metadata.image_width, s->row_handler, s->row_handler_user_data); + s->current_decoder = T4_COMPRESSION_T4_1D | T4_COMPRESSION_T4_2D | T4_COMPRESSION_T6; + break; + } + s->metadata.compression = compression; + if (!select_tiff_compression(s, T4_IMAGE_TYPE_BILEVEL)) + { + release_current_decoder(s); + s->current_decoder = 0; + pre_encoded_init(&s->decoder.no_decoder); + } + return t4_t6_decode_set_encoding(&s->decoder.t4_t6, compression); + case T4_COMPRESSION_T85: + case T4_COMPRESSION_T85_L0: + switch (s->metadata.compression) + { + case T4_COMPRESSION_T85: + case T4_COMPRESSION_T85_L0: + break; + default: + release_current_decoder(s); t85_decode_init(&s->decoder.t85, s->row_handler, s->row_handler_user_data); + s->current_decoder = T4_COMPRESSION_T85 | T4_COMPRESSION_T85_L0; /* Constrain received images to the maximum width of any FAX. This will avoid one potential cause of trouble, where a bad received image has a gigantic dimension that sucks our memory dry. */ t85_decode_set_image_size_constraints(&s->decoder.t85, T4_WIDTH_1200_A3, 0); break; } - s->line_encoding = encoding; + s->metadata.compression = compression; + if (!select_tiff_compression(s, T4_IMAGE_TYPE_BILEVEL)) + { + release_current_decoder(s); + s->current_decoder = 0; + pre_encoded_init(&s->decoder.no_decoder); + } return 0; +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + switch (s->metadata.compression) + { + case T4_COMPRESSION_T88: + break; + default: + release_current_decoder(s); + t88_decode_init(&s->decoder.t88, s->row_handler, s->row_handler_user_data); + s->current_decoder = T4_COMPRESSION_T88; + break; + } + s->metadata.compression = compression; + if (!select_tiff_compression(s, T4_IMAGE_TYPE_BILEVEL)) + { + release_current_decoder(s); + s->current_decoder = 0; + pre_encoded_init(&s->decoder.no_decoder); + } + return 0; +#endif + case T4_COMPRESSION_T42_T81: + case T4_COMPRESSION_SYCC_T81: + switch (s->metadata.compression) + { + case T4_COMPRESSION_T42_T81: + case T4_COMPRESSION_SYCC_T81: + break; + default: + release_current_decoder(s); + t42_decode_init(&s->decoder.t42, s->row_handler, s->row_handler_user_data); + s->current_decoder = T4_COMPRESSION_T42_T81; + /* Constrain received images to the maximum width of any FAX. This will + avoid one potential cause of trouble, where a bad received image has + a gigantic dimension that sucks our memory dry. */ + t42_decode_set_image_size_constraints(&s->decoder.t42, T4_WIDTH_1200_A3, 0); + break; + } + s->metadata.compression = compression; + if (!select_tiff_compression(s, T4_IMAGE_TYPE_COLOUR_8BIT)) + { + release_current_decoder(s); + s->current_decoder = 0; + pre_encoded_init(&s->decoder.no_decoder); + } + return 0; + case T4_COMPRESSION_T43: + switch (s->metadata.compression) + { + case T4_COMPRESSION_T43: + break; + default: + release_current_decoder(s); + t43_decode_init(&s->decoder.t43, s->row_handler, s->row_handler_user_data); + s->current_decoder = T4_COMPRESSION_T43; + /* Constrain received images to the maximum width of any FAX. This will + avoid one potential cause of trouble, where a bad received image has + a gigantic dimension that sucks our memory dry. */ + t43_decode_set_image_size_constraints(&s->decoder.t43, T4_WIDTH_1200_A3, 0); + break; + } + s->metadata.compression = compression; + if (!select_tiff_compression(s, T4_IMAGE_TYPE_COLOUR_8BIT)) + { + release_current_decoder(s); + s->current_decoder = 0; + pre_encoded_init(&s->decoder.no_decoder); + } + return 0; +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + switch (s->metadata.compression) + { + case T4_COMPRESSION_T45: + break; + default: + release_current_decoder(s); + t45_decode_init(&s->decoder.t45, s->row_handler, s->row_handler_user_data); + s->current_decoder = T4_COMPRESSION_T45; + break; + } + s->metadata.compression = compression; + if (!select_tiff_compression(s, T4_IMAGE_TYPE_COLOUR_8BIT)) + { + release_current_decoder(s); + s->current_decoder = 0; + pre_encoded_init(&s->decoder.no_decoder); + } + return 0; +#endif } + return -1; } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(void) t4_rx_set_image_width(t4_rx_state_t *s, int width) { - s->image_width = width; + s->metadata.image_width = width; } /*- End of function --------------------------------------------------------*/ @@ -593,21 +1093,24 @@ SPAN_DECLARE(int) t4_rx_set_row_write_handler(t4_rx_state_t *s, t4_row_write_han { s->row_handler = handler; s->row_handler_user_data = user_data; - switch (s->line_encoding) + switch (s->current_decoder) { - case T4_COMPRESSION_ITU_T4_1D: - case T4_COMPRESSION_ITU_T4_2D: - case T4_COMPRESSION_ITU_T6: + case T4_COMPRESSION_T4_1D | T4_COMPRESSION_T4_2D | T4_COMPRESSION_T6: return t4_t6_decode_set_row_write_handler(&s->decoder.t4_t6, handler, user_data); - case T4_COMPRESSION_ITU_T42: - return t42_decode_set_row_write_handler(&s->decoder.t42, handler, user_data); -#if defined(SPANDSP_SUPPORT_T43) - case T4_COMPRESSION_ITU_T43: - return t43_decode_set_row_write_handler(&s->decoder.t43, handler, user_data); -#endif - case T4_COMPRESSION_ITU_T85: - case T4_COMPRESSION_ITU_T85_L0: + case T4_COMPRESSION_T85 | T4_COMPRESSION_T85_L0: return t85_decode_set_row_write_handler(&s->decoder.t85, handler, user_data); +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + return t88_decode_set_row_write_handler(&s->decoder.t88, handler, user_data); +#endif + case T4_COMPRESSION_T42_T81: + return t42_decode_set_row_write_handler(&s->decoder.t42, handler, user_data); + case T4_COMPRESSION_T43: + return t43_decode_set_row_write_handler(&s->decoder.t43, handler, user_data); +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + return t45_decode_set_row_write_handler(&s->decoder.t45, handler, user_data); +#endif } return -1; } @@ -618,16 +1121,25 @@ SPAN_DECLARE(void) t4_rx_get_transfer_statistics(t4_rx_state_t *s, t4_stats_t *t memset(t, 0, sizeof(*t)); t->pages_transferred = s->current_page; t->pages_in_file = s->tiff.pages_in_file; + t->image_x_resolution = s->metadata.x_resolution; t->image_y_resolution = s->metadata.y_resolution; t->x_resolution = s->metadata.x_resolution; t->y_resolution = s->metadata.y_resolution; - t->encoding = s->line_encoding; - switch (s->line_encoding) + + t->compression = s->metadata.compression; + switch (s->current_decoder) { - case T4_COMPRESSION_ITU_T4_1D: - case T4_COMPRESSION_ITU_T4_2D: - case T4_COMPRESSION_ITU_T6: + case 0: + t->type = 0; + t->width = s->metadata.image_width; + t->length = s->metadata.image_length; + t->image_type = 0; + t->image_width = t->width; + t->image_length = t->length; + t->line_image_size = s->line_image_size; + break; + case T4_COMPRESSION_T4_1D | T4_COMPRESSION_T4_2D | T4_COMPRESSION_T6: t->type = T4_IMAGE_TYPE_BILEVEL; t->width = t4_t6_decode_get_image_width(&s->decoder.t4_t6); t->length = t4_t6_decode_get_image_length(&s->decoder.t4_t6); @@ -638,28 +1150,7 @@ SPAN_DECLARE(void) t4_rx_get_transfer_statistics(t4_rx_state_t *s, t4_stats_t *t t->bad_rows = s->decoder.t4_t6.bad_rows; t->longest_bad_row_run = s->decoder.t4_t6.longest_bad_row_run; break; - case T4_COMPRESSION_ITU_T42: - t->type = 0; - t->width = t42_decode_get_image_width(&s->decoder.t42); - t->length = t42_decode_get_image_length(&s->decoder.t42); - t->image_type = t->type; - t->image_width = t->width; - t->image_length = t->length; - t->line_image_size = t42_decode_get_compressed_image_size(&s->decoder.t42)/8; - break; -#if defined(SPANDSP_SUPPORT_T43) - case T4_COMPRESSION_ITU_T43: - t->type = 0; - t->width = t43_decode_get_image_width(&s->decoder.t43); - t->length = t43_decode_get_image_length(&s->decoder.t43); - t->image_type = t->type; - t->image_width = t->width; - t->image_length = t->length; - t->line_image_size = t43_decode_get_compressed_image_size(&s->decoder.t43)/8; - break; -#endif - case T4_COMPRESSION_ITU_T85: - case T4_COMPRESSION_ITU_T85_L0: + case T4_COMPRESSION_T85 | T4_COMPRESSION_T85_L0: t->type = T4_IMAGE_TYPE_BILEVEL; t->width = t85_decode_get_image_width(&s->decoder.t85); t->length = t85_decode_get_image_length(&s->decoder.t85); @@ -668,33 +1159,74 @@ SPAN_DECLARE(void) t4_rx_get_transfer_statistics(t4_rx_state_t *s, t4_stats_t *t t->image_length = t->length; t->line_image_size = t85_decode_get_compressed_image_size(&s->decoder.t85)/8; break; +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + break; +#endif + case T4_COMPRESSION_T42_T81: + t->type = T4_IMAGE_TYPE_COLOUR_8BIT; //T4_IMAGE_TYPE_GRAY_8BIT; + t->width = t42_decode_get_image_width(&s->decoder.t42); + t->length = t42_decode_get_image_length(&s->decoder.t42); + t->image_type = t->type; + t->image_width = t->width; + t->image_length = t->length; + t->line_image_size = t42_decode_get_compressed_image_size(&s->decoder.t42)/8; + break; + case T4_COMPRESSION_T43: + t->type = T4_IMAGE_TYPE_COLOUR_8BIT; + t->width = t43_decode_get_image_width(&s->decoder.t43); + t->length = t43_decode_get_image_length(&s->decoder.t43); + t->image_type = t->type; + t->image_width = t->width; + t->image_length = t->length; + t->line_image_size = t43_decode_get_compressed_image_size(&s->decoder.t43)/8; + break; +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + break; +#endif } } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(int) t4_rx_start_page(t4_rx_state_t *s) { - span_log(&s->logging, SPAN_LOG_FLOW, "Start rx page %d - compression %s\n", s->current_page, t4_encoding_to_str(s->line_encoding)); + span_log(&s->logging, SPAN_LOG_FLOW, "Start rx page %d - compression %s\n", s->current_page, t4_compression_to_str(s->metadata.compression)); - switch (s->line_encoding) + switch (s->current_decoder) { - case T4_COMPRESSION_ITU_T4_1D: - case T4_COMPRESSION_ITU_T4_2D: - case T4_COMPRESSION_ITU_T6: - t4_t6_decode_restart(&s->decoder.t4_t6, s->image_width); + case 0: + pre_encoded_restart(&s->decoder.no_decoder); + s->image_put_handler = (t4_image_put_handler_t) pre_encoded_put; break; - case T4_COMPRESSION_ITU_T42: - t42_decode_restart(&s->decoder.t42); + case T4_COMPRESSION_T4_1D | T4_COMPRESSION_T4_2D | T4_COMPRESSION_T6: + t4_t6_decode_restart(&s->decoder.t4_t6, s->metadata.image_width); + s->image_put_handler = (t4_image_put_handler_t) t4_t6_decode_put; break; -#if defined(SPANDSP_SUPPORT_T43) - case T4_COMPRESSION_ITU_T43: - t43_decode_restart(&s->decoder.t43); + case T4_COMPRESSION_T85 | T4_COMPRESSION_T85_L0: + t85_decode_restart(&s->decoder.t85); + s->image_put_handler = (t4_image_put_handler_t) t85_decode_put; + break; +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + t88_decode_restart(&s->decoder.t88); + s->image_put_handler = (t4_image_put_handler_t) t88_decode_put; break; #endif - case T4_COMPRESSION_ITU_T85: - case T4_COMPRESSION_ITU_T85_L0: - t85_decode_restart(&s->decoder.t85); + case T4_COMPRESSION_T42_T81: + t42_decode_restart(&s->decoder.t42); + s->image_put_handler = (t4_image_put_handler_t) t42_decode_put; break; + case T4_COMPRESSION_T43: + t43_decode_restart(&s->decoder.t43); + s->image_put_handler = (t4_image_put_handler_t) t43_decode_put; + break; +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + t45_decode_restart(&s->decoder.t45); + s->image_put_handler = (t4_image_put_handler_t) t45_decode_put; + break; +#endif } s->line_image_size = 0; s->tiff.image_size = 0; @@ -715,7 +1247,7 @@ static int tiff_row_write_handler(void *user_data, const uint8_t buf[], size_t l { if (s->tiff.image_size + len >= s->tiff.image_buffer_size) { - if ((t = realloc(s->tiff.image_buffer, s->tiff.image_buffer_size + 100*len)) == NULL) + if ((t = span_realloc(s->tiff.image_buffer, s->tiff.image_buffer_size + 100*len)) == NULL) return -1; s->tiff.image_buffer_size += 100*len; s->tiff.image_buffer = t; @@ -732,29 +1264,41 @@ SPAN_DECLARE(int) t4_rx_end_page(t4_rx_state_t *s) int length; length = 0; - switch (s->line_encoding) + + if (s->image_put_handler) + s->image_put_handler((void *) &s->decoder, NULL, 0); + + switch (s->current_decoder) { - case T4_COMPRESSION_ITU_T4_1D: - case T4_COMPRESSION_ITU_T4_2D: - case T4_COMPRESSION_ITU_T6: - t4_t6_decode_put(&s->decoder.t4_t6, NULL, 0); + case 0: + length = s->decoder.no_decoder.buf_ptr; + break; + case T4_COMPRESSION_T4_1D | T4_COMPRESSION_T4_2D | T4_COMPRESSION_T6: length = t4_t6_decode_get_image_length(&s->decoder.t4_t6); break; - case T4_COMPRESSION_ITU_T42: - t42_decode_put(&s->decoder.t42, NULL, 0); - length = t42_decode_get_image_length(&s->decoder.t42); - break; -#if defined(SPANDSP_SUPPORT_T43) - case T4_COMPRESSION_ITU_T43: - t43_decode_put(&s->decoder.t43, NULL, 0); - length = t43_decode_get_image_length(&s->decoder.t43); - break; -#endif - case T4_COMPRESSION_ITU_T85: - case T4_COMPRESSION_ITU_T85_L0: - t85_decode_put(&s->decoder.t85, NULL, 0); + case T4_COMPRESSION_T85 | T4_COMPRESSION_T85_L0: length = t85_decode_get_image_length(&s->decoder.t85); break; +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + length = t88_decode_get_image_length(&s->decoder.t88); + break; +#endif + case T4_COMPRESSION_T42_T81: + length = t42_decode_get_image_length(&s->decoder.t42); + if (s->decoder.t42.samples_per_pixel == 3) + s->tiff.image_type = T4_IMAGE_TYPE_COLOUR_8BIT; + else + s->tiff.image_type = T4_IMAGE_TYPE_GRAY_8BIT; + break; + case T4_COMPRESSION_T43: + length = t43_decode_get_image_length(&s->decoder.t43); + break; +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + length = t45_decode_get_image_length(&s->decoder.t45); + break; +#endif } if (length == 0) @@ -780,16 +1324,16 @@ SPAN_DECLARE(logging_state_t *) t4_rx_get_logging_state(t4_rx_state_t *s) } /*- End of function --------------------------------------------------------*/ -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_output_compressions) { - int allocated; + bool alloced; - allocated = FALSE; + alloced = false; if (s == NULL) { - if ((s = (t4_rx_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (t4_rx_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; - allocated = TRUE; + alloced = true; } #if defined(SPANDSP_SUPPORT_TIFF_FX) TIFF_FX_init(); @@ -800,15 +1344,23 @@ SPAN_DECLARE(t4_rx_state_t *) t4_rx_init(t4_rx_state_t *s, const char *file, int span_log(&s->logging, SPAN_LOG_FLOW, "Start rx document\n"); - /* Only provide for one form of coding throughout the file, even though the - coding on the wire could change between pages. */ - s->tiff.output_encoding = output_encoding; + s->supported_tiff_compressions = supported_output_compressions; +#if !defined(SPANDSP_SUPPORT_T88) + s->supported_tiff_compressions &= ~T4_COMPRESSION_T88; +#endif +#if !defined(SPANDSP_SUPPORT_T43) + s->supported_tiff_compressions &= ~T4_COMPRESSION_T43; +#endif +#if !defined(SPANDSP_SUPPORT_T45) + s->supported_tiff_compressions &= ~T4_COMPRESSION_T45; +#endif /* Set some default values */ s->metadata.x_resolution = T4_X_RESOLUTION_R8; s->metadata.y_resolution = T4_Y_RESOLUTION_FINE; s->current_page = 0; + s->current_decoder = 0; /* Default handler */ s->row_handler = tiff_row_write_handler; @@ -819,8 +1371,8 @@ SPAN_DECLARE(t4_rx_state_t *) t4_rx_init(t4_rx_state_t *s, const char *file, int s->tiff.pages_in_file = 0; if (open_tiff_output_file(s, file) < 0) { - if (allocated) - free(s); + if (alloced) + span_free(s); return NULL; } /* Save the file name for logging reports. */ @@ -834,22 +1386,7 @@ SPAN_DECLARE(int) t4_rx_release(t4_rx_state_t *s) { if (s->tiff.file) tiff_rx_release(s); - switch (s->line_encoding) - { - case T4_COMPRESSION_ITU_T4_1D: - case T4_COMPRESSION_ITU_T4_2D: - case T4_COMPRESSION_ITU_T6: - return t4_t6_decode_release(&s->decoder.t4_t6); - case T4_COMPRESSION_ITU_T42: - return t42_decode_release(&s->decoder.t42); -#if defined(SPANDSP_SUPPORT_T43) - case T4_COMPRESSION_ITU_T43: - return t43_decode_release(&s->decoder.t43); -#endif - case T4_COMPRESSION_ITU_T85: - case T4_COMPRESSION_ITU_T85_L0: - return t85_decode_release(&s->decoder.t85); - } + release_current_decoder(s); return -1; } /*- End of function --------------------------------------------------------*/ @@ -859,7 +1396,7 @@ SPAN_DECLARE(int) t4_rx_free(t4_rx_state_t *s) int ret; ret = t4_rx_release(s); - free(s); + span_free(s); return ret; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/t4_t6_decode.c b/libs/spandsp/src/t4_t6_decode.c index 03b24ae4f3..b163277e22 100644 --- a/libs/spandsp/src/t4_t6_decode.c +++ b/libs/spandsp/src/t4_t6_decode.c @@ -60,8 +60,8 @@ #include "config.h" #endif -#include #include +#include #include #include #include @@ -75,10 +75,16 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/bit_operations.h" #include "spandsp/async.h" @@ -89,9 +95,7 @@ #include "spandsp/t81_t82_arith_coding.h" #include "spandsp/t85.h" #include "spandsp/t42.h" -#if defined(SPANDSP_SUPPORT_T43) #include "spandsp/t43.h" -#endif #include "spandsp/t4_t6_decode.h" #include "spandsp/t4_t6_encode.h" @@ -99,9 +103,7 @@ #include "spandsp/private/t81_t82_arith_coding.h" #include "spandsp/private/t85.h" #include "spandsp/private/t42.h" -#if defined(SPANDSP_SUPPORT_T43) #include "spandsp/private/t43.h" -#endif #include "spandsp/private/t4_t6_decode.h" #include "spandsp/private/t4_t6_encode.h" #include "spandsp/private/image_translate.h" @@ -138,17 +140,17 @@ static int free_buffers(t4_t6_decode_state_t *s) { if (s->cur_runs) { - free(s->cur_runs); + span_free(s->cur_runs); s->cur_runs = NULL; } if (s->ref_runs) { - free(s->ref_runs); + span_free(s->ref_runs); s->ref_runs = NULL; } if (s->row_buf) { - free(s->row_buf); + span_free(s->row_buf); s->row_buf = NULL; } s->bytes_per_row = 0; @@ -380,12 +382,12 @@ static int put_bits(t4_t6_decode_state_t *s, uint32_t bit_string, int quantity) need a minimum of 13 bits in the buffer to proceed with any bit stream analysis. */ if ((s->rx_bits += quantity) < 13) - return FALSE; + return false; if (s->consecutive_eols) { /* Check if the image has already terminated. */ if (s->consecutive_eols >= EOLS_TO_END_ANY_RX_PAGE) - return TRUE; + return true; /* Check if the image hasn't even started. */ if (s->consecutive_eols < 0) { @@ -396,14 +398,14 @@ static int put_bits(t4_t6_decode_state_t *s, uint32_t bit_string, int quantity) { s->rx_bitstream >>= 1; if (--s->rx_bits < 13) - return FALSE; + return false; } /* We have an EOL, so now the page begins and we can proceed to process the bit stream as image data. */ s->consecutive_eols = 0; - if (s->encoding == T4_COMPRESSION_ITU_T4_1D) + if (s->encoding == T4_COMPRESSION_T4_1D) { - s->row_is_2d = FALSE; + s->row_is_2d = false; force_drop_rx_bits(s, 12); } else @@ -439,12 +441,12 @@ static int put_bits(t4_t6_decode_state_t *s, uint32_t bit_string, int quantity) we should count up both EOLs, unless there is some bogus partial row ahead of them. */ s->consecutive_eols++; - if (s->encoding == T4_COMPRESSION_ITU_T6) + if (s->encoding == T4_COMPRESSION_T6) { if (s->consecutive_eols >= EOLS_TO_END_T6_RX_PAGE) { s->consecutive_eols = EOLS_TO_END_ANY_RX_PAGE; - return TRUE; + return true; } } else @@ -452,7 +454,7 @@ static int put_bits(t4_t6_decode_state_t *s, uint32_t bit_string, int quantity) if (s->consecutive_eols >= EOLS_TO_END_T4_RX_PAGE) { s->consecutive_eols = EOLS_TO_END_ANY_RX_PAGE; - return TRUE; + return true; } } } @@ -464,9 +466,9 @@ static int put_bits(t4_t6_decode_state_t *s, uint32_t bit_string, int quantity) add_run_to_row(s); s->consecutive_eols = 0; if (put_decoded_row(s)) - return TRUE; + return true; } - if (s->encoding == T4_COMPRESSION_ITU_T4_2D) + if (s->encoding == T4_COMPRESSION_T4_2D) { s->row_is_2d = !(s->rx_bitstream & 0x1000); force_drop_rx_bits(s, 13); @@ -475,7 +477,7 @@ static int put_bits(t4_t6_decode_state_t *s, uint32_t bit_string, int quantity) { force_drop_rx_bits(s, 12); } - s->in_black = FALSE; + s->in_black = false; s->black_white = 0; s->run_length = 0; s->row_len = 0; @@ -608,7 +610,7 @@ static int put_bits(t4_t6_decode_state_t *s, uint32_t bit_string, int quantity) s->a0 += t4_1d_black_table[bits].param; break; case S_TermB: - s->in_black = FALSE; + s->in_black = false; if (s->row_len < s->image_width) { s->run_length += t4_1d_black_table[bits].param; @@ -642,7 +644,7 @@ static int put_bits(t4_t6_decode_state_t *s, uint32_t bit_string, int quantity) s->a0 += t4_1d_white_table[bits].param; break; case S_TermW: - s->in_black = TRUE; + s->in_black = true; if (s->row_len < s->image_width) { s->run_length += t4_1d_white_table[bits].param; @@ -663,7 +665,7 @@ static int put_bits(t4_t6_decode_state_t *s, uint32_t bit_string, int quantity) if (s->a0 >= s->image_width) s->a0 = s->image_width - 1; - if (s->encoding == T4_COMPRESSION_ITU_T6) + if (s->encoding == T4_COMPRESSION_T6) { /* T.6 has no EOL markers. We sense the end of a line by its length alone. */ /* The last test here is a backstop protection, so a corrupt image cannot @@ -675,15 +677,15 @@ static int put_bits(t4_t6_decode_state_t *s, uint32_t bit_string, int quantity) if (s->run_length > 0) add_run_to_row(s); if (put_decoded_row(s)) - return TRUE; - s->in_black = FALSE; + return true; + s->in_black = false; s->black_white = 0; s->run_length = 0; s->row_len = 0; } } } - return FALSE; + return false; } /*- End of function --------------------------------------------------------*/ @@ -714,7 +716,7 @@ SPAN_DECLARE(int) t4_t6_decode_put_bit(t4_t6_decode_state_t *s, int bit) if (bit < 0) { t4_t6_decode_rx_status(s, bit); - return TRUE; + return true; } s->compressed_image_size++; if (put_bits(s, bit & 1, 1)) @@ -778,9 +780,9 @@ SPAN_DECLARE(int) t4_t6_decode_set_encoding(t4_t6_decode_state_t *s, int encodin { switch (encoding) { - case T4_COMPRESSION_ITU_T4_1D: - case T4_COMPRESSION_ITU_T4_2D: - case T4_COMPRESSION_ITU_T6: + case T4_COMPRESSION_T4_1D: + case T4_COMPRESSION_T4_2D: + case T4_COMPRESSION_T6: s->encoding = encoding; return 0; } @@ -824,10 +826,10 @@ SPAN_DECLARE(int) t4_t6_decode_restart(t4_t6_decode_state_t *s, int image_width) if (s->bytes_per_row == 0 || image_width != s->image_width) { /* Allocate the space required for decoding the new row length. */ - if ((bufptr = (uint32_t *) realloc(s->cur_runs, run_space)) == NULL) + if ((bufptr = (uint32_t *) span_realloc(s->cur_runs, run_space)) == NULL) return -1; s->cur_runs = bufptr; - if ((bufptr = (uint32_t *) realloc(s->ref_runs, run_space)) == NULL) + if ((bufptr = (uint32_t *) span_realloc(s->ref_runs, run_space)) == NULL) return -1; s->ref_runs = bufptr; s->image_width = image_width; @@ -835,7 +837,7 @@ SPAN_DECLARE(int) t4_t6_decode_restart(t4_t6_decode_state_t *s, int image_width) bytes_per_row = (image_width + 7)/8; if (bytes_per_row != s->bytes_per_row) { - if ((bufptr8 = (uint8_t *) realloc(s->row_buf, bytes_per_row)) == NULL) + if ((bufptr8 = (uint8_t *) span_realloc(s->row_buf, bytes_per_row)) == NULL) return -1; s->row_buf = bufptr8; s->bytes_per_row = bytes_per_row; @@ -857,17 +859,17 @@ SPAN_DECLARE(int) t4_t6_decode_restart(t4_t6_decode_state_t *s, int image_width) s->pixels = 8; s->row_len = 0; - s->in_black = FALSE; + s->in_black = false; s->black_white = 0; s->b_cursor = 1; s->a_cursor = 0; s->b1 = s->image_width; s->a0 = 0; s->run_length = 0; - s->row_is_2d = (s->encoding == T4_COMPRESSION_ITU_T6); + s->row_is_2d = (s->encoding == T4_COMPRESSION_T6); /* We start at -1 EOLs for 1D and 2D decoding, as an indication we are waiting for the first EOL. T.6 coding starts without any preamble. */ - s->consecutive_eols = (s->encoding == T4_COMPRESSION_ITU_T6) ? 0 : -1; + s->consecutive_eols = (s->encoding == T4_COMPRESSION_T6) ? 0 : -1; if (s->cur_runs) memset(s->cur_runs, 0, run_space); @@ -892,7 +894,7 @@ SPAN_DECLARE(t4_t6_decode_state_t *) t4_t6_decode_init(t4_t6_decode_state_t *s, { if (s == NULL) { - if ((s = (t4_t6_decode_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (t4_t6_decode_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -919,7 +921,7 @@ SPAN_DECLARE(int) t4_t6_decode_free(t4_t6_decode_state_t *s) int ret; ret = t4_t6_decode_release(s); - free(s); + span_free(s); return ret; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/t4_t6_encode.c b/libs/spandsp/src/t4_t6_encode.c index 22885f4ac1..b092ecd3f0 100644 --- a/libs/spandsp/src/t4_t6_encode.c +++ b/libs/spandsp/src/t4_t6_encode.c @@ -57,8 +57,8 @@ #include "config.h" #endif -#include #include +#include #include #include #include @@ -72,10 +72,16 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/bit_operations.h" #include "spandsp/async.h" @@ -86,9 +92,7 @@ #include "spandsp/t81_t82_arith_coding.h" #include "spandsp/t85.h" #include "spandsp/t42.h" -#if defined(SPANDSP_SUPPORT_T43) #include "spandsp/t43.h" -#endif #include "spandsp/t4_t6_decode.h" #include "spandsp/t4_t6_encode.h" @@ -96,9 +100,7 @@ #include "spandsp/private/t81_t82_arith_coding.h" #include "spandsp/private/t85.h" #include "spandsp/private/t42.h" -#if defined(SPANDSP_SUPPORT_T43) #include "spandsp/private/t43.h" -#endif #include "spandsp/private/t4_t6_decode.h" #include "spandsp/private/t4_t6_encode.h" #include "spandsp/private/image_translate.h" @@ -373,17 +375,17 @@ static int free_buffers(t4_t6_encode_state_t *s) { if (s->cur_runs) { - free(s->cur_runs); + span_free(s->cur_runs); s->cur_runs = NULL; } if (s->ref_runs) { - free(s->ref_runs); + span_free(s->ref_runs); s->ref_runs = NULL; } if (s->bitstream) { - free(s->bitstream); + span_free(s->bitstream); s->bitstream = NULL; } s->bytes_per_row = 0; @@ -573,7 +575,7 @@ static void encode_eol(t4_t6_encode_state_t *s) uint32_t code; int length; - if (s->encoding == T4_COMPRESSION_ITU_T4_2D) + if (s->encoding == T4_COMPRESSION_T4_2D) { code = 0x0800 | ((!s->row_is_2d) << 12); length = 13; @@ -589,7 +591,7 @@ static void encode_eol(t4_t6_encode_state_t *s) /* We may need to pad the row to a minimum length, unless we are in T.6 mode. In T.6 we only come here at the end of the page to add the EOFB marker, which is like two 1D EOLs. */ - if (s->encoding != T4_COMPRESSION_ITU_T6) + if (s->encoding != T4_COMPRESSION_T6) { if (s->row_bits + length < s->min_bits_per_row) put_encoded_bits(s, 0, s->min_bits_per_row - (s->row_bits + length)); @@ -823,14 +825,14 @@ static int encode_row(t4_t6_encode_state_t *s, const uint8_t *row_buf, size_t le { switch (s->encoding) { - case T4_COMPRESSION_ITU_T6: + case T4_COMPRESSION_T6: /* T.6 compression is a trivial step up from T.4 2D, so we just throw it in here. T.6 is only used with error correction, so it does not need independantly compressed (i.e. 1D) lines to recover from data errors. It doesn't need EOLs, either. */ encode_2d_row(s, row_buf); break; - case T4_COMPRESSION_ITU_T4_2D: + case T4_COMPRESSION_T4_2D: encode_eol(s); if (s->row_is_2d) { @@ -840,17 +842,17 @@ static int encode_row(t4_t6_encode_state_t *s, const uint8_t *row_buf, size_t le else { encode_1d_row(s, row_buf); - s->row_is_2d = TRUE; + s->row_is_2d = true; } if (s->rows_to_next_1d_row <= 0) { /* Insert a row of 1D encoding */ - s->row_is_2d = FALSE; + s->row_is_2d = false; s->rows_to_next_1d_row = s->max_rows_to_next_1d_row - 1; } break; default: - case T4_COMPRESSION_ITU_T4_1D: + case T4_COMPRESSION_T4_1D: encode_eol(s); encode_1d_row(s, row_buf); break; @@ -864,7 +866,7 @@ static int finalise_page(t4_t6_encode_state_t *s) { int i; - if (s->encoding == T4_COMPRESSION_ITU_T6) + if (s->encoding == T4_COMPRESSION_T6) { /* Attach an EOFB (end of facsimile block == 2 x EOLs) to the end of the page */ for (i = 0; i < EOLS_TO_END_T6_TX_PAGE; i++) @@ -873,7 +875,7 @@ static int finalise_page(t4_t6_encode_state_t *s) else { /* Attach an RTC (return to control == 6 x EOLs) to the end of the page */ - s->row_is_2d = FALSE; + s->row_is_2d = false; for (i = 0; i < EOLS_TO_END_T4_TX_PAGE; i++) encode_eol(s); } @@ -982,14 +984,16 @@ SPAN_DECLARE(int) t4_t6_encode_set_encoding(t4_t6_encode_state_t *s, int encodin { switch (encoding) { - case T4_COMPRESSION_ITU_T6: - case T4_COMPRESSION_ITU_T4_2D: - case T4_COMPRESSION_ITU_T4_1D: + case T4_COMPRESSION_T6: + s->min_bits_per_row = 0; + /* Fall through */ + case T4_COMPRESSION_T4_2D: + case T4_COMPRESSION_T4_1D: s->encoding = encoding; /* Set this to the default value for the lowest resolution in the T.4 spec. */ s->max_rows_to_next_1d_row = 2; s->rows_to_next_1d_row = s->max_rows_to_next_1d_row - 1; - s->row_is_2d = FALSE; + s->row_is_2d = (s->encoding == T4_COMPRESSION_T6); return 0; } return -1; @@ -998,7 +1002,16 @@ SPAN_DECLARE(int) t4_t6_encode_set_encoding(t4_t6_encode_state_t *s, int encodin SPAN_DECLARE(void) t4_t6_encode_set_min_bits_per_row(t4_t6_encode_state_t *s, int bits) { - s->min_bits_per_row = bits; + switch (s->encoding) + { + case T4_COMPRESSION_T6: + s->min_bits_per_row = 0; + break; + case T4_COMPRESSION_T4_2D: + case T4_COMPRESSION_T4_1D: + s->min_bits_per_row = bits; + break; + } } /*- End of function --------------------------------------------------------*/ @@ -1015,13 +1028,13 @@ SPAN_DECLARE(int) t4_t6_encode_set_image_width(t4_t6_encode_state_t *s, int imag s->bytes_per_row = (s->image_width + 7)/8; run_space = (s->image_width + 4)*sizeof(uint32_t); - if ((bufptr = (uint32_t *) realloc(s->cur_runs, run_space)) == NULL) + if ((bufptr = (uint32_t *) span_realloc(s->cur_runs, run_space)) == NULL) return -1; s->cur_runs = bufptr; - if ((bufptr = (uint32_t *) realloc(s->ref_runs, run_space)) == NULL) + if ((bufptr = (uint32_t *) span_realloc(s->ref_runs, run_space)) == NULL) return -1; s->ref_runs = bufptr; - if ((bufptr8 = (uint8_t *) realloc(s->bitstream, (s->image_width + 1)*sizeof(uint16_t))) == NULL) + if ((bufptr8 = (uint8_t *) span_realloc(s->bitstream, (s->image_width + 1)*sizeof(uint16_t))) == NULL) return -1; s->bitstream = bufptr8; } @@ -1029,6 +1042,12 @@ SPAN_DECLARE(int) t4_t6_encode_set_image_width(t4_t6_encode_state_t *s, int imag } /*- End of function --------------------------------------------------------*/ +SPAN_DECLARE(int) t4_t6_encode_set_image_length(t4_t6_encode_state_t *s, int image_length) +{ + return 0; +} +/*- End of function --------------------------------------------------------*/ + SPAN_DECLARE(uint32_t) t4_t6_encode_get_image_width(t4_t6_encode_state_t *s) { return s->image_width; @@ -1056,9 +1075,12 @@ SPAN_DECLARE(void) t4_t6_encode_set_max_2d_rows_per_1d_row(t4_t6_encode_state_t } y_res_table[] = { {T4_Y_RESOLUTION_STANDARD, 2}, + {T4_Y_RESOLUTION_100, 2}, {T4_Y_RESOLUTION_FINE, 4}, + {T4_Y_RESOLUTION_200, 4}, {T4_Y_RESOLUTION_300, 6}, {T4_Y_RESOLUTION_SUPERFINE, 8}, + {T4_Y_RESOLUTION_400, 8}, {T4_Y_RESOLUTION_600, 12}, {T4_Y_RESOLUTION_800, 16}, {T4_Y_RESOLUTION_1200, 24}, @@ -1084,7 +1106,7 @@ SPAN_DECLARE(void) t4_t6_encode_set_max_2d_rows_per_1d_row(t4_t6_encode_state_t } s->max_rows_to_next_1d_row = max; s->rows_to_next_1d_row = max - 1; - s->row_is_2d = FALSE; + s->row_is_2d = false; } /*- End of function --------------------------------------------------------*/ @@ -1094,11 +1116,11 @@ SPAN_DECLARE(logging_state_t *) t4_t6_encode_get_logging_state(t4_t6_encode_stat } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) t4_t6_encode_restart(t4_t6_encode_state_t *s, int image_width) +SPAN_DECLARE(int) t4_t6_encode_restart(t4_t6_encode_state_t *s, int image_width, int image_length) { /* Allow for pages being of different width. */ t4_t6_encode_set_image_width(s, image_width); - s->row_is_2d = (s->encoding == T4_COMPRESSION_ITU_T6); + s->row_is_2d = (s->encoding == T4_COMPRESSION_T6); s->rows_to_next_1d_row = s->max_rows_to_next_1d_row - 1; s->tx_bitstream = 0; @@ -1125,12 +1147,13 @@ SPAN_DECLARE(int) t4_t6_encode_restart(t4_t6_encode_state_t *s, int image_width) SPAN_DECLARE(t4_t6_encode_state_t *) t4_t6_encode_init(t4_t6_encode_state_t *s, int encoding, int image_width, + int image_length, t4_row_read_handler_t handler, void *user_data) { if (s == NULL) { - if ((s = (t4_t6_encode_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (t4_t6_encode_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -1142,7 +1165,7 @@ SPAN_DECLARE(t4_t6_encode_state_t *) t4_t6_encode_init(t4_t6_encode_state_t *s, s->row_read_user_data = user_data; s->max_rows_to_next_1d_row = 2; - t4_t6_encode_restart(s, image_width); + t4_t6_encode_restart(s, image_width, image_length); return s; } @@ -1160,7 +1183,7 @@ SPAN_DECLARE(int) t4_t6_encode_free(t4_t6_encode_state_t *s) int ret; ret = t4_t6_encode_release(s); - free(s); + span_free(s); return ret; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/t4_tx.c b/libs/spandsp/src/t4_tx.c index 5a964f6f7f..49bcd90915 100644 --- a/libs/spandsp/src/t4_tx.c +++ b/libs/spandsp/src/t4_tx.c @@ -29,8 +29,8 @@ #include "config.h" #endif -#include #include +#include #include #include #include @@ -44,10 +44,16 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/bit_operations.h" #include "spandsp/async.h" @@ -58,9 +64,7 @@ #include "spandsp/t81_t82_arith_coding.h" #include "spandsp/t85.h" #include "spandsp/t42.h" -#if defined(SPANDSP_SUPPORT_T43) #include "spandsp/t43.h" -#endif #include "spandsp/t4_t6_decode.h" #include "spandsp/t4_t6_encode.h" @@ -68,9 +72,7 @@ #include "spandsp/private/t81_t82_arith_coding.h" #include "spandsp/private/t85.h" #include "spandsp/private/t42.h" -#if defined(SPANDSP_SUPPORT_T43) #include "spandsp/private/t43.h" -#endif #include "spandsp/private/t4_t6_decode.h" #include "spandsp/private/t4_t6_encode.h" #include "spandsp/private/image_translate.h" @@ -86,30 +88,87 @@ /*! The number of centimetres in one inch */ #define CM_PER_INCH 2.54f -static void t4_tx_set_image_length(t4_tx_state_t *s, int image_length); +typedef struct +{ + uint8_t *buf; + int ptr; + int row; + int size; + int bit_mask; +} packer_t; + +static void t4_tx_set_image_type(t4_tx_state_t *s, int image_type); +static void set_image_width(t4_tx_state_t *s, uint32_t image_width); +static void set_image_length(t4_tx_state_t *s, uint32_t image_length); + +static const float x_res_table[] = +{ + 100.0f*100.0f/CM_PER_INCH, + 102.0f*100.0f/CM_PER_INCH, + 200.0f*100.0f/CM_PER_INCH, + 204.0f*100.0f/CM_PER_INCH, + 300.0f*100.0f/CM_PER_INCH, + 400.0f*100.0f/CM_PER_INCH, + 408.0f*100.0f/CM_PER_INCH, + 600.0f*100.0f/CM_PER_INCH, + 1200.0f*100.0f/CM_PER_INCH, + -1.00f +}; + +static const float y_res_table[] = +{ + 38.50f*100.0f, + 100.0f*100.0f/CM_PER_INCH, + 77.00f*100.0f, + 200.0f*100.0f/CM_PER_INCH, + 300.0f*100.0f/CM_PER_INCH, + 154.00f*100.0f, + 400.0f*100.0f/CM_PER_INCH, + 600.0f*100.0f/CM_PER_INCH, + 800.0f*100.0f/CM_PER_INCH, + 1200.0f*100.0f/CM_PER_INCH, + -1.00f +}; + +static const int resolution_map[10][9] = +{ + /* x = 100 102 200 204 300 400 408 600 1200 */ + { 0, 0, 0, T4_RESOLUTION_R8_STANDARD, 0, 0, 0, 0, 0}, /* y = 3.85/mm */ + {T4_RESOLUTION_100_100, 0, T4_RESOLUTION_200_100, 0, 0, 0, 0, 0, 0}, /* y = 100 */ + { 0, 0, 0, T4_RESOLUTION_R8_FINE, 0, 0, 0, 0, 0}, /* y = 7.7/mm */ + { 0, 0, T4_RESOLUTION_200_200, 0, 0, 0, 0, 0, 0}, /* y = 200 */ + { 0, 0, 0, 0, T4_RESOLUTION_300_300, 0, 0, 0, 0}, /* y = 300 */ + { 0, 0, 0, T4_RESOLUTION_R8_SUPERFINE, 0, 0, T4_RESOLUTION_R16_SUPERFINE, 0, 0}, /* y = 154/mm */ + { 0, 0, T4_RESOLUTION_200_400, 0, 0, T4_RESOLUTION_400_400, 0, 0, 0}, /* y = 400 */ + { 0, 0, 0, 0, T4_RESOLUTION_300_600, 0, 0, T4_RESOLUTION_600_600, 0}, /* y = 600 */ + { 0, 0, 0, 0, 0, T4_RESOLUTION_400_800, 0, 0, 0}, /* y = 800 */ + { 0, 0, 0, 0, 0, 0, 0, T4_RESOLUTION_600_1200, T4_RESOLUTION_1200_1200} /* y = 1200 */ +}; #if defined(SPANDSP_SUPPORT_TIFF_FX) /* TIFF-FX related extensions to the tag set supported by libtiff */ + static const TIFFFieldInfo tiff_fx_tiff_field_info[] = { - {TIFFTAG_INDEXED, 1, 1, TIFF_SHORT, FIELD_CUSTOM, FALSE, FALSE, (char *) "Indexed"}, - {TIFFTAG_GLOBALPARAMETERSIFD, 1, 1, TIFF_LONG, FIELD_CUSTOM, FALSE, FALSE, (char *) "GlobalParametersIFD"}, - {TIFFTAG_PROFILETYPE, 1, 1, TIFF_LONG, FIELD_CUSTOM, FALSE, FALSE, (char *) "ProfileType"}, - {TIFFTAG_FAXPROFILE, 1, 1, TIFF_BYTE, FIELD_CUSTOM, FALSE, FALSE, (char *) "FaxProfile"}, - {TIFFTAG_CODINGMETHODS, 1, 1, TIFF_LONG, FIELD_CUSTOM, FALSE, FALSE, (char *) "CodingMethods"}, - {TIFFTAG_VERSIONYEAR, 4, 4, TIFF_BYTE, FIELD_CUSTOM, FALSE, FALSE, (char *) "VersionYear"}, - {TIFFTAG_MODENUMBER, 1, 1, TIFF_BYTE, FIELD_CUSTOM, FALSE, FALSE, (char *) "ModeNumber"}, - {TIFFTAG_DECODE, TIFF_VARIABLE, TIFF_VARIABLE, TIFF_SRATIONAL, FIELD_CUSTOM, FALSE, TRUE, (char *) "Decode"}, - {TIFFTAG_IMAGEBASECOLOR, TIFF_VARIABLE, TIFF_VARIABLE, TIFF_SHORT, FIELD_CUSTOM, FALSE, TRUE, (char *) "ImageBaseColor"}, - {TIFFTAG_T82OPTIONS, 1, 1, TIFF_LONG, FIELD_CUSTOM, FALSE, FALSE, (char *) "T82Options"}, - {TIFFTAG_STRIPROWCOUNTS, TIFF_VARIABLE, TIFF_VARIABLE, TIFF_LONG, FIELD_CUSTOM, FALSE, TRUE, (char *) "StripRowCounts"}, - {TIFFTAG_IMAGELAYER, 2, 2, TIFF_LONG, FIELD_CUSTOM, FALSE, FALSE, (char *) "ImageLayer"}, + {TIFFTAG_INDEXED, 1, 1, TIFF_SHORT, FIELD_CUSTOM, false, false, (char *) "Indexed"}, + {TIFFTAG_GLOBALPARAMETERSIFD, 1, 1, TIFF_IFD8, FIELD_CUSTOM, false, false, (char *) "GlobalParametersIFD"}, + {TIFFTAG_PROFILETYPE, 1, 1, TIFF_LONG, FIELD_CUSTOM, false, false, (char *) "ProfileType"}, + {TIFFTAG_FAXPROFILE, 1, 1, TIFF_BYTE, FIELD_CUSTOM, false, false, (char *) "FaxProfile"}, + {TIFFTAG_CODINGMETHODS, 1, 1, TIFF_LONG, FIELD_CUSTOM, false, false, (char *) "CodingMethods"}, + {TIFFTAG_VERSIONYEAR, 4, 4, TIFF_BYTE, FIELD_CUSTOM, false, false, (char *) "VersionYear"}, + {TIFFTAG_MODENUMBER, 1, 1, TIFF_BYTE, FIELD_CUSTOM, false, false, (char *) "ModeNumber"}, + {TIFFTAG_DECODE, TIFF_VARIABLE, TIFF_VARIABLE, TIFF_SRATIONAL, FIELD_CUSTOM, false, true, (char *) "Decode"}, + {TIFFTAG_IMAGEBASECOLOR, TIFF_VARIABLE, TIFF_VARIABLE, TIFF_SHORT, FIELD_CUSTOM, false, true, (char *) "ImageBaseColor"}, + {TIFFTAG_T82OPTIONS, 1, 1, TIFF_LONG, FIELD_CUSTOM, false, false, (char *) "T82Options"}, + {TIFFTAG_STRIPROWCOUNTS, TIFF_VARIABLE, TIFF_VARIABLE, TIFF_LONG, FIELD_CUSTOM, false, true, (char *) "StripRowCounts"}, + {TIFFTAG_IMAGELAYER, 2, 2, TIFF_LONG, FIELD_CUSTOM, false, false, (char *) "ImageLayer"}, }; +#if TIFFLIB_VERSION >= 20120615 static TIFFField tiff_fx_tiff_fields[] = { { TIFFTAG_INDEXED, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "Indexed" }, - { TIFFTAG_GLOBALPARAMETERSIFD, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "GlobalParametersIFD", NULL }, + { TIFFTAG_GLOBALPARAMETERSIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, (char *) "GlobalParametersIFD", NULL }, { TIFFTAG_PROFILETYPE, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "ProfileType", NULL }, { TIFFTAG_FAXPROFILE, 1, 1, TIFF_BYTE, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "FaxProfile", NULL }, { TIFFTAG_CODINGMETHODS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "CodingMethods", NULL }, @@ -123,6 +182,7 @@ static TIFFField tiff_fx_tiff_fields[] = }; TIFFFieldArray tiff_fx_field_array = { tfiatOther, 0, 12, tiff_fx_tiff_fields }; +#endif static TIFFExtendProc _ParentExtender = NULL; @@ -140,11 +200,11 @@ static void TIFFFXDefaultDirectory(TIFF *tif) SPAN_DECLARE(void) TIFF_FX_init(void) { - static int first_time = TRUE; + static int first_time = true; if (!first_time) return; - first_time = FALSE; + first_time = false; /* Grab the inherited method and install */ _ParentExtender = TIFFSetTagExtender(TIFFFXDefaultDirectory); @@ -152,11 +212,135 @@ SPAN_DECLARE(void) TIFF_FX_init(void) /*- End of function --------------------------------------------------------*/ #endif -static int test_resolution(int res_unit, float actual, float expected) +static int code_to_x_resolution(int code) { - if (res_unit == RESUNIT_INCH) - actual *= 1.0f/CM_PER_INCH; - return (expected*0.95f <= actual && actual <= expected*1.05f); + static const int xxx[] = + { + T4_X_RESOLUTION_R8, /* R8 x standard */ + T4_X_RESOLUTION_R8, /* R8 x fine */ + T4_X_RESOLUTION_R8, /* R8 x superfine */ + T4_X_RESOLUTION_R16, /* R16 x superfine */ + T4_X_RESOLUTION_100, /* 100x100 */ + T4_X_RESOLUTION_200, /* 200x100 */ + T4_X_RESOLUTION_200, /* 200x200 */ + T4_X_RESOLUTION_200, /* 200x400 */ + T4_X_RESOLUTION_300, /* 300x300 */ + T4_X_RESOLUTION_300, /* 300x600 */ + T4_X_RESOLUTION_400, /* 400x400 */ + T4_X_RESOLUTION_400, /* 400x800 */ + T4_X_RESOLUTION_600, /* 600x600 */ + T4_X_RESOLUTION_600, /* 600x1200 */ + T4_X_RESOLUTION_1200 /* 1200x1200 */ + }; + int entry; + + entry = top_bit(code); + if (entry < 0 || entry > 14) + return 0; + return xxx[entry]; +} +/*- End of function --------------------------------------------------------*/ + +static int code_to_y_resolution(int code) +{ + static const int yyy[] = + { + T4_Y_RESOLUTION_STANDARD, /* R8 x standard */ + T4_Y_RESOLUTION_FINE, /* R8 x fine */ + T4_Y_RESOLUTION_SUPERFINE, /* R8 x superfine */ + T4_Y_RESOLUTION_SUPERFINE, /* R16 x superfine */ + T4_Y_RESOLUTION_100, /* 100x100 */ + T4_Y_RESOLUTION_100, /* 200x100 */ + T4_Y_RESOLUTION_200, /* 200x200 */ + T4_Y_RESOLUTION_400, /* 200x400 */ + T4_Y_RESOLUTION_300, /* 300x300 */ + T4_Y_RESOLUTION_600, /* 300x600 */ + T4_Y_RESOLUTION_400, /* 400x400 */ + T4_Y_RESOLUTION_800, /* 400x800 */ + T4_Y_RESOLUTION_600, /* 600x600 */ + T4_Y_RESOLUTION_1200, /* 600x1200 */ + T4_Y_RESOLUTION_1200 /* 1200x1200 */ + }; + int entry; + + entry = top_bit(code); + if (entry < 0 || entry > 14) + return 0; + return yyy[entry]; +} +/*- End of function --------------------------------------------------------*/ + +static int match_resolution(float actual, const float table[]) +{ + int i; + int best_entry; + float best_ratio; + float ratio; + + if (actual == 0.0f) + return -1; + + best_ratio = 0.0f; + best_entry = -1; + for (i = 0; table[i] > 0.0f; i++) + { + if (actual > table[i]) + ratio = table[i]/actual; + else + ratio = actual/table[i]; + if (ratio > best_ratio) + { + best_entry = i; + best_ratio = ratio; + } + } + if (best_ratio < 0.95f) + return -1; + return best_entry; +} +/*- End of function --------------------------------------------------------*/ + +static int best_colour_resolution(float actual, int allowed_resolutions) +{ + static const struct + { + float resolution; + int resolution_code; + } x_res_table[] = + { + { 100.0f*100.0f/CM_PER_INCH, T4_RESOLUTION_100_100}, + { 200.0f*100.0f/CM_PER_INCH, T4_RESOLUTION_200_200}, + { 300.0f*100.0f/CM_PER_INCH, T4_RESOLUTION_300_300}, + { 400.0f*100.0f/CM_PER_INCH, T4_RESOLUTION_400_400}, + { 600.0f*100.0f/CM_PER_INCH, T4_RESOLUTION_600_600}, + {1200.0f*100.0f/CM_PER_INCH, T4_RESOLUTION_1200_1200}, + { -1.00f, -1} + }; + int i; + int best_entry; + float best_ratio; + float ratio; + + if (actual == 0.0f) + return -1; + + best_ratio = 0.0f; + best_entry = -1; + for (i = 0; x_res_table[i].resolution > 0.0f; i++) + { + if (!(allowed_resolutions & x_res_table[i].resolution_code)) + continue; + if (actual > x_res_table[i].resolution) + ratio = x_res_table[i].resolution/actual; + else + ratio = actual/x_res_table[i].resolution; + if (ratio > best_ratio) + { + best_entry = i; + best_ratio = ratio; + } + } + return x_res_table[best_entry].resolution_code; } /*- End of function --------------------------------------------------------*/ @@ -177,12 +361,13 @@ static int read_colour_map(t4_tx_state_t *s, int bits_per_sample) return -1; /* TODO: This only allows for 8 bit deep maps */ - if ((s->colour_map = realloc(s->colour_map, 3*256)) == NULL) - return -1; span_log(&s->logging, SPAN_LOG_FLOW, "Got a colour map\n"); + s->colour_map_entries = 1 << bits_per_sample; + if ((s->colour_map = span_realloc(s->colour_map, 3*s->colour_map_entries)) == NULL) + return -1; #if 0 /* Sweep the colormap in the proper order */ - for (i = 0; i < (1 << bits_per_sample); i++) + for (i = 0; i < s->colour_map_entries; i++) { s->colour_map[3*i + 0] = (map_L[i] >> 8) & 0xFF; s->colour_map[3*i + 1] = (map_a[i] >> 8) & 0xFF; @@ -191,15 +376,15 @@ static int read_colour_map(t4_tx_state_t *s, int bits_per_sample) } #else /* Sweep the colormap in the order that seems to work for l04x_02x.tif */ - for (i = 0; i < (1 << bits_per_sample); i++) + for (i = 0; i < s->colour_map_entries; i++) { - s->colour_map[0*256 + i] = (map_L[i] >> 8) & 0xFF; - s->colour_map[1*256 + i] = (map_a[i] >> 8) & 0xFF; - s->colour_map[2*256 + i] = (map_b[i] >> 8) & 0xFF; + s->colour_map[0*s->colour_map_entries + i] = (map_L[i] >> 8) & 0xFF; + s->colour_map[1*s->colour_map_entries + i] = (map_a[i] >> 8) & 0xFF; + s->colour_map[2*s->colour_map_entries + i] = (map_b[i] >> 8) & 0xFF; } #endif - lab_to_srgb(&s->lab_params, s->colour_map, s->colour_map, 256); - for (i = 0; i < (1 << bits_per_sample); i++) + lab_to_srgb(&s->lab_params, s->colour_map, s->colour_map, s->colour_map_entries); + for (i = 0; i < s->colour_map_entries; i++) span_log(&s->logging, SPAN_LOG_FLOW, "Map %3d - %5d %5d %5d\n", i, s->colour_map[3*i], s->colour_map[3*i + 1], s->colour_map[3*i + 2]); return 0; } @@ -208,36 +393,6 @@ static int read_colour_map(t4_tx_state_t *s, int bits_per_sample) static int get_tiff_directory_info(t4_tx_state_t *s) { - static const struct - { - float resolution; - int code; - } x_res_table[] = - { - { 102.0f/CM_PER_INCH, T4_X_RESOLUTION_R4}, - { 204.0f/CM_PER_INCH, T4_X_RESOLUTION_R8}, - { 300.0f/CM_PER_INCH, T4_X_RESOLUTION_300}, - { 408.0f/CM_PER_INCH, T4_X_RESOLUTION_R16}, - { 600.0f/CM_PER_INCH, T4_X_RESOLUTION_600}, - { 800.0f/CM_PER_INCH, T4_X_RESOLUTION_800}, - {1200.0f/CM_PER_INCH, T4_X_RESOLUTION_1200}, - { -1.00f, -1} - }; - static const struct - { - float resolution; - int code; - } y_res_table[] = - { - { 38.50f, T4_Y_RESOLUTION_STANDARD}, - { 77.00f, T4_Y_RESOLUTION_FINE}, - { 300.0f/CM_PER_INCH, T4_Y_RESOLUTION_300}, - { 154.00f, T4_Y_RESOLUTION_SUPERFINE}, - { 600.0f/CM_PER_INCH, T4_Y_RESOLUTION_600}, - { 800.0f/CM_PER_INCH, T4_Y_RESOLUTION_800}, - {1200.0f/CM_PER_INCH, T4_Y_RESOLUTION_1200}, - { -1.00f, -1} - }; #if defined(SPANDSP_SUPPORT_TIFF_FX) static const char *tiff_fx_fax_profiles[] = { @@ -251,17 +406,30 @@ static int get_tiff_directory_info(t4_tx_state_t *s) }; char *u; char uu[10]; + float *fl_parms; + uint64_t diroff; + float lmin; + float lmax; + float amin; + float amax; + float bmin; + float bmax; uint8_t parm8; +#endif +#if defined(SPANDSP_SUPPORT_TIFF_FX) uint16_t parm16; #endif uint32_t parm32; + int best_x_entry; + int best_y_entry; float x_resolution; float y_resolution; - int i; t4_tx_tiff_state_t *t; uint16_t bits_per_sample; uint16_t samples_per_pixel; uint16_t res_unit; + uint16_t YCbCrSubsample_horiz; + uint16_t YCbCrSubsample_vert; t = &s->tiff; bits_per_sample = 1; @@ -272,6 +440,8 @@ static int get_tiff_directory_info(t4_tx_state_t *s) t->image_type = T4_IMAGE_TYPE_BILEVEL; else if (samples_per_pixel == 3 && bits_per_sample == 1) t->image_type = T4_IMAGE_TYPE_COLOUR_BILEVEL; + else if (samples_per_pixel == 4 && bits_per_sample == 1) + t->image_type = T4_IMAGE_TYPE_COLOUR_BILEVEL; else if (samples_per_pixel == 1 && bits_per_sample == 8) t->image_type = T4_IMAGE_TYPE_GRAY_8BIT; else if (samples_per_pixel == 1 && bits_per_sample > 8) @@ -282,74 +452,109 @@ static int get_tiff_directory_info(t4_tx_state_t *s) t->image_type = T4_IMAGE_TYPE_COLOUR_12BIT; else return -1; -#if 0 - /* Limit ourselves to plain black and white pages */ - if (t->image_type != T4_IMAGE_TYPE_BILEVEL) - return -1; + +#if defined(SPANDSP_SUPPORT_TIFF_FX) + parm16 = 0; + if (TIFFGetField(t->tiff_file, TIFFTAG_INDEXED, &parm16)) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Indexed %s (%u)\n", (parm16) ? "palette image" : "non-palette image", parm16); + if (parm16 == 1) + { + /* Its an indexed image, so its really a colour image, even though it may have only one sample per pixel */ + if (samples_per_pixel == 1 && bits_per_sample == 8) + t->image_type = T4_IMAGE_TYPE_COLOUR_8BIT; + else if (samples_per_pixel == 1 && bits_per_sample > 8) + t->image_type = T4_IMAGE_TYPE_COLOUR_12BIT; + } + } #endif + parm32 = 0; TIFFGetField(t->tiff_file, TIFFTAG_IMAGEWIDTH, &parm32); - t->image_width = - s->image_width = parm32; + t->image_width = parm32; parm32 = 0; TIFFGetField(t->tiff_file, TIFFTAG_IMAGELENGTH, &parm32); - t->image_length = - s->image_length = parm32; + t->image_length = parm32; + x_resolution = 0.0f; TIFFGetField(t->tiff_file, TIFFTAG_XRESOLUTION, &x_resolution); y_resolution = 0.0f; TIFFGetField(t->tiff_file, TIFFTAG_YRESOLUTION, &y_resolution); res_unit = RESUNIT_INCH; TIFFGetField(t->tiff_file, TIFFTAG_RESOLUTIONUNIT, &res_unit); + + t->x_resolution = x_resolution*100.0f; + t->y_resolution = y_resolution*100.0f; + if (res_unit == RESUNIT_INCH) + { + t->x_resolution /= CM_PER_INCH; + t->y_resolution /= CM_PER_INCH; + } + + if (((best_x_entry = match_resolution(t->x_resolution, x_res_table)) >= 0) + && + ((best_y_entry = match_resolution(t->y_resolution, y_res_table)) >= 0)) + { + t->resolution_code = resolution_map[best_y_entry][best_x_entry]; + } + else + { + t->resolution_code = 0; + } + t->photo_metric = PHOTOMETRIC_MINISWHITE; TIFFGetField(t->tiff_file, TIFFTAG_PHOTOMETRIC, &t->photo_metric); - set_lab_illuminant(&s->lab_params, 0.9638f, 1.0f, 0.8245f); - set_lab_gamut(&s->lab_params, 0, 100, -85, 85, -75, 125, FALSE); + /* The default luminant is D50 */ + set_lab_illuminant(&s->lab_params, 96.422f, 100.000f, 82.521f); + set_lab_gamut(&s->lab_params, 0, 100, -85, 85, -75, 125, false); t->compression = -1; TIFFGetField(t->tiff_file, TIFFTAG_COMPRESSION, &t->compression); + switch (t->compression) + { + case COMPRESSION_CCITT_T4: + span_log(&s->logging, SPAN_LOG_FLOW, "T.4\n"); + break; + case COMPRESSION_CCITT_T6: + span_log(&s->logging, SPAN_LOG_FLOW, "T.6\n"); + break; + case COMPRESSION_T85: + span_log(&s->logging, SPAN_LOG_FLOW, "T.85\n"); + break; + case COMPRESSION_T43: + span_log(&s->logging, SPAN_LOG_FLOW, "T.43\n"); + break; + case COMPRESSION_JPEG: + span_log(&s->logging, SPAN_LOG_FLOW, "JPEG\n"); + if (t->photo_metric == PHOTOMETRIC_ITULAB) + span_log(&s->logging, SPAN_LOG_FLOW, "ITULAB\n"); + break; + case COMPRESSION_NONE: + span_log(&s->logging, SPAN_LOG_FLOW, "No compression\n"); + break; + default: + span_log(&s->logging, SPAN_LOG_FLOW, "Unexpected compression %d\n", t->compression); + break; + } + +#if defined(SPANDSP_SUPPORT_TIFF_FX) + read_colour_map(s, bits_per_sample); +#endif + + YCbCrSubsample_horiz = 0; + YCbCrSubsample_vert = 0; + if (TIFFGetField(t->tiff_file, TIFFTAG_YCBCRSUBSAMPLING, &YCbCrSubsample_horiz, &YCbCrSubsample_vert)) + span_log(&s->logging, SPAN_LOG_FLOW, "Subsampling %d %d\n", YCbCrSubsample_horiz, YCbCrSubsample_vert); + t->fill_order = FILLORDER_LSB2MSB; - /* Allow a little range for the X resolution in centimeters. The spec doesn't pin down the - precise value. The other value should be exact. */ - /* Treat everything we can't match as R8. Most FAXes are this resolution anyway. */ - s->metadata.x_resolution = T4_X_RESOLUTION_R8; - for (i = 0; x_res_table[i].code > 0; i++) - { - if (test_resolution(res_unit, x_resolution, x_res_table[i].resolution)) - { - s->metadata.x_resolution = x_res_table[i].code; - break; - } - } - if (res_unit == RESUNIT_INCH) - t->image_x_resolution = x_resolution*100.0f/CM_PER_INCH; - else - t->image_x_resolution = x_resolution*100.0f; - - s->metadata.y_resolution = T4_Y_RESOLUTION_STANDARD; - for (i = 0; y_res_table[i].code > 0; i++) - { - if (test_resolution(res_unit, y_resolution, y_res_table[i].resolution)) - { - s->metadata.y_resolution = y_res_table[i].code; - break; - } - } - if (res_unit == RESUNIT_INCH) - t->image_y_resolution = y_resolution*100.0f/CM_PER_INCH; - else - t->image_y_resolution = y_resolution*100.0f; - - t4_tx_set_image_width(s, s->image_width); - t4_tx_set_image_length(s, s->image_length); - t4_tx_set_max_2d_rows_per_1d_row(s, -s->metadata.y_resolution); #if defined(SPANDSP_SUPPORT_TIFF_FX) if (TIFFGetField(t->tiff_file, TIFFTAG_PROFILETYPE, &parm32)) span_log(&s->logging, SPAN_LOG_FLOW, "Profile type %u\n", parm32); if (TIFFGetField(t->tiff_file, TIFFTAG_FAXPROFILE, &parm8)) span_log(&s->logging, SPAN_LOG_FLOW, "FAX profile %s (%u)\n", tiff_fx_fax_profiles[parm8], parm8); + if (TIFFGetField(t->tiff_file, TIFFTAG_CODINGMETHODS, &parm32)) span_log(&s->logging, SPAN_LOG_FLOW, "Coding methods 0x%x\n", parm32); if (TIFFGetField(t->tiff_file, TIFFTAG_VERSIONYEAR, &u)) @@ -360,6 +565,87 @@ static int get_tiff_directory_info(t4_tx_state_t *s) } if (TIFFGetField(t->tiff_file, TIFFTAG_MODENUMBER, &parm8)) span_log(&s->logging, SPAN_LOG_FLOW, "Mode number %u\n", parm8); + + switch (t->photo_metric) + { + case PHOTOMETRIC_ITULAB: +#if 1 + /* 8 bit version */ + lmin = 0.0f; + lmax = 100.0f; + amin = -21760.0f/255.0f; + amax = 21590.0f/255.0f; + bmin = -19200.0f/255.0f; + bmax = 31800.0f/255.0f; +#else + /* 12 bit version */ + lmin = 0.0f; + lmax = 100.0f; + amin = -348160.0f/4095.0f + amax = 347990.0f/4095.0f + bmin = -307200.0f/4095.0f + bmax = 511800.0f/4095.0f +#endif + break; + default: + lmin = 0.0f; + lmax = 0.0f; + amin = 0.0f; + amax = 0.0f; + bmin = 0.0f; + bmax = 0.0f; + break; + } + + if (TIFFGetField(t->tiff_file, TIFFTAG_DECODE, &parm16, &fl_parms)) + { + lmin = fl_parms[0]; + lmax = fl_parms[1]; + amin = fl_parms[2]; + amax = fl_parms[3]; + bmin = fl_parms[4]; + bmax = fl_parms[5]; + span_log(&s->logging, SPAN_LOG_FLOW, "Got decode tag %f %f %f %f %f %f\n", lmin, lmax, amin, amax, bmin, bmax); + } + + /* TIFFTAG_IMAGEBASECOLOR */ + + if (TIFFGetField(t->tiff_file, TIFFTAG_T82OPTIONS, &parm32)) + span_log(&s->logging, SPAN_LOG_FLOW, "T.82 options 0x%x\n", parm32); + + /* TIFFTAG_STRIPROWCOUNTS */ + /* TIFFTAG_IMAGELAYER */ + + /* If global parameters are present they should only be on the first page of the file. + However, as we scan the file we might as well look for them on any page. */ + if (TIFFGetField(t->tiff_file, TIFFTAG_GLOBALPARAMETERSIFD, &diroff)) + { + if (!TIFFReadCustomDirectory(t->tiff_file, diroff, &tiff_fx_field_array)) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Global parameter read failed\n"); + } + else + { + span_log(&s->logging, SPAN_LOG_FLOW, "Global parameters\n"); + if (TIFFGetField(t->tiff_file, TIFFTAG_PROFILETYPE, &parm32)) + span_log(&s->logging, SPAN_LOG_FLOW, " Profile type %u\n", parm32); + if (TIFFGetField(t->tiff_file, TIFFTAG_FAXPROFILE, &parm8)) + span_log(&s->logging, SPAN_LOG_FLOW, " FAX profile %s (%u)\n", tiff_fx_fax_profiles[parm8], parm8); + if (TIFFGetField(t->tiff_file, TIFFTAG_CODINGMETHODS, &parm32)) + span_log(&s->logging, SPAN_LOG_FLOW, " Coding methods 0x%x\n", parm32); + if (TIFFGetField(t->tiff_file, TIFFTAG_VERSIONYEAR, &u)) + { + memcpy(uu, u, 4); + uu[4] = '\0'; + span_log(&s->logging, SPAN_LOG_FLOW, " Version year \"%s\"\n", uu); + } + if (TIFFGetField(t->tiff_file, TIFFTAG_MODENUMBER, &parm8)) + span_log(&s->logging, SPAN_LOG_FLOW, " Mode number %u\n", parm8); + + if (!TIFFSetDirectory(t->tiff_file, (tdir_t) s->current_page)) + span_log(&s->logging, SPAN_LOG_FLOW, "Failed to set directory to page %d\n", s->current_page); + } + } #endif return 0; } @@ -367,44 +653,13 @@ static int get_tiff_directory_info(t4_tx_state_t *s) static int test_tiff_directory_info(t4_tx_state_t *s) { - static const struct - { - float resolution; - int code; - } x_res_table[] = - { - { 102.0f/CM_PER_INCH, T4_X_RESOLUTION_R4}, - { 204.0f/CM_PER_INCH, T4_X_RESOLUTION_R8}, - { 300.0f/CM_PER_INCH, T4_X_RESOLUTION_300}, - { 408.0f/CM_PER_INCH, T4_X_RESOLUTION_R16}, - { 600.0f/CM_PER_INCH, T4_X_RESOLUTION_600}, - { 800.0f/CM_PER_INCH, T4_X_RESOLUTION_800}, - {1200.0f/CM_PER_INCH, T4_X_RESOLUTION_1200}, - { -1.00f, -1} - }; - static const struct - { - float resolution; - int code; - } y_res_table[] = - { - { 38.50f, T4_Y_RESOLUTION_STANDARD}, - { 77.00f, T4_Y_RESOLUTION_FINE}, - { 300.0f/CM_PER_INCH, T4_Y_RESOLUTION_300}, - { 154.00f, T4_Y_RESOLUTION_SUPERFINE}, - { 600.0f/CM_PER_INCH, T4_Y_RESOLUTION_600}, - { 800.0f/CM_PER_INCH, T4_Y_RESOLUTION_800}, - {1200.0f/CM_PER_INCH, T4_Y_RESOLUTION_1200}, - { -1.00f, -1} - }; uint16_t res_unit; uint32_t parm32; - float x_resolution; - float y_resolution; uint16_t bits_per_sample; uint16_t samples_per_pixel; int image_type; - int i; + float x_resolution; + float y_resolution; t4_tx_tiff_state_t *t; t = &s->tiff; @@ -416,6 +671,8 @@ static int test_tiff_directory_info(t4_tx_state_t *s) image_type = T4_IMAGE_TYPE_BILEVEL; else if (samples_per_pixel == 3 && bits_per_sample == 1) image_type = T4_IMAGE_TYPE_COLOUR_BILEVEL; + else if (samples_per_pixel == 4 && bits_per_sample == 1) + image_type = T4_IMAGE_TYPE_COLOUR_BILEVEL; else if (samples_per_pixel == 1 && bits_per_sample == 8) image_type = T4_IMAGE_TYPE_GRAY_8BIT; else if (samples_per_pixel == 1 && bits_per_sample > 8) @@ -426,18 +683,14 @@ static int test_tiff_directory_info(t4_tx_state_t *s) image_type = T4_IMAGE_TYPE_COLOUR_12BIT; else image_type = -1; -#if 0 - /* Limit ourselves to plain black and white pages */ - if (t->image_type != T4_IMAGE_TYPE_BILEVEL) - return -1; -#endif if (t->image_type != image_type) return 1; parm32 = 0; TIFFGetField(t->tiff_file, TIFFTAG_IMAGEWIDTH, &parm32); - if (s->image_width != (int) parm32) - return 1; + if (s->tiff.image_width != (int) parm32) + return 2; + x_resolution = 0.0f; TIFFGetField(t->tiff_file, TIFFTAG_XRESOLUTION, &x_resolution); y_resolution = 0.0f; @@ -445,23 +698,18 @@ static int test_tiff_directory_info(t4_tx_state_t *s) res_unit = RESUNIT_INCH; TIFFGetField(t->tiff_file, TIFFTAG_RESOLUTIONUNIT, &res_unit); - /* Allow a little range for the X resolution in centimeters. The spec doesn't pin down the - precise value. The other value should be exact. */ - /* Treat everything we can't match as R8. Most FAXes are this resolution anyway. */ - for (i = 0; x_res_table[i].code > 0; i++) + x_resolution *= 100.0f; + y_resolution *= 100.0f; + if (res_unit == RESUNIT_INCH) { - if (test_resolution(res_unit, x_resolution, x_res_table[i].resolution)) - break; + x_resolution /= CM_PER_INCH; + y_resolution /= CM_PER_INCH; } - if (s->metadata.x_resolution != x_res_table[i].code) - return 1; - for (i = 0; y_res_table[i].code > 0; i++) - { - if (test_resolution(res_unit, y_resolution, y_res_table[i].resolution)) - break; - } - if (s->metadata.y_resolution != y_res_table[i].code) - return 1; + if (s->tiff.x_resolution != (int) x_resolution) + return 3; + if (s->tiff.y_resolution != (int) y_resolution) + return 4; + return 0; } /*- End of function --------------------------------------------------------*/ @@ -491,6 +739,19 @@ static int open_tiff_input_file(t4_tx_state_t *s, const char *file) } /*- End of function --------------------------------------------------------*/ +static int metadata_row_read_handler(void *user_data, uint8_t buf[], size_t len) +{ + t4_tx_state_t *s; + + s = (t4_tx_state_t *) user_data; + if (s->tiff.row >= s->metadata.image_length) + return 0; + memcpy(buf, &s->tiff.image_buffer[s->tiff.row*len], len); + s->tiff.row++; + return len; +} +/*- End of function --------------------------------------------------------*/ + static int tiff_row_read_handler(void *user_data, uint8_t buf[], size_t len) { t4_tx_state_t *s; @@ -498,16 +759,18 @@ static int tiff_row_read_handler(void *user_data, uint8_t buf[], size_t len) int j; s = (t4_tx_state_t *) user_data; - if (s->tiff.row >= s->image_length) + if (s->tiff.row >= s->tiff.image_length) + return 0; + if (s->tiff.image_buffer == NULL) return 0; memcpy(buf, &s->tiff.image_buffer[s->tiff.row*len], len); s->tiff.row++; /* If this is a bi-level image which has more vertical resolution than the far end will accept, we need to squash it down to size. */ - for (i = 1; i < s->row_squashing_ratio && s->tiff.row < s->image_length; i++) + for (i = 1; i < s->row_squashing_ratio && s->tiff.row < s->tiff.image_length; i++) { - for (j = 0; j < s->image_width/8; j++) + for (j = 0; j < len; j++) buf[j] |= s->tiff.image_buffer[s->tiff.row*len + j]; s->tiff.row++; } @@ -515,102 +778,601 @@ static int tiff_row_read_handler(void *user_data, uint8_t buf[], size_t len) } /*- End of function --------------------------------------------------------*/ -static int row_read(void *user_data, uint8_t buf[], size_t len) +static int translate_row_read2(void *user_data, uint8_t buf[], size_t len) { t4_tx_state_t *s; + s = (t4_tx_state_t *) user_data; + memcpy(buf, &s->pack_buf[s->pack_ptr], len); + s->pack_ptr += len; + s->pack_row++; + return len; +} +/*- End of function --------------------------------------------------------*/ + +static int translate_row_read(void *user_data, uint8_t buf[], size_t len) +{ + t4_tx_state_t *s; + int i; + int j; + s = (t4_tx_state_t *) user_data; if (s->tiff.raw_row >= s->tiff.image_length) return 0; + if (TIFFReadScanline(s->tiff.tiff_file, buf, s->tiff.raw_row, 0) < 0) return 0; + s->tiff.raw_row++; + + /* If this is a bi-level image which is stretched more vertically than we are able + to send we need to squash it down to size. */ + for (i = 1; i < s->row_squashing_ratio; i++) + { +#if defined(_MSC_VER) + uint8_t *extra_buf = (uint8_t *) _alloca(len); +#else + uint8_t extra_buf[len]; +#endif + + if (TIFFReadScanline(s->tiff.tiff_file, extra_buf, s->tiff.raw_row, 0) < 0) + return 0; + s->tiff.raw_row++; + /* We know this is a bi-level image if we are squashing */ + for (j = 0; j < s->tiff.image_width/8; j++) + buf[j] |= extra_buf[s->tiff.image_width/8 + j]; + } if (s->apply_lab) lab_to_srgb(&s->lab_params, buf, buf, len/3); - s->tiff.raw_row++; return len; } /*- End of function --------------------------------------------------------*/ +static int packing_row_write_handler(void *user_data, const uint8_t buf[], size_t len) +{ + packer_t *s; + + s = (packer_t *) user_data; + memcpy(&s->buf[s->ptr], buf, len); + s->ptr += len; + s->row++; + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int embedded_comment_handler(void *user_data, const uint8_t buf[], size_t len) +{ + t4_tx_state_t *s; + + s = (t4_tx_state_t *) user_data; + if (buf) + span_log(&s->logging, SPAN_LOG_WARNING, "T.85 comment (%d): %s\n", (int) len, buf); + else + span_log(&s->logging, SPAN_LOG_WARNING, "T.85 comment (%d): ---\n", (int) len); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int read_tiff_raw_image(t4_tx_state_t *s) +{ + int num_strips; + int total_len; + int len; + int i; + + num_strips = TIFFNumberOfStrips(s->tiff.tiff_file); + total_len = 0; + for (i = 0; i < num_strips; i++) + total_len += TIFFRawStripSize(s->tiff.tiff_file, i); + if ((s->no_encoder.buf = span_realloc(s->no_encoder.buf, total_len)) == NULL) + return -1; + total_len = 0; + for (i = 0; i < num_strips; i++, total_len += len) + { + len = TIFFRawStripSize(s->tiff.tiff_file, i); + if ((len = TIFFReadRawStrip(s->tiff.tiff_file, i, &s->no_encoder.buf[total_len], len)) < 0) + { + span_log(&s->logging, SPAN_LOG_WARNING, "%s: TIFFReadRawStrip error.\n", s->tiff.file); + return -1; + } + } + s->no_encoder.buf_len = total_len; + s->no_encoder.buf_ptr = 0; + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int read_tiff_t85_image(t4_tx_state_t *s) +{ + int biggest; + int num_strips; + int len; + int i; + int result; + uint8_t *t; + uint8_t *raw_data; + t85_decode_state_t t85; + packer_t pack; + + /* Size up and allocate the buffer for the raw data */ + num_strips = TIFFNumberOfStrips(s->tiff.tiff_file); + biggest = 0; + for (i = 0; i < num_strips; i++) + { + len = TIFFRawStripSize(s->tiff.tiff_file, i); + if (len > biggest) + biggest = len; + } + if ((raw_data = span_alloc(biggest)) == NULL) + return -1; + + s->tiff.image_size = s->tiff.image_length*((s->tiff.image_width + 7)/8); + if (s->tiff.image_size >= s->tiff.image_buffer_size) + { + if ((t = span_realloc(s->tiff.image_buffer, s->tiff.image_size)) == NULL) + { + span_free(raw_data); + return -1; + } + s->tiff.image_buffer_size = s->tiff.image_size; + s->tiff.image_buffer = t; + } + + pack.buf = s->tiff.image_buffer; + pack.ptr = 0; + pack.size = s->tiff.image_size; + pack.row = 0; + t85_decode_init(&t85, packing_row_write_handler, &pack); + t85_decode_set_comment_handler(&t85, 1000, embedded_comment_handler, s); + t85_decode_set_image_size_constraints(&t85, s->tiff.image_width, s->tiff.image_length); + result = -1; + for (i = 0; i < num_strips; i++) + { + len = TIFFRawStripSize(s->tiff.tiff_file, i); + if ((len = TIFFReadRawStrip(s->tiff.tiff_file, i, raw_data, len)) < 0) + { + span_log(&s->logging, SPAN_LOG_WARNING, "%s: TIFFReadRawStrip error.\n", s->tiff.file); + span_free(raw_data); + return -1; + } + if ((result = t85_decode_put(&t85, raw_data, len)) != T4_DECODE_MORE_DATA) + break; + } + if (result == T4_DECODE_MORE_DATA) + result = t85_decode_put(&t85, NULL, 0); + + len = t85_decode_get_compressed_image_size(&t85); + span_log(&s->logging, SPAN_LOG_WARNING, "Compressed image is %d bytes, %d rows\n", len/8, s->tiff.image_length); + t85_decode_release(&t85); + span_free(raw_data); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int read_tiff_t43_image(t4_tx_state_t *s) +{ + int biggest; + int num_strips; + int len; + int i; + int result; + uint8_t *t; + uint8_t *raw_data; + logging_state_t *logging; + t43_decode_state_t t43; + packer_t pack; + uint16_t bits_per_sample; + uint16_t samples_per_pixel; + + bits_per_sample = 1; + TIFFGetField(s->tiff.tiff_file, TIFFTAG_BITSPERSAMPLE, &bits_per_sample); + samples_per_pixel = 3; + TIFFGetField(s->tiff.tiff_file, TIFFTAG_SAMPLESPERPIXEL, &samples_per_pixel); + + samples_per_pixel = 3; + + num_strips = TIFFNumberOfStrips(s->tiff.tiff_file); + biggest = 0; + for (i = 0; i < num_strips; i++) + { + len = TIFFRawStripSize(s->tiff.tiff_file, i); + if (len > biggest) + biggest = len; + } + if ((raw_data = span_alloc(biggest)) == NULL) + return -1; + + s->tiff.image_size = samples_per_pixel*s->tiff.image_width*s->tiff.image_length; + if (s->tiff.image_size >= s->tiff.image_buffer_size) + { + if ((t = span_realloc(s->tiff.image_buffer, s->tiff.image_size)) == NULL) + { + span_free(raw_data); + return -1; + } + s->tiff.image_buffer_size = s->tiff.image_size; + s->tiff.image_buffer = t; + } + + t43_decode_init(&t43, packing_row_write_handler, &pack); + t43_decode_set_comment_handler(&t43, 1000, embedded_comment_handler, NULL); + t43_decode_set_image_size_constraints(&t43, s->tiff.image_width, s->tiff.image_length); + logging = t43_decode_get_logging_state(&t43); + span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); + + pack.buf = s->tiff.image_buffer; + pack.ptr = 0; + pack.size = s->tiff.image_size; + pack.row = 0; + + result = -1; + for (i = 0; i < num_strips; i++) + { + len = TIFFRawStripSize(s->tiff.tiff_file, i); + if ((len = TIFFReadRawStrip(s->tiff.tiff_file, i, raw_data, len)) < 0) + { + span_log(&s->logging, SPAN_LOG_WARNING, "%s: TIFFReadRawStrip error.\n", s->tiff.file); + span_free(raw_data); + return -1; + } + if ((result = t43_decode_put(&t43, raw_data, len)) != T4_DECODE_MORE_DATA) + break; + } + if (result == T4_DECODE_MORE_DATA) + result = t43_decode_put(&t43, NULL, 0); + + t43_decode_release(&t43); + span_free(raw_data); + return s->tiff.image_size; +} +/*- End of function --------------------------------------------------------*/ + +static int read_tiff_t42_t81_image(t4_tx_state_t *s) +{ + int total_len; + int len; + int i; + int num_strips; + int total_image_len; + uint8_t *t; + uint8_t *raw_data; + uint8_t *jpeg_table; + uint32_t jpeg_table_len; + packer_t pack; + uint16_t bits_per_sample; + uint16_t samples_per_pixel; + t42_decode_state_t t42; + + bits_per_sample = 1; + TIFFGetField(s->tiff.tiff_file, TIFFTAG_BITSPERSAMPLE, &bits_per_sample); + samples_per_pixel = 1; + TIFFGetField(s->tiff.tiff_file, TIFFTAG_SAMPLESPERPIXEL, &samples_per_pixel); + + num_strips = TIFFNumberOfStrips(s->tiff.tiff_file); + total_image_len = 0; + jpeg_table_len = 0; + if (TIFFGetField(s->tiff.tiff_file, TIFFTAG_JPEGTABLES, &jpeg_table_len, &jpeg_table)) + { + total_image_len += (jpeg_table_len - 4); + span_log(&s->logging, SPAN_LOG_FLOW, "JPEG tables %u\n", jpeg_table_len); + } + + for (i = 0; i < num_strips; i++) + total_image_len += TIFFRawStripSize(s->tiff.tiff_file, i); + if ((raw_data = span_alloc(total_image_len)) == NULL) + return -1; + + total_len = 0; + if (jpeg_table_len > 0) + total_len += jpeg_table_len - 4; + for (i = 0; i < num_strips; i++, total_len += len) + { + if ((len = TIFFReadRawStrip(s->tiff.tiff_file, i, &raw_data[total_len], total_image_len - total_len)) < 0) + { + span_log(&s->logging, SPAN_LOG_WARNING, "%s: TIFFReadRawStrip error.\n", s->tiff.file); + span_free(raw_data); + return -1; + } + } + if (jpeg_table_len > 0) + memcpy(raw_data, jpeg_table, jpeg_table_len - 2); + + if (total_len != total_image_len) + span_log(&s->logging, SPAN_LOG_FLOW, "Size mismatch %d %d\n", (int) total_len, (int) total_image_len); + + s->tiff.image_size = samples_per_pixel*s->tiff.image_width*s->tiff.image_length; + if (s->tiff.image_size >= s->tiff.image_buffer_size) + { + if ((t = span_realloc(s->tiff.image_buffer, s->tiff.image_size)) == NULL) + { + span_free(raw_data); + return -1; + } + s->tiff.image_buffer_size = s->tiff.image_size; + s->tiff.image_buffer = t; + } + + t42_decode_init(&t42, packing_row_write_handler, &pack); + + pack.buf = s->tiff.image_buffer; + pack.ptr = 0; + pack.row = 0; + + t42_decode_put(&t42, raw_data, total_image_len); + t42_decode_put(&t42, NULL, 0); + + t42_decode_release(&t42); + span_free(raw_data); + return s->tiff.image_size; +} +/*- End of function --------------------------------------------------------*/ + +static int read_tiff_decompressed_image(t4_tx_state_t *s) +{ + int total_len; + int len; + int num_strips; + int i; + uint8_t *t; + + /* Decode the whole image into a buffer */ + /* Let libtiff handle the decompression */ + s->tiff.image_size = s->tiff.image_length*TIFFScanlineSize(s->tiff.tiff_file); + if (s->tiff.image_size >= s->tiff.image_buffer_size) + { + if ((t = span_realloc(s->tiff.image_buffer, s->tiff.image_size)) == NULL) + return -1; + s->tiff.image_buffer_size = s->tiff.image_size; + s->tiff.image_buffer = t; + } + + /* Allow for the image being stored in multiple strips. */ + num_strips = TIFFNumberOfStrips(s->tiff.tiff_file); + for (i = 0, total_len = 0; i < num_strips; i++, total_len += len) + { + if ((len = TIFFReadEncodedStrip(s->tiff.tiff_file, i, &s->tiff.image_buffer[total_len], s->tiff.image_size - total_len)) < 0) + { + span_log(&s->logging, SPAN_LOG_WARNING, "%s: TIFFReadEncodedStrip error.\n", s->tiff.file); + return -1; + } + } + /* We might need to flip all the bits, so 1 = black and 0 = white. */ + if (s->tiff.image_type == T4_IMAGE_TYPE_BILEVEL && s->tiff.photo_metric != PHOTOMETRIC_MINISWHITE) + { + span_log(&s->logging, SPAN_LOG_FLOW, "%s: Photometric needs swapping.\n", s->tiff.file); + for (i = 0; i < s->tiff.image_size; i++) + s->tiff.image_buffer[i] = ~s->tiff.image_buffer[i]; + s->tiff.photo_metric = PHOTOMETRIC_MINISWHITE; + } + /* We might need to bit reverse each of the bytes of the image. */ + if (s->tiff.fill_order != FILLORDER_LSB2MSB) + bit_reverse(s->tiff.image_buffer, s->tiff.image_buffer, s->tiff.image_size); + return 0; +} +/*- End of function --------------------------------------------------------*/ + static int read_tiff_image(t4_tx_state_t *s) { int total_len; - int len; int i; + int alter_image; uint8_t *t; - image_translate_state_t *translator; - if (s->tiff.image_type != T4_IMAGE_TYPE_BILEVEL) + if (s->metadata.image_type != s->tiff.image_type || s->metadata.image_width != s->tiff.image_width) { - /* We need to dither this image down to pure black and white, possibly resizing it - along the way. */ - if ((translator = image_translate_init(NULL, s->tiff.image_type, s->image_width, s->image_length, T4_IMAGE_TYPE_BILEVEL, 1728, -1, row_read, s)) == NULL) - return -1; - s->image_width = image_translate_get_output_width(translator); - s->image_length = image_translate_get_output_length(translator); - s->metadata.x_resolution = T4_X_RESOLUTION_R8; - s->metadata.y_resolution = T4_Y_RESOLUTION_FINE; - s->tiff.image_size = (s->image_width*s->image_length + 7)/8; - if (s->tiff.image_size >= s->tiff.image_buffer_size) - { - if ((t = realloc(s->tiff.image_buffer, s->tiff.image_size)) == NULL) - return -1; - s->tiff.image_buffer_size = s->tiff.image_size; - s->tiff.image_buffer = t; - } - s->tiff.raw_row = 0; - switch (s->tiff.photo_metric) - { - case PHOTOMETRIC_CIELAB: - /* The default luminant is D50 */ - set_lab_illuminant(&s->lab_params, 0.96422f, 1.0f, 0.82521f); - set_lab_gamut(&s->lab_params, 0, 100, -128, 127, -128, 127, TRUE); - s->apply_lab = TRUE; - break; - case PHOTOMETRIC_ITULAB: - set_lab_illuminant(&s->lab_params, 0.9638f, 1.0f, 0.8245f); - set_lab_gamut(&s->lab_params, 0, 100, -85, 85, -75, 125, FALSE); - s->apply_lab = TRUE; - break; - default: - s->apply_lab = FALSE; - break; - } - total_len = 0; - for (i = 0; i < s->image_length; i++) - total_len += image_translate_row(translator, &s->tiff.image_buffer[total_len], s->image_width/8); - image_translate_free(translator); + /* We need to rework the image, so it can't pass directly through */ + alter_image = true; + image_translate_restart(&s->translator, s->tiff.image_length); + s->metadata.image_length = image_translate_get_output_length(&s->translator); + image_translate_set_row_read_handler(&s->translator, translate_row_read2, s); } else { - s->tiff.image_size = s->image_length*TIFFScanlineSize(s->tiff.tiff_file); - if (s->tiff.image_size >= s->tiff.image_buffer_size) - { - if ((t = realloc(s->tiff.image_buffer, s->tiff.image_size)) == NULL) - return -1; - s->tiff.image_buffer_size = s->tiff.image_size; - s->tiff.image_buffer = t; - } + alter_image = false; + s->metadata.image_length = s->tiff.image_length; + } + s->pack_buf = NULL; + s->pack_ptr = 0; + s->pack_row = 0; - for (i = 0, total_len = 0; total_len < s->tiff.image_size; i++, total_len += len) + s->apply_lab = false; + if (s->tiff.image_type != T4_IMAGE_TYPE_BILEVEL) + { + /* If colour/gray scale is supported we may be able to send the image as it is, perhaps after + a resizing. Otherwise we need to resize it, and squash it to a bilevel image. */ + if (s->tiff.compression == COMPRESSION_JPEG && s->tiff.photo_metric == PHOTOMETRIC_ITULAB) { - if ((len = TIFFReadEncodedStrip(s->tiff.tiff_file, i, &s->tiff.image_buffer[total_len], s->tiff.image_size - total_len)) < 0) + if (alter_image) { - span_log(&s->logging, SPAN_LOG_WARNING, "%s: Read error.\n", s->tiff.file); - return -1; + if (read_tiff_t42_t81_image(s) < 0) + return -1; + s->pack_buf = s->tiff.image_buffer; + } + else + { + /* Read the raw image, and send it as is */ + if (read_tiff_raw_image(s) < 0) + return -1; } } - if (s->tiff.photo_metric != PHOTOMETRIC_MINISWHITE) +#if defined(SPANDSP_SUPPORT_T43) + else if (s->tiff.compression == COMPRESSION_T43) { - span_log(&s->logging, SPAN_LOG_FLOW, "%s: Photometric needs swapping.\n", s->tiff.file); - for (i = 0; i < s->tiff.image_size; i++) - s->tiff.image_buffer[i] = ~s->tiff.image_buffer[i]; + if (alter_image) + { + if ( read_tiff_t43_image(s) < 0) + return -1; + s->pack_buf = s->tiff.image_buffer; + } + else + { + /* Read the raw image, and send it as is */ + if (read_tiff_raw_image(s) < 0) + return -1; + } + } +#endif +#if defined(SPANDSP_SUPPORT_T45) + else if (s->tiff.compression == COMPRESSION_T45) + { + if (alter_image) + { + if (read_tiff_t45_image(s) < 0) + return -1; + s->pack_buf = s->tiff.image_buffer; + } + else + { + /* Read the raw image, and send it as is */ + if (read_tiff_raw_image(s) < 0) + return -1; + } + } +#endif + else + { + /* Let libtiff handle the decompression */ + TIFFSetField(s->tiff.tiff_file, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB); + if (alter_image) + { + image_translate_set_row_read_handler(&s->translator, translate_row_read, s); + } + else + { + if (read_tiff_decompressed_image(s) < 0) + return -1; + } + } + + set_image_width(s, s->metadata.image_width); + set_image_length(s, s->metadata.image_length); + t4_tx_set_image_type(s, s->metadata.image_type); + if (s->metadata.image_type == T4_IMAGE_TYPE_BILEVEL) + { + /* We need to dither this image down to pure black and white, possibly resizing it + along the way. */ + s->tiff.image_size = (s->metadata.image_width*s->metadata.image_length + 7)/8; + if (s->tiff.image_size >= s->tiff.image_buffer_size) + { + if ((t = span_realloc(s->tiff.image_buffer, s->tiff.image_size)) == NULL) + return -1; + s->tiff.image_buffer_size = s->tiff.image_size; + s->tiff.image_buffer = t; + } + s->tiff.raw_row = 0; + switch (s->tiff.photo_metric) + { + case PHOTOMETRIC_CIELAB: + /* The default luminant is D50 */ + set_lab_illuminant(&s->lab_params, 96.422f, 100.000f, 82.521f); + set_lab_gamut(&s->lab_params, 0, 100, -128, 127, -128, 127, true); + s->apply_lab = true; + break; + case PHOTOMETRIC_ITULAB: + /* The default luminant is D50 */ + set_lab_illuminant(&s->lab_params, 96.422f, 100.000f, 82.521f); + set_lab_gamut(&s->lab_params, 0, 100, -85, 85, -75, 125, false); + s->apply_lab = true; + break; + } + total_len = 0; + for (i = 0; i < s->metadata.image_length; i++) + total_len += image_translate_row(&s->translator, &s->tiff.image_buffer[total_len], s->metadata.image_width/8); + image_translate_release(&s->translator); + s->row_handler = metadata_row_read_handler; + s->row_handler_user_data = (void *) s; + } + else + { + if (alter_image) + { + total_len = 0; + s->tiff.image_buffer = span_realloc(s->tiff.image_buffer, s->metadata.image_width*s->metadata.image_length*3); + for (i = 0; i < s->metadata.image_length; i++) + total_len += image_translate_row(&s->translator, &s->tiff.image_buffer[total_len], s->metadata.image_width); + image_translate_release(&s->translator); + s->row_handler = metadata_row_read_handler; + s->row_handler_user_data = (void *) s; + } + else + { + s->row_handler = tiff_row_read_handler; + s->row_handler_user_data = (void *) s; + } + } + } + else + { + /* The original image is a bi-level one. We can't really rescale it, as that works out + really poorly for a bi-level image. It has to be used in its original form. The only + practical exception is to conver a superfine resolution image to a fine resolution one, + or a fine image to a standard resolution one. We could pad slightly short rows or crop + slightly long one, but lets not bother. */ + switch (s->tiff.compression) + { +#if defined(SPANDSP_SUPPORT_T88) + case COMPRESSION_T88: + switch (s->metadata.compression) + { + case T4_COMPRESSION_T88: + /* Read the raw image, and send it as is */ + if (read_tiff_raw_image(s) < 0) + return -1; + break; + default: + /* libtiff probably cannot decompress T.88, so we must handle it ourselves */ + /* Decode the whole image into a buffer */ + if (read_tiff_t88_image(s) < 0) + return -1; + break; + } + break; +#endif + case COMPRESSION_T85: + switch (s->metadata.compression) + { + case T4_COMPRESSION_T85: + case T4_COMPRESSION_T85_L0: + /* Read the raw image, and send it as is */ + if (read_tiff_raw_image(s) < 0) + return -1; + break; + default: + /* libtiff probably cannot decompress T.85, so we must handle it ourselves */ + /* Decode the whole image into a buffer */ + if (read_tiff_t85_image(s) < 0) + return -1; + break; + } + break; +#if 0 + case COMPRESSION_CCITT_T6: + switch (s->metadata.compression) + { + case T4_COMPRESSION_T6: + /* Read the raw image, and send it as is */ + if (read_tiff_raw_image(s) < 0) + return -1; + break; + default: + /* Decode the whole image into a buffer */ + /* Let libtiff handle the decompression */ + if (read_tiff_decompressed_image(s) < 0) + return -1; + break; + } + break; +#endif + default: + /* Decode the whole image into a buffer */ + /* Let libtiff handle the decompression */ + if (read_tiff_decompressed_image(s) < 0) + return -1; + break; } - if (s->tiff.fill_order != FILLORDER_LSB2MSB) - bit_reverse(s->tiff.image_buffer, s->tiff.image_buffer, s->tiff.image_size); } s->tiff.row = 0; - return s->image_length; + return s->metadata.image_length; } /*- End of function --------------------------------------------------------*/ @@ -621,12 +1383,12 @@ static void tiff_tx_release(t4_tx_state_t *s) TIFFClose(s->tiff.tiff_file); s->tiff.tiff_file = NULL; if (s->tiff.file) - free((char *) s->tiff.file); + span_free((char *) s->tiff.file); s->tiff.file = NULL; } if (s->tiff.image_buffer) { - free(s->tiff.image_buffer); + span_free(s->tiff.image_buffer); s->tiff.image_buffer = NULL; s->tiff.image_size = 0; s->tiff.image_buffer_size = 0; @@ -636,21 +1398,28 @@ static void tiff_tx_release(t4_tx_state_t *s) static int set_row_read_handler(t4_tx_state_t *s, t4_row_read_handler_t handler, void *user_data) { - switch (s->line_encoding) + switch (s->metadata.compression) { - case T4_COMPRESSION_ITU_T4_1D: - case T4_COMPRESSION_ITU_T4_2D: - case T4_COMPRESSION_ITU_T6: + case T4_COMPRESSION_T4_1D: + case T4_COMPRESSION_T4_2D: + case T4_COMPRESSION_T6: return t4_t6_encode_set_row_read_handler(&s->encoder.t4_t6, handler, user_data); - case T4_COMPRESSION_ITU_T42: - return t42_encode_set_row_read_handler(&s->encoder.t42, handler, user_data); -#if defined(SPANDSP_SUPPORT_T43) - case T4_COMPRESSION_ITU_T43: - return t43_encode_set_row_read_handler(&s->encoder.t43, handler, user_data); -#endif - case T4_COMPRESSION_ITU_T85: - case T4_COMPRESSION_ITU_T85_L0: + case T4_COMPRESSION_T85: + case T4_COMPRESSION_T85_L0: return t85_encode_set_row_read_handler(&s->encoder.t85, handler, user_data); +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + return t88_encode_set_row_read_handler(&s->encoder.t88, handler, user_data); +#endif + case T4_COMPRESSION_T42_T81: + case T4_COMPRESSION_SYCC_T81: + return t42_encode_set_row_read_handler(&s->encoder.t42, handler, user_data); + case T4_COMPRESSION_T43: + return t43_encode_set_row_read_handler(&s->encoder.t43, handler, user_data); +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + return t45_encode_set_row_read_handler(&s->encoder.t45, handler, user_data); +#endif } return -1; } @@ -668,7 +1437,7 @@ static int make_header(t4_tx_state_t *s) if (s->header_text == NULL) { - if ((s->header_text = malloc(132 + 1)) == NULL) + if ((s->header_text = span_alloc(132 + 1)) == NULL) return -1; } /* This is very English oriented, but then most FAX machines are, too. Some @@ -700,39 +1469,79 @@ static int make_header(t4_tx_state_t *s) static int header_row_read_handler(void *user_data, uint8_t buf[], size_t len) { - int repeats; + int x_repeats; + int y_repeats; int pattern; int pos; int row; + int i; char *t; t4_tx_state_t *s; s = (t4_tx_state_t *) user_data; - switch (s->metadata.y_resolution) + switch (s->metadata.resolution_code) { - case T4_Y_RESOLUTION_1200: - repeats = 12; - break; - case T4_Y_RESOLUTION_800: - repeats = 8; - break; - case T4_Y_RESOLUTION_600: - repeats = 6; - break; - case T4_Y_RESOLUTION_SUPERFINE: - repeats = 4; - break; - case T4_Y_RESOLUTION_300: - repeats = 3; - break; - case T4_Y_RESOLUTION_FINE: - repeats = 2; - break; default: - repeats = 1; + case T4_RESOLUTION_100_100: + x_repeats = 1; + y_repeats = 1; + break; + case T4_RESOLUTION_R8_STANDARD: + case T4_RESOLUTION_200_100: + x_repeats = 2; + y_repeats = 1; + break; + case T4_RESOLUTION_R8_FINE: + case T4_RESOLUTION_200_200: + x_repeats = 2; + y_repeats = 2; + break; + case T4_RESOLUTION_300_300: + x_repeats = 3; + y_repeats = 3; + break; + case T4_RESOLUTION_R8_SUPERFINE: + case T4_RESOLUTION_200_400: + x_repeats = 2; + y_repeats = 4; + break; + case T4_RESOLUTION_R16_SUPERFINE: + case T4_RESOLUTION_400_400: + x_repeats = 4; + y_repeats = 4; + break; + case T4_RESOLUTION_400_800: + x_repeats = 4; + y_repeats = 8; + break; + case T4_RESOLUTION_300_600: + x_repeats = 3; + y_repeats = 6; + break; + case T4_RESOLUTION_600_600: + x_repeats = 6; + y_repeats = 6; + break; + case T4_RESOLUTION_600_1200: + x_repeats = 6; + y_repeats = 12; + break; + case T4_RESOLUTION_1200_1200: + x_repeats = 12; + y_repeats = 12; + break; + } + switch (s->metadata.width_code) + { + case T4_SUPPORT_WIDTH_215MM: + break; + case T4_SUPPORT_WIDTH_255MM: + x_repeats *= 2; + break; + case T4_SUPPORT_WIDTH_303MM: + x_repeats *= 3; break; } - repeats /= s->row_squashing_ratio; if (s->header_overlays_image) { /* Read and dump a row of the real image, allowing for the possibility @@ -743,18 +1552,62 @@ static int header_row_read_handler(void *user_data, uint8_t buf[], size_t len) return len; } } - row = s->header_row/repeats; + t = s->header_text; + row = s->header_row/y_repeats; pos = 0; - for (t = s->header_text; *t && pos <= len - 2; t++) + switch (s->metadata.image_type) { - pattern = header_font[(uint8_t) *t][row]; - buf[pos++] = (uint8_t) (pattern >> 8); - buf[pos++] = (uint8_t) (pattern & 0xFF); + case T4_IMAGE_TYPE_BILEVEL: + for ( ; *t && pos <= len - 2; t++) + { + pattern = header_font[(uint8_t) *t][row]; + buf[pos++] = (uint8_t) (pattern >> 8); + buf[pos++] = (uint8_t) (pattern & 0xFF); + } + if (pos < len) + memset(&buf[pos], 0, len - pos); + break; + case T4_IMAGE_TYPE_GRAY_8BIT: + for ( ; *t && pos <= len - 2; t++) + { + pattern = header_font[(uint8_t) *t][row]; + for (i = 0; i < 16; i++) + { + buf[pos + i] = (pattern & 0x8000) ? 0 : 0xFF; + pattern <<= 1; + } + pos += 16; + } + if (pos < len) + memset(&buf[pos], 0xFF, len - pos); + break; + case T4_IMAGE_TYPE_COLOUR_8BIT: + for ( ; *t && pos <= len - 2; t++) + { + pattern = header_font[(uint8_t) *t][row]; + for (i = 0; i < 16; i++) + { + buf[pos + 3*i + 0] = + buf[pos + 3*i + 1] = + buf[pos + 3*i + 2] = (pattern & 0x8000) ? 0 : 0xFF; + pattern <<= 1; + } + pos += 3*16; + } + if (pos < len) + memset(&buf[pos], 0xFF, len - pos); + break; + case T4_IMAGE_TYPE_COLOUR_BILEVEL: + case T4_IMAGE_TYPE_4COLOUR_BILEVEL: + case T4_IMAGE_TYPE_GRAY_12BIT: + case T4_IMAGE_TYPE_4COLOUR_8BIT: + case T4_IMAGE_TYPE_COLOUR_12BIT: + case T4_IMAGE_TYPE_4COLOUR_12BIT: + default: + memset(buf, 0xFF, len); } - while (pos < len) - buf[pos++] = 0; s->header_row++; - if (s->header_row >= 16*repeats) + if (s->header_row >= 16*y_repeats) { /* End of header. Change to normal image row data. */ set_row_read_handler(s, s->row_handler, s->row_handler_user_data); @@ -763,12 +1616,6 @@ static int header_row_read_handler(void *user_data, uint8_t buf[], size_t len) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) t4_tx_set_row_squashing_ratio(t4_tx_state_t *s, int row_squashing_ratio) -{ - s->row_squashing_ratio = row_squashing_ratio; -} -/*- End of function --------------------------------------------------------*/ - SPAN_DECLARE(int) t4_tx_next_page_has_different_format(t4_tx_state_t *s) { span_log(&s->logging, SPAN_LOG_FLOW, "Checking for the existence of page %d\n", s->current_page + 1); @@ -792,148 +1639,624 @@ SPAN_DECLARE(int) t4_tx_set_row_read_handler(t4_tx_state_t *s, t4_row_read_handl } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) t4_tx_set_tx_encoding(t4_tx_state_t *s, int encoding) +SPAN_DECLARE(int) t4_tx_set_tx_image_format(t4_tx_state_t *s, + int supported_compressions, + int supported_image_sizes, + int supported_bilevel_resolutions, + int supported_colour_resolutions) { - switch (encoding) + static const struct { - case T4_COMPRESSION_ITU_T4_1D: - case T4_COMPRESSION_ITU_T4_2D: - case T4_COMPRESSION_ITU_T6: - switch (s->line_encoding) + int width; + int width_code; + int res_code; /* Correct resolution code */ + int alt_res_code; /* Fallback resolution code, where a metric/inch swap is possible */ + } width_and_res_info[] = + { + { T4_WIDTH_100_A4, T4_SUPPORT_WIDTH_215MM, T4_RESOLUTION_100_100, 0}, + { T4_WIDTH_100_B4, T4_SUPPORT_WIDTH_255MM, T4_RESOLUTION_100_100, 0}, + { T4_WIDTH_100_A3, T4_SUPPORT_WIDTH_303MM, T4_RESOLUTION_100_100, 0}, + { T4_WIDTH_200_A4, T4_SUPPORT_WIDTH_215MM, T4_RESOLUTION_200_100, T4_RESOLUTION_R8_STANDARD}, + { T4_WIDTH_200_A4, T4_SUPPORT_WIDTH_215MM, T4_RESOLUTION_200_200, T4_RESOLUTION_R8_FINE}, + { T4_WIDTH_200_A4, T4_SUPPORT_WIDTH_215MM, T4_RESOLUTION_200_400, T4_RESOLUTION_R8_SUPERFINE}, + { T4_WIDTH_200_A4, T4_SUPPORT_WIDTH_215MM, T4_RESOLUTION_R8_STANDARD, T4_RESOLUTION_200_100}, + { T4_WIDTH_200_A4, T4_SUPPORT_WIDTH_215MM, T4_RESOLUTION_R8_FINE, T4_RESOLUTION_200_200}, + { T4_WIDTH_200_A4, T4_SUPPORT_WIDTH_215MM, T4_RESOLUTION_R8_SUPERFINE, T4_RESOLUTION_200_400}, + { T4_WIDTH_200_B4, T4_SUPPORT_WIDTH_255MM, T4_RESOLUTION_200_100, T4_RESOLUTION_R8_STANDARD}, + { T4_WIDTH_200_B4, T4_SUPPORT_WIDTH_255MM, T4_RESOLUTION_200_200, T4_RESOLUTION_R8_FINE}, + { T4_WIDTH_200_B4, T4_SUPPORT_WIDTH_255MM, T4_RESOLUTION_200_400, T4_RESOLUTION_R8_SUPERFINE}, + { T4_WIDTH_200_B4, T4_SUPPORT_WIDTH_255MM, T4_RESOLUTION_R8_STANDARD, T4_RESOLUTION_200_100}, + { T4_WIDTH_200_B4, T4_SUPPORT_WIDTH_255MM, T4_RESOLUTION_R8_FINE, T4_RESOLUTION_200_200}, + { T4_WIDTH_200_B4, T4_SUPPORT_WIDTH_255MM, T4_RESOLUTION_R8_SUPERFINE, T4_RESOLUTION_200_400}, + { T4_WIDTH_200_A3, T4_SUPPORT_WIDTH_303MM, T4_RESOLUTION_200_100, T4_RESOLUTION_R8_STANDARD}, + { T4_WIDTH_200_A3, T4_SUPPORT_WIDTH_303MM, T4_RESOLUTION_200_200, T4_RESOLUTION_R8_FINE}, + { T4_WIDTH_200_A3, T4_SUPPORT_WIDTH_303MM, T4_RESOLUTION_200_400, T4_RESOLUTION_R8_SUPERFINE}, + { T4_WIDTH_200_A3, T4_SUPPORT_WIDTH_303MM, T4_RESOLUTION_R8_STANDARD, T4_RESOLUTION_200_100}, + { T4_WIDTH_200_A3, T4_SUPPORT_WIDTH_303MM, T4_RESOLUTION_R8_FINE, T4_RESOLUTION_200_200}, + { T4_WIDTH_200_A3, T4_SUPPORT_WIDTH_303MM, T4_RESOLUTION_R8_SUPERFINE, T4_RESOLUTION_200_400}, + { T4_WIDTH_300_A4, T4_SUPPORT_WIDTH_215MM, T4_RESOLUTION_300_300, 0}, + { T4_WIDTH_300_A4, T4_SUPPORT_WIDTH_215MM, T4_RESOLUTION_300_600, 0}, + { T4_WIDTH_300_B4, T4_SUPPORT_WIDTH_255MM, T4_RESOLUTION_300_300, 0}, + { T4_WIDTH_300_B4, T4_SUPPORT_WIDTH_255MM, T4_RESOLUTION_300_600, 0}, + { T4_WIDTH_400_A4, T4_SUPPORT_WIDTH_215MM, T4_RESOLUTION_400_400, T4_RESOLUTION_R16_SUPERFINE}, + { T4_WIDTH_400_A4, T4_SUPPORT_WIDTH_215MM, T4_RESOLUTION_400_800, 0}, + { T4_WIDTH_400_A4, T4_SUPPORT_WIDTH_215MM, T4_RESOLUTION_R16_SUPERFINE, T4_RESOLUTION_400_400}, + { T4_WIDTH_300_A3, T4_SUPPORT_WIDTH_303MM, T4_RESOLUTION_300_300, 0}, + { T4_WIDTH_300_A3, T4_SUPPORT_WIDTH_303MM, T4_RESOLUTION_300_600, 0}, + { T4_WIDTH_400_B4, T4_SUPPORT_WIDTH_255MM, T4_RESOLUTION_400_400, T4_RESOLUTION_R16_SUPERFINE}, + { T4_WIDTH_400_B4, T4_SUPPORT_WIDTH_255MM, T4_RESOLUTION_400_800, 0}, + { T4_WIDTH_400_B4, T4_SUPPORT_WIDTH_255MM, T4_RESOLUTION_R16_SUPERFINE, T4_RESOLUTION_400_400}, + { T4_WIDTH_400_A3, T4_SUPPORT_WIDTH_303MM, T4_RESOLUTION_400_400, T4_RESOLUTION_R16_SUPERFINE}, + { T4_WIDTH_400_A3, T4_SUPPORT_WIDTH_303MM, T4_RESOLUTION_400_800, 0}, + { T4_WIDTH_400_A3, T4_SUPPORT_WIDTH_303MM, T4_RESOLUTION_R16_SUPERFINE, T4_RESOLUTION_400_400}, + { T4_WIDTH_600_A4, T4_SUPPORT_WIDTH_215MM, T4_RESOLUTION_600_600, 0}, + { T4_WIDTH_600_A4, T4_SUPPORT_WIDTH_215MM, T4_RESOLUTION_600_1200, 0}, + { T4_WIDTH_600_B4, T4_SUPPORT_WIDTH_255MM, T4_RESOLUTION_600_600, 0}, + { T4_WIDTH_600_B4, T4_SUPPORT_WIDTH_255MM, T4_RESOLUTION_600_1200, 0}, + { T4_WIDTH_600_A3, T4_SUPPORT_WIDTH_303MM, T4_RESOLUTION_600_600, 0}, + { T4_WIDTH_600_A3, T4_SUPPORT_WIDTH_303MM, T4_RESOLUTION_600_1200, 0}, + {T4_WIDTH_1200_A4, T4_SUPPORT_WIDTH_215MM, T4_RESOLUTION_1200_1200, 0}, + {T4_WIDTH_1200_B4, T4_SUPPORT_WIDTH_255MM, T4_RESOLUTION_1200_1200, 0}, + {T4_WIDTH_1200_A3, T4_SUPPORT_WIDTH_303MM, T4_RESOLUTION_1200_1200, 0}, + {0x7FFFFFFF, -1, -1, -1} + }; + + static const struct + { + int resolution; + struct { - case T4_COMPRESSION_ITU_T4_1D: - case T4_COMPRESSION_ITU_T4_2D: - case T4_COMPRESSION_ITU_T6: - break; - default: - t4_t6_encode_init(&s->encoder.t4_t6, encoding, s->image_width, s->row_handler, s->row_handler_user_data); - t4_t6_encode_set_max_2d_rows_per_1d_row(&s->encoder.t4_t6, -s->metadata.y_resolution); - break; - } - s->line_encoding = encoding; - return t4_t6_encode_set_encoding(&s->encoder.t4_t6, encoding); - case T4_COMPRESSION_ITU_T42: - switch (s->line_encoding) + int resolution; + int squashing_factor; + } fallback[4]; + } squashable[4] = + { { - case T4_COMPRESSION_ITU_T42: - break; - default: - t42_encode_init(&s->encoder.t42, s->image_width, s->image_length, s->row_handler, s->row_handler_user_data); - break; - } - s->line_encoding = encoding; - return 0; -#if defined(SPANDSP_SUPPORT_T43) - case T4_COMPRESSION_ITU_T43: - switch (s->line_encoding) + T4_RESOLUTION_200_400, + { + {T4_RESOLUTION_200_200, 2}, + {T4_RESOLUTION_R8_FINE, 2}, + {T4_RESOLUTION_200_100, 4}, + {T4_RESOLUTION_R8_STANDARD, 4} + } + }, { - case T4_COMPRESSION_ITU_T43: - break; - default: - t43_encode_init(&s->encoder.t43, s->image_width, s->image_length, s->row_handler, s->row_handler_user_data); - break; - } - s->line_encoding = encoding; - return 0; -#endif - case T4_COMPRESSION_ITU_T85: - case T4_COMPRESSION_ITU_T85_L0: - switch (s->line_encoding) + T4_RESOLUTION_200_200, + { + {T4_RESOLUTION_200_100, 2}, + {T4_RESOLUTION_R8_STANDARD, 2}, + {0, 0}, + {0, 0} + } + }, { - case T4_COMPRESSION_ITU_T85: - case T4_COMPRESSION_ITU_T85_L0: - break; - default: - t85_encode_init(&s->encoder.t85, s->image_width, s->image_length, s->row_handler, s->row_handler_user_data); - break; + T4_RESOLUTION_R8_SUPERFINE, + { + {T4_RESOLUTION_R8_FINE, 2}, + {T4_RESOLUTION_200_200, 2}, + {T4_RESOLUTION_R8_STANDARD, 4}, + {T4_RESOLUTION_200_100, 4} + } + }, + { + T4_RESOLUTION_R8_FINE, + { + {T4_RESOLUTION_R8_STANDARD, 2}, + {T4_RESOLUTION_200_100, 2}, + {0, 0}, + {0, 0} + } + } + }; + + int i; + int j; + int entry; + int compression; + int res; + int supported_colour_compressions; + + supported_colour_compressions = supported_compressions & (T4_COMPRESSION_T42_T81 | T4_COMPRESSION_T43 | T4_COMPRESSION_T45 | T4_COMPRESSION_SYCC_T81); + compression = -1; + s->metadata.image_type = s->tiff.image_type; + if (s->tiff.image_type != T4_IMAGE_TYPE_BILEVEL) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Non-bi-level image\n"); + /* Can we send this page as it is? */ + if (supported_colour_resolutions + && + supported_colour_compressions + && + (((s->tiff.image_type == T4_IMAGE_TYPE_COLOUR_BILEVEL || s->tiff.image_type == T4_IMAGE_TYPE_COLOUR_8BIT || s->tiff.image_type == T4_IMAGE_TYPE_COLOUR_12BIT) + && + (supported_compressions & T4_COMPRESSION_COLOUR)) + || + ((s->tiff.image_type == T4_IMAGE_TYPE_GRAY_8BIT || s->tiff.image_type == T4_IMAGE_TYPE_GRAY_12BIT) + && + (supported_compressions & T4_COMPRESSION_GRAYSCALE)))) + { + /* Gray-scale/colour is possible */ + span_log(&s->logging, SPAN_LOG_FLOW, "Gray-scale/colour is allowed\n"); + /* Choose the best gray-scale/colour encoding available to us */ + if (s->tiff.image_type == T4_IMAGE_TYPE_COLOUR_BILEVEL && (supported_compressions & T4_COMPRESSION_T43)) + compression = T4_COMPRESSION_T43; + else if ((supported_compressions & T4_COMPRESSION_T42_T81)) + compression = T4_COMPRESSION_T42_T81; + else if ((supported_compressions & T4_COMPRESSION_T43)) + compression = T4_COMPRESSION_T43; + else if ((supported_compressions & T4_COMPRESSION_T45)) + compression = T4_COMPRESSION_T45; + else if ((supported_compressions & T4_COMPRESSION_SYCC_T81)) + compression = T4_COMPRESSION_SYCC_T81; + + //best_colour_resolution(s->tiff.x_resolution, supported_colour_resolutions); + } + else + { + /* Gray-scale/colour is not possible. Can we flatten the image to send it? */ + span_log(&s->logging, SPAN_LOG_FLOW, "Gray-scale/colour is not allowed\n"); + switch (s->tiff.image_type) + { + case T4_IMAGE_TYPE_COLOUR_BILEVEL: + case T4_IMAGE_TYPE_COLOUR_8BIT: + case T4_IMAGE_TYPE_COLOUR_12BIT: + if (!(supported_compressions & T4_COMPRESSION_COLOUR_TO_BILEVEL)) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Flattening is not allowed\n"); + return T4_IMAGE_FORMAT_INCOMPATIBLE; + } + break; + case T4_IMAGE_TYPE_GRAY_8BIT: + case T4_IMAGE_TYPE_GRAY_12BIT: + if (!(supported_compressions & T4_COMPRESSION_GRAY_TO_BILEVEL)) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Flattening is not allowed\n"); + return T4_IMAGE_FORMAT_INCOMPATIBLE; + } + break; + } + /* Squashing to a bi-level image is possible */ + s->metadata.image_type = T4_IMAGE_TYPE_BILEVEL; + span_log(&s->logging, SPAN_LOG_FLOW, "The image will be flattened to %s\n", t4_image_type_to_str(s->metadata.image_type)); } - s->line_encoding = encoding; - return 0; } - return -1; + + if (s->metadata.image_type == T4_IMAGE_TYPE_BILEVEL) + { + /* Choose the best bi-level encoding available to us */ + if ((supported_compressions & T4_COMPRESSION_T85_L0)) + compression = T4_COMPRESSION_T85_L0; + else if ((supported_compressions & T4_COMPRESSION_T85)) + compression = T4_COMPRESSION_T85; + else if ((supported_compressions & T4_COMPRESSION_T6)) + compression = T4_COMPRESSION_T6; + else if ((supported_compressions & T4_COMPRESSION_T4_2D)) + compression = T4_COMPRESSION_T4_2D; + else + compression = T4_COMPRESSION_T4_1D; + } + + /* Deal with the image width/resolution combination. */ + /* Look for a pattern that matches the image */ + s->metadata.width_code = -1; + for (entry = 0; s->tiff.image_width >= width_and_res_info[entry].width; entry++) + { + if (s->tiff.image_width == width_and_res_info[entry].width && s->tiff.resolution_code == width_and_res_info[entry].res_code) + { + s->metadata.width_code = width_and_res_info[entry].width_code; + break; + } + } + res = T4_IMAGE_FORMAT_NOSIZESUPPORT; + s->row_squashing_ratio = 1; + if (s->metadata.width_code >= 0 && (supported_image_sizes & s->metadata.width_code)) + { + /* We have a valid and supported width/resolution combination */ + + /* No resize necessary */ + s->metadata.image_width = s->tiff.image_width; + s->metadata.image_length = s->tiff.image_length; + + res = T4_IMAGE_FORMAT_NORESSUPPORT; + if (s->metadata.image_type == T4_IMAGE_TYPE_BILEVEL) + { + if ((width_and_res_info[entry].res_code & supported_bilevel_resolutions)) + { + /* We can use the resolution of the original image */ + s->metadata.resolution_code = s->tiff.resolution_code; + s->metadata.x_resolution = code_to_x_resolution(s->metadata.resolution_code); + s->metadata.y_resolution = code_to_y_resolution(s->metadata.resolution_code); + res = T4_IMAGE_FORMAT_OK; + } + else if ((width_and_res_info[entry].alt_res_code & supported_bilevel_resolutions)) + { + /* We can do a metric/imperial swap, and have a usable resolution */ + span_log(&s->logging, + SPAN_LOG_FLOW, + "Image resolution %s falls back to %s\n", + t4_image_resolution_to_str(s->tiff.resolution_code), + t4_image_resolution_to_str(width_and_res_info[entry].alt_res_code)); + s->metadata.resolution_code = width_and_res_info[entry].alt_res_code; + s->metadata.x_resolution = code_to_x_resolution(s->metadata.resolution_code); + s->metadata.y_resolution = code_to_y_resolution(s->metadata.resolution_code); + res = T4_IMAGE_FORMAT_OK; + } + else + { + if (s->tiff.image_type == T4_IMAGE_TYPE_BILEVEL) + { + if ((s->tiff.resolution_code & (T4_RESOLUTION_200_400 | T4_RESOLUTION_200_200 | T4_RESOLUTION_R8_SUPERFINE | T4_RESOLUTION_R8_FINE))) + { + /* This might be a resolution we can squash down to something which is supported */ + for (i = 0; i < 4; i++) + { + if ((s->tiff.resolution_code & squashable[i].resolution)) + break; + } + if (i < 4) + { + /* This is a squashable resolution, so let's see if there is a valid + fallback we can squash the image to, scanning through the entries + in their order of preference. */ + for (j = 0; j < 4; j++) + { + if ((supported_bilevel_resolutions & squashable[i].fallback[j].resolution)) + { + span_log(&s->logging, + SPAN_LOG_FLOW, + "Image resolution %s falls back to %s\n", + t4_image_resolution_to_str(s->tiff.resolution_code), + t4_image_resolution_to_str(squashable[i].fallback[j].resolution)); + s->row_squashing_ratio = squashable[i].fallback[j].squashing_factor; + s->metadata.resolution_code = squashable[i].fallback[j].resolution; + s->metadata.x_resolution = code_to_x_resolution(s->metadata.resolution_code); + s->metadata.y_resolution = code_to_y_resolution(s->metadata.resolution_code); + res = T4_IMAGE_FORMAT_OK; + break; + } + } + } + } + } + } + /* If we have not succeeded in matching up the size and resolution, the next step will + depend on whether the original was a bi-level image. If it was, we are stuck, as you can't + really resize those. If it was not, a resize might be possible */ + if (res != T4_IMAGE_FORMAT_OK) + { + if (s->tiff.image_type == T4_IMAGE_TYPE_BILEVEL) + return T4_IMAGE_FORMAT_NORESSUPPORT; + if (!(supported_compressions & T4_COMPRESSION_RESCALING)) + return T4_IMAGE_FORMAT_NOSIZESUPPORT; + } + /* TODO */ + } + else + { + if ((width_and_res_info[entry].res_code & supported_bilevel_resolutions)) + { + if ((s->tiff.resolution_code & supported_colour_resolutions)) + { + /* We can use the resolution of the original image */ + s->metadata.resolution_code = width_and_res_info[entry].res_code; + s->metadata.x_resolution = code_to_x_resolution(s->metadata.resolution_code); + s->metadata.y_resolution = code_to_y_resolution(s->metadata.resolution_code); + res = T4_IMAGE_FORMAT_OK; + } + } + } + } + else + { + /* Can we rework the image to fit? */ + /* We can't rework a bilevel image that fits none of the patterns */ + if (s->tiff.image_type == T4_IMAGE_TYPE_BILEVEL || s->tiff.image_type == T4_IMAGE_TYPE_COLOUR_BILEVEL) + return T4_IMAGE_FORMAT_NORESSUPPORT; + if (!(supported_compressions & T4_COMPRESSION_RESCALING)) + return T4_IMAGE_FORMAT_NOSIZESUPPORT; + /* Any other kind of image might be resizable */ + res = T4_IMAGE_FORMAT_OK; + /* TODO: use more sophisticated resizing */ + s->metadata.image_width = T4_WIDTH_200_A4; + s->metadata.resolution_code = T4_RESOLUTION_200_200; + s->metadata.x_resolution = code_to_x_resolution(s->metadata.resolution_code); + s->metadata.y_resolution = code_to_y_resolution(s->metadata.resolution_code); + } + + if (res != T4_IMAGE_FORMAT_OK) + return res; + + if (s->metadata.image_type != s->tiff.image_type || s->metadata.image_width != s->tiff.image_width) + { + if (image_translate_init(&s->translator, + s->metadata.image_type, + s->metadata.image_width, + -1, + s->tiff.image_type, + s->tiff.image_width, + s->tiff.image_length, + translate_row_read2, + s) == NULL) + { + return T4_IMAGE_FORMAT_INCOMPATIBLE; + } + s->metadata.image_length = image_translate_get_output_length(&s->translator); + } + + if (compression != s->metadata.compression) + { + switch (compression) + { + case T4_COMPRESSION_T4_1D: + case T4_COMPRESSION_T4_2D: + case T4_COMPRESSION_T6: + switch (s->metadata.compression) + { + case T4_COMPRESSION_T4_1D: + case T4_COMPRESSION_T4_2D: + case T4_COMPRESSION_T6: + break; + default: + t4_t6_encode_init(&s->encoder.t4_t6, compression, s->metadata.image_width, s->metadata.image_length, s->row_handler, s->row_handler_user_data); + break; + } + s->metadata.compression = compression; + res = T4_IMAGE_FORMAT_OK; + if (t4_t6_encode_set_encoding(&s->encoder.t4_t6, compression)) + res = -1; + break; + case T4_COMPRESSION_T85: + case T4_COMPRESSION_T85_L0: + switch (s->metadata.compression) + { + case T4_COMPRESSION_T85: + case T4_COMPRESSION_T85_L0: + break; + default: + t85_encode_init(&s->encoder.t85, s->metadata.image_width, s->metadata.image_length, s->row_handler, s->row_handler_user_data); + break; + } + s->metadata.compression = compression; + res = T4_IMAGE_FORMAT_OK; + break; +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + switch (s->metadata.compression) + { + case T4_COMPRESSION_T88: + break; + default: + t88_encode_init(&s->encoder.t88, s->metadata.image_width, s->metadata.image_length, s->row_handler, s->row_handler_user_data); + break; + } + s->metadata.compression = compression; + res = T4_IMAGE_FORMAT_OK; + break; +#endif + case T4_COMPRESSION_T42_T81: + case T4_COMPRESSION_SYCC_T81: + switch (s->metadata.compression) + { + case T4_COMPRESSION_T42_T81: + case T4_COMPRESSION_SYCC_T81: + break; + default: + t42_encode_init(&s->encoder.t42, s->metadata.image_width, s->metadata.image_length, s->row_handler, s->row_handler_user_data); + break; + } + s->metadata.compression = compression; + res = T4_IMAGE_FORMAT_OK; + break; + case T4_COMPRESSION_T43: + switch (s->metadata.compression) + { + case T4_COMPRESSION_T43: + break; + default: + t43_encode_init(&s->encoder.t43, s->metadata.image_width, s->metadata.image_length, s->row_handler, s->row_handler_user_data); + break; + } + s->metadata.compression = compression; + res = T4_IMAGE_FORMAT_OK; + break; +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + switch (s->metadata.compression) + { + case T4_COMPRESSION_T45: + break; + default: + t45_encode_init(&s->encoder.t45, s->metadata.image_width, s->metadata.image_length, s->row_handler, s->row_handler_user_data); + break; + } + s->metadata.compression = compression; + res = T4_IMAGE_FORMAT_OK; + break; +#endif + } + } + + switch (s->metadata.compression) + { + case T4_COMPRESSION_T4_1D: + case T4_COMPRESSION_T4_2D: + case T4_COMPRESSION_T6: + t4_t6_encode_set_max_2d_rows_per_1d_row(&s->encoder.t4_t6, -s->metadata.y_resolution); + break; + } + + set_image_width(s, s->metadata.image_width); + set_image_length(s, s->metadata.image_length); + t4_tx_set_image_type(s, s->metadata.image_type); + return res; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_tx_get_tx_compression(t4_tx_state_t *s) +{ + return s->metadata.compression; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_tx_get_tx_image_type(t4_tx_state_t *s) +{ + return s->metadata.image_type; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_tx_get_tx_resolution(t4_tx_state_t *s) +{ + return s->metadata.resolution_code; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_tx_get_tx_x_resolution(t4_tx_state_t *s) +{ + return s->metadata.x_resolution; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_tx_get_tx_y_resolution(t4_tx_state_t *s) +{ + return s->metadata.y_resolution; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_tx_get_tx_image_width(t4_tx_state_t *s) +{ + return s->metadata.image_width; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE(int) t4_tx_get_tx_image_width_code(t4_tx_state_t *s) +{ + return s->metadata.width_code; +} +/*- End of function --------------------------------------------------------*/ + +static void set_image_width(t4_tx_state_t *s, uint32_t image_width) +{ + s->metadata.image_width = image_width; + switch (s->metadata.compression) + { + case T4_COMPRESSION_T4_1D: + case T4_COMPRESSION_T4_2D: + case T4_COMPRESSION_T6: + t4_t6_encode_set_image_width(&s->encoder.t4_t6, image_width); + break; + case T4_COMPRESSION_T85: + case T4_COMPRESSION_T85_L0: + t85_encode_set_image_width(&s->encoder.t85, image_width); + break; +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + t88_encode_set_image_width(&s->encoder.t88, image_width); + break; +#endif + case T4_COMPRESSION_T42_T81: + case T4_COMPRESSION_SYCC_T81: + t42_encode_set_image_width(&s->encoder.t42, image_width); + break; + case T4_COMPRESSION_T43: + t43_encode_set_image_width(&s->encoder.t43, image_width); + break; +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + t45_encode_set_image_width(&s->encoder.t45, image_width); + break; +#endif + } +} +/*- End of function --------------------------------------------------------*/ + +static void set_image_length(t4_tx_state_t *s, uint32_t image_length) +{ + s->metadata.image_length = image_length; + switch (s->metadata.compression) + { + case T4_COMPRESSION_T4_1D: + case T4_COMPRESSION_T4_2D: + case T4_COMPRESSION_T6: + t4_t6_encode_set_image_length(&s->encoder.t4_t6, image_length); + break; + case T4_COMPRESSION_T85: + case T4_COMPRESSION_T85_L0: + t85_encode_set_image_length(&s->encoder.t85, image_length); + break; +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + t88_encode_set_image_length(&s->encoder.t88, image_length); + break; +#endif + case T4_COMPRESSION_T42_T81: + case T4_COMPRESSION_SYCC_T81: + t42_encode_set_image_length(&s->encoder.t42, image_length); + break; + case T4_COMPRESSION_T43: + t43_encode_set_image_length(&s->encoder.t43, image_length); + break; +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + t45_encode_set_image_length(&s->encoder.t45, image_length); + break; +#endif + } +} +/*- End of function --------------------------------------------------------*/ + +static void t4_tx_set_image_type(t4_tx_state_t *s, int image_type) +{ + s->metadata.image_type = image_type; + switch (s->metadata.compression) + { +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + t88_encode_set_image_type(&s->encoder.t88, image_type); + break; +#endif + case T4_COMPRESSION_T42_T81: + case T4_COMPRESSION_SYCC_T81: + t42_encode_set_image_type(&s->encoder.t42, image_type); + break; + case T4_COMPRESSION_T43: + t43_encode_set_image_type(&s->encoder.t43, image_type); + break; +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + t45_encode_set_image_type(&s->encoder.t45, image_type); + break; +#endif + } } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(void) t4_tx_set_min_bits_per_row(t4_tx_state_t *s, int bits) { - switch (s->line_encoding) + switch (s->metadata.compression) { - case T4_COMPRESSION_ITU_T4_1D: - case T4_COMPRESSION_ITU_T4_2D: - case T4_COMPRESSION_ITU_T6: + case T4_COMPRESSION_T4_1D: + case T4_COMPRESSION_T4_2D: + case T4_COMPRESSION_T6: t4_t6_encode_set_min_bits_per_row(&s->encoder.t4_t6, bits); break; } } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) t4_tx_set_image_width(t4_tx_state_t *s, int image_width) -{ - s->image_width = image_width; - switch (s->line_encoding) - { - case T4_COMPRESSION_ITU_T4_1D: - case T4_COMPRESSION_ITU_T4_2D: - case T4_COMPRESSION_ITU_T6: - t4_t6_encode_set_image_width(&s->encoder.t4_t6, image_width); - break; - case T4_COMPRESSION_ITU_T42: - t42_encode_set_image_width(&s->encoder.t42, image_width); - break; -#if defined(SPANDSP_SUPPORT_T43) - case T4_COMPRESSION_ITU_T43: - t43_encode_set_image_width(&s->encoder.t43, image_width); - break; -#endif - case T4_COMPRESSION_ITU_T85: - case T4_COMPRESSION_ITU_T85_L0: - t85_encode_set_image_width(&s->encoder.t85, image_width); - break; - } -} -/*- End of function --------------------------------------------------------*/ - -static void t4_tx_set_image_length(t4_tx_state_t *s, int image_length) -{ - s->image_length = image_length; - switch (s->line_encoding) - { - case T4_COMPRESSION_ITU_T42: - t42_encode_set_image_length(&s->encoder.t42, image_length); - break; -#if defined(SPANDSP_SUPPORT_T43) - case T4_COMPRESSION_ITU_T43: - t43_encode_set_image_length(&s->encoder.t43, image_length); - break; -#endif - case T4_COMPRESSION_ITU_T85: - case T4_COMPRESSION_ITU_T85_L0: - t85_encode_set_image_length(&s->encoder.t85, image_length); - break; - } -} -/*- End of function --------------------------------------------------------*/ - SPAN_DECLARE(void) t4_tx_set_max_2d_rows_per_1d_row(t4_tx_state_t *s, int max) { - switch (s->line_encoding) + switch (s->metadata.compression) { - case T4_COMPRESSION_ITU_T4_1D: - case T4_COMPRESSION_ITU_T4_2D: - case T4_COMPRESSION_ITU_T6: + case T4_COMPRESSION_T4_1D: + case T4_COMPRESSION_T4_2D: + case T4_COMPRESSION_T6: t4_t6_encode_set_max_2d_rows_per_1d_row(&s->encoder.t4_t6, max); break; } } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) t4_tx_get_image_width(t4_tx_state_t *s) -{ - return s->image_width; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) t4_tx_set_header_overlays_image(t4_tx_state_t *s, int header_overlays_image) +SPAN_DECLARE(void) t4_tx_set_header_overlays_image(t4_tx_state_t *s, bool header_overlays_image) { s->header_overlays_image = header_overlays_image; } @@ -957,18 +2280,6 @@ SPAN_DECLARE(void) t4_tx_set_header_tz(t4_tx_state_t *s, struct tz_s *tz) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) t4_tx_get_y_resolution(t4_tx_state_t *s) -{ - return s->metadata.y_resolution; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) t4_tx_get_x_resolution(t4_tx_state_t *s) -{ - return s->metadata.x_resolution; -} -/*- End of function --------------------------------------------------------*/ - SPAN_DECLARE(int) t4_tx_get_pages_in_file(t4_tx_state_t *s) { int max; @@ -998,64 +2309,90 @@ SPAN_DECLARE(void) t4_tx_get_transfer_statistics(t4_tx_state_t *s, t4_stats_t *t t->image_type = s->tiff.image_type; t->image_width = s->tiff.image_width; t->image_length = s->tiff.image_length; - t->image_x_resolution = s->tiff.image_x_resolution; - t->image_y_resolution = s->tiff.image_y_resolution; + t->image_x_resolution = s->tiff.x_resolution; + t->image_y_resolution = s->tiff.y_resolution; t->x_resolution = s->metadata.x_resolution; - t->y_resolution = s->metadata.y_resolution/s->row_squashing_ratio; - t->encoding = s->line_encoding; - switch (s->line_encoding) + t->y_resolution = s->metadata.y_resolution; + + t->type = s->metadata.image_type; + t->compression = s->metadata.compression; + + switch (s->metadata.compression) { - case T4_COMPRESSION_ITU_T4_1D: - case T4_COMPRESSION_ITU_T4_2D: - case T4_COMPRESSION_ITU_T6: - t->type = T4_IMAGE_TYPE_BILEVEL; + case T4_COMPRESSION_T4_1D: + case T4_COMPRESSION_T4_2D: + case T4_COMPRESSION_T6: t->width = t4_t6_encode_get_image_width(&s->encoder.t4_t6); - t->length = t4_t6_encode_get_image_length(&s->encoder.t4_t6)/s->row_squashing_ratio; + t->length = t4_t6_encode_get_image_length(&s->encoder.t4_t6); t->line_image_size = t4_t6_encode_get_compressed_image_size(&s->encoder.t4_t6)/8; break; - case T4_COMPRESSION_ITU_T42: - t->type = 0; - t->width = t42_encode_get_image_width(&s->encoder.t42); - t->length = t42_encode_get_image_length(&s->encoder.t42)/s->row_squashing_ratio; - t->line_image_size = t42_encode_get_compressed_image_size(&s->encoder.t42)/8; - break; -#if defined(SPANDSP_SUPPORT_T43) - case T4_COMPRESSION_ITU_T43: - t->type = 0; - t->width = t43_encode_get_image_width(&s->encoder.t43); - t->length = t43_encode_get_image_length(&s->encoder.t43)/s->row_squashing_ratio; - t->line_image_size = t43_encode_get_compressed_image_size(&s->encoder.t43)/8; - break; -#endif - case T4_COMPRESSION_ITU_T85: - case T4_COMPRESSION_ITU_T85_L0: - t->type = T4_IMAGE_TYPE_BILEVEL; + case T4_COMPRESSION_T85: + case T4_COMPRESSION_T85_L0: t->width = t85_encode_get_image_width(&s->encoder.t85); - t->length = t85_encode_get_image_length(&s->encoder.t85)/s->row_squashing_ratio; + t->length = t85_encode_get_image_length(&s->encoder.t85); t->line_image_size = t85_encode_get_compressed_image_size(&s->encoder.t85)/8; break; +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + t->width = t88_encode_get_image_width(&s->encoder.t88); + t->length = t88_encode_get_image_length(&s->encoder.t88); + t->line_image_size = t88_encode_get_compressed_image_size(&s->encoder.t88)/8; + break; +#endif + case T4_COMPRESSION_T42_T81: + case T4_COMPRESSION_SYCC_T81: + t->width = t42_encode_get_image_width(&s->encoder.t42); + t->length = t42_encode_get_image_length(&s->encoder.t42); + t->line_image_size = t42_encode_get_compressed_image_size(&s->encoder.t42)/8; + break; + case T4_COMPRESSION_T43: + t->width = t43_encode_get_image_width(&s->encoder.t43); + t->length = t43_encode_get_image_length(&s->encoder.t43); + t->line_image_size = t43_encode_get_compressed_image_size(&s->encoder.t43)/8; + break; +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + t->width = t45_encode_get_image_width(&s->encoder.t45); + t->length = t45_encode_get_image_length(&s->encoder.t45); + t->line_image_size = t45_encode_get_compressed_image_size(&s->encoder.t45)/8; + break; +#endif } } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(int) t4_tx_image_complete(t4_tx_state_t *s) { - switch (s->line_encoding) + if (s->no_encoder.buf_len > 0) { - case T4_COMPRESSION_ITU_T4_1D: - case T4_COMPRESSION_ITU_T4_2D: - case T4_COMPRESSION_ITU_T6: + if (s->no_encoder.buf_ptr >= s->no_encoder.buf_len) + return SIG_STATUS_END_OF_DATA; + return 0; + } + + switch (s->metadata.compression) + { + case T4_COMPRESSION_T4_1D: + case T4_COMPRESSION_T4_2D: + case T4_COMPRESSION_T6: return t4_t6_encode_image_complete(&s->encoder.t4_t6); - case T4_COMPRESSION_ITU_T42: - return t42_encode_image_complete(&s->encoder.t42); -#if defined(SPANDSP_SUPPORT_T43) - case T4_COMPRESSION_ITU_T43: - return t43_encode_image_complete(&s->encoder.t43); -#endif - case T4_COMPRESSION_ITU_T85: - case T4_COMPRESSION_ITU_T85_L0: + case T4_COMPRESSION_T85: + case T4_COMPRESSION_T85_L0: return t85_encode_image_complete(&s->encoder.t85); +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + return t88_encode_image_complete(&s->encoder.t88); +#endif + case T4_COMPRESSION_T42_T81: + case T4_COMPRESSION_SYCC_T81: + return t42_encode_image_complete(&s->encoder.t42); + case T4_COMPRESSION_T43: + return t43_encode_image_complete(&s->encoder.t43); +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + return t45_encode_image_complete(&s->encoder.t45); +#endif } return SIG_STATUS_END_OF_DATA; } @@ -1063,36 +2400,46 @@ SPAN_DECLARE(int) t4_tx_image_complete(t4_tx_state_t *s) SPAN_DECLARE(int) t4_tx_get_bit(t4_tx_state_t *s) { + int bit; + /* We only get bit by bit for T.4 1D and T.4 2-D. */ + if (s->no_encoder.buf_len > 0) + { + if (s->no_encoder.buf_ptr >= s->no_encoder.buf_len) + return SIG_STATUS_END_OF_DATA; + bit = (s->no_encoder.buf[s->no_encoder.buf_ptr] >> s->no_encoder.bit) & 1; + if (++s->no_encoder.bit >= 8) + { + s->no_encoder.bit = 0; + s->no_encoder.buf_ptr++; + } + return bit; + } return t4_t6_encode_get_bit(&s->encoder.t4_t6); } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(int) t4_tx_get(t4_tx_state_t *s, uint8_t buf[], size_t max_len) { - switch (s->line_encoding) + if (s->no_encoder.buf_len > 0) { - case T4_COMPRESSION_ITU_T4_1D: - case T4_COMPRESSION_ITU_T4_2D: - case T4_COMPRESSION_ITU_T6: - return t4_t6_encode_get(&s->encoder.t4_t6, buf, max_len); - case T4_COMPRESSION_ITU_T42: - return t42_encode_get(&s->encoder.t42, buf, max_len); -#if defined(SPANDSP_SUPPORT_T43) - case T4_COMPRESSION_ITU_T43: - return t43_encode_get(&s->encoder.t43, buf, max_len); -#endif - case T4_COMPRESSION_ITU_T85: - case T4_COMPRESSION_ITU_T85_L0: - return t85_encode_get(&s->encoder.t85, buf, max_len); + if (max_len > (s->no_encoder.buf_len - s->no_encoder.buf_ptr)) + max_len = s->no_encoder.buf_len - s->no_encoder.buf_ptr; + memcpy(buf, &s->no_encoder.buf[s->no_encoder.buf_ptr], max_len); + s->no_encoder.buf_ptr += max_len; + return max_len; } + + if (s->image_get_handler) + return s->image_get_handler((void *) &s->encoder, buf, max_len); + return 0; } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(int) t4_tx_start_page(t4_tx_state_t *s) { - span_log(&s->logging, SPAN_LOG_FLOW, "Start tx page %d - compression %s\n", s->current_page, t4_encoding_to_str(s->line_encoding)); + span_log(&s->logging, SPAN_LOG_FLOW, "Start tx page %d - compression %s\n", s->current_page, t4_compression_to_str(s->metadata.compression)); if (s->current_page > s->stop_page) return -1; if (s->tiff.file) @@ -1105,31 +2452,51 @@ SPAN_DECLARE(int) t4_tx_start_page(t4_tx_state_t *s) } else { - s->image_length = UINT32_MAX; + s->metadata.image_length = UINT32_MAX; } - switch (s->line_encoding) + switch (s->metadata.compression) { - case T4_COMPRESSION_ITU_T4_1D: - case T4_COMPRESSION_ITU_T4_2D: - case T4_COMPRESSION_ITU_T6: - t4_t6_encode_restart(&s->encoder.t4_t6, s->image_width); + case T4_COMPRESSION_T4_1D: + case T4_COMPRESSION_T4_2D: + case T4_COMPRESSION_T6: + t4_t6_encode_restart(&s->encoder.t4_t6, s->metadata.image_width, s->metadata.image_length); + s->image_get_handler = (t4_image_get_handler_t) t4_t6_encode_get; break; - case T4_COMPRESSION_ITU_T42: - t42_encode_restart(&s->encoder.t42, s->image_width, s->image_length); + case T4_COMPRESSION_T85: + case T4_COMPRESSION_T85_L0: + t85_encode_restart(&s->encoder.t85, s->metadata.image_width, s->metadata.image_length); + s->image_get_handler = (t4_image_get_handler_t) t85_encode_get; break; -#if defined(SPANDSP_SUPPORT_T43) - case T4_COMPRESSION_ITU_T43: - t43_encode_restart(&s->encoder.t43, s->image_width, s->image_length); +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + t88_encode_restart(&s->encoder.t88, s->metadata.image_width, s->metadata.image_length); + s->image_get_handler = (t4_image_get_handler_t) t88_encode_get; break; #endif - case T4_COMPRESSION_ITU_T85: - case T4_COMPRESSION_ITU_T85_L0: - t85_encode_restart(&s->encoder.t85, s->image_width, s->image_length); + case T4_COMPRESSION_T42_T81: + case T4_COMPRESSION_SYCC_T81: + t42_encode_restart(&s->encoder.t42, s->metadata.image_width, s->metadata.image_length); + s->image_get_handler = (t4_image_get_handler_t) t42_encode_get; + break; + case T4_COMPRESSION_T43: + t43_encode_restart(&s->encoder.t43, s->metadata.image_width, s->metadata.image_length); + s->image_get_handler = (t4_image_get_handler_t) t43_encode_get; + break; +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + t45_encode_restart(&s->encoder.t45, s->metadata.image_width, s->metadata.image_length); + s->image_get_handler = (t4_image_get_handler_t) t45_encode_get; + break; +#endif + default: + s->image_get_handler = NULL; break; } + /* If there is a page header, create that first */ - if (s->tiff.image_type == T4_IMAGE_TYPE_BILEVEL && s->header_info && s->header_info[0] && make_header(s) == 0) + //if (s->metadata.image_type == T4_IMAGE_TYPE_BILEVEL && s->header_info && s->header_info[0] && make_header(s) == 0) + if (s->header_info && s->header_info[0] && make_header(s) == 0) { s->header_row = 0; set_row_read_handler(s, header_row_read_handler, (void *) s); @@ -1167,12 +2534,12 @@ SPAN_DECLARE(t4_tx_state_t *) t4_tx_init(t4_tx_state_t *s, const char *file, int { int allocated; - allocated = FALSE; + allocated = false; if (s == NULL) { - if ((s = (t4_tx_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (t4_tx_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; - allocated = TRUE; + allocated = true; } memset(s, 0, sizeof(*s)); #if defined(SPANDSP_SUPPORT_TIFF_FX) @@ -1186,7 +2553,7 @@ SPAN_DECLARE(t4_tx_state_t *) t4_tx_init(t4_tx_state_t *s, const char *file, int s->current_page = s->start_page = (start_page >= 0) ? start_page : 0; s->stop_page = (stop_page >= 0) ? stop_page : INT_MAX; - s->line_encoding = T4_COMPRESSION_NONE; + s->metadata.compression = T4_COMPRESSION_NONE; s->row_handler = tiff_row_read_handler; s->row_handler_user_data = (void *) s; @@ -1198,7 +2565,7 @@ SPAN_DECLARE(t4_tx_state_t *) t4_tx_init(t4_tx_state_t *s, const char *file, int if (open_tiff_input_file(s, file) < 0) { if (allocated) - free(s); + span_free(s); return NULL; } s->tiff.file = strdup(file); @@ -1209,7 +2576,7 @@ SPAN_DECLARE(t4_tx_state_t *) t4_tx_init(t4_tx_state_t *s, const char *file, int { tiff_tx_release(s); if (allocated) - free(s); + span_free(s); return NULL; } } @@ -1223,29 +2590,36 @@ SPAN_DECLARE(int) t4_tx_release(t4_tx_state_t *s) tiff_tx_release(s); if (s->header_text) { - free(s->header_text); + span_free(s->header_text); s->header_text = NULL; } if (s->colour_map) { - free(s->colour_map); + span_free(s->colour_map); s->colour_map = NULL; } - switch (s->line_encoding) + switch (s->metadata.compression) { - case T4_COMPRESSION_ITU_T4_1D: - case T4_COMPRESSION_ITU_T4_2D: - case T4_COMPRESSION_ITU_T6: + case T4_COMPRESSION_T4_1D: + case T4_COMPRESSION_T4_2D: + case T4_COMPRESSION_T6: return t4_t6_encode_release(&s->encoder.t4_t6); - case T4_COMPRESSION_ITU_T42: - return t42_encode_release(&s->encoder.t42); -#if defined(SPANDSP_SUPPORT_T43) - case T4_COMPRESSION_ITU_T43: - return t43_encode_release(&s->encoder.t43); -#endif - case T4_COMPRESSION_ITU_T85: - case T4_COMPRESSION_ITU_T85_L0: + case T4_COMPRESSION_T85: + case T4_COMPRESSION_T85_L0: return t85_encode_release(&s->encoder.t85); +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + return t88_encode_release(&s->encoder.t88); +#endif + case T4_COMPRESSION_T42_T81: + case T4_COMPRESSION_SYCC_T81: + return t42_encode_release(&s->encoder.t42); + case T4_COMPRESSION_T43: + return t43_encode_release(&s->encoder.t43); +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + return t45_encode_release(&s->encoder.t45); +#endif } return -1; } @@ -1256,7 +2630,7 @@ SPAN_DECLARE(int) t4_tx_free(t4_tx_state_t *s) int ret; ret = t4_tx_release(s); - free(s); + span_free(s); return ret; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/t81_t82_arith_coding.c b/libs/spandsp/src/t81_t82_arith_coding.c index 86e7e0271f..f9c1408c66 100644 --- a/libs/spandsp/src/t81_t82_arith_coding.c +++ b/libs/spandsp/src/t81_t82_arith_coding.c @@ -33,8 +33,14 @@ #include #include #include +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/t81_t82_arith_coding.h" #include "spandsp/private/t81_t82_arith_coding.h" @@ -45,9 +51,6 @@ compression schemes, such as T.81. However, this code has not been checked to see if it follows the letter of any spec other than T.82. */ -#define FALSE 0 -#define TRUE (!FALSE) - /* Code bytes which must trigger stuffing */ enum { @@ -341,14 +344,14 @@ SPAN_DECLARE(t81_t82_arith_encode_state_t *) t81_t82_arith_encode_init(t81_t82_a { if (s == NULL) { - if ((s = (t81_t82_arith_encode_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (t81_t82_arith_encode_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); s->output_byte_handler = output_byte_handler; s->user_data = user_data; - t81_t82_arith_encode_restart(s, FALSE); + t81_t82_arith_encode_restart(s, false); return s; } /*- End of function --------------------------------------------------------*/ @@ -364,7 +367,7 @@ SPAN_DECLARE(int) t81_t82_arith_encode_free(t81_t82_arith_encode_state_t *s) int ret; ret = t81_t82_arith_encode_release(s); - free(s); + span_free(s); return ret; } /*- End of function --------------------------------------------------------*/ @@ -399,7 +402,7 @@ SPAN_DECLARE(int) t81_t82_arith_decode(t81_t82_arith_decode_state_t *s, int cx) if (s->nopadding) { /* Subsequent symbols might depend on zero padding */ - s->nopadding = FALSE; + s->nopadding = false; return -2; } } @@ -415,7 +418,7 @@ SPAN_DECLARE(int) t81_t82_arith_decode(t81_t82_arith_decode_state_t *s, int cx) if (s->ct >= 0) s->ct--; if (s->a == 0x10000) - s->startup = FALSE; + s->startup = false; } /* T.82 figure 32 - DECODE */ @@ -471,8 +474,8 @@ SPAN_DECLARE(int) t81_t82_arith_decode_restart(t81_t82_arith_decode_state_t *s, s->c = 0; s->a = 1; s->ct = 0; - s->startup = TRUE; - s->nopadding = FALSE; + s->startup = true; + s->nopadding = false; return 0; } /*- End of function --------------------------------------------------------*/ @@ -481,12 +484,12 @@ SPAN_DECLARE(t81_t82_arith_decode_state_t *) t81_t82_arith_decode_init(t81_t82_a { if (s == NULL) { - if ((s = (t81_t82_arith_decode_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (t81_t82_arith_decode_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); - t81_t82_arith_decode_restart(s, FALSE); + t81_t82_arith_decode_restart(s, false); return s; } /*- End of function --------------------------------------------------------*/ @@ -502,7 +505,7 @@ SPAN_DECLARE(int) t81_t82_arith_decode_free(t81_t82_arith_decode_state_t *s) int ret; ret = t81_t82_arith_decode_release(s); - free(s); + span_free(s); return ret; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/t85_decode.c b/libs/spandsp/src/t85_decode.c index 93efc06e81..a687961c02 100644 --- a/libs/spandsp/src/t85_decode.c +++ b/libs/spandsp/src/t85_decode.c @@ -33,8 +33,14 @@ #include #include #include +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/async.h" #include "spandsp/timezone.h" @@ -47,10 +53,7 @@ #include "spandsp/private/t81_t82_arith_coding.h" #include "spandsp/private/t85.h" -#define FALSE 0 -#define TRUE (!FALSE) - -static __inline__ int32_t pack_32(uint8_t *s) +static __inline__ int32_t pack_32(const uint8_t *s) { int32_t value; @@ -78,7 +81,7 @@ static size_t decode_pscd(t85_decode_state_t *s, const uint8_t data[], size_t le s->s.pscd_ptr = data; s->s.pscd_end = data + len; - for (s->interrupt = FALSE; s->i < s->l0 && s->y < s->yd && !s->interrupt; s->i++, s->y++) + for (s->interrupt = false; s->i < s->l0 && s->y < s->yd && !s->interrupt; s->i++, s->y++) { /* Point to the current image bytes */ for (i = 0; i < 3; i++) @@ -126,7 +129,7 @@ static size_t decode_pscd(t85_decode_state_t *s, const uint8_t data[], size_t le } /* This row is 'not typical' and has to be coded completely */ } - s->pseudo = FALSE; + s->pseudo = false; if (s->x == 0) { @@ -223,7 +226,7 @@ static size_t decode_pscd(t85_decode_state_t *s, const uint8_t data[], size_t le *(hp[0] - 1) <<= (s->bytes_per_row*8 - s->xd); s->interrupt = s->row_write_handler(s->row_write_user_data, &s->row_buf[s->p[0]*s->bytes_per_row], s->bytes_per_row); s->x = 0; - s->pseudo = TRUE; + s->pseudo = true; /* Shuffle the row buffers */ s->p[2] = s->p[1]; s->p[1] = s->p[0]; @@ -237,7 +240,7 @@ static size_t decode_pscd(t85_decode_state_t *s, const uint8_t data[], size_t le static int finish_sde(t85_decode_state_t *s) { /* Decode final pixels based on trailing zero bytes */ - s->s.nopadding = FALSE; + s->s.nopadding = false; if (decode_pscd(s, s->buffer, 2) != 2 && s->interrupt) return 1; @@ -247,12 +250,12 @@ static int finish_sde(t85_decode_state_t *s) s->x = 0; s->i = 0; - s->pseudo = TRUE; + s->pseudo = true; s->at_moves = 0; if (s->buffer[1] == T82_SDRST) { s->tx = 0; - s->lntp = TRUE; + s->lntp = true; s->p[0] = 0; s->p[1] = -1; s->p[2] = -1; @@ -262,7 +265,53 @@ static int finish_sde(t85_decode_state_t *s) } /*- End of function --------------------------------------------------------*/ -static int check_bih(t85_decode_state_t *s) +SPAN_DECLARE(bool) t85_analyse_header(uint32_t *width, uint32_t *length, const uint8_t data[], size_t len) +{ + uint32_t i; + uint32_t skip; + + if (len < 20) + { + *width = 0; + *length = 0; + return false; + } + *width = pack_32(&data[6]); + *length = pack_32(&data[10]); + if ((data[19] & T85_VLENGTH)) + { + /* There should be an image length sequence terminating the image later on. */ + /* TODO: scan for a true length, instead of this fudge */ + for (i = 20; i < len - 6; i++) + { + if (data[i] == T82_ESC) + { + if (data[i + 1] == T82_COMMENT) + { + skip = pack_32(&data[2]); + if ((skip + 6) > (len - i)) + break; + i += (6 + skip - 1); + } + else if (data[i + 1] == T82_ATMOVE) + { + i += (8 - 1); + } + else if (data[i + 1] == T82_NEWLEN) + { + /* We are only allow to have one of these, so if we find one + we should not look any further. */ + *length = pack_32(&data[i + 2]); + break; + } + } + } + } + return true; +} +/*- End of function --------------------------------------------------------*/ + +static int extract_bih(t85_decode_state_t *s) { /* Check that the fixed parameters have the values they are expected to be fixed at - see T.85/Table 1 */ @@ -286,50 +335,75 @@ static int check_bih(t85_decode_state_t *s) #endif { span_log(&s->logging, SPAN_LOG_FLOW, "BIH invalid. Fixed bytes do not contain expected values.\n"); + s->end_of_data = 2; return T4_DECODE_INVALID_DATA; } /* P - Number of bit planes */ - if (s->buffer[2] < s->min_bit_planes || s->buffer[2] > s->max_bit_planes) - { - span_log(&s->logging, SPAN_LOG_FLOW, "BIH invalid. %d bit planes. Should be %d to %d.\n", s->buffer[2], s->min_bit_planes, s->max_bit_planes); - return T4_DECODE_INVALID_DATA; - } s->bit_planes = s->buffer[2]; s->current_bit_plane = 0; /* Now look at the stuff which actually counts in a T.85 header. */ /* XD - Horizontal image size at layer D */ s->xd = pack_32(&s->buffer[4]); + /* YD - Vertical image size at layer D */ + s->yd = pack_32(&s->buffer[8]); + /* L0 - Rows per stripe, at the lowest resolution */ + s->l0 = pack_32(&s->buffer[12]); + /* MX - Maximum horizontal offset allowed for AT pixel */ + s->mx = s->buffer[16]; + /* Options byte */ + s->options = s->buffer[19]; + + if (s->bit_planes < s->min_bit_planes || s->bit_planes > s->max_bit_planes) + { + span_log(&s->logging, SPAN_LOG_FLOW, "BIH invalid. %d bit planes. Should be %d to %d.\n", s->bit_planes, s->min_bit_planes, s->max_bit_planes); + s->end_of_data = 2; + return T4_DECODE_INVALID_DATA; + } if (s->xd == 0 || (s->max_xd && s->xd > s->max_xd)) { span_log(&s->logging, SPAN_LOG_FLOW, "BIH invalid. Width is %" PRIu32 "\n", s->xd); + s->end_of_data = 2; return T4_DECODE_INVALID_DATA; } - /* YD - Vertical image size at layer D */ - s->yd = pack_32(&s->buffer[8]); - if (s->yd == 0 || (s->max_yd && s->yd > s->max_yd)) + if (s->yd == 0) { span_log(&s->logging, SPAN_LOG_FLOW, "BIH invalid. Length is %" PRIu32 "\n", s->yd); + s->end_of_data = 2; return T4_DECODE_INVALID_DATA; } - /* L0 - Rows per stripe, at the lowest resolution */ - s->l0 = pack_32(&s->buffer[12]); + if (s->max_yd) + { + if ((s->options & T85_VLENGTH)) + { + if (s->yd > s->max_yd) + s->yd = s->max_yd; + } + else + { + if (s->yd > s->max_yd) + { + span_log(&s->logging, SPAN_LOG_FLOW, "BIH invalid. Length is %" PRIu32 "\n", s->yd); + s->end_of_data = 2; + return T4_DECODE_INVALID_DATA; + } + } + } if (s->l0 == 0) { span_log(&s->logging, SPAN_LOG_FLOW, "BIH invalid. L0 is %" PRIu32 "\n", s->l0); + s->end_of_data = 2; return T4_DECODE_INVALID_DATA; } - /* MX - Maximum horizontal offset allowed for AT pixel */ - s->mx = s->buffer[16]; if (s->mx > 127) { span_log(&s->logging, SPAN_LOG_FLOW, "BIH invalid. MX is %d\n", s->mx); + s->end_of_data = 2; return T4_DECODE_INVALID_DATA; } - /* Options byte */ - s->options = s->buffer[19]; - if ((s->options & 0x97)) + if ((s->options & ~(T85_LRLTWO | T85_VLENGTH | T85_TPBON))) { span_log(&s->logging, SPAN_LOG_FLOW, "BIH invalid. Options are 0x%X\n", s->options); + s->end_of_data = 2; return T4_DECODE_INVALID_DATA; } span_log(&s->logging, SPAN_LOG_FLOW, "BIH is OK. Image is %" PRIu32 "x%" PRIu32 " pixels\n", s->xd, s->yd); @@ -375,6 +449,8 @@ SPAN_DECLARE(int) t85_decode_put(t85_decode_state_t *s, const uint8_t data[], si { if (s->y >= s->yd) return T4_DECODE_OK; + if (s->end_of_data > 0) + return T4_DECODE_INVALID_DATA; /* This is the end of image condition */ s->end_of_data = 1; } @@ -391,7 +467,7 @@ SPAN_DECLARE(int) t85_decode_put(t85_decode_state_t *s, const uint8_t data[], si cnt = i; if (s->bie_len < 20) return T4_DECODE_MORE_DATA; - if ((ret = check_bih(s)) != T4_DECODE_OK) + if ((ret = extract_bih(s)) != T4_DECODE_OK) return ret; /* Set up the two/three row buffer */ bytes_per_row = (s->xd + 7) >> 3; @@ -399,7 +475,7 @@ SPAN_DECLARE(int) t85_decode_put(t85_decode_state_t *s, const uint8_t data[], si if (min_len > s->row_buf_len) { /* We need to expand the 3 row buffer */ - if ((buf = (uint8_t *) realloc(s->row_buf, min_len)) == NULL) + if ((buf = (uint8_t *) span_realloc(s->row_buf, min_len)) == NULL) return T4_DECODE_NOMEM; s->row_buf = buf; s->row_buf_len = min_len; @@ -409,7 +485,7 @@ SPAN_DECLARE(int) t85_decode_put(t85_decode_state_t *s, const uint8_t data[], si s->s.nopadding = s->options & T85_VLENGTH; if (s->comment) { - free(s->comment); + span_free(s->comment); s->comment = NULL; } s->comment_len = 0; @@ -419,10 +495,10 @@ SPAN_DECLARE(int) t85_decode_put(t85_decode_state_t *s, const uint8_t data[], si s->x = 0; s->y = 0; s->i = 0; - s->pseudo = TRUE; + s->pseudo = true; s->at_moves = 0; s->tx = 0; - s->lntp = TRUE; + s->lntp = true; s->bytes_per_row = bytes_per_row; s->p[0] = 0; s->p[1] = -1; @@ -455,7 +531,7 @@ SPAN_DECLARE(int) t85_decode_put(t85_decode_state_t *s, const uint8_t data[], si s->interrupt = s->comment_handler(s->comment_user_data, s->comment, s->comment_len); if (s->comment) { - free(s->comment); + span_free(s->comment); s->comment = NULL; } s->comment_len = 0; @@ -489,7 +565,6 @@ SPAN_DECLARE(int) t85_decode_put(t85_decode_state_t *s, const uint8_t data[], si the commonest thing for us to hit here. */ decode_pscd(s, s->buffer, 2); s->buf_len = 0; - if (s->interrupt) return T4_DECODE_INTERRUPT; break; @@ -506,12 +581,12 @@ SPAN_DECLARE(int) t85_decode_put(t85_decode_state_t *s, const uint8_t data[], si s->comment_len = pack_32(&s->buffer[2]); /* Only try to buffer and process the comment's contents if we have a defined callback routine to do something with it. */ - /* If this malloc fails we carry on working just fine, and don't try to + /* If this allocate fails we carry on working just fine, and don't try to process the contents of the comment. That is fairly benign, as the comments are not generally of critical importance, so let's not worry. */ if (s->comment_handler && s->comment_len > 0 && s->comment_len <= s->max_comment_len) - s->comment = malloc(s->comment_len); + s->comment = span_alloc(s->comment_len); s->comment_progress = 0; continue; case T82_ATMOVE: @@ -520,9 +595,11 @@ SPAN_DECLARE(int) t85_decode_put(t85_decode_state_t *s, const uint8_t data[], si continue; s->buf_needed = 2; s->buf_len = 0; - if (s->at_moves >= T85_ATMOVES_MAX) + { + s->end_of_data = 2; return T4_DECODE_INVALID_DATA; + } s->at_row[s->at_moves] = pack_32(&s->buffer[2]); s->at_tx[s->at_moves] = s->buffer[6]; if (s->at_tx[s->at_moves] > s->mx @@ -531,6 +608,7 @@ SPAN_DECLARE(int) t85_decode_put(t85_decode_state_t *s, const uint8_t data[], si || s->buffer[7] != 0) { + s->end_of_data = 2; return T4_DECODE_INVALID_DATA; } s->at_moves++; @@ -541,14 +619,19 @@ SPAN_DECLARE(int) t85_decode_put(t85_decode_state_t *s, const uint8_t data[], si continue; s->buf_needed = 2; s->buf_len = 0; - if (!(s->options & T85_VLENGTH)) + { + s->end_of_data = 2; return T4_DECODE_INVALID_DATA; + } s->options &= ~T85_VLENGTH; y = pack_32(&s->buffer[2]); /* An update to the image length is not allowed to stretch it. */ if (y > s->yd) + { + s->end_of_data = 2; return T4_DECODE_INVALID_DATA; + } s->yd = y; break; case T82_SDNORM: @@ -630,7 +713,10 @@ SPAN_DECLARE(int) t85_decode_put(t85_decode_state_t *s, const uint8_t data[], si y = pack_32(&s->buffer[4]); /* An update to the image length is not allowed to stretch it. */ if (y > s->yd) + { + s->end_of_data = 2; return T4_DECODE_INVALID_DATA; + } /* Things look OK, so accept this new length, and proceed. */ s->yd = y; /* Now process the T82_SDNORM or T82_SDRST */ @@ -644,6 +730,7 @@ SPAN_DECLARE(int) t85_decode_put(t85_decode_state_t *s, const uint8_t data[], si break; default: s->buf_len = 0; + s->end_of_data = 2; return T4_DECODE_INVALID_DATA; } } @@ -657,13 +744,15 @@ SPAN_DECLARE(int) t85_decode_put(t85_decode_state_t *s, const uint8_t data[], si cnt += decode_pscd(s, data + cnt, len - cnt); if (s->interrupt) return T4_DECODE_INTERRUPT; - /* We should only have stopped processing PSCD if - we ran out of data, or hit a T82_ESC */ + /* We should only have stopped processing PSCD if we ran out of data, + or hit a T82_ESC */ if (cnt < len && data[cnt] != T82_ESC) + { + s->end_of_data = 2; return T4_DECODE_INVALID_DATA; + } } } - return T4_DECODE_MORE_DATA; } /*- End of function --------------------------------------------------------*/ @@ -732,20 +821,20 @@ SPAN_DECLARE(int) t85_decode_new_plane(t85_decode_state_t *s) memset(s->at_row, 0, sizeof(s->at_row)); memset(s->at_tx, 0, sizeof(s->at_tx)); memset(s->row_h, 0, sizeof(s->row_h)); - s->pseudo = FALSE; - s->lntp = FALSE; - s->interrupt = FALSE; + s->pseudo = false; + s->lntp = false; + s->interrupt = false; s->end_of_data = 0; if (s->comment) { - free(s->comment); + span_free(s->comment); s->comment = NULL; } s->comment_len = 0; s->comment_progress = 0; s->compressed_image_size = 0; - t81_t82_arith_decode_restart(&s->s, FALSE); + t81_t82_arith_decode_restart(&s->s, false); s->s.nopadding = s->options & T85_VLENGTH; s->buf_len = 0; @@ -753,10 +842,10 @@ SPAN_DECLARE(int) t85_decode_new_plane(t85_decode_state_t *s) s->x = 0; s->y = 0; s->i = 0; - s->pseudo = TRUE; + s->pseudo = true; s->at_moves = 0; s->tx = 0; - s->lntp = TRUE; + s->lntp = true; s->p[0] = 0; s->p[1] = -1; s->p[2] = -1; @@ -780,20 +869,20 @@ SPAN_DECLARE(int) t85_decode_restart(t85_decode_state_t *s) memset(s->at_row, 0, sizeof(s->at_row)); memset(s->at_tx, 0, sizeof(s->at_tx)); memset(s->row_h, 0, sizeof(s->row_h)); - s->pseudo = FALSE; - s->lntp = FALSE; - s->interrupt = FALSE; + s->pseudo = false; + s->lntp = false; + s->interrupt = false; s->end_of_data = 0; if (s->comment) { - free(s->comment); + span_free(s->comment); s->comment = NULL; } s->comment_len = 0; s->comment_progress = 0; s->compressed_image_size = 0; - t81_t82_arith_decode_restart(&s->s, FALSE); + t81_t82_arith_decode_restart(&s->s, false); return 0; } @@ -811,7 +900,7 @@ SPAN_DECLARE(t85_decode_state_t *) t85_decode_init(t85_decode_state_t *s, { if (s == NULL) { - if ((s = (t85_decode_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (t85_decode_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -837,12 +926,12 @@ SPAN_DECLARE(int) t85_decode_release(t85_decode_state_t *s) { if (s->row_buf) { - free(s->row_buf); + span_free(s->row_buf); s->row_buf = NULL; } if (s->comment) { - free(s->comment); + span_free(s->comment); s->comment = NULL; } return 0; @@ -854,7 +943,7 @@ SPAN_DECLARE(int) t85_decode_free(t85_decode_state_t *s) int ret; ret = t85_decode_release(s); - free(s); + span_free(s); return ret; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/t85_encode.c b/libs/spandsp/src/t85_encode.c index ed8e47364f..ed4d1adaff 100644 --- a/libs/spandsp/src/t85_encode.c +++ b/libs/spandsp/src/t85_encode.c @@ -33,8 +33,14 @@ #include #include #include +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/async.h" #include "spandsp/timezone.h" @@ -78,7 +84,7 @@ static void put_stuff(t85_encode_state_t *s, const uint8_t buf[], int len) /* The number of uncompressed bytes per row seems like a reasonable measure of what to expect as a poor case for a compressed row. */ bytes_per_row = (s->xd + 7) >> 3; - if ((new_buf = realloc(s->bitstream, s->bitstream_len + len + bytes_per_row)) == NULL) + if ((new_buf = span_realloc(s->bitstream, s->bitstream_len + len + bytes_per_row)) == NULL) return; s->bitstream = new_buf; s->bitstream_len += (len + bytes_per_row); @@ -278,7 +284,7 @@ static int get_next_row(t85_encode_state_t *s) return 0; /* We can't clip the image to the current length. We will have to continue up to the original length with blank (all white) rows. */ - s->fill_with_white = TRUE; + s->fill_with_white = true; memset(s->prev_row[0], 0, bytes_per_row); } } @@ -311,11 +317,11 @@ static int get_next_row(t85_encode_state_t *s) for (i = 0; i <= s->mx; i++) s->c[i] = 0; } - t81_t82_arith_encode_restart(&s->s, TRUE); + t81_t82_arith_encode_restart(&s->s, true); } /* Typical prediction */ - ltp = FALSE; + ltp = false; if ((s->options & T85_TPBON)) { /* Look for a match between the rows */ @@ -518,7 +524,7 @@ SPAN_DECLARE(int) t85_encode_set_image_width(t85_encode_state_t *s, uint32_t ima return -1; s->xd = image_width; bytes_per_row = (s->xd + 7) >> 3; - if ((t = (uint8_t *) realloc(s->row_buf, 3*bytes_per_row)) == NULL) + if ((t = (uint8_t *) span_realloc(s->row_buf, 3*bytes_per_row)) == NULL) return -1; s->row_buf = t; memset(s->row_buf, 0, 3*bytes_per_row); @@ -658,16 +664,16 @@ SPAN_DECLARE(int) t85_encode_restart(t85_encode_state_t *s, uint32_t image_width s->newlen = NEWLEN_NONE; s->new_tx = -1; s->tx = 0; - s->prev_ltp = FALSE; + s->prev_ltp = false; s->bitstream_iptr = 0; s->bitstream_optr = 0; if (s->bitstream) { - free(s->bitstream); + span_free(s->bitstream); s->bitstream = NULL; } s->bitstream_len = 0; - s->fill_with_white = FALSE; + s->fill_with_white = false; s->compressed_image_size = 0; t81_t82_arith_encode_init(&s->s, output_byte, s); @@ -689,7 +695,7 @@ SPAN_DECLARE(t85_encode_state_t *) t85_encode_init(t85_encode_state_t *s, { if (s == NULL) { - if ((s = (t85_encode_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (t85_encode_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -722,12 +728,12 @@ SPAN_DECLARE(int) t85_encode_release(t85_encode_state_t *s) { if (s->row_buf) { - free(s->row_buf); + span_free(s->row_buf); s->row_buf = NULL; } if (s->bitstream) { - free(s->bitstream); + span_free(s->bitstream); s->bitstream = NULL; s->bitstream_len = 0; } @@ -740,7 +746,7 @@ SPAN_DECLARE(int) t85_encode_free(t85_encode_state_t *s) int ret; ret = t85_encode_release(s); - free(s); + span_free(s); return ret; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/time_scale.c b/libs/spandsp/src/time_scale.c index 5b2a64a66b..1096ca3e32 100644 --- a/libs/spandsp/src/time_scale.c +++ b/libs/spandsp/src/time_scale.c @@ -42,9 +42,15 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/fast_convert.h" #include "spandsp/time_scale.h" #include "spandsp/saturated.h" @@ -125,17 +131,17 @@ SPAN_DECLARE(int) time_scale_rate(time_scale_state_t *s, float playout_rate) SPAN_DECLARE(time_scale_state_t *) time_scale_init(time_scale_state_t *s, int sample_rate, float playout_rate) { - int alloced; + bool alloced; if (sample_rate > TIME_SCALE_MAX_SAMPLE_RATE) return NULL; - alloced = FALSE; + alloced = false; if (s == NULL) { - if ((s = (time_scale_state_t *) malloc(sizeof (*s))) == NULL) + if ((s = (time_scale_state_t *) span_alloc(sizeof (*s))) == NULL) return NULL; /*endif*/ - alloced = TRUE; + alloced = true; } /*endif*/ s->sample_rate = sample_rate; @@ -145,7 +151,7 @@ SPAN_DECLARE(time_scale_state_t *) time_scale_init(time_scale_state_t *s, int sa if (time_scale_rate(s, playout_rate)) { if (alloced) - free(s); + span_free(s); return NULL; } /*endif*/ @@ -164,7 +170,7 @@ SPAN_DECLARE(int) time_scale_release(time_scale_state_t *s) SPAN_DECLARE(int) time_scale_free(time_scale_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/timezone.c b/libs/spandsp/src/timezone.c index 79966f1d4c..cd84dc42e2 100644 --- a/libs/spandsp/src/timezone.c +++ b/libs/spandsp/src/timezone.c @@ -44,21 +44,19 @@ #include #include #include +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/timezone.h" #include "spandsp/private/timezone.h" -#if !defined(FALSE) -#define FALSE 0 -#endif - -#if !defined(TRUE) -#define TRUE (!FALSE) -#endif - #define SECS_PER_MIN 60 #define MINS_PER_HOUR 60 #define HOURS_PER_DAY 24 @@ -644,7 +642,7 @@ static int tzparse(const char *name, struct tz_state_s * const sp, const int las } } /* Initially we're assumed to be in standard time. */ - isdst = FALSE; + isdst = false; theiroffset = theirstdoffset; /* Now juggle transition times and types tracking offsets as you do. */ for (i = 0; i < sp->timecnt; i++) @@ -680,10 +678,10 @@ static int tzparse(const char *name, struct tz_state_s * const sp, const int las } /* Finally, fill in ttis. ttisstd and ttisgmt need not be handled. */ sp->ttis[0].gmtoff = -stdoffset; - sp->ttis[0].isdst = FALSE; + sp->ttis[0].isdst = false; sp->ttis[0].abbrind = 0; sp->ttis[1].gmtoff = -dstoffset; - sp->ttis[1].isdst = TRUE; + sp->ttis[1].isdst = true; sp->ttis[1].abbrind = stdlen + 1; sp->typecnt = 2; } @@ -741,9 +739,9 @@ static void tz_set(tz_t *tz, const char *tzstring) lclptr->ttis[0].abbrind = 0; strcpy(lclptr->chars, gmt); } - else if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) + else if (name[0] == ':' || tzparse(name, lclptr, false) != 0) { - tzparse(gmt, lclptr, TRUE); + tzparse(gmt, lclptr, true); } set_tzname(tz); } @@ -796,7 +794,7 @@ SPAN_DECLARE(tz_t *) tz_init(tz_t *tz, const char *tzstring) { if (tz == NULL) { - if ((tz = (tz_t *) malloc(sizeof(*tz))) == NULL) + if ((tz = (tz_t *) span_alloc(sizeof(*tz))) == NULL) return NULL; } memset(tz, 0, sizeof(*tz)); @@ -816,7 +814,7 @@ SPAN_DECLARE(int) tz_release(tz_t *tz) SPAN_DECLARE(int) tz_free(tz_t *tz) { if (tz) - free(tz); + span_free(tz); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/tone_detect.c b/libs/spandsp/src/tone_detect.c index 4dfea5d5bf..2865ba40d8 100644 --- a/libs/spandsp/src/tone_detect.c +++ b/libs/spandsp/src/tone_detect.c @@ -44,6 +44,7 @@ #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/complex.h" #include "spandsp/complex_vector_float.h" #include "spandsp/tone_detect.h" @@ -72,7 +73,7 @@ SPAN_DECLARE(goertzel_state_t *) goertzel_init(goertzel_state_t *s, { if (s == NULL) { - if ((s = (goertzel_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (goertzel_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } #if defined(SPANDSP_USE_FIXED_POINT) @@ -98,7 +99,7 @@ SPAN_DECLARE(int) goertzel_release(goertzel_state_t *s) SPAN_DECLARE(int) goertzel_free(goertzel_state_t *s) { if (s) - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/tone_generate.c b/libs/spandsp/src/tone_generate.c index 21285f6a96..be3f6854a4 100644 --- a/libs/spandsp/src/tone_generate.c +++ b/libs/spandsp/src/tone_generate.c @@ -44,6 +44,7 @@ #include "floating_fudge.h" #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/fast_convert.h" #include "spandsp/complex.h" #include "spandsp/dds.h" @@ -69,7 +70,7 @@ SPAN_DECLARE(tone_gen_descriptor_t *) tone_gen_descriptor_init(tone_gen_descript { if (s == NULL) { - if ((s = (tone_gen_descriptor_t *) malloc(sizeof(*s))) == NULL) + if ((s = (tone_gen_descriptor_t *) span_alloc(sizeof(*s))) == NULL) { return NULL; } @@ -114,7 +115,7 @@ SPAN_DECLARE(tone_gen_descriptor_t *) tone_gen_descriptor_init(tone_gen_descript SPAN_DECLARE(void) tone_gen_descriptor_free(tone_gen_descriptor_t *s) { - free(s); + span_free(s); } /*- End of function --------------------------------------------------------*/ @@ -220,7 +221,7 @@ SPAN_DECLARE(tone_gen_state_t *) tone_gen_init(tone_gen_state_t *s, tone_gen_des if (s == NULL) { - if ((s = (tone_gen_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (tone_gen_state_t *) span_alloc(sizeof(*s))) == NULL) { return NULL; } @@ -252,7 +253,7 @@ SPAN_DECLARE(int) tone_gen_release(tone_gen_state_t *s) SPAN_DECLARE(int) tone_gen_free(tone_gen_state_t *s) { if (s) - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/v17rx.c b/libs/spandsp/src/v17rx.c index 9aae8bfbf1..85d72d0ed6 100644 --- a/libs/spandsp/src/v17rx.c +++ b/libs/spandsp/src/v17rx.c @@ -40,9 +40,15 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/fast_convert.h" #include "spandsp/math_fixed.h" @@ -63,6 +69,7 @@ #include "spandsp/v17rx.h" #include "spandsp/private/logging.h" +#include "spandsp/private/power_meter.h" #include "spandsp/private/v17rx.h" #if defined(SPANDSP_USE_FIXED_POINTx) @@ -73,10 +80,21 @@ #define FP_SCALE(x) (x) #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) +#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_rx_constellation_maps.h" @@ -106,6 +124,23 @@ /*! The 16 bit pattern used in the bridge section of the training sequence */ #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 { TRAINING_STAGE_NORMAL_OPERATION = 0, @@ -123,33 +158,6 @@ enum 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) static const int16_t constellation_spacing[4] = #else @@ -245,14 +253,14 @@ static void equalizer_reset(v17_rx_state_t *s) { /* Start with an equalizer based on everything being perfect */ #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); s->eq_coeff[V17_EQUALIZER_PRE_LEN] = x; cvec_zeroi16(s->eq_buf, V17_EQUALIZER_LEN); s->eq_delta = 32768.0f*EQUALIZER_DELTA/V17_EQUALIZER_LEN; #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); s->eq_coeff[V17_EQUALIZER_PRE_LEN] = x; @@ -313,20 +321,6 @@ static void tune_equalizer(v17_rx_state_t *s, const complexf_t *z, const complex #endif /*- 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) static __inline__ void track_carrier(v17_rx_state_t *s, const complexi16_t *z, const complexi16_t *target) #else @@ -343,7 +337,7 @@ static __inline__ void track_carrier(v17_rx_state_t *s, const complexf_t *z, con positions is proportional to the phase error, for any particular target. However, the different amplitudes of the various target positions scale things. */ #if defined(SPANDSP_USE_FIXED_POINTx) - error = z->im*(target->re >> FP_SHIFT_FACTOR) - z->re*(target->im >> FP_SHIFT_FACTOR); + error = z->im*(((int32_t) target->re) >> FP_SHIFT_FACTOR) - z->re*(((int32_t) target->im) >> FP_SHIFT_FACTOR); s->carrier_phase_rate += ((s->carrier_track_i*error) >> FP_SHIFT_FACTOR); s->carrier_phase += ((s->carrier_track_p*error) >> FP_SHIFT_FACTOR); #else @@ -355,15 +349,30 @@ static __inline__ void track_carrier(v17_rx_state_t *s, const complexf_t *z, con } /*- 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) { int out_bit; /* We need to strip the last part of the training - the test period of all 1s - before we let data go to the application. */ + out_bit = descramble(s, bit); if (s->training_stage == TRAINING_STAGE_NORMAL_OPERATION) { - out_bit = descramble(s, bit); s->put_bit(s->put_bit_user_data, out_bit); } else if (s->training_stage == TRAINING_STAGE_TEST_ONES) @@ -371,16 +380,15 @@ static __inline__ void put_bit(v17_rx_state_t *s, int bit) /* The bits during the final stage of training should be all ones. However, buggy modems mean you cannot rely on this. Therefore we don't bother testing for ones, but just rely on a constellation mismatch measurement. */ - out_bit = descramble(s, bit); //span_log(&s->logging, SPAN_LOG_FLOW, "A 1 is really %d\n", out_bit); } } /*- End of function --------------------------------------------------------*/ #if defined(SPANDSP_USE_FIXED_POINTx) -static __inline__ uint32_t dist_sq(const complexi32_t *x, const complexi32_t *y) +static __inline__ uint32_t dist_sq(const complexi16_t *x, const complexi16_t *y) { - return (x->re - y->re)*(x->re - y->re) + (x->im - y->im)*(x->im - y->im); + return (int32_t) (x->re - y->re)*(x->re - y->re) + (int32_t) (x->im - y->im)*(x->im - y->im); } /*- End of function --------------------------------------------------------*/ #else @@ -444,11 +452,11 @@ static int decode_baud(v17_rx_state_t *s, complexf_t *z) #endif #if defined(SPANDSP_USE_FIXED_POINTx) - re = (z->re + 9*FP_FACTOR) >> (FP_SHIFT_FACTOR - 1); - im = (z->im + 9*FP_FACTOR) >> (FP_SHIFT_FACTOR - 1); + re = (z->re + FP_CONSTELLATION_SCALE(9.0f)) >> (FP_CONSTELLATION_SHIFT_FACTOR - 1); + im = (z->im + FP_CONSTELLATION_SCALE(9.0f)) >> (FP_CONSTELLATION_SHIFT_FACTOR - 1); #else - re = (int) ((z->re + 9.0f)*2.0f); - im = (int) ((z->im + 9.0f)*2.0f); + re = (int) ((z->re + FP_CONSTELLATION_SCALE(9.0f))*2.0f); + im = (int) ((z->im + FP_CONSTELLATION_SCALE(9.0f))*2.0f); #endif if (re > 35) re = 35; @@ -609,9 +617,9 @@ static __inline__ void symbol_sync(v17_rx_state_t *s) #if defined(SPANDSP_USE_FIXED_POINTx) /* TODO: The scalings used here need more thorough evaluation, to see if overflows are possible. */ /* Cross correlate */ - v = (((s->symbol_sync_low[1] >> 5)*(s->symbol_sync_high[0] >> 4)) >> 15)*SYNC_LOW_BAND_EDGE_COEFF_2 - - (((s->symbol_sync_low[0] >> 5)*(s->symbol_sync_high[1] >> 4)) >> 15)*SYNC_HIGH_BAND_EDGE_COEFF_2 - + (((s->symbol_sync_low[1] >> 5)*(s->symbol_sync_high[1] >> 4)) >> 15)*SYNC_MIXED_EDGES_COEFF_3; + v = (((s->symbol_sync_low[1] >> (FP_SYNC_SHIFT_FACTOR/2))*(s->symbol_sync_high[0] >> (FP_SYNC_SHIFT_FACTOR/2))) >> 14)*SYNC_LOW_BAND_EDGE_COEFF_2 + - (((s->symbol_sync_low[0] >> (FP_SYNC_SHIFT_FACTOR/2))*(s->symbol_sync_high[1] >> (FP_SYNC_SHIFT_FACTOR/2))) >> 14)*SYNC_HIGH_BAND_EDGE_COEFF_2 + + (((s->symbol_sync_low[1] >> (FP_SYNC_SHIFT_FACTOR/2))*(s->symbol_sync_high[1] >> (FP_SYNC_SHIFT_FACTOR/2))) >> 14)*SYNC_MIXED_EDGES_COEFF_3; /* Filter away any DC component */ p = v - s->symbol_sync_dc_filter[1]; s->symbol_sync_dc_filter[1] = s->symbol_sync_dc_filter[0]; @@ -619,10 +627,10 @@ static __inline__ void symbol_sync(v17_rx_state_t *s) /* A little integration will now filter away much of the HF noise */ s->baud_phase -= p; v = labs(s->baud_phase); - if (v > 100*FP_FACTOR) + if (v > FP_SYNC_SCALE_32(100.0f)) { - i = (v > 1000*FP_FACTOR) ? 15 : 1; - if (s->baud_phase < 0) + i = (v > FP_SYNC_SCALE_32(1000.0f)) ? 15 : 1; + if (s->baud_phase < FP_SYNC_SCALE_32(0.0f)) i = -i; //printf("v = %10.5f %5d - %f %f %d %d\n", v, i, p, s->baud_phase, s->total_baud_timing_correction); s->eq_put_step += i; @@ -640,10 +648,10 @@ static __inline__ void symbol_sync(v17_rx_state_t *s) /* A little integration will now filter away much of the HF noise */ s->baud_phase -= p; v = fabsf(s->baud_phase); - if (v > 100.0f) + if (v > FP_SYNC_SCALE_32(100.0f)) { - i = (v > 1000.0f) ? 15 : 1; - if (s->baud_phase < 0.0f) + i = (v > FP_SYNC_SCALE_32(1000.0f)) ? 15 : 1; + if (s->baud_phase < FP_SYNC_SCALE_32(0.0f)) i = -i; //printf("v = %10.5f %5d - %f %f %d\n", v, i, p, s->baud_phase, s->total_baud_timing_correction); s->eq_put_step += i; @@ -675,13 +683,13 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample) complexi16_t z; complexi16_t z16; 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 float p; complexf_t z; complexf_t zz; 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 int bit; int i; @@ -724,13 +732,8 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample) s->training_stage = TRAINING_STAGE_LOG_PHASE; vec_zeroi32(s->diff_angles, 16); s->last_angles[0] = arctan2(z.im, z.re); -#if defined(SPANDSP_USE_FIXED_POINTx) - if (s->agc_scaling_save == 0) + if (s->agc_scaling_save == FP_SCALE(0.0f)) s->agc_scaling_save = s->agc_scaling; -#else - if (s->agc_scaling_save == 0.0f) - s->agc_scaling_save = s->agc_scaling; -#endif } break; case TRAINING_STAGE_LOG_PHASE: @@ -816,11 +819,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"); /* Park this modem */ -#if defined(SPANDSP_USE_FIXED_POINTx) - s->agc_scaling_save = 0; -#else - s->agc_scaling_save = 0.0f; -#endif + s->agc_scaling_save = FP_SCALE(0.0f); s->training_stage = TRAINING_STAGE_PARKED; report_status_change(s, SIG_STATUS_TRAINING_FAILED); break; @@ -860,11 +859,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. */ span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n"); /* Park this modem */ -#if defined(SPANDSP_USE_FIXED_POINTx) - s->agc_scaling_save = 0; -#else - s->agc_scaling_save = 0.0f; -#endif + s->agc_scaling_save = FP_SCALE(0.0f); s->training_stage = TRAINING_STAGE_PARKED; report_status_change(s, SIG_STATUS_TRAINING_FAILED); } @@ -880,12 +875,11 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample) #if defined(SPANDSP_USE_FIXED_POINTx) z16 = complex_subi16(&z, target); 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 zz = complex_subf(&z, target); 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 + 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 if (++s->training_count == V17_TRAINING_SEG_2_LEN - 2000) #endif @@ -911,12 +905,11 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample) tune_equalizer(s, &z, target); if (++s->training_count >= V17_TRAINING_SEG_2_LEN - 48) { + s->training_error = FP_SCALE(0.0f); #if defined(SPANDSP_USE_FIXED_POINTx) - s->training_error = 0; s->carrier_track_i = 100; s->carrier_track_p = 500000; #else - s->training_error = 0.0f; s->carrier_track_i = 100.0f; s->carrier_track_p = 500000.0f; #endif @@ -948,15 +941,12 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample) { #if defined(SPANDSP_USE_FIXED_POINTx) 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 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 + 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_stage = TRAINING_STAGE_BRIDGE; } @@ -964,11 +954,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"); /* Park this modem */ -#if defined(SPANDSP_USE_FIXED_POINTx) - s->agc_scaling_save = 0; -#else - s->agc_scaling_save = 0.0f; -#endif + s->agc_scaling_save = FP_SCALE(0.0f); s->training_stage = TRAINING_STAGE_PARKED; report_status_change(s, SIG_STATUS_TRAINING_FAILED); } @@ -980,11 +966,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample) target = &z; if (++s->training_count >= V17_TRAINING_SEG_3_LEN) { -#if defined(SPANDSP_USE_FIXED_POINTx) - s->training_error = 0; -#else - s->training_error = 0.0f; -#endif + s->training_error = FP_SCALE(0.0f); s->training_count = 0; if (s->bits_per_symbol == 2) { @@ -1012,11 +994,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample) bit = descramble(s, 1); bit = (bit << 1) | descramble(s, 1); target = &cdba[bit]; -#if defined(SPANDSP_USE_FIXED_POINTx) - s->training_error = 0; -#else - s->training_error = 0.0f; -#endif + s->training_error = FP_SCALE(0.0f); s->training_count = 1; s->training_stage = TRAINING_STAGE_SHORT_TRAIN_ON_CDBA_AND_TEST; break; @@ -1066,11 +1044,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. However, it is not clear why this is an improvement, If something gives 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)*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 + if (s->training_error < (V17_TRAINING_SHORT_SEG_2_LEN - 8)*FP_SCALE(4.0f)*FP_SCALE(1.0f)*constellation_spacing[s->space_map]) { s->training_count = 0; if (s->bits_per_symbol == 2) @@ -1078,11 +1052,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 */ /* Restart the differential decoder */ s->diff = (s->short_train) ? 0 : 1; -#if defined(SPANDSP_USE_FIXED_POINTx) - s->training_error = 0; -#else - s->training_error = 0.0f; -#endif + s->training_error = FP_SCALE(0.0f); s->training_stage = TRAINING_STAGE_TEST_ONES; } else @@ -1116,11 +1086,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample) #endif if (++s->training_count >= V17_TRAINING_SEG_4A_LEN) { -#if defined(SPANDSP_USE_FIXED_POINTx) - s->training_error = 0; -#else - s->training_error = 0.0f; -#endif + s->training_error = FP_SCALE(0.0f); s->training_count = 0; /* Restart the differential decoder */ s->diff = (s->short_train) ? 0 : 1; @@ -1143,13 +1109,11 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample) #endif 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_FACTOR*FP_FACTOR*constellation_spacing[s->space_map]) + if (s->training_error < V17_TRAINING_SEG_4_LEN*FP_SCALE(1.0f)*FP_SCALE(1.0f)*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); #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); #endif /* We are up and running */ @@ -1159,7 +1123,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample) s->signal_present = 60; equalizer_save(s); s->carrier_phase_rate_save = s->carrier_phase_rate; - s->short_train = TRUE; + s->short_train = true; s->training_stage = TRAINING_STAGE_NORMAL_OPERATION; } else @@ -1167,13 +1131,11 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample) /* Training has failed. Park this modem. */ #if defined(SPANDSP_USE_FIXED_POINTx) 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 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 + if (!s->short_train) + s->agc_scaling_save = FP_SCALE(0.0f); s->training_stage = TRAINING_STAGE_PARKED; report_status_change(s, SIG_STATUS_TRAINING_FAILED); } @@ -1256,7 +1218,7 @@ static __inline__ int signal_detect(v17_rx_state_t *s, int16_t amp) } #if defined(IAXMODEM_STUFF) /* Carrier has dropped, but the put_bit is pending the signal_present delay. */ - s->carrier_drop_pending = TRUE; + s->carrier_drop_pending = true; #endif } } @@ -1267,7 +1229,7 @@ static __inline__ int signal_detect(v17_rx_state_t *s, int16_t amp) return 0; s->signal_present = 1; #if defined(IAXMODEM_STUFF) - s->carrier_drop_pending = FALSE; + s->carrier_drop_pending = false; #endif report_status_change(s, SIG_STATUS_CARRIER_UP); } @@ -1317,11 +1279,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; /* Symbol timing synchronisation band edge filters */ /* 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) >> FP_SYNC_SHIFT_FACTOR) + + ((s->symbol_sync_low[1]*SYNC_LOW_BAND_EDGE_COEFF_1) >> FP_SYNC_SHIFT_FACTOR) + + sample.re; s->symbol_sync_low[1] = s->symbol_sync_low[0]; s->symbol_sync_low[0] = v; /* High Nyquist band edge filter */ - v = ((s->symbol_sync_high[0]*SYNC_HIGH_BAND_EDGE_COEFF_0) >> 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) >> FP_SYNC_SHIFT_FACTOR) + + ((s->symbol_sync_high[1]*SYNC_HIGH_BAND_EDGE_COEFF_1) >> FP_SYNC_SHIFT_FACTOR) + + sample.re; s->symbol_sync_high[1] = s->symbol_sync_high[0]; s->symbol_sync_high[0] = v; #else @@ -1342,18 +1308,16 @@ SPAN_DECLARE_NONSTD(int) v17_rx(v17_rx_state_t *s, const int16_t amp[], int len) if (s->eq_put_step <= 0) { /* 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 (s->agc_scaling_save == 0) - s->agc_scaling = saturate16(((int32_t) (1024.0f*FP_FACTOR*2.17f))/fixed_sqrt32(power)); + s->agc_scaling = saturate16(((int32_t) (FP_SCALE(2.17f)*1024.0f))/fixed_sqrt32(power)); #else - if (s->agc_scaling_save == 0.0f) - s->agc_scaling = (1.0f/RX_PULSESHAPER_GAIN)*2.17f/sqrtf(power); + s->agc_scaling = (FP_SCALE(2.17f)/RX_PULSESHAPER_GAIN)/sqrtf(power); #endif /* Pulse shape while still at the carrier frequency, using a quadrature pair of filters. This results in a properly bandpass filtered complex signal, which can be brought directly to baseband by complex mixing. 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) 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; @@ -1367,6 +1331,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.im = -sample.re*z.im - sample.im*z.re; #endif + s->eq_put_step += RX_PULSESHAPER_COEFF_SETS*10/(3*2); process_half_baud(s, &zz); } #if defined(SPANDSP_USE_FIXED_POINT) @@ -1427,7 +1392,7 @@ SPAN_DECLARE(logging_state_t *) v17_rx_get_logging_state(v17_rx_state_t *s) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) v17_rx_restart(v17_rx_state_t *s, int bit_rate, int short_train) +SPAN_DECLARE(int) v17_rx_restart(v17_rx_state_t *s, int bit_rate, bool short_train) { int i; @@ -1467,11 +1432,10 @@ SPAN_DECLARE(int) v17_rx_restart(v17_rx_state_t *s, int bit_rate, int short_trai s->bit_rate = bit_rate; #if defined(SPANDSP_USE_FIXED_POINTx) vec_zeroi16(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0])); - s->training_error = 0; #else vec_zerof(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0])); - s->training_error = 0.0f; #endif + s->training_error = FP_SCALE(0.0f); s->rrc_filter_step = 0; s->diff = 1; @@ -1482,23 +1446,19 @@ SPAN_DECLARE(int) v17_rx_restart(v17_rx_state_t *s, int bit_rate, int short_trai #if defined(IAXMODEM_STUFF) s->high_sample = 0; s->low_samples = 0; - s->carrier_drop_pending = FALSE; + s->carrier_drop_pending = false; #endif if (short_train != 2) s->short_train = short_train; - memset(s->last_angles, 0, sizeof(s->last_angles)); - memset(s->diff_angles, 0, sizeof(s->diff_angles)); + vec_zeroi32(s->last_angles, 2); + vec_zeroi32(s->diff_angles, 16); /* Initialise the TCM decoder parameters. */ /* The accumulated distance vectors are set so state zero starts at a value of zero, and all others start larger. This forces the initial paths to merge at the zero states. */ for (i = 0; i < 8; i++) -#if defined(SPANDSP_USE_FIXED_POINTx) - s->distances[i] = 99*DIST_FACTOR*DIST_FACTOR; -#else - s->distances[i] = 99.0f; -#endif + s->distances[i] = FP_CONSTELLATION_SCALE(99.0f)*FP_CONSTELLATION_SCALE(1.0f); memset(s->full_path_to_past_state_locations, 0, sizeof(s->full_path_to_past_state_locations)); memset(s->past_state_locations, 0, sizeof(s->past_state_locations)); s->distances[0] = 0; @@ -1525,17 +1485,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); equalizer_reset(s); + s->agc_scaling_save = FP_SCALE(0.0f); #if defined(SPANDSP_USE_FIXED_POINTx) - s->agc_scaling_save = 0; - 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->agc_scaling = (float) (FP_SCALE(2.17f)*1024.0f)/735.0f; s->carrier_track_i = 5000; s->carrier_track_p = 40000; #else + s->agc_scaling = (FP_SCALE(2.17f)/RX_PULSESHAPER_GAIN)/735.0f; s->carrier_track_i = 5000.0f; s->carrier_track_p = 40000.0f; #endif @@ -1545,23 +1501,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)); /* Initialise the working data for symbol timing synchronisation */ -#if defined(SPANDSP_USE_FIXED_POINTx) for (i = 0; i < 2; i++) { - s->symbol_sync_low[i] = 0; - s->symbol_sync_high[i] = 0; - s->symbol_sync_dc_filter[i] = 0; + s->symbol_sync_low[i] = FP_SCALE(0.0f); + s->symbol_sync_high[i] = FP_SCALE(0.0f); + s->symbol_sync_dc_filter[i] = FP_SCALE(0.0f); } - s->baud_phase = 0; -#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_phase = FP_SCALE(0.0f); s->baud_half = 0; s->total_baud_timing_correction = 0; @@ -1586,7 +1532,7 @@ SPAN_DECLARE(v17_rx_state_t *) v17_rx_init(v17_rx_state_t *s, int bit_rate, put_ } if (s == NULL) { - if ((s = (v17_rx_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (v17_rx_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -1594,7 +1540,7 @@ SPAN_DECLARE(v17_rx_state_t *) v17_rx_init(v17_rx_state_t *s, int bit_rate, put_ span_log_set_protocol(&s->logging, "V.17 RX"); s->put_bit = put_bit; s->put_bit_user_data = user_data; - s->short_train = FALSE; + s->short_train = false; s->scrambler_tap = 18 - 1; v17_rx_signal_cutoff(s, -45.5f); s->carrier_phase_rate_save = DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ); @@ -1611,7 +1557,7 @@ SPAN_DECLARE(int) v17_rx_release(v17_rx_state_t *s) SPAN_DECLARE(int) v17_rx_free(v17_rx_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/v17tx.c b/libs/spandsp/src/v17tx.c index fe361d7744..cbe261a6cf 100644 --- a/libs/spandsp/src/v17tx.c +++ b/libs/spandsp/src/v17tx.c @@ -39,9 +39,15 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/fast_convert.h" #include "spandsp/logging.h" #include "spandsp/complex.h" @@ -251,7 +257,7 @@ static __inline__ complexf_t getbaud(v17_tx_state_t *s) { /* Training finished - commence normal operation. */ s->current_get_bit = s->get_bit; - s->in_training = FALSE; + s->in_training = false; } } else @@ -279,7 +285,7 @@ static __inline__ complexf_t getbaud(v17_tx_state_t *s) if (s->status_handler) s->status_handler(s->status_user_data, SIG_STATUS_END_OF_DATA); s->current_get_bit = fake_get_bit; - s->in_training = TRUE; + s->in_training = true; bit = 1; } bits |= (scramble(s, bit) << i); @@ -380,7 +386,7 @@ SPAN_DECLARE(logging_state_t *) v17_tx_get_logging_state(v17_tx_state_t *s) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) v17_tx_restart(v17_tx_state_t *s, int bit_rate, int tep, int short_train) +SPAN_DECLARE(int) v17_tx_restart(v17_tx_state_t *s, int bit_rate, bool tep, bool short_train) { switch (bit_rate) { @@ -422,7 +428,7 @@ SPAN_DECLARE(int) v17_tx_restart(v17_tx_state_t *s, int bit_rate, int tep, int s s->rrc_filter_step = 0; s->convolution = 0; s->scramble_reg = 0x2ECDD5; - s->in_training = TRUE; + s->in_training = true; s->short_train = short_train; s->training_step = (tep) ? V17_TRAINING_SEG_TEP_A : V17_TRAINING_SEG_1; s->carrier_phase = 0; @@ -433,7 +439,7 @@ SPAN_DECLARE(int) v17_tx_restart(v17_tx_state_t *s, int bit_rate, int tep, int s } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(v17_tx_state_t *) v17_tx_init(v17_tx_state_t *s, int bit_rate, int tep, get_bit_func_t get_bit, void *user_data) +SPAN_DECLARE(v17_tx_state_t *) v17_tx_init(v17_tx_state_t *s, int bit_rate, bool tep, get_bit_func_t get_bit, void *user_data) { switch (bit_rate) { @@ -449,7 +455,7 @@ SPAN_DECLARE(v17_tx_state_t *) v17_tx_init(v17_tx_state_t *s, int bit_rate, int } if (s == NULL) { - if ((s = (v17_tx_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (v17_tx_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -460,7 +466,7 @@ SPAN_DECLARE(v17_tx_state_t *) v17_tx_init(v17_tx_state_t *s, int bit_rate, int s->scrambler_tap = 18 - 1; s->carrier_phase_rate = dds_phase_ratef(CARRIER_NOMINAL_FREQ); v17_tx_power(s, -14.0f); - v17_tx_restart(s, bit_rate, tep, FALSE); + v17_tx_restart(s, bit_rate, tep, false); return s; } /*- End of function --------------------------------------------------------*/ @@ -473,7 +479,7 @@ SPAN_DECLARE(int) v17_tx_release(v17_tx_state_t *s) SPAN_DECLARE(int) v17_tx_free(v17_tx_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/v18.c b/libs/spandsp/src/v18.c index 3529fe6f0d..c1a0e89c4f 100644 --- a/libs/spandsp/src/v18.c +++ b/libs/spandsp/src/v18.c @@ -40,9 +40,15 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/queue.h" #include "spandsp/async.h" @@ -62,6 +68,7 @@ #include "spandsp/private/queue.h" #include "spandsp/private/tone_generate.h" #include "spandsp/private/async.h" +#include "spandsp/private/power_meter.h" #include "spandsp/private/fsk.h" #include "spandsp/private/dtmf.h" #include "spandsp/private/modem_connect_tones.h" @@ -78,13 +85,13 @@ Silence for 0.5s then send TXP DTMF Proceed as Annex B - 1650Hz (V21 ch 2 low) + 1650Hz (V21 ch 2 low) [1650Hz +-12Hz] Proceed as Annex F in call mode - 1300Hz (Calling tone) + 1300Hz (Calling tone) [1300Hz +-16Hz] Proceed as Annex E in call mode - 1400Hz/1800Hz (Weitbrecht) + 1400Hz/1800Hz (Weitbrecht) [1400Hz +-5% and 1800Hz +-5%] Detect rate and proceed as Annex A - 980Hz/1180Hz (V21 ch 1) + 980Hz/1180Hz (V21 ch 1) [980Hz +-12Hz, 1180Hz +-12Hz] Start timer Tr 2225Hz (Bell ANS) Proceed as Annex D call mode @@ -98,21 +105,21 @@ Monitor as caller for 980Hz or 1300Hz CI/XCI Respond with ANSam - 1300Hz + 1300Hz [1300Hz +-16Hz] Probe Timer Ta (3s) Probe - 1400Hz/1800Hz (Weitbrecht) + 1400Hz/1800Hz (Weitbrecht) [1400Hz +-5% and 1800Hz +-5%] Detect rate and proceed as Annex A DTMF Proceed as Annex B - 980Hz (V21 ch 1 low) + 980Hz (V21 ch 1 low) [980Hz +-12Hz] Start timer Te 1270Hz (Bell103 ch 2 high) Proceed as Annex D answer mode 2225Hz (Bell ANS) Proceed as Annex D call mode - 1650Hz (V21 ch 2 low) + 1650Hz (V21 ch 2 low) [1650Hz +-12Hz] Proceed as Annex F answer mode ANSam Proceed as V.8 caller Annex G @@ -131,6 +138,7 @@ struct dtmf_to_ascii_s static const struct dtmf_to_ascii_s dtmf_to_ascii[] = { + {"###0", '!'}, {"###1", 'C'}, {"###2", 'F'}, {"###3", 'I'}, @@ -140,7 +148,6 @@ static const struct dtmf_to_ascii_s dtmf_to_ascii[] = {"###7", 'U'}, {"###8", 'X'}, {"###9", ';'}, - {"###0", '!'}, {"##*1", 'A'}, {"##*2", 'D'}, {"##*3", 'G'}, @@ -373,71 +380,174 @@ static const uint8_t txp[] = "1111111111000101011100001101110000010101"; 100 ms mark. */ static const uint8_t xci[] = "01111111110111111111"; -static int cmp(const void *s, const void *t) +/* The entries here must match the order in which the related names are defined in v18.h */ +static const int automoding_sequences[][6] = { - const char *ss; - struct dtmf_to_ascii_s *tt; - - ss = (const char *) s; - tt = (struct dtmf_to_ascii_s *) t; - return strncmp(ss, tt->dtmf, strlen(tt->dtmf)); -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v18_encode_dtmf(v18_state_t *s, char dtmf[], const char msg[]) -{ - const char *t; - const char *v; - char *u; - - t = msg; - u = dtmf; - while (*t) { - v = ascii_to_dtmf[*t & 0x7F]; - while (*v) - *u++ = *v++; - t++; - } - *u = '\0'; - - return u - dtmf; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v18_decode_dtmf(v18_state_t *s, char msg[], const char dtmf[]) -{ - int entries; - const char *t; - char *u; - struct dtmf_to_ascii_s *ss; - - entries = sizeof(dtmf_to_ascii)/sizeof(dtmf_to_ascii[0]) - 1; - t = dtmf; - u = msg; - while (*t) + /* Dummy entry 0 */ + V18_MODE_5BIT_4545, + V18_MODE_BELL103, + V18_MODE_V21TEXTPHONE, + V18_MODE_V23VIDEOTEX, + V18_MODE_EDT, + V18_MODE_DTMF + }, { - ss = bsearch(t, dtmf_to_ascii, entries, sizeof(dtmf_to_ascii[0]), cmp); - if (ss) - { - t += strlen(ss->dtmf); - *u++ = ss->ascii; - } - else - { - /* Can't match the code. Let's assume this is a code we just don't know, and skip over it */ - while (*t == '#' || *t == '*') - t++; - if (*t) - t++; - } + /* Australia */ + V18_MODE_5BIT_50, + V18_MODE_V21TEXTPHONE, + V18_MODE_V23VIDEOTEX, + V18_MODE_EDT, + V18_MODE_DTMF, + V18_MODE_BELL103 + }, + { + /* Ireland */ + V18_MODE_5BIT_50, + V18_MODE_V21TEXTPHONE, + V18_MODE_V23VIDEOTEX, + V18_MODE_EDT, + V18_MODE_DTMF, + V18_MODE_BELL103 + }, + { + /* Germany */ + V18_MODE_EDT, + V18_MODE_V21TEXTPHONE, + V18_MODE_V23VIDEOTEX, + V18_MODE_5BIT_50, + V18_MODE_DTMF, + V18_MODE_BELL103 + }, + { + /* Switzerland */ + V18_MODE_EDT, + V18_MODE_V21TEXTPHONE, + V18_MODE_V23VIDEOTEX, + V18_MODE_5BIT_50, + V18_MODE_DTMF, + V18_MODE_BELL103 + }, + { + /* Italy */ + V18_MODE_EDT, + V18_MODE_V21TEXTPHONE, + V18_MODE_V23VIDEOTEX, + V18_MODE_5BIT_50, + V18_MODE_DTMF, + V18_MODE_BELL103 + }, + { + /* Spain */ + V18_MODE_EDT, + V18_MODE_V21TEXTPHONE, + V18_MODE_V23VIDEOTEX, + V18_MODE_5BIT_50, + V18_MODE_DTMF, + V18_MODE_BELL103 + }, + { + /* Austria */ + V18_MODE_EDT, + V18_MODE_V21TEXTPHONE, + V18_MODE_V23VIDEOTEX, + V18_MODE_5BIT_50, + V18_MODE_DTMF, + V18_MODE_BELL103 + }, + { + /* Netherlands */ + V18_MODE_DTMF, + V18_MODE_V21TEXTPHONE, + V18_MODE_V23VIDEOTEX, + V18_MODE_5BIT_50, + V18_MODE_EDT, + V18_MODE_BELL103 + }, + { + /* Iceland */ + V18_MODE_V21TEXTPHONE, + V18_MODE_DTMF, + V18_MODE_5BIT_50, + V18_MODE_EDT, + V18_MODE_V23VIDEOTEX, + V18_MODE_BELL103 + }, + { + /* Norway */ + V18_MODE_V21TEXTPHONE, + V18_MODE_DTMF, + V18_MODE_5BIT_50, + V18_MODE_EDT, + V18_MODE_V23VIDEOTEX, + V18_MODE_BELL103 + }, + { + /* Sweden */ + V18_MODE_V21TEXTPHONE, + V18_MODE_DTMF, + V18_MODE_5BIT_50, + V18_MODE_EDT, + V18_MODE_V23VIDEOTEX, + V18_MODE_BELL103 + }, + { + /* Finland */ + V18_MODE_V21TEXTPHONE, + V18_MODE_DTMF, + V18_MODE_5BIT_50, + V18_MODE_EDT, + V18_MODE_V23VIDEOTEX, + V18_MODE_BELL103 + }, + { + /* Denmark */ + V18_MODE_V21TEXTPHONE, + V18_MODE_DTMF, + V18_MODE_5BIT_50, + V18_MODE_EDT, + V18_MODE_V23VIDEOTEX, + V18_MODE_BELL103 + }, + { + /* UK */ + V18_MODE_V21TEXTPHONE, + V18_MODE_5BIT_50, + V18_MODE_V23VIDEOTEX, + V18_MODE_EDT, + V18_MODE_DTMF, + V18_MODE_BELL103 + }, + { + /* USA */ + V18_MODE_5BIT_4545, + V18_MODE_BELL103, + V18_MODE_V21TEXTPHONE, + V18_MODE_V23VIDEOTEX, + V18_MODE_EDT, + V18_MODE_DTMF + }, + { + /* France */ + V18_MODE_V23VIDEOTEX, + V18_MODE_EDT, + V18_MODE_DTMF, + V18_MODE_5BIT_50, + V18_MODE_V21TEXTPHONE, + V18_MODE_BELL103 + }, + { + /* Belgium */ + V18_MODE_V23VIDEOTEX, + V18_MODE_EDT, + V18_MODE_DTMF, + V18_MODE_5BIT_50, + V18_MODE_V21TEXTPHONE, + V18_MODE_BELL103 } - *u = '\0'; - return u - msg; -} -/*- End of function --------------------------------------------------------*/ +}; -SPAN_DECLARE(uint16_t) v18_encode_baudot(v18_state_t *s, uint8_t ch) +static uint16_t encode_baudot(v18_state_t *s, uint8_t ch) { static const uint8_t conv[128] = { @@ -449,7 +559,7 @@ SPAN_DECLARE(uint16_t) v18_encode_baudot(v18_state_t *s, uint8_t ch) 0xFF, /* ENQ */ 0xFF, /* ACK */ 0xFF, /* BEL */ - 0x00, /* BS */ + 0x40, /* BS */ 0x44, /* HT >> SPACE */ 0x42, /* LF */ 0x42, /* VT >> LF */ @@ -572,14 +682,7 @@ SPAN_DECLARE(uint16_t) v18_encode_baudot(v18_state_t *s, uint8_t ch) }; uint16_t shift; - if (ch == 0x7F) - { - /* DLE is a special character meaning "force a - change to the letter character set */ - shift = BAUDOT_LETTER_SHIFT; - return 0; - } - ch = conv[ch]; + ch = conv[ch & 0x7F]; /* Is it a non-existant code? */ if (ch == 0xFF) return 0; @@ -605,7 +708,7 @@ SPAN_DECLARE(uint16_t) v18_encode_baudot(v18_state_t *s, uint8_t ch) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(uint8_t) v18_decode_baudot(v18_state_t *s, uint8_t ch) +static uint8_t decode_baudot(v18_state_t *s, uint8_t ch) { static const uint8_t conv[2][32] = { @@ -624,18 +727,8 @@ SPAN_DECLARE(uint8_t) v18_decode_baudot(v18_state_t *s, uint8_t ch) default: return conv[s->baudot_rx_shift][ch]; } - /* return 0 if we did not produce a character */ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static void v18_rx_dtmf(void *user_data, const char digits[], int len) -{ -#if 0 - v18_state_t *s; - - s = (v18_state_t *) user_data; -#endif + /* Return 0xFF if we did not produce a character */ + return 0xFF; } /*- End of function --------------------------------------------------------*/ @@ -643,21 +736,82 @@ static int v18_tdd_get_async_byte(void *user_data) { v18_state_t *s; int ch; + unsigned int x; + + s = (v18_state_t *) user_data; + + if (s->next_byte != 0xFF) + { + s->rx_suppression = (300*SAMPLE_RATE)/1000; + x = s->next_byte; + s->next_byte = (uint8_t) 0xFF; + return x; + } + for (;;) + { + if ((ch = queue_read_byte(&s->queue.queue)) < 0) + { + if (s->tx_signal_on) + { + /* The FSK should now be switched off. */ + s->tx_signal_on = 0; + } + async_tx_presend_bits(&s->async_tx, 42); + return SIG_STATUS_LINK_IDLE; + } + if ((x = encode_baudot(s, ch)) != 0) + break; + } + s->rx_suppression = (300*SAMPLE_RATE)/1000; + if (s->tx_signal_on == 1) + { + async_tx_presend_bits(&s->async_tx, 7); + s->tx_signal_on = 2; + } + if ((x & 0x3E0)) + { + s->next_byte = (uint8_t) (x & 0x1F); + return (uint8_t) ((x >> 5) & 0x1F); + } + s->next_byte = (uint8_t) 0xFF; + return (uint8_t) (x & 0x1F); +} +/*- End of function --------------------------------------------------------*/ + +static void v18_dtmf_get(void *user_data) +{ + v18_state_t *s; + int ch; + int len; + const char *t; s = (v18_state_t *) user_data; if ((ch = queue_read_byte(&s->queue.queue)) >= 0) - return ch; - if (s->tx_signal_on) { - /* The FSK should now be switched off. */ - s->tx_signal_on = FALSE; + t = ascii_to_dtmf[ch & 0x7F]; + len = strlen(t); + dtmf_tx_put(&s->dtmf_tx, t, len); + s->rx_suppression = ((300 + 100*len)*SAMPLE_RATE)/1000; } - return 0x1F; } /*- End of function --------------------------------------------------------*/ static int v18_edt_get_async_byte(void *user_data) { + v18_state_t *s; + int ch; + + s = (v18_state_t *) user_data; + if ((ch = queue_read_byte(&s->queue.queue)) >= 0) + { + s->rx_suppression = (300*SAMPLE_RATE)/1000; + return ch; + } + if (s->tx_signal_on) + { + /* The FSK should now be switched off. */ + s->tx_signal_on = 0; + } return 0; } /*- End of function --------------------------------------------------------*/ @@ -696,10 +850,15 @@ static void v18_tdd_put_async_byte(void *user_data, int byte) } return; } + if (s->rx_suppression > 0) + return; span_log(&s->logging, SPAN_LOG_FLOW, "Rx byte %x\n", byte); - if ((octet = v18_decode_baudot(s, byte))) + if ((octet = decode_baudot(s, byte)) != 0xFF) + { s->rx_msg[s->rx_msg_len++] = octet; - if (s->rx_msg_len >= 256) + span_log(&s->logging, SPAN_LOG_FLOW, "Rx byte 0x%x '%c'\n", octet, octet); + } + if (s->rx_msg_len > 0) //= 256) { s->rx_msg[s->rx_msg_len] = '\0'; if (s->put_msg) @@ -709,23 +868,112 @@ static void v18_tdd_put_async_byte(void *user_data, int byte) } /*- End of function --------------------------------------------------------*/ +static int decode_dtmf_cmp(const void *s, const void *t) +{ + const char *ss; + struct dtmf_to_ascii_s *tt; + + ss = (const char *) s; + tt = (struct dtmf_to_ascii_s *) t; + return strncmp(ss, tt->dtmf, strlen(tt->dtmf)); +} +/*- End of function --------------------------------------------------------*/ + +static int decode_dtmf(v18_state_t *s, char msg[], const char dtmf[]) +{ + int entries; + int len; + const char *t; + char *u; + struct dtmf_to_ascii_s *ss; + + entries = sizeof(dtmf_to_ascii)/sizeof(dtmf_to_ascii[0]) - 1; + t = dtmf; + u = msg; + while (*t) + { + ss = bsearch(t, dtmf_to_ascii, entries, sizeof(dtmf_to_ascii[0]), decode_dtmf_cmp); + if (ss) + { + len = strlen(ss->dtmf); + t += len; + *u++ = ss->ascii; + return len; + } + /* Can't match the code. Let's assume this is a code we just don't know, and skip over it */ + while (*t == '#' || *t == '*') + t++; + if (*t) + t++; + } + *u = '\0'; + return u - msg; +} +/*- End of function --------------------------------------------------------*/ + +static void v18_dtmf_put(void *user_data, const char dtmf[], int len) +{ + v18_state_t *s; + char buf[128]; + int i; + int matched; + + s = (v18_state_t *) user_data; + if (s->rx_suppression > 0) + return; + for (i = 0; i < len; i++) + { + s->rx_msg[s->rx_msg_len++] = dtmf[i]; + if (dtmf[i] >= '0' && dtmf[i] <= '9') + { + s->rx_msg[s->rx_msg_len] = '\0'; + if ((matched = decode_dtmf(s, buf, (const char *) s->rx_msg)) > 0) + { + buf[1] = '\0'; + s->put_msg(s->user_data, (const uint8_t *) buf, 1); + } + if (s->rx_msg_len > matched) + memcpy(&s->rx_msg[0], &s->rx_msg[matched], s->rx_msg_len - matched); + s->rx_msg_len -= matched; + } + } + s->in_progress = 5*SAMPLE_RATE; +} +/*- End of function --------------------------------------------------------*/ + static void v18_edt_put_async_byte(void *user_data, int byte) { + v18_state_t *s; + s = (v18_state_t *) user_data; + if (s->rx_suppression > 0) + return; } /*- End of function --------------------------------------------------------*/ static void v18_bell103_put_async_byte(void *user_data, int byte) { + v18_state_t *s; + s = (v18_state_t *) user_data; + if (s->rx_suppression > 0) + return; } /*- End of function --------------------------------------------------------*/ static void v18_videotex_put_async_byte(void *user_data, int byte) { + v18_state_t *s; + s = (v18_state_t *) user_data; + if (s->rx_suppression > 0) + return; } /*- End of function --------------------------------------------------------*/ static void v18_textphone_put_async_byte(void *user_data, int byte) { + v18_state_t *s; + s = (v18_state_t *) user_data; + if (s->rx_suppression > 0) + return; } /*- End of function --------------------------------------------------------*/ @@ -741,13 +989,13 @@ SPAN_DECLARE_NONSTD(int) v18_tx(v18_state_t *s, int16_t *amp, int max_len) { case V18_MODE_DTMF: if (len < max_len) - len += dtmf_tx(&s->dtmftx, amp, max_len - len); + len += dtmf_tx(&s->dtmf_tx, amp, max_len - len); break; default: if (len < max_len) { - if ((lenx = fsk_tx(&s->fsktx, amp + len, max_len - len)) <= 0) - s->tx_signal_on = FALSE; + if ((lenx = fsk_tx(&s->fsk_tx, amp + len, max_len - len)) <= 0) + s->tx_signal_on = 0; len += lenx; } break; @@ -759,18 +1007,61 @@ SPAN_DECLARE_NONSTD(int) v18_tx(v18_state_t *s, int16_t *amp, int max_len) SPAN_DECLARE_NONSTD(int) v18_rx(v18_state_t *s, const int16_t amp[], int len) { - switch (s->mode) + if (s->rx_suppression > 0) + { + if (s->rx_suppression > len) + s->rx_suppression -= len; + else + s->rx_suppression = 0; + } + if ((s->mode & V18_MODE_DTMF)) { - case V18_MODE_DTMF: /* Apply a message timeout. */ - s->in_progress -= len; - if (s->in_progress <= 0) - s->rx_msg_len = 0; - dtmf_rx(&s->dtmfrx, amp, len); - break; - default: - fsk_rx(&s->fskrx, amp, len); - break; + if (s->in_progress) + { + s->in_progress -= len; + if (s->in_progress <= 0) + { + s->in_progress = 0; + s->rx_msg_len = 0; + } + } + dtmf_rx(&s->dtmf_rx, amp, len); + } + if ((s->mode & (V18_MODE_5BIT_4545 | V18_MODE_5BIT_476 | V18_MODE_5BIT_50))) + { + fsk_rx(&s->fsk_rx, amp, len); + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +SPAN_DECLARE_NONSTD(int) v18_rx_fillin(v18_state_t *s, int len) +{ + if (s->rx_suppression > 0) + { + if (s->rx_suppression > len) + s->rx_suppression -= len; + else + s->rx_suppression = 0; + } + if ((s->mode & V18_MODE_DTMF)) + { + /* Apply a message timeout. */ + if (s->in_progress) + { + s->in_progress -= len; + if (s->in_progress <= 0) + { + s->in_progress = 0; + s->rx_msg_len = 0; + } + } + dtmf_rx_fillin(&s->dtmf_rx, len); + } + if ((s->mode & (V18_MODE_5BIT_4545 | V18_MODE_5BIT_476 | V18_MODE_5BIT_50))) + { + fsk_rx_fillin(&s->fsk_rx, len); } return 0; } @@ -778,9 +1069,6 @@ SPAN_DECLARE_NONSTD(int) v18_rx(v18_state_t *s, const int16_t amp[], int len) SPAN_DECLARE(int) v18_put(v18_state_t *s, const char msg[], int len) { - char buf[256 + 1]; - int x; - int n; int i; /* This returns the number of characters that would not fit in the buffer. @@ -791,40 +1079,24 @@ SPAN_DECLARE(int) v18_put(v18_state_t *s, const char msg[], int len) if ((len = strlen(msg)) == 0) return 0; } - switch (s->mode) - { - case V18_MODE_5BIT_45: - case V18_MODE_5BIT_50: - for (i = 0; i < len; i++) - { - n = 0; - if ((x = v18_encode_baudot(s, msg[i]))) - { - if ((x & 0x3E0)) - buf[n++] = (uint8_t) ((x >> 5) & 0x1F); - buf[n++] = (uint8_t) (x & 0x1F); - /* TODO: Deal with out of space condition */ - if (queue_write(&s->queue.queue, (const uint8_t *) buf, n) < 0) - return i; - s->tx_signal_on = TRUE; - } - } - return len; - case V18_MODE_DTMF: - break; - } - return -1; + /* TODO: Deal with out of space condition */ + if ((i = queue_write(&s->queue.queue, (const uint8_t *) msg, len)) < 0) + return i; + s->tx_signal_on = 1; + return i; } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(const char *) v18_mode_to_str(int mode) { - switch (mode & 0xFF) + switch ((mode & 0xFFF)) { case V18_MODE_NONE: return "None"; - case V18_MODE_5BIT_45: + case V18_MODE_5BIT_4545: return "Weitbrecht TDD (45.45bps)"; + case V18_MODE_5BIT_476: + return "Weitbrecht TDD (47.6bps)"; case V18_MODE_5BIT_50: return "Weitbrecht TDD (50bps)"; case V18_MODE_DTMF: @@ -851,76 +1123,95 @@ SPAN_DECLARE(logging_state_t *) v18_get_logging_state(v18_state_t *s) /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(v18_state_t *) v18_init(v18_state_t *s, - int calling_party, + bool calling_party, int mode, + int nation, put_msg_func_t put_msg, void *user_data) { + if (nation < 0 || nation >= V18_AUTOMODING_END) + return NULL; + if (s == NULL) { - if ((s = (v18_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (v18_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); s->calling_party = calling_party; - s->mode = mode & 0xFF; + s->mode = mode & ~V18_MODE_REPETITIVE_SHIFTS_OPTION; s->put_msg = put_msg; s->user_data = user_data; switch (s->mode) { - case V18_MODE_5BIT_45: - fsk_tx_init(&s->fsktx, &preset_fsk_specs[FSK_WEITBRECHT], async_tx_get_bit, &s->asynctx); - async_tx_init(&s->asynctx, 5, ASYNC_PARITY_NONE, 2, FALSE, v18_tdd_get_async_byte, s); + case V18_MODE_5BIT_4545: + s->repeat_shifts = mode & V18_MODE_REPETITIVE_SHIFTS_OPTION; + fsk_tx_init(&s->fsk_tx, &preset_fsk_specs[FSK_WEITBRECHT_4545], async_tx_get_bit, &s->async_tx); + async_tx_init(&s->async_tx, 5, ASYNC_PARITY_NONE, 2, false, v18_tdd_get_async_byte, s); /* Schedule an explicit shift at the start of baudot transmission */ s->baudot_tx_shift = 2; /* TDD uses 5 bit data, no parity and 1.5 stop bits. We scan for the first stop bit, and ride over the fraction. */ - fsk_rx_init(&s->fskrx, &preset_fsk_specs[FSK_WEITBRECHT], FSK_FRAME_MODE_5N1_FRAMES, v18_tdd_put_async_byte, s); + fsk_rx_init(&s->fsk_rx, &preset_fsk_specs[FSK_WEITBRECHT_4545], FSK_FRAME_MODE_5N1_FRAMES, v18_tdd_put_async_byte, s); s->baudot_rx_shift = 0; - s->repeat_shifts = mode & 0x100; + s->next_byte = (uint8_t) 0xFF; + break; + case V18_MODE_5BIT_476: + s->repeat_shifts = mode & V18_MODE_REPETITIVE_SHIFTS_OPTION; + fsk_tx_init(&s->fsk_tx, &preset_fsk_specs[FSK_WEITBRECHT_476], async_tx_get_bit, &s->async_tx); + async_tx_init(&s->async_tx, 5, ASYNC_PARITY_NONE, 2, false, v18_tdd_get_async_byte, s); + /* Schedule an explicit shift at the start of baudot transmission */ + s->baudot_tx_shift = 2; + /* TDD uses 5 bit data, no parity and 1.5 stop bits. We scan for the first stop bit, and + ride over the fraction. */ + fsk_rx_init(&s->fsk_rx, &preset_fsk_specs[FSK_WEITBRECHT_476], FSK_FRAME_MODE_5N1_FRAMES, v18_tdd_put_async_byte, s); + s->baudot_rx_shift = 0; + s->next_byte = (uint8_t) 0xFF; break; case V18_MODE_5BIT_50: - fsk_tx_init(&s->fsktx, &preset_fsk_specs[FSK_WEITBRECHT50], async_tx_get_bit, &s->asynctx); - async_tx_init(&s->asynctx, 5, ASYNC_PARITY_NONE, 2, FALSE, v18_tdd_get_async_byte, s); + s->repeat_shifts = mode & V18_MODE_REPETITIVE_SHIFTS_OPTION; + fsk_tx_init(&s->fsk_tx, &preset_fsk_specs[FSK_WEITBRECHT_50], async_tx_get_bit, &s->async_tx); + async_tx_init(&s->async_tx, 5, ASYNC_PARITY_NONE, 2, false, v18_tdd_get_async_byte, s); /* Schedule an explicit shift at the start of baudot transmission */ s->baudot_tx_shift = 2; /* TDD uses 5 bit data, no parity and 1.5 stop bits. We scan for the first stop bit, and ride over the fraction. */ - fsk_rx_init(&s->fskrx, &preset_fsk_specs[FSK_WEITBRECHT50], FSK_FRAME_MODE_5N1_FRAMES, v18_tdd_put_async_byte, s); + fsk_rx_init(&s->fsk_rx, &preset_fsk_specs[FSK_WEITBRECHT_50], FSK_FRAME_MODE_5N1_FRAMES, v18_tdd_put_async_byte, s); s->baudot_rx_shift = 0; - s->repeat_shifts = mode & 0x100; + s->next_byte = (uint8_t) 0xFF; break; case V18_MODE_DTMF: - dtmf_tx_init(&s->dtmftx, NULL, NULL); - dtmf_rx_init(&s->dtmfrx, v18_rx_dtmf, s); + dtmf_tx_init(&s->dtmf_tx, v18_dtmf_get, s); + dtmf_rx_init(&s->dtmf_rx, v18_dtmf_put, s); break; case V18_MODE_EDT: - fsk_tx_init(&s->fsktx, &preset_fsk_specs[FSK_V21CH1_110], async_tx_get_bit, &s->asynctx); - async_tx_init(&s->asynctx, 7, ASYNC_PARITY_EVEN, 2, FALSE, v18_edt_get_async_byte, s); - fsk_rx_init(&s->fskrx, &preset_fsk_specs[FSK_V21CH1_110], FSK_FRAME_MODE_7E2_FRAMES, v18_edt_put_async_byte, s); + fsk_tx_init(&s->fsk_tx, &preset_fsk_specs[FSK_V21CH1_110], async_tx_get_bit, &s->async_tx); + async_tx_init(&s->async_tx, 7, ASYNC_PARITY_EVEN, 2, false, v18_edt_get_async_byte, s); + fsk_rx_init(&s->fsk_rx, &preset_fsk_specs[FSK_V21CH1_110], FSK_FRAME_MODE_7E2_FRAMES, v18_edt_put_async_byte, s); break; case V18_MODE_BELL103: - fsk_tx_init(&s->fsktx, &preset_fsk_specs[FSK_BELL103CH1], async_tx_get_bit, &s->asynctx); - async_tx_init(&s->asynctx, 7, ASYNC_PARITY_EVEN, 1, FALSE, v18_edt_get_async_byte, s); - fsk_rx_init(&s->fskrx, &preset_fsk_specs[FSK_BELL103CH2], FSK_FRAME_MODE_7E1_FRAMES, v18_bell103_put_async_byte, s); + fsk_tx_init(&s->fsk_tx, &preset_fsk_specs[FSK_BELL103CH1], async_tx_get_bit, &s->async_tx); + async_tx_init(&s->async_tx, 7, ASYNC_PARITY_EVEN, 1, false, v18_edt_get_async_byte, s); + fsk_rx_init(&s->fsk_rx, &preset_fsk_specs[FSK_BELL103CH2], FSK_FRAME_MODE_7E1_FRAMES, v18_bell103_put_async_byte, s); break; case V18_MODE_V23VIDEOTEX: - fsk_tx_init(&s->fsktx, &preset_fsk_specs[FSK_V23CH1], async_tx_get_bit, &s->asynctx); - async_tx_init(&s->asynctx, 7, ASYNC_PARITY_EVEN, 1, FALSE, v18_edt_get_async_byte, s); - fsk_rx_init(&s->fskrx, &preset_fsk_specs[FSK_V23CH2], FSK_FRAME_MODE_7E1_FRAMES, v18_videotex_put_async_byte, s); + fsk_tx_init(&s->fsk_tx, &preset_fsk_specs[FSK_V23CH1], async_tx_get_bit, &s->async_tx); + async_tx_init(&s->async_tx, 7, ASYNC_PARITY_EVEN, 1, false, v18_edt_get_async_byte, s); + fsk_rx_init(&s->fsk_rx, &preset_fsk_specs[FSK_V23CH2], FSK_FRAME_MODE_7E1_FRAMES, v18_videotex_put_async_byte, s); break; case V18_MODE_V21TEXTPHONE: - fsk_tx_init(&s->fsktx, &preset_fsk_specs[FSK_V21CH1], async_tx_get_bit, &s->asynctx); - async_tx_init(&s->asynctx, 7, ASYNC_PARITY_EVEN, 1, FALSE, v18_edt_get_async_byte, s); - fsk_rx_init(&s->fskrx, &preset_fsk_specs[FSK_V21CH1], FSK_FRAME_MODE_7E1_FRAMES, v18_textphone_put_async_byte, s); + fsk_tx_init(&s->fsk_tx, &preset_fsk_specs[FSK_V21CH1], async_tx_get_bit, &s->async_tx); + async_tx_init(&s->async_tx, 7, ASYNC_PARITY_EVEN, 1, false, v18_edt_get_async_byte, s); + fsk_rx_init(&s->fsk_rx, &preset_fsk_specs[FSK_V21CH1], FSK_FRAME_MODE_7E1_FRAMES, v18_textphone_put_async_byte, s); break; case V18_MODE_V18TEXTPHONE: - fsk_tx_init(&s->fsktx, &preset_fsk_specs[FSK_V21CH1], async_tx_get_bit, &s->asynctx); - async_tx_init(&s->asynctx, 7, ASYNC_PARITY_EVEN, 1, FALSE, v18_edt_get_async_byte, s); - fsk_rx_init(&s->fskrx, &preset_fsk_specs[FSK_V21CH1], FSK_FRAME_MODE_7E1_FRAMES, v18_textphone_put_async_byte, s); + fsk_tx_init(&s->fsk_tx, &preset_fsk_specs[FSK_V21CH1], async_tx_get_bit, &s->async_tx); + async_tx_init(&s->async_tx, 7, ASYNC_PARITY_EVEN, 1, false, v18_edt_get_async_byte, s); + fsk_rx_init(&s->fsk_rx, &preset_fsk_specs[FSK_V21CH1], FSK_FRAME_MODE_7E1_FRAMES, v18_textphone_put_async_byte, s); break; } + s->nation = nation; queue_init(&s->queue.queue, 128, QUEUE_READ_ATOMIC | QUEUE_WRITE_ATOMIC); return s; } @@ -934,7 +1225,7 @@ SPAN_DECLARE(int) v18_release(v18_state_t *s) SPAN_DECLARE(int) v18_free(v18_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/v22bis_rx.c b/libs/spandsp/src/v22bis_rx.c index 099eb8bff0..aba3dd2980 100644 --- a/libs/spandsp/src/v22bis_rx.c +++ b/libs/spandsp/src/v22bis_rx.c @@ -48,6 +48,11 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include "spandsp/telephony.h" @@ -70,6 +75,7 @@ #include "spandsp/v22bis.h" #include "spandsp/private/logging.h" +#include "spandsp/private/power_meter.h" #include "spandsp/private/v22bis.h" #if defined(SPANDSP_USE_FIXED_POINT) @@ -711,7 +717,7 @@ static __inline__ void process_half_baud(v22bis_state_t *s, const complexf_t *sa if (s->rx.training_count >= ms_to_symbols(100 + 450)) { span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting 16 way decisions (caller)\n"); - s->rx.sixteen_way_decisions = TRUE; + s->rx.sixteen_way_decisions = true; s->rx.training = V22BIS_RX_TRAINING_STAGE_WAIT_FOR_SCRAMBLED_ONES_AT_2400; s->rx.pattern_repeats = 0; #if defined(SPANDSP_USE_FIXED_POINT) @@ -726,7 +732,7 @@ static __inline__ void process_half_baud(v22bis_state_t *s, const complexf_t *sa if (s->rx.training_count >= ms_to_symbols(450)) { span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting 16 way decisions (answerer)\n"); - s->rx.sixteen_way_decisions = TRUE; + s->rx.sixteen_way_decisions = true; s->rx.training = V22BIS_RX_TRAINING_STAGE_WAIT_FOR_SCRAMBLED_ONES_AT_2400; s->rx.pattern_repeats = 0; } @@ -839,7 +845,7 @@ SPAN_DECLARE_NONSTD(int) v22bis_rx(v22bis_state_t *s, const int16_t amp[], int l /* Look for power exceeding the carrier on point */ if (power < s->rx.carrier_on_power) continue; - s->rx.signal_present = TRUE; + s->rx.signal_present = true; v22bis_report_status_change(s, SIG_STATUS_CARRIER_UP); } /* Only spend effort processing this data if the modem is not parked, after @@ -952,7 +958,7 @@ int v22bis_rx_restart(v22bis_state_t *s) s->rx.scrambler_pattern_count = 0; s->rx.training = V22BIS_RX_TRAINING_STAGE_SYMBOL_ACQUISITION; s->rx.training_count = 0; - s->rx.signal_present = FALSE; + s->rx.signal_present = false; s->rx.carrier_phase_rate = (s->calling_party) ? DDS_PHASE_RATE(2400.0f) : DDS_PHASE_RATE(1200.0f); s->rx.carrier_phase = 0; @@ -965,7 +971,7 @@ int v22bis_rx_restart(v22bis_state_t *s) #endif s->rx.constellation_state = 0; - s->rx.sixteen_way_decisions = FALSE; + s->rx.sixteen_way_decisions = false; equalizer_reset(s); diff --git a/libs/spandsp/src/v22bis_tx.c b/libs/spandsp/src/v22bis_tx.c index bb18b77b26..15d31cb9d7 100644 --- a/libs/spandsp/src/v22bis_tx.c +++ b/libs/spandsp/src/v22bis_tx.c @@ -42,9 +42,15 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/fast_convert.h" #include "spandsp/logging.h" #include "spandsp/complex.h" @@ -60,6 +66,7 @@ #include "spandsp/v22bis.h" #include "spandsp/private/logging.h" +#include "spandsp/private/power_meter.h" #include "spandsp/private/v22bis.h" #if defined(SPANDSP_USE_FIXED_POINT) @@ -668,7 +675,7 @@ SPAN_DECLARE(int) v22bis_request_retrain(v22bis_state_t *s, int bit_rate) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) v22bis_remote_loopback(v22bis_state_t *s, int enable) +SPAN_DECLARE(int) v22bis_remote_loopback(v22bis_state_t *s, bool enable) { /* TODO: */ return -1; @@ -684,7 +691,7 @@ SPAN_DECLARE(int) v22bis_get_current_bit_rate(v22bis_state_t *s) SPAN_DECLARE(v22bis_state_t *) v22bis_init(v22bis_state_t *s, int bit_rate, int guard, - int calling_party, + bool calling_party, get_bit_func_t get_bit, void *get_bit_user_data, put_bit_func_t put_bit, @@ -700,7 +707,7 @@ SPAN_DECLARE(v22bis_state_t *) v22bis_init(v22bis_state_t *s, } if (s == NULL) { - if ((s = (v22bis_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (v22bis_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -748,7 +755,7 @@ SPAN_DECLARE(int) v22bis_release(v22bis_state_t *s) SPAN_DECLARE(int) v22bis_free(v22bis_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/v27ter_rx.c b/libs/spandsp/src/v27ter_rx.c index 459163a997..3451d66026 100644 --- a/libs/spandsp/src/v27ter_rx.c +++ b/libs/spandsp/src/v27ter_rx.c @@ -40,9 +40,15 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/fast_convert.h" #include "spandsp/math_fixed.h" @@ -62,6 +68,7 @@ #include "spandsp/v27ter_rx.h" #include "spandsp/private/logging.h" +#include "spandsp/private/power_meter.h" #include "spandsp/private/v27ter_rx.h" #if defined(SPANDSP_USE_FIXED_POINT) @@ -171,8 +178,13 @@ SPAN_DECLARE(int) v27ter_rx_equalizer_state(v27ter_rx_state_t *s, complexi16_t * SPAN_DECLARE(int) v27ter_rx_equalizer_state(v27ter_rx_state_t *s, complexf_t **coeffs) #endif { +#if defined(SPANDSP_USE_FIXED_POINT) + *coeffs = NULL; + return 0; +#else *coeffs = s->eq_coeff; return V27TER_EQUALIZER_LEN; +#endif } /*- End of function --------------------------------------------------------*/ @@ -782,13 +794,13 @@ static __inline__ int signal_detect(v27ter_rx_state_t *s, int16_t amp) { /* Count down a short delay, to ensure we push the last few bits through the filters before stopping. */ - v27ter_rx_restart(s, s->bit_rate, FALSE); + v27ter_rx_restart(s, s->bit_rate, false); report_status_change(s, SIG_STATUS_CARRIER_DOWN); return 0; } #if defined(IAXMODEM_STUFF) /* Carrier has dropped, but the put_bit is pending the signal_present delay. */ - s->carrier_drop_pending = TRUE; + s->carrier_drop_pending = true; #endif } } @@ -799,7 +811,7 @@ static __inline__ int signal_detect(v27ter_rx_state_t *s, int16_t amp) return 0; s->signal_present = 1; #if defined(IAXMODEM_STUFF) - s->carrier_drop_pending = FALSE; + s->carrier_drop_pending = false; #endif report_status_change(s, SIG_STATUS_CARRIER_UP); } @@ -1007,7 +1019,7 @@ SPAN_DECLARE(logging_state_t *) v27ter_rx_get_logging_state(v27ter_rx_state_t *s } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) v27ter_rx_restart(v27ter_rx_state_t *s, int bit_rate, int old_train) +SPAN_DECLARE(int) v27ter_rx_restart(v27ter_rx_state_t *s, int bit_rate, bool old_train) { span_log(&s->logging, SPAN_LOG_FLOW, "Restarting V.27ter\n"); if (bit_rate != 4800 && bit_rate != 2400) @@ -1031,8 +1043,9 @@ SPAN_DECLARE(int) v27ter_rx_restart(v27ter_rx_state_t *s, int bit_rate, int old_ #if defined(IAXMODEM_STUFF) s->high_sample = 0; s->low_samples = 0; - s->carrier_drop_pending = FALSE; + s->carrier_drop_pending = false; #endif + vec_zeroi32(s->diff_angles, 16); s->carrier_phase = 0; #if defined(SPANDSP_USE_FIXED_POINT) @@ -1086,7 +1099,7 @@ SPAN_DECLARE(v27ter_rx_state_t *) v27ter_rx_init(v27ter_rx_state_t *s, int bit_r } if (s == NULL) { - if ((s = (v27ter_rx_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (v27ter_rx_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -1096,7 +1109,7 @@ SPAN_DECLARE(v27ter_rx_state_t *) v27ter_rx_init(v27ter_rx_state_t *s, int bit_r s->put_bit = put_bit; s->put_bit_user_data = user_data; - v27ter_rx_restart(s, bit_rate, FALSE); + v27ter_rx_restart(s, bit_rate, false); return s; } /*- End of function --------------------------------------------------------*/ @@ -1109,7 +1122,7 @@ SPAN_DECLARE(int) v27ter_rx_release(v27ter_rx_state_t *s) SPAN_DECLARE(int) v27ter_rx_free(v27ter_rx_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/v27ter_tx.c b/libs/spandsp/src/v27ter_tx.c index f1d7ce263d..1cb724b42e 100644 --- a/libs/spandsp/src/v27ter_tx.c +++ b/libs/spandsp/src/v27ter_tx.c @@ -39,9 +39,15 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/fast_convert.h" #include "spandsp/logging.h" #include "spandsp/complex.h" @@ -128,7 +134,7 @@ static __inline__ int get_scrambled_bit(v27ter_tx_state_t *s) if (s->status_handler) s->status_handler(s->status_user_data, SIG_STATUS_END_OF_DATA); s->current_get_bit = fake_get_bit; - s->in_training = TRUE; + s->in_training = true; bit = 1; } return scramble(s, bit); @@ -208,7 +214,7 @@ static complexf_t getbaud(v27ter_tx_state_t *s) /* Switch from the fake get_bit routine, to the user supplied real one, and we are up and running. */ s->current_get_bit = s->get_bit; - s->in_training = FALSE; + s->in_training = false; } if (s->training_step == V27TER_TRAINING_SHUTDOWN_END) { @@ -367,7 +373,7 @@ SPAN_DECLARE(logging_state_t *) v27ter_tx_get_logging_state(v27ter_tx_state_t *s } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) v27ter_tx_restart(v27ter_tx_state_t *s, int bit_rate, int tep) +SPAN_DECLARE(int) v27ter_tx_restart(v27ter_tx_state_t *s, int bit_rate, bool tep) { if (bit_rate != 4800 && bit_rate != 2400) return -1; @@ -382,7 +388,7 @@ SPAN_DECLARE(int) v27ter_tx_restart(v27ter_tx_state_t *s, int bit_rate, int tep) s->rrc_filter_step = 0; s->scramble_reg = 0x3C; s->scrambler_pattern_count = 0; - s->in_training = TRUE; + s->in_training = true; s->training_step = (tep) ? V27TER_TRAINING_SEG_1 : V27TER_TRAINING_SEG_2; s->carrier_phase = 0; s->baud_phase = 0; @@ -392,7 +398,7 @@ SPAN_DECLARE(int) v27ter_tx_restart(v27ter_tx_state_t *s, int bit_rate, int tep) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(v27ter_tx_state_t *) v27ter_tx_init(v27ter_tx_state_t *s, int bit_rate, int tep, get_bit_func_t get_bit, void *user_data) +SPAN_DECLARE(v27ter_tx_state_t *) v27ter_tx_init(v27ter_tx_state_t *s, int bit_rate, bool tep, get_bit_func_t get_bit, void *user_data) { switch (bit_rate) { @@ -404,7 +410,7 @@ SPAN_DECLARE(v27ter_tx_state_t *) v27ter_tx_init(v27ter_tx_state_t *s, int bit_r } if (s == NULL) { - if ((s = (v27ter_tx_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (v27ter_tx_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -427,7 +433,7 @@ SPAN_DECLARE(int) v27ter_tx_release(v27ter_tx_state_t *s) SPAN_DECLARE(int) v27ter_tx_free(v27ter_tx_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/v29rx.c b/libs/spandsp/src/v29rx.c index f875966056..8431ffbfd7 100644 --- a/libs/spandsp/src/v29rx.c +++ b/libs/spandsp/src/v29rx.c @@ -40,9 +40,15 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/fast_convert.h" #include "spandsp/math_fixed.h" @@ -61,6 +67,7 @@ #include "spandsp/v29rx.h" #include "spandsp/private/logging.h" +#include "spandsp/private/power_meter.h" #include "spandsp/private/v29rx.h" #if defined(SPANDSP_USE_FIXED_POINT) @@ -860,14 +867,14 @@ static __inline__ int signal_detect(v29_rx_state_t *s, int16_t amp) { /* Count down a short delay, to ensure we push the last few bits through the filters before stopping. */ - v29_rx_restart(s, s->bit_rate, FALSE); + v29_rx_restart(s, s->bit_rate, false); report_status_change(s, SIG_STATUS_CARRIER_DOWN); return 0; } #if defined(IAXMODEM_STUFF) /* Carrier has dropped, but the put_bit is pending the signal_present delay. */ - s->carrier_drop_pending = TRUE; + s->carrier_drop_pending = true; #endif } } @@ -878,7 +885,7 @@ static __inline__ int signal_detect(v29_rx_state_t *s, int16_t amp) return 0; s->signal_present = 1; #if defined(IAXMODEM_STUFF) - s->carrier_drop_pending = FALSE; + s->carrier_drop_pending = false; #endif report_status_change(s, SIG_STATUS_CARRIER_UP); } @@ -1047,7 +1054,7 @@ SPAN_DECLARE(logging_state_t *) v29_rx_get_logging_state(v29_rx_state_t *s) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) v29_rx_restart(v29_rx_state_t *s, int bit_rate, int old_train) +SPAN_DECLARE(int) v29_rx_restart(v29_rx_state_t *s, int bit_rate, bool old_train) { int i; @@ -1082,9 +1089,10 @@ SPAN_DECLARE(int) v29_rx_restart(v29_rx_state_t *s, int bit_rate, int old_train) #if defined(IAXMODEM_STUFF) s->high_sample = 0; s->low_samples = 0; - s->carrier_drop_pending = FALSE; + s->carrier_drop_pending = false; #endif s->old_train = old_train; + vec_zeroi32(s->diff_angles, 16); s->carrier_phase = 0; @@ -1147,7 +1155,7 @@ SPAN_DECLARE(v29_rx_state_t *) v29_rx_init(v29_rx_state_t *s, int bit_rate, put_ } if (s == NULL) { - if ((s = (v29_rx_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (v29_rx_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -1162,7 +1170,7 @@ SPAN_DECLARE(v29_rx_state_t *) v29_rx_init(v29_rx_state_t *s, int bit_rate, put_ /* The thresholds should be on at -26dBm0 and off at -31dBm0 */ v29_rx_signal_cutoff(s, -28.5f); - v29_rx_restart(s, bit_rate, FALSE); + v29_rx_restart(s, bit_rate, false); return s; } /*- End of function --------------------------------------------------------*/ @@ -1175,7 +1183,7 @@ SPAN_DECLARE(int) v29_rx_release(v29_rx_state_t *s) SPAN_DECLARE(int) v29_rx_free(v29_rx_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/v29tx.c b/libs/spandsp/src/v29tx.c index 3eac97e1bc..749047f099 100644 --- a/libs/spandsp/src/v29tx.c +++ b/libs/spandsp/src/v29tx.c @@ -39,9 +39,15 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/fast_convert.h" #include "spandsp/logging.h" #include "spandsp/complex.h" @@ -106,7 +112,7 @@ static __inline__ int get_scrambled_bit(v29_tx_state_t *s) if (s->status_handler) s->status_handler(s->status_user_data, SIG_STATUS_END_OF_DATA); s->current_get_bit = fake_get_bit; - s->in_training = TRUE; + s->in_training = true; bit = 1; } out_bit = (bit ^ (s->scramble_reg >> (18 - 1)) ^ (s->scramble_reg >> (23 - 1))) & 1; @@ -174,7 +180,7 @@ static __inline__ complexf_t getbaud(v29_tx_state_t *s) /* Switch from the fake get_bit routine, to the user supplied real one, and we are up and running. */ s->current_get_bit = s->get_bit; - s->in_training = FALSE; + s->in_training = false; } if (s->training_step == V29_TRAINING_SHUTDOWN_END) { @@ -336,7 +342,7 @@ SPAN_DECLARE(logging_state_t *) v29_tx_get_logging_state(v29_tx_state_t *s) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) v29_tx_restart(v29_tx_state_t *s, int bit_rate, int tep) +SPAN_DECLARE(int) v29_tx_restart(v29_tx_state_t *s, int bit_rate, bool tep) { span_log(&s->logging, SPAN_LOG_FLOW, "Restarting V.29\n"); s->bit_rate = bit_rate; @@ -365,7 +371,7 @@ SPAN_DECLARE(int) v29_tx_restart(v29_tx_state_t *s, int bit_rate, int tep) s->rrc_filter_step = 0; s->scramble_reg = 0; s->training_scramble_reg = 0x2A; - s->in_training = TRUE; + s->in_training = true; s->training_step = (tep) ? V29_TRAINING_SEG_TEP : V29_TRAINING_SEG_1; s->carrier_phase = 0; s->baud_phase = 0; @@ -375,7 +381,7 @@ SPAN_DECLARE(int) v29_tx_restart(v29_tx_state_t *s, int bit_rate, int tep) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(v29_tx_state_t *) v29_tx_init(v29_tx_state_t *s, int bit_rate, int tep, get_bit_func_t get_bit, void *user_data) +SPAN_DECLARE(v29_tx_state_t *) v29_tx_init(v29_tx_state_t *s, int bit_rate, bool tep, get_bit_func_t get_bit, void *user_data) { switch (bit_rate) { @@ -388,7 +394,7 @@ SPAN_DECLARE(v29_tx_state_t *) v29_tx_init(v29_tx_state_t *s, int bit_rate, int } if (s == NULL) { - if ((s = (v29_tx_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (v29_tx_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -411,7 +417,7 @@ SPAN_DECLARE(int) v29_tx_release(v29_tx_state_t *s) SPAN_DECLARE(int) v29_tx_free(v29_tx_state_t *s) { - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/v42.c b/libs/spandsp/src/v42.c index 3830f5c53a..c52a9676a2 100644 --- a/libs/spandsp/src/v42.c +++ b/libs/spandsp/src/v42.c @@ -38,9 +38,15 @@ #include #include #include +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/bit_operations.h" #include "spandsp/async.h" @@ -51,9 +57,6 @@ #include "spandsp/private/hdlc.h" #include "spandsp/private/v42.h" -#define FALSE 0 -#define TRUE (!FALSE) - /* Detection phase timer */ #define T_400 750 /* Acknowledgement timer - 1 second between SABME's */ @@ -305,9 +308,9 @@ static int receive_xid(v42_state_t *ss, const uint8_t *frame, int len) param_id = buf[0]; param_len = buf[1]; buf += 2; - group_len -= (2 + param_len); - if (group_len < 0) + if (group_len < (2 + param_len)) break; + group_len -= (2 + param_len); switch (param_id) { case PI_HDLC_OPTIONAL_FUNCTIONS: @@ -347,9 +350,9 @@ static int receive_xid(v42_state_t *ss, const uint8_t *frame, int len) param_id = buf[0]; param_len = buf[1]; buf += 2; - group_len -= (2 + param_len); - if (group_len < 0) + if (group_len < 2 + param_len) break; + group_len -= (2 + param_len); switch (param_id) { case PI_PARAMETER_SET_ID: @@ -625,30 +628,30 @@ static int tx_information_frame(v42_state_t *ss) s = &ss->lapm; if (s->far_busy || ((s->vs - s->va) & 0x7F) >= s->tx_window_size_k) - return FALSE; + return false; if (s->info_get != s->info_put) - return TRUE; + return true; if ((info_put_next = s->info_put + 1) >= V42_INFO_FRAMES) info_put_next = 0; if (info_put_next == s->info_get || info_put_next == s->info_acked) - return FALSE; + return false; f = &s->info_buf[s->info_put]; buf = f->buf; if (s->iframe_get == NULL) - return FALSE; + return false; n = s->iframe_get(s->iframe_get_user_data, buf + 3, s->tx_n401); if (n < 0) { /* Error */ report_rx_status_change(ss, SIG_STATUS_LINK_ERROR); - return FALSE; + return false; } if (n == 0) - return FALSE; + return false; f->len = n + 3; s->info_put = info_put_next; - return TRUE; + return true; } /*- End of function --------------------------------------------------------*/ @@ -767,11 +770,11 @@ static void receive_information_frame(v42_state_t *ss, const uint8_t *frame, int if (!s->rejected) { tx_supervisory_frame(s, s->rsp_addr, LAPM_S_REJ, (frame[2] & 0x1)); - s->rejected = TRUE; + s->rejected = true; } return; } - s->rejected = FALSE; + s->rejected = false; s->iframe_put(s->iframe_put_user_data, frame + 3, len - 3); /* Increment vr */ @@ -789,20 +792,20 @@ static void rx_supervisory_cmd_frame(v42_state_t *ss, const uint8_t *frame, int switch (frame[1] & 0x0C) { case LAPM_S_RR: - s->far_busy = FALSE; + s->far_busy = false; ack_info(ss, frame[2] >> 1); /* If p = 1 may be used for status checking? */ tx_information_rr_rnr_response(ss, frame, len); break; case LAPM_S_RNR: - s->far_busy = TRUE; + s->far_busy = true; ack_info(ss, frame[2] >> 1); /* If p = 1 may be used for status checking? */ if ((frame[2] & 0x1)) tx_supervisory_frame(s, s->rsp_addr, (s->local_busy) ? LAPM_S_RNR : LAPM_S_RR, 1); break; case LAPM_S_REJ: - s->far_busy = FALSE; + s->far_busy = false; ack_info(ss, frame[2] >> 1); if (s->retry_count == 0) { @@ -831,7 +834,7 @@ static void rx_supervisory_rsp_frame(v42_state_t *ss, const uint8_t *frame, int switch (frame[1] & 0x0C) { case LAPM_S_RR: - s->far_busy = FALSE; + s->far_busy = false; ack_info(ss, frame[2] >> 1); if (s->retry_count && (frame[2] & 0x1)) { @@ -840,7 +843,7 @@ static void rx_supervisory_rsp_frame(v42_state_t *ss, const uint8_t *frame, int } break; case LAPM_S_RNR: - s->far_busy = TRUE; + s->far_busy = true; ack_info(ss, frame[2] >> 1); if (s->retry_count && (frame[2] & 0x1)) { @@ -851,7 +854,7 @@ static void rx_supervisory_rsp_frame(v42_state_t *ss, const uint8_t *frame, int t401_start(ss); break; case LAPM_S_REJ: - s->far_busy = FALSE; + s->far_busy = false; ack_info(ss, frame[2] >> 1); if (s->retry_count == 0 || (frame[2] & 0x1)) { @@ -997,7 +1000,7 @@ static int rx_unnumbered_rsp_frame(v42_state_t *ss, const uint8_t *frame, int le if (s->configuring) { receive_xid(ss, frame, len); - s->configuring = FALSE; + s->configuring = false; t401_stop(ss); switch (s->state) { @@ -1005,7 +1008,7 @@ static int rx_unnumbered_rsp_frame(v42_state_t *ss, const uint8_t *frame, int le lapm_connect(ss); break; case LAPM_DATA: - s->local_busy = FALSE; + s->local_busy = false; tx_supervisory_frame(s, s->cmd_addr, LAPM_S_RR, 0); break; } @@ -1140,10 +1143,10 @@ static int lapm_config(v42_state_t *ss) lapm_state_t *s; s = &ss->lapm; - s->configuring = TRUE; + s->configuring = true; if (s->state == LAPM_DATA) { - s->local_busy = TRUE; + s->local_busy = true; tx_supervisory_frame(s, s->cmd_addr, LAPM_S_RNR, 1); } transmit_xid(ss, s->cmd_addr); @@ -1158,8 +1161,8 @@ static void reset_lapm(v42_state_t *ss) s = &ss->lapm; /* Reset the LAP.M state */ - s->local_busy = FALSE; - s->far_busy = FALSE; + s->local_busy = false; + s->far_busy = false; s->vs = 0; s->va = 0; s->vr = 0; @@ -1320,7 +1323,7 @@ static void negotiation_rx_bit(v42_state_t *s, int new_bit) } else { - s->neg.odp_seen = TRUE; + s->neg.odp_seen = true; } /*endif*/ break; @@ -1471,8 +1474,8 @@ SPAN_DECLARE(void) v42_set_status_callback(v42_state_t *s, modem_status_func_t s SPAN_DECLARE(void) v42_restart(v42_state_t *s) { - hdlc_tx_init(&s->lapm.hdlc_tx, FALSE, 1, TRUE, lapm_hdlc_underflow, s); - hdlc_rx_init(&s->lapm.hdlc_rx, FALSE, FALSE, 1, lapm_receive, s); + hdlc_tx_init(&s->lapm.hdlc_tx, false, 1, true, lapm_hdlc_underflow, s); + hdlc_rx_init(&s->lapm.hdlc_rx, false, false, 1, lapm_receive, s); if (s->detect) { @@ -1484,7 +1487,7 @@ SPAN_DECLARE(void) v42_restart(v42_state_t *s) s->neg.rxoks = 0; s->neg.txadps = 0; s->neg.rx_negotiation_step = 0; - s->neg.odp_seen = FALSE; + s->neg.odp_seen = false; t400_start(s); s->lapm.state = LAPM_DETECT; } @@ -1499,8 +1502,8 @@ SPAN_DECLARE(void) v42_restart(v42_state_t *s) /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(v42_state_t *) v42_init(v42_state_t *ss, - int calling_party, - int detect, + bool calling_party, + bool detect, get_msg_func_t iframe_get, put_msg_func_t iframe_put, void *user_data) @@ -1509,7 +1512,7 @@ SPAN_DECLARE(v42_state_t *) v42_init(v42_state_t *ss, if (ss == NULL) { - if ((ss = (v42_state_t *) malloc(sizeof(*ss))) == NULL) + if ((ss = (v42_state_t *) span_alloc(sizeof(*ss))) == NULL) return NULL; } memset(ss, 0, sizeof(*ss)); @@ -1523,8 +1526,8 @@ SPAN_DECLARE(v42_state_t *) v42_init(v42_state_t *ss, s->iframe_put_user_data = user_data; s->state = (ss->detect) ? LAPM_DETECT : LAPM_IDLE; - s->local_busy = FALSE; - s->far_busy = FALSE; + s->local_busy = false; + s->far_busy = false; /* The address octet is: Data link connection identifier (0) @@ -1564,7 +1567,7 @@ SPAN_DECLARE(int) v42_release(v42_state_t *s) SPAN_DECLARE(int) v42_free(v42_state_t *s) { v42_release(s); - free(s); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/v42bis.c b/libs/spandsp/src/v42bis.c index fec129a6f2..3ca07fc493 100644 --- a/libs/spandsp/src/v42bis.c +++ b/libs/spandsp/src/v42bis.c @@ -37,8 +37,14 @@ #include #include #include +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/bit_operations.h" #include "spandsp/async.h" @@ -170,8 +176,8 @@ static void dictionary_init(v42bis_comp_state_t *s) s->flushed_length = 0; s->string_length = 0; s->escape_code = 0; - s->transparent = TRUE; - s->escaped = FALSE; + s->transparent = true; + s->escaped = false; s->compression_performance = COMPRESSIBILITY_MONITOR; } /*- End of function --------------------------------------------------------*/ @@ -329,7 +335,7 @@ static void go_compressed(v42bis_state_t *ss) push_octet(s, s->escape_code); push_octet(s, V42BIS_ECM); s->bit_buffer = 0; - s->transparent = FALSE; + s->transparent = false; } /*- End of function --------------------------------------------------------*/ @@ -352,7 +358,7 @@ static void go_transparent(v42bis_state_t *ss) s->last_added = 0; push_compressed_code(s, V42BIS_ETM); push_octet_alignment(s); - s->transparent = TRUE; + s->transparent = true; } /*- End of function --------------------------------------------------------*/ @@ -534,14 +540,14 @@ SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *ss, const uint8_t buf[], int if (s->escaped) { /* Command */ - s->escaped = FALSE; + s->escaped = false; switch (in) { case V42BIS_ECM: /* Enter compressed mode */ span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_ECM\n"); send_string(s); - s->transparent = FALSE; + s->transparent = false; s->update_at = s->last_matched; s->last_matched = 0; i++; @@ -567,12 +573,12 @@ SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *ss, const uint8_t buf[], int } else if (in == s->escape_code) { - s->escaped = TRUE; + s->escaped = true; i++; continue; } - yyy = TRUE; + yyy = true; for (j = 0; j < 2 && yyy; j++) { if (s->update_at) @@ -605,7 +611,7 @@ SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *ss, const uint8_t buf[], int s->last_matched = 0; } i++; - yyy = FALSE; + yyy = false; } } } @@ -632,7 +638,7 @@ SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *ss, const uint8_t buf[], int /* Enter transparent mode */ span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_ETM\n"); s->bit_count = 0; - s->transparent = TRUE; + s->transparent = true; s->last_matched = 0; s->last_added = 0; break; @@ -729,7 +735,7 @@ SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s, return NULL; if (s == NULL) { - if ((s = (v42bis_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (v42bis_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -760,6 +766,7 @@ SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s) { comp_exit(&s->compress); comp_exit(&s->decompress); + span_free(s); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/v8.c b/libs/spandsp/src/v8.c index e04a1eba9c..464d90b0fe 100644 --- a/libs/spandsp/src/v8.c +++ b/libs/spandsp/src/v8.c @@ -39,9 +39,15 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include "spandsp/telephony.h" +#include "spandsp/alloc.h" #include "spandsp/logging.h" #include "spandsp/queue.h" #include "spandsp/async.h" @@ -57,6 +63,7 @@ #include "spandsp/v8.h" #include "spandsp/private/logging.h" +#include "spandsp/private/power_meter.h" #include "spandsp/private/fsk.h" #include "spandsp/private/modem_connect_tones.h" #include "spandsp/private/v8.h" @@ -190,15 +197,15 @@ SPAN_DECLARE(const char *) v8_pstn_access_to_str(int pstn_access) return "Calling modem on cellular"; case V8_PSTN_ACCESS_ANSWER_DCE_CELLULAR: return "Answering modem on cellular"; - case V8_PSTN_ACCESS_ANSWER_DCE_CELLULAR | V8_PSTN_ACCESS_CALL_DCE_CELLULAR: + case (V8_PSTN_ACCESS_ANSWER_DCE_CELLULAR | V8_PSTN_ACCESS_CALL_DCE_CELLULAR): return "Answering and calling modems on cellular"; case V8_PSTN_ACCESS_DCE_ON_DIGITAL: return "DCE on digital"; - case V8_PSTN_ACCESS_DCE_ON_DIGITAL | V8_PSTN_ACCESS_CALL_DCE_CELLULAR: + case (V8_PSTN_ACCESS_DCE_ON_DIGITAL | V8_PSTN_ACCESS_CALL_DCE_CELLULAR): return "DCE on digital, and calling modem on cellular"; - case V8_PSTN_ACCESS_DCE_ON_DIGITAL | V8_PSTN_ACCESS_ANSWER_DCE_CELLULAR: + case (V8_PSTN_ACCESS_DCE_ON_DIGITAL | V8_PSTN_ACCESS_ANSWER_DCE_CELLULAR): return "DCE on digital, answering modem on cellular"; - case V8_PSTN_ACCESS_DCE_ON_DIGITAL | V8_PSTN_ACCESS_ANSWER_DCE_CELLULAR | V8_PSTN_ACCESS_CALL_DCE_CELLULAR: + case (V8_PSTN_ACCESS_DCE_ON_DIGITAL | V8_PSTN_ACCESS_ANSWER_DCE_CELLULAR | V8_PSTN_ACCESS_CALL_DCE_CELLULAR): return "DCE on digital, and answering and calling modems on cellular"; } return "PSTN access unknown"; @@ -226,15 +233,15 @@ SPAN_DECLARE(const char *) v8_pcm_modem_availability_to_str(int pcm_modem_availa return "V.90/V.92 analogue available"; case V8_PSTN_PCM_MODEM_V90_V92_DIGITAL: return "V.90/V.92 digital available"; - case V8_PSTN_PCM_MODEM_V90_V92_DIGITAL | V8_PSTN_PCM_MODEM_V90_V92_ANALOGUE: + case (V8_PSTN_PCM_MODEM_V90_V92_DIGITAL | V8_PSTN_PCM_MODEM_V90_V92_ANALOGUE): return "V.90/V.92 digital/analogue available"; case V8_PSTN_PCM_MODEM_V91: return "V.91 available"; - case V8_PSTN_PCM_MODEM_V91 | V8_PSTN_PCM_MODEM_V90_V92_ANALOGUE: + case (V8_PSTN_PCM_MODEM_V91 | V8_PSTN_PCM_MODEM_V90_V92_ANALOGUE): return "V.91 and V.90/V.92 analogue available"; - case V8_PSTN_PCM_MODEM_V91 | V8_PSTN_PCM_MODEM_V90_V92_DIGITAL: + case (V8_PSTN_PCM_MODEM_V91 | V8_PSTN_PCM_MODEM_V90_V92_DIGITAL): return "V.91 and V.90/V.92 digital available"; - case V8_PSTN_PCM_MODEM_V91 | V8_PSTN_PCM_MODEM_V90_V92_DIGITAL | V8_PSTN_PCM_MODEM_V90_V92_ANALOGUE: + case (V8_PSTN_PCM_MODEM_V91 | V8_PSTN_PCM_MODEM_V90_V92_DIGITAL | V8_PSTN_PCM_MODEM_V90_V92_ANALOGUE): return "V.91 and V.90/V.92 digital/analogue available"; } return "PCM availability unknown"; @@ -426,7 +433,7 @@ static void cm_jm_decode(v8_state_t *s) return; } /* We have a matching pair of CMs or JMs, so we are happy this is correct. */ - s->got_cm_jm = TRUE; + s->got_cm_jm = true; span_log(&s->logging, SPAN_LOG_FLOW, "Decoding\n"); @@ -576,7 +583,7 @@ static void put_bit(void *user_data, int bit) if (data == 0) { if (++s->zero_byte_count == 3) - s->got_cj = TRUE; + s->got_cj = true; } else { @@ -602,8 +609,8 @@ static void v8_decode_init(v8_state_t *s) s->preamble_type = V8_SYNC_UNKNOWN; s->bit_stream = 0; s->cm_jm_len = 0; - s->got_cm_jm = FALSE; - s->got_cj = FALSE; + s->got_cm_jm = false; + s->got_cj = false; s->zero_byte_count = 0; s->rx_data_ptr = 0; } @@ -750,7 +757,7 @@ SPAN_DECLARE_NONSTD(int) v8_tx(v8_state_t *s, int16_t *amp, int max_len) if (len < max_len) { span_log(&s->logging, SPAN_LOG_FLOW, "FSK ends\n"); - s->fsk_tx_on = FALSE; + s->fsk_tx_on = false; } } return len; @@ -831,7 +838,7 @@ SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len) fsk_tx_restart(&s->v21tx, &preset_fsk_specs[FSK_V21CH1]); send_ci(s); s->state = V8_CI_ON; - s->fsk_tx_on = TRUE; + s->fsk_tx_on = true; break; case V8_CI_ON: residual_samples = modem_connect_tones_rx(&s->ansam_rx, amp, len); @@ -872,7 +879,7 @@ SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len) fsk_tx_restart(&s->v21tx, &preset_fsk_specs[FSK_V21CH1]); send_ci(s); s->state = V8_CI_ON; - s->fsk_tx_on = TRUE; + s->fsk_tx_on = true; } } break; @@ -893,7 +900,7 @@ SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len) send_v92(s); send_cm_jm(s); s->state = V8_CM_ON; - s->fsk_tx_on = TRUE; + s->fsk_tx_on = true; } break; case V8_CM_ON: @@ -907,7 +914,7 @@ SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len) for (i = 0; i < 3; i++) v8_put_byte(s, 0); s->state = V8_CJ_ON; - s->fsk_tx_on = TRUE; + s->fsk_tx_on = true; break; } if ((s->negotiation_timer -= len) <= 0) @@ -960,7 +967,7 @@ SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len) s->state = V8_JM_ON; send_cm_jm(s); s->modem_connect_tone_tx_on = ms_to_samples(75); - s->fsk_tx_on = TRUE; + s->fsk_tx_on = true; break; } if ((s->negotiation_timer -= len) <= 0) @@ -1023,7 +1030,7 @@ SPAN_DECLARE(logging_state_t *) v8_get_logging_state(v8_state_t *s) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) v8_restart(v8_state_t *s, int calling_party, v8_parms_t *parms) +SPAN_DECLARE(int) v8_restart(v8_state_t *s, bool calling_party, v8_parms_t *parms) { memcpy(&s->parms, parms, sizeof(s->parms)); memset(&s->result, 0, sizeof(s->result)); @@ -1071,14 +1078,14 @@ SPAN_DECLARE(int) v8_restart(v8_state_t *s, int calling_party, v8_parms_t *parms /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(v8_state_t *) v8_init(v8_state_t *s, - int calling_party, + bool calling_party, v8_parms_t *parms, v8_result_handler_t result_handler, void *user_data) { if (s == NULL) { - if ((s = (v8_state_t *) malloc(sizeof(*s))) == NULL) + if ((s = (v8_state_t *) span_alloc(sizeof(*s))) == NULL) return NULL; } memset(s, 0, sizeof(*s)); @@ -1103,7 +1110,7 @@ SPAN_DECLARE(int) v8_free(v8_state_t *s) int ret; ret = queue_free(s->tx_queue); - free(s); + span_free(s); return ret; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/vector_int.c b/libs/spandsp/src/vector_int.c index 66166e52eb..c2ed12f98e 100644 --- a/libs/spandsp/src/vector_int.c +++ b/libs/spandsp/src/vector_int.c @@ -147,7 +147,7 @@ SPAN_DECLARE(int32_t) vec_dot_prodi16(const int16_t x[], const int16_t y[], int " emms;\n" : "=a" (z) : "S" (x), "D" (y), "a" (n) - : "cc" + : "cc", "rdx", "mm0", "mm1", "mm2" ); #elif defined(__GNUC__) && defined(SPANDSP_USE_MMX) && defined(__i386__) __asm__ __volatile__( @@ -245,7 +245,7 @@ SPAN_DECLARE(int32_t) vec_dot_prodi16(const int16_t x[], const int16_t y[], int " emms;\n" : "=a" (z) : "S" (x), "D" (y), "a" (n) - : "cc" + : "cc", "edx", "mm0", "mm1", "mm2" ); #else int i; @@ -436,7 +436,7 @@ SPAN_DECLARE(int32_t) vec_min_maxi16(const int16_t x[], int n, int16_t out[]) " emms;\n" : "=a" (max) : "S" (x), "a" (n), "d" (out), [lower] "m" (lower_bound), [upper] "m" (upper_bound) - : "ecx" + : "ecx", "mm0", "mm1", "mm2", "mm3", "mm4" ); #elif defined(__GNUC__) && defined(SPANDSP_USE_MMX) && defined(__i386__) static const int32_t lower_bound = 0x80008000; @@ -589,7 +589,7 @@ SPAN_DECLARE(int32_t) vec_min_maxi16(const int16_t x[], int n, int16_t out[]) " emms;\n" : "=a" (max) : "S" (x), "a" (n), "d" (out), [lower] "m" (lower_bound), [upper] "m" (upper_bound) - : "ecx" + : "ecx", "mm0", "mm1", "mm2", "mm3", "mm4" ); #else int i; diff --git a/libs/spandsp/test-data/etsi/fax/generate_etsi_300_242_pages.c b/libs/spandsp/test-data/etsi/fax/generate_etsi_300_242_pages.c index c862a2ba80..be425bb765 100644 --- a/libs/spandsp/test-data/etsi/fax/generate_etsi_300_242_pages.c +++ b/libs/spandsp/test-data/etsi/fax/generate_etsi_300_242_pages.c @@ -63,7 +63,7 @@ struct T4_X_RESOLUTION_R8, T4_Y_RESOLUTION_STANDARD, T4_WIDTH_R8_A4, - 1100, + 1002, COMPRESSION_CCITT_T4, 0 }, @@ -72,7 +72,7 @@ struct T4_X_RESOLUTION_R8, T4_Y_RESOLUTION_STANDARD, T4_WIDTH_R8_A4, - 1100, + 1002, COMPRESSION_CCITT_T4, 1 }, @@ -81,7 +81,7 @@ struct T4_X_RESOLUTION_R8, T4_Y_RESOLUTION_STANDARD, T4_WIDTH_R8_A4, - 1100, + 237, COMPRESSION_CCITT_T4, 2 }, @@ -90,7 +90,7 @@ struct T4_X_RESOLUTION_R8, T4_Y_RESOLUTION_STANDARD, T4_WIDTH_R8_A4, - 1100, + 237, COMPRESSION_CCITT_T4, 3 }, @@ -99,7 +99,7 @@ struct T4_X_RESOLUTION_R8, T4_Y_RESOLUTION_STANDARD, T4_WIDTH_R8_A4, - 1100, + 400, COMPRESSION_CCITT_T4, 4 }, @@ -108,7 +108,7 @@ struct T4_X_RESOLUTION_R8, T4_Y_RESOLUTION_STANDARD, T4_WIDTH_R8_A4, - 1100, + 1079, COMPRESSION_CCITT_T4, 5 }, @@ -117,7 +117,7 @@ struct T4_X_RESOLUTION_R8, T4_Y_RESOLUTION_STANDARD, T4_WIDTH_R8_A4, - 1100, + 1728, COMPRESSION_CCITT_T4, 6 }, @@ -153,7 +153,7 @@ struct T4_X_RESOLUTION_R8, T4_Y_RESOLUTION_STANDARD, T4_WIDTH_R8_A4, - 1100, + 1079, COMPRESSION_CCITT_T4, 5 }, @@ -178,12 +178,6 @@ struct int photo_metric = PHOTOMETRIC_MINISWHITE; int fill_order = FILLORDER_LSB2MSB; -static void clear_row(uint8_t buf[], int width) -{ - memset(buf, 0, width/8 + 1); -} -/*- End of function --------------------------------------------------------*/ - static void set_pixel(uint8_t buf[], int row, int pixel) { row--; @@ -191,13 +185,6 @@ static void set_pixel(uint8_t buf[], int row, int pixel) } /*- End of function --------------------------------------------------------*/ -static void clear_pixel(uint8_t buf[], int row, int pixel) -{ - row--; - buf[row*1728/8 + pixel/8] &= ~(0x80 >> (pixel & 0x07)); -} -/*- End of function --------------------------------------------------------*/ - static void set_pixel_range(uint8_t buf[], int row, int start, int end) { int i; @@ -207,6 +194,13 @@ static void set_pixel_range(uint8_t buf[], int row, int start, int end) } /*- End of function --------------------------------------------------------*/ +static void clear_pixel(uint8_t buf[], int row, int pixel) +{ + row--; + buf[row*1728/8 + pixel/8] &= ~(0x80 >> (pixel & 0x07)); +} +/*- End of function --------------------------------------------------------*/ + static void clear_pixel_range(uint8_t buf[], int row, int start, int end) { int i; @@ -216,6 +210,12 @@ static void clear_pixel_range(uint8_t buf[], int row, int start, int end) } /*- End of function --------------------------------------------------------*/ +static void clear_row(uint8_t buf[], int width) +{ + memset(buf, 0, width/8 + 1); +} +/*- End of function --------------------------------------------------------*/ + static int create_white_page(TIFF *tiff_file) { uint8_t image_buffer[8192]; @@ -593,7 +593,6 @@ int main(int argc, char *argv[]) TIFFSetField(tiff_file, TIFFTAG_BITSPERSAMPLE, 1); TIFFSetField(tiff_file, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(tiff_file, TIFFTAG_SAMPLESPERPIXEL, 1); - TIFFSetField(tiff_file, TIFFTAG_ROWSPERSTRIP, -1L); TIFFSetField(tiff_file, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(tiff_file, TIFFTAG_PHOTOMETRIC, photo_metric); TIFFSetField(tiff_file, TIFFTAG_FILLORDER, fill_order); @@ -625,6 +624,7 @@ int main(int argc, char *argv[]) image_length = sequence[i].length; TIFFSetField(tiff_file, TIFFTAG_PAGENUMBER, 0, 1); TIFFSetField(tiff_file, TIFFTAG_CLEANFAXDATA, CLEANFAXDATA_CLEAN); + TIFFSetField(tiff_file, TIFFTAG_ROWSPERSTRIP, 128); TIFFSetField(tiff_file, TIFFTAG_IMAGELENGTH, image_length); TIFFCheckpointDirectory(tiff_file); @@ -665,7 +665,11 @@ int main(int argc, char *argv[]) break; } /* ....then the directory entry, and libtiff is happy. */ - TIFFSetField(tiff_file, TIFFTAG_IMAGELENGTH, image_length); + if (image_length != sequence[i].length) + { + printf("Length mismatch - %d: %d vs %d\n", i, image_length, sequence[i].length); + exit(2); + } TIFFWriteDirectory(tiff_file); } diff --git a/libs/spandsp/test-data/itu/fax/Makefile.am b/libs/spandsp/test-data/itu/fax/Makefile.am index 595b5f7e93..bc8234f66b 100644 --- a/libs/spandsp/test-data/itu/fax/Makefile.am +++ b/libs/spandsp/test-data/itu/fax/Makefile.am @@ -62,36 +62,48 @@ ITU_TEST_PAGES = itu1.tif \ test3.tif \ test4.tif -MIXED_SIZE_PAGES = R1200_1200_A4.tif \ - R1200_1200_B4.tif \ - R1200_1200_A3.tif \ - R600_1200_A4.tif \ - R600_1200_B4.tif \ - R600_1200_A3.tif \ - R600_600_A4.tif \ - R600_600_B4.tif \ - R600_600_A3.tif \ - R16_800_A4.tif \ - R16_800_B4.tif \ - R16_800_A3.tif \ - R16_154_A4.tif \ - R16_154_B4.tif \ - R16_154_A3.tif \ - R300_600_A4.tif \ - R300_600_B4.tif \ - R300_600_A3.tif \ - R300_300_A4.tif \ - R300_300_B4.tif \ - R300_300_A3.tif \ - R8_154_A4.tif \ - R8_154_B4.tif \ - R8_154_A3.tif \ - R8_77_A4.tif \ - R8_77_B4.tif \ - R8_77_A3.tif \ - R8_385_A4.tif \ - R8_385_B4.tif \ - R8_385_A3.tif +MIXED_SIZE_PAGES = bilevel_1200_1200_A4.tif \ + bilevel_1200_1200_B4.tif \ + bilevel_1200_1200_A3.tif \ + bilevel_600_1200_A4.tif \ + bilevel_600_1200_B4.tif \ + bilevel_600_1200_A3.tif \ + bilevel_600_600_A4.tif \ + bilevel_600_600_B4.tif \ + bilevel_600_600_A3.tif \ + bilevel_400_800_A4.tif \ + bilevel_400_800_B4.tif \ + bilevel_400_800_A3.tif \ + bilevel_400_400_A4.tif \ + bilevel_400_400_B4.tif \ + bilevel_400_400_A3.tif \ + bilevel_300_600_A4.tif \ + bilevel_300_600_B4.tif \ + bilevel_300_600_A3.tif \ + bilevel_300_300_A4.tif \ + bilevel_300_300_B4.tif \ + bilevel_300_300_A3.tif \ + bilevel_200_400_A4.tif \ + bilevel_200_400_B4.tif \ + bilevel_200_400_A3.tif \ + bilevel_200_200_A4.tif \ + bilevel_200_200_B4.tif \ + bilevel_200_200_A3.tif \ + bilevel_200_100_A4.tif \ + bilevel_200_100_B4.tif \ + bilevel_200_100_A3.tif \ + bilevel_R16_154_A4.tif \ + bilevel_R16_154_B4.tif \ + bilevel_R16_154_A3.tif \ + bilevel_R8_154_A4.tif \ + bilevel_R8_154_B4.tif \ + bilevel_R8_154_A3.tif \ + bilevel_R8_77_A4.tif \ + bilevel_R8_77_B4.tif \ + bilevel_R8_77_A3.tif \ + bilevel_R8_385_A4.tif \ + bilevel_R8_385_B4.tif \ + bilevel_R8_385_A3.tif EXTRA_DIST = ${ITU_TEST_PAGES_PBM} diff --git a/libs/spandsp/test-data/itu/fax/generate_dithered_tif.c b/libs/spandsp/test-data/itu/fax/generate_dithered_tif.c index 4276b8c835..857ccbee72 100644 --- a/libs/spandsp/test-data/itu/fax/generate_dithered_tif.c +++ b/libs/spandsp/test-data/itu/fax/generate_dithered_tif.c @@ -63,7 +63,6 @@ int main(int argc, char *argv[]) { int image_width; int row; - int resunit; int output_compression; int output_t4_options; uint8_t image_buffer[1024]; @@ -93,15 +92,12 @@ int main(int argc, char *argv[]) /* Prepare the directory entry fully before writing the image, or libtiff complains */ TIFFSetField(tiff_file, TIFFTAG_COMPRESSION, output_compression); if (output_compression == COMPRESSION_CCITT_T4) - { TIFFSetField(tiff_file, TIFFTAG_T4OPTIONS, output_t4_options); - TIFFSetField(tiff_file, TIFFTAG_FAXMODE, FAXMODE_CLASSF); - } + TIFFSetField(tiff_file, TIFFTAG_FAXMODE, FAXMODE_CLASSF); TIFFSetField(tiff_file, TIFFTAG_IMAGEWIDTH, image_width); TIFFSetField(tiff_file, TIFFTAG_BITSPERSAMPLE, 1); TIFFSetField(tiff_file, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(tiff_file, TIFFTAG_SAMPLESPERPIXEL, 1); - TIFFSetField(tiff_file, TIFFTAG_ROWSPERSTRIP, -1L); TIFFSetField(tiff_file, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(tiff_file, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE); TIFFSetField(tiff_file, TIFFTAG_FILLORDER, FILLORDER_LSB2MSB); @@ -110,16 +106,15 @@ int main(int argc, char *argv[]) y_resolution = y_res/100.0f; TIFFSetField(tiff_file, TIFFTAG_XRESOLUTION, floorf(x_resolution*2.54f + 0.5f)); TIFFSetField(tiff_file, TIFFTAG_YRESOLUTION, floorf(y_resolution*2.54f + 0.5f)); - resunit = RESUNIT_INCH; - TIFFSetField(tiff_file, TIFFTAG_RESOLUTIONUNIT, resunit); + TIFFSetField(tiff_file, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); - TIFFSetField(tiff_file, TIFFTAG_SOFTWARE, "spandsp"); if (gethostname(buf, sizeof(buf)) == 0) TIFFSetField(tiff_file, TIFFTAG_HOSTCOMPUTER, buf); + TIFFSetField(tiff_file, TIFFTAG_SOFTWARE, "Spandsp"); TIFFSetField(tiff_file, TIFFTAG_IMAGEDESCRIPTION, "Checkerboard or dithered ones"); TIFFSetField(tiff_file, TIFFTAG_MAKE, "soft-switch.org"); - TIFFSetField(tiff_file, TIFFTAG_MODEL, "test data"); + TIFFSetField(tiff_file, TIFFTAG_MODEL, "testy"); time(&now); tm = localtime(&now); @@ -133,6 +128,7 @@ int main(int argc, char *argv[]) tm->tm_sec); TIFFSetField(tiff_file, TIFFTAG_DATETIME, buf); + TIFFSetField(tiff_file, TIFFTAG_ROWSPERSTRIP, image_length); TIFFSetField(tiff_file, TIFFTAG_IMAGELENGTH, image_length); TIFFSetField(tiff_file, TIFFTAG_PAGENUMBER, 0, 1); TIFFSetField(tiff_file, TIFFTAG_CLEANFAXDATA, CLEANFAXDATA_CLEAN); diff --git a/libs/spandsp/test-data/itu/fax/generate_sized_pages.c b/libs/spandsp/test-data/itu/fax/generate_sized_pages.c index 983e5e49b9..dcede55457 100644 --- a/libs/spandsp/test-data/itu/fax/generate_sized_pages.c +++ b/libs/spandsp/test-data/itu/fax/generate_sized_pages.c @@ -2,7 +2,7 @@ * SpanDSP - a series of DSP components for telephony * * generate_sized_pages.c - Create a series of TIFF files in the various page sizes - * and resolutions. + * and resolutions. * * Written by Steve Underwood * @@ -55,227 +55,539 @@ struct int y_res; int width; int length; + int squashing_factor; } sequence[] = { { - "R8_385_A4.tif", + "bilevel_R8_385_A4.tif", T4_X_RESOLUTION_R8, T4_Y_RESOLUTION_STANDARD, T4_WIDTH_R8_A4, - 1100 + 1100, + 1 }, { - "R8_385_B4.tif", + "bilevel_R8_385_B4.tif", T4_X_RESOLUTION_R8, T4_Y_RESOLUTION_STANDARD, T4_WIDTH_R8_B4, - 1200 + 1200, + 1 }, { - "R8_385_A3.tif", + "bilevel_R8_385_A3.tif", T4_X_RESOLUTION_R8, T4_Y_RESOLUTION_STANDARD, T4_WIDTH_R8_A3, - 1556 + 1556, + 1 }, { - "R8_77_A4.tif", + "bilevel_R8_77_A4.tif", T4_X_RESOLUTION_R8, T4_Y_RESOLUTION_FINE, T4_WIDTH_R8_A4, - 1100*2 + 1100*2, + 1 }, { - "R8_77_B4.tif", + "bilevel_R8_77_B4.tif", T4_X_RESOLUTION_R8, T4_Y_RESOLUTION_FINE, T4_WIDTH_R8_B4, - 1200*2 + 1200*2, + 1 }, { - "R8_77_A3.tif", + "bilevel_R8_77_A3.tif", T4_X_RESOLUTION_R8, T4_Y_RESOLUTION_FINE, T4_WIDTH_R8_A3, - 1556*2 + 1556*2, + 1 }, { - "R8_154_A4.tif", + "bilevel_R8_154_A4.tif", T4_X_RESOLUTION_R8, T4_Y_RESOLUTION_SUPERFINE, T4_WIDTH_R8_A4, - 1100*4 + 1100*4, + 1 }, { - "R8_154_B4.tif", + "bilevel_R8_154_B4.tif", T4_X_RESOLUTION_R8, T4_Y_RESOLUTION_SUPERFINE, T4_WIDTH_R8_B4, - 1200*4 + 1200*4, + 1 }, { - "R8_154_A3.tif", + "bilevel_R8_154_A3.tif", T4_X_RESOLUTION_R8, T4_Y_RESOLUTION_SUPERFINE, T4_WIDTH_R8_A3, - 1556*4 + 1556*4, + 1 }, { - "R300_300_A4.tif", - T4_X_RESOLUTION_300, - T4_Y_RESOLUTION_300, - T4_WIDTH_300_A4, - 1100*3 - }, - { - "R300_300_B4.tif", - T4_X_RESOLUTION_300, - T4_Y_RESOLUTION_300, - T4_WIDTH_300_B4, - 1200*3 - }, - { - "R300_300_A3.tif", - T4_X_RESOLUTION_300, - T4_Y_RESOLUTION_300, - T4_WIDTH_300_A3, - 1556*3 - }, - { - "R300_600_A4.tif", - T4_X_RESOLUTION_300, - T4_Y_RESOLUTION_600, - T4_WIDTH_300_A4, - 1100*6 - }, - { - "R300_600_B4.tif", - T4_X_RESOLUTION_300, - T4_Y_RESOLUTION_600, - T4_WIDTH_300_B4, - 1200*6 - }, - { - "R300_600_A3.tif", - T4_X_RESOLUTION_300, - T4_Y_RESOLUTION_600, - T4_WIDTH_300_A3, - 1556*6 - }, - { - "R16_154_A4.tif", + "bilevel_R16_154_A4.tif", T4_X_RESOLUTION_R16, T4_Y_RESOLUTION_SUPERFINE, T4_WIDTH_R16_A4, - 1100*4 + 1100*4, + 1 }, { - "R16_154_B4.tif", + "bilevel_R16_154_B4.tif", T4_X_RESOLUTION_R16, T4_Y_RESOLUTION_SUPERFINE, T4_WIDTH_R16_B4, - 1200*4 + 1200*4, + 1 }, { - "R16_154_A3.tif", + "bilevel_R16_154_A3.tif", T4_X_RESOLUTION_R16, T4_Y_RESOLUTION_SUPERFINE, T4_WIDTH_R16_A3, - 1556*4 + 1556*4, + 1 }, { - "R16_800_A4.tif", - T4_X_RESOLUTION_R16, + "bilevel_200_100_A4.tif", + T4_X_RESOLUTION_200, + T4_Y_RESOLUTION_100, + T4_WIDTH_200_A4, + 1100, + 1 + }, + { + "bilevel_200_100_B4.tif", + T4_X_RESOLUTION_200, + T4_Y_RESOLUTION_100, + T4_WIDTH_200_B4, + 1200, + 1 + }, + { + "bilevel_200_100_A3.tif", + T4_X_RESOLUTION_200, + T4_Y_RESOLUTION_100, + T4_WIDTH_200_A3, + 1556, + 1 + }, + { + "bilevel_200_200_A4.tif", + T4_X_RESOLUTION_200, + T4_Y_RESOLUTION_200, + T4_WIDTH_200_A4, + 1100*2, + 1 + }, + { + "bilevel_200_200_B4.tif", + T4_X_RESOLUTION_200, + T4_Y_RESOLUTION_200, + T4_WIDTH_200_B4, + 1200*2, + 1 + }, + { + "bilevel_200_200_A3.tif", + T4_X_RESOLUTION_200, + T4_Y_RESOLUTION_200, + T4_WIDTH_200_A3, + 1556*2, + 1 + }, + { + "bilevel_200_400_A4.tif", + T4_X_RESOLUTION_200, + T4_Y_RESOLUTION_400, + T4_WIDTH_200_A4, + 1100*4, + 1 + }, + { + "bilevel_200_400_B4.tif", + T4_X_RESOLUTION_200, + T4_Y_RESOLUTION_400, + T4_WIDTH_200_B4, + 1200*4, + 1 + }, + { + "bilevel_200_400_A3.tif", + T4_X_RESOLUTION_200, + T4_Y_RESOLUTION_400, + T4_WIDTH_200_A3, + 1556*4, + 1 + }, + { + "bilevel_300_300_A4.tif", + T4_X_RESOLUTION_300, + T4_Y_RESOLUTION_300, + T4_WIDTH_300_A4, + 1100*3, + 1 + }, + { + "bilevel_300_300_B4.tif", + T4_X_RESOLUTION_300, + T4_Y_RESOLUTION_300, + T4_WIDTH_300_B4, + 1200*3, + 1 + }, + { + "bilevel_300_300_A3.tif", + T4_X_RESOLUTION_300, + T4_Y_RESOLUTION_300, + T4_WIDTH_300_A3, + 1556*3, + 1 + }, + { + "bilevel_300_600_A4.tif", + T4_X_RESOLUTION_300, + T4_Y_RESOLUTION_600, + T4_WIDTH_300_A4, + 1100*6, + 1 + }, + { + "bilevel_300_600_B4.tif", + T4_X_RESOLUTION_300, + T4_Y_RESOLUTION_600, + T4_WIDTH_300_B4, + 1200*6, + 1 + }, + { + "bilevel_300_600_A3.tif", + T4_X_RESOLUTION_300, + T4_Y_RESOLUTION_600, + T4_WIDTH_300_A3, + 1556*6, + 1 + }, + { + "bilevel_400_400_A4.tif", + T4_X_RESOLUTION_400, + T4_Y_RESOLUTION_400, + T4_WIDTH_400_A4, + 1100*4, + 1 + }, + { + "bilevel_400_400_B4.tif", + T4_X_RESOLUTION_400, + T4_Y_RESOLUTION_400, + T4_WIDTH_400_B4, + 1200*4, + 1 + }, + { + "bilevel_400_400_A3.tif", + T4_X_RESOLUTION_400, + T4_Y_RESOLUTION_400, + T4_WIDTH_400_A3, + 1556*4, + 1 + }, + { + "bilevel_400_800_A4.tif", + T4_X_RESOLUTION_400, T4_Y_RESOLUTION_800, - T4_WIDTH_R16_A4, - 1100*8 + T4_WIDTH_400_A4, + 1100*8, + 1 }, { - "R16_800_B4.tif", - T4_X_RESOLUTION_R16, + "bilevel_400_800_B4.tif", + T4_X_RESOLUTION_400, T4_Y_RESOLUTION_800, - T4_WIDTH_R16_B4, - 1200*8 + T4_WIDTH_400_B4, + 1200*8, + 1 }, { - "R16_800_A3.tif", - T4_X_RESOLUTION_R16, + "bilevel_400_800_A3.tif", + T4_X_RESOLUTION_400, T4_Y_RESOLUTION_800, - T4_WIDTH_R16_A3, - 1556*8 + T4_WIDTH_400_A3, + 1556*8, + 1 }, { - "R600_600_A4.tif", + "bilevel_600_600_A4.tif", T4_X_RESOLUTION_600, T4_Y_RESOLUTION_600, T4_WIDTH_600_A4, - 1100*6 + 1100*6, + 1 }, { - "R600_600_B4.tif", + "bilevel_600_600_B4.tif", T4_X_RESOLUTION_600, T4_Y_RESOLUTION_600, T4_WIDTH_600_B4, - 1200*6 + 1200*6, + 1 }, { - "R600_600_A3.tif", + "bilevel_600_600_A3.tif", T4_X_RESOLUTION_600, T4_Y_RESOLUTION_600, T4_WIDTH_600_A3, - 1556*6 + 1556*6, + 1 }, { - "R600_1200_A4.tif", + "bilevel_600_1200_A4.tif", T4_X_RESOLUTION_600, T4_Y_RESOLUTION_1200, T4_WIDTH_600_A4, - 1100*12 + 1100*12, + 1 }, { - "R600_1200_B4.tif", + "bilevel_600_1200_B4.tif", T4_X_RESOLUTION_600, T4_Y_RESOLUTION_1200, T4_WIDTH_600_B4, - 1200*12 + 1200*12, + 1 }, { - "R600_1200_A3.tif", + "bilevel_600_1200_A3.tif", T4_X_RESOLUTION_600, T4_Y_RESOLUTION_1200, T4_WIDTH_600_A3, - 1556*12 + 1556*12, + 1 }, { - "R1200_1200_A4.tif", + "bilevel_1200_1200_A4.tif", T4_X_RESOLUTION_1200, T4_Y_RESOLUTION_1200, T4_WIDTH_1200_A4, - 1100*12 + 1100*12, + 1 }, { - "R1200_1200_B4.tif", + "bilevel_1200_1200_B4.tif", T4_X_RESOLUTION_1200, T4_Y_RESOLUTION_1200, T4_WIDTH_1200_B4, - 1200*12 + 1200*12, + 1 }, { - "R1200_1200_A3.tif", + "bilevel_1200_1200_A3.tif", T4_X_RESOLUTION_1200, T4_Y_RESOLUTION_1200, T4_WIDTH_1200_A3, - 1556*12 + 1556*12, + 1 + }, + { + "bilevel_R8_77SQ_A4.tif", + T4_X_RESOLUTION_R8, + T4_Y_RESOLUTION_STANDARD, + T4_WIDTH_R8_A4, + 1100, + 2 + }, + { + "bilevel_R8_77SQ_B4.tif", + T4_X_RESOLUTION_R8, + T4_Y_RESOLUTION_STANDARD, + T4_WIDTH_R8_B4, + 1200, + 2 + }, + { + "bilevel_R8_77SQ_A3.tif", + T4_X_RESOLUTION_R8, + T4_Y_RESOLUTION_STANDARD, + T4_WIDTH_R8_A3, + 1556, + 2 + }, + { + "bilevel_R8_154SQSQ_A4.tif", + T4_X_RESOLUTION_R8, + T4_Y_RESOLUTION_STANDARD, + T4_WIDTH_R8_A4, + 1100, + 4 + }, + { + "bilevel_R8_154SQSQ_B4.tif", + T4_X_RESOLUTION_R8, + T4_Y_RESOLUTION_STANDARD, + T4_WIDTH_R8_B4, + 1200, + 4 + }, + { + "bilevel_R8_154SQSQ_A3.tif", + T4_X_RESOLUTION_R8, + T4_Y_RESOLUTION_STANDARD, + T4_WIDTH_R8_A3, + 1556, + 4 + }, + { + "bilevel_R8_154SQ_A4.tif", + T4_X_RESOLUTION_R8, + T4_Y_RESOLUTION_FINE, + T4_WIDTH_R8_A4, + 1100*2, + 2 + }, + { + "bilevel_R8_154SQ_B4.tif", + T4_X_RESOLUTION_R8, + T4_Y_RESOLUTION_FINE, + T4_WIDTH_R8_B4, + 1200*2, + 2 + }, + { + "bilevel_R8_154SQ_A3.tif", + T4_X_RESOLUTION_R8, + T4_Y_RESOLUTION_FINE, + T4_WIDTH_R8_A3, + 1556*2, + 2 + }, + { + "bilevel_200_200SQ_A4.tif", + T4_X_RESOLUTION_200, + T4_Y_RESOLUTION_100, + T4_WIDTH_200_A4, + 1100, + 2 + }, + { + "bilevel_200_200SQ_B4.tif", + T4_X_RESOLUTION_200, + T4_Y_RESOLUTION_100, + T4_WIDTH_200_B4, + 1200, + 2 + }, + { + "bilevel_200_200SQ_A3.tif", + T4_X_RESOLUTION_200, + T4_Y_RESOLUTION_100, + T4_WIDTH_200_A3, + 1556, + 2 + }, + { + "bilevel_200_400SQSQ_A4.tif", + T4_X_RESOLUTION_200, + T4_Y_RESOLUTION_100, + T4_WIDTH_200_A4, + 1100, + 4 + }, + { + "bilevel_200_400SQSQ_B4.tif", + T4_X_RESOLUTION_200, + T4_Y_RESOLUTION_100, + T4_WIDTH_200_B4, + 1200, + 4 + }, + { + "bilevel_200_400SQSQ_A3.tif", + T4_X_RESOLUTION_200, + T4_Y_RESOLUTION_100, + T4_WIDTH_200_A3, + 1556, + 4 + }, + { + "bilevel_200_400SQ_A4.tif", + T4_X_RESOLUTION_200, + T4_Y_RESOLUTION_200, + T4_WIDTH_200_A4, + 1100*2, + 2 + }, + { + "bilevel_200_400SQ_B4.tif", + T4_X_RESOLUTION_200, + T4_Y_RESOLUTION_200, + T4_WIDTH_200_B4, + 1200*2, + 2 + }, + { + "bilevel_200_400SQ_A3.tif", + T4_X_RESOLUTION_200, + T4_Y_RESOLUTION_200, + T4_WIDTH_200_A3, + 1556*2, + 2 }, { NULL, 0, 0, 0, + 0, 0 }, }; +static void set_pixel(uint8_t buf[], int row, int pixel) +{ + row--; + buf[row*1728/8 + pixel/8] |= (0x80 >> (pixel & 0x07)); +} +/*- End of function --------------------------------------------------------*/ + +static void set_pixel_range(uint8_t buf[], int row, int start, int end) +{ + int i; + + for (i = start; i <= end; i++) + set_pixel(buf, row, i); +} +/*- End of function --------------------------------------------------------*/ + +#if 0 +static void clear_pixel(uint8_t buf[], int row, int pixel) +{ + row--; + buf[row*1728/8 + pixel/8] &= ~(0x80 >> (pixel & 0x07)); +} +/*- End of function --------------------------------------------------------*/ + +static void clear_pixel_range(uint8_t buf[], int row, int start, int end) +{ + int i; + + for (i = start; i <= end; i++) + clear_pixel(buf, row, i); +} +/*- End of function --------------------------------------------------------*/ +#endif + +static void clear_row(uint8_t buf[], int width) +{ + memset(buf, 0, width/8 + 1); +} +/*- End of function --------------------------------------------------------*/ + int main(int argc, char *argv[]) { int row; @@ -287,12 +599,16 @@ int main(int argc, char *argv[]) float x_resolution; float y_resolution; int i; + int j; + int k; int opt; int compression; int photo_metric; int fill_order; + int output_t4_options; - compression = T4_COMPRESSION_ITU_T6; + compression = COMPRESSION_CCITT_T6; + output_t4_options = 0; photo_metric = PHOTOMETRIC_MINISWHITE; fill_order = FILLORDER_LSB2MSB; while ((opt = getopt(argc, argv, "126ir")) != -1) @@ -300,13 +616,16 @@ int main(int argc, char *argv[]) switch (opt) { case '1': - compression = T4_COMPRESSION_ITU_T4_1D; + compression = COMPRESSION_CCITT_T4; + output_t4_options = GROUP3OPT_FILLBITS; break; case '2': - compression = T4_COMPRESSION_ITU_T4_2D; + compression = COMPRESSION_CCITT_T4; + output_t4_options = GROUP3OPT_FILLBITS | GROUP3OPT_2DENCODING; break; case '6': - compression = T4_COMPRESSION_ITU_T6; + compression = COMPRESSION_CCITT_T6; + output_t4_options = 0; break; case 'i': photo_metric = PHOTOMETRIC_MINISBLACK; @@ -328,11 +647,13 @@ int main(int argc, char *argv[]) /* Prepare the directory entry fully before writing the image, or libtiff complains */ TIFFSetField(tiff_file, TIFFTAG_COMPRESSION, compression); + if (output_t4_options) + TIFFSetField(tiff_file, TIFFTAG_T4OPTIONS, output_t4_options); + TIFFSetField(tiff_file, TIFFTAG_FAXMODE, FAXMODE_CLASSF); TIFFSetField(tiff_file, TIFFTAG_IMAGEWIDTH, sequence[i].width); TIFFSetField(tiff_file, TIFFTAG_BITSPERSAMPLE, 1); TIFFSetField(tiff_file, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(tiff_file, TIFFTAG_SAMPLESPERPIXEL, 1); - TIFFSetField(tiff_file, TIFFTAG_ROWSPERSTRIP, -1L); TIFFSetField(tiff_file, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(tiff_file, TIFFTAG_PHOTOMETRIC, photo_metric); TIFFSetField(tiff_file, TIFFTAG_FILLORDER, fill_order); @@ -343,13 +664,13 @@ int main(int argc, char *argv[]) TIFFSetField(tiff_file, TIFFTAG_YRESOLUTION, floorf(y_resolution*2.54f + 0.5f)); TIFFSetField(tiff_file, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); - TIFFSetField(tiff_file, TIFFTAG_SOFTWARE, "spandsp"); if (gethostname(buf, sizeof(buf)) == 0) TIFFSetField(tiff_file, TIFFTAG_HOSTCOMPUTER, buf); - TIFFSetField(tiff_file, TIFFTAG_IMAGEDESCRIPTION, "Blank test image"); + TIFFSetField(tiff_file, TIFFTAG_SOFTWARE, "Spandsp"); + TIFFSetField(tiff_file, TIFFTAG_IMAGEDESCRIPTION, "Diagonally striped test image"); TIFFSetField(tiff_file, TIFFTAG_MAKE, "soft-switch.org"); - TIFFSetField(tiff_file, TIFFTAG_MODEL, "test data"); + TIFFSetField(tiff_file, TIFFTAG_MODEL, "testy"); time(&now); tm = localtime(&now); @@ -363,6 +684,7 @@ int main(int argc, char *argv[]) tm->tm_sec); TIFFSetField(tiff_file, TIFFTAG_DATETIME, buf); + TIFFSetField(tiff_file, TIFFTAG_ROWSPERSTRIP, sequence[i].length); TIFFSetField(tiff_file, TIFFTAG_IMAGELENGTH, sequence[i].length); TIFFSetField(tiff_file, TIFFTAG_PAGENUMBER, 0, 1); TIFFSetField(tiff_file, TIFFTAG_CLEANFAXDATA, CLEANFAXDATA_CLEAN); @@ -370,9 +692,18 @@ int main(int argc, char *argv[]) TIFFCheckpointDirectory(tiff_file); /* Write the image first.... */ + /* Produce a pattern of diagonal bands */ for (row = 0; row < sequence[i].length; row++) { - memset(image_buffer, 0, sequence[i].width/8 + 1); + clear_row(image_buffer, sequence[i].width); + for (j = 0; j < sequence[i].squashing_factor; j++) + { + k = row*sequence[i].squashing_factor + j; + if (((k/sequence[i].width) & 1) == 0) + set_pixel_range(image_buffer, 1, k%sequence[i].width, sequence[i].width - 1); + else + set_pixel_range(image_buffer, 1, 0, k%sequence[i].width); + } if (TIFFWriteScanline(tiff_file, image_buffer, row, 0) < 0) { printf("Write error at row %d.\n", row); diff --git a/libs/spandsp/test-data/itu/fax/generate_striped_pages.c b/libs/spandsp/test-data/itu/fax/generate_striped_pages.c index 63b8e755c7..8ad5098ca4 100644 --- a/libs/spandsp/test-data/itu/fax/generate_striped_pages.c +++ b/libs/spandsp/test-data/itu/fax/generate_striped_pages.c @@ -81,11 +81,14 @@ int main(int argc, char *argv[]) TIFFSetField(tiff_file, TIFFTAG_XRESOLUTION, 204.0f); TIFFSetField(tiff_file, TIFFTAG_YRESOLUTION, 196.0f); TIFFSetField(tiff_file, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); - TIFFSetField(tiff_file, TIFFTAG_SOFTWARE, "Spandsp"); - TIFFSetField(tiff_file, TIFFTAG_HOSTCOMPUTER, "host"); TIFFSetField(tiff_file, TIFFTAG_FAXSUBADDRESS, "1111"); + + if (gethostname(buf, sizeof(buf)) == 0) + TIFFSetField(tiff_file, TIFFTAG_HOSTCOMPUTER, buf); + + TIFFSetField(tiff_file, TIFFTAG_SOFTWARE, "Spandsp"); TIFFSetField(tiff_file, TIFFTAG_IMAGEDESCRIPTION, "Image in stripes"); - TIFFSetField(tiff_file, TIFFTAG_MAKE, "spandsp"); + TIFFSetField(tiff_file, TIFFTAG_MAKE, "soft-switch.org"); TIFFSetField(tiff_file, TIFFTAG_MODEL, "testy"); time(&now); @@ -108,7 +111,7 @@ int main(int argc, char *argv[]) image_size = IMAGE_WIDTH*ROWS_PER_STRIPE/8; memset(image_buffer, 0x18, image_size); - for (i = 0; i < IMAGE_LENGTH/ROWS_PER_STRIPE; i++) + for (i = 0; i*ROWS_PER_STRIPE < IMAGE_LENGTH; i++) { if (IMAGE_LENGTH > (i + 1)*ROWS_PER_STRIPE) image_size = IMAGE_WIDTH*ROWS_PER_STRIPE/8; diff --git a/libs/spandsp/test-data/local/lenna-colour-bilevel.tif b/libs/spandsp/test-data/local/lenna-colour-bilevel.tif new file mode 100644 index 0000000000000000000000000000000000000000..9d79aa868e5a66cc5eed3d360ea28066a3493039 GIT binary patch literal 990730 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

8LDieweB^-1iV8F`5 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 z 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

ZA7zj(x;Y;uW z+|Ux>Lts=~l9jL$aFq8@r}Bm4WL2CQ%**?~f*&LI!?;m3k`Es|)duCFI4jE7giRbP z%@l+CXwB6_;Na(8EUqKk$Jt@pks?F6D@d(wuM?r9**X7_g#rVkm}GW_zD`V~Zb_P^ zatS%lZf-95k{vj2kRSL%^^6UGUAds(!UeG&{Bt_rW14;j(P$))2tdRckLy7{D-u70 z0+?g5QT2Em=_^D&31?ok1B!6{#*N#^-%!YoU=B%^cZ zKsqxuJCZWInu$f9>u8JmC$dO4UbFch`$lXHt|4m_@;O?%5g;rX`yB{9wiM1!pv2!K zuQGu5C^L$NqL-9;XE!@v842@Rbv&EO+sY8gVO@ew^{&9J+TaNe8k$Tvbj*50ha1w)KMgtv0Q%+AEqVX$va0zAWK-^icVNCa+|39nqznrb#`(x9?wLX0z%LXP5U+s{T!VYZC-fv zXo$(Xx9}hF(JfXbei28;TKFP6HfCbDT>Y9M9wf9W!HU@vhFuro2TxK_`2F2`Yz1JmQei3Dq_15#-4Z&9vhLe8-_@WgzV{2Qk0mqT@p!Lq2t;s zF27ep@qyP=Z5OjL7OJML)5Kjj#8$lKf1Jc@jd^N z;R6?(xL|m3|2H!sGY8I`8>SRDtX1 zRql4HM2-}hSRq&&kDDQYnT(O&Wf-9Vp>F>szYrOekb$8e3@7lKFv|6lj!EAqyduLP zE-OGHxr*OIF|&c6#9L>-Ejz(reLn7DAl(etJMl^()4Bqjin8ehACS&6d0{c9;gd7?i0$8)&NVw?I1 z3UO+yfCT^?BfM~Q2cpUVVYVgW`x1?jVa-U*X69v*LLdAF z18XB=mBldU>W+@Aq;AUOGM=5~$aS>c(fFtZkphiibZb#So3XON2osNJu%VBKAulEV z2JApM@W#&5*Fj3*bx7PPVBOo^|0ZE@#PgiWSFRt9pg3TMbg=w>%@wBPVPR~la_5dU zrVZN5&Uuf`gJmUK%g;;%yM0viB{{EnQ=2xu+FhY<}`j zfyhO_GSyH)pIZKU;f#a;-iH99s!C}%*9B;Ir{J^TLrImKjsirUrHB$%y4CJ2N#?TSqoY=d0(<1YWd|Wq$%?wn37}Jr?FP>C3F#TF)=RcF>S-`+ojq z5^8f4L$L)WE(ipXUXf&A18u_5@ma@R6C@k-Sc{4%VtV9P?84Yn!CAyBNY2)gqWnV| z4Ff?$7sN*L4Uxv4AfXvu8A`Z~XNJ}`oq-{~xcJp;WG2~GslKtgrI}j??TSGO_y_oi zJyvB*|aAffj^#=zI0eu6B z3B}l7k=mZ8t|wtOs85RRYP)w5tMxF0ioNJI6<%m*6e3cP32no5Z{#7Qh?D`ItcBR` zANykKICnPF;HX0hxiQKabHnT*bpA&vo$?s{gN%`Ll-zgot>Pu+m^}^;W6lq3RZ?(_tP8Tya4YBS-p%T2{*CQ%7 zBF9VS9kGsFf2~`5Q1J`8)k^dg%vciX04{L2;u#1STK7joxW$NS$S@i1kM}iq747;c zJS9hJP;3K7@z0jt^Fc$gAj!@+V=464k#4dV%L728OUwsQT& zJdRi^O{Pv01UUCR$O%O7RAE{DCgo{1d>+|Qf%{2ZPvD5q)U0Hsnbz4%XXiH@kPv@9 zI^Ml^S$?>A23Z^eb?-xT=8F>WJj9xH(s?K~b3(H)m#^c#wD&sN z;2Kb;>_ku*gvit24l8Vj=;hWaC2V1K6kAr8f-HFEr)Y{kXfYDMdcB&u%YBM1tWW&Q zt`@8X)2oZ<+Gf+5lSl!y-j5&L8-wQ1kD7kcyevg$v*7(n>?>AZnmYL<8`R;^rVzn4 z_7r*cmTfh)wA4pvieo6MoEv@?o2V*OY8rDWO<+(tLRj$)1qQ?Y7+iA!mk-kgFRGvL zP@iIrVzM!bDxc!8R~q@~abkNae@y8tQEXi+EoJOuxPp-Du@(fOikRaSCdN}*s#sl1 z69_VVaI`~C9q1xIg-_QSYs~T6j^ti5N&O89!9iw58nr63*vTPeZ#Ga85oQmS=Wqp` z1o?mP7fR8|vqptm7+6lQ`12u(r($u$Mzpop8h?LDOR)}|F$ z+sSC7khl<{-@A|BzK&ySbJ%oKZUdOcQm80*A_39i2(XY+NDv&uD?6ipCzd_;NZfMV~{(y4?tE8;1``8n{28&rY0aVAewb zFS2WjeOl__E|_#^sfoEJARJmN{*u@C3mZO3La=@EyJbOrjMg&GaSh2CO+5Mtx)D)*q35Q68iO1bleHX9bdqUfiVX zz-bY(*SCh#Ny$PvHh#~QL*xV}4Cz0OUPdFQhHcDUM>*`zDW;O`}G?2`1Q~hC8UBw$V|);TZ<*- zv8Lu}ZNJn`iqf+c5MQ}4%C|qK2{q*IW{SfjigOYer3%IpXZxQak?-r>G9*1I$tW9T z%Qz zVSLo$rOd9RK6}?ilp%~v0I^Js!Qe=lM1o^{-OK0EhMXE-CrYu$Uhq6nL$8wK;3NHf zh@74Ko`dnpfgDJI@p|(=_kWnNBMb#MqqA_~^X0gC27WIjHHMt$<4?Xk3*`ji5Z*ZR z-}!4zoKVmbg0I`qP4e=$Ae32eEN~d01PB|vJz&PG<8AydK_IaRbVw+W5*ToHch}n- zwC|bOU@2ZW`(2S@Lpi)}S;O++q|C|fI`K(YQJ#-V-~_m_*RhxOb&ik!)C=((XVEl) zSJMI|h9`r4{Nt93PCpjJc@^0auKC97I+I8{bmx8cOcc}f{a!C@6_5}(2fBG?6+QXh zp*2%fWl~y%b{MnzHfnZUH@$_40Wd5P(fBP)e|wZC^T6W)Xy9q#XXB8q_z?QRLfALA zw#{DlJV?}B8=s}08J*i+#^N6{3EIduW>LokLn|MGmG{Y`*@^nj=86A-P<^Dbw-WyU z153Iw;;XUhB7oD~8-3(v8ShW-%j!e7i z#KW7KXl@4QbP|kXp%5Bu*8G6;WEfDF&d7icE2m)}-=<_Ltg6{a`zl zm}N4AB*Ghzdq!hQ!#x_Hy@4%G{;3RD%7q$b)sX4OIT3~Hgo3!{S6pdi^`OkzFxX(M z7V{HmAr~W<;8v*nw_!S^Ov5Cqa@3>M8KWoBa0rR0v!~vLaCaT{)cb=hrAgToSxdSg zp>Zf1#i9IV7kVt%!)lT=Xo%@axF52Q&0%KiXStiS1!|p&-i3g~xr?3z9>D_=rXT8Z zf<}=y3=^Fs&Br6-(82(M{ilG^wtB-e*%r{er!5IUyd${HV)BinG>`!xsLN_ z-B3(lXR{Ehn)t(4E42x~6I+AWm5s^>#Wma!+Bx`y^ZFHFA2_o#Al4B)W)4db;e~x$B2vXVgm(B~kNs z`A!p7B}IQgz0(0jOkCPf*CZ~J@)?Jz+Mc{isjYkpic5^ zK`-;GO=E6SflI-3jz%?2)?@}n8jBQ81*biAUO zQlvOECq4sQfGv@@iHpd{5dHfHe;aQMCQ3jhgz&s1JTedh7-LRWckNcQJ};k#a%yN; z^{i7MKIx81GLI>B!yDfa)j2APTUL1g%xcGldX#hzg;yD!a?4_5;4NKKKpk+BZ<5GC zPvgkY441_@7fw2D5@g%LmEdI5aNqs*29!6O-rB$LyOfZ!1NCuH_fs&*lAfe*LNmks z6`(*f0S`tF=s<(EMcu!x6jeuq#Ax>Sdxdb9$8{yoE z>pDO5%pvICoz*xT9Mm|L#%yr30tMsn97sU~28zT$pZqBrz{qy5NurmMWEysBf&A*R z02IT;fntUx(Fop6d#|VDaf8n2sepli0*y*)-*gTjqEaCYa0)>PEi}lte_@lZfAt(* zU^J%cYEGOyK>C+7AB&O7bzH8&W-hDZ3son1_$-Ts7u|>{!xi9kIN% zHTFCm^{W(#;&O2x{xABJMc-(pxikP?Kqrx)5X>=QTEQS#{yS)rSiU+}T+_yF4s2s~ z3!(>3U1^T7FEu>MOQ7Vq{q)a|sqSB(xSQSb#fI0d`Gr~M7bgIN@G(_uVn1_7re7;E zUR;kQmWZcg3q3iMfz@pifQO{kaher_?qd7!rUtqE-_An|q5^6o_u$A^&p~XFhI50& z;L4w8EAbn;lcLsG2Evu#k&wjJHIi`FM`&(-XC>!2FQZ>0C94g z`j0WfyN8}m!0ZO71PW~|7~4NJ|DmZ?>z$Hhf;EJ+V@8OiM_bw03i*T3+6U-SsO)TZ z!sKo4rI7mYLN){c-QXu~+euOeAp$9L(+g+l1kl!wiimeuye)!p&KVf>CIVtAx2bP} zhe@Lo1|0|$V)o*uFE&u}FV=+yy#5ZZ&k#VJa<*-#|KcNpZVWU7kXYM9q`;l;cO*Ac zRTu`rS?5`^2Qd(kGivt;brv9y6>dhwm(muMUAvXz_wfvcK_OTmO*X`6ZQSP`(%Dph zo3>=#+>aI`yngV-h;!JaNq!xL^pgm0VEacu3#0@8#C4{c(@!`mwp32iA!#N}9LXv_(WF}<&55lEBk z0H#h$91Zoc1a#%$W1gP%xf5QA+F(3nX2T#w%3}fv0I5owbW(++J)tx17aD7xX zxn8-eFn6FB5Da!ight{O#o9X5JlK@=X@=u$R~~*lU*IzXX7Fm^3<<6nEE8zweP|rU1~8dn0NQ4Ie4I%ai>jnv5w zMJDF8JO)Y5Ji{!%dH4d!Qt4r7P~9D=t5|N8NP#yD*s-Z=M>@{E^w*x?C+J))-VAme;y>u z?a+(c8)p|tj_WO)tl7c1{s5{O%*)d(tkz%WB|_=#!XVy3X?|Qz9u#q(RM2FJ$rq<+ zK0~9OO(ScIU;Dj#IVEh6(ms3l2c*%i`5#}Hz7;a2$|n2^)tyxdQ`-isZDnr)rL?IH za}YE?-bMNan}O#ch$99nwlbH{$7Iuz|8)GQ7N~Qu#Uo)H$XfF;Ij0kr&@|OSemHkC zzb3ZuTq^h@626~BXWLm0mj?)$dLIR)tGzpZz0!J>u0q4Px7fud2qdL+uWJ9_uLJq@^LM&m=JLQqp zXDoc;Nw=LDQS8}iq!$=v5s9`M+eCjmz9mg#VMSxf8Y(~gp?(#~=>E$eifs4(Q+O(Z zs*cPKX_LdILKtBVFi{bwGE&NWgF**u!Dmd8!X}W`KfOml$#?DQHVCgVNc=u25Bcq* z#b|Cq7UBwkui#O*>BnyJBHGXNZmeBEr#lQJ=BlnW1R!Vg;kJngTYQc+wlH!UZ|^abOQ`=SKBUpq3z) znFay;EXrf>#*J(V*q8GhoNpGP8Lp{5wWpi4i1PQrQzTk!Tw~83ei;l`O#0!wv^?3l z65|eo7IH|iih#Dn;xva8ebc)R@bt*V9wa|7VWi6dN7Rj2quej}SWg-6B`)mF#%9!@ zp-{qV&m5c>)z83tXWx0-UuiGl&VVc{xcEp+@lO^EWTp4vk=h7MDozf`T@r~PDs4#z z(K>-a74u60sOLaFl3g}2fYZQ9kw}qTgib17O{ndNG_wcPD1&>LVd8o5F_QiF$LSYe}M@Ett>-5y7) zH-Esxqq5wY%nz4u=rN53X~Tw?!?=m0r2zm!O@0OIf^R$YRjS7yrRR4ncZ^_4Ip6jn zWxwnUt050mH-}^w>J*BvrH-73Ktk~z&BdW~;Qb&TaLie`HUl(xO`xQfb{=Ya#nji! z<3{#rKRR=qxvhomKMk~DJO+jfd0HZfqAf+MBo2T28T>|-qi4$+k-TD^!%nrB%cBV- znLcJ`4kDb$P;1IM zLPyD&+@#fBH3LAShh>!m(Y9#0NJMk=Xe6F&78?Q6HhhR~+0ob&tHQ3FAn``bXHb=f z|C%<`C4r^wcx5Co?hCOTE;2 z#KE{@o85fvZt_bsEp8x9g_qs+(b}i@X$Dv`-#K+&UY!t!Hmg8^B-9dzF~l6g!dQ<$PGLY){6g2 z|AX>(qI5WC3bC{4OjY6rV*&!N2}`DOl$#{?{r6q1B$!z~ujj8dJId+E(Bb~2h$$gc9AU2&40G!#^@hrc zw6LVG1u+l{IA$)lcK!6ip5-s#O|eaYIQ( z!944VFs7~PWRt>eOnt^ zP+Py8Mw^X)vA}3JR`+3A3kElFN~kY@r~1ps17sJip2mZPYa3d_smeG;QJ1O*KELMw znr`112-|!hYE#fI)CCvjR=PU55y9#CNedk(iM9jQ(4&y_Bap_d zQrk&VWC%*6mE1LaB>UPVD*x)GB0bSFu29SlIuxW{c;8qxK0S(sB=)%fE+q|g*dWpL z4G9R%65GMP++c4kSrTpz{|+&fQr);}sS)PkLPde%=Juc{qyFyFZugabO;u9shYco57O*fb2K^Gcle-7seU$ZNigl z9b+H@>1(2q;A=FQTA5jSG6g%1soR`zU=1^cg*b9)+zA)cjE4*&# zCU#>*GY^s#P_)C2s&KpMh34Bv(qS?vdP-Gt)H@QwU_B_j?A*++Eolp@FwFR0qqr!z zT!3N1(zpy%3pT$|v!(Mu^=9=x!K~W@Y6DcJk>|3S3nJ)yKC_Ra6hzRDn ze5g;P9wOWa(aD%7(hown^e$fYNO=+2CQ?YGOK`##ISXPu#Q0;TVj3QBX4Fc+4f!H| zXwc6{X;LO+vC`)*e8@qUmo9xS+%WDxJK5;pmV7z~x|U=lUH2}e>kUnBb~SeiV8Z3< zlb;Guq5eayN4Vxd3mGUVz=OySWj`$V`~UVg;)Dz%Sz2X2=0x9fwp31^J!KVw z4D~5Q8*50CWyTYn$zO50?oat!%;d)^Nz|4IV-yw=^H?cf-`hE23%wO7P_J$qjbqsO zfjTEY3Uk*P)BZ?>kq;nnM4xFaMNfAa3UYB$QbdCF*jp@Tu<`Ug?;xPU>une^BctRM zD~c`wtqUJT9$N0-x`$fAM8HC)Stm-mt=V)}M0H%GTv)@-GqlqXi-yvKyk4^NkskrIz`s~6 z!r}CV>#iku*;*YP)>#>OIR&E?e5Y_Pg_uKPXFVq_XSS&351SB&}3i*>dP2 zqbW^etY%6&)zm8G})17D^%PJ>^2K!mO`bNxWIVh?a+}E~Amw z_pfC_k=y{`eQHqPl>|$pvITlNedIc!HkSzl6R?uU~S=t!nCWDKKTtN&aZJrl=A><)B=Fx;`Xu)$? z{L9>iG`>8T1AEsv*PDdND^%>71fxtlqum;b6u|n%BOsJHl}#wd6WMzm8POs4SISsI zB0>YO(E_@7r!6W2Z`cH&ivAA4XogBZnk|Awv^uoxgp<0<$(L>xcwC~VpX0&<%NjSW zb=$PG4Sj3wB4=8rTqkIS@Bs`7$fZLb5ku@Q^=3bVYlYfb{LsangQqyao{R2{MLqw{ zy9Z2gr;BG-{6{|C2Igi?6=kK`GW*bAl6Vwb<{`Rk?mrdPMG-c2al1Z^l7e>nUcKv zMZ+Z0uY}Vn?t^U%3f)w$xie>{V4#A{)p$)bOH8KKI53|aHQX^J=$t2ibDEoBZC^X) zI;2?^_Qm3CkN%olAAn~g$eX@8&^gSp168e`)(#OLvIqE-+DePj*YvNw11nY6EBMW@ zOu4y#OXA(gWIrCEGZ#f`1Zgi7Bxu=pzw&|Y(y`lLzKPT^Zv+o zBmYY|dcW-rc0~VZci~_F9s|fU%(u-jgQ5QYN6;#cL=egRi;qq{w)N%mzfa=hnC`?G z@&D<(L@?W_=iYU3@6LZh|2b;CopYd5=Tq#ghu_~Gv_UxP45rLb5c+2hk|0xDyKF}u zDrMe#_8NQ&XTwz&-kGh(_5c`MaCAVvpH_e7WoBL_P>g@ww!Xq1!B>F}Ifd-#UKZ3| zK+l!Wm#!MKkeh3aGXckB<=Btkvv1}DKINKH8tJx6NtZ4U6YC(f^N8G*{}PymAIJOB z<>Wsy4#G7D>fy~IubFjWwt-{P181^J5-R>u@oRte%NPGG#7xv8s=OfE&EK%{?A#mE zXuN<9Nd25tz{6o0ny#bHmg5)(N+s9N*X3ur?QuR zbtHuudH<9GH4gvjU(t{if~HzkjPxp@GAs?`4+Mi{o1|7?xU^~N4IE-kmf9+D{&M77 z?r2{H)2SnAR2SVY%yb(=@^&mPQ_Z;)z#TrmxbgU}am6$nrd_C6xYU_t>lT8uj3qEa zqgp0A*&wRU8gzv_+!B39UNa5mIZ)n&Aq7?m%Y4Dsc$*lDcA>4KB)RJ?v?Zp3Nt<6u z7u(N#H|4{V6#7D}N*aK`>sBzjnq7ce;IkiEmyM3s{UD&ZYsVjQ)0`1z3pJ@Q{^R}v zXsk+NvAFM+!@bt?iT-BBSzQH>o)NyQGbW zV=#i7t$SbDPvF1sGumr$3Tkf(=BB5QP|71c-ev>3-L3o%nO4#j5WpM#BLPaMMar|d zw-Y)7Ir<)e7&X+*{ayA*Oq_=34-Lf3_5kH3HDYNxzWwd_}tRI`5QaBWu?IXj*R9zyoYsT{km3T`W+LOqRSts36!YfEp{l zzKY+qEt9bUFJTpMvWi`Bne%$y3`!t{*J9ZPaFBQ-cEd)6u8GGB^3S%{rq#9tY>QMF z7s4gHUFkHZ2>|fGFwSreH=cbDbYe&rxVK^th_#}=PvPnudQC5ff>dCDn|2&L}ES1Zt^-a^5$#F{->7*uSWB63K_&MoG?Q1 zXaI5K@PZrGG8JzS17n`t5*+;*Oh?Z%hO7eJxiv>wuC<)zT{GSGlDkT!OPRa8&ClzC zgE^qhZy9ZX$NNYx@xzAiIo&{z1M$)@^*}TPUWYULn8e83s7gYyf2gt za0mhewacD|!08$rc%xyyKhFieIANa1T5FZwZj%=g}q(m8={=G0?k zsQ^f&jteliBtha(NDvhtJ>&Wl{s^9@aM+YZ`IPIu4FSx?KC_RIAkujpKZ!IyHkGy~ zRF=+!JlfK&oQ6lt%aLY2Fb)Rh5prGIo|c&^t;Ji*fAk6YIp7|J*eGM3g|bTYNgivc zcXoDVqM?8p31{3wwIuM9K3l}3+K4~-t4UxdT~9!=>=1Ft3>+oU<1G|T2@kEuDjb4s zK=O>LtSMlN8sN8v=h0xV_)DzBm*^C%{c)!gLPY>^0ZmwJX7D#2C_FE=zV(!8Y$HJ_ z7+8;7%>lb>VrwmsB*BcWfxRWL`mmdE&nf)Y!@xn%rGe^Fcnlp@JZaH9VmG*Aav>CP zuGjPpCA!!dNQrnHX#`=JZk=V5z!MCV4fdc8()*RrE5+7#m|xYRzAQ%5@~uBgO7)zt!DC5p{Oy^-6DQL zF$y%;);jU%+z7pRVl6~2O}XPZ7kODv2?wZYACSd35ZdF2^vWO7KH`vDN*FvI91P>i z|DpkZ)zV!&ny#jrAPI8{i_<*#4M9ts-dT(WghM(!-}^y2*uXLT^)BiTeirS64fMB} zhVmRZ5n9?$f^-lE$0tBmoo*@~UB2fLCI!kjadEvln3g{utBl4&snZ_s#me7|i~*MT zD}|4Kl=U2`8HtGn5G5E>BE)DlpmS)tMm=H(H#g6NRxN^^$~F{XsoTY>&)pcWEb=TxYTLx z4dZ_q-*j$bawTBm_?|yLe{vbKxnJFW^8Gv9pv85kja*ymTkA}pcvpc00GMO6^zV$$ zG13$CCd~3}g+zhB%fJgA2!r8ZfrLFnZ^D65*RiB$m?_?hT&PnT4P6z8G~I;g^fU_B z6Zx5QIn?m;E7#COFPu`+_9EJ^-nAIKRntPRhpIJ`+lu#}TELlr;v_ZU z09htf(R&c-7F9k52NzRLqgeZk=3lT;BpO{=)>Xdk=GkFZgJ&uHKHGut$;t&v+%!4L zV|t@ZpR)6Ey6U!bC%r#kmThH*B1=H zWd`S793e3x`$6vK-D`%B@BD;9dR`-k#l)+>TP+d*SJZihty_D_xNVu2o)#K@1 z&{!$!7DPzGN*OHjrMF+*3|ZtaId#!TMy;hqyOk=+ua|hmt4(6&cw5}&Jl7MX*f+^S zT8kx9Rte=Y_NV_JV{ZeT<$2zFwvLQn48kv%*cPZDfmD!9<`w@5Wu9sb`{r#@{d0q)`&z?0hNUz?H=eeKzxvu~9zy8;CoiU-*e~$(y4<&;# z59Gp>CLA3_4d_ThpfB*Sb{eRH;nD8skyad)LWCl39jeAsn6}nH>6ng!>tQiv6f7R? z+%8ZFeJ)OkMy#ZO+^m|Ot;RYKR*;!olhE5FGC$NWh8%gre5OjSIGlRk}Q)8IoQ7kq0;||-V znr+6w;8XPbnQ@tAXeMr#L--U8&WjjwV;2_>`wz8amvtItkpq|@P8rDw;J_1`nvRu+ zMCQTP7yDc>YsNWD>q0?k29Ear&?fr__x}|kT1#=*N6t(?`=79iB%a$Sp)B@UuB2U& z1@ed!I@(c!F&-LrhU0^3@hL>vTeUnPlp(7I9~06K^BhsFlFlD8J6xgDZ>hsTUuv0W z4R{7xc&piJ)<7~@q#5x#X_tmRcZ@R=1sI%z1R_~SJp4|_W%>*OW;v7~To5r#Fk@5_i~x#KxbnBq##>)b>Rc#;T%7(3Y{wCfT`on85`^yxHj}(x#>b*`q+DX1;xcW`UWG#(R*&W43 z1;13O7N}{9DyL9_r#G_QOaUf@OUPl`ijt*5t`2$CXeNm=Fx|qFq6I%$PJN=w&m130Q3Ne?gJBjK7zU)` zZ{Q45Q)wnmwleR5jdf$|IXfIfOPLcR^%FaEB^67kO+@ZPW*V!87)}(^u0nDLWkm*(s)Es!g+gST%5l~m6U1PV zh7E-pXd1*OlhYZk{-BnK=iKLjem}JTzX>5ghv^@v!D5%P88(};4fltgYSfUsPpVaR zT$iMpK2oJRhi1dS@7>5Tu&0Ls0ZXY81SonUSj`X~yJoKC_6Nui^@=c2ZiBU229o-rtajXJBPCUbk{k ztFQpsF;*oyWCN!Ng2*Z<7LS*l{B3M0P`dS@Tdy30?T+-4IZn`xGGEpfYU==Z(Kwpl z^QCTiIO$wpp$E;hwSfaNml{+?c<=N5-`>_Vzw-4%t&!_^lAP08kPVLV$#-@^5zIxm z`lFsA42A5%uaK?M=VcAf5|5hN$=Jn?x9vF(XY%BaddlwljSKkVrpFe{u_cWS*?6_` znTmUs)Av^lA&5vBj|`HKyBY*lP!IkhJ!YDDV^kx21f)p+BVvoto#=<9Wuz+f=vjJ3 zLc&MVdu5!&tkg{oWa4~p$32M=iJVowG8yUsDky^X(-H~^_Jd<0=afG+s(Nx=bvh?s z9efC9BRB*=3elKUHMJ20#|fVO#f3lI^W0hHQ2qDsvkdX_bnrqYCP_qF!2Bab9iCW# zl39=@2$cAs5=;urk{xUQU_wcpW&YIkZ7G-J$z{LF7BO2zkf-3rUO9?@qp!@HpZ%lB z-4Ng_){vL0`+8v#O6%w@2`9HxN>+Y0m$ z!B9oPq@BWH9u89#iwOxjN8hzc8OtVI`R;jTE$6CxDy>`MnH6-AKwsC0Q$+enAHA4a zw~5Mc=p57Bz6GRjm@^HF{(I}hw3q>32H&pP>SP>CYLgaZe8pHK(=l#urY1IH$B;?3 zNG4Nq$-UV@+9f#m4&M%(qXz)F#BDB~;ZeV$+0`P#n@?W(gs4~w6}jaL_3Q1xa~$hH z%rZAUSA}D{&cK)RK9~yL8{!13!T=x62U|%u_2{7!&;}D6G>x@27K@1#58nHF{dM1P z{$>EsUy!DF0^EVEG#!ttCbWX^g~ivdav;}Vfep6i*Dh8#;I5}ENYl9(UmKRu8b%|< zk<_(MTX{K5DKGnn&KE}C{_iCmo8RzZHK`(nys^dX_Cg>{ zY;A!HFNtRE&2?|PhuVkQ*bQENs23E4ZA|8J8H2S$XMvuAxEy2**@b?9BLWsPAKDJ= z!nrg9AWBh?&C-LKEER*2(E+ms{HXo&-~8B9*sa(T&*% zde@NRcmg}r448LcrZSNmTx6} zY;paHNH4a521w+&p#WCw7P`j~c}YA!cxkA12h>w`IXhN3Gl2+>cApeMrQzBHBdz;s zVaP5AA;h=_mLvKb6dSiV9xbNXXGG}^Zo12_VG1Dgc;B2*<-6&BoOTy{0#YU|{VrJA z2_!WI`xzn4CKlsn4x8x9C>bHe_0qI}wCO+2M@mn6An6*0upYt_ zxWlQ@2x1fD6emdd$mYhBd})#je`;JQ=dAup(|YG?9j3;t#M|UvJR~z`lHUw(S5m3y z%hXf^8?x`Yl{Wf4boLh{fu0Pv-85OZjFiq!iiLYaw}LE~GA7EkDK(0aJOgQFd;StM$j&!IG{5SZ5xL~vKB0jC z13Z*bK^`ZN%{)$k3!lvKh;MxB5GAF8rV@(u%tU#jhgjj@#$u!%BU52o$OQ6AtvbKq9%x$0X{QL z>C%+eI|G28WL*9LmmclRN(f{~GkJQ>IzZe+ZFbAbn38T+K<7EpP)l*>*9oxX*P}fI zo*hEfRx(bw4Nab|C{%TcFWx|C6|K}m>L~z$04BZxVq~o#xZU`2duxIzF|Fn;EIeUs zFyy3+Oy3LdQ5IWx`-;V}-~1C<)2{Wz5(6sWX>C_7}aOes` z(BxG+!70<21i8TaELle$KU@?i&=c=rwS}V|VZgEQrw9o%2ZHSpD&?5V1BpbLpzPI; z^tnb`H8@J#NByg#6e>keS3H`!j2D~1Xw+x-Rm~Hvm_9%%jWq(B`bCAPS*8Fp^wi2) zPT=M+z<{)<|HbFR(qSu25Cm64txdmW#2&H&aSEOhiC7A&lf}o%(cq%q0#Hcb%^!s& zp%uM7fY~?wpogm~279sT1#sFIe@XZL`*=@_6`#DD^hn}O|u|NdMhz<2xI`>Mftw>l<x&O-m!#tyepYFNZcqFTrKl+>I8EAwT5DZ9CkZnO1_62MG#Hw9S&}ou0XJ!gd#S20u^qfrOhXX zV!W4cSH>N;#X|shJJ^eUi{EF8E@uOoM_+Ny>FZZWm!h5tG$Wkp=;Z`&s=;foJLIO% zO5HYl8;Z4{eW_F2Ta$yC*)BYDb-2rTG?(1YJjF!B+O?Ih(;eowf;x$IYE(ptIElb=0;W)>F1kCNF_$aPQV4KxX)MIzu=99B$OseDM<(M z8OUOEpJ)H=A-1-%g#6^By22b+C_oGYao}ry=QS#69 zg#mh`Z?c@6tH9y~qDz1#%dNQ(B-1;183RB8IZQwz z#~t#Bl#_o~St>M59BEif>b9V7>}CZx<(CWacq?68v+#a9h;)!m@bZy{8j49ySYm?6dR`h~x7as67pLg39;Lh;A{!z_##CBD zJbGZBaFbm?upNS2|Czh6HfqzN)SiYsppYoR0Mf8QRv?nvh{+AHlYOUOLjbjvUUw^p z6+~>}Gr=SV%d5^KmBGdEnT5U@R!g)js9}SFrUO%e@F_xpb#l3z23)QSnRlg)u?wOE@g)SGzEDJ@phLFZe+hF5rbm7&ryC zk$$P=f9s(9TOgyjh8aT0w71x9vUwcu2K*A=aBK~IjFeoo#fC8fQTjkQ8zJEsKbQo0 zo+RyO6iNOymy9;~rxgQllr-V7- zp1H1iZ#(P>TCI5W76P7*egq=oUV=AJP~Nxe+`gg7{fhy+u)w?osB8|VEfjbVy_6|L zYA-dL*vu49D#ex9z%j5JxBrAg+7$UcmK#=5!9J@DK8o5T?hW&uWLgN9Y7CedZbCk0 z$2IB;%M(fHX4*PELOzhiPhZZ!ou270K5tk;4NKCIk>%d)vClLid@FqvAq7@Oy&Q8t z4Jwf!IWk;ryB&ZzFAaI1;K;^m%&nuqI99yX-Bq(zyXM5i>3bSf)>` zNlYDkLnAS9dHQKKJ~}xtFqqhHoDsz)W>1}h2FBQcaZf!8XMMt$u-Lfd8AzFg(1)+F zcphR~+f@U~2hhf?XM6mYTIuOV6U52toif59LiYZBOBt$NId%Tw1-*}eMZ`SYNc(i- zdC8ufIfMvg@G4JzV9hd6&c@2u#UW>r0kR3OrOON*|RqfxR z4{UF-7Ue8dbYPWDW9TV4*e%?D@%B-cI2Y7Y^R;hT^J2w^#P<5B^hVF0F^i7Fg)oB0 z#$LgxUgVrfYhx&|`sHCnoEVTPZislD1XpwGHM@U97pMPxcKQMaAzhfJh}ECNTk&>u z@=3o=&Emy3@Y2IIk&uDsE)Y%q5K|5MYt#wptFkzf%s7R}G`Xdy467z1jk1OyG=xS5 ze3(hD2j(qPF^AG7JEHJaTO)e%qd8`1?8|mUn+}k5(jxcJH1ka6^nOA+60noV=F~tqA4WZeSR%=tS!CNf*V}cB zS;-`z*f5;y3L3%S1)~Yg`pGsr6Hy~|hlOv7q<@J)j>tY`uc-1;W5R_5UAUV9Eg?(d zeRyK$_Gxla;2kS!9oKV=kp?DbXyn&`PJ8&+Yph_EU2%9azJXrWe=BM5cTJ?8z>mNJ z4%lu1f=*II;dnU*4> z>GIu?J;;y8VrStEj_-ScmvHeAB^|T)4NeP5y4PfceZ+NCJ7Ledi{rn!T5^PzETKKq zgMYX3d1{{IukHev$@Sr5+ssUvaw9|Xn)=vkL3Oqi#t_ zFf&gv_aZ*Cs?~u?A8nlg>#%Pisz|*N(1*Gj@5IcetrCSWRxj0_J7Vt{`_6F34}-tx z?gS9-EFhq0**pLD8I+Py5t08y43ZXrCi=wnP$4ofSc%Lc1Q{H3aI1nm;6WMP3Bj*Ry0wP=C8XQD!%%Ut> z(!!A&4{8RN)FKim%<)DMrg)ziYmg(1W>B913Ah5HOk+%Qcz$8$(l?*_JH0`?j|PTq zGcgbyt}aD0qsyl=?f0?cCsMH*yA!DKc-4XP=A&2;LMRy~*9jo`WK8r3RiC;v*X|Rx zfUHoFKGU2wjkSZ;J85@6b_$zUoFls@0~LHevsFk?(T4`eD>52>mvGKQWy64-lR@Hl z7SGxb8SyaPSLxBsDM0g?`PSG&c=7pPq)Kjv(#ieqOt%_H3IEJ!aribMK=1|z_>%`2 zr1$`i@SOxR7|}#?+p^`WD*vN$V8$!qGSA+z{2s<^L$UOkw4p{x#^$+47EmFzE+ja) z+ogp|-Lkiuc-~!sS5&Xe00Mds)45MgiYOs@ZdE8#lZ3E44Iy&yMMnh$ z^#Mo#Acdco{UC*v!-I?rnFVq}f-{qE5gCX&T$mD8ne|xdm*$eP=arTxePsRyDY2D3 zDaHikrQ+L!E?&H0)U)HSbWbqJ1SR`vwLpeN>tf(Pc)U;l`!C726{LXW!sPK zEPZGk&&L@)@gVp%aa=i4Ib&8UJsuxiI)ijFvsNW7Gz&2sETzrji`EJ#W3eTB{G51! zGal$w<0PjoCpOkGew<9z=zR`znntjJG~XR93y`=UJv~i1fa0l*ul`Kn5{9O{ny@R$ z1257`^Y?Zux-$u-)xkhHD~G$SLM=`j4!rQ~bE}ropB2Qf7QL4Yu!oVZZAPv$P zqIer)z;#~wK1kwQ)2LMUcM_+S?Ww`&e|H<{Eq=1VoQc&#x_vY{+)31(TpD6r&+^bG zsLa44^mrs{4*?ehdIWoX9%YU6A;CBeeP{dOq3;@fZJ|K(N)g(t zZr@~(a{F|fSt7{iXS^5^291MdB-7FI&ES{cfv$+DXH1%DkEo4l9_oijhDKRZV!Ax0%JwjQ)Z`W@VfPh05Bpeh* zy|flp*Wd%jja7p~0w=gph^T3-hi7OmGKVs<5E$3m%5pptrL`+fX#!9K+2G(9aL5BI z$O+(eq%kgRx=K!=z}2ql*@phb@{7$YzZ<)t4WsJEAM36;AMF^Gy0a}!dsV@}uzX!} z$p_Inh2o7-#6V-z_J1#c5uqsplzDT?rdtL7zPIM?eUJY& zh(|JmOw~n3H-f~Z)p7~u4m>&(UXV9&T>6R(C&TB!>x588P0RFgnyPu|1iE@hE2_(5 zK7o%?f{uUT#RI3vnmztoee^Vdu!_zGUDicqdxd|vy#hi22AJXFs0e0<6&=3Sx)gTb7&GJ?gfSb^&hEqdTbh5f5gvH(kqvS5*m>%U&4R-|7QaqARPj$iW zh~b2~N{L_r8NUf1IA;3SR)Li0f2HYSRpa)&{j_HqUyO{y*+;Sl*q&Cl(I81eIQYFl zI1WZnhJ-uz-urDHBu+6EdX_Vmcgb2s%wK0sKFu43XkHUjHfaAuXk!Vb**-Q6Qh8H#V&{r@ih~Z6a@G5f}F)K~?j( z0-vAspR+}|JJ;k@n^p&4v8ja~O&p^4kX?7EJcMGi3FG>fH@85!(ytC@S7ZWhTyF(vGtc3*%&JBIcn@C;&>98k(6KNc1X45ti z7rU)=hk^>6$VQUkUYPx&seE-T|XU?QDX;Bl-*<2NB z4-ev=t$?We;X;E5~aFNrIXjS(&+v;yyZIysWP6Vkqx{~OV(nT&GWP8Ki~Ie|4;wvjz7tm z9fD9HkAXxCAMuuBzuu^`_Ar45)guO4p{(0a7|N}(9c=}#dM4>i3q1^W2J1*R(?<@v zLhe6&7hPy|;Qj%C6b$>ruI%4mN0@ugXqtNnhoy6`ncBaUsGW!nLIf8@WNtQHt78~j zP1PfXOB&v}y^#Sy_3SNK+d5J-iPfbyBQ&ISn{;&~SFDpUn7d@c0>8Z<6Nr0bkinzt zhv%a$L~_g72RI2WCaPUaBIrJWrAcd(wWPq0$;rPLQl^^gun9pUuny3>Z%6p$kRV4Ei<7QC0LK{dnl8*eQ{_NXZDm@_)2BfLkI2 zqDsr%OY2)2*N=TN@ne-vCvj_0q16dyoBtoai+2P@;hoF?@ef%qog?s@=kNF#9 zEsO?-4^!jYNg5)iOc%zO1SRVM{ehiNfQAI9EACQ2UDU!KrEmX*zs1d_9mOaCcjYd55uOZf1io*EL z<|&#@fpbzSk0;?xA7$19fK6=~Y!9hG7Orgg+8ukoG+A84Ao^&`$3X=j!2S={P6Id@ zB^OXsD6wm0UBDMO2c~DRf2xETFnfvW@iGoF@=5@~HH_xD;uWr0g<*^ZQb7Qoh{N;7wm|4iH#9+*fz#B6_eWw6vU_S98jNPP{uw327G=fsdNU*Q_5? zCdXVlbB2TaqZ)j;n>&^1qA_Nbb?FD_VYaGZm4I48n^5B!3ubRBpOU~g%pf=bU_BHx++BOVa z$BjT|a%_w6UG@^=iL`6s!eqI|!871r#d9{RyrpgMl)WBk=GoEl+3W%WBy(7NG+SO} z;lxtgfT~kh&2Bc!r>7ghm{>qO{mO%feTPW*!RZ61gHV@w!$>eOCFQMhy5e?N6Ty0v z>Ezxx{Cx%k`j?U?!6Q;A^%l?sQs)6iVCxmT8H6C$@J$=i-1Qk+(tO<1ixfFEsk>(l z&XVDbJkjuf>dYo*dQ%gwO9dWH6%gLgR@fdkj){CCd1ekVp^*R}IDL{=0F<3S!omN5 zk6Z8=o_vpBAnLG@8v}LFL5qU?OC&}Am1w#XCl<&mA&G!Hff3?2>ATwrof7}?FD%il zSAr693WQgbl1r{H?OsHO88Qm@9}RkM1Ct;Z|I45TK@2oW&ui%d7g-f^Kn9Pf$QW}oL@|zbUv2WhmPSmX|D zv?C)8U;0~{05_3>;Kdke2KGu4B}>V*GoiutJ9j5lVbMa6t&zi<;Pa~_sv4Pd8fKpl zN4SHBu~FmEve+Tw9cpk1)luE}E|DK)r-4UXipJd$jRVG7x)33kSKBdd9ji!^pc&?m zMHH6E1~@w2L{xM|YFLlZD~(wbj`6{{!9V28oe+#XC(VT=ng%B}+=iyDVU&9t@-3`AFzbqDtLHvQ&f+%(*dIA)QgBO5t+ z7mvNqO~<^&%Qlea@&XW8cL#^UtKBRqO8Hz|S?aJu5tIHX&($Vs5rvL*QdEt_$SZsv z%H_-aP>U>SX!L~pifwS54s9n+R2P^T&q20%ZU5p-np|el$x%kCIRrRD2QrW~ZS4&=IwILg18S2~I&CgwihP=joy8UK0$h4x z6=@XMxA|~Av2Vma=)*ui=b}z1RM?@!NmTCXYWhjBQ!j##JLa@MeQ_+m$Jfvda|q(_ z#`50z|4zifhcXczo+xebh}p_ozE#O?6KnSw-;qV7ii-&(5NDi?GMc&_I}UBdP5^Zn zj1iTN4kp2X#Tt~QvF`_z$&zgOaNG6-yX7JeN4ElQe3+gzS@7 zKjPV8zXrajnZD5VqrR1A7d~$n<%JdCLWcLTJS^u>AVO|7;9O(gvrny2^ni4^NLFD7 zCn&H4+=n7PMM*r?fuJaW52mlflZuK$dSr13bjS(#3@?1?iXAw@?nPsTcEK)H41gPX zXtLqkxq)fRc&2&y(_M%&SC+YBo0;U^E%T`05``}oLQ^@V1C0EW{dRThL5qNf_Pzgp zQ&Vb)^9U-Q|8W;y6M-?9rEWE{V#t+;dG0QhJmFx^SK~Ij%W%pjoX`|ktfJnrvcrB^o`@3ImiE&W4{l#fT9cG=sl=q0Y6PU2F z{I`@!vZa*N)0>%G+;jVu(j=(TVdizq9RImSwv3}!!!vl5QROicGo4QcMrIvZ4#FgH z5)8`WirJ9?kxz zstTM#!E12+!DiD_^Ihc#X(}aN;Y6q|nyGWhC%Z7STibI?*{I1ZSdCYXO`~rSZ_H`m z`nwc{8pxfbi8x`KhKhGem@Be{X$Bs-3Ow?T}&`wF$yNRLB59d*(H5HP%!(3nbi zh5zrfHy1;aNVXVdaba#PMH9mN7obz3k)D^#&>L4|%*CuIpGgRIdEo1c7>Sw*-GL|( zk&On1-3n#Qpr|0Ptm%ZBPTFUdXn4Fg=Z=-(;MzG?0@0FJx-Pzgq~g>_8~hkeQ6Q8c zOoS#nT`qRv4*QlkOX^+Ai%GbFCrCepLy~)|g7;Ad9Hf;|w_0+dP7?--3e;i&Whq+O zeRc0R)Wp83cN$1tV9KdBV(-PX7I(@(eE^m^u0n~dI>x<6CGo|oF5B2shlV^wg)V6UXb3!( z!+iujFVvIAT%TsivosifuYdlv13G`^(TDWub9^gUT%yx`+{Ye*O~Mly5t?j|3<=sug6e;eg4gDOqhj+Zh3PY>6t(QIn!{oz(m`t(L+plGkDNcaSGT5oK{(uKy=H>Vyx+*4j9kJ&`H2P1Or3;Q!3wVJ*W< zL#3Pe#a5%}k}YPyW$V`9TkCqZu?Z=na;}00mf^8u?A8&~$sA@z8Z&fbdn<`~fSZkT z%+Pwu&}22S(PHxljGMCu1v$1GH4eq3J#smX6pcq;EzCEu{ImD{!m^wh$vKB;&x7;^CWv>9Oi%wKJDEISQtXih zZvc*XOXgLPI)k`*;`E2ia|qcEZ_H;p3?e!9%ztM;`ffp6q~pJx#wne7a{VQEbUPj_ zEs)qM$1f$gV+A#J(*m=28GOeVN&02alWKyuO5iJj2S#s=Hcd`;Gdbe?!piUMt{h?2 zCJ%Csl3rpQ0UPZTqX;cwjl?3&td*Cv#K6q@PWY0r%q(P3E>rYQQR6tO@Yqc_${s5uim@n!z_F!du3{>_^-DO^;=3#9UeJ> zj}?_Q?eGq|YTCLuKkD1-(R8v@iJ!_$6TT}BoFp5Pqni41Ju_U!y9kkJIZCq)T4Nx0rWArQRrC~X zgk2GI4I7!3(bFXJ#n%-Wu}f+hBjuVSe z9%PT70=Bv@<0CopNJ(5)xkbrbhx{MAtG@o<`wOOlpRoPke0-U=4zv>r9LnP;2d?dE z^dEb-eTnPca;a)BV0rIG>SqX?+$cxVq=ncrG*E*06%c@JIET2_TrjW-QBda)Y%a@3 zz*EIw_f&rv+F(FlZvq!3M>h zWMBlXYsyBonfI>OrDI}El7^(}2AWLsJHjG)R|sJ&ibY8_x=78qf+8^>uss2H;sXnq zsmDud7{mq$Tso%R;99a^UQu=jWDK_{+o6_8uUC9~zry%r-^U{?HxT#MbO4I<9OO|T z1ms4iX%x-nR3)`(Eo#snBeE<6rBvAQA?Kc8`;X8<+3w;{Ztv!IP~=UuSrVDp|w7F;-c=-a!0 z1lS^n^6*ZJzOpn7_=b-YNH_?a1I$xOe4jXpfOrXFe2NbVP!yEL%nAT5a&$5SXA(y6 z)t~w$vm(jbB;j)Sd)`QNQ(EH^wuz4x^8q9fPWPOzhR1pQ{iz4mfk+Aq-e~TA08RF{ z6NzM+C=F51Ge+5w&!C!wh2juX8Zl>R1ST9s2IxM_dfO!Q=kF3sDyf(qvmlX^y-Z>) zXP)x&r@Ts;Q9UPn@v{t*N^13gxSKYAR99uWDmQGRauSv7-c2{+#KgcC&7rpHv{bJc zNfC%Qq7os+f(G&BlcU%WgKkaLLB~;IZ8v7kb2fzoCwf-O7jc@;EGIuZisYuHjh4Mf;9r0V&KWi1GulUBb0umi05!LGkMc`nnTWRq z)MEONsT8cq1F}!1%ni7rT%2MEV}v_1M;H_7FKLT#V*KN}GnY zPeU^Y4?xj!)L%v4o{piacGKR?F?bgcgr$c@;u4W+NlxR+O%e$@McX-Hfrky#6)LDsk87gkkJ+8kdGZT` zk>42bcbBRzvCU-ZFy$l7j^c;~W&eXwSV`jA4knWwG1;qH0c7*6)wS7;B+?;a2x#xN|WU|l&+1-s^eZg`SQsd935K(n$L}aQ-6&X3c@e8LfM|X?|2<|PbTdY zS|gLAPk~t!RR`#y^S48#pbz-fHC7WJPF)NF5lR(Xy#WCNG+?pOV;Qk}@o4lkwtDgl z*cbF(?3e7zz{z@}nMVR>AoxObM*IWZ@ejKHX=Ef_+#)bfOb*ewZXW+el4%$IPMER^`sL6gWK6>E zTI#ow^T3y!*Pf*_qP(l z;Q_IjmDqqO{u5eAP)LLD&IvH&t~yW~&j@KzJZt7R*&%VJ`FH<+z9Dh5Wk!wjH``7W z^DZ;4YJ9$&N}OmqYf^3RH%+}T^}q$!t)Oc9{Dsk`smI?x_}n8q--(0or$`>4whPz+ zj+;SfB^Z*!n{>Vj{bVN|M;%BeK^f7hBo^zD9{`6F4|t;S34Vk$PJ%&xYzCvadnRTwD47@fB*BZQ%e=2P{IyJj-0dyS(uv-aih{Fs)qYrk|eSzf(opS zTnnyyoaPu1_=YfVA=Uy3493HlNoO~Tk`XV8 z$9MOesLBM$A^sVv{=c7<9?=pLzEelOJW8D#zb7G_bS-v4wS|2nA(!*wvd({euJ6;-*VqcjF6;|bfLgq%Qbb|(l$FyzKD+{mB?5KQT}uhu4TlRw!| zb;LKbgkwW=_kvP_nEDf+-z_6>}OMwI3`*jIo@)um{|-#L_*lb25W7!xRy74vUq zkx)|$lvZ?zTWuwqo^;EU8t8O!6ZoGa?+L?}NR37H+dj&Rrgi;qF%G>^{OraW(s z)UXpBlMG~zx@*IEKqlf*I;`Pf4j}%vWZL<$L=p%n&a+&=FJ+`)F92Fp*!55o7Nf7hLEKb`y;*^z1%`QYPhZbO zQ`EVWef65(Bn{2t0Gqtk$u(@<3ic)|wv}Q#PLpaW3aBCr*Ls;9%&mEfjdYoQ&aqVr zop;|wV30&*TedSBi(9X%_^;%EV=4TbqM_u?J4o@eSIwZ zw&wgFcVki1<)lX=umU_M3&_NEf&$r#%QO>m@%f^#V!eojg%n{Guzr?HHP&nY`;0TgS4A&M!u`}I#{r%I$k z@C$e@{8sKKv){>s-~``lI=^rmUXIyQ_mWFWX_G@t!UVd|`-a?5&lD4^ZCMPf!bBzi zqG=8|h>pW+sH_rSTzHsfI%oQq-aq*M!KJI#QbdJU%@nLz+9)v{@&1RFGT{n`OEbYY zE|9}{u=}@Y@jI8fSC3PLl~l#FM9z7M1Z%`JVh9ShGF&hV(FA>?pU(U`-+l_a^ zC@9FQS#R{IMVf&NUxiGi202z(h`o$p;n9o5dt zIpCYc>ri6<^)G;g@-FddB9K@^E=YzsS@r-rfl0D+N!LakJP76@ z(lXkpr|U_RC+C4b!H*!Ad6<9-KN7N9V90G~qXNTinV zTF(B{bVeU_iy!R&*B}4?~AJw@W^D^0&c9NM<1mK$AEtv=f$rM^IGb{Py3it7y|%1(TUA7JC}wW-X{x#W@v2E?*ZoTSL4lL*tm9`O*QkD8Zi z$#QHR22Y(imTrMksB!&WR}Z4HH-kI4b%a%X}%a zb=FB#*dr(EytcIW(Z1(kGn5OB`7R!sh1wp2i6gF`+L+{O1wAv(0!dVm@nwuXJPW%8 zT`3!e2L4b;P!cGRj+cYrUK0*OjvV3eTIZlFZrxw^HrcDdJi&o%2X#3r{7%46h6Lkw z#?w0_oNYx{O0Ek=<4e1v*2d`zH6$w`a{0AXA$W5*%)>yGL9#hWtuj-=9fz553xHX( zh=|5Hca6S5!VyEnhNMfnQy$88Kw&w$mjQV%@QRQJpD~~y;n$Ah9jW}*>Gudve$GZ6 zb#{9*(&1}csiOEX;y3P3vX~Gx$me_$J28TJ0(22mg{*J`GbbQB$4Q{qwZ}jz$iXWV z-T??my4kQH&~}h_QmuqfTLUSOB=n9Aa6$Lc;9`wcvW?Q!!6wjbNCVXzps3oL7NYjq zuCBQg1E(GYlS7PHa;H{ajvOc%RyeTO7dSrdGt4txQn8L$9il6UQEt$awS~VGSF?;S zZL*-7NYf4z94uW5Nx)*lpo!2Ii*Q9`?M$N;62*g@n&`(a6o6o1n~V-LAGZ(mHN}Sw zo&O0U59uRFjs0aB0L{{G++G!)@iI88Kr^3i))G#PXrBDjzI&HZlH{O-l!yX^Fiwg} zrVFQg%9gKVhSXFyjdAw9|3EM$lzqeC*vAg<`WFA*E2+|b{%myr3mwiqt15YvkI?VZ zxvvB{!g=aGr>4$3)6-E`2y4H2;JKw2P%Vp%9$Qcb*E4z0o`m7M(Jcp=fkXBoF+&gy z96aw0&`I7q{iwT7@FjlrDFibc=z!;Px1Xa6k2S%jaPW!tNQ_3*PQ?s^Nl=Zr=E&!7 zP-K*lK!74KL!52`2%;r&XZy}Jk}w16(c-uliP8n5Z>TJ*;8IQccxaRrfd({gsygTmntvuK0+N%ZNmV7B!@oo5%4%9rqoumhpd01ASFB& ztVP+MQ!dm4XX6ZkvazbdrY)f44V0L(QsnN?dPdX4y^o_BSRs43dDyCLPw~ORO&*+I zeN>(BXmf4hcPPnfrY!9uiK}(^O>+(*>Gp%wfDD_h1pa!7+GtMQx_>Dmak!BB9owI> zUJ5c39%d|XN{Y%uu}!6I^aaKhxGmU0Bq>b~rWVHWAdd$h>JRu$0e%fa2iEUqxjlN8 z5GbIaV1c=mc2(piQBBWHa`&nqs7MODHE{0~2g>|d9jW{lqT|%&0I$aS22EBZv330$ z4L$8wPt(6Uh1DNrIXMsTB@{0_zxa53WPx!JT>_ts zP5lH)n@Bj>t;wxQ#RL#q2t)RK5n15`#(7hFw3jhvJ>$dPw2cva0R#X{*ugMg)?SL0 zOTwxvd9qIfT0YT0ls|Fz<m%g96c9iro1nbAGP-23{JQYGh<2WdG!4|LS8cHE5TG zGDadfwJtT!Dy89q2V?;)%=9DqaBbFJcJxbJ8m+(oUkOPTdw@Ar8WFl3`(!L2eFIJ% zJ3`X(Rb+ei`r$v7kru=c-+o-m$Jup_sDD9{*d`2NRDWvgJWUMJIs3i~|B z3>4!iDu%UJo7sa3i_ho$`7sAkqLvb}NlZ*eD0$)ueB~E1uuovT0CfrQ#4#sAC!rP= zFM~p*h03WLF_9mZW%oP=POksW&r%pRx-i5<6o>unK~|u8+le3k)OgC<<&$YfGbTr_ z;*>|&xcq||P2IQBjRSt+zQ!%E?)Lq20+M9}+P2xfM2T1h3+!Y~%I(+#LJ*Qi0cBgf zM$dyvK%(K4*DVR!MO0(z?Q@8T=v(L#m2q`y+75fs8+u6N_oJZ_6v0)P#9F-bYVqPZ zXoHJN%uf;wVpxmR3ID}uTduKR2VQ`#xY!Mi7vXEykES{+7pe;d8QCP#V1Ed$hE|u^ zz0mVR@k>9pm5wwM~C`TA1MQT!|QpB$!M-w?wrS>#y!s={=zh@_K(REul z=xXxpQ{?jO4Nbd2Ru2B4YN*qCBu7qlxox0pNCa{{l(%eY=vj!C=+8esw{n>&pSg51 zK}#GwSAubgRtkD5oP0xNjQ-&CZ#iY5J*s0`?^B-x{un(n5>YlE9U5YXLIgmkKI+Od zU2K`I511&RQ+tmiw;@2gml#k5%=tQyW@z*kaLwaYm-wD{>7Yuzb;MpYZ!ca@9b;6J z#|?cArQmyu2guwp@uStDtl=#EaK7kN5J|lFG?0~xH{t!qlB@eoEkpxVv))7{)*5gc zGQiNV1UHIoi2Luo|HA`k4}5v8x4dycq_DZolYmWeH5#s=>P9w$_tb{rbE$bnO{*n$ z=Z-v%f#5xji9kd$IyUo0qe~wLFDGYDp9WK55;xl~zF;gwbfp3g(3@(Jl>LVpjH{4( zbdlKva#eu7`HOZ1SQ!R4AX;)+xnXHWL4eZ1ZMlX-wORidjC+&(rYItnE0w2hB`M;v z1<5mGp0c&%fTUq*;$V`twP{O19o4A$s#t4G!vM7eduss1ZEcuD4;nLQqRo;H&13qb z2+@jCjQ|_&EFnl+Yk1VSgO}mlB40>!_%rVq{%kVNd1ljE=r9)%f74 zv+l;9k{;Vf7Zoopcjw)|U=9!mUPpg=7PxZn&fS%Bo*?EgTfY3RJC@VncxtM+77X-f zZ}h*o3op&{z)cUo#pH*~cQXnCEsaCRZHIga#sqdkcbiJ3_>9;4U$kG&cPIb(!=AEz zdxTtNzB!Y$4>6Z=K`#fgbNAXGCEP_O2hb$GDX}&po?wM^&mw>vu;i$NXJ`Jul;}yw zfS29ImE^<^Pmd=g*FWnG@$*01_(3S3#Q~r1`}{9uaQx$kM+LiRA}eNkZXO+;$=?+Q z-|uD-s#GcMyLxcx@(UmDVx+}N*C8Ez05}WQ0=botR(^b?6O3o`>m0It>cq1=)&C}s zlLN~DghAwFFY-5>Hd#nNKR70svTW6q+Suaft3S!aTGh@HZCQQ)&o&jldeJU8dBXfu zZj?mx-0+FeiMz%=|Ix!M?vJde0(7{wPy_SJ3B61r0oM;ivb&6ye1uCv7Frz;LSc#c z`79nPGa#lb9rv zwdr~k2R#I+q2-n~1Wkzlh{$M%gQa_oe#JzH9Pz}w-X$iekQQmeSU8^dDvXYyvXwfu zep8__N(!FvbQdE>P7AZz7{D+XsVgu9tW_Eg?HT`T)nFir$c?D21ta#dW_Gzoq>5qxx$SaD#8FJm?l84w zsSIpi3~^1&el*en50A31uii0Q19Arto~EJ<7{0l~S>i=%ut$%R!v%v02&|@M)(L<6 zebom@Z743;qCp>VniviIPOv<%Agogwqiwy8m+NHpn*gC8{#t;-XK02Gz0vyuz?H6U zxDoC>J`z;9A5LL~F6#L+Z0YAygFlm)+=*NjkfSr%z|q7A-XfbLZ-nlA;K9OJG)89I z#vb+}ErlntIPhIAoCKhkrXd>nR0Oz3F~k;SyPHC>2>`p5XL=+rBNmdSASue}TN#Kj zl;mdBjIMY{jtZ<(0N%EtG)8N@=W!b;`O$oZad{LCeDeN27~P*GMBOc|!Dqq>)1Q#c zCovRx)M#dWVd27rFTjgbmGL?JxSqNudgOsrFHxi^6@+Y?!)0RPrq}nz(wlmDfRV{^b`jx$B@Rq}2nG-vw(t@I z^qyzsHF}-_BObUSbXq4L7TX81YriL1jd%$)9uS#YMK=ijehp93s!V8Pc3fL?gHB33 zb_1=8tpOvI7x#7Gk8BA8N@Kmi(JU{lU}a5eQ7V4=gi>^lS}VYPEp_V66bvaDHYZQS z4Q5_8yVEe3mMyaG@`Zycov_zR;#NdvoTJ3J(yE%x!pnB;3kj+pJ~2Ov2Ush zeR193Rf?eRMy-rUI1v(bI_BN+uT6A1?l~Bx>XlQ4RQ8lU-p7`Kle&vMRjG3;6v!iQ zfeTO@!y%zR?tji%pkM~N2RhmFV07_`%5>pEKnJN9A&i+L9DSTXN+qRMcr*AQhY~(X ze3KAR#(1Qx5HN{%Pl%|5IR0zjluD{*k!XCI9hexyH%Df)aChYcO+Wa|o)?=6Fg#@G z2H&q+@W-5aeq=&NAXEw11(=(`XC-78&}Q~g`WeA}rBln;oM6FRiyV&4pfeWB)0(w# z*^^6KV>bxs;y?Y-Ba8hwptZY@&uvORW3DC_EIpnVGA zlJdRqATi6Zcm5v6Y!Z#rpsNLPA7Vu#W7ywf^R@%KR6bDoiNjK4kxxyuG-$Xd;th+2 zAdNL5Mo)*opTazYVNBP7tJn{Mzt-WJC<2YfI$#wH#ay1j!G>>k`W&Xdzjdg&_P=XW z>~iK(Qe{HilGU;T+2}=ysmKaD;8E(_sOXaKfv^aB67tGR7@6y~u$OPg>ey`t8O>QOOh191sDNMEQHecr^fAA7f^(9>h!$EBkgoV5Sy=*`Qw83JF zcA_(_tqY?@bsQ@m)v z0h%`KE-bX)2}4RF(}kmVCs_|3UCab2%m7*N#~did*Em(3avzJTp!7mJ$8{5ExHZ5JDios7l3U%ly{VPB-hwih0!?X{AIB1#e0sbwtQqVFy+jrDF#oiz|V)@z-Zf`UuzuS~QylV7?ifP`s_4 z#N9&j4FPbN6UuhxaZ%g%58p{4pCH26Nj%4uP15A`Q`Q&s$1D#ZagcUK38B%E)3wnt zebImLLuV;;u$wQA)!ci8o$WqCj?;N@?2By2v^)7-xaezN4wBE&<$|}uhqQV~mHI3< zJEylugNMZQw6#GV+Dj>@$H*Ku2D~Dd&YLTOyO?I<9Xp}i&pXkLfi2M})B1+y22+yutQV!@9uB0~UA=d)uSkkuswOV*fyBOZ$$n7f- z*vz9#gcL`^uZ{f(90x|a5z+(Awxg3qa-0en*sZMLhN#L!#8BhTscEjt$B!rcl6Al_ zZVzP+gv2Zt9BCIaRPV^dRM1%X4O`8KN=|nl%>JE1jk8Zrc-QM^5A7wpRJVHfI~F`u zHO)t$1AO5T-6sy*nkvO0Ysu9-@G-C?!%*Oqltsy4jjliFnRsJfpne(IE6Nnw{yC=V z59yZ2e~5y**REx%)npy>vm}o)(gc(vI!WwA#&<|~q)#ldJ{c}aFDgNZ66=xs_xvz< zeSnk7(aNf*s=CZ|vjtfz`o~U?Wsow9)h&=?&k&qkg67(BJuMQpl= zM7vk)A;~kTqBe){>NROxXc-EM)5veY=@{yTw3z^o>Vz>ks;#iEm>RQI3EjMl|0W(L zfgb&9Nu47ku7%e9h`JMNt@$EUp%F5pgGsK%BXa-ooAi7C76jE=m~D?hyN;l-tL7gtu#*h7yN`p?KTMROBc&W5)lOi^E{T+TgFy zIYvcr;4jBxk1LVL=yR0xkUt!mS@0kyfji%95asJ1gIspBV3W5-$6DFEDyrM%E%gFW+$kFT=cND24dm8~j zDRF&5(uLKa-?Pptej6Dmim(Ch?DjF zdxSJ@TV(2p-N_!c64xJl5gpVqv#R*S$g}DP+iYBGYAiss4d;?Lb0wW~A@_;(>o${k zv)uq)4ENRqkho%6s(wes81Xl{76%iOhTv;Hvs!UvF~f@V6hn#FRW#Ql3U)4-GOHu> zTMJr@GNuovr+@cT8>Z$EBe|?`6E;C&S@@OZYVKZ#WRzIG#05 zdv5!7(^Ag{?yy0Xm{DF5PBc)cUa~e5$Lm7BvKt1hKfwmeoAC?kc zMRr0DpCCO5M}*r(XYMwPAf`nn%-dS2igj&Z2sXGpVElnL<_0}f>~v@Z@dkae*aQl5 z1L?_!Fhhh7msaKQdH$fv!I=n%Mux#1R z#L`%8j__;DKu~tJ2_&SD zrSz197z7OIKifM8SJQts8W>wSwXhPdX2I*5DjB;qRp*Fz#K)!g;9%fuV%S3d$vKwE zfLFGH`BIkP%q(b=Fy3v)o!B;Ei?Aj@YdVuz$ImbCR|w@H`z;rV%VRU+tbOxSee=Hh z6upW*znI@2`RV*@q;yv0X&N1e0K1-Cm)=s#V~_))@fP;}?%h9cc!WMzc8=HbOSV`e zgcDiySPw%3_u~Z!8UQaK3!E4HsPQH}hlwVz47RJ$_&^2?@hZH=$LB`R?Nu&pLA5u0 z+3*8Y7C~lGj&OuLH1{(s0HHJHnhAd(rN+KG@>V^1HtiUCI~ysRnFx$PXOl#OGm;OB zkF^O4#qAyd#||$zE__<39yNQ?M#G)kyWaGEy)yiXd34)Yyc?C*n{D$3mTBimC@{b; z*y7yd;j!cf#UKYvh-HHLqcXF+yq9`yvX-IK;wDpSk`thD#ZbRfy<2Y6dlF< zao14F$6%dvxJ5O_|H}JKAUYM*5OCH+VM<%uR~A&$Q<>_R0fyKV>Ra(yQ2kVRvOe*Z zqC9wtu(A&Oq(?t&s|8M^Onm4-cK$gj=@fO?2dyeIdDM zNt2b|iA`s_(E5ZvI%zB^YxlJ7{<3{jq9lzmp;vlec$yY0cz~N7i*_m}EvjY*LL~_^ zgD*IKY-yC)(K}`@q)5deOit1OA%7WMNerHpIT%`|8l^H~pcA{z3rBs>h!sR%?o%y`jYe$G=dTOd;IPxedjl#F`fSX<=}Vne1geqWFwrcN$X;Poe%p%FVONy z+AsA5tU+P1(62%t7^ZfV2T}CyNuu2C0AMCelG5ZgNhp6R=DBH2I9cu*)#B>PpN}l9 z4JbBGu-W&+oPcdil~;!r27!`y0}h)@D%ySiJYvY&5+A)$j}-xvY##WzH4V(Zv+0e6Xl2}Za!Sh7&k$i? zC)lPUNw#ThaZ5k7X55*idu+5s=XbJrQ8|ts;OcX`D~S>};rzMYAyayHTq$_*q=`a} zi1!p%fa`FB7bvL`1i=+IoMcUX*eoZwl+6JW1^O9_ybLBh#MRg6(XA3IGO&_>vtm%2 z7VQ_LX)rLD5#kj0xGEe>-euFG8|}T=xx*Vet3Z@nJc-VRw#&^gTroRqcBQ*rT9wi4^by)MlJXW#S4& zBCx*ABj%6Y&M>I{STmSVNX2sMnI@Spj?Z<%wX&C1iliR4jm^HLcl`z$9LFc^o40DW z-TRiVvGwl8AY`Jbd)}&dnkpF*S@QQ(8KvNNybW%TB94x$PN8b~?#UkPf2d}S7%37``&Bwhk^5w0ZighNSi zAQD7Db!2Zeo6^W}fgc`ZPx$>DONkG%4~J#q(8L1K#F=%xTDP;Z_v|m`QiryD`I;v{ zVeVC4i%OKMn7}AKr+~DfjMxS)o^c`Jwsi;DKdcuzsc@ zs1DcUQRYCSSF3XZDB-lI>5Pw44U(A~T6S91S`W*ibD0rHR4$H zOPHcJt4Nmf6nL6}cN?6Ed#Z-n<+UeYdV5SlIC{uj8lHa$+k}>xqnD8ZYbevuD=ndf zevy4K+HAHLT0;Rin`b`b}dqdY- zj1Wz-_?KDBM_ZAhy-01z;60+IVku!f!W_*yhTW#Yg}$xZ6UR>%eHxsAX*LQl(eL7S zuHNUrKoAPPLl>be^q5x$^RL9$5Swo=EbKXqL|us2ztTQG2+xW1bSS9TYZ<|bH*2`@ z9zxQ7rXF!ZBut)$vcSby5_g1{e|DLvPiaSa5c#jgFb3EVnW= z+5;9RSuh6F6r}uxQ|m*?gL)z6JX@Mw9$j|eWTKPeVa9PY=9CzB=mEB{pbrTIc#iFT z_YtJ|AYiCGyeiUY%fZ+{-c&4CL5IhnN`RZ}6gv_ZQ+4gQy;b}voR0XUoRgsa3p*Ly z1r`%aDY2o_?hgWNfr9LC{Sj$2%fgGD+esU8n6)@Pv8 z0BoWLs%>wLmZ%)`50FHNY84vJoaXbh@8jsBa~k0|b1A zp&(Tk&(yZstP241I@V~Y-^+4Z*<7@1vgTT|$W>rrO?44n3h4lX94>WVz}&N4{PW`; zVxj2V9Mnu?UMtvV=Yu7!Sa2(>9pD$tMn?N-QHuj_xCHQ zLBhAICWA{tBs>Qe_`&vJEMe~E_{qtXlh!ZL}b}c zQYpW{w=Pw+pZOMr-_g1c%?9!Q-^&M}yIFbx0?3@$n#Yz6_PoG!rbkc{ zw{}l`^FqJf01?zsOHG{>KHf3qa4X;d0TYfIP?C^N0z0_l+<#}Vfwavm{NhXb&m0?Y zXf5Xz{7&{_ki}YIgeMwE1K9F&d7vYL3UI;4%!LSO1zp5j`CtZdCaryHT2Qv&b+ULI z85uZoO~`_#CO6u5x#=;xICH2b-grxoKF1lKhA~;POazuej#=O4KquZPJA%MHaYll# zjA{u47q6GZ;XjX-qsrgYJz%q*e_-wZO#+%f+jt+BK8TsWdE#gHub$n} z%t>UCyKO>>O) z;q)2W>CaTn){s%37#@|RVgcL8d^BJR=f=<=jf~KS!RqA1abnTwPbc0M?MOIK8?9V% z79Z(~RGR)C>lTHk0mb-`a1z8$&?8S{B@<<2wF6QPR1`saBM=dNZk>2oGA$>FrOB;EwkDKoR?ORTrZqhK@H#h}<5}dbSFS!gBFxG4k(Zr!&DB(WI~y5DSxm zk;Y;bI-T82dWHr7N))A-_ginp*~b+@)D7}fF8wx?Q*uyI0LNLkG2zLH33VSHxQCi1 z1--a>ctQ3|eJG;j&?Lv}j0M4Ri}dLm*rW!7oBtM(sfE4kt(Y?z;BSf6t(dakY;obH ztV5pu$8Cg;NT<3fLUTRfiUaiZn{a$)PN<9_Ya? zw-Bv_BDF+gp-Z4g_ZF$l5u(-axVv~t4Uu*uqLoANUC|>3a3EX6Oz4-6S6@Vuf`g_# zb0+bjIzIJ4A}omD0C#GZ_DSM|fHWkcxHFldy$;yJ@Pgyh^+o4K04Aq}>X0C?LIReF z*ItfzTV5oHB6$FK0}d(bdZmu+7{GoWC(&x3WT4JvMMNh_GwhL zAr0oDwRp5s>Xe8iC_H=IJRZy)hAE*7e4(=NkYR-;2VyF{6w-vdNnYaO(09Pf!X6D# zV`B>?f5D9YUDKAoO!ZNn|L#rRo1R!GX4@A5PE4bx#+pN1#np1Zson2Nei?{m=pc#W zurVB`kRePRef3sx7buJdESbApNOy~7G;6qdGB0jau1gd*#*`?oK|mUy0@tFR$Yle@ zY2ZQoL_c^57%ECn-52PmPUM961-w=L=Fn()#gb}vplzU8c@nFvI-NSG0K+O{L6yX? z6%O1(P8Cc{6$Q5?29Zp147F@Qh~p_(UTCE&XM})v1Vc8b-5PfI=NlBS#~>+CZ%ve| zGdz>9H~J7Bdxh>c)VQ4@j~EpwTwX3M=NGnTYYfPW0TnzPw}SCUtc^zkCJgqCKskn$ z(JFx*lcf`)<;|xOOc_5Q07z9-iPFI>zeD?)IyeJ#!~N0B4^km;0#5%t69g2~{O9-k z_I+j#b>llNW|}_2-4gCLAYq9`U6oPU^p#&RKRb_y=|nB>;=)#QR?T;xfD@(3a# zSe49!=PU*Xy~_ic`y@qN93(G7YjOx8YN^9J0XV#EADHKn$Cf!K6cG=V>i4W;RnCfH z64GHT7l;j9cZdwqWT>EHG&;#7m?w_;JpGv$-@o89Pv%mhAe?eljH}}Zn+jqb5+W%b zH>hnE2+NTfU?`=b(h1G*IWkxI@6vnu@_6G+L7d*g3UwC9i~QAjU;U}yebtro0Q$RM zZ5aj5{2sMn%NX}!v__8;LOH?%cAr1ths`>SkmIR+I5kZh6I)p&FpTVT&A*@h-(x{N%uw-#PcM*9uGwl0-*A`6A_^JR!sPn} zAMM9FDthR=N_b?f25XJEhz$0XUPNw$(qwr-EtC~;+p`GVlnlY6Yn^#COcV^x;o>?- zoQSAB&M=+y2*oeWw_e?+06EBgSqx0m8bknN&8I#j7wQ{U zoLJsVKI|HnR3^*nc9?}4VGjVD0b+mpvEv7?jgWFO8%hxt2MF#S>2-ksqv#MwqTHf-!*KJWE$BM>=7Uq=nUYuJ775WoK(PSQUB9rc~C zHHHpzpJatu9Pt{`AbZO>l}uFWea0CIkL5j3uyDDUQ_sbYF8WH`-}6dB<&X>_@6-`V z8MP1e95^}32m%I^!OO9;jvucF zUdU~elzFhiolO-#_VUF>vh9rboOf>A!UBqcp=fj+zk!~Z+CUptL(?Dlkhg1uic*eGa372Ji_cQ*n#c^_n7TnP6q%Z=WLwchlt zB*o>h5sGXpGG`8tJ|Wx3YLR_5S>yNcF<=H0O95v(wsHh$dy-Dttknh>P&s4)fvq;k zv)U`QDmbV+`Ioy2zT?2Wpn>7E%;5$yPXPU5aS#NGY9Ah@tl8+!27Z`qm?bvE(7}+0 zu}juZg+->-kh>+Vn3W4GE0+E2+tM&}LkDt?WG;iI5{So?<-Pn7usJ7)MQjwKM*}f{ zYp})xb_2xd5aAJhp~4bd#{yu+gvhXe7w6 zU>2^4xIUcV|Eq;@?p@IW3j$Wc+yt<|rP8bh_n0G%slI)!-33&=Oo|+3qEgkb=ws~k zs3139q|@=CZ!^t-Ii0i!Bnc(^V&W#i2_Bx7g3e*!s78lA-xpq3e&+01KGsJimChg9 zhhn)fc=i3JGO|0&uPVF)Ab~0Yg;7Pt9EkjQ4fZ76Tm+Euv9%MRB5e&>0wfC zYs@gZ6mSy1r^Nv!6;31EO>+k6SJ#i>q&Yn6 zwh(WyMtMuUly*|i5u`yd=8?NsA0UG*2}Pj#R4a)MYyu&*;nMv_s{j6TlL#UG@xUxk zf)_rF3)2BTLjrC1MJM-?k;2rNzIr2~MP5J(9>ch9;LGSZix~|(LKJ70#F_h5K@m%< zh>e+u`L2fu!vTL8(HHv0Xj!X*s1gT=QTuYxxE^zC_h1Dw-`oqz(5;&?GQp56GnaXk zZYfA5Aab5oy~!ubzwdeO$IN>) zCuPeRmU7A8HWHT;3Ut>omW&!pUd}v-he?sj0lJ03-t1KFO=K~4b2xX&1D83e^(ZB5C-aq};h3Hf<6&|(pDPkq9PQ58xU<2AJK0KrY(C6}-KmN_CYpey0fls;DTONHEj%@^mJ0Dh-rp8S$F~W%@E#&5VN5!a z1PaV7Wqv)SX%Z00Ak5pH&V|^Tjtg+GCvsobWKkhzP7MwxrduU=R9u4uY!VWaHK`+& zcH-pB_ZxCdw>Vw_sYHWAAcXm|x>eM#lVlrbkVQaE=c@}jSfnDFiIZ{-CQpTL)Aw;L zVtsjaf+U<#hF*f!5yr)PUH5EJ5zL8YpOW5?Urg_kO6Lwv{R8c6?tEqDq7Cz1m#0dZ zn@O3sASdA(Mw`5@vB7X9IYsQjXmX3t>o_-gzzUFoX(_1-d`5kNK43&w!8y#ES8gbi zvJJ>c2+C8X;Y?f(_bomNKZMy)OJhDJm=$`-MZO{@n6tBrvy5DFU=xTy#V2p{BPt;tj zPdaIy7@0Pd#@dz7BW#*ieh`(R)h!_x=HH#~khfAcKnr-juh zXvAF!50uU3&6|RL?8yhXTEi%*l347RbVcagj-pi$%2NDPmtQs{exs`D&J|kk<*05D z4db(jZ#j~3fC4@ZXR7WJUTG)CWT)xx9Yt`Kq%Ummw$wOplS!b_P0;NMukK&*)Mj_A z5ielp)gk$jPpEle)$yJ~JppNxC}RU#+LHZz*JysFBaucqNs@*Pee6bY+Dmo5qw`^9LL8Bzw**6j$h|&jyR~4jjNTamNBpu*xwRw%K0{3A{Td$lLVx}J=#tpF^ z*G^_GS~Rg`0X#rrPmKVqiQ@#30Y7MVaTMX<&Pb<9#USe8_|= zYe2|9Je)fAw9;am$EC)39zOz*=8`cdDX%1&V=EizxU_yflUW3G>>UcgGd0|P zG+IR-&}Xp#G-tktQk5G?`Nu=~2<#jw2N= zG>lgRakin#VO|5Y46k|Ni-v}vOP&UHC{y9r?nWg%Yq=DKxtaO$Ep+SK`kYeYV_*5P z$I-I^83;h&S)s>VX&X6~-F+|c_CTZyU;ngocQfOzj#n-3{Ix%!&zY;hg+Iz%gf5xl zSFn*i6y86jcRb<%G|Bh-tqH2or1VYg`>1;{WnLWXj1WO1P@yw(cKm&Pl>tOVZZ{$k ze?i2tEg=q$owD_f_8)9OJhX4$&D*2@V3f-*W7axYaQe;kX@0uuZ(OU$CW%p8{UV_S zP~?w`9V`=11R9&fK-U2uuR-xVic%y`Yx2E(mjFHSs(8!zut?wqK)n8g)OtVh23U8` zLs1p=t=~}F-7)?xs@OXIEV!GXpWTzOeM4B`?f4~7=MHiMrL+-Q7P*qHa5G_C5aj|6 zNEq7*{g#?&oH(6K_YU4`r4@b%A1Rp-qz=+zf~{sv zokRd|$4HO=rZNAHDT$nReLGfeNCV;xIqfPgI&wJ}AbU7toWdCKJV^(M>|_U}2AFA( zY`k{6z+SxL>bBO#$?u3^was5yg=@pZLp|ZBHZVvCcq4BC+5>+5Mm0~O196K zDw@f0dq?L)Nd)*ED_@|cqMHev_{=-yaB?F$i!#d1Bgj&)r-7kEnh`O*2CYLk%dZe; zV2R4;*B0Q$)~~0;AqGS%u&6k9j)p}MTivgt?kDu-I_;VooozJeG%FdPr!hff^ejnV za!ur|%v=nzX09UQWlk=cxax}z%aLXZ5f?7u*o(9Pg5^^~k?RH;ph?Y|>4j5{CL0>n zX^?XyAVGoPUkvV8h$m_eOiL&y3YG!|;)KXukgBkM^+CNr7RaF|rK>Br$m zI3VB$%_3_88FvCnDdJDy9U=K+GEEX@Qn8 z4&^wm&PE!uh3gYl0sGmvW2S6cC%jE4j$RuS>>TdP;29a%P)(l%%hX7`be9W<<%l!E z8c9Wl%6SF3jNlQpS21V=6lwmEa=h@S?7v8%V`^Z*`b}38`9LYMV4+YSxF3ZZe*6Fw z<|TgF%i%B={v&(qPu%g6*5aS?Go7{^1X^L~ti}(tZjKqVBNpZYpnevLE0dCq3ai7m z5lVqToctD71X%#L3WZ3F{fIczk0M||+ky#Jr6jmiZ$rg5jfk2bZ=D*ic!b}_>^u** z8corKNl-g>s**Her?L1zb48Fw~8ALM+)4ri!gv^Qed1tj{;Zp&{1O7 z6Uhjg%m65OHk>08ViHmTG^(Cus?y&1s#}2~kSsHnGEAJY*yNB(_&$6q^COSnhnG+8 z+qd9-zyH#yz*>TvWk_>$`0@$7j_x+dch)cv>%s|Vh+p{njvae%-hMl91RYG$#(*Lc z?IW$iuLi`~u#KY*B}xJd3G5_~A3TTrk3K)41doId#c~^aQcvWLokMW$+wE(w@x1*tG*`i~U{=xT1acZ3k(t4yTTOw}(vDzsU`V1v4x&2aa)K0Y zSZ;PQAz}X8nMkcY3IoJ}<}F)aV@8Zpih%{@5eS&ADGHI^rcW5S%!7o=?t?a%tGNR?SZH<3jSu)y6hKgtwA7t1b}O$E|d8|eDsRli#bB$ zP>#F;*N#zEoWhTBs3}?g)nyzYahD4c1}y0j`AD)>T%^|EqUf9@(pf)2tc_yFi4w0> zUo4a9f#_+YliVOx%l!W4cM}$KocK>TlYG~LT{Re+6u_238$G zyEplK)MF*v$uX|Y|L3Nb`c=n>zriz`O+#^Lfbpca6e;hd?+2znXpaydhoV6`65OCi znr5RxxGBf#Tcjk8Zm^bKc=9>Shq%^VihnwNNc}ysV^#}CW~U*bhFi#n z#%Y(dLStoOF~e- zgu5@_F6w5%qt_BQF$3(L|cty3DdEKuy+E0(4A& z9{?ansg*&_mKFKrS3K1wTH!xiY8F;NF$IAKq$R#FS|KLDJeZ9(@g&1LDWfCH1oD*c z!XQ$bG-+diIZ`I4IWSBNpZnEiel8zZvb{h91f_MuorwH5 zjg#1nk!Eh2K#QyhfBi{reX|)J7YVaiyLJjUIQ8Em1$KD=poxintYGi7J-#Ze5@Ae& zvEZmKvO#9pqS%Y9o~SD<-<}r|6GlP3P$r4GBHNi1fl*2Ck#v!;QlRcpWQly5dbyMM zydzAAF^HP5^K|gxaLAynD4Jq;sFHOcj}ZIFqu!=;_zBexbbj;BCqclSt-6VFu&)1=YVeKax!+--em_ z?6Z!#RSk8vq%oN!&CyV@bZgbKQK2*!!7}d=!>sDg=!``n$#KVfGLPXmt4yq*gx$T5 z0iTwP@7R9)rdw}Wmr60{kH7b?_%+sXQ?M=TP7~f{Bsy@NMFuaOl_a zHsQ$wkpx-^>Lz8hGVM!fQ~2e0yY#|xbi{lS*_uKN2(o6}No4|0jTEeQ!24ii69F zy57KQmd^?A6qX(#%7_w*>S#DCZ_`zsaE&2dHN8rvnbvyTHgBQkC>CzPIb3EUI(bZT zEYL&YU!vXwdk#jdKhixYf|MdbT|tCyRzaAtb7$RtKu#!q@lxs%q2|FRr6s^$W;m-L zWzX2-FIWnQc1LIc0r4&hN$nk$itf9nhR@l+(&V3Hr76cJ9~D9y&?J2W z3B66>_=w_S8v@d=+FTfW2l=`Q3KA|2O-yACk6GVN%E-#FwZM3#<=~XVh5)^T&p6J> zd#LOUaF6gIbeE|{Cj#WpF-(s^-J`K0u!ng@=r-qX)UnWa`1o#b4<4ZafVm}isVwuk=O=NTkwIo zsBFAZ^<&MJfJ?az%PyuJtC(nE)DIp8vA+DsQ{0G;!5LJJ(1sAj+!m1Vf?bR9;F=)v zNJTwp882$=+TT7%E^1MWNM{L_qlvBaWJ-g3i;*Ie!bGQGTrkX}wzh$uB*<%?P)7~3 z8nUf?&8hk$sAHT)6(ootp8$$W7+M%*TN{g#UN+SJ6YsI~V(7?$2cTgUR`#NY!FO{T zg_68SwPTydkU`SI*`Ot6jh2OgcWL6fOAYfI$Az+b6O!Pxk_*b&@sm> znDNKN-CzzoZTpC;mi&V*j^uW~#p0S*b_)ZuVn8N)Ne>vU zq1q5+kqTtVxN^m{$b6IVO5miiEg_e zR9}oM%R+i|yVtqUsA|d_WR?~YD~JS6R3LTXxAs&*zGc>>qB_dT9zD_w+11@~u zVmkYM%4AM*BQx&W2%@3BS{y>IsX-mBD2K^XCuWkX$_@djBi4Df<0~AMe!Gw2aI!dY zh#RZ^3iR^nr=K#WX$HA3raROza(my8=rX6OmrvTUmu@>SN5L*dwh4wJl*W@ph)Ey4 zJ@0u#&L>We&ymoG^9)ENgOl<(84AnTlMDda)XpT{L0}Gr?cV|t6jw7oAQ2&H)x=xY zo-tOlYRa-R&^3#f?X@Xk>8*c$=U(cp#?eQ2=H{+ao8&=e@0HkSJ3zPCh^0n+&`3Jb01OKz5> z{GK|auxURjtqt=Aq*}owo?7hJnC%->Z$w3jMkS074}-ZZ5)b`hC{(%A4e!(dwVKUHtz;C{h4;9VZ?zN>(N)&{!lJ$&1+$WOR$Je}&O?Yz0>YA{z|ss_0FgqoptE?aOs&5y8{9J5u7V@{Zm zCbImA5#eni{eTc)Cs4{m$Uh2uN>CN(GqA*q~OSTz!aXWFa+LHX`vzdC&i_2x7XzPb~E^8Et1%xVG`j8YX z_22<>u#`T{bv&yz3d=CaAPAD({0wm8) zPZe32Ye|%l--Q3pydPPe#l-bVm2qMZ&KdN;Jwpo%K7)wWs{5L)V7U5VAO#;#0 z?k4ZVN6xIG;;L^kzZD2z&HD|czL>8Gq6vI--`uSn-nM`t!XV*`048dL@aO4m<0JkQ z2!tCKPf3ahz~VGBl#xM;qOKS2jCMg7NJUZgc?`4{eN@ZaCy(#Z1(tnjXUL;vY^J z3J|G7d-F44BvT)%R${`(+AXNdi#hQ>hfbKXuNZ<2X8-vg*6#EiuCdSCV2}6awM79&- zdA2Z<7#R!2Qv`cYI4Ls?Bj7=UCIBOZ6r?*|LEkFIp}Js6^vxYs5aEz2gdD>QFFiv1 z8y}P6H4#?wN_5qb2>yg9j)tfBBl_&1qBafwnmt((RvUN|NA)B?t{YBvMIi`Uc$)>xmN-q!9c^dwH-8a0iYN;BB6iDAu7C zfi_+Dgb3!@xHgnFebq-s`)e0cJRIVy+{l9FwzGNl5ByAHKOo}4`I;z6A}KU6@j7zLaN$-6dkt}PEUF_K-c5UtGU##J3-@{G`)x?+<`rgf zH`#xfyreBdTxLOH^vZOs2|%84LU0G{6Sgl4l$zz=+lqI(qvR@d5>L=S8*x@(7EldQ zH@k$Kl*PSFOKfwo{aMn?x;rJr;!CDSTNugLPU>Szzc${ zNg}6*7S^iKt<$HzH}RoKjhZ;#04X)D zH~KC{{L*8AK}h{eY(A`ueuvJE%wG_>w1jwEkC`wLlDw*!oyzmE7&J^IFU0m8e9hM9 zGpGn}El1}EaJ4}d0PeT+-f5T}EjD3STT+n`WQb7-Kp}`@*^ihX+WrTN-k+s|8t;v82@S*=U0MIbyn$uLtS5iTEvu^2Zml zUAUnp+NdOrL-T9EPWMQJQyv25E;PbyF&`azk@|hE5hG;RK?y1tYu~cH`dx1O1((Qp zB725pJwQ?t+$kgfPTr~og;0(CJ(vZSG=e9{*PV7r!dnt*M|SB3SQGTaWWm&=k2Z#P zAXLbE83$ltl5B>`V0y#Q@WmF!4}JuwSuOaX0_fQ+*#A^u6RHlH_cNLb@WZgpibNQM z0Oy+14&*WS&6oI~Q2GLZ#7;@!yc}jH&j2a-jXfl&nnf%zpmQAT^p|`4j(^tKaHb&# z6hYD)w1eI}@+_ew4%cnRzu;dI5D2s*6ewzECQ(m#`)xoHj={=qG%1tVB4Ag7LIWQE9QJQjFXO{NDEDFt=IFT{%itB8jG18Z9Lk3(Yr`vlnEHntkVYk#7(Bv-)R;HzaJ;#u+MO=%4RFBeU@%%}D9-)L zO?$|+hM@tsdjDKJ_Z-Fms5gk_!0U>zF5kxHaMoSOr(GOOcE~o1hl|nnaNLr`A?@HqBKD+ICkoH(_s+eK6V{#{ z^>gCmm{*0_8#C;dnW03RYp16mqKdh|EH>bU%r}Y&T<{2kE$u!R?SE8yhziryev8}@ zl^Qv!ceHbSPA27}YGH`>&}BoGEkurrss;fL)kckv>n2?qy05bgjsvA9KU`0wX+BJ_ zLjFU(gh+MHa@DT32v7%Mg>`}y(K|RvGH30DlmXG2|C)!$<4NTcy0AJ@G8Mwc_g24`5B_<62ybSq|(gSk*%6$uL7z6pghVGGV z9B>G-;~v1j>}woU?9!MqrQjvx9yVW$h#wJ6vS|^x(R-h#fiF>yEcL=PVEpQXg-PY*2#-pTO>+zqsPLnfVUDV$$7<8zKHi-ippu=Kz z08Xo#w`fH!Kxky4{Mqg~?95(be?ic6;G&JcRca*&O)@b7?%l1Zw%3*W3epn*S zk|9(=KyrcRq6ny<=Qrm@h&4@D76-$>fga}Q^1&|J< zQ8cw#JU#RuPPoh*<=m|aQt&u+N#`f0YEC-Rzyi8j8~c&ya&iD@qnNegjaNTVRl;wQ z%&Gzx@S#;t(*4)ZoqebBT!kiNt@L+KXK^y+L9;&3z+gEwAVOHNqG%h5+#!z#L z%VypB=Y8k%6j;$25m7b+wBl_tIK!plyNo=_fJdxXe4?i|`BMg}cp^!LuR~rLYvc9w z5Cg)w%KVVdE#W4&;?Ioz8K6N{ZI~+Tp#O`z40Lw%)C%pI^+++wlleoUJ{Iv#%U&MzBo ztHIM9h_18r02z2RN@lHg55~WclVHr%ivYqQR$MV4ZQR*TjlJYqwDkieqZ4D^chB#+ z9F+QD`%{Vvl3*3Bj@_^L2(Lrh=HwKoP-z!q(^xMcJ9sAYns6M3u~fpiqG>V^IFQQ` z+8Y2a1lNw?GVU64R9qmfKOpFeSJLP=R+FLKA<%i|F~>YvldaOlwomhV=G)+9vyFnd zHq~$$x>U&voGn@1J@e66v%^)uMXNbZ55_8$RPpvg33skL6c&=)0o(I)y6c6o_+C;{ zcq_gJpdqXvrJ&l(Q4G&;9D%Vo3z77QFxtafC-isxJd`8=E9;*ST@)PBumTFj^ep1g zz|BVQs*I}>lVi~sg+ZRVqOkCxCHz3?G+a^jsixD36(V;{{6FgCce+d5#~B-`a244N zXheduUBze*<#wE}PiJ#9PmV%1n}CiKO3}s~en+)zn)q9an0f{ z#)4Eq@xg#6auk)i2&p%{ z{|8qdv1~o7rZ^W#ctl$8znz?z&?p8zRnv@CRD^WlTP^t{f%BQfC{q}-v5G*c^By0hdOvE zLSDKMcc6WV>Zb=!9)J6@juHkc%(^@CwEOxh={-FDk+~w?rW7v5GH}pMa0m~?2l~^# zeJ>$qW&U^^!{kAI+F3XK?Z0F$Q{P9-t9thMXI4wS-*B;EHgEW8M{fGt)JPq#SUPtu zEp6l>zL*3Vo0m`Oy27Ptn zw_-)IHz?wbz!YgMuYnx#Q{=r8BDvuZ0?uS;%F_$-DO>%7jRK7E(LrdX-;Fhss*AN* zbnt7B{V|H={Lv#Bp$43(QmcmE%N@)b-n5cK*DqkQw)5iq1HC}~nsQ@3`|uuU|;xEv&sTeis3^YcV626l7n9N1NY z7h#Qga(HUAo)~@E7&sHY=p63dLhrM@)dH8-SI#LLXn=T_Z|@%y|4c8E@6DUu;2y@* zL0Y6LQGkpT7?0AQb{Bo;=P&D=H@z=U@i127OG5pJ&#l91Typqf}AdXU`WPpD>GcOm3`x(Ss*{q)RAASF=j zAj;A-y%*-8`r=O?123s9AzWrzS!IG!C6+2yYntDxSwb(m^qfT_CF~2xJ5KNpK&9!Q zOtLFLki%;cnB2XHb)~=Dm`n{9OfMl_W0&ZiQ=393jJAZUjS>@?3iFv3_s!Whdx@tmC4{tN9{{RdrhAQM#wa|r@Ok|n{6S{rph-bX#U zz?(_->RM=lMlaaZehd!*=7X?oTc36Ttsq_CM9Mhx2XL4h!7HiMLQ(VRsS$7s{{P&$ zE3eZ6K%Zbkpj6hpevFw^4r;Q2ljE~?i>T0|-W{r+09BT71)*tvj-#_TR3LKbPSrDe zRPj4q4I1YRy^3=qu{}5<1U}F^k#$sl@qwb?wkwAhUINhQhaQfvc+oG_oyP5M2Vw8} z%?N=2P}X@yp$d(0$%;ueg4~l$|4bcwS z%NW_jdF#0Dl}%t}cX1#&N)=A?=~2J{;6q9bkt0@{()xuANbl-$x!MB2+8XCYP*{?w zE#<3rBk%u3hk?V%BJoQi3PF!0_aui4f^FOW%Iihw1n*#4+r}28$;rE-E+JF?sMIB& z7gYCpG4lPtNlOg|MQ+a1>CvktmuI-8dG9|Jhinuz^*A(m{=seqlC|Ti{l< z#K{QeGO{(+(fvWzHu@N5dO`^qX<WRoFV_)7HQZhpgpyrKdXd#iY z!`3;$r>$ooCrBMLBRg!OEt*+a@dQ_EiF(^P%;8YCWlsWFtOBuV%Wo+&1Mb4jSmwW@b|axpc@7Q{sR#grEvhCjZoM^}#@ ze?R&B%wo{{k-g38gbYOU#*EHvMoc4_u{SA6ycOr zfTY?d9kK27I0WHK;E_OJk%7v1iCB=}Rd{!Q!2<+KNJnJQMCX3}u?YwMKNOXFe-2YpE}(dYOX+zksJu3SX$c_5s%bQ91zL*G1$7Mc!l* zeWl}$QwZ$DcL8WTRWH>wdWKVQZ31Vf`OY_k8l7C0=+V zK7Nnr<=Edmv8U-D250>2Q>O3o7k8-!Oj+VZJFK%srAAxF!s~{U4fO}!|AT64RH6=+ z(C9?K7a~}0TG&=XGYn4n0+UGmXsd)s{IssCXT&wx@`z4|1(Zxot!>tytQy~0VSR?) z>1ct;I!)COJ@!PqtZTs}0fdii{Ct=mrJaAoI|Wk+*QL#O57}UeBMyBQYV`gZH)Ipd zQ$gMMU^5j**u{@R!Z1Q{NZIVeSaIaH!-pdmLt)gO-k05`ZR*i#s^Ym-8I8=b&^vqeaB&>0S1h$B`ER?Cq0Xg}ggABTXr z`wZhuI%k7=X^JM6P8onG#WjiKC*Y(&Q4p>XrLcan1L%sf&|QKv3r9&5-PZPaf1!;2 zilm#6z1`nVCWd4Q7af+1zI&znkHS$E7Dahn;$g4`FtO3fIwSVnP+Z06=*TZ#d9jQ= z+xqy`^_5p99>HC*l+~xX(p{ltVkR~M*QZKrS#5e;$x(u8=}0s>3O5-bZvO>pEumeK zRk8C4uiAvTRhBWjhJSS#>?<$Eg|mIo|4Z2c^jhsm_XI`T`C9OpP!0AX60eP1AiQzA zit|{G?k?V{rrbzO{WW{XUE#ifG6hLS;SQFI8{77WRE3|3v83_{`*-v5xW^OOL4K{Y z>!Cm=-Y@*Hz-D}QF#@cFxR>dbB>I2_VP4`6Zy5)yY&j*2xMS~n%-#C4cWiwl+8MI{ z1`C&z6rYQtFK5_HZ>qYV)KOXu#WWfgj2=6^in6~XQ#6yU=qeO9o({n%{kGZM%_JFP zM@9nMFs$wINEkT=6XT!yN4S5mb#RP!{Un%)=GCeA+}E+URXPrIa~fOd3PvZ-&{1_F zAeV=8{Wf8;*|xwa{DT#hIkdu3yMbizOUX5(P@(DxO>S2EGzl;=-xXv6oo2RLFpU%3 z6B!3Vf%7kWDrYS3+zraP^=2k`moVo0?IGbtPbIBa@TJ|j;Efbv)02*0zHqFRhe^>` z@#FyrZxXeG-1K8I9hJrYDT;)TBT1$<=&#V~{Ms1=$M0J<{q2)`m`n8|P*auddHX&> zl~am}ckZGG-sjyCgo%$zt~qIx_10!f1OypxQS{A`UkRuaI46?@12dw~T0|iyQG_NJ z{xST164gZe%n&Th+j%2@`X-&)v!ykPo9# za)Lb9t#&|$jKcwXT!SpvzDsK3;8x_EimxfYRbaUHa(!8=dM}r_v3f=E-Rvmq4Eja;1zi=&9;+Y&x*0q=zVe^t_k*@W> zkap0VB~bi|0f}2QzR>mbTc9-^x5g8wJ?oLwz>&~PZ|BdqRU^#HHMJhv;0VM`rw$pm z*!?tt36Kk86yCvyY>uAy#4s|6MvnQ*)?AU=p?mxfNcZqiJlgj>afA#xL{H(l3oV^w zgY902LsDgHXrcCj_m4ZZNbT};1cjm1BS*o>_%^sZEQ`9+c>je|M2ylaR97KvDb0DnZZ%as_ZPd@Y zkz<2p#vCSrT8KSg3biu{r%Y(@<(7j*2P9ddBu$i$6lyq8b5XT4Of5owwaZJOs zxzhp%2qlO^_Y>ce6olP1)8QBRjyO4^Cp>haJx4Ho5j=>RgrZmDI3{6&ReSrR`Tz%I z49&YjM_ID-rNMKelogD6BrzwV1_yv%6=M%jWcit2Q)SIuC~Yy9-`PO<78Orj4?<5w zArXZ*zh?yk;5OfZ!JSv~KQB0dS>4=HzjxLmLULve0jc_j$lbv16sTXqXAE8bP;*bQ zQAr~Op>55~acaN#)}yU+JcM>=^Zmy{0vS7TPvXANI&3zp0N28YO7pM}qE6mU`k#JSE;;uc;Evr zE6h>qMukH=3p2z%IZGuxsH2VR1;iwn&Zb+kc}*P^`g zv1mFw$mUh|Yrs$QwZwx$IXN)k(C2LfyY6KJ(u-)(d9aIOUs5@+EU*i9^&jkQoVTzwo~lK z&PIx{BGotrMVq;2@04f_JYKj(m^V03j~I>*=GAB@U+Ceb9o^*?7DSxh!}SL zBW4QyTi7JT!OiQxy2xoQ=jRF7;4}f-w&&^}XSK*Aeb3A@tcQ|2KzpwJJh@PTd1?z7 z7KZD%6+5hY)woon5H_%N1 z1X(Q72%hfeHIOeeX97}UU!XJ7##;drsu-+Ht`TsXco_ZK$JVN(G*Ol-ND|;l|H(J9 zDHl#uEZxiGMqQqHiEW1S9sl*CI)0+gsB$CFWcSp*?bH@Anj4m88C~N#zs@IAEZypS zN8kj`k@j+Gh>iU5l!6IiLAd?j_@?|R`eB>!f_OS|TVZ+DRMAwJ7QTJk`IY$%U6r@q z%+PS!>($|0MJnKdz89i`h?EFY!`HJg{9XnO_8kAGarC{6ET79H^B(~rs@}eD6~*dkg^sJ} z-S?xaXDjcz`+*1E-zES|Ov&Wiy7EP6A`0RO0aUDfLRWn2Ykbh<<9psj3MB}ac)7>t zm5Qg*ubNYf6ZOY<$~rS49mq4@Wy7NHzx$PcW=r(^{H3q_n6AOcKELfhY*@IV=FTK# zzzLhgv_w~jM!hKd`VYxf$m0iU)hhDL=x8y$B2}r5@j=YPNwlX-;$VDs9f!lM-A{@gc12g*&lO@3(L4PNqX76fZ zE(SQkpY$VG9xD$od~V}OF}If9ZFTpq?E z1!i8BuIFC_t?;!>xh_mCnw;0~C%E=WObhO^EvxgS7Z*^4g?p;G67V;8{}NOw{k5F7 z?}s|6&<^?^n(FuZMf z$@cGTz|e!4j@IC~qLYd|Srm}YWTZ7|0MJY1U4VDD9ULY{_Zm~eAm)FI%QX#e#&OA! zhj!$5od>D1qHs4L5^9&&D+pUyZ%7!cnea{gAj1T|9*qn+91btV=pGU1ntkKQWg0&c zEqXDS{j`AV$_BtH7tpm#z3J`IlsO#ZA4=WSU8;(;cpc>to`xnhhPDs@dNBqm4m~Pg zB=e{6cT5j;HY$uDkT#v)p{ND7iG0Z2O+zQAe()1;Mqu@;4%RE=TW|{;z1}(%JBe%D zYTN>gtJv?lX{f-rk`Ntb8^aM|1d7)YNf$RfUXy)(*jMJ(UE$VV5Z!^7Mthwtrzr6O zc}-*Ub8>4D`-7|T%A;(p=DML!@`9q+G~G@esPicc zKgfr=ihw$=wjM0kxQPITgbp`%m-m$WLrMBq&;IKCfE;hg7N}VTtg(+<#lt-1b=~y5Dw-f4C$dW-uN<0GNfwav|8HXu_ZjDDUZF zQCRJ0yIn}Tp@^qWb<&6vt{FIoxjsm+CRR^UcELMLR8#Zdi|!INN$dsoMcO({l_O%K zRTBG#4x#o8^4_-`gdaQu{vmMVn=Pc(jb6|Wh8+zSCdwD{?;W5pznZo(Sy$9(FB4@0 zWik-2pm)mtFke?>7KsZ(Saa>iAk1EKOOIC$y9&`VL-!_b+EuL;&$)kVtXXlWkEzh==kldgCT z=GIcp(g?96ZWPf(A(vquv21N?v#FV}0dLa~fx-i@Hqq8hhl%S9`+~`gSQ;N4P|@fu zL>ee#43A>f>uhy_b0iJqa+r`-C93r1jnDZWe>nt=93}-Xbq->NN!*d|axqcT!I0D6 zVLkeu_Dw2%TE}Xg%RLRK^4_1bHL*i2yJ0vWU7)~dzjm;IBL&3J!mNDWN*qf5)M%(Ra1We6g&i<_0c!d~+VwhlumJ8Lh^Fygv(OdUa<_^+n#%m z#|9<&U^Cd=HmS2|JfKL$T6X2^}~kDbz2PO$w<}gv7qw z!d7Mj#}zBkz>yOLm&gxr8FJBCocbiRyQfSM-ogMUyXGAj<{p+t5O+3-Hh?d7+AC?A z#i5nMrN(Y~(XE4Yd!!nrP!fl5vh*U44tA`5v1W_mn`Dk2?|;%fu?NFlLBfS(X{4Z6 zoPh8_Stllmm@A9qkh_w>@~y2+QZls!yX3l)v8wJ@x<>aTq~+x+>(~ni(Ch`h_HKyK zl;xuQcle_`ROqJ8F%WVjY_Gv#f#63NX>B;>LwG(XWw)_EmtOp-c4)YknR8KarMMUt zPSF&(!&Fd3I+}|TW$}hXtXc_5V$c;gB*Svyjcld_!mT;EW+b}|98esKMF5mwN0FLb z%9eDMVtK-(Xx8Lqpc=;p0QEHK1i?h{+Utd&i`ey76dQ#2g{?sfdgPYI|5$~ryJts% zNbP&me+h?Y&aaw+?2@6OKTD`3kV$fllgNdjJ7sfp$LWV6qrgRAvF^=X4N+E6FS(p8S(vG=jx9>V%8%=teZQ=tEp*bEViyW z{Q;3|OBK|T4ES&{1LqwY8L1WXKt2N?NJo*qOp-?KLVChK4wkeOT)yarHgYV)H7ZA{ zq~XHqs{gy;*&n?RfMH}geT?@p(BQ7V^T+O6woCxXAS}eo-TS64?;NFNa)LgI)8WH2 zz!Ct%w@ZL(@?pOTz!m5$u~$WoB~e)!;PLt3V+1;`bDR&W!3nd@pfE`n6fd5r?AtmL zc{Llpy=c*fnhh`T(EJTU-#hh01jIM(tL^6{2UcR8=|2zdZXxYUett*)F}n8NQ^n-&^?8(d zFV>nuIqf&-#qq@E%v7T5*gn!zq%QHHI3+t~Vist%+?fM(j0%!uw;d9giETbcQ zBW4KHL-{x^a|*r_OZi<$mnGeQMZftcbu{mMTg$?sDR+rLC^Rl07CllLuES?Yi3Ot& z9!|ICC;Jz;I|5*+$ICpo>sEm%Qv`HxbiINYuy6>lAa0B7#=wHo{U_iPpf&V4`g2DXiMgNX?{Qdsg?}CKMY7pEmkfrCK`iEGW ze^c_4kpJ2Vm%b~*v<3@qN84@R)>Cv4!MUq{2|=fOLUAuw#fM^CH5t8HK~)Kpz1#D1 zQdU!p?Ky*4yGHxJ0gY9C>Ku`%T#yD|!lja4i65wP@p1M`_$IS-pc$^u=F=X3n>Z(B zbkZVnD+qYFM0lD2D6W@>2TYeiq?fF^F1FJi2pLuJ0NX-3e!30<4nw+1c^#P~;U2$_ zi|Bn}Xo6`KU%tpOT8>M37$_G+0%A!niHrd4WhgAW2q31~eMAT4cqnNmY%B0Hg#A1~HfZg5+M`}D>tu*sZ7)j&wLH{)bh*p#C zD(ZdMe{ul696AJS;f=0cpeKR#z>yE(d##KikxG1EgxWE#zSqBT6wS7h=1mG{P_m6M zf5M94okytxpf^JW8L>PQIhh(192%E#b7Zp^-GNfKz&0Z_$I?r?w38>o-&-*mb?Ri} zFg^idz$#WX+MkCFMCvN#(^LA{_)PKcw1H95>GV#7IKfVklr=XiC7breId%=vq00e! zLC6g6yCtE-bG!&W&WOd2rfj^$-a=%8MAq9oOpPvYG50W|Rc%;t7lQ-&2lNw6$Mmwh2k0U}Ssh{}!&zuvvr zIo$N~9sl~t(vtv|&pN81H*$N=??w(oa;m`=G<=4KBUNL!nrI|!3M%}*iJv&51VoZ@ zH$f=fc;sG~H3ig3KqZs*BBQZ}$;bTzu*u#pJ61UjAn~#WoPj*E?q2g)#`H zrE~WV-nSBzv}`L?-Mnn~KAHwnFiqvu`E)!9DP23XB7_ORl<-u#4A~P2u%va8J}F)$ zp1uyE1Vt8LB;gy7rk!(&;0kafdh|~uytN^p%*|Go3)bmQa0E!G0UA86t1WG3Hy>DF^jlR5FHaw3(LnUJQI30gZ0) z?;l1DN>5>@NronOtoKWZmMhXhl(R(7J3P=9`(P2i`&(Q_h6V`HYOsb^+N@D0J2VY( zaCelpL$uf--T_NUrNhRY%Cn?H_w-FMRA!O|XEnl+VAk|E0^KihbGR@F?U}@=Xjht} z#mRS`##31)0wxMcBkTYUkot|=Ko6i^165Wbpuy_6%9&;%e}s#+=~Vq^I~UuU>-_Ee zj#6o~rR*l&5L$^^6XLi2T8o?r0yzvMM88G4i)t60;u`P~M%%{h$5E@yMw+OswI~k3 zqbq5_rR*Q4@1A;=HU|H zMss1dz_QeCvF{;8(`6WU@`z`T5|3I$B>(RP#6uECn-DN>qKxN&%FZ7?Hyh6kIJp}n z6@_RVhrEzz1UDY_xQ56oO>yxXhuVF24uWuZ>@3?hrdmSivp-q1=D4wbJQxb;&BK5=bFz8risXZyN~H_?E%@LO(UaDYG# zf$q+!{$JuKf&kwy{+T&N{<2G9YUo1?leCb-VaKU_=U&MMo{-(3T1*I2kFg;8MZpW* zyo>$V-Wx5i4;6K=2%r;!A$SxZ2d&ATYFn`+4-)EH5N?e>y1pSuDXf8AB3*W9Ml zDxTtAY$b~^fVkyIyLWDaM~YYWk2CxXRJ#)l!W*~&;$8TWnOD&S9M&a1xnJR}fVRcE zm&=829632gr5=e6nWwlt3}NaSRss|V>kz0ci3hn1!Bl8*XsUv%Hn$QF8E)j;eOOA2 zjZQU>PdIt{(Fi6|irE$qn$trvK^&|&&O3*3X3^VIvm%!nBsUL-Aufh%(UFB!K%PzK zP0WGq^rE?g!3RI55M=DF!W+fZB3qm`!S{w`wDRmVdr64-)fTVsj9?z(>U#bzeH!syCu({Cd&(T|a-I_*h1Gz>55czWz4FUGzTV zjmBrsxN~}CVodPRb@tGm8ScB`#8C41PJslp;6$TFNBss`S!#lX5XSgbZ=*^@Uuz}w z*Zz2nd=kfk_H+EfkGdJy^l4`a0Ohle+*}43Fh`nf6WS1_H_f2K%QB!#L-u=4Dn7y$mr5# z&?VlG1NW$cnM!B`h>~Q{kpfCjNT7H`0Y`#L5lp2w5bAK!3C$GWOj0S{1=PeJmWlsv z+p})|hDEQuy!xe&|JAX-VYa|59=%nYq7;m79MRd@5Lqh|!H)NlHw8rtwxKGNX`f7< zqI#463@r=h18In21zTe!y@p~~$N`81-m1F4oh~m^aba`LMZQJL07B_>@X=jTTg+M#-jj|*!PFb2&5Rt=s%V&=6J zM1!4}zKmL~o%g^vqVhMVF;w7Pu_pe9$fTwj2BqAjP&8G*@BI8|A;!}lD74)Av(Vh; zuDp(t(h=Icsd3n)M_8ybSnmku!30%h3*R=)Ph7d23y0wZ0YpxYO6mT>eaJ_WXd!f# zpbs1|)CQ*ZLzN%hUp@2A&Eu4aH8s~&L|a~yL=^5|?U8Dew==tlc;HBZR;!J@tFP3- zY>a+b|74QNfPar z9F94I@~zQESYk2KO}ZeO8Tacu!kZ&ZWRcG{k7Clnq_r$PX`!2>oiy+maD0K2Gm{AD ziZlkOF*>2NR^6>yMfQVe-hMG0m&)`Slc^|hpm&z+g(o-LX{(F4)yxg?geE?co%78p zqRyW1V&v8ti{nIw%dV#K4`3AIFhZFyaaa))WEC^4sSR4c-g17ROl}0(t$hY%Pe7Lo z-^b;^>6FDD`AIXq#BQzW#Np+--{}FvQl>TJ42q$9s+yPvnP0>IViasbba2kP{0Quk zh2sfDWK`^b*(PAtb-UkewT&L_;DUc9mr8z*qLXQND^1&kQCUK)(KCOH5QH0@|95G9 z+VVZkoE<4SS(Jdjpb#~@zx*Q1$f54uDbN;8vX}+5vIItexS-hn?pVzOxx!j*;!9{M zxXY}j4zenGBO&iKxCu5Q5w_l@8~_LfA=A_6dr2$BsI$fV=51~#0Al0})f|QH*7)L% zm7o^{+YmeL+^LVc4?r91MIC5V!K`5$n0DRH?f~x6U+$pyQ$#dMMOZ8Bh}ZDTgSNdU z<`BJweijuryzH!hX(;ca?Cx|7LW*uNQYx$j_Jd|ns&&9wa7>Xbi%@4K<#XfJ0XD;YVZ;zAF8LvCDt)Ys!LKn9&nt->V1Ih_TV)Nwqum7oHBPG~D zfS|jeWQg~`$MXjcMCcRmE}DSq$g)hl#BbwpbmT#UupEMc8_+;nhk!D1Xu>KVy8%LE zc_iOn?gkMGN@R`&{I&0PBs`q`|K2&j-$ks^p z6t6*ipx3HMfCxt7I5Gx>CC%O>z)YO!b+7lReElS3i6zO-!*!wpOhQEx?Hk`>RKRNV zwy$n@0V<6b4dq|S|4%>r68DIuD@xcY(9XXek4*uEp*Hk z0h#oD*es23u$Q_Qg9i<4c%A|}PpE53o5^)V^cT0Yg@_@fNU*5h{4+btecW?11v9_|VJ{U1MQfLDC*Pwy1Wt7!o+9cDN$7kFXxu5sz?LSeyNy^#z z0E`4kwH(%Sc!0(K=#`tA<|^jLM`LKybO1l_11qMQ+Y~mWv=fICRt=xsRqbRT5?68g znI}W@3+z9h#43*^XQVK2xjPukx11{Xn9Re_P^h8kZuLCf-9HI|!97)G)kv>EZ3Sk* zP01cap(;fn!dG0UjDIM2(I)VG*Mpn#^B~iAur~dLJ?rs(BzRP1O5Q`dp(KoLV27~z z{4Reu}7|rwnEu_p9odc)l1wOi^pZd6>0Wy6l>R)dmy?LLUrW8>X1R)n}Z5e zrQts3oH#VoUmz4H!mK2idyEbotUYIdg6pq0G zTgx~Fwi3&XCPWlQuNAWV;M3QhKob&Y-K}3#lJ4 zbtao67+^n@asM*w+>IM86WocD6Ag<|5YM4(Fiq&aK;DAlEBge3-kb0FUuXK5{Km<)l8)=qN8z>|r!?F%E4)lmN>-L~Ef|3Kw9C|dU&FJf# z`)y52kb#3Opk#5%9yX5p6!yS4TZBq-0b{*#IEsVV(gpTYL>AHWi4Y73&K3gGq%2f4 zQOL$Ig{TD`3D1Bbw2Sh8@U}?wA|DGg2@%Uy5i6=NgVF%T(omP1HX6EQs3jILb`ihP z=yl@<`48=c0=9cW&!;Re6FJ40``A%M!4{Xsj21=m`R)R1``xFBNn+NnX0)C}8Nrg( zfhInu0guQogL~OLsY8>S6}yr!IUg&jg2llqPAF>e62tfeambN{oyv@)lyjhAXfA`! z_MgDu)_-i*T-rqGDy)EZY}|C!{f-lGV3vhM*iPE&7HglwjhYW~Vj;TQ-&Xw0P^rlP62>qOBT~0;q;|ap8*5Z7@?nR6yRyH=xJa z{6rC47~id?_0Fg+g28#W=l?lo(eua0KrMBvfGVg^a?^i@_M^G;*B354&rpKh&7J?N zz+_)#-}ySyLdVqAnx)wq*&Am&W}JyHN`Cv=SxjOC;XsyqDrQb5fyCs?uYEI#A^zkW zp;vkkMbDlWj&|;59zeshmFQ9+hCbSjN_c}D)9n_2llfUnofGv}rHl*s)(vEhC?@hU zyq$+~BShjO0)GWB6cB6jHAPr+Ef*wm^G_O&0Fo+_ErI3I#c-W~kIbmPo7OB-4?cF_ z7UmkQ`TL$vx*zNQTDLQffGtL5Xd4KEyirVZSi(y@RPLU{k$G3z+{E2qvUXpF1i%^R z>9CkJz#_(j5GJlxh>-P-RAaky=RwHUl>^-ZALffRnq@K5Lw_hXGk1y_SMM6^_s(A< zwGBT(!)#1E?e{mg!ry3Ccp5tudYC0zi?AS=xPEbrHHSNSn4%n97EzTs2k2w1j}Jgw z7^so1HNlK6saL)E9-qq8$ZkU-#rQQ5E#yY9?fs8tktuFQZK+Mf2$Dja$XD)Jr6d2t zU-(}ix$;vgYP3b4#PBC=vWO%~QSg+O--6Ou%j2k2NPppWbdvPT|GDrgKM%>_G|afU z=42)L>PZ?b`T-LYe8E5IZGtEE(GW-C9w5oijne9luzx+_9r}r=`btc*uNoX)hARqOF)2FuVhkNENz83rnfP$jqvDNA zOm0Z82xk~QZ6_NVebdaHMUXuY#^@$x8SqWACp_S5!~NQ~_P9PtVw_4b4BsY*y^`^0 z0q9~0kcY@d(0c9w4ia)~2M5d!0B;CJTM*%{BwMZ~!>XJh*>HZOo!B;VD{K!m2yT)@ zYeb({GA-h6k!1Q5E&zWt{-p*Gql#%Idq}0*zkY6ra z$fQdygqfhTXU8=B=%e4FKP@G-aV1%T--G{gP zmu?yGIa*te@v6+38Mbr%q=llmX<)(o1BgEe(y2a165RWcP4asfWAvl}M}B2$y#eXM z=c+^iS-`|>qCdxz)(hR70T?!jpNw%acZPGE!GSdcOgTG_`gowQd;Lkg5eyQ*t^Q1h z-I|1zg_7mOJOCKT94L>L|9-GA)wZ~l&8y=e6M-+}z9BSO%i0mH05;hnI_Q=q)G1nC zRlnkg^qKj$UDfa4j%l_N_Z*ou_91B?@CJKS@d|Z9GoS1JMQSMrflD?>KGYoqig^di z63Ie9rxaQ7X!$7kqNJ`0pRInM)8tO03}^%ph+624NWFx40|aY!!2`U;A1=vqdoM+5 zNEtidKMq#7%Ih)3vOuhm)^2fCtEnmaXv!G1Xld@-%RXT1+Sj^;G!<(VH9^!LM%NlG zO)TKFt6Tx%ueQf6K_@f#2zw+xpVmH8{ob4vh=jUxWB>t3lIFHe!d=YNJNS^R4(T`y zBki{bra?+(t+vfCvp1re;0J62==aoSF41rSO=cP(U28FCLzZaD0z%N!UGvS8@jot2 zzqxzro$wwtq!eh!!URSH7aObIrX|WE3V%W#Qb`Ls*nl$)CCl-;AB#wWqOggsEJi#n zfe@8C01U(vi|A}m-H;Rq4jk?Qd99k-bTF_h)J;1&;P~|G`ii6Q?fZu@$-s9ZlfCku*flmh>?0>cU?18qOJKM;1DjA`@nwb-f zoaRM_#m1Be3NXg1wHnKTH-|`d*S5-$dkX+wOqN7^<4j%gfJQ!QhY6~AE1oq8fRTv_ zK-hY*6@Vu_F4BqS|I)z0wDXE65;Wc1T|S4lPs%X*>7#&`p^R0hvS|Y=0Rh7_>T}-P zER>o6N9}4Q|DXRxOF1wr&{R_OXEL2p& zn;>4WMHNN}?td^w?(o5sO_kqiQizzxwoetLnCo#&vA7l;-qcD+#s!TTjqVBF)qcJA zUv85ZqC#onr?W>8Vp|E7APdfnECBE`i7(s}cGo}l%|$h~Wmz%nZaTW*MHv5!28k2K z77kS7Q|ddnukQLCNVKYJE^f$cuKQ^;V%%J%XEQlO-%;z7q4BtUn_8#9(&0rJGe__i zLMiepNSu|a(3{OnrHy)!&=^MRnJAC-zwRDTNnLt%b3InR3h9Ly2K`?WFD`H)^ati3ZNzJ_+j-zEVW7GRVDwz#b=)ZJ}hu{?@>Dqk}`zo&(V&6 zlqUOuo7FU4G&V^gkh=rmlC`X4FUkzJ_AZcD2!+@%`Wv=35rp%IRFOsRCh3y2DR{;k zQp&=A#I$LVge~bWJ(xtDQNB}OgyEJNno;aC2@9rjRWe2zdq+^Dc9@f2bKW>DW*70I%?09e2*Hjl(}2*F7#nu4t%yGUc`nQ2B^h$oV=_BszO zzmg_Dhi@)E6Alvxyt{G+85^pDa>VF@v+ByD24-==Ox1BhH>C%qz5wkFJkvJ!Yn4m~P{3#OQ zk?VdVVG9bsGe7Pb3M4WlVKzpLu))*cO{J29vj6om*&DGF!$iMJkxyu-nWr&Ceav zkB&90%*X>EO7z{{Xi^1-@W%+`l5MH;BXNlQBW>YKnf}4Sgh;Svtxws01(0%OAqi@F zoSG3(&LGJf5gtPrETavdTDB+Q6+-AYEoms`iz?t&2qZD+7OHpIBW%)|ET9$lHMEk_ z+=>%OsOcJ&)W~YkI*nyS^GB#pU;jJE265J@S^s%8l$BJDXg*mK3cLf+s&*ZR%b135 zRY9?=drIs4zerQ_Y#V33VA{ZUo<2YGE+8^KwfA8>q=N4U6}B*PybF_!W}=nL7r1sF ziJ(#)IFYz?iVPR-&H;HML4gmS81=s@TQvL8i$iY|l7PT9J#BU%nz``yjpw_VO;BMY zFcJ;j4HS$)q?}3}N-)+#hY6ICqk%NhGwEZkmv9;F7qfgt#1~BvAC*pus#x-RO!;M1`Me zPPb@2R8K@997XgZBe;)4RF)L_iqKs6#i0;*pg9L^=PzOOB0XskVTLG*&e$b^ zjRnDmW2rd{mCteXybmu9YM4WI)+3w8;H=roW_ln7E#Z_!=RLUsvf40$%9|`B7Pgp^ zb~@(OG^AciDqE}c&85)S4L&4vjo6SqlfhLvL~9C+f=Xga(#bVKoM2v(^2XT^R#qhe z71pt5{-N~teg%Ypr2?;T6z*8^hctjukG+MP91}S7NTzb+1R{yVujQERA%(7GG1qHr zoU~iIt3SD8Wl9DG<md7l*XpM4O`j|gx}hBCh98P>CA_sj zfjn>kIuFXGg>G?i;Ya$}*ZF-0(1elk+_nI0LdSSdP80|ft72O}4$Ncw5VZ2O z?w3yempS9N^?+B0Mn7T3W$yd`jz+lOKXnVT7TPsL&ijL+8$!Bi=MEaydN&7g&i#vf zqP--3o_j^A-2dnkN#B8|&wr9~$=*)5%+x9ne*8&2Iefek? zZ1kUqi1#R{!m3{__J+Gk|9wc@E<@sAPxwIHk$pr{6&Gkl;s=gJFGSCeu>neIF&{$< zNqfae6vG~>$}iHhuN`0V-EU$!%;#Z+lV72o#&nvRXL^1fuF2h+D18LBiA;iSA|}sT zNwH4&T&a%eiylHoT9wv22X`mB+GU+cGO_JuoU~Hnm{hm59D%Fp#*if+AsEG{Afwg9 zYfLLf?qA_NPP*oDXky*HNTj3~N-DZ>mC-bnn19w@t{0B{85)@In5-3*V?bFnn@Q1> zK7$Rce*v@NbG#P&O)o)b1RC(LAYr1a*}Net5g~1yj^QZe2IqH=U3^wYoR5EqvJacI z(m46_P20H$3>OEt*tn$nF~H&nrUqTA$t!gIHYy|+004E*#b3suPneb&YzJCh;C@@K zsImh&g~j;<_x4}ULTVri_=IFt5J8)wakLZ>UI-O~fi|aaEei=Zl3$d#Sg`8HK#XNz zN+E?LSr97RWaaxKfx?faJfoATucTM)tAW{H^sPOOaiAqtfo$TTs*{!VEf@FbVT zigLtrMciW6VB0l?5@>K;0NYOXkqMe@({Pb<%=z*Ah~DfRs2e~_4zjtW6 zx2pDUKNBo@RieJUm-6p1x5V|Qn-gY|uNEh9SJ-;+`Lclpwr~nLblM(aRW2QtrDaX7 zyftJl&oYSrpRl)q&HBFbd}pYE$6(;$r3nTP_<_g8QGqs&+c>@4-1wyh<0b>`Xu7;~ z`sOaCS%}TdYEhIn6Ju;hF)=QJnNC(46Eaz8lI+TYgml$O11UC(6gkXHIznuNq1^%H zO1F_xDHl!R`}v&T|1pqu?-GYN_Ve<8e*fR^obUOb?>UE?^5Mj9Eh{IN1U%=}I8El9 zFdgIx?Ml=h7fcQ-Iwn+-H#^LXB{HXUf$6hQ*?d|m#7mcCzNl?NFpI&9A>bdH??$Hb z+DVegL7(u(Hg}RRJW|~eB3&;A=9W9|(D{|En9RUo+_UvSPh%ZE`ytzB7pVXu)KPm2 zVOIKD*L2t}+EAiyhuJsV#D&ndMD&-EALIeT7bnLYP7qfo7OA@P{+)6ZlkGK!*>{C_>@$_NO@{LkEYfPQRe;`6hv2g93+|-K!dUhvLvWZ(444|X~OYF zfR7~RsrkT@D^x6B*?^O`gNt2D(64k>z24t<=4WVRkjUU@b4(p_N+PXa4$y?|GP93J z9_fy8=e{-AM}#CR!3*fbCrOh3JuJC(Z6@<&w^Aw@J_%}ySH9HHy$5Yt7SQ=agJ?tJNvm*&6pBgP^kvZ8_^ z>g;Gg&&Fg+f)b)(NBOMi!y0K%CmL1^kp!mCrzVK=f}x22=t!gwI1_QwX>9EQjY;a` zZFm6Ns?!P+7n47R9<=F=jUO;It{Bayi2n?9mYi%>{e{i{FiI%2XPi2_p*=pe08d_yC-;`LQ2ZM`lOwt-IWGX%t=a50?V z$cgD*uok1nc|mM5DKgXuc5bj>3ALz1Gs&zOYg_&e??Rgu{(2kPFGz*UY5PosHkq0- z$l>P{-V)Vk4HAymJiHyV`!dGkBC5CI5Up}BlC2-~VKtz%Fsucp+98fSbP8~I%WxRm zqpTy(Pm!UyAA%v8!zmBMkfyf(_}@Tez!o4BhKw-VI~%5RU&Zq@kd2n)d*_*U!TnRy zFqiyRKwJ`F=vW-qR(TMA0u#WxyiD`%w@3i8k>F(Z(p>98Ez^0i?HYU@%YEbrSF4Wx zZD)QIB888+a{dasSfCY5ldH@3Unz?IOyi)+wu!Ls40l4~V|)yI#FP)%6~Zl4n`{gE z#s;=^un;ys)Rw#(m#gSgUsK&u-n{|9M@xNTby>Z3M+q$+KCTM~E>eZF>O&GNNLLwm z?1o5R)==D7m17to)Z7Fe*gn%ZaFR_Gdy{J!C^b-*qQLHqzkxDU=Oo(VLM%r>A>85)bhK;WYi4y>i zi2 z!oG?Xl#7Mxhrvz2DA6;9fiJ;`JzT&ab`$VoxmCbj4T-xojEm_vy*=7&O8q37c?r!* z9mq^cKOGV2YzZ&qyiW*ORxt$DBD@djeV@3l(oWHi035S)a{LtGE!2g%)i^2i%t_#s zE1gmp1c9gYAL|rL6}nj&C*nVTz*^;+qRp+OF(F=Lgt$;z-qjF(eK;{u)A(A=hvH$F zk`G}}ApO9hT9(LUCg~mbFU^)a2j3GUi}4$Z#ePN^NYDOMkUHcoj(H8dDG;Q%`X`{2 z*c6GIWuuh7G%VR;s&hn0vnLy@;J?G?W)y+Rn%}QpnT*O$b(YcIta2??KtW`f)wz0L z{{6E*!Mq`9i}&cOLepD;Oy5kV0D>6$O~qs$5y*gaBVZ3y2QcD(`p~A5=BMnw^5!Xl zNTY34@|PO&4GTtSZGZ4G6+e0K3BBy69lQc%^H^ko7C+rZXE-nqYE@orNnjG3F7Uul z5)@7H&^T>>SEzUYHN|%f~q8VN}wXXDWQqzf{xwb9g0$C!}!U(An{yy1%O>Z@C5goZ13g8c^N3zz`OaRpA)% zpHjC-mUsxICWzDcF`R|%S`3Y!9uFl47ThL{SfB`uTOF7|Z4(74=ADgqNRd+Eajts% z;fhs=AsrjCC58oIC5{|FdOV2olJT%xV`5xYq2XyP1@f0am00;;e`h1f zc|T_U>9@B`IEITwzmLZC{FM$!}LPtbD^@ZS1mc=;E^ z#qj1plTZBRzuJMr*UV%L=AHS87e_9PaCZz@a%d4gcw;K7PMAh-3!G&WUrCXn4w zkfgvvVE%Cl+ZqO0Dj>jp4?zm>gXd9LTo z=8-EQPsm6c$o7bnW>6?awvS5zpi+;*{@@lK z7w%1gn~O%Z;irPO)MeVQ3=u&9BcpN18-Rzv;KdhTr0))X2Z$@@Q(IL~zbW z=zgXU71UH)(?D>P`CK3{dK*dU*jVo;-_8Gc7v&iUQrM&W>7eoen7*ZD<|>9U<8atS zF(s&l5P8o66>g>+U*W|kUhy42nt1KxP_PG}^7J9`{Oc8aB)6|Jg|$d#1q{F^=QL}*)T;67;+8y%6NbL~09EI348EC0t9HQI*CiV%tLimyGphwX^Zw5Ak z`#AtH@Qi{bLozv@SUms3|1eu?y}A$K6bB0UWSJQUPJ_r*U1x_zg#cAya-Xz%6T=2O z5@7aGhif3E1=_wGy~IhwSxkogNw5S~)@{ynB?xEM9OlUtgU3IE_53<_1vLNQeS5z; zyYO}HEw%Rf$m2w#H@UQ8VOgkc6VG<-4{nkt$+_u*GY^@4JINE=^nT&WjNq$&Zr7C4 zBlL8mcWvc}ObW@I|6^xW_hP7!H<8X(>;K4~^wTuue!Ii%ru3NhC(D)5QcwbffM@t1 zx~!O}i2k=oQ_j9Vg??xhBA3sRd$`iG2dTv6hKj1sTQ0P4`p8J3p^A*rYHFYle1~yE zyJODInUTAbxPnxQFJ{`Ol=d)_!-t^Te5Ze%KaE%TA4ROb$wZSXB1~2>0;0v!5_c+oIf4Gkcj2K*tB$h=rH=@Xc4k-<%OkNw}w3?5} zlrgLkR?$?q5potanhUuCF;4@y9XnPL@6fU7ZRKlNkC)ZaY60zj0EeReL9~brK^k4> zWabAkPvxUX3G8}>-Ak#q_2~G!MZF;k7}m>+fX6ZpT3Nb zhC9;#@Evbs!AkcthU$cSy(>XzR*OeZwb(Y6TEuOlP&rhhfpIaa-Z3{5F)M+xj9Kok zt!hhXnp4%?xm`j={c^=1^)-dfM8HJ9mNDlRfmmjJT`bE@G{F7AR~yzvpc`VBuQ-@a z|AAIOhX+svy&N=0NF;w?Ag~kF zPHRD=5t@y+dta`gJeiE!@J+=)X=mh5yic!_SMW$wL}Au%fLem604{uzQmp|b*MAux;~mv)(}ie{={$7 z#$|spuw~QYsNrZFTZ{_xmt;I(znFMAO9@T0$b=jqvBD0rHiGp^zz-iPT6&RmVQl0c zc>9K9sAYvEY#PYaV}T;~b$m~0kd^Qc&Z?JWW2dnxEHvT^aw-0EW8yQgkIc|YdS?sE zLb_(DEGioIKoD;s{~+XO;Vvf$Ssk#1Qgekj05*7ym|Mtc0Vj%kT_+td-5Yy)Hw+gE zq|&q?h*14<^Oz}?s_qw7oqOXG5j3p?L6_|ij!L9(8u9p5YrPYo7M2=5g}?0m!_~0D zSdg^wmP2<5A!$dj?AZQ4e!7s%MylhZ5p|-4f||t!&5B44Qq~R)Hpp~PQTrxDDduf= zI3N|^LK7YivMSYBCqf?9k5hglVF-V!O%7QrdN+uV9am_>gcxRR3)axQAJq&Iow3bD zcd>E=KHEX%ER&h}*w}Fh=PyMb%qKVT(w+z);TesT)7uk>*)hlh_R zeZCac`l~R&U|!73%^`=naJ}`dE;_3Wy4~G_3!pMC*%R)~Q=PiZdqE6UPd@uW!#^Xi zz%e(JjWpzGB|;1NzCA|nJOq}5SH@LC12B+qjsIig6-2lT`Ys<>x@-J0yvg`NI?vNc zWkpr@vkhf^968cKvkx{?`8>{i!?JD60|dU%zUBUh8XCwHQ3TvGbH$p+E`b=rQR9Lc zo@kOMB&5mFS4Fa5}JM#!nI?wh$ z)pw?94u6=*xP~g=hAJo~KH@zLVm>>rZnpILafy;nfu;l&>D`17{P_JSmsML%61(iFh55U_8aN58ucCz-S3o{vT&p{^_e^)mDG)Pm!DaV&A9#?w?L0 znx)knObMGYYcXo2BF2<`dST0j)c4+0FJ42V9bP+VPz*^NLHs45GlG-3PwmbxBkI5- zK>={yWko#%GmaLc2oS2`ih@bT3x|$Ag)v1TW!-qPHY=20MrW zGTy*BVwNI252>b1Pp~j?__Jysgf`~b@7USV>X;DKkMyy66rd7359c^e^*Tmn;338! z(&PVAxB+4A{~?Ko)(>^z-3d|6oxA<%9vm|%oOE^3fr@Uv(GR;UN*yq~c5o85MU{`F z51&KchebePv-V%#Hf7IsICTS2ZwL_MFXqotJHg!O)R^ww)I>wKVK=8lGIM1#>1F_M z-HGqgaMk2Y^R!nBeA-fy2Ongw+6vv3n5CFn>_@3#$lL&w#6)F7pNPDVkrn^icxB5Y z+}JGS!X%$4Yo_T*!XZhf7xYC+X0ewD^uP;WX*dR=4cqBZ9&R1mNNNd+zZC^$v4s|{ zg!YuIL&SHau$ijhNUt9*p1X1ik>?in=DumI9gX>(wcu*87w}Gmf@{NM&xIq$ms-x6 zv_OKtK&)m>u-DPM$DU%*jY8LFTC#+pB!6n3c!1D2Pg;`x%+IB%3Hi+Q-NhzMqSmMuKXXn{5Rw%jp#Po4=rLD;CEju*%}L!9tzt_v4nlK% zoWpKmVLX&a$2tlsK7>8xW}*?wuM#m8(WCJrHOqW>1%$+p zAam`dvZY{YTHZ}t_J+zNA`yGg^7q3J)3=76-O+YZxPr;~=}GF=Nf=TtjYvEpmRXy4 z1SRF~zg;`I3)>l=LJ<#1V*;>40+jCRmY=Y>V|~@9AZ}APIMC% zxjc!lwh~4qEhL9|4}A4pXcqdTl`rkP3&26sxqFsSc3d4T=RVtcb$r8`s%eT;`Y2dF zvv)bYR_?zaDubsC(QoD86-ub@eG`@iH7!oJi+?$jO(74L zs=yh*e;ppCF^6SjSHu*p7?VyJBa=dBlxb!xa4re3Fq0 z@FS2VK@24Rj*jctFMhMVnII=fA3=g{Dw4?$Z*PuqiIf$PJPz1}do8v;o?BGY3w1&~ z+n&=f(D04GG!O{Pdn!k!yC2^JBhs8X>=iD?2#PO22}MPqp9xJC&AaNDvr9&WTPw(r zpXa%esz+=%Wk~wy0${;PEN}q-XUhrkz-pinQw%Le4pTXPxQ)^bG_Q;|pcsPR!WS5P zx;rX%Tw8Tqek`&tE*2|Qw5yzGx_5q(m*DncJ_Lkz17=Z0w!9S)I&N(_IZ8t3Z4Jcd zG0E7N85ac}fu@1gAYaK|$!>v?7>goMebUT@0#nlNJM`r!9fcWGy{r`D2W6mTx9?E$ zClfbY?37CS=}V+I1$4sosk<#h-HmU<30j}NaILP+y0ySAm2xIBi~teh;h-i%u*ES7 z-3D#PlAFd`zL#(anZPtvhHF6y0@iTe5crfD7b@eZ(V^Bw2~o7lpePFu$g~;d1~d)g zQ&ns-=hFc`sm`rRpM>z?!n8_xPWqz*qEI=$fiK!8)5>uY+)jC7>>vMf1EQt}CiP6E zu5V-(9)I{<8`Y+*6Mqwy=i58T2QF>mBa`#OgrFu#{n)sbd5nqPpATlLk7xvT?r9E{ z$Aa_Ec@g#Iiv1ic?xmZDpsH@&JbX4iDk=Uqy&OVbHUJx!-Mn6f1*dKOJc0lcLgsX2 zedz`WNyP>UcTHsv=rm%PNW;!cCWfgCQn9>Pi1H&NC~J!pIiQLMSw1W_A}_}lSDGL3 zSBw3bJa;m(=crw8RYk@w+0vGPY~$F(i!Y*Bx-A2w@;>b({>Bii<7FeW22>!^UO5cp z0P7I-0!Cx0tsAN)Hh*KaGmrRe97RD?7#6Ocgf}*LoSMn%Yv4n}MH=F_xrK$#&idhp z^664N{@Z#H3zN2sosl^E>>0N@@B@qV!YZioN!ub0d;z|P;KqP6X-;@sMl4qppp}kg z+lOXvxw#L%8pU7JN>Y?teRIh(PP)jO-@r{Iua8S!NU2WWObUN(!CDnrjX6uFPeoX< z(A2~GLT{R#cG@qJh=%t;>WjRmh?GT(^T=}ZIRPqjZLK`fWu1g z`)KGUkAzgmNATy2QDXO_R z_z{Xf)pQ71t(1Ykc;1*aPzgscgo|{Zic&Vodd!9+YNE17-$Sgwg8#}c*0l#?;UHLi z;By{LYDyzK8t9=>HolGYX?@vGf6hVQNK`y)X#d~rRvE$M)Oc1LERVjq0b=1GxI^h- zNQI?<%>;Si@iAdP3LPDX_#Ya|v0_rMfeAdr*!6g_uBN9K@I-Yj4HGB>^k9|^u8e76 zHX4zePLAd{HY5cVSvbsDEqxJp8YjmI$7@@*Q8Z5xc_nBZE}W3PwV@pHhu{HjC+b&N z9I;#zzbqQ&n>zbX>T(z#$1tap$jcm zk8UOK@h~c=@-1f!zO{IcsjczkJ%o*QAxk801tV0(Xt0<%$TSW~SduwLs`Pi@=IMRF zDg5|Y0i<-L`+?b+MAqvFdlk-@^ij!v?x3UT5UOb|JqkzCh6yHvzQ*nkJ~Il&E8z#^ zonhhRF3hbF3%58i7U%%&M#v|?5i_dY%=g?8-AQ_Ay{@hnN{tU{D|;rpY4f9x9K(cJ zZeEKQlbmt_A+2baanJSjV3d?HiCKPh#Q@Kc@DX9BL_rYt;t^s{Lp@=#7<#-GYybpE z1!Ae7N57?Si&2(^wkc0&xvL)r0ti=Pw^;3ppwb$PSbXr4Mk5}lKDL@6AvCz@3ac65NT1!NRm-X4g7eCq>?UDmHW;O zgdp!81w&?zg%hp1j5HA7iiw~288=k0YU(&*CeEKT+SjH_F$s8K*%^y<6+H*Vj0XHlDVHk*k7hRrKolm5hYwqAdR)D6j0s=yy zN1|M26SwELp+cc1AW(|}Tly9?^s8m#?kh1dfb9w z_ezbU8w<5osP7Y5GE%vkD2Mm;6vsxqIM%QeZlnx$kKF-H5_rkZEtogLwET&aLoYH# z1UvZo6YV>g4bOJ4=sbk+%}fKU*kQ*T+gcm$94h3fAf}Ey$&*a#5V*>yX;6O5fI?0s z-`y0)CU=*(k>Cb?*Ei$biPzJt*9LCMdD ze0*0X(mHb-eVcm?7>lv8={&Z;uV2`>Pw^6Up*K@Xq>A?QPnPfkugbfJ92#BJ!Z z)8{QwAJR3G5as{xo7@-djy2umV^8P{y#Vb)@6f2ftxe_^(J=V7rfMkp3dITN`ZiuDM&{DikTpkbL z-o(052gTEle!BRpUH|b*FO8Mo`O@6gTmK6q3!Yz@KGUar=AepYyQSc_hUgo~f_oPC zMp~aSuJep~&p84^gFpoX(G0r`vb+y^L8uT>HPty7a5kRcgvVCwpb^2KC4P8X&a-v^ z-!N;ah|_DQw>*8(+H=V6o3{*}V8fzU`17qn?MCJT!6dX zF;>8X8?#BBPn^!NNBPFYBbsj@40Y4E-%ztGCxbL_01>9k5G08fQ_G1%UXB&x@G+gE8_eH_U~AKma3~UaQ%Gogny@5^;1J zbC_*c|I8{nS#sA1du_!=drO`VF%pvG`FFk_ZEq>j3G=`uQSLW;ka~+j6pwJKHS{>q zqQJDO#~Ay=zx>yUcWe&l5`^Kzc!ksA|9R)?TocW?ygxd^eN{*C6`>3a*MCn~OPs9Q zSa8^`r+bLcu;I}&jVH}mTV8`HqgfoH3sBl60H_s;3Vt>W7WeRvqfYCsnxD~nbmNuz)Boe{H&)!=_2o5J=5Lc}*Wbv`b4_d* zT))vZu7exI&0@$OPRCjv+^gGMx3#g3usbxC!z;HpQ`e%~pq^}$ro(Sr!5}S_${#@U z-=M(<0jqS&3*`8q24?uI$hJd?1z)z7<|0Ro3|7b*uTPi!Z&_B@xb490zN)M z2P|4n7Y9bmXcC-TBJ4bl_*Zf+_;o0t0kXc#?DNJ5zgTlHm4f`>14xI+U4-PG)BTJ@ z5$89y7}yosBua;VmL9!*8D5{qPeFuB>IZL&z9aq7sUOuh zhq~gH>ks~55?0(!kH8Pyj#F-X-YvfZ_8^QoyLZoJRv9J0UToLe(-ytq(`Y%Tx?rF;%o%svoC11+{zE-D85sP9s-WmLe`~&`M z@(`qN8tZ7uWL|b4)e*4Wk;7UW%Yi3yw2)z)5Wo(eU~}5W8f%2}Jx)(FeAC>G$O|Yk zL&~99^&oju@{|5NwexQIeOjC9J<;uno33nBuf~im8Jm^i5%~WJP0Wl zeuxc2M_c)3S456-4jKjFfRSP}HK*+)_DW-K1I}djD(JXm0BpD!#lp7KP$@v@6xO$p zyI6PPh`EtAq&Kg31I+%r`-`YD2AKXTFX-mRoeeMtZJ{d!$=oX@$z8)5Ou>* zQ9QRMRbT+pPULH#;Prc1EXSKFe*NX654YVQmir1GjRXq@I68p=v2>h}#-Ii;2{{oL zrkq<91AU3q_?d-MWZTJxFk_AV06Sux@CIEiehwYUFn!i5Hc5*-Ko3*6_@1`jvBBD- z#N2XWbkE`DYW=MZrZR&VQ96Nj)XS?0jGUeXRfN)HY(y}mcjLTO^_-P zajw-Lav3v@4$wgaz{r&wZj;bKzD*7T7niT0WjeN4>8J&in-<@&^q$P8x2$we0F`YS z9}+FdHj##FH2;Jz;p00R#`jK{NA@(3PGpq;*N?h-pEcS{Uw^z6rf6@Qiy5^|TozM@ z=YqTTH_WgQ#9fK@>7r1=nZS@WN=Mk*ByJ!)kR+^BpsZ7|ca^&Ku1oQM}{i;D-x?P)VttIM@uWaT_oM3k~M2&Ovh;cY{L{yrzQ-3XovO zJLhQvNIn!1$uBY%5M5^-ULwO+pnb7mi=AIVrE6^^;rw8M=8u44G^0@z6|G;rvAS+7 zOiJ%z!Wf7e2E(6m>&?f+79i2X#;S~4l^nk59uG4gz@6p;*nBq425Si_ar?a>+flYO z-FndH)UT#ry!V8^SQXeJ&+OzE11jkun@DPJ*LJzLbNow#)wt`SL+k%hXC3Ajvuc+C zt^rVWmh;5tNYv}hbVvf?YK)<`1uP1DITASF=+?`CuBIBy6 z|LqV(VF;5#DaJeva%j2a_KrQ65^^?*j`9wcW{I=P95yl3YqI3FzF|C1w31!6eqWmF zC?(s%jn-AgFV-Mt$+Qr{Jdrr#t@b#>wNKbm7N`w?PBI$_ZGbn@>!nK*vIUf4B@@IDS$P98K$7qXa3iP`9_vD9 zZzc@$*))o=?SCj;)2HuyieXE8PiY^~V3iq9U!;(tfayYB&7PEVCf4IUMz zOI$+|Aa(QNrwTbSOlqj3d@=Q;0GpIOQ6%8tXqtW}Y_P-*^UB%K2h2z=LMzMfneOFo zH{yINf8ms;AJd95&lCbjf)E%#Op|-~Zv|=iS{?%doho%W)4VKJgEK|nBjCi3QV0OX zX@L(>sR0^+G4)ztHY-=)c(|Adma!0+h={OK^MZEUJVwZwG9pPF8zJ%4>VcklxE;A4 zm4jTg4VzQH4E#FhE?Qh>2INE1<6LX@f6%T*I2>foWwCWy>$3%u&a~DDz(z-eD!zb5 zSUEY9MB`x10>t5o6fF$w?afnro$^wlVu*}_Xpaei(#D8gE_jo0DfG*&X0AtZ$M_%s zs@Fol&6^*+{@hW($h|bxhusoZ#ckAPK)c#87FYjyv+U0b!iOTUqc+0M;FY+6RV&VdbD>k#1H)KGCcD(x*Om1cLhPy=JUDMr57v>G z9$^d!YfuYYyQ+15*1a%_23#aL$ObgK;&i(Z!q;fOrMan7G~RD(cmX< zBUs6>N^F;M|EB(&VYiPk%AwZ^Ywj)YWTb8F5c()Z!0hX!n|cf5E-10w$uhL0YGfNr z)w5qr+ElFtvwoQF0ZQ?FJ8lC0hFzrw@dP@jBY@Y%+(0}XB#9c6;Owae1)cE!&07`^ zTLQHM5-9gdacfqwkEr(LG`q_#};@N*#OI6D00nEE8%-cg&@pPfl~~W5`~y2zp-p zu{RuggjQo@LW>{i z%dlv4ghoPFCf_$mGwhXS`RILClM1HH@wrsl*NK`B9~ahMn0T#G&4+7gubRR&gRV*6&hycXLg+wGO@2QMG`oX)8oFyOr9Pzx_%oREzhRF+tM3b#m?j3 zW2or=8fA18n-__6LA@J!yrfp^V8yOKD5*Z{_Nc} zt*5svmAUk{KmDyI7SleZVfM(ko_LnYHD~5h^D;zt_^ULBW&BPgC7^9UO8q2n`2S8S zjp;gDKqyNcFJB-dDwstVfk42EltA%%(>y<}EdwGM@W_4; z?1yk8KHDToA_hr$FA`spAzbh!xf1`_Tldw@lUrZ>MSR3R6L^gO_tSen{i_+=g-`$E zu2(m&h9S8bw@B;b(}-UT`-|5n9{DL}0y9Z6m2+oEivgER6&u975AqH%Xf~Z<{Js`5 zjvVwWrh(_=POpMk5nO013@8-2zEw?4Bo>M$1RgX++CHezj3+DGA6|mGgq!%v?3^e zg0Y}U!q0H=q^)thaUv);aM0ZGS*fvUj1A488td{}O=NCtRW;a-x5Pm7!z-gw!D%9h zBNWFpa@1{g;F9svZNiLuuyl~W;Ye7(CMp7);9^6kl3}2l&zXtX+ zr(3SG+Em+*A#OK;3m;;R34wwOpd179jlN^2mk3<7=oK=8 zc%88SWxy70nH#JmGEAyPRk$eB1U>hpZWO$of=Alfu=HG($dtE@%>rxz0pI~EsU7C| z*lBh*d64@Kj&@Oh4zB~LB6$+EyU~FqK^~r2qO{muJc|r{I2iLDws)ZUE=374YIv41 zJbm&mcFS^_iV!h>;=2s_M!H zSroyF@Qfqi${s_w6FS(Tq29l@(T=PiYV9=e(yT?rP>mV?O@ixbC@XO{co#}x==M6c zcr$z`RW&a!QFr@74YG1B?*zfTrxmNP6h5V_>2N+{M&RKqfFtaUq3^N=qfWM_Yu}8% zilLroiR7Na5%o>*PX{Cyl_tlb@&$l$?q; z@R#!r4oWi&($1x5!Hf5m<;kyG#10z7&dg#QaL`sZB8c`s``K*A&<4XU5D=t?6aJX; z_!WiZVY7&zz#0cQz1;P@{gT48km;qmoE7GT6E_eLnIOb8@^tT%qzP6Dq`}2$>tMc| zX`>b7vZCv%W5C$+(TXJk6;xKXj$x*BP@OJHWW@<}CP`{r4nWdkV!)8bXBfs5=rP1V zVQV6T0=&T+bA=8}#hL&tf&sDKny8Oc)N2CCT#cZL4dXs{#d3vfgYR=!ju+r+NVj1A zFfAD5#a?9(Zo#$(tswu!bm|k1K(jt)%gN|Ua5^&FxnaXtQr=-%=$8k=;zOt+jznJ9 zTMh@rl;_)-5t(CBBxRT@n;C+IdstuFO1C5oQ5cs%3b(mSqh`60sIp1FnWRcgFGPe7 znixmsG5ZTUk*Smt~j_nW4o| z_uF@ufCE%SFPDuV4?33IIs5gy-{j+u)5nEHsO5tO_z7Gfga~9IxFE>{82JyS)nq;5 zI>yeBXb|ShuB(~BpnD+` z%?}rFCr^IYZ>d48p*^$#iUC%HoJ=01&;Y_?k;z@;wyjaJ66()pP{blo;W7*bF$$Nu zj8T7>4oW6k?nE75u*=$1){h&L57Ds+pTP`_#M~UV3-2EhFFGScdHA?CV{md2-bQm_ zG^G~}l3UYCNBqlD;JBirci4KUGqBo7teTY(@IHHrKA9yX+PkZ2)?a_nUHwD0AKPi@ zB;#9pp*l`%z^#=vVvmJC8e0)RM!$2eCzom#-5YLDCz*dFF&mdICQwQqMNZ&w z$~6(vHXr%iYBe#Y6yn~Jg8F;M-a~t==d@?akPwILL#LXnX*S8aO306EG243BVt+cS z#q&4cu+5xy#-T=Tmbj4CBSgS#5d1XW+T(8t2tN>O;m!RrmjyT$fPIw_NILZv#uT$F zuFT`nNO$TXr-W`KC^+F9R?22z^FA=lDL|@GjY32}^ToURB=`333M5Y6nabjp#~?gN z)^M+-x7Y^@|3xJ$jROcJf@)y7Ikh1Bh89eBh^5EdkSJHJ(>PTkpV&J zi7#cOPUL!s@q>X0fv3qIe{dQN$?FGEugf5!PU8m8*GGA|JRTYS(pH?bR7-TR^yWr4op=PqrRU%C?(Dgg`C8biNS5VF- z4u!hp?x*Iz2~t`*eaf7*VzP1+FH}dLEf+wjC0PtmsYDUed6txo`d#aGM0$Zc0-99% z$=8?(+O6Q^gWaco^L76+7vnr(9vzF4DOtf;={NBUf5XBjm2i~mgbu|I=+aR{vwG{M z7ZI+;2l`?DrGZcP1W!^p`soF`_HI4(STZ3woUNlW;Fc}2@ksEc^POin8!^b?>Q>x0 zULb~+gfAjAlsDB{h6iSs9H{C*eDevR*P7lxzmZ6g{TTxEm$}KBR+I51{8! z;&7&(1$W|`cg0&Ni(S!;e@g&p7ah1X#=xRD<{ZF>kZ&==HrLZa^8nu+vV?Qk4)6%r zaRG}5I?}-NL;Re9ZNxXB3**O@H2A&d4t^ON#wefAiDNUlDwKUw$x}P$$|{=h#`C;H zdN?cE8>F+h5A0~G3&XvXzRv;Lf-Hs$I6%XtN~0#@@gi}H(^U0K;HC}>hAQQp@WL^I z12ag!C5j2;Ra-pl+A8$J=)yX4RE#p*hBuEkqa6A@f|DpG#A3Y+(MztL&f`FYEd(kA zIif2Tw-t?t7BFIJzq z+3RF_hVi@D64gdbWs8awyL^1M2S?V zOKN1ICPYixV$Cn<9+$zILG};at!rx8f41@<-oTm(dm;;V zd@D(J=|sGkM@466eFtv~pkqk_lmunt2cS)AiCT;6Wj)y!W(%oD61htHjVZi=PvXBR z`0ZsviyG&l!X?r`pKLcYq9 z6lABlCRnO{Z-@_)Kg~#5Rz)d=Yy?X;-f^v<)FuYjk z48ntEnHp6Jw*5Fea`!`KKybR`TP(S$!ZFi@p57d5iTM|-?Xicp3{k-@OAX8daBW7Hxq#PtIvcJu#Nse5)z4k;o;uYPQr z*MdXHT%qCRGdEn#@gl;5?5#x^tYE97i3+I@8{*Y`mRpgq9h^lmyu=? zfOwPqn5L+fB;dsl>3_#Ne)nW{3;7<>Wb3M<=YRbLCiiu|+Qgl1dTFdeo57w}-{xS; zFdFoqhk2&rJoRstiD0V7{^?ksVk$rbSENSRowBOEwt3({MD5GQi#ThoglcY$j1&Oz zf~58vQ#o3U#362MsWM^%`-GOEy48@r%@_ic{SQ>SX`nn+%WQ;Nmm(-ga;#El4T-J} zIlfQ-Z`uS~;Ys6=34X9k7zxAak+}~(W|%}Jz7dTuWf?X!nplK@@p&v@%I^#li^xTk zGlLJ$ZwB;8@w^jJEuRQ67e0m#C1GW=zf}SjEhgGd#}$HCE=VO!G!zk1nNa5aFjEFy zd_E2EzIi|XK$|{QuEKaxv7X%xSk!Pt#69#3&EDx#e-AZk4|EFV!Z*m~5U> zcg}6wCbrPL;<`V%G*DcJ=4QLi1z)dT(lx)YiMcI-w~=szSH4Pi0i`6VDD)+J{p9%(5YXuuDJKGhnS=25&P^ppPLr9B|5B$+hM! zi~t6VAS+?}yOo0F85nx55oaO|gQA3v<7{?MZ4}%<=;++tC-J3L0DAt*N#9xv&>?o_ zxy-r3whS-14Wd}WL93MV3u*L4B9%B4#1yCYbLJMZO?r#emXKb9CS_j$dp*GBTR19$ zTPlB}lEl2Lgb3`{Z^q|6)D4=9zSYZ=fAN#uDh{FQiWTFMm zpLnXNJ9v|k)T-%{jSO;$?rG*Ug&Y_?;gqQ)jwQuR1U~y`a$U@1r#V8vt2hPmkn3E* z*kFAbTHxvd7EQX;e>w(wI$*>IY`mFP=nvEk^_T;!9`I+7DKTt4cE%1`0Z@r%VC&px z-cI>z`Y>!PXDrDC=L@5VmiAkK(^EZD^hrZl?uj3I!{B6_65VD3Cm;K!6y=wGtt$jb z&|zJNj^Dc)N>-nLbs^p9yYZ&BH60%}ow2g>Kpz#oxLE!$DCRQh5Tvo)efBP8&@RnN z@c2;|T!IaBL=Ci%Ty73_8C>ECo#Gj0a{MUPJECa0X`3{!Z(MqngzKqId& zvJXhtI9LH_K#!DwRMHPgmXSe|aPsMU-GBK1v;wz&e=9co`1%BfxxG28pl)j+t=H2a zmta#y=2lTk^i&k)-5r92%wl zdPaZXl~Y?^%JX54p8uy^uYykbHnSk?5=V}u6B6F(Bid8u>q9Lc0x$Y6&m;=r*n#hD z^rX1}8sqdx{)`uikTI6H1L$$`0x`bI0XsTz;XC;X22TJ73LT-^E9xO(I9~=3(7fp| zg(6#SxXAi-cbso1X|!xBRece zh`hXJ%lykRnT1V(%6Nal+H(#T0gpTqReP`ej+QQ6$^qhOMpcjv{!6n9o8J{Z=6m@L|1+7#aD{g-@ykn4HW_9cX5N{ zsPLRbuVddDC}Ur+(D*@Gu6*!@zrnX+$tl*-bZRzPb=z>jc}w8$0pW4ol>lJt6!ARZ zQhZVkvKTq3_x3N3d2)exqiH&XN+o>JST(MUgoIOJEhej4jZ&|QxW^k+y4t=W{B*`Q%�UK7={OO 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 z z0BaA_#I%yq+U9SC`AJ{t(GtgvA<3V23&J3(yTQ7|JFsDuQ8@s&Ak}juNWZ!JqLAiL zvarvRy_EgsKonv~;afS3*TVG9%@p2N^&L468^%e-@afNn~^i?lXpwb)(d z7-{sK%aJZh`kNv)$qPBo2{kh85`8Cm=r^NuP$TDw+3UO}dE!<_uOn4tOV;Vn4pS7% z2=FwyVdFd3=AY14;6DS>vgez-fP>8&3@A2}tm(W!WJ=ov+Y;*NH9g9C=}nT{rwL{G z@;?{ea1VG3U*9@@l+tk{r|S|=GU#6kqpOE*_ep#qYGPBN)dw&J9RnL(%+^P8Z69g$ zi_R3t#MJ>wrFD_H1EwvWFF`8cr8XCyE$viJzVVjOYeI8;Jqu*fM)`Mce+EqhXRzaz zR(3kl$WX#B)>CxchBXc12Q58{hHC^>r8KUGIla@1F`+Onmk;;B>rfkG+z&@sR`gF5 zJ%3jX7@`;H?@#Ud%kA(LEH>aTYMhY!awO1!s4<*Au!x8Ww=SC}VlzE7!6x$Omgk0R z0CTk37%uscE0B}vsJjI;P{8flVV?KatxPSp{~GZ_c;CrtMoSXmN!Z5^x{3;qQ(8Hb z{ywcC>flM&+9UONzLCK~MS3`tDCr8SV0aRV0*fP1O|-j#EOJvoJl0w1s-X?LW<@iV zA4w>vE-puqGYruHaDgN|8{Mc=vpy;h%#7^u)^hcg$MB+Npb~3BEV|6TthzN#&2v|j z+k&0Dji(3HjAf(Uc-(P1Sl_if&?yZY%mEy@HZ(nP4SbtrtxavnBv^tXN`=43lbIgC z@BzGY2z5MH#7viXJd6Z)*0jd-O5(a_FQgDCkG6&`NAOCWpf=Q@d%?Fn+tnMPR+%Hh z`ohjv$+xl8oQM8Mx*@X~6#I|ujLq`2`r_r)MyhHF#)vJ;)50P9UC*@e>sc4 z;5sJ&gGmfM)?l${w$2N4PytBcN`4~#opOhy`BbP*(KHLm5vT9OXM=wfdd^ZNI{TyY zT_v-67E>IWO)#aE8rKs@gY#ddvl?T&>%x;Rnvmw>*Za+fQuy6VU`5W`MVKYdqPy_F z;6xHY$q>P;sr%l?iH5?+f)Q#=Sm`~8-%K+q;0-8m7GmYgmk8wOXk=uBLm(ljisHNP zUI~&4un~k(Vq4@gL<@$>Q*w>*z zqnwR9XW7B8t9u>oVuuVYhc_@g46r8EF5=BK&Gc9ag6-61G!`X<)3x``!BNTFsY`}GdCvFU+mEU&*L-YI32{M`|yqd#mMRh94T1 zHO*)BsZnZob^|fV%Tj9)AGvfiKv8@L`0b#hP1nTDr4_@3QRbl66SdT296mABR#wv* zSkd~BaEefb)5vPNVpu7bENqn8hgUu7r2W?eJZW457(5^V^_qffLdUuCHB{!R;rFRUKCRvlWi2;V)T<_8_x7LP|m_X+? z5g{yA>91pf^Lmmp$T-k_!QhBuE>ef$8(|Jej`_4l&I0oNV^lWH@Uc2*469`w0T^5` zP4%P9tEeH62{wGZ;D!u9%s{mQ63AXq$g$Uvk27|_XB&R^FwOPE_8m2FH6L4BQgD{L zeefh34MeH`!uQR!!Gf_`O-=A$WQ1uiC}Jnc1VQ^2SJc@D*Rx(0g|!N9V0CaYTyBW* zXz!1rV%#o4s@-YqPEqIO+!eCX`_tYL{%T}d&Sip8HCJf60uR_#u>_k$ilDdvL@Ap= zNxDZwU6Oa(w-{wHpOdwVnarBha!Ia`Gbo&jOF)@ejFsq3yD^p7t)Z*FZ;%t_fpd?c z!+_`55|gN4Z15HXJTE`6{3DT_JdPU+HK^?2;;{W^n8*A@XWLcq?h))MT20tEr>+Bb z5j=)ZmGYP{yvv-S5XOl`EgqL1{yeqp7(j4NzhfSawU9^j+;R5OX1q1p7@2yS1l$)O zg?R_DHgC=UmxX${?{Vlumi;KPfn{B838}hH7G`PC(hRW%B!a1R;dJna>93h-E1n{(>RW=SLcu3AwL(De9FU zGx7*~7~_7!_0m_nE)ztHS7LYfN8_05(y&BWJzp-oaLzS&gA$PtqY#4cK`0XdDC!_t z*$5)$Z23a`diepIc)xX4JDQQNRxEt3^6QS7{4iuWM)e5nycj=7Q`H8@2XO!aJ|-$9 zKvRhDzEOd5i2%)CP&vXNdxGMKCZU%*I3+_gcSI|K7=KT`P7_6%)cR$?DG?okc$ClZ zTdl1);oj-df&D@6U#?$@MrGdXZxo#-=YjZ<0Tc( zB!#e`BVbHi0lSpm2?!Hy*ztWF)RwPfUGoocNZ7{E5{{Mdx>HTZ=B(fnCio`k`9&A) z@CuKGYrq<+R`JzS1xaUYa%7glj@L5l5Pd7_nrDpqObz3UE_Gw8$p%52Ab-7}}@IRMOwPDJmF_2A!L5%fW(}f66Q5D3qQ+5+*5ZEy0a9#vUA-iVd!AF8+zcgBPTo z5jPdsq`{j06uSsZ7vp5j9fP0M%moj#WIT|JOt%V{XddP z05EXR-LSMhv3Rrb0RBBBlk>XgpIf|+Dnb%!6LP$xyYJbC);QXbtVi`P?!ni^7&JZ_ zt!D~@Q-Nq7WB9mt=qB)7p3-XPW>hc2qfY1nAS3a^+3Pi3>gcLaqGXO7Bo6wCb=S`U zn~JJ8AVaRdtF+@B#eYzXB*k2DucMWA5Ir>*Qt4hy>C50jvVANcGao~}(}3$DUW48kxGkw6pm z^wgjXvrY;fgLgZA{|XBzKuKJMO^h|Cs4;OVg%Y;BdF=@P_^Gh`!7_B&@`g+oAx?=g zAYLF~-~^tv=EOu~pbf&HtFda9HSegpI2@ubVk}{bv4LdgwKs*V3=e%VR|3sPE7Qz8 zYqc4TL^kY?Vl$r~C{k#21MA=-^g29w%)r(F5(pz=W&J32$upZtaV^TLTW@3?fc78L zYJea(naHTEU=v9Ka&8dM_NDGRA8)}fyo_S*4PR@(r7Ad=mNJ4MY13-HH^B{X2W?Hv z9%aWNRw}vyxVNxM6wS~`?~SED@>c$w+%nU|%>e>p3_FT|6sZV4W{eL~K9t(`S+NOl z2eC{N=WE(@=W;IPwE?~*P_*Ju&fzMj&frltDpwx5d+t4hh^Vna#W;anF4v|vrnA-H z>HzFzY*Fh20A%226bdC_es#&@qaA^z=XS+@10sc5>!@$%O~42ygRCDQ1C!FCBFW|% z42gwG1%eep78q+V^!#;C^khvVJC+-sm%^MYZBy{po< zJcCa~2bCiSVyrG3hXqg91zaAYXFd_Tj1yLBhFCf*tT?lJ_7am0R>qKu-;Qg|uPKC5 zW(E4$(3E4B$x`WI+(%$efUXaoF-5{E$)hswcuyD z&;cO3l=k$`;Er5(Isxw~59~@#yLI9ugy`{yZE=%TQ=f@cNFpYZeU~AO@WG{|G;=jt zO$HJB45cYYMNKvLSdfax8oqXn(I(es2+FCB^D>q}kX#av=%nrF#nyqnfiHt_ke?`_ zuVQ=rKdV~-@0y-b&LUl>R276T)FgTgHGXSw#Vc1TYSwL!f-=GYP0Si{`>rDerPoG% z4{%G!gWt;XwqcWy7=mU_>a;~N>e5?Gk0u2054IXCH(zp8j-}uzO|g^Mc?==JmC;Gu zy$P@pYPtvTe-9N9Z8cy5)IjX!lGZ3vv@(u1iYPgQ=0G@L8%}q>1Tf6&qPop_ZEiBC zw26Qh36eL2{C_MDnWRINrgzjesxDr3RskuzyYiuu{-qeIsNFHT)M~V1ORYPq=HPtZ zXwOw=FIGG1EQUk?+)x8Zb1nbox(EL&mjXyY)|7H78RV&1y(uk-JAWIC^ukkhirr7X zLF6hzIl^ypS+;+Qf&GvnXdJvdkv;3>l4jlh&4=fP&VBn7)ZgxBuI&iVR$J_W%#{)< zB*c;A8q(0$gn`OV2&3i>HcjddL&#)Mns&`uat*1(tvpbmm}GF#iZ!Lgga^7`?PXa| z@3h?)LUA9A21}QcS}!Y;MY)p$;~VghnL;?=N(@%hCPqn#Hf4b@0V$NHy)077dZOjJnMMlRWjHjKu%O)7!tY}fN3FK}h>2*RriU}fHw zU}dD7tEuAw)@-i=;6*D~Q#(Lppm{YI%vP`|tZZ#aRv5|{eTuaQG7I{q=>;?KbTRA< zUX!-I%I^zl72l)lp{8LVj2z%Qj1xLiFvenN^yYMdbg0!b}i zq#3A^^Z|A@TE$nR8Ki`o9B9ZLQuf3ZefAoJhTD(tNvEBGyZovpV_7nA3!4fbpr~Pb zTx@alKyz#3Nk17;pL~HkAT1L7xEu^W{h2>3I9}-16$DZ*@HI#fOn&LOW6J?CFumfk zPcXjB!kVwYjoQi0z_AnTMUCNU*i2((b?)vkD=tHBmU5`pO>8%j-rVYgih)j|<49Z+ ztr6sKY!$Xj7Uk)AlpV^7u0Y>H9{I#S3#^S_d}MzoCJNVHU8dN)+bzUHo?CA8{xVFQbG z@3)>=#n>Ya?MrRe#$E=en8)7V+bjTLjwJorjBPY1GYLr05iHHZmD{Xm_y&a8Ke7A~ zOb2qE@%ItLobN}e!|d$y*skzv+J9KLod&6S{B4Z&FL@*38QRw+(i6JN*pDnU0pTPZ zkXVia#sTf5cNC}LCP&2(X|JN?AQ-vLLUra@2B^!mWAZ!P|Cdt4IEBx*hxuF6Oxk%>@k-rvEY zh`{2+4n5I z2$H-OyrJD@tGU>`Q29dUTwAb+v(V((u>sz(`ysgFQNS zlGgmr(q2@f#ssx!>kU$tl}aq?z&Mm_W&d!m+1jekf93I^WH|rGaW?gL$!_`j*cD++ zTp{z|^e2fVT5Zt~6#|d`wky1ND1qH= z!gpl{TNyt9=Odg76LCb0r2SXRipn-^}W@48|2}ndU}YOr))z3z@7GarDM0XMnEQ(`t9=3**)Z^!6WI$uBu+?~!pDl7W! z#Q#(G$~&5;&bpU9E@xOVf+V63@3!;rBS6-I2s+|A@Y-8CFUoh3&a=d*X{@AQXP|Kq z7Z)!5po~r23!WZo1!UMfELT{?pkn1UrMDK`hJ&!(t*}sh&eD?MZ*g?MXbFGnSf6|m zU#;CIB+0Qf0TATYkI_stg%Jj`nglX@1tHXW?jg|A(FGP9+JH1I(?`HW z_Safa8hVe#Npc-cO^=}f<&f=dvML2vL(|RRQ1?5RQ2;r+CzJ1-Ir<3|%Fn-A@qfd@ zAOz-6%bP9$2e}TeR(b->ylF1?!JH~~4>W^UA0bI+sA0?5JSbN1R5g&t^6U? z>WS8XurFq1qoQRb8B!~z`dCth&>@uaa&KSdlPCYn8SesP-Uj9?NRO^MWvlKLO$xHc zSRkZR>~G;G&Z!|`b1%P2!$X`{LXE5ka; zL|8G|h_O@wEGCx6o$V$26uHV*xS4CP-z_?Q{8qRK)i6{#W1w3Pg^LvRKq`S@ z{X$(<3MKw6HQO%jw~NdX@d_1JKEZLdw&{k-_Qs;@ck?@XtYm9^-f0a8f-}!KR5(__cU-k+_T8RXEaqhl*R|&#jKny5Gjc);VP)|YTd#bC{x8M5^Xy^L) z`c*GiGGr3k2OBqIx(bg3Z-5zh(~!gb>`?3gqJpYOT#W!o1SG~O02?Dcs3YNoKm-#o zC8Ku|a`E*!|J3IdKawuT#CQK2A0U{?z>k+%^-SV!{67Ha^#MOs(cgq2@H#K^z5V#t zz5WMtUmrwY)a<*;n8ZboDpUN!!vSAJ4KL0nJ`pDu*abKeU?)zPlMM8;nbU~xi~3)o z_}3)v`fqlYr}n4Ru>IsxTDJ@0WG)=Pm?UoPklwOg3}j;91pRCw$Brtu+i)glbYV~Y z8H-3^eOJ@mfGXe@AMrl&-S82&{{US*z#^Gq1YrW*uLp>tOrLjU8ZVMT)7lbM09`;- zcDfTNeLx0EEr7ljb_^#Ou;t8T@COBJ;0~{q-1w+eyUX>g=jkBLJefuG*8iWew*k)j zJkLE7TgI=91mYt$5;`EktD-ar2SJR|b$u+P7=#)M$=SMmG+$N*h!-QJIbDWvV;l4V z4q#bj@h0PL5ynlQScRW~W@D9tw7K&RK&+No!@T`xgnEn0k=l{ME zPTI4!jD$%}$#s^;@ z5=kyok@q-|w@wbTOHLdl!7~kKPvGgLxn~OIf6UWKgSP%K0c28mW6v4CS|9n` zbUwc6^~GPWiA!=l@H_( ztZ}??+IyLZ$I+s-X(erUMgVGAny!fo&M~j}S_CaDxVT(55D9M7>`;$;K@6r+2iMrgwhNe5wrGB4rasBL!4I=hBze zX<}Y6dFP}j%H%j~{|L0qYBIW>?K&`Pf7t>!nn`V&$tl@ynM2)iWiI<^gJT)clye|^ zF8lM~VjH^^nF5`14d={D!z4F+V#?YMz5;T<;IFgdEWnd*0wiZqH=-+-LV%%>=zxHR z{%2iPGl9z1km+g_vNh&Aa5u6AK}e}6Ojze~L0r-b+t~f1 z@`lQbg0gkJh$SpBoaaQ8+T?~7QYpabz8u3q-W<#u4K>JnSd)@j_9${KegRd))w65Q zX;MTl*+dVSYE%Zf!$Jzu^|CIES}QZ4sp5Ml?`IsTYcoAr6C9n!pCDFk&=8o?mY{Wk z%CpMGeI=RV2<-G{LEywF2i&3;XHoE;qVQQ=Zh>(NaLe|Fb0EBosWn?@s&`Y`I zgLM{%_6Y--rvhsc9Y1lp5}l4OQvOH1~Rq)Ryt2dJZw6d9ou6gp@1KlP<7d$hf# zKD;eoc?@=$;i#&7;!ZQq1w#cU=>f&tmY>ts=}q=Q_?;~W)?i~~k0lq7XOmsWgXI^C z^o{VP7>WNqKB9mRFnp1Osayf3x&N(GgN%-x@>j|DchkK%&y0-@BXns(DZKaA|Il|C zSG|A6<_>LeWlXFdmXZh($l4F8Q~qJjBoxpR#xhlGlynG8VH`%_aTjwXiR9J$m(X3+ zVyx}j8?Gx4|ePq=-iNCrKmB-~;~xvUw4e%Yu#Tc*z}q z8~?lGMMoeUvUcRLCDa#E8(t_uoWMR&De{Cf@CGE5Ad?zPzn0ao5|x!50dQ`rcE5r8 ze1lLf^M5?{;(%WGv)mi-JIaGHjK*93ckfda;s83Qdw`>_@y4?de(T44E0rlUq{>y} zshjX;Y~bw!t&RyGc~qVou|@#n=7W9O({vx~MTV#0Z^W-g+#~4VWkrU zkh)swkV(2;YD*Rh_^|7lCRB-SLNiPJ-CAtv*g@rDpagImXACWykB7*7rRI^kHed}O z6&(cMu;!1x-MlOgAHF8)3Bt8hXEKOVfkUO<5dAsd-POS+<2w!0F67_I1!2@gJ`pOrZ zy~4C1tBj^@w)5UJBHLCDd8Ohq;Zv{1F$f5DK3Lp95!hBVQTqH@z5AJrlm{Fm!}Jlca`XnE!N|oDc6to*V|+Lo27ty# zVIU!ji^sBuX){i3KZ;3cfqf;W{=p)N+G;H!mLq`zxT3_k z%p`5jiULefSzH}{`-8`l!%_aaG{@ay0`DJ$fa`@d)QS@_nsU&MS|W5b*f>~iiZZp0 zNH+XCb)}+PDV2=w>r#GuWAGT@CYc=Vw;Fkj8Bewd0ZD5wPoiZLDcKn|B$t&KSGTL& z@>4&9a||WxUjy*CHc7@4#5LA59F3_HZ^ZlR`$QG*Ie{bcII@s+7JR6HB6<=kg;hDC zDwBrDA+c*bT3{qw;;gSOFz^wM$@1L$gI#cjNV4L{;RIxIcCkmwiFS4sPer*cZ@pryr2e<0s zC`?h5@@jj%fjIp84D%jgZ|+3d;v}b2pNYAXZ{+y*2R&$u_rXDNkn#Rpj{qtGaJ)F) ziuhgvF4+lf=e+Lq#0qdGrbQNCCH+(EUhkeyp(_r=#r3v= z7&z&X3{friK8QaNHT7s(bK@C~xp}aqY3x>6F)s{n zQG;3mh!$?TEAvqyT1m$fzd8~nDIP2{mMuh80)@dcq?_#56<;`+CO*NMyM-U?)WCBe ztj{37N!xaekLxGWvj-6k_wt3qb;vq97VB$4O2^l!OZj-x_JH;3TK3y}I!H_hICF;Jy6^I1W4l##DGXNp5o-B3CY`rx? z06gs+HKs;Eu-b@yzjTe@@X8pB6?v9UDW)-}qA(TO;mj&PO(-xGy#^ACz3salv`%q? z+kd#EnF=VqBb7sTT<@~0>)b1~wr^YP)V5E3j@2$o2!x*Ky}df!;u65jB^&k8FEmwd z0$9a6hg4Z#IDOZW7NY}JaQUu0Ijy}pdw64tpv)+Wc4!ccbqJILPRwFgZ@4}{*pa!n zR>keG%6qf{*vCGOI;;FTm?s6L?0*RA4pV!3fDfIS zd_1D-FE3J4D^BDG9o4PM1{v=`E)G?1z(;T3VFrRKp%L}cv0?Eib!+<=qY99b;V}yM zs{zu71u%moe4C)!vh0cY9O;CVaz1w zIed+%;dd=XSjIt_ud=1E32s2nw-tewXxN*|==JdVvT9H2;O$~};Ooqi5qgq04T{e4 zA!4c*%G%U5(4DzqaRJCF#DxA#P|Wg39q^DS^4B4!3c?(56aZc!0hbMkGqEU@Dka8t z5stl4#ppcVB$b#BzCAYj6-bx2W^JMnHT?3OXNaG=`ZCwr5tO*BJb8MOf5(JRy$i*t zrYAu)GeIs)ZkoE_l0llvl1vDc3!^46w86lSj;Uo}ou-{L?hF6l5D%BGfaCe<6MZx8 zgAo{}%UjLry&JdFJr!65ga0L(*u={vaSb8cqqKaKLVw~HGSFr@ms6hrBnV|N*^5Hd+rOw96+cXVa5Bt@mww-R^f)-! zoZN^DbCEd;D0$P-a(aPl;&vtY2X2X92+}5sQX-k{?{6<0t|vwlTOd;ngwly}$}jXY z{~!iTVH^B|Uws2*^Tyij43N~Qs|uYkuMgJjUb2WGQ$5%SKl`qgD3-8EWcrWjN$*EU z;)!;y`Pn?FK$g?=;7UE$`ce7)u11($2p6cA{fQSL6v^;Y^nW#BATa_B*9-E%`ohUL1|qb@5cUE8rz4lG+7lU%wb<*w{$iRydGvarC&? z_d$fjUI}TykYwm9n1VkhpJQ{O)ske@<6!&ug|U-4A~_*8(} zP_z;b&-qirr<~E}Im2Rpp92hS0VCY9S0~E|B}*jl6;R{rrmyO)s3X*K2}!VK{GGQX zS@zv(6fy@t^5u*C-^&1?%8Un@75%U%irW`TCzPECB2aq5q#$DH2DnI+B=g-tH7xzn zqr%WW^;W=7BwKWL=bs&YMW(L{+AbRw#zN6VgNqU+s(@Bbkbt-A=wC{S>1-DfRu?1C>Hg#bQx>%XQJtHCMiy94d#x9grx9qw;OdnG;R(08)l~pwqAjuAu1j z_44Kmh?}XqarQocCKGTyJci-0y3!)X}6QGf>SXh3Vu z?M(G0Rt?YAdU&a$6RjCpLlH1F`eUaMkf7#rsfad~a?87Trr8|Ae+J{=5?nvgU9q7c zkc#Dmg@cT&-S#dNS=^v;aZujF2vlRF-Z)CWD2gcd#ukr`0W`00mNTAens(-EE;Z+7 zTG3S3BNfEbfNy4+q+B#~PgkqdBFD$qME@9AhjriPb+nbC(_W*$H4DyCIhTg&%n68+ zijo)KgKDAiDLucWLd6{M0-Wns7DtqA>^i_6F>(N(+X)|_VeuX>$X3{j0p3b@MKN&E?2FMB;!A z-XE&a>@5-@4oEu)zUsJ+K)Ea!vLnFB{jL)YYJ^hvaC9ImR<064^h_pFBO=_?_q0km zbL*}=mpD2m0>i+d=A2YI&c+mR%11v5`k)Z$QwXG7VUX;iw|dEb8le9Ct>I~xnid)q z7f;!#Hh00JV3nCu=k~2*$o5Qp_~18&>5UqNqKRtKaBZR(0$fzi?Ss6bL;J0<&POj9 zY0(t-wJ0VYUQ0*wnQ4!LYQ!~2IMCq`tZ(8U;-xqhFpYyPiPiCa=>sVkk2OJ@zy`nl zi-~MYd^c5=GNy?ijo3c^E(siDWJva68MRZu1mj@ncfJw;fSOV?m%Y%hxgHQk!(O1m z`WMbmeh}`3A9~?+CJn6hzxwV^E&b-`8qUNQi_#Vt!&43*7LsPq*>7h@6`0ar$cUuk z8AQ#DGt;x@USB1CWujzAICY%S-b}^(r(c|shr#^M&VKOJTxVxPxQLQ??KP43!10yCrv&DJ4})H= zyB;N<{5r^;1S*b+4aoggVP4x%*}e_E4}=*Vu#4?guA_1}k0MgY2rjT1><Q^fTGcfnk&E%om7t2Q5QKvJraEZZ7ME= z_k?!<+~o1$buN6E5P0#pu~z4fyh*j^VFy4CQKx}MQISwK80Kg(x*Bk<6HTwhoYp8k zcBd{Q&w*kj|1JH2Hfd^y(D$-fg|nK&Acp}h7(vc)5)BUf;vEw`R4!!lD@cT3j2e%9 zy}vv9pn|M3GUawCC~jB11Dt8ac6Qnx*u9w6EYm0lNDYkA#iXRlh7;wc7?9{sTLB30 zQ@#G0*Az%Q%1O4jv#vohVfn`;n`i36F=ZNgYWcf^j#`mfehhGrF9#t z_(K2#gt76hwiQ&L_rDlvz4Yw@*9ww>=GCG6yPQfD+X|~dNjtOZWRC+NS&IB)dmz9t z>o#yQ>o%~o&SRfVNh}FotX%&;=z%DdUHl-jI5awr^b)%8{w*+DNb2$2mTaqOad9g7 z#jzcVjse@;N$*9pFKINQQ`0#jk~ALo$U1r z+%qvJY47a5Czj9>Q(ZlGDr1_AvA~f3>#fm>YB(8)7i2T2YDP!*Dt<|lU?OFupJHco z>s@d+YpN&R$Fyu>=Gfl8K7Og|R4sLZpKiK@{7L|nZ@U5j?&<70t%TiP64INv(Ky#BwxW>Y zHMAktWvuo+NZ-On9~Uw^($_5ij&eA(c58`0?DQU%CvHY<7R6-BdLlKV6vBt5qx5JW zX&}8%Y^*$paTP;gB2vxfTp*l*UuW48Bti{tVf-qAhHYAkDo>u6uiT+Vmk=ib(@p}p z8xVy@M6H!B*?}KxX>K*!EgnTA*pR4UTye`$l9!QW#7=O{qF`ijP?02$$PC8f^4tLS z^&$<)m2-L|tg>&8-Rb!o?pFtc*8vEk8D7HQl#K3`%jTR$Qy$@Q*lqO8l%2=|eFYOR-C57rUD^{g@4!R0lM*c^fkiSOECR z5evwK4lrG=uUki?u6dQzLzT}(G%*kpy&og5RV zSgtCB>X9q}uoIi=mvWH#&$EF)c}FVCCv?w->-x0@7wvsxJJ>c}ckJcIpuLa^RgJ1O%r_$p~b zRJ#gihQYe4yrSnaz$8U}(b^HW({duDBzkU7^6D~n&#i6T3(oT;@XG~=RodYg7RO!^ zL~Ghqq%;G-+!)_j;00Q7=o}X02#L&N=M1V2!2fB7N!wv3qHwJQGZlNPj;rs5iX5V zEOB7KdGuI3CL=tbtj^u_)D?RlxQYuBEeMs6YzNudsM9jLoZ|}8yb+?DN1WKft-47O zQ>0$3ZlrjrU4H@r=HmjF6i$tTduKd?56q*_cGYz5#eHV)48{x*;KnMjv2E#uN{Qwr z1ThSq1Y9s4fsUpW6NeWQN#O!Y(8L&y=~IFjNV;9#`OmQdK69qI^VH%w``^WRFV6zYj54jesP+)RsEqL+d}?X4k*^5W#Rwk%#F-Srb;2Sy1CSs#;@lFk6hS?e zoPH|M306b;r+9thO(MJpOW`^F-cQoCi*FaoZ(^2$FouhJ$7oWVaKQmI5B?cNoI77Q z&j?CbnmfKeN(skH5mTw+%Kb(0jR0`bR+I=Bz@G=|p%)O0U&weWK^+h;!4-j8AW+3Y zkEA2_ig^-AqZ67PN=SYU81o?P5TC_s!}oA7eR%8jy~Vr+u^UdZhZ+AYzXG z*uZX@Xn*OEFx5lez|#n*PQ?I{XW~iL5x^4;XxWcE1*r>JF*Q!QxrH}09k2x%cRH%U z7-YjrRWj{os}NmH9oe=+bx>Z^w+(1!DQljuT@~qN&D92%KK3LF9x3iR&o<52bU6-& z=x7@$Dp6H9yb7JX>POk(czY00ZOAvn!Gpb%SQXT0XmFy{fK7k|nnyQ*0TJAn)?1YR z^}vaHuCdpXCBDcQNXe+uop+WTkKH>0_fdu)gzXBv3}21*pmtpM+UdaTfR{H{RYeeD z0yeibv}7~!fNb`QOz*P`MQv{jR}ymwt*(~$55iBF=(u+bxbMx5MizH3B!ID@gkiDS zzFt7&NZ4pp)$y%Ry%-Hhp|*xP(?gfH#t7mF{ooblgX||;uYknxFRc%V_npv3iwvS5 z!1ePpgOb>gGQfu<&OpJ*JMY1jt)!WLiR|FOSLdw9PqKJm|9wcTp;H1nm^?4t&sU+o zfI!JKgi6p1N1%V-&XT9c@^rL0$q)B4RN*RFPEGqfGYiEwxLMTB`yR`HyI95a9cis& zk%*^Of1t?jGFTT;2DJy4BX^rG&eV7X(UU?7B3V_kqBZLt%8LbFt$|f&aaJ<``12cU za7@vPkJ<_WMc$nKnvCsh6Q^kr#bZjE-i4L2KrCPi0a*{W*!s%R zo5%!Y@D!_}pa9<3NA7b9I;1065w)s`5}DX|CaL1mNy-&VJ2Gk^!4q15E8toXrNpq& zZfb_keB++e4zTA>@4YsoQz=rF9+~IT=b}{j3^z-oSklS=c-b zz|{#s2=M%Y(E<(oudW~XuzYJdYLgKL+in=Sa09gx)kt-R|JH{SXxW#%h1@J~1^*#~ zF&ATil8S5hk^{=}t?6kc?ehzDoi)1U{)ioNy&G9L?^UjEymo=NbDUJ&)^$A5*9SU0 z?${gkQ$44Ukn>{+*hs1puptMD=Mi$i1Ll^yzr_q&BxygQ{6(S!7YvtMCBlPTNsEL} zSX8mUp{x_TOf4A75Naoa5}Q!?cS5Yq;&jAu!ONpeetZZQnbFZt@51e+>;D{MR+DVU zj43Z8OF7?FvWYNOQT_M$zX#KMN+6!p6Q3*Kv= zHjJW%DZ^g|`@PxN>aBG6sJc&@#mGi%f0t< z<;O;eM%LhYl)xovY)FV(T$Q*|-rWVuw;2r!$Rwp5F#wrIUlx7|F@eq>mLtOhQ596= zU>UR&gBpPk>HQo0T_R;Aa4EG#NAd;kH&=FB z&m)&}_?}_~m5u2$JUp({X%%wh=rdjlwg`^q1Z)QhPHJ*2?k5gn+NSE4S~VLwk9|i& z+jD-~*}16F>f4YZ21#qxdAjPk;4df-AqnUwnRbKGY`lcM2g)P7(x@75Jqz7TNCN$U zc~H4jbhw>tZ95s;l$q{;oh!)S)XiyCK?ofg*?HvX8#h|cA8f@G)(QhDsyC4j@*vw2 z*l?@zY^tD=d5myS=q$9G9=RAg6zQl*g@Ci=ojS9+^a=sUOt7K?u83gfegc9bMoND0 z9vFK->`PJL%AyV`QTeQe{WJGF`~{ygYX}e?fD~3zG$GAH55+C#JHe`uaZ?C%47;89 z6=xf}H(#!QclTr%XZ5gW2X=QIa9D*bTaYCR5C};0O49^K^aBO^CLAAi3>;>eL&Z>W z*aOW|YW};NeED zT}YZ2Zq)CzicmuQ0GR^rA8h+U!&nqTq7!l7?jp$jYE1?hB@K(zfr}7^8-O|!RjvXz zgcXyjMV+~6wC4nzSckve!7>pKZQiW$76?A___Kg79YE?HCIP3gvJw*D=<&K&$Ng%V)bmEJ^t^rqIbLqE;PK zGowJ}49klOq8zGRfy#VoI#(I$UiC;74n}u}X+6gk3)45V_g)kGw9F%$U)YMi8tT!G zY@K>py-Q<^=^fwin$AWf0SJ_VB5nn~Xj;yCa<_4_p@|059z0Np@QxvxJ!I(vhJcMM z-BPX{Ua(DiMqlwmwjRebeV!MSsCh_GrD95bHx9_LYF9_73Z_BZ~WM-m~HjeE_ZQDq&- zBbAeZ17QoY<-!92Z|1hdd<|m7$1}W=$boUhVo4*Uxk?;v5|&1k!yjbq)F^~WC)$(! z%(s3L#mbXUorXVwg2>I;-&OP5&Qr}yk?ea;ue!d=v+kOM2Mq3M4_%^=gtg0*FGlE$ z>duVSO*3!5<#zP8eNR1y^GM%A_X1bSu+r1@u4nQlutmTWAqN8yDRID>pjv%aIZZLL z7h-+DsRFN%&`Y9ELgL|xrIwun^N{fd5%CH6@qKG4&Nj)L!CDri z@i(toLMBR1ct>x?oS!Cg$s^7rxWS&todksOm$-7uaS}yRJai<(+}&?7q=45-BP4wb z2$VBDGx%wsN>lZMd%fNJCNpw^`rpSN|JP@ZK-7N7mdYcdObhBZZ8APs;UMzKn2n@z z#9^?ljdTO*C@(soQ4zSX1ipmWlq?kLtwP(Ax`qA2)@UXcfMbU15S&I$hA8Fp-xA{; z=_27b4<7@qfW_lOA?0qRf$a=IVU_C;Ql*hzY%#zS&G*>0Y^&T2iEPkQ0V*w{;RC*` zpn&pq1Mm&eED{e^c+~Wfp8149o|9nkyhRqRA7;u*A;G0=-6FO%&>zSMwTtoK3Izh$ z$n1kk+)NN<-qdr1DIEyMdhy7G-d|fd(ov5{z-Av@Dit3>0GAQQ;wq5?TL#%9r>z-o zMH108g4e$6t(ZV?q=!sQzieOLhAx-t6|oW_4X+Ix>pgT^oJ-)As7SkYP%x5)k(71^ z;%L2>BD6XtfpY~86DWz@>1%9C)_mZ)36EYME|!%ktI*!dz*pV~)BRUI_Bhmv&{jMP z;dW!$wHvg(mTkTAOc@TJM6cg8u{J~$`{%>zYu~{=o=4cRR%o~Z!m_pzK!`_7mmNw&no5vjJy9G2P02r57GU}wpMChejwjhY;8t2GnDBw5>V`2bZVl^d zM6GJ?L8Rieuw#?4%ke!GRDb#t+a9VYWMLcqr2YwrC7jIQU8)=fT5ih*?qQ8^3?-qON_{Lmg*Y*RI<4g<8a6j>;>%M)FB+AO4+~M5%0u~! zIH=H(eKH(*fwdg~-f)m|d^rpb#hB%3LW**2OTfSl?8Nz&N}3M0gysD*vVVH7m4?`> za?8KtLaxw`29|;GwE6+@A?rrnGX5g_L|uFJ=w<+jtB2VufFbvn#OZ*>V#mQ`(+!QE zOi#sb*-C(eMa3jbZTB0(9x9PgF%p51!@z?+|E3}m9!!U2f)#hzFz9f*He4%tlz3Em zoMm40SNff?Zr8I?5tC}ucms-hd6iIkd(eEE9Ug&x#KNMkFPz%0@ht}Bl*;bUf3_oc z)p8gqQg}fx{T2XP*PsShy(iJp=Jr2$6iJs%j{Z}yk-V49awcpR&b7M(%*V1l7B|k6 zEq|RQo2#av5<1-{XU|>mEIB&UBS*V; z?bp0z%FBy0DugIXyrkYRckb=CY@)IhH7F`QW5bJAL&S9ArMDQp49(X>_P)MdV+McAWR;NNp0Sd@9h(>}~5e(3BZCp?18LUpCSFD4jaGwMt z>32jzLX!YL>DLRt>le8&>AS!Gljul(8{hx#^?@56L9uwh&W}v0?$-(&Ee31GLl`)eHdQ++WXt1NxHDZIx9wYyRhLp zn~=|6l{BXKqYK(+vEG%{$6zY92@~B8b}jZ2a5z3N#xOor_(DYCp^2m^Irn5J9LdZe2VyH@Y>&CF*&;}R|03*bE%i(d9uyKD?fqXON|A1(OcC2e z%Mm%1JgMYw^ieaKR&E!%v~cxq`h@zD1>+-#cLgL1&+$}qM7ELe?uZx$o2R$b^uJO8 zF*C2R)gg!>T_`wi;y}kYL^V`$1Qm*e452Q&w4pGnvpc`n1_*PEgq*5F#Gs zrVXz>%rI^osQ_48w{qA)5J~1_U@WhAIMK+cZg>r`4&S4X5tT2&sBQOjs2JQCf{B(X zacU<;{$<^OV1ki?Q!tx|=1tF?U#{q2tJAq$v8A_3NP^--&>O8_4(SqpVDbJmgOzBX zp5KF4BDWWwriP|^{ukdLg@(ZS(A*jr!~MnH79xet)^M6zx%}0NRorr~%x-U!lb!ze z?XT=Px%;_SzIrQ&EG2@~iwLtcqv{6+BBC>XpGbQwy^3_cK>{JL}px6Vg)<;OGpYfa0A7N*p!8^gID zz(8Po8BKOFG9Urg23n^e^gyR+06-26IBGY24^>XF6D$eA6dMoAlw5|9kcFKBEeV3-{#$rtM(H0T0) z&g0%Y_DOXOi(kju_s5-7( z-rBKSgQ+i0;d$UXLCfr>5=|=-t9QBjbHFWG6gLtTH@^tl1yl|(6Xpj@6b+V6 z5fq~;or>Zcd(L2QPHoG>54+)bBHJpX;>~ck76@4AU6o^Ouh`=_1-Op>iKM)-7gTm8 z+qutn{To=ucpP25MHjPTyv$;J5=Cr>Q|WUU^}gB59>J>Rbm@ZXl4biZ=ZLX*!Mxkq zH09;dCX_Aw6vGGzuES@(I%(=%Q)crH@DpRB|E+7Zd-5jcM-Gn?F^$|o7ZiZS>1oy9 zx)tw&KJl4uZWP=ey1-m-*bgf5g?iq#}xj1`vbjP7$} z(KsU`ed7QEVThHM^n-y{L^bK`3os@iOUC~EJLqMc-r^UM@-@9dR+~fU^3CIrG(V(J z$J9pjynOpOL$Eo9PyMIgSkR*iWgij^%Mwtc3oe#zS?MeThy~;b5~U#e3Fzh(lElhR zND2#B!kv>18^Sf9Ci=D(c0X6M9U`}EUwVs>@u>^4*%Hi>Np2j`X# zc5nV;%wTAXHGeWR!AVn;ic*DIOuvzpQDDOrq{b8y*%csxOaWOzY+wi0u<@H4QJ^<0 zKmYvmH;&d36|S>oAHTK}b=<=(+xWvCVfmaFkEf;pw|P1q-ALL}BW(Jd9!D%2;ACP- z)aDip{rNT9dU&XLfT5#RT&gHg1tetAaqa+aF9Q`x=|kTta<>Ex&YlnTNi86VB-lE{ zS>rAS684}9G@Wi~^Ef#mb#R>+P-)OUod_m?muJGp!(l`{I|=>tK~n%TEzQrSUP6@( zw0GbExAhi50<6S&OaymUydKp(wnOr4CShOyvFn47mdGAYJ3_rz!h=rl#I{LAfPWf^ zF;sdK3jj+IYBTNU zhY&6fm$XSHrsM4L?nBR1P=abbMmI3*5Xl)p*y*FbqdN`D@Ejn=F6|6UPp91q7*eni&PHE)qqOK?`n*++x_~>tWmFgmU5b%pi ze46FOK|)W1>bF#MNJMixSnuMi-m0~<#$DOeZFQ8!_fzxHJca3*0kVMVIR@DlH5 zM2+V?;S~$N5|_xpKK@C0mb&UF$!nL(;S>T{+uWd*`KJ0CHwI3b_%WQ0@ z{c|oyRFecO6zXUv8e`5v;Im5!4syC#1t}d~oW8_VYU%>aaK14?AYLQ876nivnO{`55?uk61I8PD8DfRa z!PaL??f7q}#;T7hl3&Fx$JSE0EKS{tq6_4s}ELB`I((?}$%2fOkVdurtIi2aOn z1glWZ^vvJaQjs}D1Y6`Yfd`~}I66(TvWFpNV@MOh$4*~+YC{-Lr;sOm@YfgFW(+(A ztn%v@HdOq;6e{)&;taKZOmN7KZllbE9)_WS{FdMSFh28owM~yd3!6{#c@01`%o79+ z)a@gm(uNXW5h50n3@t5}cH1XlA4!bjgQOx95vbo*@B6jgQIN|0zd0N{kj{mQi0k0o zH8enEz-8yfz}HfyC!d(y2h(LlPK6@$mJioY@?6!=&CS7uO4c z66)TUjB{)`92x~EuDJbRDV_3`dSkUH(J|Q$S$dJu>3*9i71sj7Xd=QH!$N0z$#>s> z<>l3nUjBpoy5`;2m2+-0i@?I5LYi+r3sD1k!+0Gin{dw$#vbG;QdUOkO5rwBg9z1v zCr@g;u=O93m z)!-U7_si3?ob(0_96YamEvah)&4PXm*7_H`PDtwbYaDA24hiZZc9bDbp3w?y0jwIA zrahJb81~4O>({S`8_jQ#kpakNi{c0lhvr5%cnrPNTbc1Xa1Wm{>*O(qkp|rxTZO68 zmy4@|Pnb;w;mcd{KOnuODL*I0p<_)a!T}0SoC#=cntnkQBLQ|(`lLlK-rx*QkGUiB zRt=J5>=lqp7cN8#I6Dj~ zvgti7fvLbR?5d<|a^*aSnBS04um>rGrIwjQCnRnmg}{jCNKiM_w{icsUehm-aW#J{7 zl}d=yJ{d5+MCK0yHyi4i5WwEAUeh>23rP~s@Z6VJ>omI#Cva3P^S=qksY;C*=dJgfV=P0zk>EW^!Jtpy&P zd;DJsx;818OMlz)ie#2tmHOr=_tb}@2XH5bqJN=@ zmLe+x&Y|Gmfq%g-WY|bpKrNX3aKFPAXeR7UE1@ak5bVD6UN``WjZMb^yQnhYo4gde zck3_&0RtXe#W<)n3781rDyd}Pk2@lE`WL~g!ut~4PpZ~ zlrz(4WxVbx)LMzefd4CRPL*pPE-uFG{L{b{HWKbrerI}-G)u%hr&UW#Z%Bf;Bu*e1 z)E1TtqmV2Y<4ytT3vaSQEuPIt0c9Zo<8z2b5FU5^zyngh;aG72;7;KSPrSX3LY}hOzGHBd12FJ$FnZ z<@T^!ZLu6~%bXahorDdz?(xpPxC7S-jy8^Pn~Si8ie<&M=JS9R_6lDOQfu=T_kypJ zWr0nEde)L!cm2tuL6WVt_@$x^oF~Ob<*|rX%=nAtgCGvFa3%v%h-`(3mqq$ZCp%}( zU18yZTFz&upnI7yrA&vAnx^4V2$s{$o%K_0ol5QLEha#MQW%{CcTkC*hUrRaEOT`= za*t)f5J;QEd!hF|Q@IIjGp%}mIO>jmdf$@Q0+l2Jg<#8X&#|C_YzB9`45LUQ5QYng zDv=UdRF2Y;;3IpJghPD4toT%+GgXxH`X0LP;82ISbvVaz@I{Mco zzZc#T!sQ#$sm!41AH2tv?|H`p&KsY6^)ndAo%-K6EZ~RrAL?>T<~;H&?1>tnv9Wqu z)Hj0D_$N8hWmiOaqjLJb=+DXyiR%;8OM-$yuoOV3@aY>2)<&(Px;MKH+#juYI6JKg zDa}#Aqd6>k)@Q(yP0AVwScbtHSReSX(0{Tuwbc+{cis<<&}tp|i@^(cKnS5epVwlF zXPZ_aaSSX*AQh_CODIxzx1ex{T?azgVP3I~SS=L=N9Vn66cVBtagl7j^(DQ*$Vsm+eJ>>$O zj9x*U9uCsFT)&U+#QWOO*xU~?L$W)sg)lTddIdelt#d6DXR!I!ccyXXh))-l~Ipm=EKK!*?+BqmmiG<79{{>;dC!WVPR#J z^SkvgahT6aswgdNx9~6$L4U9)ENi*dFeQH&25!isj>jBf&NMfaw3xZ|jGEy0S+z{u ztl2!vzr+WZL`(y9=|cr}@tV<@G_IXWBtL=w+s!ffCOYQC*4|@8Ty#zkC|GKBHE3Pu zN78;rcPzCz7X>C|Eh{%t@aym>tcF-pmB|ula@$NW4qM-$0I*gUAfYA6c@EKYBHoatLZvPO zzST#caeaEkF@gYB!Kt;GvKKh7jOr@a=G*)~U99ZS-VYI80UaP$0zX&=t_%~Ok<6)w zs1RNhsn;k;(NE=2ylxV{jJ|pp+HG(d`CCxOM?vH_{?-0Y7}R=8oxF z6x@zH|Kor;Tadxf#1HgQnA5w)G$;hT5?9gYC|C(SuYc}jyUq7nP@;J$brv`^y%w<* zv=vW2nDe{u`-v*2#KTChMGt2i=@YXTW)E4eg7j(Rh>_6UA{YN6w4xax2fU?ao2v}} zyXNy>R(e$GL?q$1TpuH*WT$Ks16sCOMu*5^H8cG#Wk({;tU-P7W8?Ls@i;sYz-0BL ziTFm45OK~b1Dz~q_U!_$JlWDY+)Rb&*)DABM!Wl3Xf-ND>s!53^>1$fTiwtvKc9AQ zKn;TPR~Uw^jFssDU8fcUOZG<{2QWlm^(JaWm)>ux?t80(p-c2wpDD$z7k!L6-uQ=r zn@|V9==7jOj-5+VF!3{qQ{j|?W5}efg0V!+DD%i@m!iW>`c~4$PT(#I<)c7D{@ zNRhx8uQL6<9}^v9C?a~8ghCE{97O_SlhC3EHRk=JpL8BiKSi(g8!H!Wd~U`I2m2}8 zJbH<@-8;FDD+s!ng6?+p``fo~PePZ`=-7gMDxA1Cg>Pl@-3*6{%o5)ccrKl!hjCn4 z4ud84O*q1+v;k`XYm5emU*j@PjnR&KXD_>NHMeDIDj@mrxG~38!=6n7&sQQ&O^ULJ zT{StlX_9CyUdVn_p=7i2?1#kT1z`g_3EyJt2vT{TISt!`)g7xwC5_f2I@qMxag~Lv zgm8iI9qpiSPPGEMyX+6CiX_lZm~8Dssbingb>xt3_onm zH}Yn1gq7ret+^o!CAZ^j-*#^ooOuBOL{Wa~UxKia%-BKMq@x7`^xKLv%U$ zEgDj=x#N?YKdw9NhC);S*F&R=F6Cr?-vD@|w&aQPsq5L|;#tnTW+~uoEeMZ3oK}s5 z&?TP*iEE>>`EpGJalnNf*6TIrUb$^B34ld$G6rX5dk+4n7K1w_##T6JreSiZkVeD; zK6){nQ-t8Y>c>D@&Rv|wIHLiH+r9Jmg>wQK4Fw~iXya-M zNiw#Qa}qG@Gdv%ofVT*Y`O)2*S+JmDG9#2Ud8lAi@DDg(R_c!}q7u}a{BQLB_qTW; z-EMec+y0^L_!??r3R#-cxXH0kO(GAPjy&I7!fmnA8LRm!4%Z%s=tfUGiTM$B2?z?96WCV}bR%@V)_TPY$7MliNpxdbXWp^O zY%TF{cntDrsADrvS*b)yLn%;f%qk&+TFJt7AN~QT4oH#1>fEGx1#{2A-KB6a%xsV}?}pXi-}NX(YS5 z)W=kym!h5)uNQ9~LYFA2WwZ=6sO+eiBY>3mb7!+dd+I503jcV$nM>7o87;Qn%cb0i zQ$15N5d+T)$r4c~dQM_zy+NW*sng=*eO=S$5?-7FkTAp-?5IV;Vg#~=L`p_T7;-~cen+#N`_Yz5%&vpNHyXLxQMjD8fGYkW zraeswYCxlzHe;CGNvDxaqyh_2h-`$1&-xMB3Goy;8c7OAzbgYx3L1$g8@9y`L<0%W zVK{3v!0Z!eOpC~VtQBQF6cO|xVkla(1+kA%TtlmQQJQ0mW)3l2(wJhR{lE0|v_yuCR19_dbz&20Q5Q(Jdm~wu0+L%Vj&MGJ~O_Whe zSt};Ok&wr0%P}l67q%6v@yPmIBv~ncBt-)@IP zBPXd7BXrO%Z!O(3 zxkTlba2IU?>Z1)c8c2_#fZr2>&|~qZdTBfm;Z}l{-L;iQ`}sp0@uy` ztt=*JVtSgsDYL`w#6|_rjOC`l%i2*1PQvr5D6)`(kRc!ogR84KcX0sGm0OZ~9_B*; zg>4`btcy5T0IK8*<;5d095>x|S3t(`x|5_D5}&xZ*oa=LV;<-Y7mIfb^TQIp^CEh* zFYmx!6TE}%L(LYr6iR=xs8;YsA#`!rrfUpTQjX$nkMQrecVumza^~6wy{TtxfBmo>7**>LyP*r|!*evuTKHX=fPB7X69 zj|cbn{mDQ+5Dr(cg%`&6={y6@O5D?S<^KWJ=X0q}q{bvL3RzLKAi+0*Q3%<4EK0ZR zrrg}Zbz*z|4bM22?R)PV&3)k6Rj*Yw?v_=I2 zoON)p{Q6M}60NP54`bm%JU&1D$lYzb6y5B@)U8U%2|1{!5!X_bFHvBU)@5rVj+4%R zvS_B7dPS1ojEg1orp{loY3EQ~%4da;+((!d(SqLmM;LrZe-R;p?NkMAOb%fCv`r`i z6cGwpt|dsU4^bx6(Q!st!WoEp5^Sg?%_mtHWN$16>H%T3%iRNIpnG8ZMJ@HYM=wuX zfNkN7WrkTM?#Q_)s9^Phw0S{Tl~8xmrk$}haC7C$^?8QSMkR6^p*-S}be6}vmLPOb zNAjnwIlH4}8=kvcSxAN%JJ9%46U4#iwTgjml5@iJ(52w8zBWcEfP1nqbo2T#hI`T8 z{NR}*&vQeEm;f<^mu~Mu*b^g16+=uBmq@&GyLmv~Mz!nzbmooEy6dSs<~o3D{rO$a zP^LYLxJ`_Xnyb^2dGw|yuOA4>UC2}%GR{Z`phqfx#6%0HNYG)Dq*`=VUBoT8)JaeM zgjALcSo;dqhg*=jmNG}_{!d?9*1z_Y#>$lpL7-8KA-8_)%J5WbovLt7hkF^CDQc8_jYlkq>kO?-PJ*hvM%Hk@khbSE;^dC z=oayGLiD96Cc`cTFhI!jQ|9)Of8Tp)d(-Hw1*m8HtOxDIjm}1x8BBB%J!)G%)0%|Y3yNnQBcNqk-<2JQi$If;7Dvq@C#XuC&l*y zYZ5|O@CC0SR4IZU-?D&qG8)HMEWCQWX9fZ%;st)E_$@!RI3!*P^-HqmwQoIu4CAHw zcl82(>^LK*1HGI=Kl|#h`12FI>N8J4C2hnc@GXwH1-(&R1_miu!Wr(Fef!HYNqw+K z0Gb5dq=^1kE=P7~{9eL%0H1raBV#r}RTPV|zXw%=F!~Z#()>D%R&YAEmXDSiF z+`BOaB}8-xcEiwv0L0dkZ;Kjt{=h=I8QF(G&dv~_Spy4?Q)J636xdW`Cqs1^SvpZk zWdWFhDse&%gv{S)xlM*c_RL(mYAXQq=26vlf03un2OQ$z0Ie7@5P7&$rBYJa3hN?W zJXA-z8nNUh4N^56O(L{WyF*BClI%dEL@l0_0zBl)tZY;aALGr8DzCCtpf0r?nuZU4 z)7WC*v0IxsLWIKBE>Cc>pNM3dBqK&Aet6@tcVbH+vA&Lm4Mf8?VH$$=r~7f~BDDqB zN-=atNk7fn%B+mG-$NkOiS^Rm%h$*4o!`4XB9D-=otHoJBAESZ7#Z@*>uUt z!VFMiLi9q?cs^zs#jEm*@xjudMYH__tjH*Dz(CQetn_)XT=SM>?apoC6PW(h!(tQA zYnwj1wwHZ&^-LwQC~CX&)lcsw6VD6^xs6VP{vwNmsK>TOYB*Ti{flm?IK3gfHTAwiQF6vKLXSl zI>ne&f#KKqYo)BEf77jaJArse9Da^epNSUY5*Y(!e}O<0%0b;`Jl;@|m1 zBycs!Je)TqR5*_%un4t2CR;fqfQ&gp4+w=i7g}7C*VUu_pM188|7V>H}oA924jC)!xJk|{3$5`VrDXL_&8*zv~&}^%+<_>YusrmtxcxEA1Qnit5 z0$t<6I~09y9{^V}mVpNdJcO{7=*6O033)0VJJK{@SD~#z;#fHxQAZ0o&K&*MkF9r)Vj1b zK&rixErnhpU2}L|yd$lg7np_1nFEMVEB|WRE0$6@3pEQMA^=-dlxx37!$Umn$@vcq z$H$)3Q_U6{j49cWR-9o27VhkL!1zQh#Ps={Z7@Ajo+{(qKs{m}&^m}frZsHj>#?;+ zBwJk$pCEZxa|or~*>vd?ku#5Ym84n7BFavPvk`FNGNw}fSyWxZC`Q~^DkVZRru)j7 zCw|5VXn;q_vitVGHEV8PIiLl@ma$pliWTPQ=y-t}Hum;iKJ+u_0wxMD)X}gC;BlV7 z-siv`2zeP90DH5uZ^j%ZNzbC_6ikAd+N`O(t}KJWIJgqHfxilvks*;p zmlTPV@iI`H_s#T5=YRJ!Ll=`UM!=ZpDUx|ff!-6!5Jz4yn#i%0R*U^w3O(0Cyr4DQ@#@k!y&fi(Fc6n~7X0x;{5)_CLs1!#W`7{xW-Hh%$ZI>$P4!K%V zE|~8Gr$B;Z^kako;kBPi4+B&Qkxco*lBFi9=&EZF-Sy|oV`Jpu#!SJX%nzrw++d3c z78jvOXvb7DdGH86Su~2U6@Xl>JOhPar%lRujafXxrcz*P^9?Vm;;re2sNv70RZOBk z*I!pVg8YP1O1CltRe&ku-Mt&mf_=f{Y_N7_eh-L)ll37ridx(WbFWAMQ>_=A$4UBK z1b>-mjz=B~sTRsIh;cB*B(oD%k?b5B41X(gVT#ImnjAB(<~dSWvC|OI2D&(49L%c@ zxsNyga zz+^Uco<`2edz{l?H`r&Cwr935VFFUj=;GjU00})RGw(3gYlA5gP} zyB~y)+W=_kpXSbx#GG!X9Xq7#B=n4?A~ zGfA_tJGKNDKaRL8H-79+85jk=j34H&6|f*mfRzo{sp64(>phy5XC< zfeKN~8qdmYESlK0i+`pE49DIbs6@0h?+s^SJIRf`h8Y` z;hGB)U#x}D-RL_`;yd?o>cCZzYeC7>D zy1o|Hn}xK2*6~65a?#n+O(Q9K4)HCGjciLkt~^Sg--tSl?*;Jq^*~KOoSQLe^jDgv(iDG{$u8oPGD1i#xdyQwh&@`l9Ov%lw~4)mTTh0Fz2u;KBaixTy?#6I$8})ZT+tN3N`{k%L*x)wlpe{yg>Uw9rk=NGw~-e`MWx!nvgE zY)K%VZW>ED(k@?Hz1|-z%1s;~ooOiyofE)G;V&uXW+gF@vYicWj=4GATRMGyL<#Tya_@4w$v(L~Ejv5Ob%P%xnL^$f=2 z<(tB1p~)~NXGkNVko2oJ#ryPwHUS5I$;v^&;}m&{|KTU;U4bfI-3iwhv?3^3^dN>Q zZ_~~5lZ}Jv`^#r#EXd%UNJ<{8|BZ~w5(aD2wZ)+h_dLY48SZ)RWLFd51P?#1wo{(D z`dkn($%JG2h(0I7G4bBG#BezC)92BhM6vEJfD!U(Fv=o^SIv&v9&c4p!U2Zu@T5Z@ ztrvTCJYOG5|M|i8Num(|M9LAzH!LsAb%;-HiBXt5EsNqq-EWge{4kBK7_^%)tD+oZ zDJKfDRgt|iv5ws9I-&IkS}9vF%uBe!6_yf#G;2YW`C2CsNF#aPlGmzAv5EH}0!F)n zuS#=^6bS>b{KJw@IP5v<%CVD424sGdW5c3;yP(1;uVwPYe`ln{Tlid znif%xhSjX4=SZ_BBtcx88|eMB%LHg>+kgau!9Du#&E{$4P>iqyJ~sjy0hhwF0uu+V5S!=3tMj^*oMR++aT|%IE8C|ZRtX`+V+^@lLOB@aY5b^Tr?#{d(;XStFh~qY9x^qc1CrV}Pl_tiH6W|PMC=f#60^n$b z;^)ke32;|?{{|6)`c}9UK#NFs=bFpLVl%VlH09D4L#1aPFgWVsTpw#4lnrbm5ssnS zMz^uJEB9_Knf?)_ldK*zKj0n&HTKv_02n6e9P&mzB7N%}&&1dP-B~cO zS*KKK9m@n*0yLrKCR_~N&ea&J>qRz(F+oUSEtJJGM+AE@hQ>76x`!s~02fKP!m3HU zOcWwb$Ei{}FG@EbA3V}^{y@A9xJ7S z-yr{f3zwVImv@TW*~7y$Js5h~w6&q5P1a)qA#mwI=aAwcBM?6FCIL4$RFvI@v%I=r z`>DC>KseY!nF`jPc$RnKj>lb200|nED}GKay&kru%nGauh~z-$b)zn1q7ksu%Viz&I98zW)`Ua0iAfWz%#H}94kq4oGdIev76p<_6M>K44>$pkJA?_UJPXl zNI07>6e|P}DKKV7f#4;V5H`l2;oh>Ptt$HW7NVivjC)hbz^t8QOsUB^&`hy+=oXEk zm?i<^LN7f~K~UVid5@2^8@Oa#K_jQYh5g5WNo7bVvo@dfGu9X*(ct%!F%lG^HbWjI z+vlKdXbOn&WrSna<=J{vVCHnMReZY`4pT#76AwkpVGX(boWDWphWy#|g?cv>Dw4UP zz@-=jGpT3_z0uS=US-IB$SxiY(&~{ubnRUNB~U{Tbjg&zxZ+#6gtq$~{8Mkdlr44^@}U#qCU*2DYYajJW~(W;l=W zHFO@nZNfDPssM~|8UZU^wi*&&%i_88$eaYuf=MZmCH_nn_KW9|aVq1~O#mH`O_8wh zS|~E%p8}Ip;5dSp$zVd^Yrbzm)slTJc#iO+1HD91NWrc3qFO3OpXz?K=ZD}%P|t%` zN+v%j4*UM$3%J)+LRe8)Tj4R5p25_Ger5PCFrQ$K4lVl3spk|hmZ$9z75<)XV)54U z##Eiq0P}SZ#{YA{q;F;{vTeQFiP5~-DAd zaKhk>5VL%dmP2*|3*ZzfNEmg_WSe3yZ#}hkc`335<2gNxpedc>(O{5=Q8ePc$lYRA zDGwL&c=!fGD?&LQvJF@k^j4hXw_>=d_5`#+X9Gj7VAh?s6WTwVShIC&TbMv$Cl(P0 zg+H_|r6RkGaC0LFC1M89XM&!E?zm>ti&qZmYw%e9#FyBVa?xo(W3A)k*#XO}8I`V; zWN-+Hl2{&PXorCcXTBC27pWvv9Im%0X0BtuqM@Baey}K!ep7bGOb;32+Al8J6v5b3WGil_jJ9C%^Py24n{3OMb_2BdzP z6eIMqGsOj9UNy1~0+b~a)g0J>)JiOQoROuoXYp6t*G+c87qaC-c84 zY6OCt*HpR!=bwBnN&Qx4=6Eoqo`ct*7s6x{_(xcxHo0-AMolhjMyX_Iz9T=UHUI~s z#-S1@jT&kN@C0TI97)TR>OybBAWafrO~oS|CeSJZeaYbQrDe&^mOIS})>I($XoO?| z$ZTMsH_@G|2~>_}M+e<@x<%@?qJjpD5UP+dAlSX8qWgwFA7Ix4QMQ%40JG0A?fBpZ zY3-GA=57wwF-2w|jL~xC7J}?3qjdlF;f=92h1&O@AXrj4Y9RRY;Ipwua8b%Cuc8$0ML;c7w!rphh$1#FX7 z0Le)0U#H@hJN0)QFl%87Qz8D85hafx>?nhIIe^F&?M?8bi^HHQ`QOEZ#GBKah`Dd| zmH_hBn5gCM;t~im00%zF{!y6+WGDCpfC@Kb7f#&vHl~q1Pa{?ydQOELh3E+R*Uffx zUm$7X)!15&G9)o0WLzs?Vt@>gpbcq}3+ICy8LP+V+^KdR=H^3uZf8I<1S2o9R6wh( z0_|Na>(=f=)IO6BGc+11oB+N&{VmaD1Q;o^D}W{+IpLH?vM+}m&Fw@PyqimaI-id4 z?qeYV6$2UCFfAr#wtoaFZiSb`eD9T4oCOdL|!Db~Ga>W$#lkUWnVFNFg%I@ff6wG(`mWqKY>uK_*IK z#zTDy?n$d_pD`~vp)wPAra4o=ADe=Nu6B4`eEzh_B zO2$9oo5@NPTmTH$sYwjEUJsM4?5op=SAjG>i{Q zY_y8}5tW6`WX9iFJrXsuH?d`q$E0X9PuX2O_aTkj@+@YTrq!o;E)SX(gpD@G5QBL%ABMB92Tm*csp?uxa zzs>Xxw%#9S8*psGT&XN5$v@mA)6M)Zd4D=zBZVao<9TLxfj{W)W_Q3xA(&r9myW4% zhMI|p@k!rqzl-(}6vHWmoo;Tq`F55c0W&B+fi=umArlD9{F3~-DHVgz2v~{v0K{NM z0W0iJQyj7b;_K0T%i)DJC(P8s14uy5FK6_yH$Q7zTq++%Cd{o2EmNe$iHsA~coT@6 zT=YjTw|xBZpBl$YIZ0oFMU(dJ(0}j+dgxInACMD}+~GAxl5oLL5lyCv(LUVDbWe4p z1|U`lEk+cj*aPWXB|d3ZCq)zILwJHAf|0N)z`>aEQf(kD7yB|D)Xf*oRc!Q>3rshm zbxs3;gP!1pQAZE}0mD&2;)NWpy-N114FjII7`09(r@FDf;;AO2A(X6uDEJZYJak)g z%`-aEhShLx=pJw{3G+2V3hU}6Q5;|3LWp^^fOq)OWa~3OdaQj%tf%r92Y;L%xM-)L zaRlJZZ%<{S!fZS<+Np@Lk_kSc*4oWXasqKHM-)?yg2)4r0oGKOw&sRj>Du2Oz=fa` zi~xuZUIkQR4&kBzz%b{@OW2+`u#{6o@DR^wC8JxeBupY0NnC*0%5JEIuGGGc>#`1K zV%{>bWc0U5)y1Rfdqiz9N7<`)VQcBFkN;QJ8O5SBag<4a?_?Yl#ZRPRl`+*XELLE5 zIZ8Eh87T+gihYFbMwJU0QD9Jf=Kcj;Q?|x2R(54_&tXD1r_dc62-TNWZ2LtNCoLp? z{!xidyZz&wNvOKnj0nxa(n{_I`fp`X7@F@`Fc$m{OC00}Har)32Qy#`wB4k(0WuL5 zCnR8U9zn6^rOUT5kTLBQvfJuy*-)%gA5;!z71B@LYDtSm_%vhX_?Dkjq@jSVW)7|j zZd_@!59UWd+?risTwuq0!WSN@(`)lNp5RH#DZhIuSpsP$sb-4W1O3Y$tJVBqE_Am}D)v#ZXx@-!HTMy1NWx4LJnX1G${TNOb%ARUzl z!NR1cZ}ze&e?>e`9YIO4f}vEQaI!ca1{)(t{pU`8<;Bj?%cnkb zN6*j$h+bZJyArc&%v|zgv*o_Efk^FBtbOJ0U&j zoGqPHO&)@$JbT$3@aLr0xHdq~(`QDh%ndJIbg9@C!ZM>hCOun{x`hukto=RpE>rRu zIs^aGaj#$qOjoosh=9pc8wO#gQsIbLkPi<_r1+imC9?tKch2|GhZC@f8mo{#BDCn0 zAP97lQikUC?82=5e3#XUcoQO4Qss3Jn6(@W>8?q6>~1snW3WnoMj&Kihmi^SH1=6g zEw9{GPEV{g0sBH6Cc-wJlz#l|Zp}6zQ39h#8U$uL=g307woM9@|5G{(8)3dm1<9*I z>{%JHDSY(ZznOJtq>|aC&YcL2;^j-9P>Bn8vz}-696dj{m4&cxVX)Udf)@HebiDK< z_88g#;;X124q$5;+s*eoNkrQ``1DLuBx0}T)T1NW)F!Iae3=ioo(RGLU0#C#gYZfn zHJSE7qZg)*4CT3G+y$YF|nhm6Vo@RF=)E z4YS$AUnn+XBq5FkxFq7Rp9XX-ft8{@psbSLr6KxtesWbW5}#{#hc<)&ML?ofx22Sy z0j`iN(qzptQVX7^dEY`OTo93wFa~a_19RuOx*WK*BW5#VdB=6CZQ&hgjpa=M#bwSr zY~SGAMj0CI>l)fF1SMlxQfbo2g$?Z^8*X5ULW~jn98!F>13>2#zW=YVvk$Ja&hk8B zzyt-ZfJ#UjbIHv>ZwmrOiCvUsUPcJ98E9*}hnLk+(`6V32zGasMY+=rA{RAQP*BXHqYN1t8x z;Yrr9dZi5|8e+%`Hw!@{^@(yzUP)s;=h|9@)j^9#b;@3KGKA40kzHY&s)z{6lif;; zMJJh}VL>3A+A@XbNIc9pvj-Ht5T*YixPmNX|C&cO`C$9impX_~J`6uy#kfZJ_yv?SiG&no8Xw!$bki(lsD_5z5itc;Q>W6cb{sLoWbYGZx znz!oSwqw{nuN77pq5Oz97Oq$(ELs6N!HxJiv%y2iAa^Cz~>#9q42(&N^~!9etr6T-usk%?tUa?68zM;xBFHld&jL;Qn z{O0D6{-Xod@a9_E945qc>1a+z*jSDK;giT3!S+r|s=ag3evDjHQ{bdIu_>EsFx-!Bdl=2g+dRo;oNa;fU99qTcM(q4G1Czi@ghfHbRAm$GL$J9t zqD&Db;USoTJ3oNoPO=^W{KCW}c?X!1tI@18!qZ|fk}B4NMI+H`*K*G6>U=W!EFi{* zqmm78kr)C55^yObz>BE723{@(Y=kBS`X_@f32u5I07)$j77F4xLP_Z;`o``%l9or# zyj70Aw6I#LE!+&+i=KJv85C;bmLi&lX<@Gfj|8LSAJ1e?=k(!P=)T1uSFN9D7_~1) zi0iCb4WWbVMXpA7hbKGJ(}`MI1_#^))k6ESIGd)h!SXU)zu3ZKP)h=LrL5q5U>gCo zi_qZ}cbQ>-jO^`PeE4#2^jz*=qEcGyt0WrFRG|hOStfgiDm;b&7-kW^Gz$(C#Qy07gb8mZ!s?m-y-J}6>s?@eOODDttIlJgD<=XzWtng? z5576#f9Ca*9V6uyYFeF9{XF~8v3D3W$i(kBHn0KHKOtT%!q(_$z4u)54v;v7Ay~3 z!j-t^@LKLrw`ZQwn`8s0ORUf!*+C&G8EV}i$2+$K-t1mTUD`JN_@#MKRs?({v2!jl zb)XaWiA=%%f@q%||9?0IVlcOgC21Tzd%d-8HzjPHo=&^FS02^;3J!mk!0^Bbv~nf{7Xj(r=j?w%fUxB;F@#6acMgo45|)?{TReIr zt6s$Br=sXF=>^?e;1Y-cJX!K(@l?@aOHbIaKfr(q3i__>VZIHBq@R)(kef_W?d2ruHK-?5tM&Oob+nmcPXe*wrF|+I7c93|1SB zuEG(Jtf0Z=fN7p9S2-&wnP6YADk+JCu{W4u&2&zhZM40Z3ESq}*U<*b083;`1~HP1 zWiM0lu3Wu(?p!a!ogi$Z#||HgE{p3;2FOIUSEo#cY#ceY!{QSQfvVd zNmcHW>U5{o$=x&;Vub*!g?A#f0aJCPFXINd)4c)lPN#dYTCFY0F zxQEnES063(4joAyfBC_YSQMPbRf1;a3U&!)Cv7CI#$E$j2FN`kM9sCD?6G+M%VLF5 znbGpwHGBj2y38l(z|tF-|N&__8pInsjMIA!yNBuy{y%tMHCxo-3kV>4Z} z`I)z4G?P`f9O@AE72@KcyMU4Mk)lgVbK%i7DA0Lz&(;ACzSaOL4%_xDG;p zM`8VybuA1S68gYN#crWNPI~|mNSegl>F2~swiF&uo8&uCf@il3Q?UReNLseCd03DN z;5pr@&GoVi74q{IoM8Y|rY34X;CN=l#BlEVaFHNULL&AIwenGkm^w6JiMV4xiHsYP z%?Ps2#Hi(rTw~}K&O~uBr-T~Y*(++ zInF`=zhoaxGtrQnNGEjt6{(2;?ThnpuLHd|WxZJPH`>UF49@nd7jl=dDa?c|)t;z2 z8DUc94Mo_%&8?B0oHUB-0beEE8i^OioeKgnVTf}W)au7_pKbo9lwr0eSj`fN~ zl<~EmazzeB5OBiE9U7l(B55D<|EWtdkRgR)f`?;R zg#1OFh3#1qFA%;|tdJoNe%11#QFv8^7R9s7K!U8w=u`14V_qqs2vFmJ1pnacuU)+a zaMF8R`)`t6rf}0z zc=wGAgo;1VC3G$BBq{gIOV|DU|AsAmSpE4U-X5q)FG)AM{cOC+))h6+gkd$e9epB0 zuNTC)_dNCjr7bpv$CP)ZZYXX?JOfq%=djE1A>7ia8hyVAzRW(h4ZMgAtJ%=VPqa+@ zH*m5n(bY;AmKO_5jOjF}=rKb>8YDe6{r#PWLDH^>Bnc$BRm}77502#bb+n~4&eLj~ zL!plV(qTX!Ve*d@F3}GAXDClR=g7JX_#?PQJ&DYXEHSMdCxd3-MRJEf@3Vh@GEtfT z@O~|R!R}rm48lR_u|B|=9YJ%aInl;P!UO`Oo6rF)vby1+mG>^kT_h20M`-(jDydv3 zCd#uqnpAFNdFi9L1XtJpEc%7HP!ABKiR`v{kouiXQPnG#5Gsxx_n%vWqM*P9pet+005@N%0E@?khGKSdF)u1j-#K+s$Q;v&MV zp_?pvL=%o{y6$MUb{-71_jozEvjr@73qw)noBR)d<8`zEI79>D5fzQ$THdEC3(g0y z7NyVW`Evabl!ABY-HP{2aybl@*n^VCDhFQ9;7NMI;zq(l>8@$ zdn=J_G}wTQsG;R8VWd;raf<7>Eo{BgmYc;&NiQyeBLI0yEO0a9?L%mOH;!)^EAImTmYCJotK8X&mXXxG={T0-4nHB!M zpdPL);10NCIhAas9VeB`slI@dO>Y@EPtT5n2PY;WDQGrNheSkncB+0a*D%<{WKvkO z3INI0Cj*28!;0Z45Dp2*f;=@8`oJzU>S94QHjuMFfkibz{^P)w@bBS8M_qQx03@$gba-PtdP)a8gW5Cq zOyy0_RMLaB``eYr7Ey>h^NYHFKF>_QmFOg%reX(2NOP8LXdtE>vq4;_VC7rLzT9{A z==x32F71dqAFu3d2jbXzXZ-(_kwCUg7&NRbGw{))j)1&LF*P}!Mopo2t{g7qY zMOpKdV|MYI@(wNe=*WkFdAO8W(9B};1X2Og7`h}K;A^XH{NX%-P*f?Qyg@qK`8b!7 zDj?=0aQX~qe5SJUwgqI|KK*pu&wrcU6waK{uGsOGen&0S%*{*-J(&@1ryY{Gz3bWA zs#$4dJ!@I;eC%SXFNQ0Zbnu+fs}{f+F-9iQ?McJ7Jav|fcp9^b+>0B5ACsyNm)t?b zxINdU2hz;?l9V;xJ^h`sN& zc!RWXNr_4?ZT+LSh_ z*gMF5KtBlX_!-h3@+?|&)yUCW0S_Dr3X5}tWi}XETzMucs#w#?eRq_B-Fo`pbEZ%_ zPHK@@1rH-%vYQ2vAqZ<_)Qh0=MK%M0HUNc^ z4S}k!W;@~Ti7_GY2L^9-3=9*JeT_Kg-|+V(yi?ja#lJ&_OUe+*RM)AzgM^+XC`NNq z0Pyad_99%GzD9X12_`Q1YOY8L^M#y_$SR_`2+T$2jRmEXbvHD~M-U0=Qp24?G6&Dj zUCN7CDHR%o7zDZYcV$htK^8nXx>=JYPGEeZ4;#ZGUeGmVj4*-4j&-kCm6v=t*yw0y?@6eyH- zG;N{De!6x|)1sVtxx(te)0~2hDbw!a?r`36^dkf%m7A}6FSp`O?j0`w`%L-l0oWEE zbI2cES&^LYr9WIiEccj2MW#q;$>PVdijH?sjWrQ8Z}!tW$I;DZm8?0m+Dy8%^ndHW|jznQqHgVCxa+9K25AL2&4xxlGV`12qCK<0(qi?4p|2R|6N+vMsX}`o!#I6+Gn>H1ATlycDc)yua?b6SYAqy}ACizVH0Lcrbz|zRu)uW--HpL@Vg1acRDy4yu-pZza7@#dD@K zEY;Yb(1DS6CZs3Sfzcy%i^R5er7gs`0W^eEOcIxfR8$IZ^AqY5>8ntYC$>nk1@&1o zcg|sMoB;J$A1HPt6{)Z_>T~UHmB?%RuY{5S;Y&~mva&Ip88wFqb27mfNJPZ#=a{t+ zmD@l(#PQ9WFTOh8U{0w3P^BIYp59n;u(+LzW@_vMMpZ%#gbyBu+SAKH+7mKpZ8t(D zFy=YfmDCG?e24DF1c*`eeZra)!&9r z`65#dQ@!b*RU(Hz&~EVraWK`yyQ+I*Akf|%)fKC?cE+n<1a?GKZrVGL9tuEyAH~VG zLn#b{J?Va)(P4?S(?&oy5|hV+<;u$%cb)GH55tSDvyRdt}Cq z^C^)zM60hexfLo@@Wikci_PC`umwB*ILce(-`VBXpyXPcE4C7*UhX2PL;rk%Di_?) zmdQbHlPUc2&bO>wmwfQ`mp4=JPPanrHa=MARn$9z*!aWiuEyL)Qao+s|NAIr-N4EP z(FQ=8Xocnus(O0Kq!9Ox-^S|CvP`+WV;+EA)M^a|mB=)wO<5eFM^CF^vFeD}3WO3Z zTqrQBFwFj}ZjtW;C{+5ey+JLoX^qCMML zVl=abKh% z70KRjfi!`5wUa?~0APE7&clj|$x>HrvUM$BkQ(~dx_`*v9j zcfX))_k<(;BbHnR5H58+u?B3HM3cqbQB$FXQ+v4|+x|V%paZlOlYa;3(aGXq&%8At z`XabVYB$q$T**JVPqX22W4U?fS&nR*Yn^8@VqM?RN+km(W4f3{d>ziT=vDF4WL8e& z&~{z_EflYRetuQu@NafKzvEk=1-Oh{-9Hm?x7Tg@uh$iO~mfDpV^&J@q^)F1hIutFqYLQW#D zQiKscFL82BDRF`sqv$1mtN0e9PsgK?r?UkZll{pM#@H;<$Wx;az79kp&0<|mniUik zHcVq~$oi@LGU}5{Z+q>%OSD({PVMoZ9_OiLEZwo+aaM3mb#w>(*Vk9a1xwJ+Djvr^mws$wiB*`3Sfzx9{mjwcPD5Ny9Z*u{45y1n+q1lm zp49Oi>@K_LU%JZdk~?FX2R1Cs8kqT{HjeCp+6IEz#g%36Jd231y{T*Za4S9&0|NK= zoR(#lH-1wSG7?ZE^W{H?l5-WlD=Y9It3LD)=J z6fidZTOA6bk>svnOy~q>heCOS-<4~cSvN6UIxF2{_pZd7k)61yxA5eXpM0#s3|_=A zSD+E*W8yDyBVv3`J4}eSg0HC9F|NTJh5IqF6G@@Bs5qsD@FN*|Upe;6o+O&$kQ?}G zp*G+dB<&moAV70L3pk7gA~9kZJ9(uJ2b`UzgNVnvW3sr5)Rh*k1#)&4_dUD7yGX7R ztkU$`u|@Leunlx+!=}d4;Z53EE^IfEUFji?QQac-h90YAkmm>cTi<1`@Z90cQ1<~0 z5UDv7+i}+5NYG%|rbN?Amcg&^6qK1l*BtQ;i$j}Z-f%-Qn7;qTgDJDaV)Q|nywci+ z8Khbm#QGHVTqsb$v*xuib;RxAf50VnJ)x>Nrs7WGYG>_F?0X_vqI0q#GU2(>1BV5L z?`rI7XBF3zY5)hpy|i68fZYe9A$Q?(5liA>_*J2fvxZLKLF=XXG{BB)KdS5!iV59u7*M<)yjy>jSBj4QB?s{_)isZ8#7=?{ z60=!u%FnV~3#?m8YcE1k<*+AV)J_tqg7ae61i+oMmX4BH4&nu#y%J67Kk=KQf~8?!~D29AU$8t@3GprFc>y2OKK*3`rGRps1sVvF|)5H zO&uX&(Yyv=*V5R-^%ER$l5MjfARWVUcVUP?AWY!C5U9#=vBhVcZO55%b#!eg&J0`F zReZFYmKP8W*^r-Bp*kAm z2s`tDL2J~o1g!=RCYH_jg9tK5{4Qt2Sfc8_j zf$W_CB{ZkR1@LdV5-;Oo@Tbz($X#3mI>ss^66b%-kCV%Pnr378e+D7vXlpW2UW5*{ zGkAJo`|zooNe&EAf`fYU#A>>>k%%bWvxR7OwQ*DUiC|@T9?YU4o z8=yjOH%f?Ab)xb_rs8kh26wUv(&XuOO_y!|b@7f1xrFkokz{x5ejZ@JtO-xS_>K?H2Giv=H&@nmOAgWaY zyb!uzh{zhS=g-CjJ8T3*%5uI%ykag?zGIs0rUdwE>gowiFwfv01D)NtI&A}Y7|Kb5 z!0DRj)4b@auLFAa`TGwzafu;8vIYNaQJVPnxr= zO$g;td`dX57B-gD?QBK_cbR4vh55=BvnTm>&DU4DZWL}%F1-+-t^FjcF(*lhat?kc z(%5bA@jHMpkL`qjWd)cu%FX+e_a@Xo?U*z&Ga?lNe7?5b5dJF z#c!g`iKY~S^zKeD%TUQk8>s}Gzk5Z`{?6p3WOz%z6U|XVl_w! zfbcTV7zr_ONwh#Qi-q|mg9C4psv!9c$S92-&Yc=j+#lW%52IhfQvxZxV#KNDW=ykG z%E<(e-eiKHoVNT1&U6Zt3jrn!NeB_!kiRMT zL8O9n!;(^iQFcsksy5V&{Hn;^^tLwBONEwpZsc@eNHubk`zO>Z_gG7T4Zh&e0h{Kx ztV@9|ol0urVkgwP(Is`qSPvXP#azuHfG>{Ypp9L(Hd3^s+rll&@$>rNO=54!v*@JC zabpoH(Q0ua(bZzwPhF4CaN#w(S#(0f4V6YoYmA-d!f`wH361@>nE!qUw5ruAgtc^|Rk)I31Zridm3xQTLb4ED zJ*NyH7=m26SIs*XU`Q>mt^H^}w=9yv1C9zK@0YG9Oc*9Z#j_BC<=}|Gnd;qIEwYm2 zz%!bJ9YXs`wqPK)0x#IqcqjK9$DfQ8;Szm50;Pig`B2HBplGl&n5r%sENMd=)}cIF zLqeZ;#W7TjNdPQxBhm5^5<|q1P(MZAmfTPy?e+AkQ>-N#1AlD&gqCNnM5I4j5ZI%p zJ}5sMg=|}!uXslmVLli}b`7ODem{5??yDYpZr((9za24qy%*Mu8+h7&MpV+nt)9*` zl(zs1FcPrOW`)=6$MxIu+BISXf}?@tTO(-+OtB=7_PlI*Q3)56_%Ad{Os$5*4`kM&E42MZL$-QtK>%i!#o8T$8M5NUc(L$=!A zB>C#1n=*S)Bp`}@3g?%ie1dwC80FULLhkR`a_YqH$3LV`J|!HxcAS41b!wg|h0C@a z-(7LTx0XzKDB941P543ivi3he4>qv92`LcjQ+J_lwNX12AKRbb!ARvByT1)^VZ;n| zH)MTi!eJdUtxprVL4GHzyeXSYnFyX3Jp_jaN)QC#I7js$q%(YilM7-cbGPJgL^F8b z(F{%zDipCs0GSchYxa)mMG0eY5cW;s&6Av^2xr2l$7g2VokL5X`^OJV!=xVyMT80F zP<~jt@7=qPlc|~XCIbm+d(z&?_ctF{Q_cGzFrkMVDIDe;f5>N^BGZKer=t4;Lg3wS zB@DA3uBsc(RaP>cC)4P{i$s0T=*5k+P(wa_Iyts($64=c{Iq@Hr_3_AFTFKK=e4~V zDJ<-(w?q1ZbH;t4KL2ZhdGnRedkv{)JzM=yU!$zlQ7JHm@6Rr*49p0J@ul-Xw(92NwI*g9ZRA`Z8iJZ(VI`71>Q#yMm+r^U2>#jxVKEt7~5bq zVA?%%nAf07{40tlpyl;7I2dfl`_aNYv}&Ow(Cm;gHV+g&2{PqNY58mgsaomn`|4+n z>sneUsI#Rk!Au7au_0&)8N7v8G}J{@pI8zZ)+RV3TF4(IvLPz_!}OEE^Q*wf?1fvESGXCO#bc!Z(7=gj@+OEYlbb;97VXATot&o3YEx7JTnK**Q9+G)$gSm z3~=LKQ5Z9@Ww8k$8X$yCLz%)S#c)ofXlZaK5f~R!W!Gs0|Is*Xd~=)m;TCkxT^5bA zGlU}hjvP3Mq_uP{Th?6#Pz@56?PNbB_Jo-oDYZ=ON=Xkk2P-6h#%`gsE1?l?tZW^x zW@v`R+;+e32Kjal+KcMH}(HAf&O=aeRiP)Z6FTunb zcxOZ0CdC*lA5WME6%7*6m`#pBZaNI@2QG@~`m>^5(h-->agF{NMPo6w5hi_b5B;JifPbrZ^x%_Jjmf%e4G(YAo z5*|*@$VQ<5&nUQT`c5Q%?fj`STcK>)cS_i7_04Jn$uLseMlfs@^Xj(Obxwr+h% zz0|ao`ZcM0Tqafr6(i~a_-AedTvvE6cohe+5PH#QAbL^j<(nSU;!-Rty<#Xsrh9F# zt(YQQHDsj&mWINqJD+pfbdrs{OEX}_*IO6JAGI~87qt+fg#Qw|@K)*(iTU{0D9A2vztKvsmyV@2 z=nTOc$)plnMaYRkj-UzeMKy2zb{*D|UY{(&JtZ*%0m~cZZ zh2R!2NIwqMB$Pr_971)Y2*|lS9|Ut@^E?`3*(^(L8uo$qVwOGgglLA?_IKexyPELzp zT9%w7mz-@Xq$Cpos|7nmY4jQ71-RF%)Uri#4;Dc}g7w9HvGb%#vK7a%-LOrq6HvuV z2sohA{Y~h{xvc`#zzdPDku^8~2D^&$Cei?tp!sSJF}nhyCd8vCz!xaK?pC6?Ov<3akf-S40C4oRU#zEACq0E&t0CJ?{sb#elsk^j)Lz- zrI(e4jC*wV5w}K}RQ{~MS z=7K+59Hba0*|M2aPofeUGLgUgC8~F;8ol^;6+EDyKLW+Shloy z#e7$mqwD z2}VJy&u}qQX@Qpus!7xU5{0N+iA=q%?UVE(b7lI@5u8$Vq@%HY^3Qllp$-X2^67VF>UQ85R$q36d%BW;q$>@s{J}9o^ z=*RvG&&X3nsc&&GHQ5_rBZ-<%em{%u_mCx&>CkV48XW-4Pq&69rwKMpT_Kvp4X*fcqQ!OA&|Lb5n|`>`j53pkAL*U>LPQvR_t z?~TZYpbj7oI$`HGfhYLp)b)1A+0(`@+%yEeD!%bG01)G!931rD9;H2^(IHU|ROEXE z{V~Wz*To;(Dnw7IXnMI``9=)=T7`7pgIpx|r?4ToffR|??&(@aIkel<5bznWVVztR4Z*2QSF%IMbWNWNWT9%Q& znT$#)P79iZ4LiUI4y}7Z?!9?GsdUc9M$s!Mo)D<)_XJ~(a?@cWA7G5R4}21`HM!Rs zy#fhxtc?jQGB;AB0nqRcQEZpcTI670+g)eUMh+Y+h|Zcx{H6=1_*HU>jJ$|K@ebD_ za%hrNk-!Q5wSnvqb}soO)XJ&vs|)5*kdO$qq@FgJr)*c0*1WI^VX8=>DO!YsMy=P4 zaXA>gP&IOdN%n{rf$-_9_7j1#^x8myXju}tjes7->|8EkQ2PeYP;B-E<2Xe^xJ42y zs5Kdo7#KJQMFFM-P<*s*TDUjzZ@M zn<6h^E4-?Axnk|5hj0*38V;vLP4K$R3WJje0>eTw*!xq5WR?$d#o8_~FEo8f70*D+ zF*43+b1F>MkWK*p5X(m|E|-&jTw>v<{~Fmrfrh1L@Jffe(u6-D76(j8PV*tVoV4Oc z{1@V+*gxJ{)aJ}s`8`|Tdk*|-JK|VQXh9%J*%jNaB|HOt;xa^PRM@f#46-_5jKuu+ z3@;}?qU$tHhF@X^I5eU<8D?qr9?mxk1HB!cnG+-k@540@wYpG=n;Jl97!u{nQJq2H zVx$e3zp3bs@w;HQIQb1(EkBClMAIf^6Z%*#UztoFpH@x%jV)X2jm{~rLGq-?M9zl) z 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 + * + * Copyright (C) 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 General Public License version 2, 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/*! \file */ + +/*! \page alloc_tests_page Memory allocation tests +\section alloc_tests_page_sec_1 What does it do? +???. + +\section alloc_tests_page_sec_2 How does it work? +???. +*/ + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "spandsp.h" + +int main(int argc, char *argv[]) +{ + void *a; + void *b; + void *c; + + if (span_mem_allocators(malloc, + realloc, + free, + memalign, + free)) + { + printf("Failed\n"); + exit(2); + } + a = span_aligned_alloc(8, 42); + b = span_alloc(42); + c = span_realloc(NULL, 42); + printf("%p %p %p\n", a, b, c); + span_aligned_free(a); + span_free(b); + span_free(c); +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/async_tests.c b/libs/spandsp/tests/async_tests.c index bd1a7d9d07..48c96e4d36 100644 --- a/libs/spandsp/tests/async_tests.c +++ b/libs/spandsp/tests/async_tests.c @@ -59,6 +59,7 @@ int v14_test_async_tx_get_bit(void *user_data) { async_tx_state_t *s; int bit; + int parity_bit; static int destuff = 0; /* Special routine to test V.14 rate adaption, by randomly skipping @@ -66,42 +67,39 @@ int v14_test_async_tx_get_bit(void *user_data) s = (async_tx_state_t *) user_data; if (s->bitpos == 0) { + s->byte_in_progress = s->get_byte(s->user_data); + s->byte_in_progress &= (0xFFFF >> (16 - s->data_bits)); + if (s->parity) + { + parity_bit = parity8(s->byte_in_progress); + if (s->parity == ASYNC_PARITY_ODD) + parity_bit ^= 1; + s->byte_in_progress |= (parity_bit << s->data_bits); + s->byte_in_progress |= (0xFFFF << (s->data_bits + 1)); + } + else + { + s->byte_in_progress |= (0xFFFF << s->data_bits); + } /* Start bit */ bit = 0; - s->byte_in_progress = s->get_byte(s->user_data); - s->parity_bit = 0; s->bitpos++; } - else if (s->bitpos <= s->data_bits) - { - bit = s->byte_in_progress & 1; - s->byte_in_progress >>= 1; - s->parity_bit ^= bit; - s->bitpos++; - if (!s->parity && s->bitpos == s->data_bits + 1) - { - /* Drop the stop bit on every fourth character for V.14 simulation*/ - if ((++destuff & 3) == 0) - s->bitpos = 0; - } - } - else if (s->parity && s->bitpos == s->data_bits + 1) - { - if (s->parity == ASYNC_PARITY_ODD) - s->parity_bit ^= 1; - bit = s->parity_bit; - s->bitpos++; - /* Drop the stop bit on every fourth character for V.14 simulation */ - if ((++destuff & 3) == 0) - s->bitpos = 0; - } else { - /* Stop bit(s) */ - bit = 1; - s->bitpos++; - if (s->bitpos > s->data_bits + s->stop_bits) - s->bitpos = 0; + bit = s->byte_in_progress & 1; + s->byte_in_progress >>= 1; + /* Drop the stop bit on every fourth character for V.14 simulation */ + if ((++destuff & 3) == 0) + { + if (++s->bitpos > s->total_bits - 1) + s->bitpos = 0; + } + else + { + if (++s->bitpos > s->total_bits) + s->bitpos = 0; + } } return bit; } @@ -130,8 +128,8 @@ int main(int argc, char *argv[]) int bit; printf("Test with async 8N1\n"); - async_tx_init(&tx_async, 8, ASYNC_PARITY_NONE, 1, FALSE, test_get_async_byte, NULL); - async_rx_init(&rx_async, 8, ASYNC_PARITY_NONE, 1, FALSE, test_put_async_byte, NULL); + async_tx_init(&tx_async, 8, ASYNC_PARITY_NONE, 1, false, test_get_async_byte, NULL); + async_rx_init(&rx_async, 8, ASYNC_PARITY_NONE, 1, false, test_put_async_byte, NULL); tx_async_chars = 0; rx_async_chars = 0; rx_async_char_mask = 0xFF; @@ -152,8 +150,8 @@ int main(int argc, char *argv[]) } printf("Test with async 7E1\n"); - async_tx_init(&tx_async, 7, ASYNC_PARITY_EVEN, 1, FALSE, test_get_async_byte, NULL); - async_rx_init(&rx_async, 7, ASYNC_PARITY_EVEN, 1, FALSE, test_put_async_byte, NULL); + async_tx_init(&tx_async, 7, ASYNC_PARITY_EVEN, 1, false, test_get_async_byte, NULL); + async_rx_init(&rx_async, 7, ASYNC_PARITY_EVEN, 1, false, test_put_async_byte, NULL); tx_async_chars = 0; rx_async_chars = 0; rx_async_char_mask = 0x7F; @@ -174,8 +172,8 @@ int main(int argc, char *argv[]) } printf("Test with async 8O1\n"); - async_tx_init(&tx_async, 8, ASYNC_PARITY_ODD, 1, FALSE, test_get_async_byte, NULL); - async_rx_init(&rx_async, 8, ASYNC_PARITY_ODD, 1, FALSE, test_put_async_byte, NULL); + async_tx_init(&tx_async, 8, ASYNC_PARITY_ODD, 1, false, test_get_async_byte, NULL); + async_rx_init(&rx_async, 8, ASYNC_PARITY_ODD, 1, false, test_put_async_byte, NULL); tx_async_chars = 0; rx_async_chars = 0; rx_async_char_mask = 0xFF; @@ -196,8 +194,8 @@ int main(int argc, char *argv[]) } printf("Test with async 8O1 and V.14\n"); - async_tx_init(&tx_async, 8, ASYNC_PARITY_ODD, 1, TRUE, test_get_async_byte, NULL); - async_rx_init(&rx_async, 8, ASYNC_PARITY_ODD, 1, TRUE, test_put_async_byte, NULL); + async_tx_init(&tx_async, 8, ASYNC_PARITY_ODD, 1, true, test_get_async_byte, NULL); + async_rx_init(&rx_async, 8, ASYNC_PARITY_ODD, 1, true, test_put_async_byte, NULL); tx_async_chars = 0; rx_async_chars = 0; rx_async_char_mask = 0xFF; @@ -207,7 +205,7 @@ int main(int argc, char *argv[]) async_rx_put_bit(&rx_async, bit); } printf("Chars=%d/%d, PE=%d, FE=%d\n", tx_async_chars, rx_async_chars, rx_async.parity_errors, rx_async.framing_errors); - if (tx_async_chars != rx_async_chars + 1 + if (tx_async_chars != rx_async_chars || rx_async.parity_errors || @@ -218,8 +216,8 @@ int main(int argc, char *argv[]) } printf("Test with async 5N2\n"); - async_tx_init(&tx_async, 5, ASYNC_PARITY_NONE, 2, FALSE, test_get_async_byte, NULL); - async_rx_init(&rx_async, 5, ASYNC_PARITY_NONE, 2, FALSE, test_put_async_byte, NULL); + async_tx_init(&tx_async, 5, ASYNC_PARITY_NONE, 2, false, test_get_async_byte, NULL); + async_rx_init(&rx_async, 5, ASYNC_PARITY_NONE, 2, false, test_put_async_byte, NULL); tx_async_chars = 0; rx_async_chars = 0; rx_async_char_mask = 0x1F; diff --git a/libs/spandsp/tests/bell_mf_rx_tests.c b/libs/spandsp/tests/bell_mf_rx_tests.c index ed33c95d35..0c938caa01 100644 --- a/libs/spandsp/tests/bell_mf_rx_tests.c +++ b/libs/spandsp/tests/bell_mf_rx_tests.c @@ -112,7 +112,7 @@ static tone_gen_descriptor_t my_mf_digit_tones[16]; static char bell_mf_tone_codes[] = "1234567890CA*B#"; -int callback_ok; +bool callback_ok; int callback_roll; static void my_mf_gen_init(float low_fudge, @@ -139,7 +139,7 @@ static void my_mf_gen_init(float low_fudge, gap, 0, 0, - FALSE); + false); } } /*- End of function --------------------------------------------------------*/ @@ -188,10 +188,10 @@ static void digit_delivery(void *data, const char *digits, int len) if (data != (void *) 0x12345678) { - callback_ok = FALSE; + callback_ok = false; return; } - callback_ok = TRUE; + callback_ok = true; t = s + callback_roll; seg = 15 - callback_roll; for (i = 0; i < len; i += seg, seg = 15) @@ -200,7 +200,7 @@ static void digit_delivery(void *data, const char *digits, int len) seg = len - i; if (memcmp(digits + i, t, seg)) { - callback_ok = FALSE; + callback_ok = false; printf("Fail at %d %d\n", i, seg); break; } @@ -522,7 +522,7 @@ int main(int argc, char *argv[]) /* Test the callback mode for delivering detected digits */ printf("Test: Callback digit delivery mode.\n"); - callback_ok = FALSE; + callback_ok = false; callback_roll = 0; mf_state = bell_mf_rx_init(NULL, digit_delivery, (void *) 0x12345678); my_mf_gen_init(0.0, -10, 0.0, -10, 68, 68); diff --git a/libs/spandsp/tests/bert_tests.c b/libs/spandsp/tests/bert_tests.c index 6818f61889..5b6bb6151f 100644 --- a/libs/spandsp/tests/bert_tests.c +++ b/libs/spandsp/tests/bert_tests.c @@ -210,18 +210,18 @@ int main(int argc, char *argv[]) bert_put_bit(rx_bert, bit); test[tx_bert->tx.reg]++; } - failed = FALSE; + failed = false; if (test[0] != 0) { printf("XXX %d %d\n", 0, test[0]); - failed = TRUE; + failed = true; } for (i = 1; i < 0x200; i++) { if (test[i] != 2) { printf("XXX %d %d\n", i, test[i]); - failed = TRUE; + failed = true; } } bert_result(rx_bert, &bert_results); @@ -254,18 +254,18 @@ int main(int argc, char *argv[]) bert_put_bit(rx_bert, bit); test[tx_bert->tx.reg]++; } - failed = FALSE; + failed = false; if (test[0] != 0) { printf("XXX %d %d\n", 0, test[0]); - failed = TRUE; + failed = true; } for (i = 1; i < 0x800; i++) { if (test[i] != 2) { printf("XXX %d %d\n", i, test[i]); - failed = TRUE; + failed = true; } } bert_result(rx_bert, &bert_results); @@ -298,18 +298,18 @@ int main(int argc, char *argv[]) bert_put_bit(rx_bert, bit); test[tx_bert->tx.reg]++; } - failed = FALSE; + failed = false; if (test[0] != 0) { printf("XXX %d %d\n", 0, test[0]); - failed = TRUE; + failed = true; } for (i = 1; i < 0x8000; i++) { if (test[i] != 2) { printf("XXX %d %d\n", i, test[i]); - failed = TRUE; + failed = true; } } bert_result(rx_bert, &bert_results); @@ -342,11 +342,11 @@ int main(int argc, char *argv[]) bert_put_bit(rx_bert, bit); test[tx_bert->tx.reg]++; } - failed = FALSE; + failed = false; if (test[0] != 0) { printf("XXX %d %d\n", 0, test[0]); - failed = TRUE; + failed = true; } for (i = 1; i < 0x100000; i++) { @@ -383,11 +383,11 @@ int main(int argc, char *argv[]) bert_put_bit(rx_bert, bit); test[tx_bert->tx.reg]++; } - failed = FALSE; + failed = false; if (test[0] != 0) { printf("XXX %d %d\n", 0, test[0]); - failed = TRUE; + failed = true; } for (i = 1; i < 0x800000; i++) { diff --git a/libs/spandsp/tests/bitstream_tests.c b/libs/spandsp/tests/bitstream_tests.c index 2d70cd0029..3e7b441a55 100644 --- a/libs/spandsp/tests/bitstream_tests.c +++ b/libs/spandsp/tests/bitstream_tests.c @@ -45,7 +45,7 @@ uint8_t buffer[256]; -#define PATTERN 0x11111111 +#define PATTERN 0x1111111 #define SEQUENCE_LENGTH 17 uint8_t left[] = @@ -106,12 +106,12 @@ int main(int argc, char *argv[]) unsigned int x; int total_bits; - s = bitstream_init(&state, TRUE); + s = bitstream_init(&state, true); w = buffer; total_bits = 0; for (i = 0; i < SEQUENCE_LENGTH; i++) { - bitstream_put(s, &w, PATTERN*i, i + 1); + bitstream_put(s, &w, i*PATTERN, i + 1); total_bits += (i + 1); } bitstream_flush(s, &w); @@ -130,7 +130,7 @@ int main(int argc, char *argv[]) exit(2); } - s = bitstream_init(&state, TRUE); + s = bitstream_init(&state, true); r = buffer; for (i = 0; i < SEQUENCE_LENGTH; i++) { @@ -143,7 +143,7 @@ int main(int argc, char *argv[]) } } - s = bitstream_init(&state, FALSE); + s = bitstream_init(&state, false); w = buffer; total_bits = 0; for (i = 0; i < SEQUENCE_LENGTH; i++) @@ -167,7 +167,7 @@ int main(int argc, char *argv[]) exit(2); } - s = bitstream_init(&state, FALSE); + s = bitstream_init(&state, false); r = buffer; for (i = 0; i < SEQUENCE_LENGTH; i++) { diff --git a/libs/spandsp/tests/dtmf_rx_tests.c b/libs/spandsp/tests/dtmf_rx_tests.c index 89a456bd82..18267645f2 100644 --- a/libs/spandsp/tests/dtmf_rx_tests.c +++ b/libs/spandsp/tests/dtmf_rx_tests.c @@ -145,15 +145,15 @@ float dtmf_col[] = char dtmf_positions[] = "123A" "456B" "789C" "*0#D"; -int callback_hit; -int callback_ok; +bool callback_hit; +bool callback_ok; int callback_roll; int step; float max_forward_twist; float max_reverse_twist; -int use_dialtone_filter = FALSE; +bool use_dialtone_filter = false; char *decode_test_file = NULL; @@ -185,7 +185,7 @@ static void my_dtmf_gen_init(float low_fudge, gap, 0, 0, - FALSE); + false); } } } @@ -219,7 +219,7 @@ static void digit_delivery(void *data, const char *digits, int len) const char *s = ALL_POSSIBLE_DIGITS; const char *t; - callback_hit = TRUE; + callback_hit = true; if (data == (void *) 0x12345678) { t = s + callback_roll; @@ -230,7 +230,7 @@ static void digit_delivery(void *data, const char *digits, int len) seg = len - i; if (memcmp(digits + i, t, seg)) { - callback_ok = FALSE; + callback_ok = false; printf("Fail at %d %d\n", i, seg); break; } @@ -240,7 +240,7 @@ static void digit_delivery(void *data, const char *digits, int len) } else { - callback_ok = FALSE; + callback_ok = false; } } /*- End of function --------------------------------------------------------*/ @@ -250,10 +250,10 @@ static void digit_status(void *data, int signal, int level, int delay) const char *s = ALL_POSSIBLE_DIGITS; int len; static int last_step = 0; - static int first = TRUE; + static int first = true; //printf("Digit status %d %d %d\n", signal, level, delay); - callback_hit = TRUE; + callback_hit = true; len = step - last_step; if (data == (void *) 0x12345678) { @@ -262,12 +262,12 @@ static void digit_status(void *data, int signal, int level, int delay) if (first) { /* At the beginning the apparent duration is expected to be wrong */ - first = FALSE; + first = false; } else { printf("Failed for signal %s length %d at %d\n", (callback_roll & 1) ? "on" : "off", len, step); - callback_ok = FALSE; + callback_ok = false; } } if (callback_roll & 1) @@ -275,7 +275,7 @@ static void digit_status(void *data, int signal, int level, int delay) if (signal != 0) { printf("Failed for signal 0x%X instead of 0\n", signal); - callback_ok = FALSE; + callback_ok = false; } } else @@ -283,12 +283,12 @@ static void digit_status(void *data, int signal, int level, int delay) if (signal != s[callback_roll >> 1]) { printf("Failed for signal 0x%X instead of 0x%X\n", signal, s[callback_roll >> 1]); - callback_ok = FALSE; + callback_ok = false; } if (level < DEFAULT_DTMF_TX_LEVEL + 3 - 1 || level > DEFAULT_DTMF_TX_LEVEL + 3 + 1) { printf("Failed for level %d instead of %d\n", level, DEFAULT_DTMF_TX_LEVEL + 3); - callback_ok = FALSE; + callback_ok = false; } } if (++callback_roll >= 32) @@ -296,7 +296,7 @@ static void digit_status(void *data, int signal, int level, int delay) } else { - callback_ok = FALSE; + callback_ok = false; } last_step = step; } @@ -675,11 +675,11 @@ static void mitel_cm7291_side_2_and_bellcore_tests(void) { if (hit_types[i]) { - printf(" Digit %c had %d false hits\n", i, hit_types[i]); + printf(" Digit %c had %d false hits.\n", i, hit_types[i]); j += hit_types[i]; } } - printf(" %d hits in total\n", j); + printf(" %d false hits in total.\n", j); if (j > 470) { printf(" Failed\n"); @@ -714,7 +714,7 @@ static void dial_tone_tolerance_tests(void) for (j = -30; j < -3; j++) { - tone_gen_descriptor_init(&dial_tone_desc, 350, j, 440, j, 1, 0, 0, 0, TRUE); + tone_gen_descriptor_init(&dial_tone_desc, 350, j, 440, j, 1, 0, 0, 0, true); tone_gen_init(&dial_tone, &dial_tone_desc); for (i = 0; i < 10; i++) { @@ -755,8 +755,8 @@ static void callback_function_tests(void) /* Test the callback mode for delivering detected digits */ printf("Test: Callback digit delivery mode.\n"); - callback_hit = FALSE; - callback_ok = TRUE; + callback_hit = false; + callback_ok = true; callback_roll = 0; dtmf_state = dtmf_rx_init(NULL, digit_delivery, (void *) 0x12345678); if (use_dialtone_filter || max_forward_twist >= 0.0f || max_reverse_twist >= 0.0f) @@ -784,8 +784,8 @@ static void callback_function_tests(void) /* Test the realtime callback mode for reporting detected digits */ printf("Test: Realtime callback digit delivery mode.\n"); - callback_hit = FALSE; - callback_ok = TRUE; + callback_hit = false; + callback_ok = true; callback_roll = 0; dtmf_rx_init(dtmf_state, NULL, NULL); dtmf_rx_set_realtime_callback(dtmf_state, digit_status, (void *) 0x12345678); @@ -867,7 +867,7 @@ int main(int argc, char *argv[]) int channel_codec; int opt; - use_dialtone_filter = FALSE; + use_dialtone_filter = false; channel_codec = MUNGE_CODEC_NONE; decode_test_file = NULL; max_forward_twist = -1.0f; @@ -886,7 +886,7 @@ int main(int argc, char *argv[]) max_forward_twist = atof(optarg); break; case 'f': - use_dialtone_filter = TRUE; + use_dialtone_filter = true; break; case 'R': max_reverse_twist = atof(optarg); diff --git a/libs/spandsp/tests/dtmf_tx_tests.c b/libs/spandsp/tests/dtmf_tx_tests.c index 176cf1783b..3f6f234ce7 100644 --- a/libs/spandsp/tests/dtmf_tx_tests.c +++ b/libs/spandsp/tests/dtmf_tx_tests.c @@ -188,7 +188,7 @@ int main(int argc, char *argv[]) exit(2); } - add_digits = TRUE; + add_digits = true; do { len = dtmf_tx(gen, amp, 160); @@ -200,7 +200,7 @@ int main(int argc, char *argv[]) if (dtmf_tx_put(gen, "1234567890", -1)) { printf("Digit buffer full\n"); - add_digits = FALSE; + add_digits = false; } } } diff --git a/libs/spandsp/tests/echo_tests.c b/libs/spandsp/tests/echo_tests.c index aba34d92b9..93d496e302 100644 --- a/libs/spandsp/tests/echo_tests.c +++ b/libs/spandsp/tests/echo_tests.c @@ -616,7 +616,7 @@ static void run_test(echo_can_state_t *ctx, int16_t (*tx_source)(void), int16_t static void print_test_title(const char *title) { - if (quiet == FALSE) + if (quiet == false) printf(title); } /*- End of function --------------------------------------------------------*/ @@ -1567,23 +1567,23 @@ int main(int argc, char *argv[]) int i; time_t now; int simulate; - int cng; - int hpf; - int two_channel_file; int opt; int mode; + bool cng; + bool hpf; + bool two_channel_file; /* Check which tests we should run */ if (argc < 2) fprintf(stderr, "Usage: echo tests [-g] [-m ] [-s] \n"); line_model_no = 0; supp_line_model_no = 0; - cng = FALSE; - hpf = FALSE; - use_gui = FALSE; - simulate = FALSE; + cng = false; + hpf = false; + use_gui = false; + simulate = false; munger = -1; - two_channel_file = FALSE; + two_channel_file = false; erl = -12.0f; while ((opt = getopt(argc, argv, "2ace:ghm:M:su")) != -1) @@ -1591,13 +1591,13 @@ int main(int argc, char *argv[]) switch (opt) { case '2': - two_channel_file = TRUE; + two_channel_file = true; break; case 'a': munger = G711_ALAW; break; case 'c': - cng = TRUE; + cng = true; break; case 'e': /* Allow for ERL being entered as x or -x */ @@ -1605,14 +1605,14 @@ int main(int argc, char *argv[]) break; case 'g': #if defined(ENABLE_GUI) - use_gui = TRUE; + use_gui = true; #else fprintf(stderr, "Graphical monitoring not available\n"); exit(2); #endif break; case 'h': - hpf = TRUE; + hpf = true; break; case 'm': line_model_no = atoi(optarg); @@ -1621,7 +1621,7 @@ int main(int argc, char *argv[]) supp_line_model_no = atoi(optarg); break; case 's': - simulate = TRUE; + simulate = true; break; case 'u': munger = G711_ULAW; diff --git a/libs/spandsp/tests/fax_decode.c b/libs/spandsp/tests/fax_decode.c index 37792a9f2b..9fedc23c66 100644 --- a/libs/spandsp/tests/fax_decode.c +++ b/libs/spandsp/tests/fax_decode.c @@ -83,12 +83,12 @@ static const struct { 0, 0, 0, 0} }; -int decode_test = FALSE; +bool decode_test = false; int rx_bits = 0; t30_state_t t30_dummy; t4_rx_state_t t4_rx_state; -int t4_up = FALSE; +bool t4_up = false; hdlc_rx_state_t hdlcrx; @@ -97,14 +97,14 @@ int fast_trained = FAX_NONE; uint8_t ecm_data[256][260]; int16_t ecm_len[256]; -int line_encoding = T4_COMPRESSION_ITU_T4_1D; +int line_encoding = T4_COMPRESSION_T4_1D; int x_resolution = T4_X_RESOLUTION_R8; int y_resolution = T4_Y_RESOLUTION_STANDARD; int image_width = 1728; int octets_per_ecm_frame = 256; -int error_correcting_mode = FALSE; +bool error_correcting_mode = false; int current_fallback = 0; -int end_of_page_detected = FALSE; +bool end_of_page_detected = false; static void decode_20digit_msg(const uint8_t *pkt, int len) { @@ -221,11 +221,11 @@ static int check_rx_dcs(const uint8_t *msg, int len) /* Check which compression we will use. */ if ((dcs_frame[6] & DISBIT7)) - line_encoding = T4_COMPRESSION_ITU_T6; + line_encoding = T4_COMPRESSION_T6; else if ((dcs_frame[4] & DISBIT8)) - line_encoding = T4_COMPRESSION_ITU_T4_2D; + line_encoding = T4_COMPRESSION_T4_2D; else - line_encoding = T4_COMPRESSION_ITU_T4_1D; + line_encoding = T4_COMPRESSION_T4_1D; fprintf(stderr, "Selected compression %d\n", line_encoding); if ((current_fallback = find_fallback_entry(dcs_frame[4] & (DISBIT6 | DISBIT5 | DISBIT4 | DISBIT3))) < 0) @@ -294,8 +294,8 @@ static void t4_begin(void) t4_rx_set_image_width(&t4_rx_state, image_width); t4_rx_start_page(&t4_rx_state); - t4_up = TRUE; - end_of_page_detected = FALSE; + t4_up = true; + end_of_page_detected = false; for (i = 0; i < 256; i++) ecm_len[i] = -1; @@ -326,7 +326,7 @@ static void t4_end(void) fprintf(stderr, "Image resolution = %dx%d\n", stats.x_resolution, stats.y_resolution); fprintf(stderr, "Bad rows = %d\n", stats.bad_rows); fprintf(stderr, "Longest bad row run = %d\n", stats.longest_bad_row_run); - t4_up = FALSE; + t4_up = false; } /*- End of function --------------------------------------------------------*/ @@ -381,7 +381,7 @@ static void v17_put_bit(void *user_data, int bit) t4_end(); if (!end_of_page_detected) fprintf(stderr, "End of page detected\n"); - end_of_page_detected = TRUE; + end_of_page_detected = true; } } //printf("V.17 Rx bit %d - %d\n", rx_bits++, bit); @@ -419,7 +419,7 @@ static void v29_put_bit(void *user_data, int bit) t4_end(); if (!end_of_page_detected) fprintf(stderr, "End of page detected\n"); - end_of_page_detected = TRUE; + end_of_page_detected = true; } } //printf("V.29 Rx bit %d - %d\n", rx_bits++, bit); @@ -457,7 +457,7 @@ static void v27ter_put_bit(void *user_data, int bit) t4_end(); if (!end_of_page_detected) fprintf(stderr, "End of page detected\n"); - end_of_page_detected = TRUE; + end_of_page_detected = true; } } //printf("V.27ter Rx bit %d - %d\n", rx_bits++, bit); @@ -504,7 +504,7 @@ int main(int argc, char *argv[]) span_log_init(&t30_dummy.logging, SPAN_LOG_FLOW, NULL); span_log_set_protocol(&t30_dummy.logging, "T.30"); - hdlc_rx_init(&hdlcrx, FALSE, TRUE, 5, hdlc_accept, NULL); + hdlc_rx_init(&hdlcrx, false, true, 5, hdlc_accept, NULL); fsk = fsk_rx_init(NULL, &preset_fsk_specs[FSK_V21CH2], FSK_FRAME_MODE_SYNC, v21_put_bit, NULL); v17 = v17_rx_init(NULL, 14400, v17_put_bit, NULL); v29 = v29_rx_init(NULL, 9600, v29_put_bit, NULL); @@ -540,7 +540,7 @@ int main(int argc, char *argv[]) span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW); #endif - if (t4_rx_init(&t4_rx_state, "fax_decode.tif", T4_COMPRESSION_ITU_T4_2D) == NULL) + if (t4_rx_init(&t4_rx_state, "fax_decode.tif", T4_COMPRESSION_T4_2D) == NULL) { fprintf(stderr, "Failed to init\n"); exit(0); diff --git a/libs/spandsp/tests/fax_tester.c b/libs/spandsp/tests/fax_tester.c index d42ea3a074..77016202a5 100644 --- a/libs/spandsp/tests/fax_tester.c +++ b/libs/spandsp/tests/fax_tester.c @@ -239,23 +239,23 @@ static void non_ecm_rx_status(void *user_data, int status) switch (status) { case SIG_STATUS_TRAINING_FAILED: - s->modems.rx_trained = FALSE; + s->modems.rx_trained = false; break; case SIG_STATUS_TRAINING_SUCCEEDED: /* The modem is now trained */ - s->modems.rx_trained = TRUE; + s->modems.rx_trained = true; break; case SIG_STATUS_CARRIER_UP: - s->modems.rx_signal_present = TRUE; + s->modems.rx_signal_present = true; break; case SIG_STATUS_CARRIER_DOWN: if (s->modems.rx_trained) { if (s->real_time_frame_handler) - s->real_time_frame_handler(s, s->real_time_frame_user_data, TRUE, NULL, 0); + s->real_time_frame_handler(s, s->real_time_frame_user_data, true, NULL, 0); } - s->modems.rx_signal_present = FALSE; - s->modems.rx_trained = FALSE; + s->modems.rx_signal_present = false; + s->modems.rx_trained = false; break; } } @@ -280,18 +280,18 @@ static void hdlc_rx_status(void *user_data, int status) switch (status) { case SIG_STATUS_TRAINING_FAILED: - s->modems.rx_trained = FALSE; + s->modems.rx_trained = false; break; case SIG_STATUS_TRAINING_SUCCEEDED: /* The modem is now trained */ - s->modems.rx_trained = TRUE; + s->modems.rx_trained = true; break; case SIG_STATUS_CARRIER_UP: - s->modems.rx_signal_present = TRUE; + s->modems.rx_signal_present = true; break; case SIG_STATUS_CARRIER_DOWN: - s->modems.rx_signal_present = FALSE; - s->modems.rx_trained = FALSE; + s->modems.rx_signal_present = false; + s->modems.rx_trained = false; break; } } @@ -308,7 +308,7 @@ static void hdlc_accept(void *user_data, const uint8_t *msg, int len, int ok) } s = (faxtester_state_t *) user_data; if (s->real_time_frame_handler) - s->real_time_frame_handler(s, s->real_time_frame_user_data, TRUE, msg, len); + s->real_time_frame_handler(s, s->real_time_frame_user_data, true, msg, len); } /*- End of function --------------------------------------------------------*/ @@ -325,7 +325,7 @@ int faxtester_rx(faxtester_state_t *s, int16_t *amp, int len) { if (!s->modems.rx_signal_present) { - s->wait_for_silence = FALSE; + s->wait_for_silence = false; front_end_step_complete(s); } } @@ -371,7 +371,7 @@ int faxtester_tx(faxtester_state_t *s, int16_t *amp, int max_len) void faxtest_set_rx_silence(faxtester_state_t *s) { - s->wait_for_silence = TRUE; + s->wait_for_silence = true; } /*- End of function --------------------------------------------------------*/ @@ -387,7 +387,7 @@ void faxtester_set_rx_type(void *user_data, int type, int bit_rate, int short_tr return; s->current_rx_type = type; if (use_hdlc) - hdlc_rx_init(&t->hdlc_rx, FALSE, FALSE, HDLC_FRAMING_OK_THRESHOLD, hdlc_accept, s); + hdlc_rx_init(&t->hdlc_rx, false, false, HDLC_FRAMING_OK_THRESHOLD, hdlc_accept, s); switch (type) { case T30_MODEM_CED: @@ -449,18 +449,18 @@ void faxtester_set_tx_type(void *user_data, int type, int bit_rate, int short_tr case T30_MODEM_PAUSE: silence_gen_alter(&t->silence_gen, ms_to_samples(short_train)); fax_modems_set_tx_handler(t, (span_tx_handler_t) &silence_gen, &t->silence_gen); - s->transmit = TRUE; + s->transmit = true; break; case T30_MODEM_CED: case T30_MODEM_CNG: tone = (type == T30_MODEM_CED) ? MODEM_CONNECT_TONES_FAX_CED : MODEM_CONNECT_TONES_FAX_CNG; fax_modems_start_slow_modem(t, tone); - s->transmit = TRUE; + s->transmit = true; break; case T30_MODEM_V21: fax_modems_start_slow_modem(t, FAX_MODEM_V21_TX); fsk_tx_set_modem_status_handler(&t->v21_tx, modem_tx_status, (void *) s); - s->transmit = TRUE; + s->transmit = true; break; case T30_MODEM_V27TER: fax_modems_set_get_bit(t, get_bit_func, get_bit_user_data); @@ -468,7 +468,7 @@ void faxtester_set_tx_type(void *user_data, int type, int bit_rate, int short_tr v27ter_tx_set_modem_status_handler(&t->fast_modems.v27ter_tx, modem_tx_status, (void *) s); /* For any fast modem, set 200ms of preamble flags */ hdlc_tx_flags(&t->hdlc_tx, bit_rate/(8*5)); - s->transmit = TRUE; + s->transmit = true; break; case T30_MODEM_V29: fax_modems_set_get_bit(t, get_bit_func, get_bit_user_data); @@ -476,7 +476,7 @@ void faxtester_set_tx_type(void *user_data, int type, int bit_rate, int short_tr v29_tx_set_modem_status_handler(&t->fast_modems.v29_tx, modem_tx_status, (void *) s); /* For any fast modem, set 200ms of preamble flags */ hdlc_tx_flags(&t->hdlc_tx, bit_rate/(8*5)); - s->transmit = TRUE; + s->transmit = true; break; case T30_MODEM_V17: fax_modems_set_get_bit(t, get_bit_func, get_bit_user_data); @@ -484,7 +484,7 @@ void faxtester_set_tx_type(void *user_data, int type, int bit_rate, int short_tr v17_tx_set_modem_status_handler(&t->fast_modems.v17_tx, modem_tx_status, (void *) s); /* For any fast modem, set 200ms of preamble flags */ hdlc_tx_flags(&t->hdlc_tx, bit_rate/(8*5)); - s->transmit = TRUE; + s->transmit = true; break; case T30_MODEM_DONE: span_log(&s->logging, SPAN_LOG_FLOW, "FAX exchange complete\n"); @@ -492,7 +492,7 @@ void faxtester_set_tx_type(void *user_data, int type, int bit_rate, int short_tr default: silence_gen_alter(&t->silence_gen, 0); fax_modems_set_tx_handler(t, (span_tx_handler_t) &silence_gen, &t->silence_gen); - s->transmit = FALSE; + s->transmit = false; break; } s->current_tx_type = type; @@ -553,17 +553,17 @@ faxtester_state_t *faxtester_init(faxtester_state_t *s, int calling_party) span_log_init(&s->logging, SPAN_LOG_NONE, NULL); span_log_set_protocol(&s->logging, "TST"); fax_modems_init(&s->modems, - FALSE, + false, NULL, hdlc_underflow_handler, non_ecm_put_bit, t38_non_ecm_buffer_get_bit, tone_detected, s); - fax_modems_set_tep_mode(&s->modems, FALSE); - fax_modems_set_rx_active(&s->modems, TRUE); + fax_modems_set_tep_mode(&s->modems, false); + fax_modems_set_rx_active(&s->modems, true); faxtester_set_timeout(s, -1); - faxtester_set_tx_type(s, T30_MODEM_NONE, 0, FALSE, FALSE); + faxtester_set_tx_type(s, T30_MODEM_NONE, 0, false, false); return s; } diff --git a/libs/spandsp/tests/fax_tester.h b/libs/spandsp/tests/fax_tester.h index 45054ec7ec..bcfcb1d085 100644 --- a/libs/spandsp/tests/fax_tester.h +++ b/libs/spandsp/tests/fax_tester.h @@ -44,7 +44,7 @@ typedef void (*faxtester_flush_handler_t)(faxtester_state_t *s, void *user_data, \brief FAX tester real time frame handler. \param s The FAX tester context. \param user_data An opaque pointer. - \param direction TRUE for incoming, FALSE for outgoing. + \param direction True for incoming, false for outgoing. \param msg The HDLC message. \param len The length of the message. */ @@ -94,11 +94,11 @@ struct faxtester_state_s /*! \brief CED or CNG detector */ modem_connect_tones_rx_state_t connect_rx; - /*! If TRUE, transmission is in progress */ - int transmit; + /*! If true, transmission is in progress */ + bool transmit; - /*! \brief TRUE is the short training sequence should be used. */ - int short_train; + /*! \brief true if the short training sequence should be used. */ + bool short_train; /*! \brief The currently select receiver type */ int current_rx_type; @@ -157,7 +157,7 @@ void faxtester_set_flush_handler(faxtester_state_t *s, faxtester_flush_handler_t /*! Select whether silent audio will be sent when FAX transmit is idle. \brief Select whether silent audio will be sent when FAX transmit is idle. \param s The FAX tester context. - \param transmit_on_idle TRUE if silent audio should be output when the FAX transmitter is + \param transmit_on_idle true if silent audio should be output when the FAX transmitter is idle. FALSE to transmit zero length audio when the FAX transmitter is idle. The default behaviour is FALSE. */ @@ -166,7 +166,7 @@ void faxtester_set_transmit_on_idle(faxtester_state_t *s, int transmit_on_idle); /*! Select whether talker echo protection tone will be sent for the image modems. \brief Select whether TEP will be sent for the image modems. \param s The FAX tester context. - \param use_tep TRUE if TEP should be sent. + \param use_tep true if TEP should be sent. */ void faxtester_set_tep_mode(faxtester_state_t *s, int use_tep); @@ -185,7 +185,7 @@ void faxtester_set_ecm_image_buffer(faxtester_state_t *s, const uint8_t *buf, in /*! Initialise a FAX context. \brief Initialise a FAX context. \param s The FAX tester context. - \param calling_party TRUE if the context is for a calling party. FALSE if the + \param calling_party true if the context is for a calling party. FALSE if the context is for an answering party. \return A pointer to the FAX context, or NULL if there was a problem. */ diff --git a/libs/spandsp/tests/fax_tests.c b/libs/spandsp/tests/fax_tests.c index 02c840974a..5f8ce070e2 100644 --- a/libs/spandsp/tests/fax_tests.c +++ b/libs/spandsp/tests/fax_tests.c @@ -116,16 +116,16 @@ int t38_subst_seq[2] = {0, 0}; t30_exchanged_info_t expected_rx_info[2]; -int use_receiver_not_ready = FALSE; -int test_local_interrupt = FALSE; +bool use_receiver_not_ready = false; +bool test_local_interrupt = false; double when = 0.0; -int phase_e_reached[2] = {FALSE, FALSE}; -int completed[2] = {FALSE, FALSE}; -int succeeded[2] = {FALSE, FALSE}; +bool phase_e_reached[2] = {false, false}; +bool completed[2] = {false, false}; +bool succeeded[2] = {false, false}; -int t38_simulate_incrementing_repeats = FALSE; +bool t38_simulate_incrementing_repeats = false; static int phase_b_handler(t30_state_t *s, void *user_data, int result) { @@ -316,7 +316,7 @@ static int phase_d_handler(t30_state_t *s, void *user_data, int result) if (i == 'A') { printf("%c: Initiating interrupt request\n", i); - t30_local_interrupt_request(s, TRUE); + t30_local_interrupt_request(s, true); } else { @@ -327,7 +327,7 @@ static int phase_d_handler(t30_state_t *s, void *user_data, int result) case T30_PRI_EOM: case T30_PRI_EOP: printf("%c: Accepting interrupt request\n", i); - t30_local_interrupt_request(s, TRUE); + t30_local_interrupt_request(s, true); break; case T30_PIN: break; @@ -352,13 +352,13 @@ static void phase_e_handler(t30_state_t *s, void *user_data, int result) fax_log_rx_parameters(s, tag); t30_get_transfer_statistics(s, &t); succeeded[i] = (result == T30_ERR_OK); - phase_e_reached[i] = TRUE; + phase_e_reached[i] = true; } /*- End of function --------------------------------------------------------*/ static void real_time_frame_handler(t30_state_t *s, void *user_data, - int direction, + bool incoming, const uint8_t *msg, int len) { @@ -367,7 +367,7 @@ static void real_time_frame_handler(t30_state_t *s, i = (intptr_t) user_data; printf("%c: Real time frame handler - %s, %s, length = %d\n", i + 'A', - (direction) ? "line->T.30" : "T.30->line", + (incoming) ? "line->T.30" : "T.30->line", t30_frametype(msg[2]), len); } @@ -379,7 +379,7 @@ static int document_handler(t30_state_t *s, void *user_data, int event) i = (intptr_t) user_data; printf("%c: Document handler - event %d\n", i + 'A', event); - return FALSE; + return false; } /*- End of function --------------------------------------------------------*/ @@ -395,7 +395,7 @@ static void set_t30_callbacks(t30_state_t *t30, int chan) static void real_time_gateway_frame_handler(t38_gateway_state_t *s, void *user_data, - int direction, + bool incoming, const uint8_t *msg, int len) { @@ -404,7 +404,7 @@ static void real_time_gateway_frame_handler(t38_gateway_state_t *s, i = (intptr_t) user_data; printf("%c: Real time gateway frame handler - %s, %s, length = %d\n", i + 'A', - (direction) ? "PSTN->T.38" : "T.38->PSTN", + (incoming) ? "PSTN->T.38" : "T.38->PSTN", t30_frametype(msg[2]), len); } @@ -463,8 +463,8 @@ int main(int argc, char *argv[]) int outframes; SNDFILE *wave_handle; SNDFILE *input_wave_handle; - int use_ecm; - int use_tep; + bool use_ecm; + bool use_tep; int feedback_audio; int use_transmit_on_idle; int t38_version; @@ -479,7 +479,6 @@ int main(int argc, char *argv[]) double tx_when; double rx_when; int supported_modems; - int remove_fill_bits; int opt; int start_page; int end_page; @@ -490,6 +489,11 @@ int main(int argc, char *argv[]) int noise_level; int code_to_look_up; int scan_line_time; + int allowed_bilevel_resolutions[2]; + int allowed; + bool remove_fill_bits; + bool colour_enabled; + bool t37_like_output; t38_stats_t t38_stats; t30_stats_t t30_stats; logging_state_t *logging; @@ -503,19 +507,19 @@ int main(int argc, char *argv[]) #endif #if defined(ENABLE_GUI) - use_gui = FALSE; + use_gui = false; #endif - log_audio = FALSE; - use_ecm = FALSE; + log_audio = false; + use_ecm = false; t38_version = 1; input_tiff_file_name = INPUT_TIFF_FILE_NAME; - t38_simulate_incrementing_repeats = FALSE; + t38_simulate_incrementing_repeats = false; g1050_model_no = 0; g1050_speed_pattern_no = 1; - remove_fill_bits = FALSE; - use_tep = FALSE; - feedback_audio = FALSE; - use_transmit_on_idle = TRUE; + remove_fill_bits = false; + use_tep = false; + feedback_audio = false; + use_transmit_on_idle = true; supported_modems = T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17; page_header_info = NULL; page_header_tz = NULL; @@ -528,14 +532,29 @@ int main(int argc, char *argv[]) scan_line_time = 0; decode_file_name = NULL; code_to_look_up = -1; + allowed_bilevel_resolutions[0] = 0; + allowed_bilevel_resolutions[1] = 0; + allowed = 0; + colour_enabled = false; + t37_like_output = false; t38_transport = T38_TRANSPORT_UDPTL; - while ((opt = getopt(argc, argv, "c:d:D:efFgH:i:Ilm:M:n:p:s:S:tT:u:v:z:")) != -1) + while ((opt = getopt(argc, argv, "7b:c:Cd:D:efFgH:i:Ilm:M:n:p:s:S:tT:u:v:z:")) != -1) { switch (opt) { + case '7': + t37_like_output = true; + break; + case 'b': + allowed_bilevel_resolutions[allowed] = atoi(optarg); + allowed ^= 1; + break; case 'c': code_to_look_up = atoi(optarg); break; + case 'C': + colour_enabled = true; + break; case 'd': decode_file_name = optarg; break; @@ -544,17 +563,17 @@ int main(int argc, char *argv[]) drop_frame = atoi(optarg); break; case 'e': - use_ecm = TRUE; + use_ecm = true; break; case 'f': - feedback_audio = TRUE; + feedback_audio = true; break; case 'F': - remove_fill_bits = TRUE; + remove_fill_bits = true; break; case 'g': #if defined(ENABLE_GUI) - use_gui = TRUE; + use_gui = true; #else fprintf(stderr, "Graphical monitoring not available\n"); exit(2); @@ -567,10 +586,10 @@ int main(int argc, char *argv[]) input_tiff_file_name = optarg; break; case 'I': - t38_simulate_incrementing_repeats = TRUE; + t38_simulate_incrementing_repeats = true; break; case 'l': - log_audio = TRUE; + log_audio = true; break; case 'm': supported_modems = atoi(optarg); @@ -620,7 +639,7 @@ int main(int argc, char *argv[]) scan_line_time = atoi(optarg); break; case 't': - use_tep = TRUE; + use_tep = true; break; case 'T': start_page = 0; @@ -839,43 +858,118 @@ int main(int argc, char *argv[]) | T30_SUPPORT_SELECTIVE_POLLING | T30_SUPPORT_SUB_ADDRESSING); t30_set_supported_image_sizes(t30_state[i], - T30_SUPPORT_US_LETTER_LENGTH - | T30_SUPPORT_US_LEGAL_LENGTH - | T30_SUPPORT_UNLIMITED_LENGTH - | T30_SUPPORT_215MM_WIDTH - | T30_SUPPORT_255MM_WIDTH - | T30_SUPPORT_303MM_WIDTH); - t30_set_supported_resolutions(t30_state[i], - T30_SUPPORT_STANDARD_RESOLUTION - | T30_SUPPORT_FINE_RESOLUTION - | T30_SUPPORT_SUPERFINE_RESOLUTION - | T30_SUPPORT_R8_RESOLUTION - | T30_SUPPORT_R16_RESOLUTION - | T30_SUPPORT_300_300_RESOLUTION - | T30_SUPPORT_400_400_RESOLUTION - | T30_SUPPORT_600_600_RESOLUTION - | T30_SUPPORT_1200_1200_RESOLUTION - | T30_SUPPORT_300_600_RESOLUTION - | T30_SUPPORT_400_800_RESOLUTION - | T30_SUPPORT_600_1200_RESOLUTION); - //t30_set_rx_encoding(t30_state[i], T4_COMPRESSION_ITU_T85); - t30_set_ecm_capability(t30_state[i], use_ecm); - if (use_ecm) + T4_SUPPORT_WIDTH_215MM + | T4_SUPPORT_WIDTH_255MM + | T4_SUPPORT_WIDTH_303MM + | T4_SUPPORT_LENGTH_US_LETTER + | T4_SUPPORT_LENGTH_US_LEGAL + | T4_SUPPORT_LENGTH_UNLIMITED); + switch (allowed_bilevel_resolutions[i]) { - t30_set_supported_compressions(t30_state[i], - T30_SUPPORT_T4_1D_COMPRESSION - | T30_SUPPORT_T4_2D_COMPRESSION - | T30_SUPPORT_T6_COMPRESSION - //| T30_SUPPORT_T81_COMPRESSION - | T30_SUPPORT_T85_COMPRESSION - | T30_SUPPORT_T85_L0_COMPRESSION); + case 0: + /* Allow anything */ + t30_set_supported_bilevel_resolutions(t30_state[i], + T4_RESOLUTION_R8_STANDARD + | T4_RESOLUTION_R8_FINE + | T4_RESOLUTION_R8_SUPERFINE + | T4_RESOLUTION_R16_SUPERFINE + | T4_RESOLUTION_200_100 + | T4_RESOLUTION_200_200 + | T4_RESOLUTION_200_400 + | T4_RESOLUTION_300_300 + | T4_RESOLUTION_300_600 + | T4_RESOLUTION_400_400 + | T4_RESOLUTION_400_800 + | T4_RESOLUTION_600_600 + | T4_RESOLUTION_600_1200 + | T4_RESOLUTION_1200_1200); + break; + case 1: + /* Allow anything metric */ + t30_set_supported_bilevel_resolutions(t30_state[i], + T4_RESOLUTION_R8_STANDARD + | T4_RESOLUTION_R8_FINE + | T4_RESOLUTION_R8_SUPERFINE + | T4_RESOLUTION_R16_SUPERFINE); + break; + case 2: + /* Allow anything inch based */ + t30_set_supported_bilevel_resolutions(t30_state[i], + T4_RESOLUTION_200_100 + | T4_RESOLUTION_200_200 + | T4_RESOLUTION_200_400 + | T4_RESOLUTION_300_300 + | T4_RESOLUTION_300_600 + | T4_RESOLUTION_400_400 + | T4_RESOLUTION_400_800 + | T4_RESOLUTION_600_600 + | T4_RESOLUTION_600_1200 + | T4_RESOLUTION_1200_1200); + break; + case 3: + /* Allow only restricted length resolution */ + t30_set_supported_bilevel_resolutions(t30_state[i], + T4_RESOLUTION_R8_STANDARD + | T4_RESOLUTION_R8_FINE + | T4_RESOLUTION_200_100 + | T4_RESOLUTION_200_200); + break; + case 4: + /* Allow only more restricted length resolution */ + t30_set_supported_bilevel_resolutions(t30_state[i], + T4_RESOLUTION_R8_STANDARD + | T4_RESOLUTION_200_100); + break; + } + if (colour_enabled) + { + t30_set_supported_colour_resolutions(t30_state[i], + T4_RESOLUTION_100_100 + | T4_RESOLUTION_200_200 + | T4_RESOLUTION_300_300 + | T4_RESOLUTION_400_400 + | T4_RESOLUTION_600_600 + | T4_RESOLUTION_1200_1200); } else { - t30_set_supported_compressions(t30_state[i], - T30_SUPPORT_T4_1D_COMPRESSION - | T30_SUPPORT_T4_2D_COMPRESSION); + t30_set_supported_colour_resolutions(t30_state[i], 0); } + if (t37_like_output) + { + t30_set_supported_output_compressions(t30_state[i], + T4_COMPRESSION_T85 + | T4_COMPRESSION_T85_L0 + | T4_COMPRESSION_T6 + | T4_COMPRESSION_T42_T81); + } + else + { + t30_set_supported_output_compressions(t30_state[i], + T4_COMPRESSION_T6 + | T4_COMPRESSION_JPEG); + } + + t30_set_ecm_capability(t30_state[i], use_ecm); + t30_set_supported_compressions(t30_state[i], + T4_COMPRESSION_T4_1D + | T4_COMPRESSION_T4_2D + | T4_COMPRESSION_T6 + | T4_COMPRESSION_T85 + | T4_COMPRESSION_T85_L0 + //| T4_COMPRESSION_T88 + | T4_COMPRESSION_T43 + | T4_COMPRESSION_T45 + | T4_COMPRESSION_T42_T81 + | T4_COMPRESSION_SYCC_T81 + | T4_COMPRESSION_GRAYSCALE + | T4_COMPRESSION_COLOUR + | T4_COMPRESSION_12BIT + | T4_COMPRESSION_COLOUR_TO_GRAY + | T4_COMPRESSION_GRAY_TO_BILEVEL + | T4_COMPRESSION_COLOUR_TO_BILEVEL + | T4_COMPRESSION_RESCALING + | 0); t30_set_minimum_scan_line_time(t30_state[i], scan_line_time); if (mode[i] == T38_GATEWAY_FAX) @@ -904,9 +998,9 @@ int main(int argc, char *argv[]) break; case T38_TRANSPORT_TCP: case T38_TRANSPORT_TCP_TPKT: - t38_terminal_set_fill_bit_removal(t38_state[i], TRUE); + t38_terminal_set_fill_bit_removal(t38_state[i], true); t38_terminal_set_config(t38_state[i], T38_TERMINAL_OPTION_NO_PACING | T38_TERMINAL_OPTION_NO_INDICATORS); - t38_terminal_set_tep_mode(t38_state[i], FALSE); + t38_terminal_set_tep_mode(t38_state[i], false); break; } } @@ -951,10 +1045,14 @@ int main(int argc, char *argv[]) logging = fax_get_logging_state(fax_state[i]); 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); if (!t30_call_active(t30_state[i])) { - completed[i] = TRUE; + completed[i] = true; continue; } diff --git a/libs/spandsp/tests/fax_tests.sh b/libs/spandsp/tests/fax_tests.sh index e273968630..a4d36ce501 100755 --- a/libs/spandsp/tests/fax_tests.sh +++ b/libs/spandsp/tests/fax_tests.sh @@ -17,7 +17,7 @@ run_fax_test() { - rm -f fax_tests_1.tif + rm -f fax_tests.tif echo ./fax_tests ${OPTS} -i ${FILE} ./fax_tests ${OPTS} -i ${FILE} >xyzzy 2>xyzzy2 RETVAL=$? @@ -28,118 +28,371 @@ run_fax_test() fi # Now use tiffcmp to check the results. It will return non-zero if any page images differ. The -t # option means the normal differences in tags will be ignored. - tiffcmp -t ${FILE} fax_tests.tif >/dev/null + ${TIFFCMP} -t ${FILE} fax_tests.tif >/dev/null RETVAL=$? if [ $RETVAL != 0 ] then echo fax_tests failed! exit $RETVAL fi - rm -f fax_tests_1.tif + rm -f fax_tests.tif echo tested ${FILE} } -ITUTESTS_DIR=../test-data/itu/fax +run_fax_squash_test() +{ + # Test with lengthwise squashing of a bilevel image + rm -f fax_tests.tif + echo ./fax_tests -b ${SQ} -b ${SQ} ${OPTS} -i ${IN_FILE} + ./fax_tests -b ${SQ} ${OPTS} -i ${IN_FILE} >xyzzy 2>xyzzy2 + RETVAL=$? + if [ $RETVAL != 0 ] + then + echo fax_tests failed! + exit $RETVAL + fi + # Now use tiffcmp to check the results. It will return non-zero if any page images differ. The -t + # option means the normal differences in tags will be ignored. + ${TIFFCMP} -t ${OUT_FILE} fax_tests.tif >/dev/null + RETVAL=$? + if [ $RETVAL != 0 ] + then + echo fax_tests failed! + exit $RETVAL + fi + rm -f fax_tests.tif + echo tested ${FILE} +} +run_colour_fax_test() +{ + rm -f fax_tests.tif + echo ./fax_tests ${OPTS} -i ${IN_FILE} + ./fax_tests ${OPTS} -i ${IN_FILE} >xyzzy 2>xyzzy2 + RETVAL=$? + if [ $RETVAL != 0 ] + then + echo fax_tests failed! + exit $RETVAL + fi + # Now use tiffcmp to check the results. It will return non-zero if any page images differ. The -t + # option means the normal differences in tags will be ignored. + ${TIFFCMP} -t ${OUT_FILE} fax_tests.tif >/dev/null + RETVAL=$? + if [ $RETVAL != 0 ] + then + echo fax_tests failed! + exit $RETVAL + fi + rm -f fax_tests.tif + echo tested ${IN_FILE} to ${OUT_FILE} +} + +ITUTESTS_DIR=../test-data/itu/fax +TIFFFX_DIR=../test-data/itu/tiff-fx +LOCALTESTS_DIR=../test-data/local +TIFFCMP=tiffcmp + +# Colour/gray -> bilevel by not allowing ECM +for OPTS in "-p AA" "-p TT" "-p GG" "-p TG" "-p GT" +do + IN_FILE="${LOCALTESTS_DIR}/lenna-colour.tif" + OUT_FILE="${LOCALTESTS_DIR}/lenna-colour-bilevel.tif" + run_colour_fax_test + + IN_FILE="${LOCALTESTS_DIR}/lenna-bw.tif" + OUT_FILE="${LOCALTESTS_DIR}/lenna-bw-bilevel.tif" + run_colour_fax_test + + IN_FILE="${TIFFFX_DIR}/c03x_02x.tif" + OUT_FILE="${TIFFFX_DIR}/c03x_02x-bilevel.tif" + run_colour_fax_test + + IN_FILE="${TIFFFX_DIR}/l02x_02x.tif" + OUT_FILE="${TIFFFX_DIR}/l02x_02x-bilevel.tif" + run_colour_fax_test + + IN_FILE="${TIFFFX_DIR}/l04x_02x.tif" + OUT_FILE="${TIFFFX_DIR}/l04x_02x-bilevel.tif" + run_colour_fax_test +done + +# Colour/gray -> colour/gray +for OPTS in "-p AA -C -e" "-p TT -C -e" "-p GG -C -e" "-p TG -C -e" "-p GT -C -e" +do +# IN_FILE="${LOCALTESTS_DIR}/lenna-colour.tif" +# OUT_FILE="${LOCALTESTS_DIR}/lenna-colour-out.tif" +# run_colour_fax_test + +# IN_FILE="${LOCALTESTS_DIR}/lenna-bw.tif" +# OUT_FILE="${LOCALTESTS_DIR}/lenna-bw-out.tif" +# run_colour_fax_test + +# IN_FILE="${TIFFFX_DIR}/c03x_02x.tif" +# OUT_FILE="${TIFFFX_DIR}/c03x_02x-out.tif" +# run_colour_fax_test + + IN_FILE="${TIFFFX_DIR}/l02x_02x.tif" + OUT_FILE="${TIFFFX_DIR}/l02x_02x.tif" + run_colour_fax_test + +# IN_FILE="${TIFFFX_DIR}/l04x_02x.tif" +# OUT_FILE="${TIFFFX_DIR}/l04x_02x.tif" +# run_colour_fax_test +done + +# Bi-level tests with image squashing for OPTS in "-p AA" "-p AA -e" "-p TT" "-p TT -e" "-p GG" "-p GG -e" "-p TG" "-p TG -e" "-p GT" "-p GT -e" do - FILE="${ITUTESTS_DIR}/R8_385_A4.tif" + IN_FILE="${ITUTESTS_DIR}/bilevel_R8_77_A4.tif" + OUT_FILE="${ITUTESTS_DIR}/bilevel_R8_77SQ_A4.tif" + SQ=4 + run_fax_squash_test + + IN_FILE="${ITUTESTS_DIR}/bilevel_R8_77_B4.tif" + OUT_FILE="${ITUTESTS_DIR}/bilevel_R8_77SQ_B4.tif" + SQ=4 + run_fax_squash_test + + IN_FILE="${ITUTESTS_DIR}/bilevel_R8_77_A3.tif" + OUT_FILE="${ITUTESTS_DIR}/bilevel_R8_77SQ_A3.tif" + SQ=4 + run_fax_squash_test + + + IN_FILE="${ITUTESTS_DIR}/bilevel_R8_154_A4.tif" + OUT_FILE="${ITUTESTS_DIR}/bilevel_R8_154SQ_A4.tif" + SQ=3 + run_fax_squash_test + + IN_FILE="${ITUTESTS_DIR}/bilevel_R8_154_B4.tif" + OUT_FILE="${ITUTESTS_DIR}/bilevel_R8_154SQ_B4.tif" + SQ=3 + run_fax_squash_test + + IN_FILE="${ITUTESTS_DIR}/bilevel_R8_154_A3.tif" + OUT_FILE="${ITUTESTS_DIR}/bilevel_R8_154SQ_A3.tif" + SQ=3 + run_fax_squash_test + + + IN_FILE="${ITUTESTS_DIR}/bilevel_R8_154_A4.tif" + OUT_FILE="${ITUTESTS_DIR}/bilevel_R8_154SQSQ_A4.tif" + SQ=4 + run_fax_squash_test + + IN_FILE="${ITUTESTS_DIR}/bilevel_R8_154_B4.tif" + OUT_FILE="${ITUTESTS_DIR}/bilevel_R8_154SQSQ_B4.tif" + SQ=4 + run_fax_squash_test + + IN_FILE="${ITUTESTS_DIR}/bilevel_R8_154_A3.tif" + OUT_FILE="${ITUTESTS_DIR}/bilevel_R8_154SQSQ_A3.tif" + SQ=4 + run_fax_squash_test + + + IN_FILE="${ITUTESTS_DIR}/bilevel_200_200_A4.tif" + OUT_FILE="${ITUTESTS_DIR}/bilevel_200_200SQ_A4.tif" + SQ=4 + run_fax_squash_test + + IN_FILE="${ITUTESTS_DIR}/bilevel_200_200_B4.tif" + OUT_FILE="${ITUTESTS_DIR}/bilevel_200_200SQ_B4.tif" + SQ=4 + run_fax_squash_test + + IN_FILE="${ITUTESTS_DIR}/bilevel_200_200_A3.tif" + OUT_FILE="${ITUTESTS_DIR}/bilevel_200_200SQ_A3.tif" + SQ=4 + run_fax_squash_test + + + IN_FILE="${ITUTESTS_DIR}/bilevel_200_400_A4.tif" + OUT_FILE="${ITUTESTS_DIR}/bilevel_200_400SQ_A4.tif" + SQ=3 + run_fax_squash_test + + IN_FILE="${ITUTESTS_DIR}/bilevel_200_400_B4.tif" + OUT_FILE="${ITUTESTS_DIR}/bilevel_200_400SQ_B4.tif" + SQ=3 + run_fax_squash_test + + IN_FILE="${ITUTESTS_DIR}/bilevel_200_400_A3.tif" + OUT_FILE="${ITUTESTS_DIR}/bilevel_200_400SQ_A3.tif" + SQ=3 + run_fax_squash_test + + + IN_FILE="${ITUTESTS_DIR}/bilevel_200_400_A4.tif" + OUT_FILE="${ITUTESTS_DIR}/bilevel_200_400SQSQ_A4.tif" + SQ=4 + run_fax_squash_test + + IN_FILE="${ITUTESTS_DIR}/bilevel_200_400_B4.tif" + OUT_FILE="${ITUTESTS_DIR}/bilevel_200_400SQSQ_B4.tif" + SQ=4 + run_fax_squash_test + + IN_FILE="${ITUTESTS_DIR}/bilevel_200_400_A3.tif" + OUT_FILE="${ITUTESTS_DIR}/bilevel_200_400SQSQ_A3.tif" + SQ=4 + run_fax_squash_test +done + +# Bi-level tests +for OPTS in "-p AA" "-p AA -e" "-p TT" "-p TT -e" "-p GG" "-p GG -e" "-p TG" "-p TG -e" "-p GT" "-p GT -e" +do + FILE="${ITUTESTS_DIR}/itutests.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R8_385_B4.tif" + FILE="${ITUTESTS_DIR}/100pages.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R8_385_A3.tif" + FILE="${ITUTESTS_DIR}/striped.tif" + run_fax_test + + FILE="${ITUTESTS_DIR}/mixed_size_pages.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R8_77_A4.tif" + FILE="${ITUTESTS_DIR}/bilevel_R8_385_A4.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R8_77_B4.tif" + FILE="${ITUTESTS_DIR}/bilevel_R8_385_B4.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R8_77_A3.tif" + FILE="${ITUTESTS_DIR}/bilevel_R8_385_A3.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R8_154_A4.tif" + FILE="${ITUTESTS_DIR}/bilevel_R8_77_A4.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R8_154_B4.tif" + FILE="${ITUTESTS_DIR}/bilevel_R8_77_B4.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R8_154_A3.tif" + FILE="${ITUTESTS_DIR}/bilevel_R8_77_A3.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R300_300_A4.tif" + FILE="${ITUTESTS_DIR}/bilevel_R8_154_A4.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R300_300_B4.tif" + FILE="${ITUTESTS_DIR}/bilevel_R8_154_B4.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R300_300_A3.tif" + FILE="${ITUTESTS_DIR}/bilevel_R8_154_A3.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R300_600_A4.tif" + FILE="${ITUTESTS_DIR}/bilevel_R16_154_A4.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R300_600_B4.tif" + FILE="${ITUTESTS_DIR}/bilevel_R16_154_B4.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R300_600_A3.tif" + FILE="${ITUTESTS_DIR}/bilevel_R16_154_A3.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R16_154_A4.tif" + FILE="${ITUTESTS_DIR}/bilevel_200_100_A4.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R16_154_B4.tif" + FILE="${ITUTESTS_DIR}/bilevel_200_100_B4.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R16_154_A3.tif" + FILE="${ITUTESTS_DIR}/bilevel_200_100_A3.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R16_800_A4.tif" + FILE="${ITUTESTS_DIR}/bilevel_200_200_A4.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R16_800_B4.tif" + FILE="${ITUTESTS_DIR}/bilevel_200_200_B4.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R16_800_A3.tif" + FILE="${ITUTESTS_DIR}/bilevel_200_200_A3.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R600_600_A4.tif" + FILE="${ITUTESTS_DIR}/bilevel_200_400_A4.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R600_600_B4.tif" + FILE="${ITUTESTS_DIR}/bilevel_200_400_B4.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R600_600_A3.tif" + FILE="${ITUTESTS_DIR}/bilevel_200_400_A3.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R600_1200_A4.tif" + FILE="${ITUTESTS_DIR}/bilevel_300_300_A4.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R600_1200_B4.tif" + FILE="${ITUTESTS_DIR}/bilevel_300_300_B4.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R600_1200_A3.tif" + FILE="${ITUTESTS_DIR}/bilevel_300_300_A3.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R1200_1200_A4.tif" + FILE="${ITUTESTS_DIR}/bilevel_300_600_A4.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R1200_1200_B4.tif" + FILE="${ITUTESTS_DIR}/bilevel_300_600_B4.tif" run_fax_test - FILE="${ITUTESTS_DIR}/R1200_1200_A3.tif" + FILE="${ITUTESTS_DIR}/bilevel_300_600_A3.tif" + run_fax_test + + + FILE="${ITUTESTS_DIR}/bilevel_400_400_A4.tif" + run_fax_test + + FILE="${ITUTESTS_DIR}/bilevel_400_400_B4.tif" + run_fax_test + + FILE="${ITUTESTS_DIR}/bilevel_400_400_A3.tif" + run_fax_test + + + FILE="${ITUTESTS_DIR}/bilevel_400_800_A4.tif" + run_fax_test + + FILE="${ITUTESTS_DIR}/bilevel_400_800_B4.tif" + run_fax_test + + FILE="${ITUTESTS_DIR}/bilevel_400_800_A3.tif" + run_fax_test + + + FILE="${ITUTESTS_DIR}/bilevel_600_600_A4.tif" + run_fax_test + + FILE="${ITUTESTS_DIR}/bilevel_600_600_B4.tif" + run_fax_test + + FILE="${ITUTESTS_DIR}/bilevel_600_600_A3.tif" + run_fax_test + + + FILE="${ITUTESTS_DIR}/bilevel_600_1200_A4.tif" + run_fax_test + + FILE="${ITUTESTS_DIR}/bilevel_600_1200_B4.tif" + run_fax_test + + FILE="${ITUTESTS_DIR}/bilevel_600_1200_A3.tif" + run_fax_test + + + FILE="${ITUTESTS_DIR}/bilevel_1200_1200_A4.tif" + run_fax_test + + FILE="${ITUTESTS_DIR}/bilevel_1200_1200_B4.tif" + run_fax_test + + FILE="${ITUTESTS_DIR}/bilevel_1200_1200_A3.tif" run_fax_test done diff --git a/libs/spandsp/tests/fax_utils.c b/libs/spandsp/tests/fax_utils.c index b6f075da6d..7491d862f3 100644 --- a/libs/spandsp/tests/fax_utils.c +++ b/libs/spandsp/tests/fax_utils.c @@ -103,7 +103,7 @@ void fax_log_page_transfer_statistics(t30_state_t *s, const char *tag) printf("%s: Pages in the file %d\n", tag, t.pages_in_file); printf("%s: Bad rows %d, longest bad row run %d\n", tag, t.bad_rows, t.longest_bad_row_run); printf("%s: Bad ECM frames %d\n", tag, t.error_correcting_mode_retries); - printf("%s: Compression type %s (%d)\n", tag, t4_encoding_to_str(t.encoding), t.encoding); + printf("%s: Compression type %s (%d)\n", tag, t4_compression_to_str(t.compression), t.compression); printf("%s: Compressed image size %d bytes\n", tag, t.image_size); printf("%s: Image type %s (%s in the file)\n", tag, t4_image_type_to_str(t.type), t4_image_type_to_str(t.image_type)); printf("%s: Image size %d pels x %d pels (%d pels x %d pels in the file)\n", tag, t.width, t.length, t.image_width, t.image_length); diff --git a/libs/spandsp/tests/fsk_tests.c b/libs/spandsp/tests/fsk_tests.c index 9cd69f5865..db8a1335a7 100644 --- a/libs/spandsp/tests/fsk_tests.c +++ b/libs/spandsp/tests/fsk_tests.c @@ -61,7 +61,7 @@ These tests allow either: char *decode_test_file = NULL; both_ways_line_model_state_t *model; int rx_bits = 0; -int cutoff_test_carrier = FALSE; +bool cutoff_test_carrier = false; static void rx_status(void *user_data, int status) { @@ -93,10 +93,10 @@ static void cutoff_test_rx_status(void *user_data, int status) switch (status) { case SIG_STATUS_CARRIER_UP: - cutoff_test_carrier = TRUE; + cutoff_test_carrier = true; break; case SIG_STATUS_CARRIER_DOWN: - cutoff_test_carrier = FALSE; + cutoff_test_carrier = false; break; } } @@ -186,23 +186,23 @@ int main(int argc, char *argv[]) int modem_under_test_1; int modem_under_test_2; int modems_set; - int log_audio; int channel_codec; int rbs_pattern; int on_at; int off_at; + int opt; + bool log_audio; tone_gen_descriptor_t tone_desc; tone_gen_state_t tone_tx; - int opt; channel_codec = MUNGE_CODEC_NONE; rbs_pattern = 0; line_model_no = 0; decode_test_file = NULL; - noise_sweep = FALSE; + noise_sweep = false; modem_under_test_1 = FSK_V21CH1; modem_under_test_2 = FSK_V21CH2; - log_audio = FALSE; + log_audio = false; modems_set = 0; while ((opt = getopt(argc, argv, "c:d:lm:nr:s:")) != -1) { @@ -215,13 +215,13 @@ int main(int argc, char *argv[]) decode_test_file = optarg; break; case 'l': - log_audio = TRUE; + log_audio = true; break; case 'm': line_model_no = atoi(optarg); break; case 'n': - noise_sweep = TRUE; + noise_sweep = true; break; case 'r': rbs_pattern = atoi(optarg); @@ -315,7 +315,7 @@ int main(int argc, char *argv[]) 0, 0, 0, - TRUE); + true); tone_gen_init(&tone_tx, &tone_desc); for (j = 0; j < 10; j++) { @@ -338,7 +338,7 @@ int main(int argc, char *argv[]) 0, 0, 0, - TRUE); + true); tone_gen_init(&tone_tx, &tone_desc); for (j = 0; j < 10; j++) { diff --git a/libs/spandsp/tests/g1050_tests.c b/libs/spandsp/tests/g1050_tests.c index b9d87f5dd3..a7919e9575 100644 --- a/libs/spandsp/tests/g1050_tests.c +++ b/libs/spandsp/tests/g1050_tests.c @@ -87,7 +87,7 @@ int main(int argc, char *argv[]) #endif #if defined(ENABLE_GUI) - use_gui = FALSE; + use_gui = false; #endif model_no = MODEL_NO; speed_pattern_no = SPEED_PATTERN_NO; @@ -98,7 +98,7 @@ int main(int argc, char *argv[]) { case 'g': #if defined(ENABLE_GUI) - use_gui = TRUE; + use_gui = true; #else fprintf(stderr, "Graphical monitoring not available\n"); exit(2); diff --git a/libs/spandsp/tests/g168_tests.c b/libs/spandsp/tests/g168_tests.c index 8a1fbabbc0..41351496c6 100644 --- a/libs/spandsp/tests/g168_tests.c +++ b/libs/spandsp/tests/g168_tests.c @@ -38,9 +38,6 @@ #include "spandsp/g168models.h" #include "spandsp-sim.h" -#define FALSE 0 -#define TRUE (!FALSE) - typedef struct { const char *name; @@ -158,7 +155,7 @@ int main(int argc, char *argv[]) 0, 0, 0, - TRUE); + true); tone_gen_init(&tone_state, &tone_desc); tone_gen(&tone_state, amp, 8000); for (i = 0; i < 10; i++) diff --git a/libs/spandsp/tests/g711_tests.c b/libs/spandsp/tests/g711_tests.c index bb0956d677..c6ef2b1f78 100644 --- a/libs/spandsp/tests/g711_tests.c +++ b/libs/spandsp/tests/g711_tests.c @@ -353,10 +353,10 @@ int main(int argc, char *argv[]) int16_t outdata[BLOCK_LEN]; uint8_t g711data[BLOCK_LEN]; - basic_tests = TRUE; + basic_tests = true; law = G711_ALAW; - encode = FALSE; - decode = FALSE; + encode = false; + decode = false; in_file = NULL; out_file = NULL; while ((opt = getopt(argc, argv, "ad:e:l:u")) != -1) @@ -365,24 +365,24 @@ int main(int argc, char *argv[]) { case 'a': law = G711_ALAW; - basic_tests = FALSE; + basic_tests = false; break; case 'd': in_file = optarg; - basic_tests = FALSE; - decode = TRUE; + basic_tests = false; + decode = true; break; case 'e': in_file = optarg; - basic_tests = FALSE; - encode = TRUE; + basic_tests = false; + encode = true; break; case 'l': out_file = optarg; break; case 'u': law = G711_ULAW; - basic_tests = FALSE; + basic_tests = false; break; default: //usage(); @@ -392,14 +392,14 @@ int main(int argc, char *argv[]) if (basic_tests) { - compliance_tests(TRUE); + compliance_tests(true); } else { if (!decode && !encode) { decode = - encode = TRUE; + encode = true; } if (in_file == NULL) { diff --git a/libs/spandsp/tests/g722_tests.c b/libs/spandsp/tests/g722_tests.c index dff1b959d2..daafaef6d6 100644 --- a/libs/spandsp/tests/g722_tests.c +++ b/libs/spandsp/tests/g722_tests.c @@ -258,7 +258,7 @@ static void itu_compliance_tests(void) } len = j - i; enc_state = g722_encode_init(NULL, 64000, 0); - enc_state->itu_test_mode = TRUE; + enc_state->itu_test_mode = true; len2 = g722_encode(enc_state, compressed, itu_data + i, len); /* Check the result against the ITU's reference output data */ @@ -324,7 +324,7 @@ static void itu_compliance_tests(void) compressed[k] = itu_data[k + i] >> ((mode == 3) ? 10 : (mode == 2) ? 9 : 8); dec_state = g722_decode_init(NULL, (mode == 3) ? 48000 : (mode == 2) ? 56000 : 64000, 0); - dec_state->itu_test_mode = TRUE; + dec_state->itu_test_mode = true; len2 = g722_decode(dec_state, decompressed, compressed, len); /* Check the result against the ITU's reference output data */ @@ -358,8 +358,8 @@ static void signal_to_distortion_tests(void) g722_encode_state_t *enc_state; g722_decode_state_t *dec_state; swept_tone_state_t *swept; - power_meter_t in_meter; - power_meter_t out_meter; + power_meter_t *in_meter; + power_meter_t *out_meter; int16_t original[1024]; uint8_t compressed[1024]; int16_t decompressed[1024]; @@ -374,32 +374,32 @@ static void signal_to_distortion_tests(void) Figure 16/G.722, Figure A.1/G.722, and Figure A.2/G.722 */ enc_state = g722_encode_init(NULL, 64000, 0); dec_state = g722_decode_init(NULL, 64000, 0); - power_meter_init(&in_meter, 7); - power_meter_init(&out_meter, 7); + in_meter = power_meter_init(NULL, 7); + out_meter = power_meter_init(NULL, 7); /* First some silence */ len = 1024; memset(original, 0, len*sizeof(original[0])); for (i = 0; i < len; i++) - in_level = power_meter_update(&in_meter, original[i]); + in_level = power_meter_update(in_meter, original[i]); len2 = g722_encode(enc_state, compressed, original, len); len3 = g722_decode(dec_state, decompressed, compressed, len2); out_level = 0; for (i = 0; i < len3; i++) - out_level = power_meter_update(&out_meter, decompressed[i]); + out_level = power_meter_update(out_meter, decompressed[i]); printf("Silence produces %d at the output\n", out_level); /* Now a swept tone test */ - swept = swept_tone_init(NULL, 25.0f, 3500.0f, -10.0f, 60*16000, FALSE); + swept = swept_tone_init(NULL, 25.0f, 3500.0f, -10.0f, 60*16000, false); do { len = swept_tone(swept, original, 1024); for (i = 0; i < len; i++) - in_level = power_meter_update(&in_meter, original[i]); + in_level = power_meter_update(in_meter, original[i]); len2 = g722_encode(enc_state, compressed, original, len); len3 = g722_decode(dec_state, decompressed, compressed, len2); for (i = 0; i < len3; i++) - out_level = power_meter_update(&out_meter, decompressed[i]); + out_level = power_meter_update(out_meter, decompressed[i]); printf("%10d, %10d, %f\n", in_level, out_level, (float) out_level/in_level); } while (len > 0); @@ -437,12 +437,12 @@ int main(int argc, char *argv[]) int32_t tone_phase_rate; bit_rate = 64000; - eight_k_in = FALSE; - eight_k_out = FALSE; - itutests = TRUE; - encode = FALSE; - decode = FALSE; - tone_test = FALSE; + eight_k_in = false; + eight_k_out = false; + itutests = true; + encode = false; + decode = false; + tone_test = false; in_file = NULL; out_file = NULL; while ((opt = getopt(argc, argv, "b:d:e:i:l:o:t")) != -1) @@ -456,17 +456,17 @@ int main(int argc, char *argv[]) fprintf(stderr, "Invalid bit rate selected. Only 48000, 56000 and 64000 are valid.\n"); exit(2); } - itutests = FALSE; + itutests = false; break; case 'd': in_file = optarg; - decode = TRUE; - itutests = FALSE; + decode = true; + itutests = false; break; case 'e': in_file = optarg; - encode = TRUE; - itutests = FALSE; + encode = true; + itutests = false; break; case 'i': i = atoi(optarg); @@ -492,8 +492,8 @@ int main(int argc, char *argv[]) eight_k_out = (i == 8000); break; case 't': - tone_test = TRUE; - itutests = FALSE; + tone_test = true; + itutests = false; break; default: //usage(); @@ -514,7 +514,7 @@ int main(int argc, char *argv[]) if (!decode && !encode) { decode = - encode = TRUE; + encode = true; } if (in_file == NULL) { diff --git a/libs/spandsp/tests/g726_tests.c b/libs/spandsp/tests/g726_tests.c index 4fba66021e..0bba6e2fcc 100644 --- a/libs/spandsp/tests/g726_tests.c +++ b/libs/spandsp/tests/g726_tests.c @@ -1196,7 +1196,7 @@ int main(int argc, char *argv[]) g726_state_t enc_state; g726_state_t dec_state; int opt; - int itutests; + bool itutests; int bit_rate; SNDFILE *inhandle; SNDFILE *outhandle; @@ -1206,7 +1206,7 @@ int main(int argc, char *argv[]) int packing; bit_rate = 32000; - itutests = TRUE; + itutests = true; packing = G726_PACKING_NONE; while ((opt = getopt(argc, argv, "b:LR")) != -1) { @@ -1219,7 +1219,7 @@ int main(int argc, char *argv[]) fprintf(stderr, "Invalid bit rate selected. Only 16000, 24000, 32000 and 40000 are valid.\n"); exit(2); } - itutests = FALSE; + itutests = false; break; case 'L': packing = G726_PACKING_LEFT; diff --git a/libs/spandsp/tests/gsm0610_tests.c b/libs/spandsp/tests/gsm0610_tests.c index 9993a39260..346f574e99 100644 --- a/libs/spandsp/tests/gsm0610_tests.c +++ b/libs/spandsp/tests/gsm0610_tests.c @@ -512,21 +512,21 @@ static int perform_pack_unpack_test(void) static void etsi_compliance_tests(void) { - perform_linear_test(TRUE, 1, "Seq01"); - perform_linear_test(TRUE, 1, "Seq02"); - perform_linear_test(TRUE, 1, "Seq03"); - perform_linear_test(TRUE, 1, "Seq04"); - perform_linear_test(FALSE, 1, "Seq05"); - perform_law_test(TRUE, 'a', "Seq01"); - perform_law_test(TRUE, 'a', "Seq02"); - perform_law_test(TRUE, 'a', "Seq03"); - perform_law_test(TRUE, 'a', "Seq04"); - perform_law_test(FALSE, 'a', "Seq05"); - perform_law_test(TRUE, 'u', "Seq01"); - perform_law_test(TRUE, 'u', "Seq02"); - perform_law_test(TRUE, 'u', "Seq03"); - perform_law_test(TRUE, 'u', "Seq04"); - perform_law_test(FALSE, 'u', "Seq05"); + perform_linear_test(true, 1, "Seq01"); + perform_linear_test(true, 1, "Seq02"); + perform_linear_test(true, 1, "Seq03"); + perform_linear_test(true, 1, "Seq04"); + perform_linear_test(false, 1, "Seq05"); + perform_law_test(true, 'a', "Seq01"); + perform_law_test(true, 'a', "Seq02"); + perform_law_test(true, 'a', "Seq03"); + perform_law_test(true, 'a', "Seq04"); + perform_law_test(false, 'a', "Seq05"); + perform_law_test(true, 'u', "Seq01"); + perform_law_test(true, 'u', "Seq02"); + perform_law_test(true, 'u', "Seq03"); + perform_law_test(true, 'u', "Seq04"); + perform_law_test(false, 'u', "Seq05"); /* This is not actually an ETSI test */ perform_pack_unpack_test(); @@ -549,14 +549,14 @@ int main(int argc, char *argv[]) int etsitests; int packing; - etsitests = TRUE; + etsitests = true; packing = GSM0610_PACKING_NONE; while ((opt = getopt(argc, argv, "lp:")) != -1) { switch (opt) { case 'l': - etsitests = FALSE; + etsitests = false; break; case 'p': packing = atoi(optarg); diff --git a/libs/spandsp/tests/hdlc_tests.c b/libs/spandsp/tests/hdlc_tests.c index 70df13425c..93a364f4f5 100644 --- a/libs/spandsp/tests/hdlc_tests.c +++ b/libs/spandsp/tests/hdlc_tests.c @@ -46,13 +46,13 @@ using both 16 and 32 bit CRCs. int ref_len; uint8_t buf[1000]; -int abort_reported; -int frame_handled; -int frame_failed; +bool abort_reported; +bool frame_handled; +bool frame_failed; int frame_len_errors; int frame_data_errors; -int underflow_reported; -int framing_ok_reported; +bool underflow_reported; +bool framing_ok_reported; int framing_ok_reports; hdlc_rx_state_t rx; @@ -96,11 +96,11 @@ static void frame_handler(void *user_data, const uint8_t *pkt, int len, int ok) switch (len) { case SIG_STATUS_FRAMING_OK: - framing_ok_reported = TRUE; + framing_ok_reported = true; framing_ok_reports++; break; case SIG_STATUS_ABORT: - abort_reported = TRUE; + abort_reported = true; break; } return; @@ -119,11 +119,11 @@ static void frame_handler(void *user_data, const uint8_t *pkt, int len, int ok) frame_data_errors++; return; } - frame_handled = TRUE; + frame_handled = true; } else { - frame_failed = TRUE; + frame_failed = true; } } /*- End of function --------------------------------------------------------*/ @@ -131,7 +131,7 @@ static void frame_handler(void *user_data, const uint8_t *pkt, int len, int ok) static void underflow_handler(void *user_data) { //printf("Underflow reported\n"); - underflow_reported = TRUE; + underflow_reported = true; } /*- End of function --------------------------------------------------------*/ @@ -183,17 +183,17 @@ static int test_hdlc_modes(void) printf("Testing with CRC-16 (byte by byte)\n"); frame_len_errors = 0; frame_data_errors = 0; - hdlc_tx_init(&tx, FALSE, 1, FALSE, underflow_handler, NULL); - hdlc_rx_init(&rx, FALSE, FALSE, 5, frame_handler, NULL); - underflow_reported = FALSE; + hdlc_tx_init(&tx, false, 1, false, underflow_handler, NULL); + hdlc_rx_init(&rx, false, false, 5, frame_handler, NULL); + underflow_reported = false; start = rdtscll(); hdlc_tx_flags(&tx, 40); /* Push an initial message so we should NOT get an underflow after the preamble. */ ref_len = cook_up_msg(buf); hdlc_tx_frame(&tx, buf, ref_len); - frame_handled = FALSE; - frame_failed = FALSE; + frame_handled = false; + frame_failed = false; frames_sent = 0; bytes_sent = 0; for (i = 0; i < 1000000; i++) @@ -202,7 +202,7 @@ static int test_hdlc_modes(void) hdlc_rx_put_byte(&rx, nextbyte); if (underflow_reported) { - underflow_reported = FALSE; + underflow_reported = false; nextbyte = hdlc_tx_get_byte(&tx); hdlc_rx_put_byte(&rx, nextbyte); frames_sent++; @@ -214,7 +214,7 @@ static int test_hdlc_modes(void) } ref_len = cook_up_msg(buf); hdlc_tx_frame(&tx, buf, ref_len); - frame_handled = FALSE; + frame_handled = false; } } end = rdtscll(); @@ -224,17 +224,17 @@ static int test_hdlc_modes(void) printf("Testing with CRC-16 (chunk by chunk)\n"); frame_len_errors = 0; frame_data_errors = 0; - hdlc_tx_init(&tx, FALSE, 1, FALSE, underflow_handler, NULL); - hdlc_rx_init(&rx, FALSE, FALSE, 5, frame_handler, NULL); - underflow_reported = FALSE; + hdlc_tx_init(&tx, false, 1, false, underflow_handler, NULL); + hdlc_rx_init(&rx, false, false, 5, frame_handler, NULL); + underflow_reported = false; start = rdtscll(); hdlc_tx_flags(&tx, 40); /* Push an initial message so we should NOT get an underflow after the preamble. */ ref_len = cook_up_msg(buf); hdlc_tx_frame(&tx, buf, ref_len); - frame_handled = FALSE; - frame_failed = FALSE; + frame_handled = false; + frame_failed = false; frames_sent = 0; bytes_sent = 0; for (i = 0; i < 10000; i++) @@ -243,7 +243,7 @@ static int test_hdlc_modes(void) hdlc_rx_put(&rx, bufx, len); if (underflow_reported) { - underflow_reported = FALSE; + underflow_reported = false; len = hdlc_tx_get(&tx, bufx, 100); hdlc_rx_put(&rx, bufx, len); frames_sent++; @@ -255,7 +255,7 @@ static int test_hdlc_modes(void) } ref_len = cook_up_msg(buf); hdlc_tx_frame(&tx, buf, ref_len); - frame_handled = FALSE; + frame_handled = false; } } end = rdtscll(); @@ -265,16 +265,16 @@ static int test_hdlc_modes(void) printf("Testing with CRC-16 (bit by bit)\n"); frame_len_errors = 0; frame_data_errors = 0; - hdlc_tx_init(&tx, FALSE, 2, FALSE, underflow_handler, NULL); - hdlc_rx_init(&rx, FALSE, FALSE, 5, frame_handler, NULL); - underflow_reported = FALSE; + hdlc_tx_init(&tx, false, 2, false, underflow_handler, NULL); + hdlc_rx_init(&rx, false, false, 5, frame_handler, NULL); + underflow_reported = false; start = rdtscll(); hdlc_tx_flags(&tx, 40); /* Don't push an initial message so we should get an underflow after the preamble. */ /* Lie for the first message, as there isn't really one */ - frame_handled = TRUE; - frame_failed = FALSE; + frame_handled = true; + frame_failed = false; frames_sent = 0; bytes_sent = 0; ref_len = 0; @@ -284,7 +284,7 @@ static int test_hdlc_modes(void) hdlc_rx_put_bit(&rx, nextbyte); if (underflow_reported) { - underflow_reported = FALSE; + underflow_reported = false; for (j = 0; j < 20; j++) { nextbyte = hdlc_tx_get_bit(&tx); @@ -302,7 +302,7 @@ static int test_hdlc_modes(void) } ref_len = cook_up_msg(buf); hdlc_tx_frame(&tx, buf, ref_len); - frame_handled = FALSE; + frame_handled = false; } } end = rdtscll(); @@ -312,16 +312,16 @@ static int test_hdlc_modes(void) printf("Testing with CRC-32 (byte by byte)\n"); frame_len_errors = 0; frame_data_errors = 0; - hdlc_tx_init(&tx, TRUE, 1, FALSE, underflow_handler, NULL); - hdlc_rx_init(&rx, TRUE, FALSE, 1, frame_handler, NULL); - underflow_reported = FALSE; + hdlc_tx_init(&tx, true, 1, false, underflow_handler, NULL); + hdlc_rx_init(&rx, true, false, 1, frame_handler, NULL); + underflow_reported = false; start = rdtscll(); hdlc_tx_flags(&tx, 40); /* Don't push an initial message so we should get an underflow after the preamble. */ /* Lie for the first message, as there isn't really one */ - frame_handled = TRUE; - frame_failed = FALSE; + frame_handled = true; + frame_failed = false; frames_sent = 0; bytes_sent = 0; ref_len = 0; @@ -331,7 +331,7 @@ static int test_hdlc_modes(void) hdlc_rx_put_byte(&rx, nextbyte); if (underflow_reported) { - underflow_reported = FALSE; + underflow_reported = false; nextbyte = hdlc_tx_get_byte(&tx); hdlc_rx_put_byte(&rx, nextbyte); if (ref_len) @@ -346,7 +346,7 @@ static int test_hdlc_modes(void) } ref_len = cook_up_msg(buf); hdlc_tx_frame(&tx, buf, ref_len); - frame_handled = FALSE; + frame_handled = false; } } end = rdtscll(); @@ -356,16 +356,16 @@ static int test_hdlc_modes(void) printf("Testing progressive mode with CRC-16 (byte by byte)\n"); frame_len_errors = 0; frame_data_errors = 0; - hdlc_tx_init(&tx, TRUE, 1, TRUE, underflow_handler, NULL); - hdlc_rx_init(&rx, TRUE, FALSE, 1, frame_handler, NULL); - underflow_reported = FALSE; + hdlc_tx_init(&tx, true, 1, true, underflow_handler, NULL); + hdlc_rx_init(&rx, true, false, 1, frame_handler, NULL); + underflow_reported = false; start = rdtscll(); hdlc_tx_flags(&tx, 40); /* Don't push an initial message so we should get an underflow after the preamble. */ /* Lie for the first message, as there isn't really one */ - frame_handled = TRUE; - frame_failed = FALSE; + frame_handled = true; + frame_failed = false; progress = 9999; progress_delay = 9999; frames_sent = 0; @@ -377,7 +377,7 @@ static int test_hdlc_modes(void) hdlc_rx_put_byte(&rx, nextbyte); if (underflow_reported) { - underflow_reported = FALSE; + underflow_reported = false; nextbyte = hdlc_tx_get_byte(&tx); hdlc_rx_put_byte(&rx, nextbyte); if (ref_len) @@ -394,7 +394,7 @@ static int test_hdlc_modes(void) hdlc_tx_frame(&tx, buf, 10); progress = 10; progress_delay = 8; - frame_handled = FALSE; + frame_handled = false; } if (progress < ref_len && progress_delay-- <= 0) { @@ -424,18 +424,18 @@ static int test_hdlc_frame_length_error_handling(void) printf("Testing frame length error handling using CRC-16 (bit by bit)\n"); frame_len_errors = 0; frame_data_errors = 0; - hdlc_tx_init(&tx, FALSE, 2, FALSE, underflow_handler, NULL); - hdlc_rx_init(&rx, FALSE, TRUE, 5, frame_handler, NULL); + hdlc_tx_init(&tx, false, 2, false, underflow_handler, NULL); + hdlc_rx_init(&rx, false, true, 5, frame_handler, NULL); hdlc_rx_set_max_frame_len(&rx, 100); - underflow_reported = FALSE; - framing_ok_reported = FALSE; + underflow_reported = false; + framing_ok_reported = false; framing_ok_reports = 0; hdlc_tx_flags(&tx, 10); /* Don't push an initial message so we should get an underflow after the preamble. */ /* Lie for the first message, as there isn't really one */ - frame_handled = TRUE; - frame_failed = FALSE; + frame_handled = true; + frame_failed = false; frames_sent = 0; bytes_sent = 0; ref_len = 0; @@ -446,11 +446,11 @@ static int test_hdlc_frame_length_error_handling(void) if (framing_ok_reported) { printf("Framing OK reported at bit %d (%d)\n", i, framing_ok_reports); - framing_ok_reported = FALSE; + framing_ok_reported = false; } if (underflow_reported) { - underflow_reported = FALSE; + underflow_reported = false; for (j = 0; j < 20; j++) { nextbyte = hdlc_tx_get_bit(&tx); @@ -458,7 +458,7 @@ static int test_hdlc_frame_length_error_handling(void) if (framing_ok_reported) { printf("Framing OK reported at bit %d (%d) - %d\n", i, framing_ok_reports, frame_handled); - framing_ok_reported = FALSE; + framing_ok_reported = false; } } if (ref_len) @@ -490,7 +490,7 @@ static int test_hdlc_frame_length_error_handling(void) } ref_len++; hdlc_tx_frame(&tx, buf, ref_len); - frame_handled = FALSE; + frame_handled = false; } } /* We shouldn't reach here */ @@ -509,21 +509,21 @@ static int test_hdlc_crc_error_handling(void) printf("Testing CRC error handling using CRC-16 (bit by bit)\n"); frame_len_errors = 0; frame_data_errors = 0; - hdlc_tx_init(&tx, FALSE, 2, FALSE, underflow_handler, NULL); - hdlc_rx_init(&rx, FALSE, TRUE, 5, frame_handler, NULL); - underflow_reported = FALSE; - framing_ok_reported = FALSE; + hdlc_tx_init(&tx, false, 2, false, underflow_handler, NULL); + hdlc_rx_init(&rx, false, true, 5, frame_handler, NULL); + underflow_reported = false; + framing_ok_reported = false; framing_ok_reports = 0; hdlc_tx_flags(&tx, 10); /* Don't push an initial message so we should get an underflow after the preamble. */ /* Lie for the first message, as there isn't really one */ - frame_handled = TRUE; - frame_failed = FALSE; + frame_handled = true; + frame_failed = false; frames_sent = 0; bytes_sent = 0; ref_len = 100; - corrupt = FALSE; + corrupt = false; for (i = 0; i < 8*1000000; i++) { nextbyte = hdlc_tx_get_bit(&tx); @@ -531,11 +531,11 @@ static int test_hdlc_crc_error_handling(void) if (framing_ok_reported) { printf("Framing OK reported at bit %d (%d)\n", i, framing_ok_reports); - framing_ok_reported = FALSE; + framing_ok_reported = false; } if (underflow_reported) { - underflow_reported = FALSE; + underflow_reported = false; for (j = 0; j < 20; j++) { nextbyte = hdlc_tx_get_bit(&tx); @@ -543,7 +543,7 @@ static int test_hdlc_crc_error_handling(void) if (framing_ok_reported) { printf("Framing OK reported at bit %d (%d) - %d\n", i, framing_ok_reports, frame_handled); - framing_ok_reported = FALSE; + framing_ok_reported = false; } } if (ref_len) @@ -571,7 +571,7 @@ static int test_hdlc_crc_error_handling(void) hdlc_tx_frame(&tx, buf, ref_len); if ((corrupt = rand() & 1)) hdlc_tx_corrupt_frame(&tx); - frame_handled = FALSE; + frame_handled = false; } } @@ -590,22 +590,22 @@ static int test_hdlc_abort_handling(void) printf("Testing abort handling using CRC-16 (bit by bit)\n"); frame_len_errors = 0; frame_data_errors = 0; - hdlc_tx_init(&tx, FALSE, 2, FALSE, underflow_handler, NULL); - hdlc_rx_init(&rx, FALSE, TRUE, 0, frame_handler, NULL); - underflow_reported = FALSE; - framing_ok_reported = FALSE; + hdlc_tx_init(&tx, false, 2, false, underflow_handler, NULL); + hdlc_rx_init(&rx, false, true, 0, frame_handler, NULL); + underflow_reported = false; + framing_ok_reported = false; framing_ok_reports = 0; hdlc_tx_flags(&tx, 10); /* Don't push an initial message so we should get an underflow after the preamble. */ /* Lie for the first message, as there isn't really one */ - frame_handled = TRUE; - frame_failed = FALSE; + frame_handled = true; + frame_failed = false; frames_sent = 0; bytes_sent = 0; ref_len = 0; - abort = FALSE; - abort_reported = FALSE; + abort = false; + abort_reported = false; for (i = 0; i < 8*1000000; i++) { nextbyte = hdlc_tx_get_bit(&tx); @@ -613,11 +613,11 @@ static int test_hdlc_abort_handling(void) if (framing_ok_reported) { printf("Framing OK reported at bit %d (%d)\n", i, framing_ok_reports); - framing_ok_reported = FALSE; + framing_ok_reported = false; } if (underflow_reported) { - underflow_reported = FALSE; + underflow_reported = false; for (j = 0; j < 20; j++) { nextbyte = hdlc_tx_get_bit(&tx); @@ -625,7 +625,7 @@ static int test_hdlc_abort_handling(void) if (framing_ok_reported) { printf("Framing OK reported at bit %d (%d) - %d\n", i, framing_ok_reports, frame_handled); - framing_ok_reported = FALSE; + framing_ok_reported = false; } } if (ref_len) @@ -667,8 +667,8 @@ static int test_hdlc_abort_handling(void) hdlc_tx_frame(&tx, buf, ref_len); if ((abort = rand() & 1)) hdlc_tx_abort(&tx); - frame_handled = FALSE; - abort_reported = FALSE; + frame_handled = false; + abort_reported = false; } } @@ -687,19 +687,19 @@ static int test_hdlc_octet_count_handling(void) printf("Testing the octet_counting handling using CRC-16 (bit by bit)\n"); frame_len_errors = 0; frame_data_errors = 0; - hdlc_tx_init(&tx, FALSE, 2, FALSE, underflow_handler, NULL); - hdlc_rx_init(&rx, FALSE, TRUE, 0, frame_handler, NULL); + hdlc_tx_init(&tx, false, 2, false, underflow_handler, NULL); + hdlc_rx_init(&rx, false, true, 0, frame_handler, NULL); //hdlc_rx_set_max_frame_len(&rx, 50); hdlc_rx_set_octet_counting_report_interval(&rx, 16); - underflow_reported = FALSE; - framing_ok_reported = FALSE; + underflow_reported = false; + framing_ok_reported = false; framing_ok_reports = 0; hdlc_tx_flags(&tx, 10); /* Don't push an initial message so we should get an underflow after the preamble. */ /* Lie for the first message, as there isn't really one */ - frame_handled = TRUE; - frame_failed = FALSE; + frame_handled = true; + frame_failed = false; frames_sent = 0; bytes_sent = 0; ref_len = 0; @@ -710,11 +710,11 @@ static int test_hdlc_octet_count_handling(void) if (framing_ok_reported) { printf("Framing OK reported at bit %d (%d)\n", i, framing_ok_reports); - framing_ok_reported = FALSE; + framing_ok_reported = false; } if (underflow_reported) { - underflow_reported = FALSE; + underflow_reported = false; for (j = 0; j < 20; j++) { nextbyte = hdlc_tx_get_bit(&tx); @@ -722,7 +722,7 @@ static int test_hdlc_octet_count_handling(void) if (framing_ok_reported) { printf("Framing OK reported at bit %d (%d) - %d\n", i, framing_ok_reports, frame_handled); - framing_ok_reported = FALSE; + framing_ok_reported = false; } } if (ref_len) @@ -741,7 +741,7 @@ static int test_hdlc_octet_count_handling(void) hdlc_tx_frame(&tx, buf, ref_len); hdlc_tx_abort(&tx); //hdlc_tx_corrupt_frame(&tx); - frame_handled = FALSE; + frame_handled = false; } } @@ -825,7 +825,7 @@ static void decode_bitstream(const char *in_file_name) exit(2); } - hdlc_rx_init(&rx, FALSE, TRUE, 2, decode_handler, NULL); + hdlc_rx_init(&rx, false, true, 2, decode_handler, NULL); while (fgets(buf, 1024, in)) { if (sscanf(buf, "Rx bit %d - %d", &num, &bit) == 2) diff --git a/libs/spandsp/tests/ima_adpcm_tests.c b/libs/spandsp/tests/ima_adpcm_tests.c index dcf2a6a4cb..e080330313 100644 --- a/libs/spandsp/tests/ima_adpcm_tests.c +++ b/libs/spandsp/tests/ima_adpcm_tests.c @@ -80,18 +80,18 @@ int main(int argc, char *argv[]) int total_pre_samples; int total_compressed_bytes; int total_post_samples; - const char *in_file_name; int variant; int chunk_size; int enc_chunk_size; - int log_encoded_data; int opt; + bool log_encoded_data; + const char *in_file_name; variant = IMA_ADPCM_DVI4; in_file_name = IN_FILE_NAME; chunk_size = 160; enc_chunk_size = 0; - log_encoded_data = FALSE; + log_encoded_data = false; while ((opt = getopt(argc, argv, "ac:i:lv")) != -1) { switch (opt) @@ -107,7 +107,7 @@ int main(int argc, char *argv[]) in_file_name = optarg; break; case 'l': - log_encoded_data = TRUE; + log_encoded_data = true; break; case 'v': variant = IMA_ADPCM_VDVI; diff --git a/libs/spandsp/tests/image_translate_tests.c b/libs/spandsp/tests/image_translate_tests.c index cd4195f7da..7b4fa9d3d3 100644 --- a/libs/spandsp/tests/image_translate_tests.c +++ b/libs/spandsp/tests/image_translate_tests.c @@ -78,6 +78,7 @@ static void create_undithered_50_by_50(image_descriptor_t *im, uint8_t buf[], in unsigned int j; uint8_t *image8; uint16_t *image16; + int samples_per_pixel; im->image = (const uint8_t *) buf; im->width = 50; @@ -88,53 +89,99 @@ static void create_undithered_50_by_50(image_descriptor_t *im, uint8_t buf[], in switch (bytes_per_pixel) { case 1: + samples_per_pixel = 1; image8 = buf; - for (i = 0; i < 50; i++) + for (i = 0; i < im->length; i++) { - for (j = 0; j < 50; j++) - image8[50*i + j] = ((i + j)*655) >> 8; + for (j = 0; j < im->width; j++) + image8[im->width*i + j] = ((i + j)*655) >> 8; } break; case 2: + samples_per_pixel = 1; image16 = (uint16_t *) buf; - for (i = 0; i < 50; i++) + for (i = 0; i < im->length; i++) { - for (j = 0; j < 50; j++) - image16[50*i + j] = (i + j)*655; + for (j = 0; j < im->width; j++) + image16[im->width*i + j] = (i + j)*655; } break; case 3: + samples_per_pixel = 3; image8 = buf; - for (i = 0; i < 50; i++) + for (i = 0; i < im->length; i++) { - for (j = 0; j < 50; j++) + for (j = 0; j < im->width; j++) { #if 0 - image8[50*3*i + 3*j + 0] = ((i + j)*655) >> 8; - image8[50*3*i + 3*j + 1] = ((i + j)*655) >> 8; - image8[50*3*i + 3*j + 2] = ((i + j)*655) >> 8; + image8[samples_per_pixel*(im->width*i + j) + 0] = ((i + j)*655) >> 8; + image8[samples_per_pixel*(im->width*i + j) + 1] = ((i + j)*655) >> 8; + image8[samples_per_pixel*(im->width*i + j) + 2] = ((i + j)*655) >> 8; #else - image8[50*3*i + 3*j + 0] = saturateu8((((i + j)*655U)*36532U) >> 23); - image8[50*3*i + 3*j + 1] = saturateu8((((i + j)*655U)*37216U) >> 24); - image8[50*3*i + 3*j + 2] = saturateu8((((i + j)*655U)*47900U) >> 22); + image8[samples_per_pixel*(im->width*i + j) + 0] = saturateu8((((i + j)*655U)*36532U) >> 23); + image8[samples_per_pixel*(im->width*i + j) + 1] = saturateu8((((i + j)*655U)*37216U) >> 24); + image8[samples_per_pixel*(im->width*i + j) + 2] = saturateu8((((i + j)*655U)*47900U) >> 22); +#endif + } + } + break; + case 4: + samples_per_pixel = 4; + image8 = buf; + for (i = 0; i < im->length; i++) + { + for (j = 0; j < im->width; j++) + { +#if 0 + image8[samples_per_pixel*(im->width*i + j) + 0] = ((i + j)*655) >> 8; + image8[samples_per_pixel*(im->width*i + j) + 1] = ((i + j)*655) >> 8; + image8[samples_per_pixel*(im->width*i + j) + 2] = ((i + j)*655) >> 8; + image8[samples_per_pixel*(im->width*i + j) + 3] = 0; +#else + image8[samples_per_pixel*(im->width*i + j) + 0] = saturateu8((((i + j)*655U)*36532U) >> 23); + image8[samples_per_pixel*(im->width*i + j) + 1] = saturateu8((((i + j)*655U)*37216U) >> 24); + image8[samples_per_pixel*(im->width*i + j) + 2] = saturateu8((((i + j)*655U)*47900U) >> 22); + image8[samples_per_pixel*(im->width*i + j) + 3] = 0; #endif } } break; case 6: + samples_per_pixel = 3; image16 = (uint16_t *) buf; - for (i = 0; i < 50; i++) + for (i = 0; i < im->length; i++) { - for (j = 0; j < 50; j++) + for (j = 0; j < im->width; j++) { #if 0 - image16[50*3*i + 3*j + 0] = (i + j)*655; - image16[50*3*i + 3*j + 1] = (i + j)*655; - image16[50*3*i + 3*j + 2] = (i + j)*655; + image16[samples_per_pixel*(im->width*i + j) + 0] = (i + j)*655; + image16[samples_per_pixel*(im->width*i + j) + 1] = (i + j)*655; + image16[samples_per_pixel*(im->width*i + j) + 2] = (i + j)*655; #else - image16[50*3*i + 3*j + 0] = saturateu16((((i + j)*655U)*36532U) >> 15); - image16[50*3*i + 3*j + 1] = saturateu16((((i + j)*655U)*37216U) >> 16); - image16[50*3*i + 3*j + 2] = saturateu16((((i + j)*655U)*47900U) >> 14); + image16[samples_per_pixel*(im->width*i + j) + 0] = saturateu16((((i + j)*655U)*36532U) >> 15); + image16[samples_per_pixel*(im->width*i + j) + 1] = saturateu16((((i + j)*655U)*37216U) >> 16); + image16[samples_per_pixel*(im->width*i + j) + 2] = saturateu16((((i + j)*655U)*47900U) >> 14); +#endif + } + } + break; + case 8: + samples_per_pixel = 4; + image16 = (uint16_t *) buf; + for (i = 0; i < im->length; i++) + { + for (j = 0; j < im->width; j++) + { +#if 0 + image16[samples_per_pixel*(im->width*i + j) + 0] = (i + j)*655; + image16[samples_per_pixel*(im->width*i + j) + 1] = (i + j)*655; + image16[samples_per_pixel*(im->width*i + j) + 2] = (i + j)*655; + image16[samples_per_pixel*(im->width*i + j) + 3] = 0; +#else + image16[samples_per_pixel*(im->width*i + j) + 0] = saturateu16((((i + j)*655U)*36532U) >> 15); + image16[samples_per_pixel*(im->width*i + j) + 1] = saturateu16((((i + j)*655U)*37216U) >> 16); + image16[samples_per_pixel*(im->width*i + j) + 2] = saturateu16((((i + j)*655U)*47900U) >> 14); + image16[samples_per_pixel*(im->width*i + j) + 3] = 0; #endif } } @@ -232,7 +279,7 @@ static void get_bilevel_image(image_translate_state_t *s, int compare) { int i; int len; - uint8_t row_buf[5000]; + uint8_t row_buf[s->output_length*s->output_width/8]; for (i = 0; i < s->output_length; i++) { @@ -264,7 +311,7 @@ static void get_gray8_image(image_translate_state_t *s, int compare) unsigned int i; unsigned int j; int len; - uint8_t row_buf[5000]; + uint8_t row_buf[s->output_length*s->output_width]; for (i = 0; i < s->output_length; i++) { @@ -298,7 +345,7 @@ static void get_gray16_image(image_translate_state_t *s, int compare) unsigned int i; unsigned int j; int len; - uint16_t row_buf[5000]; + uint16_t row_buf[s->output_length*s->output_width]; for (i = 0; i < s->output_length; i++) { @@ -309,7 +356,7 @@ static void get_gray16_image(image_translate_state_t *s, int compare) } if (compare) { - for (j = 0; j < 50; j++) + for (j = 0; j < s->output_width; j++) { if (row_buf[j] != (i + j)*655) { @@ -331,22 +378,24 @@ static void get_colour8_image(image_translate_state_t *s, int compare) { unsigned int i; unsigned int j; + int samples_per_pixel; int len; int r; int g; int b; - uint8_t row_buf[5000]; + uint8_t row_buf[3*s->output_length*s->output_width]; + samples_per_pixel = 3; for (i = 0; i < s->output_length; i++) { - if ((len = image_translate_row(s, row_buf, 3*s->output_width)) != 3*s->output_width) + if ((len = image_translate_row(s, row_buf, samples_per_pixel*s->output_width)) != samples_per_pixel*s->output_width) { - printf("Image finished early - %d %d\n", len, 3*s->output_width); + printf("Image finished early - %d %d\n", len, samples_per_pixel*s->output_width); exit(2); } if (compare) { - for (j = 0; j < 50; j++) + for (j = 0; j < s->output_width; j++) { #if 0 r = ((i + j)*655) >> 8; @@ -357,20 +406,24 @@ static void get_colour8_image(image_translate_state_t *s, int compare) g = saturateu8((((i + j)*655U)*37216U) >> 24); b = saturateu8((((i + j)*655U)*47900U) >> 22); #endif - if (row_buf[3*j + 0] != r || row_buf[3*j + 1] != g || row_buf[3*j + 2] != b) + if (row_buf[samples_per_pixel*j + 0] != r + || + row_buf[samples_per_pixel*j + 1] != g + || + row_buf[samples_per_pixel*j + 2] != b) { printf("Image mismatch - %dx%d - (%d %d %d) (%d %d %d)\n", j, i, r, g, b, - row_buf[3*j + 0], row_buf[3*j + 1], row_buf[3*j + 2]); + row_buf[samples_per_pixel*j + 0], row_buf[samples_per_pixel*j + 1], row_buf[samples_per_pixel*j + 2]); //exit(2); } } } } - if ((len = image_translate_row(s, row_buf, 2*s->output_width)) != 0) + if ((len = image_translate_row(s, row_buf, samples_per_pixel*s->output_width)) != 0) { - printf("Image finished late - %d %d\n", len, 3*s->output_width); + printf("Image finished late - %d %d\n", len, samples_per_pixel*s->output_width); exit(2); } } @@ -380,22 +433,24 @@ static void get_colour16_image(image_translate_state_t *s, int compare) { unsigned int i; unsigned int j; + int samples_per_pixel; int len; int r; int g; int b; - uint16_t row_buf[5000]; + uint16_t row_buf[3*s->output_length*s->output_width]; + samples_per_pixel = 3; for (i = 0; i < s->output_length; i++) { - if ((len = image_translate_row(s, (uint8_t *) row_buf, 6*s->output_width)) != 6*s->output_width) + if ((len = image_translate_row(s, (uint8_t *) row_buf, 2*samples_per_pixel*s->output_width)) != 2*samples_per_pixel*s->output_width) { - printf("Image finished early - %d %d\n", len, 6*s->output_width); + printf("Image finished early - %d %d\n", len, 2*samples_per_pixel*s->output_width); exit(2); } if (compare) { - for (j = 0; j < 50; j++) + for (j = 0; j < s->output_width; j++) { #if 0 r = (i + j)*655; @@ -406,60 +461,29 @@ static void get_colour16_image(image_translate_state_t *s, int compare) g = saturateu16((((i + j)*655U)*37216U) >> 16); b = saturateu16((((i + j)*655U)*47900U) >> 14); #endif - if (row_buf[3*j + 0] != r || row_buf[3*j + 1] != g || row_buf[3*j + 2] != b) + if (row_buf[samples_per_pixel*j + 0] != r + || + row_buf[samples_per_pixel*j + 1] != g + || + row_buf[samples_per_pixel*j + 2] != b) { printf("Image mismatch - %dx%d - (%d %d %d) (%d %d %d)\n", j, i, r, g, b, - row_buf[3*j + 0], row_buf[3*j + 1], row_buf[3*j + 2]); + row_buf[samples_per_pixel*j + 0], row_buf[samples_per_pixel*j + 1], row_buf[samples_per_pixel*j + 2]); //exit(2); } } } } - if ((len = image_translate_row(s, (uint8_t *) row_buf, 6*s->output_width)) != 0) + if ((len = image_translate_row(s, (uint8_t *) row_buf, 2*samples_per_pixel*s->output_width)) != 0) { - printf("Image finished late - %d %d\n", len, 6*s->output_width); + printf("Image finished late - %d %d\n", len, 2*samples_per_pixel*s->output_width); exit(2); } } /*- End of function --------------------------------------------------------*/ -static void translate_tests_gray16(void) -{ - image_translate_state_t *s; - uint16_t image[50*50]; - image_descriptor_t im; - - printf("Dithering from a 16 bit per sample gray scale to bi-level\n"); - create_undithered_50_by_50(&im, (uint8_t *) image, 2); - s = image_translate_init(NULL, T4_IMAGE_TYPE_GRAY_12BIT, im.width, im.length, T4_IMAGE_TYPE_BILEVEL, -1, -1, row_read, &im); - get_bilevel_image(s, TRUE); - - printf("Scrunching from a 16 bit per sample gray scale to 8 bit per sample gray scale\n"); - create_undithered_50_by_50(&im, (uint8_t *) image, 2); - s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_12BIT, im.width, im.length, T4_IMAGE_TYPE_GRAY_8BIT, -1, -1, row_read, &im); - get_gray8_image(s, TRUE); - - printf("Scrunching from a 16 bit per sample gray scale to 16 bit per sample gray scale\n"); - create_undithered_50_by_50(&im, (uint8_t *) image, 2); - s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_12BIT, im.width, im.length, T4_IMAGE_TYPE_GRAY_12BIT, -1, -1, row_read, &im); - get_gray16_image(s, TRUE); - - printf("Scrunching from a 16 bit per sample gray scale to 3x8 bit per sample colour\n"); - create_undithered_50_by_50(&im, (uint8_t *) image, 2); - s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_12BIT, im.width, im.length, T4_IMAGE_TYPE_COLOUR_8BIT, -1, -1, row_read, &im); - get_colour8_image(s, TRUE); - - printf("Scrunching from a 16 bit per sample gray scale to 3x16 bit per sample colour\n"); - create_undithered_50_by_50(&im, (uint8_t *) image, 2); - s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_12BIT, im.width, im.length, T4_IMAGE_TYPE_COLOUR_12BIT, -1, -1, row_read, &im); - get_colour16_image(s, TRUE); - - image_translate_free(s); -} -/*- End of function --------------------------------------------------------*/ - static void translate_tests_gray8(void) { image_translate_state_t *s; @@ -468,63 +492,63 @@ static void translate_tests_gray8(void) printf("Dithering from a 8 bit per sample gray scale to bi-level\n"); create_undithered_50_by_50(&im, image, 1); - s = image_translate_init(NULL, T4_IMAGE_TYPE_GRAY_8BIT, im.width, im.length, T4_IMAGE_TYPE_BILEVEL, -1, -1, row_read, &im); - get_bilevel_image(s, TRUE); + s = image_translate_init(NULL, T4_IMAGE_TYPE_BILEVEL, -1, -1, T4_IMAGE_TYPE_GRAY_8BIT, im.width, im.length, row_read, &im); + get_bilevel_image(s, true); printf("Scrunching from a 8 bit per sample gray scale to 8 bit per sample gray scale\n"); create_undithered_50_by_50(&im, image, 1); - s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_8BIT, im.width, im.length, T4_IMAGE_TYPE_GRAY_8BIT, -1, -1, row_read, &im); - get_gray8_image(s, TRUE); + s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_8BIT, -1, -1, T4_IMAGE_TYPE_GRAY_8BIT, im.width, im.length, row_read, &im); + get_gray8_image(s, true); printf("Scrunching from a 8 bit per sample gray scale to 16 bit per sample gray scale\n"); create_undithered_50_by_50(&im, image, 1); - s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_8BIT, im.width, im.length, T4_IMAGE_TYPE_GRAY_12BIT, -1, -1, row_read, &im); - get_gray16_image(s, TRUE); + s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_12BIT, -1, -1, T4_IMAGE_TYPE_GRAY_8BIT, im.width, im.length, row_read, &im); + get_gray16_image(s, true); printf("Scrunching from a 8 bit per sample gray scale to 3x8 bit per sample colour\n"); create_undithered_50_by_50(&im, image, 1); - s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_8BIT, im.width, im.length, T4_IMAGE_TYPE_COLOUR_8BIT, -1, -1, row_read, &im); - get_colour8_image(s, TRUE); + s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_8BIT, -1, -1, T4_IMAGE_TYPE_GRAY_8BIT, im.width, im.length, row_read, &im); + get_colour8_image(s, true); printf("Scrunching from a 8 bit per sample gray scale to 3x16 bit per sample colour\n"); create_undithered_50_by_50(&im, image, 1); - s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_8BIT, im.width, im.length, T4_IMAGE_TYPE_COLOUR_12BIT, -1, -1, row_read, &im); - get_colour16_image(s, TRUE); + s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_12BIT, -1, -1, T4_IMAGE_TYPE_GRAY_8BIT, im.width, im.length, row_read, &im); + get_colour16_image(s, true); image_translate_free(s); } /*- End of function --------------------------------------------------------*/ -static void translate_tests_colour16(void) +static void translate_tests_gray16(void) { image_translate_state_t *s; - uint16_t image[50*50*3]; + uint16_t image[50*50]; image_descriptor_t im; - printf("Dithering from a 3x16 bit per sample colour to bi-level\n"); - create_undithered_50_by_50(&im, (uint8_t *) image, 6); - s = image_translate_init(NULL, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, T4_IMAGE_TYPE_BILEVEL, -1, -1, row_read, &im); - get_bilevel_image(s, TRUE); + printf("Dithering from a 16 bit per sample gray scale to bi-level\n"); + create_undithered_50_by_50(&im, (uint8_t *) image, 2); + s = image_translate_init(NULL, T4_IMAGE_TYPE_BILEVEL, -1, -1, T4_IMAGE_TYPE_GRAY_12BIT, im.width, im.length, row_read, &im); + get_bilevel_image(s, true); - printf("Scrunching from a 3x16 bit per sample colour to 8 bit per sample gray scale\n"); - create_undithered_50_by_50(&im, (uint8_t *) image, 6); - s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, T4_IMAGE_TYPE_GRAY_8BIT, -1, -1, row_read, &im); - get_gray8_image(s, TRUE); + printf("Scrunching from a 16 bit per sample gray scale to 8 bit per sample gray scale\n"); + create_undithered_50_by_50(&im, (uint8_t *) image, 2); + s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_8BIT, -1, -1, T4_IMAGE_TYPE_GRAY_12BIT, im.width, im.length, row_read, &im); + get_gray8_image(s, true); - printf("Scrunching from a 3x16 bit per sample colour to 16 bit per sample gray scale\n"); - create_undithered_50_by_50(&im, (uint8_t *) image, 6); - s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, T4_IMAGE_TYPE_GRAY_12BIT, -1, -1, row_read, &im); - get_gray16_image(s, TRUE); + printf("Scrunching from a 16 bit per sample gray scale to 16 bit per sample gray scale\n"); + create_undithered_50_by_50(&im, (uint8_t *) image, 2); + s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_12BIT, -1, -1, T4_IMAGE_TYPE_GRAY_12BIT, im.width, im.length, row_read, &im); + get_gray16_image(s, true); - printf("Scrunching from a 3x16 bit per sample colour to 3x8 bit per sample colour\n"); - create_undithered_50_by_50(&im, (uint8_t *) image, 6); - s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, T4_IMAGE_TYPE_COLOUR_8BIT, -1, -1, row_read, &im); - get_colour8_image(s, TRUE); + printf("Scrunching from a 16 bit per sample gray scale to 3x8 bit per sample colour\n"); + create_undithered_50_by_50(&im, (uint8_t *) image, 2); + s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_8BIT, -1, -1, T4_IMAGE_TYPE_GRAY_12BIT, im.width, im.length, row_read, &im); + get_colour8_image(s, true); - printf("Scrunching from a 3x16 bit per sample colour to 3x16 bit per sample colour\n"); - create_undithered_50_by_50(&im, (uint8_t *) image, 6); - s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, T4_IMAGE_TYPE_COLOUR_12BIT, -1, -1, row_read, &im); - get_colour16_image(s, TRUE); + printf("Scrunching from a 16 bit per sample gray scale to 3x16 bit per sample colour\n"); + create_undithered_50_by_50(&im, (uint8_t *) image, 2); + s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_12BIT, -1, -1, T4_IMAGE_TYPE_GRAY_12BIT, im.width, im.length, row_read, &im); + get_colour16_image(s, true); image_translate_free(s); } @@ -533,33 +557,68 @@ static void translate_tests_colour16(void) static void translate_tests_colour8(void) { image_translate_state_t *s; - uint8_t image[50*50*3]; + uint8_t image[3*50*50]; image_descriptor_t im; printf("Dithering from a 3x8 bit per sample colour to bi-level\n"); create_undithered_50_by_50(&im, image, 3); - s = image_translate_init(NULL, T4_IMAGE_TYPE_COLOUR_8BIT, im.width, im.length, T4_IMAGE_TYPE_BILEVEL, -1, -1, row_read, &im); - get_bilevel_image(s, TRUE); + s = image_translate_init(NULL, T4_IMAGE_TYPE_BILEVEL, -1, -1, T4_IMAGE_TYPE_COLOUR_8BIT, im.width, im.length, row_read, &im); + get_bilevel_image(s, true); printf("Scrunching from a 3x8 bit per sample colour to 8 bit per sample gray scale\n"); create_undithered_50_by_50(&im, image, 3); - s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_8BIT, im.width, im.length, T4_IMAGE_TYPE_GRAY_8BIT, -1, -1, row_read, &im); - get_gray8_image(s, TRUE); + s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_8BIT, -1, -1, T4_IMAGE_TYPE_COLOUR_8BIT, im.width, im.length, row_read, &im); + get_gray8_image(s, true); printf("Scrunching from a 3x8 bit per sample colour to 16 bit per sample gray scale\n"); create_undithered_50_by_50(&im, image, 3); - s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_8BIT, im.width, im.length, T4_IMAGE_TYPE_GRAY_12BIT, -1, -1, row_read, &im); - get_gray16_image(s, TRUE); + s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_12BIT, -1, -1, T4_IMAGE_TYPE_COLOUR_8BIT, im.width, im.length, row_read, &im); + get_gray16_image(s, true); printf("Scrunching from a 3x8 bit per sample colour to 3x8 bit per sample colour\n"); create_undithered_50_by_50(&im, image, 3); - s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_8BIT, im.width, im.length, T4_IMAGE_TYPE_COLOUR_8BIT, -1, -1, row_read, &im); - get_colour8_image(s, TRUE); + s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_8BIT, -1, -1, T4_IMAGE_TYPE_COLOUR_8BIT, im.width, im.length, row_read, &im); + get_colour8_image(s, true); printf("Scrunching from a 3x8 bit per sample colour to 3x16 bit per sample colour\n"); create_undithered_50_by_50(&im, image, 3); - s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_8BIT, im.width, im.length, T4_IMAGE_TYPE_COLOUR_12BIT, -1, -1, row_read, &im); - get_colour16_image(s, TRUE); + s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_12BIT, -1, -1, T4_IMAGE_TYPE_COLOUR_8BIT, im.width, im.length, row_read, &im); + get_colour16_image(s, true); + + image_translate_free(s); +} +/*- End of function --------------------------------------------------------*/ + +static void translate_tests_colour16(void) +{ + image_translate_state_t *s; + uint16_t image[3*50*50]; + image_descriptor_t im; + + printf("Dithering from a 3x16 bit per sample colour to bi-level\n"); + create_undithered_50_by_50(&im, (uint8_t *) image, 6); + s = image_translate_init(NULL, T4_IMAGE_TYPE_BILEVEL, -1, -1, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, row_read, &im); + get_bilevel_image(s, true); + + printf("Scrunching from a 3x16 bit per sample colour to 8 bit per sample gray scale\n"); + create_undithered_50_by_50(&im, (uint8_t *) image, 6); + s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_8BIT, -1, -1, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, row_read, &im); + get_gray8_image(s, true); + + printf("Scrunching from a 3x16 bit per sample colour to 16 bit per sample gray scale\n"); + create_undithered_50_by_50(&im, (uint8_t *) image, 6); + s = image_translate_init(s, T4_IMAGE_TYPE_GRAY_12BIT, -1, -1, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, row_read, &im); + get_gray16_image(s, true); + + printf("Scrunching from a 3x16 bit per sample colour to 3x8 bit per sample colour\n"); + create_undithered_50_by_50(&im, (uint8_t *) image, 6); + s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_8BIT, -1, -1, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, row_read, &im); + get_colour8_image(s, true); + + printf("Scrunching from a 3x16 bit per sample colour to 3x16 bit per sample colour\n"); + create_undithered_50_by_50(&im, (uint8_t *) image, 6); + s = image_translate_init(s, T4_IMAGE_TYPE_COLOUR_12BIT, -1, -1, T4_IMAGE_TYPE_COLOUR_12BIT, im.width, im.length, row_read, &im); + get_colour16_image(s, true); image_translate_free(s); } @@ -568,14 +627,14 @@ static void translate_tests_colour8(void) static void grow_tests_colour8(void) { image_translate_state_t *s; - uint8_t image[50*50*3]; + uint8_t image[3*50*50]; image_descriptor_t im; printf("Image growth tests\n"); create_undithered_50_by_50(&im, image, 3); - s = image_translate_init(NULL, T4_IMAGE_TYPE_COLOUR_8BIT, im.width, im.length, T4_IMAGE_TYPE_BILEVEL, 200, -1, row_read, &im); - get_bilevel_image(s, FALSE); + s = image_translate_init(NULL, T4_IMAGE_TYPE_BILEVEL, 200, -1, T4_IMAGE_TYPE_COLOUR_8BIT, im.width, im.length, row_read, &im); + get_bilevel_image(s, false); image_translate_free(s); } /*- End of function --------------------------------------------------------*/ @@ -597,20 +656,20 @@ static void lenna_tests(int output_width, int output_length_scaling, const char int image_width; int image_length; int output_length; - uint8_t *image; - uint8_t *image2; int len; int total; - int16_t bits_per_sample; - int16_t samples_per_pixel; int i; int n; + uint8_t *image; + uint8_t *image2; + int16_t bits_per_sample; + int16_t samples_per_pixel; + uint16_t res_unit; image_translate_state_t *s; image_translate_state_t *s2; image_descriptor_t im; float x_resolution; float y_resolution; - uint16_t res_unit; if (output_length_scaling >= 0) printf("Dithering Lenna from colour to bi-level test\n"); @@ -651,7 +710,7 @@ static void lenna_tests(int output_width, int output_length_scaling, const char break; } } - printf("Image size %d %d\n", total, image_width*image_length*samples_per_pixel); + printf("Input image size %d %d\n", total, image_width*image_length*samples_per_pixel); TIFFClose(in_file); if (output_length_scaling > 0) @@ -669,20 +728,20 @@ static void lenna_tests(int output_width, int output_length_scaling, const char switch (output_length_scaling) { case -2: - s = image_translate_init(NULL, T4_IMAGE_TYPE_COLOUR_8BIT, image_width, image_length, T4_IMAGE_TYPE_GRAY_8BIT, output_width, output_length, row_read, &im); + s = image_translate_init(NULL, T4_IMAGE_TYPE_GRAY_8BIT, output_width, output_length, T4_IMAGE_TYPE_COLOUR_8BIT, image_width, image_length, row_read, &im); output_width = image_translate_get_output_width(s); output_length = image_translate_get_output_length(s); - s2 = image_translate_init(NULL, T4_IMAGE_TYPE_GRAY_8BIT, output_width, output_length, T4_IMAGE_TYPE_COLOUR_8BIT, -1, -1, row_read2, s); + s2 = image_translate_init(NULL, T4_IMAGE_TYPE_COLOUR_8BIT, -1, -1, T4_IMAGE_TYPE_GRAY_8BIT, output_width, output_length, row_read2, s); output_width = image_translate_get_output_width(s2); output_length = image_translate_get_output_length(s2); break; case -1: - s = image_translate_init(NULL, T4_IMAGE_TYPE_COLOUR_8BIT, image_width, image_length, T4_IMAGE_TYPE_COLOUR_8BIT, output_width, output_length, row_read, &im); + s = image_translate_init(NULL, T4_IMAGE_TYPE_COLOUR_8BIT, output_width, output_length, T4_IMAGE_TYPE_COLOUR_8BIT, image_width, image_length, row_read, &im); output_width = image_translate_get_output_width(s); output_length = image_translate_get_output_length(s); break; default: - s = image_translate_init(NULL, T4_IMAGE_TYPE_COLOUR_8BIT, image_width, image_length, T4_IMAGE_TYPE_BILEVEL, output_width, output_length, row_read, &im); + s = image_translate_init(NULL, T4_IMAGE_TYPE_BILEVEL, output_width, output_length, T4_IMAGE_TYPE_COLOUR_8BIT, image_width, image_length, row_read, &im); output_width = image_translate_get_output_width(s); output_length = image_translate_get_output_length(s); break; diff --git a/libs/spandsp/tests/line_model_tests.c b/libs/spandsp/tests/line_model_tests.c index 8f2091e3fb..8d31413cd4 100644 --- a/libs/spandsp/tests/line_model_tests.c +++ b/libs/spandsp/tests/line_model_tests.c @@ -363,13 +363,13 @@ static void test_line_filter(int line_model_no) int main(int argc, char *argv[]) { int line_model_no; - int speech_test; int opt; + bool speech_test; channel_codec = MUNGE_CODEC_NONE; line_model_no = 0; rbs_pattern = 0; - speech_test = FALSE; + speech_test = false; while ((opt = getopt(argc, argv, "c:m:r:s:")) != -1) { switch (opt) diff --git a/libs/spandsp/tests/logging_tests.c b/libs/spandsp/tests/logging_tests.c index 085fd0ecbc..666fc1e9bb 100644 --- a/libs/spandsp/tests/logging_tests.c +++ b/libs/spandsp/tests/logging_tests.c @@ -42,12 +42,12 @@ #include "spandsp.h" -static int tests_failed = FALSE; +static bool tests_failed = false; static int msg_step = 0; static int msg2_step = 0; -static int msg_done = FALSE; -static int msg2_done = FALSE; +static bool msg_done = false; +static bool msg2_done = false; static void message_handler(void *user_data, int level, const char *text) { @@ -78,10 +78,10 @@ static void message_handler(void *user_data, int level, const char *text) if (strcmp(ref[msg_step], text)) { printf(">>>: %s", ref[msg_step]); - tests_failed = TRUE; + tests_failed = true; } if (ref[++msg_step][0] == '\0') - msg_done = TRUE; + msg_done = true; printf("MSG: %s", text); } /*- End of function --------------------------------------------------------*/ @@ -92,10 +92,10 @@ static void message_handler2(void *user_data, int level, const char *text) if (strcmp(" FLOW Protocol NewTag Date/time tagged log 1 2 3\n", text + 23)) { printf(">>>: %s", text + 23); - tests_failed = TRUE; + tests_failed = true; } if (++msg2_step == 10) - msg2_done = TRUE; + msg2_done = true; printf("MSG: %s", text); } /*- End of function --------------------------------------------------------*/ @@ -172,7 +172,7 @@ int main(int argc, char *argv[]) if (!span_log_test(log, i)) { if (i != 6) - tests_failed = TRUE; + tests_failed = true; break; } } diff --git a/libs/spandsp/tests/lpc10_tests.c b/libs/spandsp/tests/lpc10_tests.c index dee9a624e1..0ecacfb847 100644 --- a/libs/spandsp/tests/lpc10_tests.c +++ b/libs/spandsp/tests/lpc10_tests.c @@ -79,9 +79,9 @@ int main(int argc, char *argv[]) lpc10_decode_state_t *lpc10_dec_state; int i; int block_no; - int log_error; - int compress; - int decompress; + bool log_error; + bool compress; + bool decompress; const char *in_file_name; int compress_file; int decompress_file; @@ -90,25 +90,25 @@ int main(int argc, char *argv[]) int enc_len; int dec_len; - compress = FALSE; - decompress = FALSE; - log_error = TRUE; + compress = false; + decompress = false; + log_error = true; in_file_name = IN_FILE_NAME; while ((opt = getopt(argc, argv, "cdi:l")) != -1) { switch (opt) { case 'c': - compress = TRUE; + compress = true; break; case 'd': - decompress = TRUE; + decompress = true; break; case 'i': in_file_name = optarg; break; case 'l': - log_error = FALSE; + log_error = false; break; default: //usage(); @@ -150,13 +150,13 @@ int main(int argc, char *argv[]) exit(2); } - if ((lpc10_enc_state = lpc10_encode_init(NULL, TRUE)) == NULL) + if ((lpc10_enc_state = lpc10_encode_init(NULL, true)) == NULL) { fprintf(stderr, " Cannot create encoder\n"); exit(2); } - if ((lpc10_dec_state = lpc10_decode_init(NULL, TRUE)) == NULL) + if ((lpc10_dec_state = lpc10_decode_init(NULL, true)) == NULL) { fprintf(stderr, " Cannot create decoder\n"); exit(2); diff --git a/libs/spandsp/tests/modem_connect_tones_tests.c b/libs/spandsp/tests/modem_connect_tones_tests.c index fd7f104992..1f99201b55 100644 --- a/libs/spandsp/tests/modem_connect_tones_tests.c +++ b/libs/spandsp/tests/modem_connect_tones_tests.c @@ -49,9 +49,6 @@ These tests... #define MITEL_DIR "../test-data/mitel/" #define BELLCORE_DIR "../test-data/bellcore/" -#define FALSE 0 -#define TRUE (!FALSE) - #define LEVEL_MAX -5 #define LEVEL_MIN -48 #define LEVEL_MIN_ACCEPT -43 @@ -230,13 +227,13 @@ int main(int argc, char *argv[]) int frames; int samples; int hit; - int false_hit; - int false_miss; int level2; int max_level2; int tone_type; int test_list; int opt; + bool false_hit; + bool false_miss; char *decode_test_file; fsk_tx_state_t preamble_tx; @@ -480,8 +477,8 @@ int main(int argc, char *argv[]) printf("Test 2a: CNG detection with frequency\n"); tone_type = MODEM_CONNECT_TONES_FAX_CNG; awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); - false_hit = FALSE; - false_miss = FALSE; + false_hit = false; + false_miss = false; for (pitch = 1100 - 500; pitch <= 1100 + 500; pitch++) { /* Use the transmitter to test the receiver */ @@ -509,13 +506,13 @@ int main(int argc, char *argv[]) if (pitch < (1100 - CED_FREQ_BLACKOUT) || pitch > (1100 + CED_FREQ_BLACKOUT)) { if (hit != MODEM_CONNECT_TONES_NONE) - false_hit = TRUE; + false_hit = true; /*endif*/ } else if (pitch > (1100 - CED_FREQ_TOLERANCE) && pitch < (1100 + CED_FREQ_TOLERANCE)) { if (hit != tone_type) - false_miss = TRUE; + false_miss = true; /*endif*/ } /*endif*/ @@ -538,8 +535,8 @@ int main(int argc, char *argv[]) { printf("Test 2b: CED/ANS detection with frequency\n"); awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); - false_hit = FALSE; - false_miss = FALSE; + false_hit = false; + false_miss = false; for (pitch = 2100 - 500; pitch < 2100 + 500; pitch++) { /* Use the transmitter to test the receiver */ @@ -560,13 +557,13 @@ int main(int argc, char *argv[]) if (pitch < (2100 - CNG_FREQ_BLACKOUT) || pitch > (2100 + CNG_FREQ_BLACKOUT)) { if (hit != MODEM_CONNECT_TONES_NONE) - false_hit = TRUE; + false_hit = true; /*endif*/ } else if (pitch > (2100 - CNG_FREQ_TOLERANCE) && pitch < (2100 + CNG_FREQ_TOLERANCE)) { if (hit != MODEM_CONNECT_TONES_FAX_CED) - false_miss = TRUE; + false_miss = true; /*endif*/ } /*endif*/ @@ -589,8 +586,8 @@ int main(int argc, char *argv[]) printf("Test 2c: ANSam detection with frequency\n"); tone_type = MODEM_CONNECT_TONES_ANSAM; awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); - false_hit = FALSE; - false_miss = FALSE; + false_hit = false; + false_miss = false; for (pitch = 2100 - 100; pitch <= 2100 + 100; pitch++) { /* Use the transmitter to test the receiver */ @@ -611,13 +608,13 @@ int main(int argc, char *argv[]) if (pitch < (2100 - CNG_FREQ_BLACKOUT) || pitch > (2100 + CNG_FREQ_BLACKOUT)) { if (hit != MODEM_CONNECT_TONES_NONE) - false_hit = TRUE; + false_hit = true; /*endif*/ } else if (pitch > (2100 - CNG_FREQ_TOLERANCE) && pitch < (2100 + CNG_FREQ_TOLERANCE)) { if (hit != tone_type) - false_miss = TRUE; + false_miss = true; /*endif*/ } /*endif*/ @@ -641,8 +638,8 @@ int main(int argc, char *argv[]) printf("Test 2d: ANS/ (EC-disable) detection with frequency\n"); tone_type = MODEM_CONNECT_TONES_ANS_PR; awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); - false_hit = FALSE; - false_miss = FALSE; + false_hit = false; + false_miss = false; for (pitch = 2100 - 100; pitch <= 2100 + 100; pitch++) { /* Use the transmitter to test the receiver */ @@ -663,13 +660,13 @@ int main(int argc, char *argv[]) if (pitch < (2100 - CNG_FREQ_BLACKOUT) || pitch > (2100 + CNG_FREQ_BLACKOUT)) { if (hit != MODEM_CONNECT_TONES_NONE) - false_hit = TRUE; + false_hit = true; /*endif*/ } else if (pitch > (2100 - CNG_FREQ_TOLERANCE) && pitch < (2100 + CNG_FREQ_TOLERANCE)) { if (hit != tone_type) - false_miss = TRUE; + false_miss = true; /*endif*/ } /*endif*/ @@ -693,8 +690,8 @@ int main(int argc, char *argv[]) printf("Test 2e: ANSam/ (Modulated EC-disable) detection with frequency\n"); tone_type = MODEM_CONNECT_TONES_ANSAM_PR; awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); - false_hit = FALSE; - false_miss = FALSE; + false_hit = false; + false_miss = false; for (pitch = 2100 - 100; pitch <= 2100 + 100; pitch++) { /* Use the transmitter to test the receiver */ @@ -715,13 +712,13 @@ int main(int argc, char *argv[]) if (pitch < (2100 - CNG_FREQ_BLACKOUT) || pitch > (2100 + CNG_FREQ_BLACKOUT)) { if (hit != MODEM_CONNECT_TONES_NONE) - false_hit = TRUE; + false_hit = true; /*endif*/ } else if (pitch > (2100 - CNG_FREQ_TOLERANCE) && pitch < (2100 + CNG_FREQ_TOLERANCE)) { if (hit != tone_type) - false_miss = TRUE; + false_miss = true; /*endif*/ } /*endif*/ @@ -745,8 +742,8 @@ int main(int argc, char *argv[]) printf("Test 2f: Bell answer tone detection with frequency\n"); tone_type = MODEM_CONNECT_TONES_BELL_ANS; awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); - false_hit = FALSE; - false_miss = FALSE; + false_hit = false; + false_miss = false; for (pitch = 2225 - 500; pitch <= 2225 + 500; pitch++) { /* Use the transmitter to test the receiver */ @@ -774,13 +771,13 @@ int main(int argc, char *argv[]) if (pitch < (2225 - BELL_ANS_FREQ_BLACKOUT) || pitch > (2225 + BELL_ANS_FREQ_BLACKOUT)) { if (hit != MODEM_CONNECT_TONES_NONE) - false_hit = TRUE; + false_hit = true; /*endif*/ } else if (pitch > (2225 - BELL_ANS_FREQ_TOLERANCE) && pitch < (2225 + BELL_ANS_FREQ_TOLERANCE)) { if (hit != tone_type) - false_miss = TRUE; + false_miss = true; /*endif*/ } /*endif*/ @@ -804,8 +801,8 @@ int main(int argc, char *argv[]) printf("Test 2g: Calling tone detection with frequency\n"); tone_type = MODEM_CONNECT_TONES_CALLING_TONE; awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); - false_hit = FALSE; - false_miss = FALSE; + false_hit = false; + false_miss = false; for (pitch = 1300 - 500; pitch <= 1300 + 500; pitch++) { /* Use the transmitter to test the receiver */ @@ -833,13 +830,13 @@ int main(int argc, char *argv[]) if (pitch < (1300 - CALLING_TONE_FREQ_BLACKOUT) || pitch > (1300 + CALLING_TONE_FREQ_BLACKOUT)) { if (hit != MODEM_CONNECT_TONES_NONE) - false_hit = TRUE; + false_hit = true; /*endif*/ } else if (pitch > (1300 - CALLING_TONE_FREQ_TOLERANCE) && pitch < (1300 + CALLING_TONE_FREQ_TOLERANCE)) { if (hit != tone_type) - false_miss = TRUE; + false_miss = true; /*endif*/ } /*endif*/ @@ -863,8 +860,8 @@ int main(int argc, char *argv[]) printf("Test 3a: CNG detection with level\n"); tone_type = MODEM_CONNECT_TONES_FAX_CNG; awgn_init_dbm0(&chan_noise_source, 7162534, -60.0f); - false_hit = FALSE; - false_miss = FALSE; + false_hit = false; + false_miss = false; for (pitch = 1100 - CED_FREQ_TOLERANCE; pitch <= 1100 + CED_FREQ_TOLERANCE; pitch += 2*CED_FREQ_TOLERANCE) { for (level = LEVEL_MAX; level >= LEVEL_MIN; level--) @@ -888,13 +885,13 @@ int main(int argc, char *argv[]) if (level < LEVEL_MIN_REJECT) { if (hit != MODEM_CONNECT_TONES_NONE) - false_hit = TRUE; + false_hit = true; /*endif*/ } else if (level > LEVEL_MIN_ACCEPT) { if (hit != tone_type) - false_miss = TRUE; + false_miss = true; /*endif*/ } /*endif*/ @@ -920,8 +917,8 @@ int main(int argc, char *argv[]) printf("Test 3b: CED/ANS detection with level\n"); tone_type = MODEM_CONNECT_TONES_ANS; awgn_init_dbm0(&chan_noise_source, 7162534, -60.0f); - false_hit = FALSE; - false_miss = FALSE; + false_hit = false; + false_miss = false; for (pitch = 2100 - CNG_FREQ_TOLERANCE; pitch <= 2100 + CNG_FREQ_TOLERANCE; pitch += 2*CNG_FREQ_TOLERANCE) { for (level = LEVEL_MAX; level >= LEVEL_MIN; level--) @@ -945,13 +942,13 @@ int main(int argc, char *argv[]) if (level < LEVEL_MIN_REJECT) { if (hit != MODEM_CONNECT_TONES_NONE) - false_hit = TRUE; + false_hit = true; /*endif*/ } else if (level > LEVEL_MIN_ACCEPT) { if (hit != tone_type) - false_miss = TRUE; + false_miss = true; /*endif*/ } /*endif*/ @@ -977,8 +974,8 @@ int main(int argc, char *argv[]) printf("Test 3c: ANSam detection with level\n"); tone_type = MODEM_CONNECT_TONES_ANSAM; awgn_init_dbm0(&chan_noise_source, 7162534, -60.0f); - false_hit = FALSE; - false_miss = FALSE; + false_hit = false; + false_miss = false; for (pitch = 2100 - CNG_FREQ_TOLERANCE; pitch <= 2100 + CNG_FREQ_TOLERANCE; pitch += 2*CNG_FREQ_TOLERANCE) { //for (level = LEVEL_MAX; level >= LEVEL_MIN; level--) @@ -1004,13 +1001,13 @@ int main(int argc, char *argv[]) if (level < LEVEL_MIN_REJECT) { if (hit != MODEM_CONNECT_TONES_NONE) - false_hit = TRUE; + false_hit = true; /*endif*/ } else if (level > LEVEL_MIN_ACCEPT) { if (hit != tone_type) - false_miss = TRUE; + false_miss = true; /*endif*/ } /*endif*/ @@ -1036,8 +1033,8 @@ int main(int argc, char *argv[]) printf("Test 3d: ANS/ (EC-disable) detection with level\n"); tone_type = MODEM_CONNECT_TONES_ANS_PR; awgn_init_dbm0(&chan_noise_source, 7162534, -60.0f); - false_hit = FALSE; - false_miss = FALSE; + false_hit = false; + false_miss = false; for (pitch = 2100 - CNG_FREQ_TOLERANCE; pitch <= 2100 + CNG_FREQ_TOLERANCE; pitch += 2*CNG_FREQ_TOLERANCE) { for (level = LEVEL_MAX; level >= LEVEL_MIN; level--) @@ -1061,13 +1058,13 @@ int main(int argc, char *argv[]) if (level < LEVEL_MIN_REJECT) { if (hit != MODEM_CONNECT_TONES_NONE) - false_hit = TRUE; + false_hit = true; /*endif*/ } else if (level > LEVEL_MIN_ACCEPT) { if (hit != tone_type) - false_miss = TRUE; + false_miss = true; /*endif*/ } /*endif*/ @@ -1093,8 +1090,8 @@ int main(int argc, char *argv[]) printf("Test 3e: ANSam/ (Modulated EC-disable) detection with level\n"); tone_type = MODEM_CONNECT_TONES_ANSAM_PR; awgn_init_dbm0(&chan_noise_source, 7162534, -60.0f); - false_hit = FALSE; - false_miss = FALSE; + false_hit = false; + false_miss = false; for (pitch = 2100 - CNG_FREQ_TOLERANCE; pitch <= 2100 + CNG_FREQ_TOLERANCE; pitch += 2*CNG_FREQ_TOLERANCE) { for (level = LEVEL_MAX; level >= LEVEL_MIN; level--) @@ -1119,13 +1116,13 @@ int main(int argc, char *argv[]) if (level < LEVEL_MIN_REJECT) { if (hit != MODEM_CONNECT_TONES_NONE) - false_hit = TRUE; + false_hit = true; /*endif*/ } else if (level > LEVEL_MIN_ACCEPT) { if (hit != tone_type) - false_miss = TRUE; + false_miss = true; /*endif*/ } /*endif*/ @@ -1151,8 +1148,8 @@ int main(int argc, char *argv[]) printf("Test 3f: Bell answer tone detection with level\n"); tone_type = MODEM_CONNECT_TONES_BELL_ANS; awgn_init_dbm0(&chan_noise_source, 7162534, -60.0f); - false_hit = FALSE; - false_miss = FALSE; + false_hit = false; + false_miss = false; for (pitch = 2225 - BELL_ANS_FREQ_TOLERANCE; pitch <= 2225 + BELL_ANS_FREQ_TOLERANCE; pitch += 2*BELL_ANS_FREQ_TOLERANCE) { for (level = LEVEL_MAX; level >= LEVEL_MIN; level--) @@ -1176,13 +1173,13 @@ int main(int argc, char *argv[]) if (level < LEVEL_MIN_REJECT) { if (hit != MODEM_CONNECT_TONES_NONE) - false_hit = TRUE; + false_hit = true; /*endif*/ } else if (level > LEVEL_MIN_ACCEPT) { if (hit != tone_type) - false_miss = TRUE; + false_miss = true; /*endif*/ } /*endif*/ @@ -1208,8 +1205,8 @@ int main(int argc, char *argv[]) printf("Test 3g: Calling tone detection with level\n"); tone_type = MODEM_CONNECT_TONES_CALLING_TONE; awgn_init_dbm0(&chan_noise_source, 7162534, -60.0f); - false_hit = FALSE; - false_miss = FALSE; + false_hit = false; + false_miss = false; for (pitch = 1300 - CALLING_TONE_FREQ_TOLERANCE; pitch <= 1300 + CALLING_TONE_FREQ_TOLERANCE; pitch += 2*CALLING_TONE_FREQ_TOLERANCE) { for (level = LEVEL_MAX; level >= LEVEL_MIN; level--) @@ -1233,13 +1230,13 @@ int main(int argc, char *argv[]) if (level < LEVEL_MIN_REJECT) { if (hit != MODEM_CONNECT_TONES_NONE) - false_hit = TRUE; + false_hit = true; /*endif*/ } else if (level > LEVEL_MIN_ACCEPT) { if (hit != tone_type) - false_miss = TRUE; + false_miss = true; /*endif*/ } /*endif*/ @@ -1263,8 +1260,8 @@ int main(int argc, char *argv[]) if ((test_list & PERFORM_TEST_4)) { printf("Test 4: CED detection, when stimulated with V.21 preamble\n"); - false_hit = FALSE; - false_miss = FALSE; + false_hit = false; + false_miss = false; /* Send 255 bits of preamble (0.85s, the minimum specified preamble for T.30), and then some random bits. Check the preamble detector comes on, and goes off at reasonable times. */ @@ -1299,8 +1296,8 @@ int main(int argc, char *argv[]) printf("Test 5A: ANS and ANS/ detection with reversal interval\n"); tone_type = MODEM_CONNECT_TONES_ANS_PR; awgn_init_dbm0(&chan_noise_source, 7162534, -60.0f); - false_hit = FALSE; - false_miss = FALSE; + false_hit = false; + false_miss = false; for (interval = 400; interval < 800; interval++) { printf("Reversal interval = %d\n", interval); @@ -1331,13 +1328,13 @@ int main(int argc, char *argv[]) if (interval < (450 - 25) || interval > (450 + 25)) { if (hits != 0) - false_hit = TRUE; + false_hit = true; /*endif*/ } else if (interval > (450 - 25) && interval < (450 + 25)) { if (hits == 0) - false_miss = TRUE; + false_miss = true; /*endif*/ } /*endif*/ @@ -1361,8 +1358,8 @@ int main(int argc, char *argv[]) printf("Test 5B: ANS and ANS/ detection with mixed reversal intervals\n"); awgn_init_dbm0(&chan_noise_source, 7162534, -60.0f); tone_type = MODEM_CONNECT_TONES_ANS_PR; - false_hit = FALSE; - false_miss = FALSE; + false_hit = false; + false_miss = false; interval = 450; printf("Reversal interval = %d\n", interval); /* Use the transmitter to test the receiver */ @@ -1410,8 +1407,8 @@ int main(int argc, char *argv[]) printf("Test 6a: ANSam detection with AM pitch\n"); tone_type = MODEM_CONNECT_TONES_ANSAM; awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); - false_hit = FALSE; - false_miss = FALSE; + false_hit = false; + false_miss = false; for (pitch = 5; pitch < 25; pitch++) { /* Use the transmitter to test the receiver */ @@ -1432,13 +1429,13 @@ int main(int argc, char *argv[]) if (pitch < (15 - 10) || pitch > (15 + 10)) { if (hit == tone_type) - false_hit = TRUE; + false_hit = true; /*endif*/ } else if (pitch > (15 - AM_FREQ_TOLERANCE) && pitch < (15 + AM_FREQ_TOLERANCE)) { if (hit != tone_type) - false_miss = TRUE; + false_miss = true; /*endif*/ } /*endif*/ @@ -1462,8 +1459,8 @@ int main(int argc, char *argv[]) printf("Test 6b: ANSam/ (Modulated EC-disable) detection with AM pitch\n"); tone_type = MODEM_CONNECT_TONES_ANSAM_PR; awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); - false_hit = FALSE; - false_miss = FALSE; + false_hit = false; + false_miss = false; for (pitch = 5; pitch < 25; pitch++) { /* Use the transmitter to test the receiver */ @@ -1484,13 +1481,13 @@ int main(int argc, char *argv[]) if (pitch < (15 - 10) || pitch > (15 + 10)) { if (hit == tone_type) - false_hit = TRUE; + false_hit = true; /*endif*/ } else if (pitch > (15 - AM_FREQ_TOLERANCE) && pitch < (15 + AM_FREQ_TOLERANCE)) { if (hit != tone_type) - false_miss = TRUE; + false_miss = true; /*endif*/ } /*endif*/ @@ -1515,8 +1512,8 @@ int main(int argc, char *argv[]) tone_type = MODEM_CONNECT_TONES_ANSAM; pitch = 2100; awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); - false_hit = FALSE; - false_miss = FALSE; + false_hit = false; + false_miss = false; for (depth = 0; depth < 40; depth++) { /* Use the transmitter to test the receiver */ @@ -1537,13 +1534,13 @@ int main(int argc, char *argv[]) if (depth < 10) { if (hit == tone_type) - false_hit = TRUE; + false_hit = true; /*endif*/ } else if (depth > 15) { if (hit != tone_type) - false_miss = TRUE; + false_miss = true; /*endif*/ } /*endif*/ @@ -1568,8 +1565,8 @@ int main(int argc, char *argv[]) tone_type = MODEM_CONNECT_TONES_ANSAM_PR; pitch = 2100; awgn_init_dbm0(&chan_noise_source, 7162534, -50.0f); - false_hit = FALSE; - false_miss = FALSE; + false_hit = false; + false_miss = false; for (depth = 0; depth < 40; depth++) { /* Use the transmitter to test the receiver */ @@ -1590,13 +1587,13 @@ int main(int argc, char *argv[]) if (depth < 10) { if (hit == tone_type) - false_hit = TRUE; + false_hit = true; /*endif*/ } else if (depth > 15) { if (hit != tone_type) - false_miss = TRUE; + false_miss = true; /*endif*/ } /*endif*/ diff --git a/libs/spandsp/tests/modem_echo_tests.c b/libs/spandsp/tests/modem_echo_tests.c index c6ce135a02..2cc50f4294 100644 --- a/libs/spandsp/tests/modem_echo_tests.c +++ b/libs/spandsp/tests/modem_echo_tests.c @@ -118,8 +118,8 @@ fir32_state_t line_model; SNDFILE *resulthandle; int16_t residue_sound[8000]; int residue_cur = 0; -int do_codec_munge = TRUE; -int use_gui = FALSE; +int do_codec_munge = true; +int use_gui = false; static const int16_t tone_1khz[] = {10362, 7327, 0, -7327, -10362, -7327, 0, 7327}; @@ -268,12 +268,12 @@ int main(int argc, char *argv[]) #endif line_model_no = 0; - use_gui = FALSE; + use_gui = false; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-g") == 0) { - use_gui = TRUE; + use_gui = true; continue; } line_model_no = atoi(argv[1]); @@ -307,7 +307,7 @@ int main(int argc, char *argv[]) power_meter_init(&power_after, 5); /* Measure the echo power before adaption */ - modem_echo_can_adaption_mode(ctx, FALSE); + modem_echo_can_adaption_mode(ctx, false); for (i = 0; i < 8000*5; i++) { tx = tone_1khz[i & 7]; @@ -322,7 +322,7 @@ int main(int argc, char *argv[]) /* Converge the canceller */ signal_restart(&local_css); - modem_echo_can_adaption_mode(ctx, TRUE); + modem_echo_can_adaption_mode(ctx, true); for (i = 0; i < 800*2; i++) { clean = modem_echo_can_update(ctx, 0, 0); @@ -352,7 +352,7 @@ int main(int argc, char *argv[]) } /* Now lets see how well adapted we are */ - modem_echo_can_adaption_mode(ctx, FALSE); + modem_echo_can_adaption_mode(ctx, false); for (i = 0; i < 8000*5; i++) { tx = tone_1khz[i & 7]; diff --git a/libs/spandsp/tests/msvc/complex_tests.2012.vcxproj b/libs/spandsp/tests/msvc/complex_tests.2012.vcxproj new file mode 100644 index 0000000000..edbd29ebae --- /dev/null +++ b/libs/spandsp/tests/msvc/complex_tests.2012.vcxproj @@ -0,0 +1,109 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {A349379F-0FEA-49C8-9535-05F39663337B} + complex_tests + Win32Proj + + + + Application + v110 + Unicode + true + + + Application + v110 + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60610.1 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + + Disabled + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + MachineX86 + + + + + MaxSpeed + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + true + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + true + true + MachineX86 + + + + + + + + + + + + + {1cbb0077-18c5-455f-801c-0a0ce7b0bbf5} + false + + + + + + \ No newline at end of file diff --git a/libs/spandsp/tests/msvc/complex_tests.2012.vcxproj.filters b/libs/spandsp/tests/msvc/complex_tests.2012.vcxproj.filters new file mode 100644 index 0000000000..c985311d03 --- /dev/null +++ b/libs/spandsp/tests/msvc/complex_tests.2012.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/libs/spandsp/tests/msvc/complex_vector_float_tests.2012.vcxproj b/libs/spandsp/tests/msvc/complex_vector_float_tests.2012.vcxproj new file mode 100644 index 0000000000..1a2d8178fa --- /dev/null +++ b/libs/spandsp/tests/msvc/complex_vector_float_tests.2012.vcxproj @@ -0,0 +1,109 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {2B0D705C-1CF2-401C-BFBC-A43FB806908C} + complex_vector_float_tests + Win32Proj + + + + Application + v110 + Unicode + true + + + Application + v110 + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60610.1 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + + Disabled + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + MachineX86 + + + + + MaxSpeed + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + true + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + true + true + MachineX86 + + + + + + + + + + + + + {1cbb0077-18c5-455f-801c-0a0ce7b0bbf5} + false + + + + + + \ No newline at end of file diff --git a/libs/spandsp/tests/msvc/complex_vector_float_tests.2012.vcxproj.filters b/libs/spandsp/tests/msvc/complex_vector_float_tests.2012.vcxproj.filters new file mode 100644 index 0000000000..97213f0053 --- /dev/null +++ b/libs/spandsp/tests/msvc/complex_vector_float_tests.2012.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/libs/spandsp/tests/msvc/complex_vector_int_tests.2012.vcxproj b/libs/spandsp/tests/msvc/complex_vector_int_tests.2012.vcxproj new file mode 100644 index 0000000000..6b3e33ca93 --- /dev/null +++ b/libs/spandsp/tests/msvc/complex_vector_int_tests.2012.vcxproj @@ -0,0 +1,109 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {C2E8B4D1-A398-4D57-94F8-B61F20C7D514} + complex_vector_int_tests + Win32Proj + + + + Application + v110 + Unicode + true + + + Application + v110 + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60610.1 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + + Disabled + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + MachineX86 + + + + + MaxSpeed + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + true + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + true + true + MachineX86 + + + + + + + + + + + + + {1cbb0077-18c5-455f-801c-0a0ce7b0bbf5} + false + + + + + + \ No newline at end of file diff --git a/libs/spandsp/tests/msvc/complex_vector_int_tests.2012.vcxproj.filters b/libs/spandsp/tests/msvc/complex_vector_int_tests.2012.vcxproj.filters new file mode 100644 index 0000000000..c7fd99f9aa --- /dev/null +++ b/libs/spandsp/tests/msvc/complex_vector_int_tests.2012.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/libs/spandsp/tests/msvc/dtmf_rx_tests.2012.vcxproj b/libs/spandsp/tests/msvc/dtmf_rx_tests.2012.vcxproj new file mode 100644 index 0000000000..4f17b6be84 --- /dev/null +++ b/libs/spandsp/tests/msvc/dtmf_rx_tests.2012.vcxproj @@ -0,0 +1,103 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {24E7EF80-7854-4A21-80FB-31C4E71109DE} + dtmf_rx_tests + Win32Proj + + + + Application + v110 + Unicode + true + + + Application + v110 + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60610.1 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + + Disabled + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + MachineX86 + + + + + MaxSpeed + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + true + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + true + true + MachineX86 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/spandsp/tests/msvc/dtmf_rx_tests.2012.vcxproj.filters b/libs/spandsp/tests/msvc/dtmf_rx_tests.2012.vcxproj.filters new file mode 100644 index 0000000000..dd8f8cc2d1 --- /dev/null +++ b/libs/spandsp/tests/msvc/dtmf_rx_tests.2012.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/libs/spandsp/tests/msvc/dtmf_tx_tests.2012.vcxproj b/libs/spandsp/tests/msvc/dtmf_tx_tests.2012.vcxproj new file mode 100644 index 0000000000..4419ec5829 --- /dev/null +++ b/libs/spandsp/tests/msvc/dtmf_tx_tests.2012.vcxproj @@ -0,0 +1,103 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {1577F41D-9A06-45DD-87D4-9ADCC9CCDAD5} + dtmf_tx_tests + Win32Proj + + + + Application + v110 + Unicode + true + + + Application + v110 + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60610.1 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + + Disabled + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + MachineX86 + + + + + MaxSpeed + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + true + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + true + true + MachineX86 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/spandsp/tests/msvc/dtmf_tx_tests.2012.vcxproj.filters b/libs/spandsp/tests/msvc/dtmf_tx_tests.2012.vcxproj.filters new file mode 100644 index 0000000000..e2ac03f95e --- /dev/null +++ b/libs/spandsp/tests/msvc/dtmf_tx_tests.2012.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/libs/spandsp/tests/msvc/queue_tests.2012.vcxproj b/libs/spandsp/tests/msvc/queue_tests.2012.vcxproj new file mode 100644 index 0000000000..468f0b7d98 --- /dev/null +++ b/libs/spandsp/tests/msvc/queue_tests.2012.vcxproj @@ -0,0 +1,103 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {D9C0F575-83E7-4C15-BF71-D7A0D44A26BF} + queue_tests + Win32Proj + + + + Application + v110 + Unicode + true + + + Application + v110 + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60610.1 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + + Disabled + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + MachineX86 + + + + + MaxSpeed + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + true + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + true + true + MachineX86 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/spandsp/tests/msvc/queue_tests.2012.vcxproj.filters b/libs/spandsp/tests/msvc/queue_tests.2012.vcxproj.filters new file mode 100644 index 0000000000..49ddb6a0e6 --- /dev/null +++ b/libs/spandsp/tests/msvc/queue_tests.2012.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/libs/spandsp/tests/msvc/t38_core_tests.2012.vcxproj b/libs/spandsp/tests/msvc/t38_core_tests.2012.vcxproj new file mode 100644 index 0000000000..d21b895f02 --- /dev/null +++ b/libs/spandsp/tests/msvc/t38_core_tests.2012.vcxproj @@ -0,0 +1,109 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {A34A9D0E-A7E2-4A04-B044-7BB2FE709EF3} + t38_core_tests + Win32Proj + + + + Application + v110 + Unicode + true + + + Application + v110 + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60610.1 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + + Disabled + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + MachineX86 + + + + + MaxSpeed + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + true + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + true + true + MachineX86 + + + + + + + + + + + + + {1cbb0077-18c5-455f-801c-0a0ce7b0bbf5} + false + + + + + + \ No newline at end of file diff --git a/libs/spandsp/tests/msvc/t38_core_tests.2012.vcxproj.filters b/libs/spandsp/tests/msvc/t38_core_tests.2012.vcxproj.filters new file mode 100644 index 0000000000..8a9d19c5b7 --- /dev/null +++ b/libs/spandsp/tests/msvc/t38_core_tests.2012.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/libs/spandsp/tests/msvc/t38_non_ecm_buffer_tests.2012.vcxproj b/libs/spandsp/tests/msvc/t38_non_ecm_buffer_tests.2012.vcxproj new file mode 100644 index 0000000000..40d4ff728b --- /dev/null +++ b/libs/spandsp/tests/msvc/t38_non_ecm_buffer_tests.2012.vcxproj @@ -0,0 +1,109 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {80A3D9D9-3846-4DA5-8676-F940D725EA62} + t38_non_ecm_buffer_tests + Win32Proj + + + + Application + v110 + Unicode + true + + + Application + v110 + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60610.1 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + + Disabled + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + MachineX86 + + + + + MaxSpeed + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + true + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + true + true + MachineX86 + + + + + + + + + + + + + {1cbb0077-18c5-455f-801c-0a0ce7b0bbf5} + false + + + + + + \ No newline at end of file diff --git a/libs/spandsp/tests/msvc/t38_non_ecm_buffer_tests.2012.vcxproj.filters b/libs/spandsp/tests/msvc/t38_non_ecm_buffer_tests.2012.vcxproj.filters new file mode 100644 index 0000000000..fde53cb0c3 --- /dev/null +++ b/libs/spandsp/tests/msvc/t38_non_ecm_buffer_tests.2012.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/libs/spandsp/tests/msvc/v22bis_tests.2012.vcxproj b/libs/spandsp/tests/msvc/v22bis_tests.2012.vcxproj new file mode 100644 index 0000000000..88bf6b1fdc --- /dev/null +++ b/libs/spandsp/tests/msvc/v22bis_tests.2012.vcxproj @@ -0,0 +1,103 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {DA4DB99F-E5BA-48BD-BB6B-3595CE24CBAE} + v22bis_tests + Win32Proj + + + + Application + v110 + Unicode + true + + + Application + v110 + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60610.1 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + + Disabled + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + MachineX86 + + + + + MaxSpeed + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + true + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + true + true + MachineX86 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/spandsp/tests/msvc/v22bis_tests.2012.vcxproj.filters b/libs/spandsp/tests/msvc/v22bis_tests.2012.vcxproj.filters new file mode 100644 index 0000000000..f588cc67d4 --- /dev/null +++ b/libs/spandsp/tests/msvc/v22bis_tests.2012.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/libs/spandsp/tests/msvc/v29_tests.2012.vcxproj b/libs/spandsp/tests/msvc/v29_tests.2012.vcxproj new file mode 100644 index 0000000000..672a62c1fb --- /dev/null +++ b/libs/spandsp/tests/msvc/v29_tests.2012.vcxproj @@ -0,0 +1,103 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {323BD962-4581-4561-8105-8C166A9FA933} + v29_tests + Win32Proj + + + + Application + v110 + Unicode + true + + + Application + v110 + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60610.1 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + + Disabled + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + MachineX86 + + + + + MaxSpeed + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + true + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + true + true + MachineX86 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/spandsp/tests/msvc/v29_tests.2012.vcxproj.filters b/libs/spandsp/tests/msvc/v29_tests.2012.vcxproj.filters new file mode 100644 index 0000000000..8e030a1801 --- /dev/null +++ b/libs/spandsp/tests/msvc/v29_tests.2012.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/libs/spandsp/tests/msvc/v80_tests.2012.vcxproj b/libs/spandsp/tests/msvc/v80_tests.2012.vcxproj new file mode 100644 index 0000000000..3b59f30708 --- /dev/null +++ b/libs/spandsp/tests/msvc/v80_tests.2012.vcxproj @@ -0,0 +1,103 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {10263F04-37DD-4E4A-AE4F-0641B018B714} + v80_tests + Win32Proj + + + + Application + v110 + Unicode + true + + + Application + v110 + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60610.1 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + + Disabled + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + MachineX86 + + + + + MaxSpeed + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + true + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + true + true + MachineX86 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/spandsp/tests/msvc/v80_tests.2012.vcxproj.filters b/libs/spandsp/tests/msvc/v80_tests.2012.vcxproj.filters new file mode 100644 index 0000000000..454b800c13 --- /dev/null +++ b/libs/spandsp/tests/msvc/v80_tests.2012.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/libs/spandsp/tests/msvc/v8_tests.2012.vcxproj b/libs/spandsp/tests/msvc/v8_tests.2012.vcxproj new file mode 100644 index 0000000000..03fe38e66c --- /dev/null +++ b/libs/spandsp/tests/msvc/v8_tests.2012.vcxproj @@ -0,0 +1,103 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {0C69B8C2-0CE1-4CD4-870C-1C13FB3F9B34} + v8_tests + Win32Proj + + + + Application + v110 + Unicode + true + + + Application + v110 + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60610.1 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + + Disabled + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + MachineX86 + + + + + MaxSpeed + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + true + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + true + true + MachineX86 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/spandsp/tests/msvc/v8_tests.2012.vcxproj.filters b/libs/spandsp/tests/msvc/v8_tests.2012.vcxproj.filters new file mode 100644 index 0000000000..a5737ede86 --- /dev/null +++ b/libs/spandsp/tests/msvc/v8_tests.2012.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/libs/spandsp/tests/msvc/vector_float_tests.2012.vcxproj b/libs/spandsp/tests/msvc/vector_float_tests.2012.vcxproj new file mode 100644 index 0000000000..ec6a2c3c7b --- /dev/null +++ b/libs/spandsp/tests/msvc/vector_float_tests.2012.vcxproj @@ -0,0 +1,109 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {EA745FF7-9E4B-4C13-BA19-2EE8165A6245} + vector_float_tests + Win32Proj + + + + Application + v110 + Unicode + true + + + Application + v110 + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60610.1 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + + Disabled + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + MachineX86 + + + + + MaxSpeed + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + true + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + true + true + MachineX86 + + + + + + + + + + + + + {1cbb0077-18c5-455f-801c-0a0ce7b0bbf5} + false + + + + + + \ No newline at end of file diff --git a/libs/spandsp/tests/msvc/vector_float_tests.2012.vcxproj.filters b/libs/spandsp/tests/msvc/vector_float_tests.2012.vcxproj.filters new file mode 100644 index 0000000000..58d1fe1968 --- /dev/null +++ b/libs/spandsp/tests/msvc/vector_float_tests.2012.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/libs/spandsp/tests/msvc/vector_int_tests.2012.vcxproj b/libs/spandsp/tests/msvc/vector_int_tests.2012.vcxproj new file mode 100644 index 0000000000..41ca9c3fe0 --- /dev/null +++ b/libs/spandsp/tests/msvc/vector_int_tests.2012.vcxproj @@ -0,0 +1,109 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {80A60464-29E8-4EE8-BAFA-8708B7C08CC3} + vector_int_tests + Win32Proj + + + + Application + v110 + Unicode + true + + + Application + v110 + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60610.1 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + + Disabled + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + MachineX86 + + + + + MaxSpeed + .;..\..\src\spandsp;..\..\src;..\..\src\msvc;..;..\..\tiff-4.0.3\tiff-4.0.3\libtiff;%(AdditionalIncludeDirectories) + true + WIN32;NDEBUG;_CONSOLE;HAVE_CONFIG_H;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level3 + ProgramDatabase + + + ..\..\src\Win32\Debug\libspandsp.lib;%(AdditionalDependencies) + true + Console + true + true + MachineX86 + + + + + + + + + + + + + {1cbb0077-18c5-455f-801c-0a0ce7b0bbf5} + false + + + + + + \ No newline at end of file diff --git a/libs/spandsp/tests/msvc/vector_int_tests.2012.vcxproj.filters b/libs/spandsp/tests/msvc/vector_int_tests.2012.vcxproj.filters new file mode 100644 index 0000000000..e933bb2770 --- /dev/null +++ b/libs/spandsp/tests/msvc/vector_int_tests.2012.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/libs/spandsp/tests/oki_adpcm_tests.c b/libs/spandsp/tests/oki_adpcm_tests.c index ff87b20605..f41208239c 100644 --- a/libs/spandsp/tests/oki_adpcm_tests.c +++ b/libs/spandsp/tests/oki_adpcm_tests.c @@ -88,13 +88,13 @@ int main(int argc, char *argv[]) int encoded_fd; const char *encoded_file_name; const char *in_file_name; - int log_encoded_data; + bool log_encoded_data; int opt; bit_rate = 32000; encoded_file_name = NULL; in_file_name = IN_FILE_NAME; - log_encoded_data = FALSE; + log_encoded_data = false; while ((opt = getopt(argc, argv, "2d:i:l")) != -1) { switch (opt) @@ -109,7 +109,7 @@ int main(int argc, char *argv[]) in_file_name = optarg; break; case 'l': - log_encoded_data = TRUE; + log_encoded_data = true; break; default: //usage(); diff --git a/libs/spandsp/tests/plc_tests.c b/libs/spandsp/tests/plc_tests.c index 4e97d96321..78e645d317 100644 --- a/libs/spandsp/tests/plc_tests.c +++ b/libs/spandsp/tests/plc_tests.c @@ -70,18 +70,18 @@ int main(int argc, char *argv[]) int block_len; int loss_rate; int dropit; - int block_real; - int block_synthetic; int tone; int i; + int opt; + bool block_real; + bool block_synthetic; uint32_t phase_acc; int32_t phase_rate; - int opt; loss_rate = 25; block_len = 160; - block_real = FALSE; - block_synthetic = FALSE; + block_real = false; + block_synthetic = false; tone = -1; while ((opt = getopt(argc, argv, "b:l:rst:")) != -1) { @@ -94,10 +94,10 @@ int main(int argc, char *argv[]) loss_rate = atoi(optarg); break; case 'r': - block_real = TRUE; + block_real = true; break; case 's': - block_synthetic = TRUE; + block_synthetic = true; break; case 't': tone = atoi(optarg); diff --git a/libs/spandsp/tests/power_meter_tests.c b/libs/spandsp/tests/power_meter_tests.c index 0dd04c7424..da04372778 100644 --- a/libs/spandsp/tests/power_meter_tests.c +++ b/libs/spandsp/tests/power_meter_tests.c @@ -75,7 +75,7 @@ static int power_surge_detector_tests(void) exit(2); } sig = power_surge_detector_init(NULL, -50.0f, 5.0f); - prev_signal_present = FALSE; + prev_signal_present = false; phase_rate = dds_phase_rate(450.0f); phase_acc = 0; @@ -178,7 +178,7 @@ static int power_surge_detector_file_test(const char *file) exit(2); } sig = power_surge_detector_init(NULL, -50.0f, 6.0f); - prev_signal_present = FALSE; + prev_signal_present = false; sample = 0; while ((inframes = sf_readf_short(inhandle, amp, 8000))) @@ -271,7 +271,7 @@ static int power_meter_tests(void) 0, 0, 0, - TRUE); + true); tone_gen_init(&gen, &tone_desc); len = tone_gen(&gen, amp, 1000); for (i = 0; i < len; i++) @@ -335,13 +335,13 @@ static int power_meter_tests(void) int main(int argc, char *argv[]) { - int basic_tests; - int decode; + bool basic_tests; + bool decode; int opt; const char *in_file; - basic_tests = TRUE; - decode = FALSE; + basic_tests = true; + decode = false; in_file = IN_FILE_NAME; while ((opt = getopt(argc, argv, "d:")) != -1) { @@ -349,8 +349,8 @@ int main(int argc, char *argv[]) { case 'd': in_file = optarg; - basic_tests = FALSE; - decode = TRUE; + basic_tests = false; + decode = true; break; default: //usage(); diff --git a/libs/spandsp/tests/pseudo_terminal_tests.c b/libs/spandsp/tests/pseudo_terminal_tests.c new file mode 100644 index 0000000000..b6d28d2b26 --- /dev/null +++ b/libs/spandsp/tests/pseudo_terminal_tests.c @@ -0,0 +1,150 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * pseudo_terminal_tests.c - pseudo terminal handling tests. + * + * Written by Steve Underwood + * + * Copyright (C) 2012 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include + +#if defined(WIN32) +#include +#else +#if defined(__APPLE__) +#include +#elif defined(__FreeBSD__) +#include +#include +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#endif + +#include "spandsp.h" + +#include "spandsp/t30_fcf.h" + +#include "spandsp-sim.h" + +#undef SPANDSP_EXPOSE_INTERNAL_STRUCTURES + +#include "pseudo_terminals.h" + +static int master(void) +{ + modem_t modem[10]; + char buf[1024]; + int len; + int i; + + for (i = 0; i < 10; i++) + { + if (psuedo_terminal_create(&modem[i])) + { + printf("Failure\n"); + exit(2); + } + printf("%s %s\n", modem[i].devlink, modem[i].stty); + } + + for (;;) + { + for (i = 0; i < 10; i++) + { + len = read(modem[i].master, buf, 4); + if (len >= 0) + { + buf[len] = '\0'; + printf("%d %d '%s' %s\n", i, len, buf, strerror(errno)); + } + } + } + + for (i = 0; i < 10; i++) + { + if (psuedo_terminal_close(&modem[i])) + { + printf("Failure\n"); + exit(2); + } + } + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int slave(void) +{ + int fd[10]; + char name[64]; + int i; + int j; + + for (i = 0; i < 10; i++) + { + sprintf(name, "/dev/spandsp/%d", i); + if ((fd[i] = open(name, O_RDWR)) < 0) + { + printf("Failed to open %s\n", name); + exit(2); + } + printf("%s\n", name); + } + + for (j = 0; j < 10; j++) + { + for (i = 0; i < 10; i++) + { + write(fd[i], "FRED", 4); + } + } + + for (i = 0; i < 10; i++) + { + if (close(fd[i])) + { + printf("Failed to close %d\n", i); + exit(2); + } + } + + return 0; +} +/*- End of function --------------------------------------------------------*/ + +int main(int argc, char *argv[]) +{ + if (argc < 2) + master(); + else + slave(); + return 0; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/pseudo_terminals.c b/libs/spandsp/tests/pseudo_terminals.c index f973801d13..1f042be8b9 100644 --- a/libs/spandsp/tests/pseudo_terminals.c +++ b/libs/spandsp/tests/pseudo_terminals.c @@ -51,6 +51,7 @@ #include "pseudo_terminals.h" int next_id = 0; +const char *device_root_name = "/dev/spandsp"; int psuedo_terminal_close(modem_t *modem) { @@ -172,10 +173,10 @@ int psuedo_terminal_create(modem_t *modem) psuedo_terminal_close(modem); return -1; } - modem->threadAbort = CreateEvent(NULL, TRUE, FALSE, NULL); + modem->threadAbort = CreateEvent(NULL, true, false, NULL); #else modem->slot = next_id++; - snprintf(modem->devlink, sizeof(modem->devlink), "/dev/spandsp/%d", modem->slot); + snprintf(modem->devlink, sizeof(modem->devlink), "%s/%d", device_root_name, modem->slot); /* Remove any stale link which might be present */ unlink(modem->devlink); diff --git a/libs/spandsp/tests/queue_tests.c b/libs/spandsp/tests/queue_tests.c index d01aa60ec9..f648b155f8 100644 --- a/libs/spandsp/tests/queue_tests.c +++ b/libs/spandsp/tests/queue_tests.c @@ -691,21 +691,21 @@ static void functional_message_tests(void) int main(int argc, char *argv[]) { - int threaded_messages; - int threaded_streams; + bool threaded_messages; + bool threaded_streams; int opt; - threaded_messages = FALSE; - threaded_streams = FALSE; + threaded_messages = false; + threaded_streams = false; while ((opt = getopt(argc, argv, "ms")) != -1) { switch (opt) { case 'm': - threaded_messages = TRUE; + threaded_messages = true; break; case 's': - threaded_streams = TRUE; + threaded_streams = true; break; } } diff --git a/libs/spandsp/tests/r2_mf_rx_tests.c b/libs/spandsp/tests/r2_mf_rx_tests.c index 6fb9b0781d..2402634131 100644 --- a/libs/spandsp/tests/r2_mf_rx_tests.c +++ b/libs/spandsp/tests/r2_mf_rx_tests.c @@ -165,7 +165,7 @@ static void my_mf_gen_init(float low_fudge, 0, 0, 0, - FALSE); + false); } } /*- End of function --------------------------------------------------------*/ @@ -205,7 +205,7 @@ static void digit_delivery(void *data, int digit, int level, int delay) if (data != (void *) 0x12345678) { - callback_ok = FALSE; + callback_ok = false; return; } if ((callback_roll & 1)) @@ -213,13 +213,13 @@ static void digit_delivery(void *data, int digit, int level, int delay) else ch = r2_mf_tone_codes[callback_roll >> 1]; if (ch == digit) - callback_ok = TRUE; + callback_ok = true; else - callback_ok = FALSE; + callback_ok = false; if (r2_mf_tone_codes[callback_roll >> 1]) callback_roll++; else - callback_ok = FALSE; + callback_ok = false; } /*- End of function --------------------------------------------------------*/ @@ -539,7 +539,7 @@ static int test_a_tone_set(int fwd) printf(" Passed\n"); printf("Test 8: Callback digit delivery mode.\n"); - callback_ok = FALSE; + callback_ok = false; callback_roll = 0; mf_state = r2_mf_rx_init(NULL, fwd, digit_delivery, (void *) 0x12345678); my_mf_gen_init(0.0, -3, 0.0, -3, 68, fwd); @@ -583,9 +583,9 @@ int main(int argc, char *argv[]) now = time(NULL); printf("R2 forward tones\n"); - test_a_tone_set(TRUE); + test_a_tone_set(true); printf("R2 backward tones\n"); - test_a_tone_set(FALSE); + test_a_tone_set(false); duration = time(NULL) - now; printf("Tests passed in %lds\n", duration); return 0; diff --git a/libs/spandsp/tests/r2_mf_tx_tests.c b/libs/spandsp/tests/r2_mf_tx_tests.c index ff6c5b82d5..0348f799e8 100644 --- a/libs/spandsp/tests/r2_mf_tx_tests.c +++ b/libs/spandsp/tests/r2_mf_tx_tests.c @@ -64,7 +64,7 @@ int main(int argc, char *argv[]) exit(2); } - r2_mf_tx_init(&gen, FALSE); + r2_mf_tx_init(&gen, false); for (digit = 0; digits[digit]; digit++) { r2_mf_tx_put(&gen, digits[digit]); @@ -79,7 +79,7 @@ int main(int argc, char *argv[]) sf_writef_short(outhandle, amp, len); } - r2_mf_tx_init(&gen, TRUE); + r2_mf_tx_init(&gen, true); for (digit = 0; digits[digit]; digit++) { r2_mf_tx_put(&gen, digits[digit]); diff --git a/libs/spandsp/tests/regression_tests.sh b/libs/spandsp/tests/regression_tests.sh index 31aeb5a952..949eca3fcf 100755 --- a/libs/spandsp/tests/regression_tests.sh +++ b/libs/spandsp/tests/regression_tests.sh @@ -43,6 +43,15 @@ then fi echo adsi_tests completed OK +./alloc_tests >$STDOUT_DEST 2>$STDERR_DEST +RETVAL=$? +if [ $RETVAL != 0 ] +then + echo alloc_tests failed! + exit $RETVAL +fi +echo alloc_tests completed OK + ./async_tests >$STDOUT_DEST 2>$STDERR_DEST RETVAL=$? if [ $RETVAL != 0 ] diff --git a/libs/spandsp/tests/rfc2198_sim_tests.c b/libs/spandsp/tests/rfc2198_sim_tests.c index 2c2700fc44..95d8f6b971 100644 --- a/libs/spandsp/tests/rfc2198_sim_tests.c +++ b/libs/spandsp/tests/rfc2198_sim_tests.c @@ -89,7 +89,7 @@ int main(int argc, char *argv[]) #endif #if defined(ENABLE_GUI) - use_gui = FALSE; + use_gui = false; #endif model_no = MODEL_NO; speed_pattern_no = SPEED_PATTERN_NO; @@ -100,7 +100,7 @@ int main(int argc, char *argv[]) { case 'g': #if defined(ENABLE_GUI) - use_gui = TRUE; + use_gui = true; #else fprintf(stderr, "Graphical monitoring not available\n"); exit(2); diff --git a/libs/spandsp/tests/sig_tone_tests.c b/libs/spandsp/tests/sig_tone_tests.c index 4288891e57..00af89eeba 100644 --- a/libs/spandsp/tests/sig_tone_tests.c +++ b/libs/spandsp/tests/sig_tone_tests.c @@ -83,7 +83,7 @@ static int dial_pulses = 0; static int rx_handler_callbacks = 0; static int tx_handler_callbacks = 0; -static int use_gui = FALSE; +static bool use_gui = false; static void plot_frequency_response(void) { @@ -522,13 +522,13 @@ int main(int argc, char *argv[]) template_t template[10]; int opt; - use_gui = FALSE; + use_gui = false; while ((opt = getopt(argc, argv, "g")) != -1) { switch (opt) { case 'g': - use_gui = TRUE; + use_gui = true; break; default: //usage(); diff --git a/libs/spandsp/tests/super_tone_tx_tests.c b/libs/spandsp/tests/super_tone_tx_tests.c index 561b333c36..9f32ea6c78 100644 --- a/libs/spandsp/tests/super_tone_tx_tests.c +++ b/libs/spandsp/tests/super_tone_tx_tests.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #if defined(HAVE_LIBXML_XMLMEMORY_H) diff --git a/libs/spandsp/tests/swept_tone_tests.c b/libs/spandsp/tests/swept_tone_tests.c index 9ff6bc462f..aebc54a409 100644 --- a/libs/spandsp/tests/swept_tone_tests.c +++ b/libs/spandsp/tests/swept_tone_tests.c @@ -62,7 +62,7 @@ int main(int argc, char *argv[]) } printf("Test with swept tone.\n"); - s = swept_tone_init(NULL, 200.0f, 3900.0f, -10.0f, 60*SAMPLE_RATE, TRUE); + s = swept_tone_init(NULL, 200.0f, 3900.0f, -10.0f, 60*SAMPLE_RATE, true); for (j = 0; j < 60*SAMPLE_RATE; j += BLOCK_LEN) { len = swept_tone(s, buf, BLOCK_LEN); diff --git a/libs/spandsp/tests/t31_pseudo_terminal_tests.c b/libs/spandsp/tests/t31_pseudo_terminal_tests.c index da32c80c9f..d4fc01efc3 100644 --- a/libs/spandsp/tests/t31_pseudo_terminal_tests.c +++ b/libs/spandsp/tests/t31_pseudo_terminal_tests.c @@ -47,8 +47,6 @@ #include "spandsp.h" -#include "spandsp/t30_fcf.h" - #include "spandsp-sim.h" #undef SPANDSP_EXPOSE_INTERNAL_STRUCTURES @@ -80,14 +78,14 @@ g1050_state_t *path_b_to_a; double when = 0.0; -int t38_mode = FALSE; +int t38_mode = false; struct modem_s modem[10]; char *decode_test_file = NULL; int countdown = 0; int answered = 0; -int done = FALSE; +int done = false; int test_seq_ptr = 0; @@ -155,7 +153,7 @@ printf("\n"); modem = (modem_t *) user_data; #if defined(WIN32) - o.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + o.hEvent = CreateEvent(NULL, true, false, NULL); /* Initialize the rest of the OVERLAPPED structure to zero. */ o.Internal = 0; o.InternalHigh = 0; @@ -163,7 +161,7 @@ printf("\n"); o.OffsetHigh = 0; assert(o.hEvent); if (!WriteFile(modem->master, buf, (DWORD) len, &res, &o)) - GetOverlappedResult(modem->master, &o, &res, TRUE); + GetOverlappedResult(modem->master, &o, &res, true); CloseHandle(o.hEvent); #else res = write(modem->master, buf, len); @@ -205,7 +203,7 @@ static int t31_call_control(t31_state_t *s, void *user_data, int op, const char answered = 1; break; case AT_MODEM_CONTROL_HANGUP: - //done = TRUE; + //done = true; break; case AT_MODEM_CONTROL_OFFHOOK: break; @@ -302,7 +300,7 @@ static int modem_wait_sock(modem_t *modem, int ms, modem_poll_t flags) ret = MODEM_POLL_ERROR; arHandles[0] = modem->threadAbort; - o.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + o.hEvent = CreateEvent(NULL, true, false, NULL); arHandles[1] = o.hEvent; /* Initialize the rest of the OVERLAPPED structure to zero. */ @@ -323,7 +321,7 @@ static int modem_wait_sock(modem_t *modem, int ms, modem_poll_t flags) else { /* IO is pending, wait for it to finish */ - dwWait = WaitForMultipleObjects(2, arHandles, FALSE, INFINITE); + dwWait = WaitForMultipleObjects(2, arHandles, false, INFINITE); if (dwWait == WAIT_OBJECT_0 + 1 && !modem->block_read) ret = MODEM_POLL_READ; } @@ -415,8 +413,8 @@ static int t30_tests(int t38_mode, int use_ecm, int use_gui, int log_audio, int /* Set up the test environment */ t38_version = 1; - without_pacing = FALSE; - use_tep = FALSE; + without_pacing = false; + use_tep = false; wave_handle = NULL; if (log_audio) @@ -456,7 +454,7 @@ static int t30_tests(int t38_mode, int use_ecm, int use_gui, int log_audio, int { if (t38_mode) { - if ((t38_state = t38_terminal_init(NULL, FALSE, t38_tx_packet_handler, t31_state)) == NULL) + if ((t38_state = t38_terminal_init(NULL, false, t38_tx_packet_handler, t31_state)) == NULL) { fprintf(stderr, "Cannot start the T.38 channel\n"); exit(2); @@ -465,7 +463,7 @@ static int t30_tests(int t38_mode, int use_ecm, int use_gui, int log_audio, int } else { - fax_state = fax_init(NULL, FALSE); + fax_state = fax_init(NULL, false); t30 = fax_get_t30_state(fax_state); } t30_set_rx_file(t30, OUTPUT_FILE_NAME, -1); @@ -475,7 +473,7 @@ static int t30_tests(int t38_mode, int use_ecm, int use_gui, int log_audio, int { if (t38_mode) { - if ((t38_state = t38_terminal_init(NULL, TRUE, t38_tx_packet_handler, t31_state)) == NULL) + if ((t38_state = t38_terminal_init(NULL, true, t38_tx_packet_handler, t31_state)) == NULL) { fprintf(stderr, "Cannot start the T.38 channel\n"); exit(2); @@ -484,7 +482,7 @@ static int t30_tests(int t38_mode, int use_ecm, int use_gui, int log_audio, int } else { - fax_state = fax_init(NULL, TRUE); + fax_state = fax_init(NULL, true); t30 = fax_get_t30_state(fax_state); } t30_set_tx_file(t30, INPUT_FILE_NAME, -1, -1); @@ -559,7 +557,7 @@ static int t30_tests(int t38_mode, int use_ecm, int use_gui, int log_audio, int span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); span_log_set_tag(logging, "T.31"); - t31_set_mode(t31_state, TRUE); + t31_set_mode(t31_state, true); t38_set_t38_version(t38_core, t38_version); } @@ -606,7 +604,7 @@ printf("ZZZ\n"); if ((ret & MODEM_POLL_READ)) { #if defined(WIN32) - o.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + o.hEvent = CreateEvent(NULL, true, false, NULL); /* Initialize the rest of the OVERLAPPED structure to zero. */ o.Internal = 0; @@ -615,7 +613,7 @@ printf("ZZZ\n"); o.OffsetHigh = 0; assert(o.hEvent); if (!ReadFile(modem->master, buf, avail, &read_bytes, &o)) - GetOverlappedResult(modem->master, &o, &read_bytes, TRUE); + GetOverlappedResult(modem->master, &o, &read_bytes, true); CloseHandle (o.hEvent); if ((len = read_bytes)) #else @@ -767,11 +765,11 @@ int main(int argc, char *argv[]) #endif decode_test_file = NULL; - log_audio = FALSE; - test_sending = FALSE; - t38_mode = FALSE; - use_ecm = FALSE; - use_gui = FALSE; + log_audio = false; + test_sending = false; + t38_mode = false; + use_ecm = false; + use_gui = false; g1050_model_no = 0; g1050_speed_pattern_no = 1; while ((opt = getopt(argc, argv, "d:eglM:rS:st")) != -1) @@ -782,33 +780,33 @@ int main(int argc, char *argv[]) decode_test_file = optarg; break; case 'e': - use_ecm = TRUE; + use_ecm = true; break; case 'g': #if defined(ENABLE_GUI) - use_gui = TRUE; + use_gui = true; #else fprintf(stderr, "Graphical monitoring not available\n"); exit(2); #endif break; case 'l': - log_audio = TRUE; + log_audio = true; break; case 'M': g1050_model_no = optarg[0] - 'A' + 1; break; case 'r': - test_sending = FALSE; + test_sending = false; break; case 'S': g1050_speed_pattern_no = atoi(optarg); break; case 's': - test_sending = TRUE; + test_sending = true; break; case 't': - t38_mode = TRUE; + t38_mode = true; break; default: //usage(); diff --git a/libs/spandsp/tests/t31_tests.c b/libs/spandsp/tests/t31_tests.c index 6967ee1a67..12c3426b4d 100644 --- a/libs/spandsp/tests/t31_tests.c +++ b/libs/spandsp/tests/t31_tests.c @@ -82,7 +82,7 @@ g1050_state_t *path_b_to_a; double when = 0.0; -int t38_mode = FALSE; +int t38_mode = false; #define EXCHANGE(a,b) {a, sizeof(a) - 1, b, sizeof(b) - 1} #define RESPONSE(b) {"", 0, b, sizeof(b) - 1} @@ -106,9 +106,9 @@ static const struct command_response_s fax_send_test_seq[] = EXCHANGE("AT+FRH=3\r", "\r\nCONNECT\r\n"), // #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\x99\x80\x80\x80\x18\x58\x0D\x10\x03"), // For audio FAXing #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\x99\x80\x80\x80\x18\xC4\xBD\x10\x03"), // For T.38 FAXing #endif RESPONSE("\r\nOK\r\n"), //EXCHANGE("AT+FRH=3\r", "\r\nNO CARRIER\r\n"), @@ -268,11 +268,11 @@ int countdown = 0; int command_response_test_step = -1; char response_buf[1000]; int response_buf_ptr = 0; -int answered = FALSE; -int kick = FALSE; -int dled = FALSE; -int done = FALSE; -int sequence_terminated = FALSE; +int answered = false; +int kick = false; +int dled = false; +int done = false; +int sequence_terminated = false; static const struct command_response_s *fax_test_seq; @@ -333,10 +333,10 @@ static int modem_call_control(t31_state_t *s, void *user_data, int op, const cha t31_call_event(t31_state, AT_CALL_EVENT_CONNECTED); break; case AT_MODEM_CONTROL_ANSWER: - answered = TRUE; + answered = true; break; case AT_MODEM_CONTROL_HANGUP: - done = TRUE; + done = true; break; case AT_MODEM_CONTROL_OFFHOOK: break; @@ -393,17 +393,17 @@ static int at_tx_handler(at_state_t *s, void *user_data, const uint8_t *buf, siz response_buf[response_buf_ptr] = '\0'; test_seq_ptr++; if (fax_test_seq[test_seq_ptr].command == NULL && fax_test_seq[test_seq_ptr].command == NULL) - sequence_terminated = TRUE; + sequence_terminated = true; if (fax_test_seq[test_seq_ptr].command) - kick = TRUE; + kick = true; break; } - dled = FALSE; + dled = false; } else { if (buf[i] == DLE) - dled = TRUE; + dled = true; } } i++; @@ -432,13 +432,13 @@ static int at_tx_handler(at_state_t *s, void *user_data, const uint8_t *buf, siz printf("\nMatched\n"); test_seq_ptr++; if (fax_test_seq[test_seq_ptr].command == NULL && fax_test_seq[test_seq_ptr].command == NULL) - sequence_terminated = TRUE; + sequence_terminated = true; response_buf_ptr = 0; response_buf[response_buf_ptr] = '\0'; if (fax_test_seq[test_seq_ptr].command) - kick = TRUE; + kick = true; else - dled = FALSE; + dled = false; } return 0; } @@ -511,8 +511,8 @@ static int t30_tests(int t38_mode, int use_gui, int log_audio, int test_sending, /* Set up the test environment */ t38_version = 1; - without_pacing = FALSE; - use_tep = FALSE; + without_pacing = false; + use_tep = false; wave_handle = NULL; if (log_audio) @@ -552,7 +552,7 @@ static int t30_tests(int t38_mode, int use_gui, int log_audio, int test_sending, { if (t38_mode) { - if ((t38_state = t38_terminal_init(NULL, FALSE, t38_tx_packet_handler, t31_state)) == NULL) + if ((t38_state = t38_terminal_init(NULL, false, t38_tx_packet_handler, t31_state)) == NULL) { fprintf(stderr, "Cannot start the T.38 channel\n"); exit(2); @@ -561,7 +561,7 @@ static int t30_tests(int t38_mode, int use_gui, int log_audio, int test_sending, } else { - fax_state = fax_init(NULL, FALSE); + fax_state = fax_init(NULL, false); t30 = fax_get_t30_state(fax_state); } t30_set_rx_file(t30, OUTPUT_FILE_NAME, -1); @@ -572,7 +572,7 @@ static int t30_tests(int t38_mode, int use_gui, int log_audio, int test_sending, { if (t38_mode) { - if ((t38_state = t38_terminal_init(NULL, TRUE, t38_tx_packet_handler, t31_state)) == NULL) + if ((t38_state = t38_terminal_init(NULL, true, t38_tx_packet_handler, t31_state)) == NULL) { fprintf(stderr, "Cannot start the T.38 channel\n"); exit(2); @@ -581,7 +581,7 @@ static int t30_tests(int t38_mode, int use_gui, int log_audio, int test_sending, } else { - fax_state = fax_init(NULL, TRUE); + fax_state = fax_init(NULL, true); t30 = fax_get_t30_state(fax_state); } t30_set_tx_file(t30, INPUT_FILE_NAME, -1, -1); @@ -652,14 +652,14 @@ static int t30_tests(int t38_mode, int use_gui, int log_audio, int test_sending, span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); span_log_set_tag(logging, "T.31"); - t31_set_mode(t31_state, TRUE); + t31_set_mode(t31_state, true); t38_set_t38_version(t38_core, t38_version); } - fast_send = FALSE; - fast_send_tcf = TRUE; + fast_send = false; + fast_send_tcf = true; fast_blocks = 0; - kick = TRUE; + kick = true; #if defined(ENABLE_GUI) if (use_gui) start_media_monitor(); @@ -684,7 +684,7 @@ static int t30_tests(int t38_mode, int use_gui, int log_audio, int test_sending, if (kick) { /* Work through the script */ - kick = FALSE; + kick = false; if (fax_test_seq[test_seq_ptr].command > (const char *) 2) { if (fax_test_seq[test_seq_ptr].command[0]) @@ -698,15 +698,15 @@ static int t30_tests(int t38_mode, int use_gui, int log_audio, int test_sending, if (fax_test_seq[test_seq_ptr].command == (const char *) 2) { printf("Fast send TCF\n"); - fast_send = TRUE; - fast_send_tcf = TRUE; + fast_send = true; + fast_send_tcf = true; fast_blocks = 100; } else { printf("Fast send image\n"); - fast_send = TRUE; - fast_send_tcf = FALSE; + fast_send = true; + fast_send_tcf = false; fast_blocks = 100; } } @@ -756,7 +756,7 @@ static int t30_tests(int t38_mode, int use_gui, int log_audio, int test_sending, } t31_at_rx(t31_state, (char *) fast_buf, 36); if (--fast_blocks == 0) - fast_send = FALSE; + fast_send = false; } if (t38_mode) @@ -870,7 +870,7 @@ static int t30_tests(int t38_mode, int use_gui, int log_audio, int test_sending, if (!done || !sequence_terminated) { printf("Tests failed\n"); - return 2; + return -1; } return 0; @@ -888,10 +888,10 @@ int main(int argc, char *argv[]) int opt; decode_test_file = NULL; - log_audio = FALSE; - test_sending = FALSE; - t38_mode = FALSE; - use_gui = FALSE; + log_audio = false; + test_sending = false; + t38_mode = false; + use_gui = false; g1050_model_no = 0; g1050_speed_pattern_no = 1; while ((opt = getopt(argc, argv, "d:glM:rS:st")) != -1) @@ -903,29 +903,29 @@ int main(int argc, char *argv[]) break; case 'g': #if defined(ENABLE_GUI) - use_gui = TRUE; + use_gui = true; #else fprintf(stderr, "Graphical monitoring not available\n"); exit(2); #endif break; case 'l': - log_audio = TRUE; + log_audio = true; break; case 'M': g1050_model_no = optarg[0] - 'A' + 1; break; case 'r': - test_sending = FALSE; + test_sending = false; break; case 'S': g1050_speed_pattern_no = atoi(optarg); break; case 's': - test_sending = TRUE; + test_sending = true; break; case 't': - t38_mode = TRUE; + t38_mode = true; break; default: //usage(); @@ -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"); return 0; } diff --git a/libs/spandsp/tests/t35_tests.c b/libs/spandsp/tests/t35_tests.c index 62599e7630..b65e30189d 100644 --- a/libs/spandsp/tests/t35_tests.c +++ b/libs/spandsp/tests/t35_tests.c @@ -52,7 +52,7 @@ int main(int argc, char *argv[]) const char *country; const char *model; const char *real_country; - int first_hit; + bool first_hit; printf("Sweep through all the possible countries\n"); for (i = 0; i < 256; i++) @@ -75,7 +75,7 @@ int main(int argc, char *argv[]) msg[0] = i; msg[1] = '\x00'; msg[2] = '\x00'; - first_hit = TRUE; + first_hit = true; for (j = 0; j < 65536; j++) { msg[1] = (j >> 8) & 0xFF; @@ -88,7 +88,7 @@ int main(int argc, char *argv[]) printf("%s\n", real_country); else printf("???\n"); - first_hit = FALSE; + first_hit = false; } printf(" 0x%02x 0x%02x 0x%02x '%s'\n", msg[0], msg[1], msg[2], vendor); } diff --git a/libs/spandsp/tests/t38_core_tests.c b/libs/spandsp/tests/t38_core_tests.c index 094e688827..21c131bf3c 100644 --- a/libs/spandsp/tests/t38_core_tests.c +++ b/libs/spandsp/tests/t38_core_tests.c @@ -51,8 +51,8 @@ These tests exercise the T.38 core ASN.1 processing code. #define MAX_FIELDS 42 #define MAX_FIELD_LEN 8192 +static bool succeeded = true; static int t38_version; -static int succeeded = TRUE; static int ok_indicator_packets; static int bad_indicator_packets; static int ok_data_packets; @@ -130,7 +130,7 @@ static int tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t t = (t38_core_state_t *) user_data; span_log(t38_core_get_logging_state(s), SPAN_LOG_FLOW, "Send seq %d, len %d, count %d\n", s->tx_seq_no, len, count); if (t38_core_rx_ifp_packet(t, buf, len, seq_no) < 0) - succeeded = FALSE; + succeeded = false; seq_no++; return 0; } @@ -400,7 +400,7 @@ static int encode_then_decode_tests(t38_core_state_t *a, t38_core_state_t *b) for (i = 0, seq_no = 0; i < concat_len; i += len) { if ((len = t38_core_rx_ifp_stream(b, &concat[i], concat_len - i, seq_no)) < 0) - succeeded = FALSE; + succeeded = false; seq_no++; } @@ -597,8 +597,8 @@ int main(int argc, char *argv[]) t38_set_t38_version(t38_core_a, t38_version); t38_set_t38_version(t38_core_b, t38_version); - t38_set_pace_transmission(t38_core_a, FALSE); - t38_set_pace_transmission(t38_core_b, FALSE); + t38_set_pace_transmission(t38_core_a, false); + t38_set_pace_transmission(t38_core_b, false); t38_set_data_transport_protocol(t38_core_a, T38_TRANSPORT_TCP); t38_set_data_transport_protocol(t38_core_b, T38_TRANSPORT_TCP); @@ -629,7 +629,7 @@ int main(int argc, char *argv[]) t38_set_t38_version(t38_core_a, t38_version); - t38_set_pace_transmission(t38_core_a, FALSE); + t38_set_pace_transmission(t38_core_a, false); t38_set_data_transport_protocol(t38_core_a, T38_TRANSPORT_TCP); @@ -677,8 +677,8 @@ int main(int argc, char *argv[]) t38_set_t38_version(t38_core_a, t38_version); t38_set_t38_version(t38_core_b, t38_version); - t38_set_pace_transmission(t38_core_a, FALSE); - t38_set_pace_transmission(t38_core_b, FALSE); + t38_set_pace_transmission(t38_core_a, false); + t38_set_pace_transmission(t38_core_b, false); t38_set_data_transport_protocol(t38_core_a, T38_TRANSPORT_TCP_TPKT); t38_set_data_transport_protocol(t38_core_b, T38_TRANSPORT_TCP_TPKT); @@ -708,7 +708,7 @@ int main(int argc, char *argv[]) } t38_set_t38_version(t38_core_a, t38_version); - t38_set_pace_transmission(t38_core_a, FALSE); + t38_set_pace_transmission(t38_core_a, false); t38_set_data_transport_protocol(t38_core_a, T38_TRANSPORT_TCP_TPKT); diff --git a/libs/spandsp/tests/t38_decode.c b/libs/spandsp/tests/t38_decode.c index 67660fe937..e29b64cbf6 100644 --- a/libs/spandsp/tests/t38_decode.c +++ b/libs/spandsp/tests/t38_decode.c @@ -65,9 +65,9 @@ static SNDFILE *wave_handle; static int log_audio; static int use_transmit_on_idle; -static int done = FALSE; +static int done = false; -static int started = FALSE; +static int started = false; static int64_t current = 0; static int phase_b_handler(t30_state_t *s, void *user_data, int result) @@ -263,7 +263,7 @@ static int ifp_handler(void *user_data, const uint8_t msg[], int len, int seq_no { int i; - started = TRUE; + started = true; printf("%5d >>> ", seq_no); for (i = 0; i < len; i++) @@ -333,17 +333,17 @@ int main(int argc, char *argv[]) uint32_t dest_addr; uint16_t dest_port; - caller = FALSE; - use_ecm = FALSE; + caller = false; + use_ecm = false; t38_version = 0; options = 0; input_file_name = INPUT_FILE_NAME; - fill_removal = FALSE; - use_tep = FALSE; - use_transmit_on_idle = TRUE; + fill_removal = false; + use_tep = false; + use_transmit_on_idle = true; supported_modems = T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17; - t38_terminal_operation = TRUE; - log_audio = FALSE; + t38_terminal_operation = true; + log_audio = false; src_addr = 0; src_port = 0; dest_addr = 0; @@ -353,7 +353,7 @@ int main(int argc, char *argv[]) switch (opt) { case 'c': - caller = TRUE; + caller = true; break; case 'D': dest_addr = parse_inet_addr(optarg); @@ -362,19 +362,19 @@ int main(int argc, char *argv[]) dest_port = atoi(optarg); break; case 'e': - use_ecm = TRUE; + use_ecm = true; break; case 'F': - fill_removal = TRUE; + fill_removal = true; break; case 'G': - t38_terminal_operation = FALSE; + t38_terminal_operation = false; break; case 'i': input_file_name = optarg; break; case 'l': - log_audio = TRUE; + log_audio = true; break; case 'm': supported_modems = atoi(optarg); @@ -389,7 +389,7 @@ int main(int argc, char *argv[]) src_port = atoi(optarg); break; case 't': - use_tep = TRUE; + use_tep = true; break; case 'v': t38_version = atoi(optarg); @@ -440,7 +440,36 @@ int main(int argc, char *argv[]) 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_ecm_capability(t30, use_ecm); - t30_set_supported_compressions(t30, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION | T30_SUPPORT_T85_COMPRESSION); + t30_set_supported_compressions(t30, + T4_COMPRESSION_T4_1D + | T4_COMPRESSION_T4_2D + | T4_COMPRESSION_T6 + | T4_COMPRESSION_T85 + | T4_COMPRESSION_T85_L0 + | T4_COMPRESSION_T42_T81 + | T4_COMPRESSION_COLOUR); + t30_set_supported_bilevel_resolutions(t30, + T4_RESOLUTION_R8_STANDARD + | T4_RESOLUTION_R8_FINE + | T4_RESOLUTION_R8_SUPERFINE + | T4_RESOLUTION_R16_SUPERFINE + | T4_RESOLUTION_200_100 + | T4_RESOLUTION_200_200 + | T4_RESOLUTION_200_400 + | T4_RESOLUTION_300_300 + | T4_RESOLUTION_300_600 + | T4_RESOLUTION_400_400 + | T4_RESOLUTION_400_800 + | T4_RESOLUTION_600_600 + | T4_RESOLUTION_600_1200 + | T4_RESOLUTION_1200_1200); + t30_set_supported_colour_resolutions(t30, + T4_RESOLUTION_100_100 + | T4_RESOLUTION_200_200 + | T4_RESOLUTION_300_300 + | T4_RESOLUTION_400_400 + | T4_RESOLUTION_600_600 + | T4_RESOLUTION_1200_1200); if (pcap_scan_pkts(input_file_name, src_addr, src_port, dest_addr, dest_port, t38_terminal_timing_update, process_packet, NULL)) exit(2); @@ -497,7 +526,36 @@ int main(int argc, char *argv[]) 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_ecm_capability(t30, use_ecm); - t30_set_supported_compressions(t30, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION); + t30_set_supported_compressions(t30, + T4_COMPRESSION_T4_1D + | T4_COMPRESSION_T4_2D + | T4_COMPRESSION_T6 + | T4_COMPRESSION_T85 + | T4_COMPRESSION_T85_L0 + | T4_COMPRESSION_T42_T81 + | T4_COMPRESSION_COLOUR); + t30_set_supported_bilevel_resolutions(t30, + T4_RESOLUTION_R8_STANDARD + | T4_RESOLUTION_R8_FINE + | T4_RESOLUTION_R8_SUPERFINE + | T4_RESOLUTION_R16_SUPERFINE + | T4_RESOLUTION_200_100 + | T4_RESOLUTION_200_200 + | T4_RESOLUTION_200_400 + | T4_RESOLUTION_300_300 + | T4_RESOLUTION_300_600 + | T4_RESOLUTION_400_400 + | T4_RESOLUTION_400_800 + | T4_RESOLUTION_600_600 + | T4_RESOLUTION_600_1200 + | T4_RESOLUTION_1200_1200); + t30_set_supported_colour_resolutions(t30, + T4_RESOLUTION_100_100 + | T4_RESOLUTION_200_200 + | T4_RESOLUTION_300_300 + | T4_RESOLUTION_400_400 + | T4_RESOLUTION_600_600 + | T4_RESOLUTION_1200_1200); logging = fax_get_logging_state(fax_state); span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME); diff --git a/libs/spandsp/tests/t38_non_ecm_buffer_tests.c b/libs/spandsp/tests/t38_non_ecm_buffer_tests.c index c9fa046cb4..9b4cb4039c 100644 --- a/libs/spandsp/tests/t38_non_ecm_buffer_tests.c +++ b/libs/spandsp/tests/t38_non_ecm_buffer_tests.c @@ -144,7 +144,7 @@ int main(int argc, char *argv[]) span_log_set_protocol(&logging, "Buffer"); printf("1 - Impose no minimum for the bits per row\n"); - t38_non_ecm_buffer_init(&buffer, TRUE, 0); + t38_non_ecm_buffer_init(&buffer, true, 0); n = 0; bit_no = 0; /* We should get ones until the buffers recognises an EOL */ @@ -170,7 +170,7 @@ int main(int argc, char *argv[]) t38_non_ecm_buffer_report_output_status(&buffer, &logging); printf("2 - Impose no minimum for the bits per row, different alignment\n"); - t38_non_ecm_buffer_init(&buffer, TRUE, 0); + t38_non_ecm_buffer_init(&buffer, true, 0); n = 0; memset(buf, 0, sizeof(buf)); /* The first one in this should be seen as the first EOL */ @@ -235,7 +235,7 @@ int main(int argc, char *argv[]) t38_non_ecm_buffer_report_output_status(&buffer, &logging); printf("3 - Demand a fairly high minimum for the bits per row\n"); - t38_non_ecm_buffer_init(&buffer, TRUE, 400); + t38_non_ecm_buffer_init(&buffer, true, 400); n = 0; memset(buf, 0, sizeof(buf)); /* The first one in this should be seen as the first EOL */ @@ -300,7 +300,7 @@ int main(int argc, char *argv[]) t38_non_ecm_buffer_report_output_status(&buffer, &logging); printf("4 - Take some time to get to the first row of the image, output ahead\n"); - t38_non_ecm_buffer_init(&buffer, TRUE, 400); + t38_non_ecm_buffer_init(&buffer, true, 400); n = 0; /* Get some initial bits from an empty buffer. These should be ones */ for (i = 0; i < 1000; i++) @@ -448,7 +448,7 @@ int main(int argc, char *argv[]) t38_non_ecm_buffer_report_output_status(&buffer, &logging); printf("5 - Take some time to get to the first row of the image, output behind\n"); - t38_non_ecm_buffer_init(&buffer, TRUE, 400); + t38_non_ecm_buffer_init(&buffer, true, 400); n = 0; /* Inject some ones. */ memset(buf, 0xFF, 100); @@ -585,7 +585,7 @@ int main(int argc, char *argv[]) t38_non_ecm_buffer_report_output_status(&buffer, &logging); printf("6 - TCF without leading ones\n"); - t38_non_ecm_buffer_init(&buffer, FALSE, 400); + t38_non_ecm_buffer_init(&buffer, false, 400); n = 0; /* Get some initial bits from an empty buffer. These should be ones */ for (i = 0; i < 1000; i++) @@ -630,7 +630,7 @@ int main(int argc, char *argv[]) t38_non_ecm_buffer_report_output_status(&buffer, &logging); printf("7 - TCF with leading ones\n"); - t38_non_ecm_buffer_init(&buffer, FALSE, 400); + t38_non_ecm_buffer_init(&buffer, false, 400); n = 0; /* Get some initial bits from an empty buffer. These should be ones */ for (i = 0; i < 1000; i++) diff --git a/libs/spandsp/tests/t42_tests.c b/libs/spandsp/tests/t42_tests.c index ddd5438197..ea87b4eab3 100644 --- a/libs/spandsp/tests/t42_tests.c +++ b/libs/spandsp/tests/t42_tests.c @@ -47,7 +47,6 @@ #include #endif -//#define IN_FILE_NAME "../test-data/itu/t24/F21_200.TIF" #define IN_FILE_NAME "../test-data/itu/t24/F21B400.TIF" #define OUT_FILE_NAME "t42_tests_receive.tif" @@ -148,18 +147,23 @@ int main(int argc, char *argv[]) uint16_t *map_b; uint16_t *map_z; uint32_t jpeg_table_len; +#if 0 logging_state_t *logging; +#endif printf("Demo of ITU/Lab library.\n"); +#if 0 logging = span_log_init(NULL, SPAN_LOG_FLOW, "T.42"); +#endif #if defined(SPANDSP_SUPPORT_TIFF_FX) TIFF_FX_init(); #endif - set_lab_illuminant(&lab_param, 0.9638f, 1.0f, 0.8245f); - set_lab_gamut(&lab_param, 0, 100, -85, 85, -75, 125, FALSE); + /* The default luminant is D50 */ + set_lab_illuminant(&lab_param, 96.422f, 100.000f, 82.521f); + set_lab_gamut(&lab_param, 0, 100, -85, 85, -75, 125, false); source_file = (argc > 1) ? argv[1] : IN_FILE_NAME; /* sRGB to ITU */ @@ -219,8 +223,9 @@ int main(int argc, char *argv[]) #endif lab_params_t lab; - set_lab_illuminant(&lab, 0.9638f, 1.0f, 0.8245f); - set_lab_gamut(&lab, 0, 100, -85, 85, -75, 125, FALSE); + /* The default luminant is D50 */ + set_lab_illuminant(&lab, 96.422f, 100.000f, 82.521f); + set_lab_gamut(&lab, 0, 100, -85, 85, -75, 125, false); lab_to_srgb(&lab, colour_map, colour_map, 256); for (i = 0; i < (1 << bits_per_pixel); i++) printf("Map %3d - %5d %5d %5d\n", i, colour_map[3*i], colour_map[3*i + 1], colour_map[3*i + 2]); @@ -229,7 +234,7 @@ int main(int argc, char *argv[]) { printf("There is no colour map\n"); } - process_raw = FALSE; + process_raw = false; printf("Compression is "); switch (compression) { @@ -241,18 +246,18 @@ int main(int argc, char *argv[]) return 0; case COMPRESSION_T85: printf("T.85\n"); - process_raw = TRUE; + process_raw = true; break; case COMPRESSION_T43: printf("T.43\n"); - process_raw = TRUE; + process_raw = true; break; case COMPRESSION_JPEG: printf("JPEG"); if (photometric == PHOTOMETRIC_ITULAB) { printf(" ITULAB"); - process_raw = TRUE; + process_raw = true; } printf("\n"); break; @@ -264,6 +269,7 @@ int main(int argc, char *argv[]) break; } + outsize = 0; if (process_raw) { uint8_t *jpeg_table; @@ -294,7 +300,7 @@ int main(int argc, char *argv[]) memcpy(data, jpeg_table, jpeg_table_len - 2); if (total_len != total_image_len) - printf("Size mismatch %ld %ld\n", total_len, total_image_len); + printf("Size mismatch %ld %ld\n", (long int) total_len, (long int) total_image_len); off = total_len; switch (compression) { @@ -303,7 +309,7 @@ int main(int argc, char *argv[]) case COMPRESSION_CCITT_T6: break; case COMPRESSION_T85: - printf("T.85 image %ld bytes\n", total_len); + printf("T.85 image %ld bytes\n", (long int) total_len); for (i = 0; i < 16; i++) printf("0x%02x\n", data[i]); t85_decode_init(&t85_dec, t85_row_write_handler, NULL); @@ -316,7 +322,7 @@ int main(int argc, char *argv[]) t85_decode_release(&t85_dec); return 0; case COMPRESSION_T43: - printf("T.43 image %ld bytes\n", total_len); + printf("T.43 image %ld bytes\n", (long int) total_len); if (pack_16(data) == 0xFFA8) { data += 2; @@ -441,19 +447,20 @@ int main(int argc, char *argv[]) return 1; off += bytes_per_row; } - printf("total %u, off %ld\n", totdata, off); + printf("total %u, off %ld\n", totdata, (long int) off); /* We now have the image in memory in RGB form */ if (photometric == PHOTOMETRIC_ITULAB) { printf("YYY ITULAB\n"); - - if (!t42_itulab_to_itulab(logging, (tdata_t) &outptr, &outsize, data, off, w, h)) +#if 0 + if (!t42_itulab_to_itulab(logging, (tdata_t) &outptr, &outsize, data, off, w, h, 3)) { printf("Failed to convert to ITULAB\n"); return 1; } +#endif free(data); data = (uint8_t *) outptr; off = outsize; @@ -467,15 +474,16 @@ int main(int argc, char *argv[]) printf("CIELAB\n"); /* The default luminant is D50 */ set_lab_illuminant(&lab_param, 96.422f, 100.000f, 82.521f); - set_lab_gamut(&lab_param, 0, 100, -128, 127, -128, 127, TRUE); + set_lab_gamut(&lab_param, 0, 100, -128, 127, -128, 127, true); lab_to_srgb(&lab_param, data, data, w*h); break; case PHOTOMETRIC_ITULAB: - set_lab_illuminant(&lab_param, 0.9638f, 1.0f, 0.8245f); - set_lab_gamut(&lab_param, 0, 100, -85, 85, -75, 125, FALSE); + /* The default luminant is D50 */ + set_lab_illuminant(&lab_param, 96.422f, 100.000f, 82.521f); + set_lab_gamut(&lab_param, 0, 100, -85, 85, -75, 125, false); break; } - if (!t42_srgb_to_itulab(logging, &lab_param, (tdata_t) &outptr, &outsize, data, off, w, h)) + //if (!t42_srgb_to_itulab_jpeg(logging, &lab_param, (tdata_t) &outptr, &outsize, data, off, w, h, 3)) { printf("Failed to convert to ITULAB\n"); return 1; @@ -489,7 +497,7 @@ int main(int argc, char *argv[]) } TIFFClose(tif); - printf("XXX - image is %d by %d, %ld bytes\n", w, h, off); + printf("XXX - image is %d by %d, %ld bytes\n", w, h, (long int) off); /* We now have the image in memory in ITULAB form */ @@ -533,8 +541,9 @@ int main(int argc, char *argv[]) bytes_per_row = (bits_per_pixel + 7)/8; bytes_per_row *= w*samples_per_pixel; totdata = h*bytes_per_row; - set_lab_illuminant(&lab_param, 0.9638f, 1.0f, 0.8245f); - set_lab_gamut(&lab_param, 0, 100, -85, 85, -75, 125, FALSE); + /* The default luminant is D50 */ + set_lab_illuminant(&lab_param, 96.422f, 100.000f, 82.521f); + set_lab_gamut(&lab_param, 0, 100, -85, 85, -75, 125, false); #if 0 start = rdtscll(); data2 = NULL; @@ -552,7 +561,7 @@ int main(int argc, char *argv[]) #else data2 = malloc(totdata); start = rdtscll(); - if (!t42_itulab_to_srgb(logging, &lab_param, data2, &off, data, off, &w, &h)) + //if (!t42_itulab_jpeg_to_srgb(logging, &lab_param, data2, &off, data, off, &w, &h, &samples_per_pixel)) { printf("Failed to convert from ITULAB\n"); return 1; diff --git a/libs/spandsp/tests/t43_tests.c b/libs/spandsp/tests/t43_tests.c new file mode 100644 index 0000000000..7d51d7dfb4 --- /dev/null +++ b/libs/spandsp/tests/t43_tests.c @@ -0,0 +1,1403 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * t43_tests.c - ITU T.43 JBIG for grey and colour FAX image processing + * + * Written by Steve Underwood + * + * 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 General Public License version 2, 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/*! \file */ + +/*! \page t43_tests_page T.43 tests +\section t43_tests_page_sec_1 What does it do +*/ + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES + +#include "spandsp.h" + +#if defined(SPANDSP_SUPPORT_TIFF_FX) +#include +#endif + +#define IN_FILE_NAME "../test-data/itu/tiff-fx/l04x_02x.tif" +#define OUT_FILE_NAME "t43_tests_receive.tif" + +t43_decode_state_t t43; +t85_decode_state_t t85; + +lab_params_t lab_param; + +int write_row = 0; + +typedef struct +{ + uint8_t *buf; + int ptr; +} packer_t; + +#if defined(SPANDSP_SUPPORT_TIFF_FX) +/* TIFF-FX related extensions to the tag set supported by libtiff */ +static const TIFFFieldInfo tiff_fx_tiff_field_info[] = +{ + {TIFFTAG_INDEXED, 1, 1, TIFF_SHORT, FIELD_CUSTOM, false, false, (char *) "Indexed"}, + {TIFFTAG_GLOBALPARAMETERSIFD, 1, 1, TIFF_IFD8, FIELD_CUSTOM, false, false, (char *) "GlobalParametersIFD"}, + {TIFFTAG_PROFILETYPE, 1, 1, TIFF_LONG, FIELD_CUSTOM, false, false, (char *) "ProfileType"}, + {TIFFTAG_FAXPROFILE, 1, 1, TIFF_BYTE, FIELD_CUSTOM, false, false, (char *) "FaxProfile"}, + {TIFFTAG_CODINGMETHODS, 1, 1, TIFF_LONG, FIELD_CUSTOM, false, false, (char *) "CodingMethods"}, + {TIFFTAG_VERSIONYEAR, 4, 4, TIFF_BYTE, FIELD_CUSTOM, false, false, (char *) "VersionYear"}, + {TIFFTAG_MODENUMBER, 1, 1, TIFF_BYTE, FIELD_CUSTOM, false, false, (char *) "ModeNumber"}, + {TIFFTAG_DECODE, TIFF_VARIABLE, TIFF_VARIABLE, TIFF_SRATIONAL, FIELD_CUSTOM, false, true, (char *) "Decode"}, + {TIFFTAG_IMAGEBASECOLOR, TIFF_VARIABLE, TIFF_VARIABLE, TIFF_SHORT, FIELD_CUSTOM, false, true, (char *) "ImageBaseColor"}, + {TIFFTAG_T82OPTIONS, 1, 1, TIFF_LONG, FIELD_CUSTOM, false, false, (char *) "T82Options"}, + {TIFFTAG_STRIPROWCOUNTS, TIFF_VARIABLE, TIFF_VARIABLE, TIFF_LONG, FIELD_CUSTOM, false, true, (char *) "StripRowCounts"}, + {TIFFTAG_IMAGELAYER, 2, 2, TIFF_LONG, FIELD_CUSTOM, false, false, (char *) "ImageLayer"}, +}; + +static TIFFFieldArray tifffxFieldArray; + +static TIFFField tiff_fx_tiff_fields[] = +{ + { TIFFTAG_INDEXED, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "Indexed" }, + { TIFFTAG_GLOBALPARAMETERSIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, (char *) "GlobalParametersIFD", &tifffxFieldArray }, + { TIFFTAG_PROFILETYPE, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "ProfileType", NULL }, + { TIFFTAG_FAXPROFILE, 1, 1, TIFF_BYTE, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "FaxProfile", NULL }, + { TIFFTAG_CODINGMETHODS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "CodingMethods", NULL }, + { TIFFTAG_VERSIONYEAR, 4, 4, TIFF_BYTE, 0, TIFF_SETGET_C0_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "VersionYear", NULL }, + { TIFFTAG_MODENUMBER, 1, 1, TIFF_BYTE, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "ModeNumber", NULL }, + { TIFFTAG_DECODE, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, (char *) "Decode", NULL }, + { TIFFTAG_IMAGEBASECOLOR, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, (char *) "ImageBaseColor", NULL }, + { TIFFTAG_T82OPTIONS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "T82Options", NULL }, + { TIFFTAG_STRIPROWCOUNTS, -1, -1, TIFF_LONG, 0, TIFF_SETGET_C16_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, (char *) "StripRowCounts", NULL }, + { TIFFTAG_IMAGELAYER, 2, 2, TIFF_LONG, 0, TIFF_SETGET_C0_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "ImageLayer", NULL }, +}; + +static TIFFFieldArray tiff_fx_field_array = { tfiatOther, 0, 12, tiff_fx_tiff_fields }; +#endif + +typedef struct +{ + TIFF *tif; + int pre_compressed; + uint32_t compressed_image_len; + uint32_t image_width; + uint32_t image_length; + float x_resolution; + float y_resolution; + uint16_t resolution_unit; + uint16_t bits_per_sample; + uint16_t samples_per_pixel; + uint16_t compression; + uint16_t photometric; + int16_t YCbCrSubsampleHoriz; + int16_t YCbCrSubsampleVert; + int16_t planar_config; + int32_t tile_width; + int32_t tile_length; + uint8_t *colour_map; + float lmin; + float lmax; + float amin; + float amax; + float bmin; + float bmax; +} meta_t; + +int write_file(meta_t *meta, int page, const uint8_t buf[]); +int read_file(meta_t *meta, int page); +int read_compressed_image(meta_t *meta, uint8_t **buf); +int read_decompressed_image(meta_t *meta, uint8_t **buf); + +static int row_write_handler(void *user_data, const uint8_t buf[], size_t len) +{ + packer_t *s; + + s = (packer_t *) user_data; + memcpy(&s->buf[s->ptr], buf, len); + s->ptr += len; + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int t85_comment_handler(void *user_data, const uint8_t buf[], size_t len) +{ + if (buf) + printf("Comment (%lu): %s\n", (unsigned long int) len, buf); + else + printf("Comment (%lu): ---\n", (unsigned long int) len); + return 0; +} +/*- End of function --------------------------------------------------------*/ + +static int row_read_handler(void *user_data, uint8_t row[], size_t len) +{ + packer_t *s; + + s = (packer_t *) user_data; + memcpy(row, &s->buf[s->ptr], len); + s->ptr += len; + return len; +} +/*- End of function --------------------------------------------------------*/ + +int write_file(meta_t *meta, int page, const uint8_t buf[]) +{ + TIFF *tif; + int off; + int i; + time_t now; + struct tm *tm; + char date_buf[50 + 1]; + int bytes_per_row; + t85_encode_state_t t85; + t43_encode_state_t t43; + int out_buf_len; + int out_len; + int chunk_len; + uint8_t *out_buf; + uint8_t *out_buf2; + packer_t packer; +#if defined(SPANDSP_SUPPORT_TIFF_FX) + uint64_t offset; +#endif + + tif = meta->tif; + TIFFSetField(tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE); + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, meta->image_width); + /* libtiff requires IMAGELENGTH to be set before SAMPLESPERPIXEL, + or StripOffsets and StripByteCounts will have SAMPLESPERPIXEL values */ + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, meta->image_length); + TIFFSetField(tif, TIFFTAG_COMPRESSION, meta->compression); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, meta->bits_per_sample); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, meta->samples_per_pixel); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, meta->image_length); + TIFFSetField(tif, TIFFTAG_XRESOLUTION, meta->x_resolution); + TIFFSetField(tif, TIFFTAG_YRESOLUTION, meta->y_resolution); + TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, meta->resolution_unit); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, meta->photometric); + if (meta->samples_per_pixel > 1 && (meta->YCbCrSubsampleHoriz || meta->YCbCrSubsampleVert)) + TIFFSetField(tif, TIFFTAG_YCBCRSUBSAMPLING, meta->YCbCrSubsampleHoriz, meta->YCbCrSubsampleVert); + TIFFSetField(tif, TIFFTAG_SOFTWARE, "spandsp"); + TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, "Test"); + time(&now); + tm = localtime(&now); + sprintf(date_buf, + "%4d/%02d/%02d %02d:%02d:%02d", + tm->tm_year + 1900, + tm->tm_mon + 1, + tm->tm_mday, + tm->tm_hour, + tm->tm_min, + tm->tm_sec); + TIFFSetField(tif, TIFFTAG_DATETIME, date_buf); + TIFFSetField(tif, TIFFTAG_MAKE, "soft-switch.org"); + TIFFSetField(tif, TIFFTAG_MODEL, "spandsp"); + TIFFSetField(tif, TIFFTAG_HOSTCOMPUTER, "i7.coppice.org"); +#if defined(SPANDSP_SUPPORT_TIFF_FX) + /* Make space for this to be filled in later */ + TIFFSetField(tif, TIFFTAG_GLOBALPARAMETERSIFD, 0); +#endif + + if (meta->pre_compressed) + { + if (TIFFWriteRawStrip(tif, 0, (tdata_t) buf, meta->compressed_image_len) < 0) + printf("Error writing TIFF strip.\n"); + } + else + { + switch (meta->compression) + { + case COMPRESSION_T85: + packer.buf = (uint8_t *) buf; + packer.ptr = 0; + t85_encode_init(&t85, meta->image_width, meta->image_length, row_read_handler, &packer); + //if (meta->compression == T4_COMPRESSION_T85_L0) + // t85_encode_set_options(&t85, 256, -1, -1); + out_len = 0; + out_buf_len = 0; + out_buf = NULL; + do + { + if (out_buf_len < out_len + 50000) + { + out_buf_len += 50000; + if ((out_buf2 = realloc(out_buf, out_buf_len)) == NULL) + { + if (out_buf) + free(out_buf); + return -1; + } + out_buf = out_buf2; + } + chunk_len = t85_encode_get(&t85, &out_buf[out_len], 50000); + out_len += chunk_len; + } + while (chunk_len > 0); + if (TIFFWriteRawStrip(tif, 0, out_buf, out_len) < 0) + printf("Error writing TIFF strip.\n"); + t85_encode_release(&t85); + free(out_buf); + break; + case COMPRESSION_T43: + packer.buf = (uint8_t *) buf; + packer.ptr = 0; + t43_encode_init(&t43, meta->image_width, meta->image_length, row_read_handler, &packer); + out_len = 0; + out_buf_len = 0; + out_buf = NULL; + do + { + if (out_buf_len < out_len + 50000) + { + out_buf_len += 50000; + if ((out_buf2 = realloc(out_buf, out_buf_len)) == NULL) + { + if (out_buf) + free(out_buf); + return -1; + } + out_buf = out_buf2; + } + chunk_len = t43_encode_get(&t43, &out_buf[out_len], 50000); + out_len += chunk_len; + } + while (chunk_len > 0); + if (TIFFWriteRawStrip(tif, 0, out_buf, out_len) < 0) + printf("Error writing TIFF strip.\n"); + t43_encode_release(&t43); + free(out_buf); + break; + default: + bytes_per_row = TIFFScanlineSize(tif); + for (off = 0, i = 0; i < meta->image_length; off += bytes_per_row, i++) + { + if (TIFFWriteScanline(tif, (tdata_t) &buf[off], i, 0) < 0) + printf("Error writing TIFF scan line.\n"); + } + break; + } + } + + if (!TIFFWriteDirectory(tif)) + printf("Failed to write directory.\n"); + +#if defined(SPANDSP_SUPPORT_TIFF_FX) + if (!TIFFCreateCustomDirectory(tif, &tiff_fx_field_array)) + { + TIFFSetField(tif, TIFFTAG_PROFILETYPE, PROFILETYPE_G3_FAX); + TIFFSetField(tif, TIFFTAG_FAXPROFILE, FAXPROFILE_F); + TIFFSetField(tif, TIFFTAG_CODINGMETHODS, CODINGMETHODS_T4_1D | CODINGMETHODS_T4_2D | CODINGMETHODS_T6); + TIFFSetField(tif, TIFFTAG_VERSIONYEAR, "1998"); + TIFFSetField(tif, TIFFTAG_MODENUMBER, 3); + + offset = 0; + if (!TIFFWriteCustomDirectory(tif, &offset)) + printf("Failed to write custom directory.\n"); + + if (!TIFFSetDirectory(tif, (tdir_t) page)) + printf("Failed to set directory.\n"); + if (!TIFFSetField(tif, TIFFTAG_GLOBALPARAMETERSIFD, offset)) + printf("Failed to set global parameters IFD.\n"); + if (!TIFFWriteDirectory(tif)) + printf("Failed to write directory.\n"); + } +#endif + return 0; +} +/*- End of function --------------------------------------------------------*/ + +int read_file(meta_t *meta, int page) +{ +#if defined(SPANDSP_SUPPORT_TIFF_FX) + static const char *tiff_fx_fax_profiles[] = + { + "???", + "profile S", + "profile F", + "profile J", + "profile C", + "profile L", + "profile M" + }; + uint8_t parm8; + uint16_t parm16; + uint32_t parm32; + float *fl_parms; + char uu[10]; + char *u; + uint64_t offset; +#endif + TIFF *tif; + uint16_t *map_L; + uint16_t *map_a; + uint16_t *map_b; + uint16_t *map_z; + lab_params_t lab; + int entries; + int i; + + tif = meta->tif; + printf("Read %d\n", page); + if (!TIFFSetDirectory(tif, (tdir_t) page)) + { + printf("Unable to set TIFF directory %d!\n", page); + return -1; + } + meta->image_width = 0; + TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &meta->image_width); + meta->image_length = 0; + TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &meta->image_length); + meta->x_resolution = 200.0f; + TIFFGetField(tif, TIFFTAG_XRESOLUTION, &meta->x_resolution); + meta->y_resolution = 200.0f; + TIFFGetField(tif, TIFFTAG_YRESOLUTION, &meta->y_resolution); + meta->resolution_unit = RESUNIT_INCH; + TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &meta->resolution_unit); + meta->bits_per_sample = 0; + TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &meta->bits_per_sample); + meta->samples_per_pixel = 0; + TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &meta->samples_per_pixel); + meta->compression = 0; + TIFFGetField(tif, TIFFTAG_COMPRESSION, &meta->compression); + meta->photometric = 0; + TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &meta->photometric); + meta->YCbCrSubsampleHoriz = 0; + meta->YCbCrSubsampleVert = 0; + TIFFGetField(tif, TIFFTAG_YCBCRSUBSAMPLING, &meta->YCbCrSubsampleHoriz, &meta->YCbCrSubsampleVert); + meta->planar_config = PLANARCONFIG_CONTIG; + TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &meta->planar_config); + meta->tile_width = 0; + TIFFGetField(tif, TIFFTAG_TILEWIDTH, &meta->tile_width); + meta->tile_length = 0; + TIFFGetField(tif, TIFFTAG_TILELENGTH, &meta->tile_length); + + switch (meta->photometric) + { + case PHOTOMETRIC_ITULAB: + meta->lmin = 0.0f; + meta->lmax = 100.0f; + meta->amin = -21760.0f/255.0f; // For 12 bit -348160.0f/4095.0f + meta->amax = 21590.0f/255.0f; // For 12 bit 347990.0f/4095.0f + meta->bmin = -19200.0f/255.0f; // For 12 bit -307200.0f/4095.0f + meta->bmax = 31800.0f/255.0f; // For 12 bit 511800.0f/4095.0f + break; + default: + meta->lmin = 0.0f; + meta->lmax = 0.0f; + meta->amin = 0.0f; + meta->amax = 0.0f; + meta->bmin = 0.0f; + meta->bmax = 0.0f; + break; + } +#if defined(SPANDSP_SUPPORT_TIFF_FX) + if (TIFFGetField(tif, TIFFTAG_DECODE, &parm16, &fl_parms)) + { + meta->lmin = fl_parms[0]; + meta->lmax = fl_parms[1]; + meta->amin = fl_parms[2]; + meta->amax = fl_parms[3]; + meta->bmin = fl_parms[4]; + meta->bmax = fl_parms[5]; + printf("Got decode tag %f %f %f %f %f %f\n", meta->lmin, meta->lmax, meta->amin, meta->amax, meta->bmin, meta->bmax); + } +#endif + +#if defined(SPANDSP_SUPPORT_TIFF_FX) + printf("Trying to get global parameters\n"); + if (TIFFGetField(tif, TIFFTAG_GLOBALPARAMETERSIFD, &offset)) + { + printf("Got global parameters - %" PRIu64 "\n", offset); + if (!TIFFReadCustomDirectory(tif, offset, &tiff_fx_field_array)) + { + printf("Failed to set global parameters IFD.\n"); + } + else + { + if (TIFFGetField(tif, TIFFTAG_PROFILETYPE, &parm32)) + printf(" Profile type %u\n", parm32); + if (TIFFGetField(tif, TIFFTAG_FAXPROFILE, &parm8)) + printf(" FAX profile %s (%u)\n", tiff_fx_fax_profiles[parm8], parm8); + if (TIFFGetField(tif, TIFFTAG_CODINGMETHODS, &parm32)) + printf(" Coding methods 0x%x\n", parm32); + if (TIFFGetField(tif, TIFFTAG_VERSIONYEAR, &u)) + { + memcpy(uu, u, 4); + uu[4] = '\0'; + printf(" Version year \"%s\"\n", uu); + } + if (TIFFGetField(tif, TIFFTAG_MODENUMBER, &parm8)) + printf(" Mode number %u\n", parm8); + } + TIFFSetDirectory(tif, (tdir_t) page); + } + + if (TIFFGetField(tif, TIFFTAG_PROFILETYPE, &parm32)) + printf("Profile type %u\n", parm32); + if (TIFFGetField(tif, TIFFTAG_FAXPROFILE, &parm8)) + printf("FAX profile %s (%u)\n", tiff_fx_fax_profiles[parm8], parm8); + if (TIFFGetField(tif, TIFFTAG_CODINGMETHODS, &parm32)) + printf("Coding methods 0x%x\n", parm32); + if (TIFFGetField(tif, TIFFTAG_VERSIONYEAR, &u)) + { + memcpy(uu, u, 4); + uu[4] = '\0'; + printf("Version year \"%s\"\n", uu); + } + if (TIFFGetField(tif, TIFFTAG_MODENUMBER, &parm8)) + printf("Mode number %u\n", parm8); + if (TIFFGetField(tif, TIFFTAG_T82OPTIONS, &parm32)) + printf("T.82 options 0x%x\n", parm32); +#endif + + map_L = NULL; + map_a = NULL; + map_b = NULL; + map_z = NULL; + if (TIFFGetField(tif, TIFFTAG_COLORMAP, &map_L, &map_a, &map_b, &map_z)) + { + entries = 1 << meta->bits_per_sample; + meta->colour_map = malloc(3*entries); + if (meta->colour_map) + { +#if 0 + /* Sweep the colormap in the proper order */ + for (i = 0; i < entries; i++) + { + meta->colour_map[3*i] = (map_L[i] >> 8) & 0xFF; + meta->colour_map[3*i + 1] = (map_a[i] >> 8) & 0xFF; + meta->colour_map[3*i + 2] = (map_b[i] >> 8) & 0xFF; + printf("Map %3d - %5d %5d %5d\n", i, meta->colour_map[3*i], meta->colour_map[3*i + 1], meta->colour_map[3*i + 2]); + } +#else + /* Sweep the colormap in the order that seems to work for l04x_02x.tif */ + for (i = 0; i < entries; i++) + { + meta->colour_map[i] = (map_L[i] >> 8) & 0xFF; + meta->colour_map[256 + i] = (map_a[i] >> 8) & 0xFF; + meta->colour_map[2*256 + i] = (map_b[i] >> 8) & 0xFF; + } +#endif + /* The default luminant is D50 */ + set_lab_illuminant(&lab_param, 96.422f, 100.000f, 82.521f); + set_lab_gamut(&lab, 0, 100, -85, 85, -75, 125, false); + lab_to_srgb(&lab, meta->colour_map, meta->colour_map, 256); + for (i = 0; i < entries; i++) + printf("Map %3d - %5d %5d %5d\n", i, meta->colour_map[3*i], meta->colour_map[3*i + 1], meta->colour_map[3*i + 2]); + } + } + meta->tif = tif; + return 0; +} +/*- End of function --------------------------------------------------------*/ + +int read_compressed_image(meta_t *meta, uint8_t **buf) +{ + int i; + int len; + int total_len; + int read_len; + int num_strips; + uint8_t *data; + + num_strips = TIFFNumberOfStrips(meta->tif); + for (i = 0, total_len = 0; i < num_strips; i++) + { + total_len += TIFFRawStripSize(meta->tif, i); + } + if ((data = malloc(total_len)) == NULL) + return -1; + for (i = 0, read_len = 0; i < num_strips; i++, read_len += len) + { + if ((len = TIFFReadRawStrip(meta->tif, i, &data[read_len], total_len - read_len)) < 0) + { + printf("TIFF read error.\n"); + return -1; + } + } + *buf = data; + return total_len; +} +/*- End of function --------------------------------------------------------*/ + +int read_decompressed_image(meta_t *meta, uint8_t **buf) +{ + int bytes_per_row; + int x; + int y; + int xx; + int yy; + int xxx; + int yyy; + int i; + int j; + int result; + int total_raw; + int total_data; + uint8_t *raw_buf; + uint8_t *image_buf; + t85_decode_state_t t85; + t43_decode_state_t t43; + packer_t pack; + logging_state_t *logging; + logging_state_t logging2; +#if 0 + uint8_t *jpeg_table; + uint32_t jpeg_table_len; + tsize_t off; + uint32_t w; + uint32_t h; +#endif + + image_buf = NULL; + total_data = 0; + switch (meta->compression) + { + case COMPRESSION_T85: + bytes_per_row = (meta->image_width + 7)/8; + total_data = meta->image_length*bytes_per_row; + printf("Total decompressed data %d, %d per row\n", total_data, bytes_per_row); + + /* Read the image into memory. */ + if ((image_buf = malloc(total_data)) == NULL) + { + printf("Failed to allocated image buffer\n"); + return -1; + } + total_raw = read_compressed_image(meta, &raw_buf); + t85_decode_init(&t85, row_write_handler, &pack); + t85_decode_set_comment_handler(&t85, 1000, t85_comment_handler, NULL); + logging = t85_decode_get_logging_state(&t85); + span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); + + pack.buf = image_buf; + pack.ptr = 0; + + result = t85_decode_put(&t85, raw_buf, total_raw); + if (result == T4_DECODE_MORE_DATA) + result = t85_decode_put(&t85, NULL, 0); + total_data = t85_decode_get_compressed_image_size(&t85); + printf("Compressed image is %d/%d bytes, %d rows\n", total_raw, total_data/8, write_row); + t85_decode_release(&t85); + free(raw_buf); + break; + case COMPRESSION_T43: + bytes_per_row = meta->samples_per_pixel*meta->image_width; + total_data = meta->image_length*bytes_per_row; + printf("Total decompressed data %d, %d per row\n", total_data, bytes_per_row); + +total_data *= 8; + /* Read the image into memory. */ + if ((image_buf = malloc(total_data)) == NULL) + printf("Failed to allocated image buffer\n"); + + total_raw = read_compressed_image(meta, &raw_buf); + t43_decode_init(&t43, row_write_handler, &pack); + t43_decode_set_comment_handler(&t43, 1000, t85_comment_handler, NULL); + logging = t43_decode_get_logging_state(&t43); + span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); + + pack.buf = image_buf; + pack.ptr = 0; + + result = t43_decode_put(&t43, raw_buf, total_raw); + if (result == T4_DECODE_MORE_DATA) + result = t43_decode_put(&t43, NULL, 0); + t43_decode_release(&t43); + free(raw_buf); + + meta->samples_per_pixel = 1; + meta->photometric = PHOTOMETRIC_RGB; + printf("Image %d x %d pixels\n", meta->image_width, meta->image_length); + break; + case COMPRESSION_JPEG: + if (meta->photometric == PHOTOMETRIC_ITULAB) + { + printf(" ITULAB"); + + span_log_init(&logging2, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW, "lab"); + bytes_per_row = TIFFScanlineSize(meta->tif); + total_data = meta->image_length*bytes_per_row; + printf("Total decompressed data %d, %d per row\n", total_data, bytes_per_row); + + /* Read the image into memory. */ + if ((image_buf = malloc(total_data)) == NULL) + printf("Failed to allocated image buffer\n"); + +#if 0 + jpeg_table_len = 0; + if (TIFFGetField(meta->tif, TIFFTAG_JPEGTABLES, &jpeg_table_len, &jpeg_table)) + { + total_image_len += (jpeg_table_len - 4); + printf("JPEG tables %u\n", jpeg_table_len); +{ +int ii; +printf("YYY1 %d - ", jpeg_table_len); +for (ii = 0; ii < jpeg_table_len; ii++) + printf(" %02x", jpeg_table[ii]); +printf("\n"); +} + } +#endif + total_raw = read_compressed_image(meta, &raw_buf); + //if (!t42_itulab_jpeg_to_srgb(&logging2, &lab_param, (tdata_t) image_buf, &off, raw_buf, total_raw, &w, &h, &samples_per_pixel)) + { + printf("Failed to convert from ITULAB.\n"); + return 1; + } + meta->photometric = PHOTOMETRIC_RGB; + +#if 0 + total_len = 0; + if (jpeg_table_len > 0) + total_len += jpeg_table_len - 4; + +printf("nstrips %d\n", nstrips); + data2 = NULL; + for (i = 0; i < nstrips; i++, total_len += len) + { + total_len = 0; + if (jpeg_table_len > 0) + total_len += jpeg_table_len - 4; + if ((len = TIFFReadRawStrip(tif, i, &data[total_len], total_image_len - total_len)) < 0) + { + printf("TIFF read error.\n"); + return -1; + } + if (jpeg_table_len > 0) + { + memcpy(data, jpeg_table, jpeg_table_len - 2); +printf("%02x %02x %02x %02x\n", data[total_len], data[total_len + 1], data[total_len + 2], data[total_len + 3]); + } + totdata = meta->image_width*3000*meta->samples_per_pixel; + data2 = realloc(data2, totdata); + off = total_len; + if (!t42_itulab_jpeg_to_srgb(&logging2, &lab_param, data2, &off, data, off, &w, &h, &samples_per_pixel)) + { + printf("Failed to convert from ITULAB.\n"); + return 1; + } + } + if (data2) + free(data2); + //exit(2); + if (jpeg_table_len > 0) + memcpy(data, jpeg_table, jpeg_table_len - 2); + + if (total_len != total_image_len) + printf("Size mismatch %d %d\n", (int) total_len, (int) total_image_len); +{ +int ii; + +printf("YYY2 %d - ", jpeg_table_len); +for (ii = 0; ii < 800; ii++) + printf(" %02x", data[ii]); +printf("\n"); +} + off = total_len; + len = total_len; +#endif + break; + } + /* Fall through */ + default: + if (meta->tile_width > 0) + { + /* The image is tiled, so we need to patch together a bunch of tiles */ + switch (meta->planar_config) + { + case PLANARCONFIG_CONTIG: + bytes_per_row = TIFFScanlineSize(meta->tif); + total_data = meta->image_length*bytes_per_row; + printf("Total decompressed data %d, %d per row\n", total_data, bytes_per_row); + + /* Read the image into memory. */ + if ((image_buf = malloc(total_data)) == NULL) + printf("Failed to allocated image buffer\n"); + + for (y = 0; y < meta->image_length; y += meta->tile_length) + { + for (x = 0; x < meta->image_width; x += meta->tile_width) + { + uint8_t data[meta->tile_width*meta->tile_length*meta->samples_per_pixel]; + + TIFFReadTile(meta->tif, data, x, y, 0, 0); + yyy = meta->tile_length; + if (y + meta->tile_length > meta->image_length) + yyy = meta->image_length - y; + xxx = meta->tile_width; + if (x + meta->tile_width > meta->image_width) + xxx = meta->image_width - x; + for (yy = 0; yy < yyy; yy++) + { + for (xx = 0; xx < xxx; xx++) + { + for (j = 0; j < meta->samples_per_pixel; j++) + image_buf[meta->samples_per_pixel*((y + yy)*meta->image_width + x + xx) + j] = data[meta->samples_per_pixel*(yy*meta->tile_width + xx) + j]; + } + } + } + } + break; + case PLANARCONFIG_SEPARATE: + bytes_per_row = TIFFScanlineSize(meta->tif); + total_data = meta->samples_per_pixel*meta->image_length*bytes_per_row; + printf("Total decompressed data %d, %d per row\n", total_data, bytes_per_row); + + /* Read the image into memory. */ + if ((image_buf = malloc(total_data)) == NULL) + printf("Failed to allocated image buffer\n"); + + for (j = 0; j < meta->samples_per_pixel; j++) + { + for (y = 0; y < meta->image_length; y += meta->tile_length) + { + for (x = 0; x < meta->image_width; x += meta->tile_width) + { + uint8_t data[meta->tile_width*meta->tile_length*meta->samples_per_pixel]; + + TIFFReadTile(meta->tif, data, x, y, 0, j); + yyy = meta->tile_length; + if (y + meta->tile_length > meta->image_length) + yyy = meta->image_length - y; + xxx = meta->tile_width; + if (x + meta->tile_width > meta->image_width) + xxx = meta->image_width - x; + for (yy = 0; yy < yyy; yy++) + { + for (xx = 0; xx < xxx; xx++) + { + image_buf[meta->samples_per_pixel*((y + yy)*meta->image_width + x + xx) + j] = data[yy*meta->tile_width + xx]; + } + } + } + } + } + break; + } + } + else + { + /* There is no tiling to worry about, but we might have planar issues to resolve */ + switch (meta->planar_config) + { + case PLANARCONFIG_CONTIG: + bytes_per_row = TIFFScanlineSize(meta->tif); + total_data = meta->image_length*bytes_per_row; + printf("Total decompressed data %d, %d per row\n", total_data, bytes_per_row); + + /* Read the image into memory. */ + if ((image_buf = malloc(total_data)) == NULL) + printf("Failed to allocated image buffer\n"); + + for (y = 0; y < meta->image_length; y++) + { + if (TIFFReadScanline(meta->tif, &image_buf[y*bytes_per_row], y, 0) < 0) + return 1; + } + break; + case PLANARCONFIG_SEPARATE: + bytes_per_row = TIFFScanlineSize(meta->tif); + total_data = meta->samples_per_pixel*meta->image_length*bytes_per_row; + printf("Total decompressed data %d, %d per row\n", total_data, bytes_per_row); + + /* Read the image into memory. */ + if ((image_buf = malloc(total_data)) == NULL) + printf("Failed to allocated image buffer\n"); + + for (j = 0; j < meta->samples_per_pixel; j++) + { + uint8_t data[bytes_per_row]; + + for (y = 0; y < meta->image_length; y++) + { + if (TIFFReadScanline(meta->tif, data, y, j) < 0) + return 1; + for (x = 0; x < meta->image_width; x++) + image_buf[meta->samples_per_pixel*(y*bytes_per_row + x) + j] = data[x]; + } + } + break; + } + } + break; + } + /* Normalise bi-level images, so they are always in PHOTOMETRIC_MINISWHITE form */ + if (image_buf && meta->samples_per_pixel == 1 && meta->bits_per_sample == 1) + { + if (meta->photometric != PHOTOMETRIC_MINISWHITE) + { + for (i = 0; i < total_data; i++) + image_buf[i] = ~image_buf[i]; + meta->photometric = PHOTOMETRIC_MINISWHITE; + } + } + + *buf = image_buf; + return total_data; +} +/*- End of function --------------------------------------------------------*/ + +int main(int argc, char *argv[]) +{ + const char *source_file; + const char *destination_file; + TIFF *tif; + tstrip_t nstrips; + uint32_t totdata; + tsize_t off; + uint8_t *data; + uint8_t *data2; + int row; + int bytes_per_row; + tsize_t outsize; + char *outptr; + int i; + int k; + int x; + int y; + uint64_t start; + uint64_t end; + logging_state_t logging2; + meta_t in_meta; + meta_t meta; + int output_compression; + int page_no; +#if defined(SPANDSP_SUPPORT_TIFF_FX) + uint64_t offset; +#endif + + source_file = (argc > 1) ? argv[1] : IN_FILE_NAME; + printf("Processing '%s'\n", source_file); + destination_file = OUT_FILE_NAME; + output_compression = (argc > 2) ? atoi(argv[2]) : COMPRESSION_CCITT_T6; + +#if defined(SPANDSP_SUPPORT_TIFF_FX) + TIFF_FX_init(); +#endif + + if ((in_meta.tif = TIFFOpen(source_file, "r")) == NULL) + { + printf("Unable to open '%s'!\n", source_file); + return 1; + } + + if ((meta.tif = TIFFOpen(destination_file, "w")) == NULL) + { + printf("Unable to open '%s'!\n", destination_file); + return 1; + } + span_log_init(&logging2, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW, "lab"); + + /* The default luminant is D50 */ + set_lab_illuminant(&lab_param, 96.422f, 100.000f, 82.521f); + set_lab_gamut(&lab_param, 0, 100, -85, 85, -75, 125, false); + + outptr = NULL; + for (page_no = 0; ; page_no++) + { + if (read_file(&in_meta, page_no) < 0) + { + printf("Failed to read from %s\n", source_file); + TIFFClose(in_meta.tif); + TIFFClose(meta.tif); + exit(2); + } + + tif = in_meta.tif; + + nstrips = TIFFNumberOfStrips(tif); + if (in_meta.compression == output_compression && nstrips == 1 && in_meta.tile_width == 0) + { + /* There might be no need to re-compress the image */ + } + else + { + /* It looks like we need to decompress and recompress the image */ + } + + printf("Width %d, height %d, bits %d, samples %d\n", in_meta.image_width, in_meta.image_length, in_meta.bits_per_sample, in_meta.samples_per_pixel); + + totdata = read_decompressed_image(&in_meta, &data); + off = totdata; + + bytes_per_row = TIFFScanlineSize(tif); + + printf("bits_per_sample %d, samples_per_pixel %d, w %d, h %d\n", in_meta.bits_per_sample, in_meta.samples_per_pixel, in_meta.image_width, in_meta.image_length); + + + printf("total %d, off %d\n", totdata, (int) off); + + switch (in_meta.samples_per_pixel) + { + case 1: + if (in_meta.bits_per_sample == 1) + { + printf("Bi-level\n"); + + /* We have finished acquiring the image. Now we need to push it out */ + meta.pre_compressed = false; + meta.image_width = in_meta.image_width; + meta.image_length = in_meta.image_length; + meta.x_resolution = in_meta.x_resolution; + meta.y_resolution = in_meta.y_resolution; + meta.resolution_unit = in_meta.resolution_unit; + meta.bits_per_sample = in_meta.bits_per_sample; + meta.samples_per_pixel = in_meta.samples_per_pixel; + meta.compression = COMPRESSION_CCITT_T6; + meta.photometric = PHOTOMETRIC_MINISWHITE; + + write_file(&meta, page_no, data); + } + else + { + printf("Gray scale, %d bits\n", in_meta.bits_per_sample); + if (in_meta.bits_per_sample == 8) + { + /* Nothing needs to be done */ + } + else if (in_meta.bits_per_sample == 16) + { + if ((outptr = malloc(in_meta.image_width*in_meta.image_length)) == NULL) + printf("Failed to allocate buffer\n"); + for (i = 0; i < in_meta.image_width*in_meta.image_length; i++) + outptr[i] = data[2*i]; + free(data); + data = (uint8_t *) outptr; + } + else + { + uint32_t bitstream; + int bits; + int j; + + /* Deal with the messy cases where the number of bits is not a whole + number of bytes. */ + if ((outptr = malloc(in_meta.image_width*in_meta.image_length)) == NULL) + printf("Failed to allocate buffer\n"); + bitstream = 0; + bits = 0; + j = 0; + for (i = 0; i < in_meta.image_width*in_meta.image_length; i++) + { + while (bits < in_meta.bits_per_sample) + { + bitstream = (bitstream << 8) | data[j++]; + bits += 8; + } + outptr[i] = bitstream >> (bits - 8); + bits -= in_meta.bits_per_sample; + } + free(data); + data = (uint8_t *) outptr; + } + off = in_meta.samples_per_pixel*in_meta.image_width*in_meta.image_length; + + /* We have finished acquiring the image. Now we need to push it out */ + meta.pre_compressed = false; + meta.image_width = in_meta.image_width; + meta.image_length = in_meta.image_length; + meta.x_resolution = in_meta.x_resolution; + meta.y_resolution = in_meta.y_resolution; + meta.resolution_unit = in_meta.resolution_unit; + meta.bits_per_sample = 8; + meta.samples_per_pixel = in_meta.samples_per_pixel; + meta.compression = COMPRESSION_JPEG; + meta.photometric = PHOTOMETRIC_MINISBLACK; + + write_file(&meta, page_no, data); + } + break; + case 3: + printf("Photometric is %d\n", in_meta.photometric); + + /* We now have the image in memory in RGB form */ + + if (in_meta.photometric == PHOTOMETRIC_ITULAB) + { + printf("ITU Lab\n"); + /* We are already in the ITULAB color space */ + if ((outptr = malloc(totdata)) == NULL) + printf("Failed to allocate buffer\n"); + lab_to_srgb(&lab_param, (tdata_t) outptr, data, totdata/3); + free(data); + data = (uint8_t *) outptr; + + meta.pre_compressed = false; + meta.image_width = in_meta.image_width; + meta.image_length = in_meta.image_length; + meta.x_resolution = in_meta.x_resolution; + meta.y_resolution = in_meta.y_resolution; + meta.resolution_unit = in_meta.resolution_unit; + meta.bits_per_sample = 8; + meta.samples_per_pixel = in_meta.samples_per_pixel; + meta.compression = COMPRESSION_JPEG; + meta.photometric = PHOTOMETRIC_RGB; + } + else + { +#if 1 + start = rdtscll(); + switch (in_meta.photometric) + { + case PHOTOMETRIC_CIELAB: + printf("CIELAB\n"); + /* Convert this to sRGB first */ + /* The default luminant is D50 */ + set_lab_illuminant(&lab_param, 96.422f, 100.000f, 82.521f); + set_lab_gamut(&lab_param, 0, 100, -128, 127, -128, 127, true); + lab_to_srgb(&lab_param, data, data, in_meta.image_width*in_meta.image_length); + break; + case PHOTOMETRIC_RGB: + printf("RGB\n"); + if (in_meta.bits_per_sample == 8) + { + } + else if (in_meta.bits_per_sample == 16) + { + printf("Pack %d to %d\n", totdata, in_meta.samples_per_pixel*in_meta.image_width*in_meta.image_length); + if ((outptr = malloc(in_meta.samples_per_pixel*in_meta.image_width*in_meta.image_length)) == NULL) + printf("Failed to allocate buffer\n"); + for (i = 0; i < in_meta.image_width*in_meta.image_length; i++) + { + outptr[in_meta.samples_per_pixel*i + 0] = (data[in_meta.samples_per_pixel*2*i + 1] << 4) | (data[in_meta.samples_per_pixel*2*i + 0] >> 4); + outptr[in_meta.samples_per_pixel*i + 1] = (data[in_meta.samples_per_pixel*2*i + 3] << 4) | (data[in_meta.samples_per_pixel*2*i + 2] >> 4); + outptr[in_meta.samples_per_pixel*i + 2] = (data[in_meta.samples_per_pixel*2*i + 5] << 4) | (data[in_meta.samples_per_pixel*2*i + 4] >> 4); + } + free(data); + data = (uint8_t *) outptr; + off = in_meta.samples_per_pixel*in_meta.image_width*in_meta.image_length; + in_meta.bits_per_sample = 8; + } + else + { + uint32_t bitstream; + int bits; + int j; + + /* Deal with the messy cases where the number of bits is not a whole number of bytes. */ + printf("Pack %d to %d\n", totdata, in_meta.samples_per_pixel*in_meta.image_width*in_meta.image_length); + if ((outptr = malloc(in_meta.samples_per_pixel*in_meta.image_width*in_meta.image_length)) == NULL) + printf("Failed to allocate buffer\n"); + bitstream = 0; + bits = 0; + j = 0; + for (i = 0; i < in_meta.image_width*in_meta.image_length; i++) + { + for (k = 0; k < in_meta.samples_per_pixel; k++) + { + while (bits < in_meta.bits_per_sample) + { + bitstream = (bitstream << 8) | data[j++]; + bits += 8; + } + outptr[in_meta.samples_per_pixel*i + k] = bitstream >> (bits - 8); + bits -= in_meta.bits_per_sample; + } + } + free(data); + data = (uint8_t *) outptr; + off = in_meta.samples_per_pixel*in_meta.image_width*in_meta.image_length; + in_meta.bits_per_sample = 8; + } + break; + } +#if 0 + /* The default luminant is D50 */ + set_lab_illuminant(&lab_param, 96.422f, 100.000f, 82.521f); + set_lab_gamut(&lab_param, 0, 100, -85, 85, -75, 125, false); + if (!t42_srgb_to_itulab_jpeg(&logging2, &lab_param, (tdata_t) &outptr, &outsize, data, off, in_meta.image_width, in_meta.image_length, 3)) + { + printf("Failed to convert to ITULAB (B).\n"); + return 1; + } + end = rdtscll(); + printf("Duration %" PRIu64 "\n", end - start); + free(data); + data = (uint8_t *) outptr; + off = outsize; +#endif +#endif + meta.pre_compressed = false; + meta.image_width = in_meta.image_width; + meta.image_length = in_meta.image_length; + meta.x_resolution = in_meta.x_resolution; + meta.y_resolution = in_meta.y_resolution; + meta.resolution_unit = in_meta.resolution_unit; + meta.bits_per_sample = 8; + meta.samples_per_pixel = in_meta.samples_per_pixel; + meta.compression = COMPRESSION_JPEG; + meta.photometric = PHOTOMETRIC_RGB; + } + write_file(&meta, page_no, data); + break; + case 4: + printf("Photometric is %d\n", in_meta.photometric); + + /* We now have the image in memory in RGB form */ + + if (in_meta.photometric == PHOTOMETRIC_ITULAB) + { + /* We are already in the ITULAB color space */ +#if 0 + if (!t42_itulab_to_itulab(&logging2, (tdata_t) &outptr, &outsize, data, off, in_meta.image_width, in_meta.image_length, 3)) + { + printf("Failed to convert to ITULAB (C).\n"); + return 1; + } +#endif + free(data); + data = (uint8_t *) outptr; + off = outsize; + } + else + { + start = rdtscll(); + switch (in_meta.photometric) + { + case PHOTOMETRIC_CIELAB: + printf("CIELAB\n"); + /* TODO: This doesn't work yet */ + /* Convert this to sRGB first */ + /* The default luminant is D50 */ + set_lab_illuminant(&lab_param, 96.422f, 100.000f, 82.521f); + set_lab_gamut(&lab_param, 0, 100, -128, 127, -128, 127, true); + lab_to_srgb(&lab_param, data, data, in_meta.image_width*in_meta.image_length); + break; + case PHOTOMETRIC_SEPARATED: + for (y = 0; y < in_meta.image_length; y++) + { + for (x = 0; x < in_meta.image_width; x++) + { + k = data[(y*in_meta.image_width + x)*4 + 0] + data[(y*in_meta.image_width + x)*4 + 3]; + if (k > 255) + k = 255; + data[(y*in_meta.image_width + x)*3 + 0] = 255 - k; + k = data[(y*in_meta.image_width + x)*4 + 1] + data[(y*in_meta.image_width + x)*4 + 3]; + if (k > 255) + k = 255; + data[(y*in_meta.image_width + x)*3 + 1] = 255 - k; + k = data[(y*in_meta.image_width + x)*4 + 2] + data[(y*in_meta.image_width + x)*4 + 3]; + if (k > 255) + k = 255; + data[(y*in_meta.image_width + x)*3 + 2] = 255 - k; + } + } + off = 3*in_meta.image_width*in_meta.image_length; + in_meta.bits_per_sample = 8; + break; + } + + /* The default luminant is D50 */ + set_lab_illuminant(&lab_param, 96.422f, 100.000f, 82.521f); + set_lab_gamut(&lab_param, 0, 100, -85, 85, -75, 125, false); + //if (!t42_srgb_to_itulab_jpeg(&logging2, &lab_param, (tdata_t) &outptr, &outsize, data, off, in_meta.image_width, in_meta.image_length, 3)) + { + printf("Failed to convert to ITULAB (D).\n"); + return 1; + } + end = rdtscll(); + printf("Duration %" PRIu64 "\n", end - start); + off = outsize; + in_meta.bits_per_sample = 8; + } + meta.pre_compressed = false; + meta.image_width = in_meta.image_width; + meta.image_length = in_meta.image_length; + meta.x_resolution = in_meta.x_resolution; + meta.y_resolution = in_meta.y_resolution; + meta.resolution_unit = in_meta.resolution_unit; + meta.bits_per_sample = 8; + meta.samples_per_pixel = 3; + meta.compression = COMPRESSION_JPEG; + meta.photometric = PHOTOMETRIC_RGB; + + write_file(&meta, page_no, data); + break; + } + } + + + + printf("XXX - image is %d by %d, %d bytes\n", in_meta.image_width, in_meta.image_length, (int) off); + + /* We now have the image in memory in ITULAB form */ + + meta.pre_compressed = false; + meta.compressed_image_len = off; + meta.image_width = in_meta.image_width; + meta.image_length = in_meta.image_length; + meta.x_resolution = in_meta.x_resolution; + meta.y_resolution = in_meta.y_resolution; + meta.resolution_unit = in_meta.resolution_unit; + meta.bits_per_sample = 8; + meta.samples_per_pixel = 3; + meta.compression = COMPRESSION_JPEG; +#if 1 + meta.photometric = PHOTOMETRIC_RGB; +#elif 1 + /* Most image processors won't know what to do with the ITULAB colorspace. + So we'll be converting it to RGB for portability. */ + /* If PHOTOMETRIC_ITULAB is not available the admin cannot enable color fax anyway. + This is done so that older libtiffs without it can build fine. */ + meta.photometric = PHOTOMETRIC_ITULAB; +#else + meta.photometric = PHOTOMETRIC_YCBCR; +#endif + meta.YCbCrSubsampleHoriz = in_meta.YCbCrSubsampleHoriz; + meta.YCbCrSubsampleVert = in_meta.YCbCrSubsampleVert; + + if ((tif = TIFFOpen(destination_file, "w")) == NULL) + { + printf("Unable to open '%s'!\n", destination_file); + return 1; + } + TIFFSetField(tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE); + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, meta.image_width); + /* libtiff requires IMAGELENGTH to be set before SAMPLESPERPIXEL, + or StripOffsets and StripByteCounts will have SAMPLESPERPIXEL values */ + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, meta.image_length); + TIFFSetField(tif, TIFFTAG_COMPRESSION, meta.compression); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, meta.bits_per_sample); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, meta.samples_per_pixel); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, meta.image_length); + TIFFSetField(tif, TIFFTAG_XRESOLUTION, meta.x_resolution); + TIFFSetField(tif, TIFFTAG_YRESOLUTION, meta.y_resolution); + TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, meta.resolution_unit); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, meta.photometric); + if (meta.samples_per_pixel > 1 && (meta.YCbCrSubsampleHoriz || meta.YCbCrSubsampleVert)) + TIFFSetField(tif, TIFFTAG_YCBCRSUBSAMPLING, meta.YCbCrSubsampleHoriz, meta.YCbCrSubsampleVert); + TIFFSetField(tif, TIFFTAG_SOFTWARE, "spandsp"); + TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, "Test"); + TIFFSetField(tif, TIFFTAG_DATETIME, "2011/02/03 12:30:45"); + TIFFSetField(tif, TIFFTAG_MAKE, "soft-switch.org"); + TIFFSetField(tif, TIFFTAG_MODEL, "spandsp"); + TIFFSetField(tif, TIFFTAG_HOSTCOMPUTER, "i7.coppice.org"); +#if defined(SPANDSP_SUPPORT_TIFF_FX) + /* Make space for this to be filled in later */ + TIFFSetField(tif, TIFFTAG_GLOBALPARAMETERSIFD, 0); +#endif + + if (meta.pre_compressed) + { + if (TIFFWriteRawStrip(tif, 0, (tdata_t) data, meta.compressed_image_len) == -1) + { + printf("Write error to TIFF file\n"); + return 1; + } + free(data); + } + else + { + if (in_meta.samples_per_pixel > 1) + { + bytes_per_row = ((meta.bits_per_sample + 7)/8)*meta.image_width*meta.samples_per_pixel; + totdata = meta.image_length*bytes_per_row; + /* The default luminant is D50 */ + set_lab_illuminant(&lab_param, 96.422f, 100.000f, 82.521f); + set_lab_gamut(&lab_param, 0, 100, -85, 85, -75, 125, false); +#if 0 + start = rdtscll(); + data2 = NULL; + totdata = 0; + if (!t42_itulab_to_JPEG(&logging2, &lab_param, (void **) &data2, &totdata, data, off)) + { + printf("Failed to convert from ITULAB (A).\n"); + return 1; + } + end = rdtscll(); + printf("Duration %" PRIu64 "\n", end - start); + printf("Compressed length %d (%p)\n", totdata, data2); + if (TIFFWriteRawStrip(tif, 0, data2, totdata) < 0) + { + printf("Failed to convert from ITULAB (B).\n"); + return 1; + } + free(data); + data = data2; +#elif 1 + data2 = malloc(totdata); + start = rdtscll(); + //if (!t42_itulab_jpeg_to_srgb(&logging2, &lab_param, data2, &off, data, off, &meta.image_width, &meta.image_length, &meta.samples_per_pixel)) + { + printf("Failed to convert from ITULAB.\n"); + return 1; + } + end = rdtscll(); + printf("Duration %" PRIu64 "\n", end - start); + free(data); + data = data2; +#endif + } + off = 0; + bytes_per_row = ((meta.bits_per_sample + 7)/8)*meta.image_width*meta.samples_per_pixel; + for (row = 0; row < meta.image_length; row++) + { + if (TIFFWriteScanline(tif, &data[off], row, 0) < 0) + return 1; + off += bytes_per_row; + } + free(data); + } + + if (!TIFFWriteDirectory(tif)) + printf("Failed to write directory.\n"); + +#if defined(SPANDSP_SUPPORT_TIFF_FX) + if (!TIFFCreateCustomDirectory(tif, &tiff_fx_field_array)) + { + TIFFSetField(tif, TIFFTAG_PROFILETYPE, PROFILETYPE_G3_FAX); + TIFFSetField(tif, TIFFTAG_FAXPROFILE, FAXPROFILE_F); + TIFFSetField(tif, TIFFTAG_CODINGMETHODS, CODINGMETHODS_T4_1D | CODINGMETHODS_T4_2D | CODINGMETHODS_T6); + TIFFSetField(tif, TIFFTAG_VERSIONYEAR, "1998"); + TIFFSetField(tif, TIFFTAG_MODENUMBER, 3); + + offset = 0; + if (!TIFFWriteCustomDirectory(tif, &offset)) + printf("Failed to write custom directory.\n"); + + if (!TIFFSetDirectory(tif, (tdir_t) page_no)) + printf("Failed to set directory.\n"); + if (!TIFFSetField(tif, TIFFTAG_GLOBALPARAMETERSIFD, offset)) + printf("Failed to set global parameters IFD.\n"); + if (!TIFFWriteDirectory(tif)) + printf("Failed to write directory.\n"); + } +#endif + TIFFClose(tif); + printf("Done!\n"); + return 0; +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/spandsp/tests/t4_t6_tests.c b/libs/spandsp/tests/t4_t6_tests.c index 418e24b655..0e583ab059 100644 --- a/libs/spandsp/tests/t4_t6_tests.c +++ b/libs/spandsp/tests/t4_t6_tests.c @@ -205,8 +205,8 @@ static int detect_page_end(int bit, int page_ended) end_marks = 0; eol_zeros = 11; - eol_ones = (page_ended == T4_COMPRESSION_ITU_T4_2D) ? 2 : 1; - expected_eols = (page_ended == T4_COMPRESSION_ITU_T6) ? 2 : 6; + eol_ones = (page_ended == T4_COMPRESSION_T4_2D) ? 2 : 1; + expected_eols = (page_ended == T4_COMPRESSION_T6) ? 2 : 6; return 0; } @@ -266,9 +266,9 @@ int main(int argc, char *argv[]) { static const int compression_sequence[] = { - T4_COMPRESSION_ITU_T4_1D, - T4_COMPRESSION_ITU_T4_2D, - T4_COMPRESSION_ITU_T6, + T4_COMPRESSION_T4_1D, + T4_COMPRESSION_T4_2D, + T4_COMPRESSION_T6, -1 }; int bit; @@ -303,17 +303,17 @@ int main(int argc, char *argv[]) case 'c': if (strcmp(optarg, "T41D") == 0) { - compression = T4_COMPRESSION_ITU_T4_1D; + compression = T4_COMPRESSION_T4_1D; compression_step = -1; } else if (strcmp(optarg, "T42D") == 0) { - compression = T4_COMPRESSION_ITU_T4_2D; + compression = T4_COMPRESSION_T4_2D; compression_step = -1; } else if (strcmp(optarg, "T6") == 0) { - compression = T4_COMPRESSION_ITU_T6; + compression = T4_COMPRESSION_T6; compression_step = -1; } break; @@ -327,11 +327,11 @@ int main(int argc, char *argv[]) } } - end_of_page = FALSE; + end_of_page = false; #if 1 printf("Testing image_function->compress->decompress->image_function\n"); /* Send end gets image from a function */ - if ((send_state = t4_t6_encode_init(NULL, compression, 1728, row_read_handler, NULL)) == NULL) + if ((send_state = t4_t6_encode_init(NULL, compression, 1728, -1, row_read_handler, NULL)) == NULL) { printf("Failed to init T.4/T.6 encoder\n"); exit(2); @@ -364,7 +364,7 @@ int main(int argc, char *argv[]) t4_t6_encode_set_encoding(send_state, compression); t4_t6_decode_set_encoding(receive_state, compression); - if (t4_t6_encode_restart(send_state, 1728)) + if (t4_t6_encode_restart(send_state, 1728, -1)) break; if (t4_t6_decode_restart(receive_state, 1728)) break; @@ -372,7 +372,7 @@ int main(int argc, char *argv[]) switch (block_size) { case 0: - end_of_page = FALSE; + end_of_page = false; for (;;) { bit = t4_t6_encode_get_bit(send_state); diff --git a/libs/spandsp/tests/t4_tests.c b/libs/spandsp/tests/t4_tests.c index afded4ec2b..98a57cfe54 100644 --- a/libs/spandsp/tests/t4_tests.c +++ b/libs/spandsp/tests/t4_tests.c @@ -53,48 +53,6 @@ in ITU specifications T.4 and T.6. t4_tx_state_t *send_state; t4_rx_state_t *receive_state; -/* The following are some test cases from T.4 */ -#define FILL_70 " " -#define FILL_80 " " -#define FILL_100 " " -#define FILL_670 FILL_100 FILL_100 FILL_100 FILL_100 FILL_100 FILL_100 FILL_70 -#define FILL_980 FILL_100 FILL_100 FILL_100 FILL_100 FILL_100 FILL_100 FILL_100 FILL_100 FILL_100 FILL_80 - -static const char t4_t6_test_patterns[][1728 + 1] = -{ - "XXXXXX " FILL_980 " XXX XXX X " FILL_670 " XXXX", - "XXXXXX " FILL_980 " XXX X " FILL_670 " XXXX", - /* Line start should code to V(0). Line middle codes to VR(3) VL(2) V(0). Line end should code to V(0) V(0). */ - - " XXXX " FILL_980 " XXXXXXX " FILL_670 " XX ", - "XXXXX " FILL_980 "XX XX " FILL_670 " XXXX", - /* Line start should code to VL(1). Line middle codes to H(7,2). Line end should code to V(0) VR(2) */ - - "XXX " FILL_980 " XX XX XX XXX " FILL_670 " X ", - " " FILL_980 " X XXX XXXX " FILL_670 " X XX", - /* Line start should code to P. Line middle codes to P VL(1) V(0) H(3,4) P. Line end codes to V(0) VL(2) V(0). */ - - "XXXXX " FILL_980 " " FILL_670 " XXXX", - " XXX " FILL_980 " " FILL_670 " XX ", - /* Line start should code to VR(2). Line end codes to V(0) VL(2) V(0). */ - - " XX " FILL_980 " " FILL_670 " X XXX", - "XXX X " FILL_980 " " FILL_670 " X ", - /* Line start should code to H(0,3) VR(1). Line end codes to V(0) VR(3). */ - - " " FILL_980 " " FILL_670 " XX ", - " " FILL_980 " " FILL_670 " ", - /* Line end codes to P V(0) a'0. */ - - " " FILL_980 " " FILL_670 " XXXXXXXXXX", - " " FILL_980 " " FILL_670 " XXXXXX XXXXXX", - /* Line end codes to H(2,6). */ - - " " FILL_980 " " FILL_670 " XX XXXXX", - " " FILL_980 " " FILL_670 " XX ", - /* Line end codes to V(0) H(7,0). */ -}; - int rows_written = 0; int rows_read = 0; @@ -128,7 +86,7 @@ static void display_page_stats(t4_rx_state_t *s) t4_rx_get_transfer_statistics(s, &stats); printf("Pages = %d\n", stats.pages_transferred); - printf("Compression = %s\n", t4_encoding_to_str(stats.encoding)); + printf("Compression = %s\n", t4_compression_to_str(stats.compression)); printf("Compressed size = %d\n", stats.line_image_size); printf("Raw image size = %d pels x %d pels\n", stats.image_width, stats.image_length); printf("Image size = %d pels x %d pels\n", stats.width, stats.length); @@ -140,63 +98,7 @@ static void display_page_stats(t4_rx_state_t *s) } /*- End of function --------------------------------------------------------*/ -static int row_read_handler(void *user_data, uint8_t buf[], size_t len) -{ - int i; - int j; - const char *s; - - /* Send the test pattern. */ - if (rows_read >= 16) - return 0; - s = t4_t6_test_patterns[rows_read++]; - memset(buf, 0, len); - for (i = 0; i < len; i++) - { - for (j = 0; j < 8; j++) - { - if (*s++ != ' ') - buf[i] |= (0x80 >> j); - } - } - if (*s) - printf("Oops - '%c' at end of row %d\n", *s, rows_read); - return len; -} -/*- End of function --------------------------------------------------------*/ - -static int row_write_handler(void *user_data, const uint8_t buf[], size_t len) -{ - int i; - int j; - const char *s; - uint8_t ref[8192]; - - /* Verify that what is received matches the test pattern. */ - if (len == 0) - return 0; - s = t4_t6_test_patterns[rows_written++]; - memset(ref, 0, len); - for (i = 0; i < len; i++) - { - for (j = 0; j < 8; j++) - { - if (*s++ != ' ') - ref[i] |= (0x80 >> j); - } - } - if (*s) - printf("Oops - '%c' at end of row %d\n", *s, rows_written); - if (memcmp(buf, ref, len)) - { - printf("Test failed at row %d\n", rows_written); - exit(2); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int detect_page_end(int bit, int page_ended) +static int detect_non_ecm_page_end(int bit, int page_ended) { static int consecutive_eols; static int max_consecutive_eols; @@ -207,10 +109,10 @@ static int detect_page_end(int bit, int page_ended) static int expected_eols; static int end_marks; - /* Check the EOLs are added properly to the end of an image. We can't rely on the - decoder giving the right answer, as a full set of EOLs is not needed for the - decoder to work. */ - if (bit == -1000000) + /* Check the EOLs are added properly to the end of a non-ECM image. We can't rely + on the decoder giving the right answer, as a full set of EOLs is not needed for + the decoder to work. */ + if (bit == -1) { /* Reset */ consecutive_eols = 0; @@ -220,8 +122,8 @@ static int detect_page_end(int bit, int page_ended) end_marks = 0; eol_zeros = 11; - eol_ones = (page_ended == T4_COMPRESSION_ITU_T4_2D) ? 2 : 1; - expected_eols = (page_ended == T4_COMPRESSION_ITU_T6) ? 2 : 6; + eol_ones = (page_ended == T4_COMPRESSION_T4_2D) ? 2 : 1; + expected_eols = (page_ended == T4_COMPRESSION_T6) ? 2 : 6; return 0; } @@ -282,19 +184,24 @@ int main(int argc, char *argv[]) static const int compression_sequence[] = { //T4_COMPRESSION_NONE, - T4_COMPRESSION_ITU_T4_1D, - T4_COMPRESSION_ITU_T4_2D, - T4_COMPRESSION_ITU_T6, + T4_COMPRESSION_T4_1D, + T4_COMPRESSION_T4_2D, + T4_COMPRESSION_T6, + T4_COMPRESSION_T85, + T4_COMPRESSION_T85_L0, +#if defined(SPANDSP_SUPPORT_T88x) + T4_COMPRESSION_T88, +#endif #if defined(SPANDSP_SUPPORT_T42x) - T4_COMPRESSION_ITU_T42, - T4_COMPRESSION_ITU_SYCC_T42, + T4_COMPRESSION_T42_T81, + T4_COMPRESSION_SYCC_T81, #endif #if defined(SPANDSP_SUPPORT_T43x) - T4_COMPRESSION_ITU_T43, + T4_COMPRESSION_T43, +#endif +#if defined(SPANDSP_SUPPORT_T45x) + T4_COMPRESSION_T45, #endif - T4_COMPRESSION_ITU_T85, - T4_COMPRESSION_ITU_T85_L0, - //T4_COMPRESSION_ITU_T45, -1 }; int sends; @@ -304,10 +211,7 @@ int main(int argc, char *argv[]) int res; int compression; int compression_step; - int add_page_headers; - int overlay_page_headers; int min_row_bits; - int restart_pages; int block_size; char buf[1024]; uint8_t block[1024]; @@ -319,8 +223,11 @@ int main(int argc, char *argv[]) int len; int i; int bit_error_rate; - int dump_as_xxx; int tests_failed; + bool restart_pages; + bool add_page_headers; + bool overlay_page_headers; + bool dump_as_xxx; unsigned int last_pkt_no; unsigned int pkt_no; int page_ended; @@ -329,9 +236,9 @@ int main(int argc, char *argv[]) tests_failed = 0; compression = -1; compression_step = 0; - add_page_headers = FALSE; - overlay_page_headers = FALSE; - restart_pages = FALSE; + add_page_headers = false; + overlay_page_headers = false; + restart_pages = false; in_file_name = IN_FILE_NAME; decode_file_name = NULL; page_header_tz = NULL; @@ -340,7 +247,7 @@ int main(int argc, char *argv[]) min_row_bits = 50; block_size = 1; bit_error_rate = 0; - dump_as_xxx = FALSE; + dump_as_xxx = false; while ((opt = getopt(argc, argv, "b:c:d:ehHri:m:t:x")) != -1) { switch (opt) @@ -348,43 +255,61 @@ int main(int argc, char *argv[]) case 'b': block_size = atoi(optarg); if (block_size > 1024) - block_size = 1024; + { + printf("Block size too large. Must be 1024 or less\n"); + exit(2); + } break; case 'c': if (strcmp(optarg, "T41D") == 0) { - compression = T4_COMPRESSION_ITU_T4_1D; + compression = T4_COMPRESSION_T4_1D; compression_step = -1; } else if (strcmp(optarg, "T42D") == 0) { - compression = T4_COMPRESSION_ITU_T4_2D; + compression = T4_COMPRESSION_T4_2D; compression_step = -1; } else if (strcmp(optarg, "T6") == 0) { - compression = T4_COMPRESSION_ITU_T6; + compression = T4_COMPRESSION_T6; compression_step = -1; } -#if defined(SPANDSP_SUPPORT_T42) - else if (strcmp(optarg, "T42") == 0) - { - compression = T4_COMPRESSION_ITU_T42; - compression_step = -1; - } -#endif -#if defined(SPANDSP_SUPPORT_T43) - else if (strcmp(optarg, "T43") == 0) - { - compression = T4_COMPRESSION_ITU_T43; - compression_step = -1; - } -#endif else if (strcmp(optarg, "T85") == 0) { - compression = T4_COMPRESSION_ITU_T85; + compression = T4_COMPRESSION_T85; compression_step = -1; } +#if defined(SPANDSP_SUPPORT_T88) + else if (strcmp(optarg, "T88") == 0) + { + compression = T4_COMPRESSION_T88; + compression_step = -1; + } +#endif + else if (strcmp(optarg, "T81") == 0) + { + compression = T4_COMPRESSION_T42_T81; + compression_step = -1; + } + else if (strcmp(optarg, "T43") == 0) + { + compression = T4_COMPRESSION_T43; + compression_step = -1; + } +#if defined(SPANDSP_SUPPORT_T45) + else if (strcmp(optarg, "T45") == 0) + { + compression = T4_COMPRESSION_T45; + compression_step = -1; + } +#endif + else + { + printf("Unrecognised compression.\n"); + exit(2); + } break; case 'd': decode_file_name = optarg; @@ -393,15 +318,15 @@ int main(int argc, char *argv[]) bit_error_rate = 0x3FF; break; case 'h': - add_page_headers = TRUE; - overlay_page_headers = FALSE; + add_page_headers = true; + overlay_page_headers = false; break; case 'H': - add_page_headers = TRUE; - overlay_page_headers = TRUE; + add_page_headers = true; + overlay_page_headers = true; break; case 'r': - restart_pages = TRUE; + restart_pages = true; break; case 'i': in_file_name = optarg; @@ -413,7 +338,7 @@ int main(int argc, char *argv[]) page_header_tz = optarg; break; case 'x': - dump_as_xxx = TRUE; + dump_as_xxx = true; break; default: //usage(); @@ -426,9 +351,9 @@ int main(int argc, char *argv[]) if (decode_file_name) { if (compression < 0) - compression = T4_COMPRESSION_ITU_T4_1D; + compression = T4_COMPRESSION_T4_1D; /* Receive end puts TIFF to a new file. We assume the receive width here. */ - if ((receive_state = t4_rx_init(NULL, OUT_FILE_NAME, T4_COMPRESSION_ITU_T4_2D)) == NULL) + if ((receive_state = t4_rx_init(NULL, OUT_FILE_NAME, T4_COMPRESSION_T4_2D)) == NULL) { printf("Failed to init T.4 rx\n"); exit(2); @@ -533,130 +458,6 @@ int main(int argc, char *argv[]) } else { -#if 1 - printf("Testing image_function->compress->decompress->image_function\n"); - /* Send end gets image from a function */ - if ((send_state = t4_tx_init(NULL, NULL, -1, -1)) == NULL) - { - printf("Failed to init T.4 tx\n"); - exit(2); - } - span_log_set_level(t4_tx_get_logging_state(send_state), SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW); - t4_tx_set_row_read_handler(send_state, row_read_handler, NULL); - t4_tx_set_image_width(send_state, 1728); - t4_tx_set_min_bits_per_row(send_state, min_row_bits); - t4_tx_set_max_2d_rows_per_1d_row(send_state, 2); - - /* Receive end puts TIFF to a function. */ - if ((receive_state = t4_rx_init(NULL, NULL, T4_COMPRESSION_ITU_T4_2D)) == NULL) - { - printf("Failed to init T.4 rx\n"); - exit(2); - } - span_log_set_level(t4_rx_get_logging_state(receive_state), SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW); - t4_rx_set_row_write_handler(receive_state, row_write_handler, NULL); - t4_rx_set_image_width(receive_state, t4_tx_get_image_width(send_state)); - t4_rx_set_x_resolution(receive_state, t4_tx_get_x_resolution(send_state)); - t4_rx_set_y_resolution(receive_state, t4_tx_get_y_resolution(send_state)); - - /* Now send and receive the test data with all compression modes. */ - /* If we are stepping around the compression schemes, reset to the start of the sequence. */ - if (compression_step > 0) - compression_step = 0; - for (;;) - { - end_marks = 0; - if (compression_step >= 0) - { - compression = compression_sequence[compression_step++]; - if (compression < 0 || (block_size == 0 && compression_step >= 3)) - break; - } - t4_tx_set_tx_encoding(send_state, compression); - t4_rx_set_rx_encoding(receive_state, compression); - - rows_read = 0; - rows_written = 0; - if (t4_tx_start_page(send_state)) - break; - if (t4_rx_start_page(receive_state)) - break; - detect_page_end(-1000000, compression); - page_ended = FALSE; - switch (block_size) - { - case 0: - while ((bit = t4_tx_get_bit(send_state)) >= 0) - { - /* Monitor whether the EOLs are there in the correct amount */ - if ((res = detect_page_end(bit, page_ended))) - { - printf("Incorrect EOLs - %d\n", res); - tests_failed += (res - 1); - break; - } - if (bit >= 0) - { - if (bit_error_rate) - { - if ((rand() % bit_error_rate) == 0) - bit ^= 1; - } - end_of_page = t4_rx_put_bit(receive_state, bit); - } - } - while (end_of_page != T4_DECODE_OK) - { - end_of_page = t4_rx_put_bit(receive_state, 0); - if (++end_marks > 50) - { - printf("Receiver missed the end of page mark\n"); - tests_failed++; - break; - } - } - /* Now throw junk at the receive context, to ensure stuff occuring - after the end of page condition has no bad effect. */ - for (i = 0; i < 1000; i++) - t4_rx_put_bit(receive_state, (rand() >> 10) & 1); - break; - default: - /* Some decoders require a few extra bits before the recognise the end - of an image, so be prepared to offer it a few. */ - do - { - len = t4_tx_get(send_state, block, block_size); - if (len > 0) - end_of_page = t4_rx_put(receive_state, block, len); - } - while (len > 0); - while (end_of_page != T4_DECODE_OK) - { - block[0] = 0; - end_of_page = t4_rx_put(receive_state, block, 1); - if (++end_marks > 5) - { - printf("Receiver missed the end of page mark\n"); - tests_failed++; - break; - } - } - break; - } - display_page_stats(receive_state); - t4_tx_end_page(send_state); - t4_rx_end_page(receive_state); - if (rows_read != (15 + 1) || rows_written != (15 + 1)) - { - printf("Test failed: %d rows read, %d rows written\n", rows_read, rows_written); - exit(2); - } - if (compression_step < 0) - break; - } - t4_tx_release(send_state); - t4_rx_release(receive_state); -#endif #if 1 printf("Testing TIFF->compress->decompress->TIFF cycle\n"); /* Send end gets TIFF from a file */ @@ -670,7 +471,7 @@ int main(int argc, char *argv[]) t4_tx_set_local_ident(send_state, "111 2222 3333"); /* Receive end puts TIFF to a new file. */ - if ((receive_state = t4_rx_init(NULL, OUT_FILE_NAME, T4_COMPRESSION_ITU_T4_2D)) == NULL) + if ((receive_state = t4_rx_init(NULL, OUT_FILE_NAME, T4_COMPRESSION_T4_2D)) == NULL) { printf("Failed to init T.4 rx for '%s'\n", OUT_FILE_NAME); exit(2); @@ -713,25 +514,55 @@ int main(int argc, char *argv[]) compression = compression_sequence[compression_step++]; } } - t4_tx_set_tx_encoding(send_state, compression); + if (t4_tx_set_tx_image_format(send_state, + compression, + T4_SUPPORT_WIDTH_215MM + | T4_SUPPORT_LENGTH_US_LETTER + | T4_SUPPORT_LENGTH_US_LEGAL + | T4_SUPPORT_LENGTH_UNLIMITED, + T4_RESOLUTION_R8_STANDARD + | T4_RESOLUTION_R8_FINE + | T4_RESOLUTION_R8_SUPERFINE + | T4_RESOLUTION_R16_SUPERFINE + | T4_RESOLUTION_200_100 + | T4_RESOLUTION_200_200 + | T4_RESOLUTION_200_400 + | T4_RESOLUTION_300_300 + | T4_RESOLUTION_300_600 + | T4_RESOLUTION_400_400 + | T4_RESOLUTION_400_800 + | T4_RESOLUTION_600_600 + | T4_RESOLUTION_600_1200 + | T4_RESOLUTION_1200_1200, + T4_RESOLUTION_100_100 + | T4_RESOLUTION_200_200 + | T4_RESOLUTION_300_300 + | T4_RESOLUTION_400_400 + | T4_RESOLUTION_600_600 + | T4_RESOLUTION_1200_1200) < 0) + { + break; + } t4_rx_set_rx_encoding(receive_state, compression); if (t4_tx_start_page(send_state)) break; - t4_rx_set_x_resolution(receive_state, t4_tx_get_x_resolution(send_state)); - t4_rx_set_y_resolution(receive_state, t4_tx_get_y_resolution(send_state)); - t4_rx_set_image_width(receive_state, t4_tx_get_image_width(send_state)); + t4_rx_set_x_resolution(receive_state, t4_tx_get_tx_x_resolution(send_state)); + t4_rx_set_y_resolution(receive_state, t4_tx_get_tx_y_resolution(send_state)); + t4_rx_set_image_width(receive_state, t4_tx_get_tx_image_width(send_state)); } t4_rx_start_page(receive_state); - detect_page_end(-1000000, compression); - page_ended = FALSE; + detect_non_ecm_page_end(-1, compression); + page_ended = false; switch (block_size) { case 0: + /* Bit by bit operation. This is only appropriate for T.4 1D and 2D, + which are used without ECM. */ while ((bit = t4_tx_get_bit(send_state)) >= 0) { /* Monitor whether the EOLs are there in the correct amount */ - if ((res = detect_page_end(bit, page_ended))) + if ((res = detect_non_ecm_page_end(bit, page_ended))) { printf("Incorrect EOLs - %d\n", res); tests_failed += (res - 1); @@ -767,7 +598,7 @@ int main(int argc, char *argv[]) end_of_page = t4_rx_put(receive_state, block, len); } while (len > 0); - /* Some decoders require a few extra bits before the recognise the end + /* Some decoders require a few extra bits before they recognise the end of an image, so be prepared to offer it a few. */ while (end_of_page != T4_DECODE_OK) { diff --git a/libs/spandsp/tests/t81_t82_arith_coding_tests.c b/libs/spandsp/tests/t81_t82_arith_coding_tests.c index 748a8259db..8de5749928 100644 --- a/libs/spandsp/tests/t81_t82_arith_coding_tests.c +++ b/libs/spandsp/tests/t81_t82_arith_coding_tests.c @@ -52,9 +52,6 @@ the present time. #define MSG_SIZE 10000 -#define FALSE 0 -#define TRUE (!FALSE) - uint8_t msg[MSG_SIZE]; int32_t msg_len; @@ -134,7 +131,7 @@ int main(int argc, char *argv[]) printf("Arithmetic decoder tests from ITU-T T.82/7.1\n"); printf("Decoding byte by byte...\n"); - test_failed = FALSE; + test_failed = false; if ((sd = t81_t82_arith_decode_init(NULL)) == NULL) { fprintf(stderr, "Failed to allocate arithmetic decoder!\n"); @@ -162,7 +159,7 @@ int main(int argc, char *argv[]) printf("Bad pixel %d, byte %" PRIdPTR ".\n\n", i*16 + j + 1, sd->pscd_ptr - sd->pscd_end); - test_failed = TRUE; + test_failed = true; break; } if (pix != ((pix_7_1[i] >> (15 - j)) & 1)) @@ -170,7 +167,7 @@ int main(int argc, char *argv[]) printf("Bad PIX (%d) at pixel %d.\n\n", pix, i*16 + j + 1); - test_failed = TRUE; + test_failed = true; break; } } @@ -179,7 +176,7 @@ int main(int argc, char *argv[]) { printf("%" PRIdPTR " bytes left after decoder finished.\n\n", sd->pscd_end - sd->pscd_ptr - 2); - test_failed = TRUE; + test_failed = true; } if (test_failed) { @@ -189,7 +186,7 @@ int main(int argc, char *argv[]) printf("Test passed\n"); printf("Decoding chunk by chunk...\n"); - test_failed = FALSE; + test_failed = false; t81_t82_arith_decode_init(sd); sd->pscd_ptr = sde_7_1; sd->pscd_end = sde_7_1 + SDE_7_1_FULL_LEN; @@ -203,7 +200,7 @@ int main(int argc, char *argv[]) printf("Bad pixel %d, byte %" PRIdPTR ".\n\n", i*16 + j + 1, sd->pscd_ptr - sd->pscd_end); - test_failed = TRUE; + test_failed = true; break; } if (pix != ((pix_7_1[i] >> (15 - j)) & 1)) @@ -211,7 +208,7 @@ int main(int argc, char *argv[]) printf("Bad PIX (%d) at pixel %d.\n\n", pix, i*16 + j + 1); - test_failed = TRUE; + test_failed = true; break; } } @@ -220,7 +217,7 @@ int main(int argc, char *argv[]) { printf("%" PRIdPTR " bytes left after decoder finished.\n\n", sd->pscd_end - sd->pscd_ptr - 2); - test_failed = TRUE; + test_failed = true; } if (test_failed) { diff --git a/libs/spandsp/tests/t85_tests.c b/libs/spandsp/tests/t85_tests.c index b7047d2ad6..8acca038c5 100644 --- a/libs/spandsp/tests/t85_tests.c +++ b/libs/spandsp/tests/t85_tests.c @@ -57,9 +57,6 @@ in ITU specifications T.85. #define TESTBUF_SIZE 400000 #define TEST_IMAGE_SIZE (1951*1960/8) -#define FALSE 0 -#define TRUE (!FALSE) - uint8_t testbuf[TESTBUF_SIZE]; uint8_t test_image[TEST_IMAGE_SIZE]; diff --git a/libs/spandsp/tests/time_scale_tests.c b/libs/spandsp/tests/time_scale_tests.c index 8e6ae19117..3400b5f9b2 100644 --- a/libs/spandsp/tests/time_scale_tests.c +++ b/libs/spandsp/tests/time_scale_tests.c @@ -69,11 +69,11 @@ int main(int argc, char *argv[]) float rate; float sample_rate; const char *in_file_name; - int sweep_rate; + bool sweep_rate; int opt; rate = 1.8f; - sweep_rate = FALSE; + sweep_rate = false; in_file_name = IN_FILE_NAME; while ((opt = getopt(argc, argv, "i:r:s")) != -1) { @@ -86,7 +86,7 @@ int main(int argc, char *argv[]) rate = atof(optarg); break; case 's': - sweep_rate = TRUE; + sweep_rate = true; break; default: //usage(); diff --git a/libs/spandsp/tests/timezone_tests.c b/libs/spandsp/tests/timezone_tests.c index 9ec4af76d7..ab4efe6890 100644 --- a/libs/spandsp/tests/timezone_tests.c +++ b/libs/spandsp/tests/timezone_tests.c @@ -39,14 +39,6 @@ #include "spandsp.h" -#ifndef FALSE -#define FALSE 0 -#endif - -#ifndef TRUE -#define TRUE (!FALSE) -#endif - int main(int argc, char *argv[]) { struct tm tms; diff --git a/libs/spandsp/tests/tone_generate_tests.c b/libs/spandsp/tests/tone_generate_tests.c index 54b7c4e828..6f1f8af4ea 100644 --- a/libs/spandsp/tests/tone_generate_tests.c +++ b/libs/spandsp/tests/tone_generate_tests.c @@ -68,7 +68,7 @@ int main(int argc, char *argv[]) 200, 300, 400, - FALSE); + false); tone_gen_init(&tone_state, &tone_desc); for (i = 0; i < 1000; i++) @@ -90,7 +90,7 @@ int main(int argc, char *argv[]) 300, 200, 100, - TRUE); + true); tone_gen_init(&tone_state, &tone_desc); for (i = 0; i < 1000; i++) @@ -112,7 +112,7 @@ int main(int argc, char *argv[]) 200, 300, 400, - TRUE); + true); tone_gen_init(&tone_state, &tone_desc); for (i = 0; i < 1000; i++) @@ -134,7 +134,7 @@ int main(int argc, char *argv[]) 200, 300, 400, - TRUE); + true); tone_gen_init(&tone_state, &tone_desc); for (i = 0; i < 1000; i++) @@ -156,7 +156,7 @@ int main(int argc, char *argv[]) 0, 0, 0, - FALSE); + false); tone_gen_init(&tone_state, &tone_desc); for (i = 0; i < 1000; i++) @@ -178,7 +178,7 @@ int main(int argc, char *argv[]) 0, 0, 0, - FALSE); + false); tone_gen_init(&tone_state, &tone_desc); for (i = 0; i < 1000; i++) @@ -200,7 +200,7 @@ int main(int argc, char *argv[]) 200, 300, 400, - TRUE); + true); tone_gen_init(&tone_state, &tone_desc); for (i = 0; i < 1000; i++) @@ -222,7 +222,7 @@ int main(int argc, char *argv[]) 200, 300, 400, - TRUE); + true); tone_gen_init(&tone_state, &tone_desc); for (i = 0; i < 1000; i++) diff --git a/libs/spandsp/tests/tsb85_extra_tests.sh b/libs/spandsp/tests/tsb85_extra_tests.sh index 2d64fb05b4..8aa3b24740 100755 --- a/libs/spandsp/tests/tsb85_extra_tests.sh +++ b/libs/spandsp/tests/tsb85_extra_tests.sh @@ -28,7 +28,7 @@ run_tsb85_test() fi } -for TEST in PPS-MPS-lost-PPS +for TEST in PPS-MPS-lost-PPS V17-12000-V29-9600 do run_tsb85_test done diff --git a/libs/spandsp/tests/tsb85_tests.c b/libs/spandsp/tests/tsb85_tests.c index 9d431f4f3f..c8012162ef 100644 --- a/libs/spandsp/tests/tsb85_tests.c +++ b/libs/spandsp/tests/tsb85_tests.c @@ -71,12 +71,12 @@ SNDFILE *out_handle; -int use_receiver_not_ready = FALSE; -int test_local_interrupt = FALSE; +bool use_receiver_not_ready = false; +bool test_local_interrupt = false; const char *output_tiff_file_name; -int log_audio = FALSE; +bool log_audio = false; fax_state_t *fax; faxtester_state_t state; @@ -230,7 +230,7 @@ static int phase_d_handler(t30_state_t *s, void *user_data, int result) if (i == 'A') { printf("%c: Initiating interrupt request\n", i); - t30_local_interrupt_request(s, TRUE); + t30_local_interrupt_request(s, true); } else { @@ -241,7 +241,7 @@ static int phase_d_handler(t30_state_t *s, void *user_data, int result) case T30_PRI_EOM: case T30_PRI_EOP: printf("%c: Accepting interrupt request\n", i); - t30_local_interrupt_request(s, TRUE); + t30_local_interrupt_request(s, true); break; case T30_PIN: break; @@ -268,7 +268,7 @@ static void phase_e_handler(t30_state_t *s, void *user_data, int result) static void t30_real_time_frame_handler(t30_state_t *s, void *user_data, - int direction, + bool incoming, const uint8_t *msg, int len) { @@ -279,7 +279,7 @@ static void t30_real_time_frame_handler(t30_state_t *s, { fprintf(stderr, "T.30: Real time frame handler - %s, %s, length = %d\n", - (direction) ? "line->T.30" : "T.30->line", + (incoming) ? "line->T.30" : "T.30->line", t30_frametype(msg[2]), len); } @@ -296,9 +296,9 @@ static int document_handler(t30_state_t *s, void *user_data, int event) { t30_set_tx_file(s, next_tx_file, -1, -1); next_tx_file[0] = '\0'; - return TRUE; + return true; } - return FALSE; + return false; } /*- End of function --------------------------------------------------------*/ @@ -367,8 +367,8 @@ static void fax_prepare(void) logging_state_t *logging; t30 = fax_get_t30_state(fax); - fax_set_transmit_on_idle(fax, TRUE); - fax_set_tep_mode(fax, TRUE); + fax_set_transmit_on_idle(fax, true); + fax_set_tep_mode(fax, true); #if 0 t30_set_tx_ident(t30, "1234567890"); t30_set_tx_sub_address(t30, "Sub-address"); @@ -380,33 +380,37 @@ static void fax_prepare(void) t30_set_tx_nsf(t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp NSF\x00", 16); //t30_set_tx_nss(t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp NSS\x00", 16); t30_set_tx_nsc(t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp NSC\x00", 16); - t30_set_ecm_capability(t30, TRUE); + t30_set_ecm_capability(t30, true); t30_set_supported_t30_features(t30, T30_SUPPORT_IDENTIFICATION | T30_SUPPORT_SELECTIVE_POLLING | T30_SUPPORT_SUB_ADDRESSING); t30_set_supported_image_sizes(t30, - T30_SUPPORT_US_LETTER_LENGTH - | T30_SUPPORT_US_LEGAL_LENGTH - | T30_SUPPORT_UNLIMITED_LENGTH - | T30_SUPPORT_215MM_WIDTH - | T30_SUPPORT_255MM_WIDTH - | T30_SUPPORT_303MM_WIDTH); - t30_set_supported_resolutions(t30, - T30_SUPPORT_STANDARD_RESOLUTION - | T30_SUPPORT_FINE_RESOLUTION - | T30_SUPPORT_SUPERFINE_RESOLUTION - | T30_SUPPORT_R8_RESOLUTION - | T30_SUPPORT_R16_RESOLUTION - | T30_SUPPORT_300_300_RESOLUTION - | T30_SUPPORT_400_400_RESOLUTION - | T30_SUPPORT_600_600_RESOLUTION - | T30_SUPPORT_1200_1200_RESOLUTION - | T30_SUPPORT_300_600_RESOLUTION - | T30_SUPPORT_400_800_RESOLUTION - | T30_SUPPORT_600_1200_RESOLUTION); + T4_SUPPORT_WIDTH_215MM + | T4_SUPPORT_WIDTH_255MM + | T4_SUPPORT_WIDTH_303MM + | T4_SUPPORT_LENGTH_US_LETTER + | T4_SUPPORT_LENGTH_US_LEGAL + | T4_SUPPORT_LENGTH_UNLIMITED); + t30_set_supported_bilevel_resolutions(t30, + T4_RESOLUTION_R8_STANDARD + | T4_RESOLUTION_R8_FINE + | T4_RESOLUTION_R8_SUPERFINE + | T4_RESOLUTION_R16_SUPERFINE + | T4_RESOLUTION_100_100 + | T4_RESOLUTION_200_100 + | T4_RESOLUTION_200_200 + | T4_RESOLUTION_200_400 + | T4_RESOLUTION_300_300 + | T4_RESOLUTION_300_600 + | T4_RESOLUTION_400_400 + | T4_RESOLUTION_400_800 + | T4_RESOLUTION_600_600 + | T4_RESOLUTION_600_1200 + | T4_RESOLUTION_1200_1200); + t30_set_supported_colour_resolutions(t30, 0); t30_set_supported_modems(t30, T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17); - t30_set_supported_compressions(t30, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION); + t30_set_supported_compressions(t30, T4_COMPRESSION_T4_1D | T4_COMPRESSION_T4_2D | T4_COMPRESSION_T6); 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_e_handler(t30, phase_e_handler, (void *) (intptr_t) 'A'); @@ -636,9 +640,9 @@ static int next_step(faxtester_state_t *s) /* Add a bit of waiting at the end, to ensure everything gets flushed through, any timers can expire, etc. */ faxtester_set_timeout(s, -1); - faxtester_set_rx_type(s, T30_MODEM_NONE, 0, FALSE, FALSE); - faxtester_set_tx_type(s, T30_MODEM_PAUSE, 0, 120000, FALSE); - s->final_delayed = TRUE; + faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false); + faxtester_set_tx_type(s, T30_MODEM_PAUSE, 0, 120000, false); + s->final_delayed = true; return 1; } /* Finished */ @@ -696,10 +700,10 @@ static int next_step(faxtester_state_t *s) { hdlc = (strcasecmp((const char *) type, "PREAMBLE") == 0); short_train = (strcasecmp((const char *) type, "TCF") != 0); - faxtester_set_tx_type(s, T30_MODEM_NONE, 0, FALSE, FALSE); + faxtester_set_tx_type(s, T30_MODEM_NONE, 0, false, false); if (strcasecmp((const char *) modem, "V.21") == 0) { - faxtester_set_rx_type(s, T30_MODEM_V21, 300, FALSE, TRUE); + faxtester_set_rx_type(s, T30_MODEM_V21, 300, false, true); } else if (strcasecmp((const char *) modem, "V.17/14400") == 0) { @@ -719,19 +723,19 @@ static int next_step(faxtester_state_t *s) } else if (strcasecmp((const char *) modem, "V.29/9600") == 0) { - faxtester_set_rx_type(s, T30_MODEM_V29, 9600, FALSE, hdlc); + faxtester_set_rx_type(s, T30_MODEM_V29, 9600, false, hdlc); } else if (strcasecmp((const char *) modem, "V.29/7200") == 0) { - faxtester_set_rx_type(s, T30_MODEM_V29, 7200, FALSE, hdlc); + faxtester_set_rx_type(s, T30_MODEM_V29, 7200, false, hdlc); } else if (strcasecmp((const char *) modem, "V.27ter/4800") == 0) { - faxtester_set_rx_type(s, T30_MODEM_V27TER, 4800, FALSE, hdlc); + faxtester_set_rx_type(s, T30_MODEM_V27TER, 4800, false, hdlc); } else if (strcasecmp((const char *) modem, "V.27ter/2400") == 0) { - faxtester_set_rx_type(s, T30_MODEM_V27TER, 2400, FALSE, hdlc); + faxtester_set_rx_type(s, T30_MODEM_V27TER, 2400, false, hdlc); } else { @@ -758,14 +762,14 @@ static int next_step(faxtester_state_t *s) else if (strcasecmp((const char *) type, "CNG") == 0) { /* Look for CNG */ - faxtester_set_rx_type(s, T30_MODEM_CNG, 0, FALSE, FALSE); - faxtester_set_tx_type(s, T30_MODEM_NONE, 0, FALSE, FALSE); + faxtester_set_rx_type(s, T30_MODEM_CNG, 0, false, false); + faxtester_set_tx_type(s, T30_MODEM_NONE, 0, false, false); } else if (strcasecmp((const char *) type, "CED") == 0) { /* Look for CED */ - faxtester_set_rx_type(s, T30_MODEM_CED, 0, FALSE, FALSE); - faxtester_set_tx_type(s, T30_MODEM_NONE, 0, FALSE, FALSE); + faxtester_set_rx_type(s, T30_MODEM_CED, 0, false, false); + faxtester_set_tx_type(s, T30_MODEM_NONE, 0, false, false); } else if (strcasecmp((const char *) type, "HDLC") == 0) { @@ -799,10 +803,10 @@ static int next_step(faxtester_state_t *s) { hdlc = (strcasecmp((const char *) type, "PREAMBLE") == 0); short_train = (strcasecmp((const char *) type, "TCF") != 0); - faxtester_set_rx_type(s, T30_MODEM_NONE, 0, FALSE, FALSE); + faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false); if (strcasecmp((const char *) modem, "V.21") == 0) { - faxtester_set_tx_type(s, T30_MODEM_V21, 300, FALSE, TRUE); + faxtester_set_tx_type(s, T30_MODEM_V21, 300, false, true); } else if (strcasecmp((const char *) modem, "V.17/14400") == 0) { @@ -822,19 +826,19 @@ static int next_step(faxtester_state_t *s) } else if (strcasecmp((const char *) modem, "V.29/9600") == 0) { - faxtester_set_tx_type(s, T30_MODEM_V29, 9600, FALSE, hdlc); + faxtester_set_tx_type(s, T30_MODEM_V29, 9600, false, hdlc); } else if (strcasecmp((const char *) modem, "V.29/7200") == 0) { - faxtester_set_tx_type(s, T30_MODEM_V29, 7200, FALSE, hdlc); + faxtester_set_tx_type(s, T30_MODEM_V29, 7200, false, hdlc); } else if (strcasecmp((const char *) modem, "V.27ter/4800") == 0) { - faxtester_set_tx_type(s, T30_MODEM_V27TER, 4800, FALSE, hdlc); + faxtester_set_tx_type(s, T30_MODEM_V27TER, 4800, false, hdlc); } else if (strcasecmp((const char *) modem, "V.27ter/2400") == 0) { - faxtester_set_tx_type(s, T30_MODEM_V27TER, 2400, FALSE, hdlc); + faxtester_set_tx_type(s, T30_MODEM_V27TER, 2400, false, hdlc); } else { @@ -873,13 +877,13 @@ static int next_step(faxtester_state_t *s) } else if (strcasecmp((const char *) type, "CALL") == 0) { - fax = fax_init(NULL, FALSE); + fax = fax_init(NULL, false); fax_prepare(); next_tx_file[0] = '\0'; t30 = fax_get_t30_state(fax); t30_set_rx_file(t30, output_tiff_file_name, -1); /* Avoid libtiff 3.8.2 and earlier bug on complex 2D lines. */ - t30_set_rx_encoding(t30, T4_COMPRESSION_ITU_T4_1D); + t30_set_supported_output_compressions(t30, T4_COMPRESSION_T4_1D); if (value) { sprintf(path, "%s/%s", image_path, (const char *) value); @@ -889,12 +893,12 @@ static int next_step(faxtester_state_t *s) } else if (strcasecmp((const char *) type, "ANSWER") == 0) { - fax = fax_init(NULL, TRUE); + fax = fax_init(NULL, true); fax_prepare(); next_tx_file[0] = '\0'; t30 = fax_get_t30_state(fax); /* Avoid libtiff 3.8.2 and earlier bug on complex 2D lines. */ - t30_set_rx_encoding(t30, T4_COMPRESSION_ITU_T4_1D); + t30_set_supported_output_compressions(t30, T4_COMPRESSION_T4_1D); if (value) { sprintf(path, "%s/%s", image_path, (const char *) value); @@ -904,19 +908,19 @@ static int next_step(faxtester_state_t *s) } else if (strcasecmp((const char *) type, "CNG") == 0) { - faxtester_set_rx_type(s, T30_MODEM_NONE, 0, FALSE, FALSE); - faxtester_set_tx_type(s, T30_MODEM_CNG, 0, FALSE, FALSE); + faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false); + faxtester_set_tx_type(s, T30_MODEM_CNG, 0, false, false); } else if (strcasecmp((const char *) type, "CED") == 0) { - faxtester_set_rx_type(s, T30_MODEM_NONE, 0, FALSE, FALSE); - faxtester_set_tx_type(s, T30_MODEM_CED, 0, FALSE, FALSE); + faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false); + faxtester_set_tx_type(s, T30_MODEM_CED, 0, false, false); } else if (strcasecmp((const char *) type, "WAIT") == 0) { delay = (value) ? atoi((const char *) value) : 1; - faxtester_set_rx_type(s, T30_MODEM_NONE, 0, FALSE, FALSE); - faxtester_set_tx_type(s, T30_MODEM_PAUSE, 0, delay, FALSE); + faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false); + faxtester_set_tx_type(s, T30_MODEM_PAUSE, 0, delay, false); } else if (strcasecmp((const char *) type, "PREAMBLE") == 0) { @@ -933,9 +937,9 @@ static int next_step(faxtester_state_t *s) i = string_to_msg(buf, mask, (const char *) value); bit_reverse(buf, buf, abs(i)); if (crc_error && strcasecmp((const char *) crc_error, "0") == 0) - faxtester_send_hdlc_msg(s, buf, abs(i), FALSE); + faxtester_send_hdlc_msg(s, buf, abs(i), false); else - faxtester_send_hdlc_msg(s, buf, abs(i), TRUE); + faxtester_send_hdlc_msg(s, buf, abs(i), true); } else if (strcasecmp((const char *) type, "TCF") == 0) { @@ -969,15 +973,45 @@ static int next_step(faxtester_state_t *s) exit(2); } t4_tx_set_header_info(&t4_tx_state, NULL); - compression_type = T4_COMPRESSION_ITU_T4_1D; + compression_type = T4_COMPRESSION_T4_1D; if (compression) { if (strcasecmp((const char *) compression, "T.4 2D") == 0) - compression_type = T4_COMPRESSION_ITU_T4_2D; + compression_type = T4_COMPRESSION_T4_2D; else if (strcasecmp((const char *) compression, "T.6") == 0) - compression_type = T4_COMPRESSION_ITU_T6; + compression_type = T4_COMPRESSION_T6; + } + if (t4_tx_set_tx_image_format(&t4_tx_state, + compression_type, + T4_SUPPORT_WIDTH_215MM + | T4_SUPPORT_LENGTH_US_LETTER + | T4_SUPPORT_LENGTH_US_LEGAL + | T4_SUPPORT_LENGTH_UNLIMITED, + T4_RESOLUTION_R8_STANDARD + | T4_RESOLUTION_R8_FINE + | T4_RESOLUTION_R8_SUPERFINE + | T4_RESOLUTION_R16_SUPERFINE + | T4_RESOLUTION_200_100 + | T4_RESOLUTION_200_200 + | T4_RESOLUTION_200_400 + | T4_RESOLUTION_300_300 + | T4_RESOLUTION_300_600 + | T4_RESOLUTION_400_400 + | T4_RESOLUTION_400_800 + | T4_RESOLUTION_600_600 + | T4_RESOLUTION_600_1200 + | T4_RESOLUTION_1200_1200, + T4_RESOLUTION_100_100 + | T4_RESOLUTION_200_200 + | T4_RESOLUTION_300_300 + | T4_RESOLUTION_400_400 + | T4_RESOLUTION_600_600 + | T4_RESOLUTION_1200_1200) < 0) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Failed to set T.4 compression\n"); + printf("Test failed\n"); + exit(2); } - t4_tx_set_tx_encoding(&t4_tx_state, compression_type); t4_tx_set_min_bits_per_row(&t4_tx_state, min_row_bits); if (t4_tx_start_page(&t4_tx_state)) { @@ -1009,15 +1043,45 @@ static int next_step(faxtester_state_t *s) exit(2); } t4_tx_set_header_info(&t4_tx_state, NULL); - compression_type = T4_COMPRESSION_ITU_T4_1D; + compression_type = T4_COMPRESSION_T4_1D; if (compression) { if (strcasecmp((const char *) compression, "T.4 2D") == 0) - compression_type = T4_COMPRESSION_ITU_T4_2D; + compression_type = T4_COMPRESSION_T4_2D; else if (strcasecmp((const char *) compression, "T.6") == 0) - compression_type = T4_COMPRESSION_ITU_T6; + compression_type = T4_COMPRESSION_T6; + } + if (t4_tx_set_tx_image_format(&t4_tx_state, + compression_type, + T4_SUPPORT_WIDTH_215MM + | T4_SUPPORT_LENGTH_US_LETTER + | T4_SUPPORT_LENGTH_US_LEGAL + | T4_SUPPORT_LENGTH_UNLIMITED, + T4_RESOLUTION_R8_STANDARD + | T4_RESOLUTION_R8_FINE + | T4_RESOLUTION_R8_SUPERFINE + | T4_RESOLUTION_R16_SUPERFINE + | T4_RESOLUTION_200_100 + | T4_RESOLUTION_200_200 + | T4_RESOLUTION_200_400 + | T4_RESOLUTION_300_300 + | T4_RESOLUTION_300_600 + | T4_RESOLUTION_400_400 + | T4_RESOLUTION_400_800 + | T4_RESOLUTION_600_600 + | T4_RESOLUTION_600_1200 + | T4_RESOLUTION_1200_1200, + T4_RESOLUTION_100_100 + | T4_RESOLUTION_200_200 + | T4_RESOLUTION_300_300 + | T4_RESOLUTION_400_400 + | T4_RESOLUTION_600_600 + | T4_RESOLUTION_1200_1200) < 0) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Failed to set T.4 compression\n"); + printf("Test failed\n"); + exit(2); } - t4_tx_set_tx_encoding(&t4_tx_state, compression_type); t4_tx_set_min_bits_per_row(&t4_tx_state, min_row_bits); if (t4_tx_start_page(&t4_tx_state)) { @@ -1074,12 +1138,12 @@ static void exchange(faxtester_state_t *s) total_audio_time = 0; - faxtester_set_transmit_on_idle(&state, TRUE); + faxtester_set_transmit_on_idle(&state, true); faxtester_set_real_time_frame_handler(&state, faxtester_real_time_frame_handler, NULL); faxtester_set_front_end_step_complete_handler(&state, faxtester_front_end_step_complete_handler, NULL); faxtester_set_front_end_step_timeout_handler(&state, faxtester_front_end_step_timeout_handler, NULL); - fax = fax_init(NULL, FALSE); + fax = fax_init(NULL, false); fax_prepare(); next_tx_file[0] = '\0'; @@ -1291,13 +1355,13 @@ int main(int argc, char *argv[]) xml_file_name = "../spandsp/tsb85.xml"; test_name = "MRGN01"; - log_audio = FALSE; + log_audio = false; while ((opt = getopt(argc, argv, "lx:")) != -1) { switch (opt) { case 'l': - log_audio = TRUE; + log_audio = true; break; case 'x': xml_file_name = optarg; @@ -1314,7 +1378,7 @@ int main(int argc, char *argv[]) test_name = argv[0]; strcpy(image_path, "."); - faxtester_init(&state, TRUE); + faxtester_init(&state, true); memset(&expected_rx_info, 0, sizeof(expected_rx_info)); span_log_set_level(&state.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW); span_log_set_tag(&state.logging, "B"); diff --git a/libs/spandsp/tests/udptl.c b/libs/spandsp/tests/udptl.c index 96f2c25162..1ddb8e346d 100644 --- a/libs/spandsp/tests/udptl.c +++ b/libs/spandsp/tests/udptl.c @@ -34,12 +34,14 @@ #include #include #include +#if defined(HAVE_STDBOOL_H) +#include +#else +#include +#endif #include "udptl.h" -#define FALSE 0 -#define TRUE (!FALSE) - static int decode_length(const uint8_t *buf, int limit, int *len, int *pvalue) { if (*len >= limit) @@ -58,7 +60,7 @@ static int decode_length(const uint8_t *buf, int limit, int *len, int *pvalue) return 0; } *pvalue = (buf[(*len)++] & 0x3F) << 14; - /* Indicate we have a fragment */ + /* Indicate that we have a fragment */ return 1; } /*- End of function --------------------------------------------------------*/ @@ -66,11 +68,13 @@ static int decode_length(const uint8_t *buf, int limit, int *len, int *pvalue) static int decode_open_type(const uint8_t *buf, int limit, int *len, const uint8_t **p_object, int *p_num_octets) { int octet_cnt; +#if 0 int octet_idx; int stat; const uint8_t **pbuf; - for (octet_idx = 0, *p_num_octets = 0; ; octet_idx += octet_cnt) + *p_num_octets = 0; + for (octet_idx = 0; ; octet_idx += octet_cnt) { if ((stat = decode_length(buf, limit, len, &octet_cnt)) < 0) return -1; @@ -89,6 +93,21 @@ static int decode_open_type(const uint8_t *buf, int limit, int *len, const uint8 if (stat == 0) break; } +#else + /* We do not deal with fragments, so there is no point in looping through them. Just say that something + fragmented is bad. */ + if (decode_length(buf, limit, len, &octet_cnt) != 0) + return -1; + *p_num_octets = octet_cnt; + if (octet_cnt > 0) + { + /* Make sure the buffer contains at least the number of bits requested */ + if ((*len + octet_cnt) > limit) + return -1; + *p_object = &buf[*len]; + *len += octet_cnt; + } +#endif return 0; } /*- End of function --------------------------------------------------------*/ @@ -153,7 +172,6 @@ static int encode_open_type(uint8_t *buf, int *len, const uint8_t *data, int num int udptl_rx_packet(udptl_state_t *s, const uint8_t buf[], int len) { int stat; - int stat2; int i; int j; int k; @@ -216,16 +234,16 @@ int udptl_rx_packet(udptl_state_t *s, const uint8_t buf[], int len) total_count = 0; do { - if ((stat2 = decode_length(buf, len, &ptr, &count)) < 0) + if ((stat = decode_length(buf, len, &ptr, &count)) < 0) return -1; for (i = 0; i < count; i++) { - if ((stat = decode_open_type(buf, len, &ptr, &bufs[total_count + i], &lengths[total_count + i])) != 0) + if (decode_open_type(buf, len, &ptr, &bufs[total_count + i], &lengths[total_count + i]) != 0) return -1; } total_count += count; } - while (stat2 > 0); + while (stat > 0); /* We should now be exactly at the end of the packet. If not, this is a fault. */ if (ptr != len) return -1; @@ -246,7 +264,8 @@ int udptl_rx_packet(udptl_state_t *s, const uint8_t buf[], int len) /* Save the new packet. Redundancy mode won't use this, but some systems will switch into FEC mode after sending some redundant packets, and this may then be important. */ x = (seq_no - i) & UDPTL_BUF_MASK; - memcpy(s->rx[x].buf, bufs[i - 1], lengths[i - 1]); + if (lengths[i - 1] > 0) + memcpy(s->rx[x].buf, bufs[i - 1], lengths[i - 1]); s->rx[x].buf_len = lengths[i - 1]; s->rx[x].fec_len[0] = 0; s->rx[x].fec_span = 0; @@ -275,7 +294,7 @@ int udptl_rx_packet(udptl_state_t *s, const uint8_t buf[], int len) s->rx[x].fec_span = span; memset(repaired, 0, sizeof(repaired)); - repaired[x] = TRUE; + repaired[x] = true; /* The number of entries is defined as a length, but will only ever be a small value. Treat it as such. */ @@ -334,7 +353,7 @@ int udptl_rx_packet(udptl_state_t *s, const uint8_t buf[], int len) } } s->rx[which].buf_len = s->rx[l].fec_len[m]; - repaired[which] = TRUE; + repaired[which] = true; } } } diff --git a/libs/spandsp/tests/v17_tests.c b/libs/spandsp/tests/v17_tests.c index ca6bd54ca5..8ceb12060e 100644 --- a/libs/spandsp/tests/v17_tests.c +++ b/libs/spandsp/tests/v17_tests.c @@ -79,7 +79,7 @@ display of modem status is maintained. #define OUT_FILE_NAME "v17.wav" char *decode_test_file = NULL; -int use_gui = FALSE; +bool use_gui = false; int symbol_no = 0; @@ -319,29 +319,29 @@ int main(int argc, char *argv[]) SNDFILE *outhandle; int outframes; int samples; - int tep; int block_no; int noise_level; int signal_level; int bits_per_test; int line_model_no; - int log_audio; int channel_codec; int rbs_pattern; int opt; + bool tep; + bool log_audio; logging_state_t *logging; channel_codec = MUNGE_CODEC_NONE; rbs_pattern = 0; test_bps = 14400; - tep = FALSE; + tep = false; line_model_no = 0; decode_test_file = NULL; - use_gui = FALSE; + use_gui = false; noise_level = -70; signal_level = -13; bits_per_test = 50000; - log_audio = FALSE; + log_audio = false; while ((opt = getopt(argc, argv, "b:B:c:d:glm:n:r:s:t")) != -1) { switch (opt) @@ -374,14 +374,14 @@ int main(int argc, char *argv[]) break; case 'g': #if defined(ENABLE_GUI) - use_gui = TRUE; + use_gui = true; #else fprintf(stderr, "Graphical monitoring not available\n"); exit(2); #endif break; case 'l': - log_audio = TRUE; + log_audio = true; break; case 'm': line_model_no = atoi(optarg); @@ -396,7 +396,7 @@ int main(int argc, char *argv[]) signal_level = atoi(optarg); break; case 't': - tep = TRUE; + tep = true; break; default: //usage(); @@ -529,9 +529,9 @@ int main(int argc, char *argv[]) /* Bump the receiver AGC gain by 1dB, to compensate for the above */ rx->agc_scaling_save *= 1.122f; #endif - v17_tx_restart(tx, test_bps, tep, TRUE); + v17_tx_restart(tx, test_bps, tep, true); v17_tx_power(tx, signal_level); - v17_rx_restart(rx, test_bps, TRUE); + v17_rx_restart(rx, test_bps, true); //rx.eq_put_step = rand()%(192*10/3); bert_init(&bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); bert_set_report(&bert, 10000, reporter, NULL); diff --git a/libs/spandsp/tests/v18_tests.c b/libs/spandsp/tests/v18_tests.c index 23efd7ae3c..948ffef501 100644 --- a/libs/spandsp/tests/v18_tests.c +++ b/libs/spandsp/tests/v18_tests.c @@ -41,17 +41,14 @@ #include "spandsp.h" #include "spandsp-sim.h" -#define FALSE 0 -#define TRUE (!FALSE) - #define OUTPUT_FILE_NAME "v18.wav" #define SAMPLES_PER_CHUNK 160 -int log_audio = FALSE; +int log_audio = false; SNDFILE *outhandle = NULL; -char result[1024]; -int unexpected_echo = FALSE; +char result[2][1024]; +int unexpected_echo = false; char *decode_test_file = NULL; @@ -81,14 +78,13 @@ static void put_text_msg(void *user_data, const uint8_t *msg, int len) } else { - good_message_received = TRUE; + good_message_received = true; } } /*- End of function --------------------------------------------------------*/ static void basic_tests(int mode) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -100,14 +96,14 @@ static void basic_tests(int mode) int j; printf("Testing %s\n", v18_mode_to_str(mode)); - v18[0] = v18_init(NULL, TRUE, mode, put_text_msg, NULL); + v18[0] = v18_init(NULL, true, mode, V18_AUTOMODING_GLOBAL, put_text_msg, NULL); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, mode, put_text_msg, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, mode, V18_AUTOMODING_GLOBAL, put_text_msg, NULL); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -125,7 +121,7 @@ static void basic_tests(int mode) } /* Fake an OK condition for the first message test */ - good_message_received = TRUE; + good_message_received = true; push = 0; if (v18_put(v18[0], qbf_tx, -1) != strlen(qbf_tx)) { @@ -133,6 +129,8 @@ static void basic_tests(int mode) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { if (push == 0) @@ -151,7 +149,7 @@ static void basic_tests(int mode) printf("No message received\n"); exit(2); } - good_message_received = FALSE; + good_message_received = false; if (v18_put(v18[0], qbf_tx, -1) != strlen(qbf_tx)) { printf("V.18 put failed\n"); @@ -204,9 +202,13 @@ static void basic_tests(int mode) } /*- End of function --------------------------------------------------------*/ +static void misc_01_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_misc_01(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -223,18 +225,18 @@ static int test_misc_01(void) Preamble: N/A Method: A call is made to the TUT from the tester which remains off hook for 10 minutes without sending any signal. - Pass criteria: The TUT should answer the call and enter the probing state after 3 seconds. The + Pass criteria: The TUT should answer the call and enter the probing state after 3s. The TUT should continue to probe until the test is terminated. Comments: This feature should also be verified by observation during the automoding tests. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, misc_01_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, misc_01_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -251,6 +253,8 @@ static int test_misc_01(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -299,9 +303,13 @@ static int test_misc_01(void) } /*- End of function --------------------------------------------------------*/ +static void misc_02_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_misc_02(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -315,25 +323,25 @@ static int test_misc_02(void) /* III.5.4.1.2 Automatic resumption of automoding Purpose: To ensure that the DCE can be configured to automatically re-assume the automode - calling state after 10 s of no valid signal. + calling state after 10s of no valid signal. Preamble: The TUT should be configured to automatically re-assume the initial automoding state. Method: The tester should set up a call to the TUT in V.21 mode and then drop the carrier. - The tester will then transmit silence for 11 seconds followed by a 1300Hz tone for - 5 seconds (i.e. V.23). - Pass criteria: 1) Ten seconds after dropping the carrier the TUT should return to state Monitor 1. - 2) After 2.7+-0.3 seconds the TUT should select V.23 mode and send a 390Hz tone. + The tester will then transmit silence for 11s followed by a 1300Hz tone for + 5s (i.e. V.23). + Pass criteria: 1) 10s after dropping the carrier the TUT should return to state Monitor 1. + 2) After 2.7+-0.3s the TUT should select V.23 mode and send a 390Hz tone. Comments: The TUT should indicate that carrier has been lost at some time after the 1650Hz signal is lost. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, misc_02_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, misc_02_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -350,6 +358,8 @@ static int test_misc_02(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -398,9 +408,13 @@ static int test_misc_02(void) } /*- End of function --------------------------------------------------------*/ +static void misc_03_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_misc_03(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -418,21 +432,21 @@ static int test_misc_03(void) Preamble: The TUT should be configured to remain in the selected transmission mode when the carrier is lost. Method: The tester should set up a call to the TUT in V.21 mode, for example. It will drop - the carrier for 9 seconds and then re-start transmission of the same carrier for - 1 second followed by a short message. + the carrier for 9s and then re-start transmission of the same carrier for + 1s followed by a short message. Pass criteria: The TUT should resume operation in V.21 mode and capture the entire test message. Comments: The TUT should indicate that carrier has been lost at some time after the carrier signal is removed and not disconnect. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, misc_03_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, misc_03_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -449,6 +463,8 @@ static int test_misc_03(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -497,9 +513,13 @@ static int test_misc_03(void) } /*- End of function --------------------------------------------------------*/ +static void misc_04_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_misc_04(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -523,14 +543,14 @@ static int test_misc_04(void) automatically hang up when busy tone is detected. PABX busy tones may differ in frequency and cadence from national parameters. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, misc_04_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, misc_04_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -547,6 +567,8 @@ static int test_misc_04(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -595,9 +617,13 @@ static int test_misc_04(void) } /*- End of function --------------------------------------------------------*/ +static void misc_05_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_misc_05(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -618,14 +644,14 @@ static int test_misc_05(void) Pass criteria: The RINGING condition should be visually indicated by the TUT. Comments: This test should be repeated across a range of valid timings and ring voltages. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, misc_05_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, misc_05_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -642,6 +668,8 @@ static int test_misc_05(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -690,9 +718,13 @@ static int test_misc_05(void) } /*- End of function --------------------------------------------------------*/ +static void misc_06_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_misc_06(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -716,14 +748,14 @@ static int test_misc_06(void) mode. There may be other cases, e.g. where the V.18 DCE is used in a gateway, when automatic disconnection is required. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, misc_06_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, misc_06_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -740,6 +772,8 @@ static int test_misc_06(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -788,9 +822,13 @@ static int test_misc_06(void) } /*- End of function --------------------------------------------------------*/ +static void misc_07_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_misc_07(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -812,14 +850,14 @@ static int test_misc_07(void) However, this may possibly not be indicated by the DTE. Comments: The possible modes are: V.21, V.23, Baudot 45, Baudot 50, EDT, Bell 103, DTMF. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, misc_07_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, misc_07_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -836,6 +874,8 @@ static int test_misc_07(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -884,9 +924,13 @@ static int test_misc_07(void) } /*- End of function --------------------------------------------------------*/ +static void misc_08_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_misc_08(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -902,21 +946,21 @@ static int test_misc_08(void) Purpose: To ensure that the DCE implements circuit 135 or an equivalent way of indicating presence of a signal. Preamble: N/A - Method: A call from the TUT should be answered in voice mode after 20 seconds. The tester + Method: A call from the TUT should be answered in voice mode after 20s. The tester will transmit sampled voice messages. V.24 circuit 135 or its equivalent should be observed. Pass criteria: The ring tone and speech shall be indicated by circuit 135. Comment: The response times and signal level thresholds of Circuit 135 are not specified in ITU-T V.18 or V.24 and therefore the pattern indicated may vary. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, misc_08_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, misc_08_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -933,6 +977,8 @@ static int test_misc_08(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -981,9 +1027,13 @@ static int test_misc_08(void) } /*- End of function --------------------------------------------------------*/ +static void misc_09_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_misc_09(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -1003,14 +1053,14 @@ static int test_misc_09(void) Pass criteria: TBD Comment: TBD */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, misc_09_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, misc_09_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -1027,6 +1077,8 @@ static int test_misc_09(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -1075,9 +1127,13 @@ static int test_misc_09(void) } /*- End of function --------------------------------------------------------*/ +static void org_01_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_org_01(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -1098,22 +1154,22 @@ static int test_org_01(void) check for correct coding and timing of the signal. Pass criteria: 1) No signal should be transmitted for one second after connecting to the line. 2) Four CI patterns are transmitted for each repetition. - 3) No signal is transmitted for two seconds after the end of each CI. + 3) No signal is transmitted for 2s after the end of each CI. 4) Each CI must have the correct bit pattern. - 5) The CI patterns followed by two seconds of silence must be repeated twice. + 5) The CI patterns followed by 2s of silence must be repeated twice. 6) One second after every 3 blocks CI an XCI signal must be transmitted. 7) The XCI should have the structure defined in 3.11. 8) The whole sequence should be repeated until the call is cleared. 9) When V.18 to V.18, the XCI must not force V.23 or Minitel mode. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_01_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_01_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -1130,6 +1186,8 @@ static int test_org_01(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -1178,9 +1236,13 @@ static int test_org_01(void) } /*- End of function --------------------------------------------------------*/ +static void org_02_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_org_02(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -1198,20 +1260,19 @@ static int test_org_02(void) Preamble: Make a V.18 call from the TUT. Method: The Test System waits for the TUT to stop transmitting a CI and responds with an ANS signal. The V.21 demodulator is used to decode the TXP sequence and a timer - measures the silence intervals between them. ANS should be transmitted for 2 - seconds. - Pass criteria: 1) No signal should be transmitted by TUT for 0.5 seconds from detection of ANS. + measures the silence intervals between them. ANS should be transmitted for 2s. + Pass criteria: 1) No signal should be transmitted by TUT for 0.5s from detection of ANS. 2) The TUT should reply with transmission of TXP as defined in 5.1.2. 3) Verify that TXP sequence has correct bit pattern. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_02_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_02_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -1228,6 +1289,8 @@ static int test_org_02(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -1276,9 +1339,13 @@ static int test_org_02(void) } /*- End of function --------------------------------------------------------*/ +static void org_03_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_org_03(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -1294,19 +1361,19 @@ static int test_org_03(void) Purpose: The TUT should stop sending TXP at the end of the current sequence when the ANS tone ceases. Preamble: Test ORG-02 should be successfully completed immediately prior to this test. - Method: The tester sends ANS for 2 seconds followed by silence. The tester will then + Method: The tester sends ANS for 2s followed by silence. The tester will then monitor for cessation of TXP at the end of the answer tone. Pass criteria: The TUT should stop sending TXP at the end of the current sequence when ANS tone ceases. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_03_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_03_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -1323,6 +1390,8 @@ static int test_org_03(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -1371,9 +1440,13 @@ static int test_org_03(void) } /*- End of function --------------------------------------------------------*/ +static void org_04_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_org_04(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -1388,24 +1461,24 @@ static int test_org_04(void) III.5.4.2.4 ANS tone followed by TXP Purpose: To check correct detection of V.18 modem. Preamble: Tests ORG-02 and ORG-03 should be successfully completed prior to this test. - Method: Tester transmits ANS for 2.5 seconds followed by 75 ms of no tone then transmits - 3 TXP sequences using V.21 (2) and starts a 1 s timer. It will then transmit 1650Hz - for 5 seconds. + Method: Tester transmits ANS for 2.5s followed by 75ms of no tone then transmits + 3 TXP sequences using V.21 (2) and starts a 1s timer. It will then transmit 1650Hz + for 5s. Pass criteria: 1) TUT should initially respond with TXP. - 2) TUT should stop sending TXP within 0.2 seconds of end of ANS. - 3) TUT should respond with 980Hz carrier within 1 second of end of 3 TXP sequences. + 2) TUT should stop sending TXP within 0.2s of end of ANS. + 3) TUT should respond with 980Hz carrier within 1s of end of 3 TXP sequences. 4) Data should be transmitted and received according to ITU-T T.140 to comply with the V.18 operational requirements. Comments: The TUT should indicate that V.18 mode has been selected. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_04_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_04_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -1422,6 +1495,8 @@ static int test_org_04(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -1470,9 +1545,13 @@ static int test_org_04(void) } /*- End of function --------------------------------------------------------*/ +static void org_05_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_org_05(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -1488,24 +1567,24 @@ static int test_org_05(void) Purpose: To check correct detection of V.21 modem upper channel when preceded by answer tone and to confirm discrimination between V.21 and V.18 modes. Preamble: Tests ORG-02 and ORG-03 should be successfully completed prior to this test. - Method: Tester transmits ANS for 2.5 seconds followed by 75 ms of no tone then transmits + Method: Tester transmits ANS for 2.5s followed by 75ms of no tone then transmits 1650Hz and starts a 0.7 second timer. Pass criteria: 1) TUT should initially respond with TXP. - 2) TUT should stop sending TXP within 0.2 seconds of end of ANS. - 3) TUT should respond with 980Hz at 0.5(+0.2-0.0) seconds of start of 1650Hz. + 2) TUT should stop sending TXP within 0.2s of end of ANS. + 3) TUT should respond with 980Hz at 0.5(+0.2-0.0)s of start of 1650Hz. 4) Data should be transmitted and received at 300 bit/s complying with Annex F. Comments: Selection of ITU-T V.21 as opposed to ITU-T V.18 should be confirmed by examination of TUT. If there is no visual indication, verify by use of ITU-T T.50 for ITU-T V.21 as opposed to UTF-8 coded ISO 10646 character set for ITU-T V.18. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_05_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_05_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -1522,6 +1601,8 @@ static int test_org_05(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -1570,9 +1651,13 @@ static int test_org_05(void) } /*- End of function --------------------------------------------------------*/ +static void org_06_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_org_06(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -1588,23 +1673,23 @@ static int test_org_06(void) Purpose: To check correct detection of V.23 modem upper channel when preceded by answer tone. Preamble: Tests ORG-02 and ORG-03 should be successfully completed prior to this test. - Method: Tester transmits ANS for 2.5 seconds followed by 75 ms of no tone then transmits - 1300Hz and starts a 2.7 s timer. + Method: Tester transmits ANS for 2.5s followed by 75ms of no tone then transmits + 1300Hz and starts a 2.7s timer. Pass criteria: 1) TUT should initially respond with TXP. - 2) TUT should stop sending TXP within 0.2 seconds of end of ANS. - 3) TUT should respond with 390Hz after 1.7(+0.2-0.0) seconds of start of 1300Hz. + 2) TUT should stop sending TXP within 0.2s of end of ANS. + 3) TUT should respond with 390Hz after 1.7(+0.2-0.0)s of start of 1300Hz. 4) Data should be transmitted and received at 75 bit/s and 1200 bit/s respectively by the TUT to comply with Annex E. Comments: The TUT should indicate that V.23 mode has been selected. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_06_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_06_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -1621,6 +1706,8 @@ static int test_org_06(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -1669,9 +1756,13 @@ static int test_org_06(void) } /*- End of function --------------------------------------------------------*/ +static void org_07_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_org_07(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -1686,24 +1777,24 @@ static int test_org_07(void) III.5.4.2.7 ANS tone followed by no tone Purpose: To confirm that TUT does not lock up under this condition. Preamble: Tests ORG-02 and ORG-03 should be successfully completed prior to this test. - Method: Tester transmits ANS for 2.5 seconds followed by no tone for 10 s. It then transmits - DTMF tones for 2 seconds. + Method: Tester transmits ANS for 2.5s followed by no tone for 10 s. It then transmits + DTMF tones for 2s. Pass criteria: 1) TUT should initially respond with TXP. - 2) TUT should stop sending TXP within 0.2 seconds of end of ANS. + 2) TUT should stop sending TXP within 0.2s of end of ANS. 3) TUT should return to Monitor 1 state and then connect in DTMF mode within - 12 seconds of the end of ANS tone. + 12s of the end of ANS tone. Comments: This condition would cause the terminal to lock up if the V.18 standard is followed literally. It may however, occur when connected to certain Swedish textphones if the handset is lifted just after the start of an automatically answered incoming call. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_07_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_07_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -1720,6 +1811,8 @@ static int test_org_07(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -1768,9 +1861,13 @@ static int test_org_07(void) } /*- End of function --------------------------------------------------------*/ +static void org_08_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_org_08(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -1786,19 +1883,19 @@ static int test_org_08(void) Purpose: To verify that the TUT correctly detects the Bell 103 upper channel signal during the 2-second interval between transmission of CI sequences. Preamble: N/A - Method: The tester waits for a CI and then sends a 2225Hz signal for 5 seconds. - Pass criteria: 1) The TUT should respond with a 1270Hz tone in 0.5+-0.1 seconds. + Method: The tester waits for a CI and then sends a 2225Hz signal for 5s. + Pass criteria: 1) The TUT should respond with a 1270Hz tone in 0.5+-0.1s. 2) Data should be transmitted and received at 300 bit/s to comply with Annex D. Comments: The TUT should indicate that Bell 103 mode has been selected. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_08_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_08_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -1815,6 +1912,8 @@ static int test_org_08(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -1863,9 +1962,13 @@ static int test_org_08(void) } /*- End of function --------------------------------------------------------*/ +static void org_09_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_org_09(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -1881,19 +1984,19 @@ static int test_org_09(void) Purpose: To verify that the TUT correctly detects the V.21 upper channel signal during the 2-second interval between transmission of CI sequences. Preamble: N/A - Method: The tester waits for a CI and then sends a 1650Hz signal for 5 seconds. - Pass criteria: 1) The TUT should respond with a 980Hz tone in 0.5+-0.1 seconds. + Method: The tester waits for a CI and then sends a 1650Hz signal for 5s. + Pass criteria: 1) The TUT should respond with a 980Hz tone in 0.5+-0.1s. 2) Data should be transmitted and received at 300 bit/s to comply with Annex F. Comments: The TUT should indicate that V.21 mode has been selected. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_09_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_09_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -1910,6 +2013,8 @@ static int test_org_09(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -1958,9 +2063,13 @@ static int test_org_09(void) } /*- End of function --------------------------------------------------------*/ +static void org_10_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_org_10(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -1976,20 +2085,20 @@ static int test_org_10(void) Purpose: To verify that the TUT correctly detects the V.23 upper channel signal during the 2-second interval between transmission of CI sequences. Preamble: N/A - Method: The tester waits for a CI and then sends a 1300Hz signal for 5 seconds. - Pass criteria: 1) The TUT should respond with a 390Hz tone in 1.7+-0.1 seconds. + Method: The tester waits for a CI and then sends a 1300Hz signal for 5s. + Pass criteria: 1) The TUT should respond with a 390Hz tone in 1.7+-0.1s. 2) Data should be transmitted and received at 75 bit/s and 1200 bit/s respectively by the TUT to comply with Annex E. Comments: The TUT should indicate that V.23 mode has been selected. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_10_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_10_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -2006,6 +2115,8 @@ static int test_org_10(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -2054,9 +2165,13 @@ static int test_org_10(void) } /*- End of function --------------------------------------------------------*/ +static void org_11_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_org_11(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -2072,23 +2187,23 @@ static int test_org_11(void) Purpose: To confirm correct selection of V.23 reverse mode during sending of XCI. Preamble: N/A Method: The tester should wait for the start of the XCI signal and then send 390Hz to TUT - for 5 seconds. + for 5s. Pass criteria: 1) The TUT should complete the XCI as normal. 2) The TUT should then maintain the 1300Hz tone while the 390Hz test tone is present. 3) Data should be transmitted and received at 1200 bit/s and 75 bit/s respectively by the TUT to comply with Annex E when connection is indicated. - Comments: The TUT should indicate that V.23 mode has been selected at least 3 seconds after + Comments: The TUT should indicate that V.23 mode has been selected at least 3s after the start of the 390Hz tone. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_11_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_11_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -2105,6 +2220,8 @@ static int test_org_11(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -2153,9 +2270,13 @@ static int test_org_11(void) } /*- End of function --------------------------------------------------------*/ +static void org_12_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_org_12(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -2185,14 +2306,14 @@ static int test_org_12(void) automode answer state. The TUT may then select either 45.45 or 50 bit/s for the transmission. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_12_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_12_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -2209,6 +2330,8 @@ static int test_org_12(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -2257,9 +2380,13 @@ static int test_org_12(void) } /*- End of function --------------------------------------------------------*/ +static void org_13_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_org_13(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -2275,7 +2402,7 @@ static int test_org_13(void) Purpose: To verify whether the TUT correctly recognizes DTMF signals during the 2-second interval between transmission of CI. Preamble: N/A - Method: The tester will send a single DTMF tone of 40 ms duration to TUT. When TUT + Method: The tester will send a single DTMF tone of 40ms duration to TUT. When TUT indicates a connection, type at least 5 characters back to the tester so that correct selection of mode can be confirmed. Pass criteria: The tester will analyse the received characters to confirm DTMF mode selection. @@ -2283,14 +2410,14 @@ static int test_org_13(void) TUT should comply with ITU-T Q.24 for the Danish Administration while receiving for best possible performance. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_13_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_13_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -2307,6 +2434,8 @@ static int test_org_13(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -2355,9 +2484,13 @@ static int test_org_13(void) } /*- End of function --------------------------------------------------------*/ +static void org_14_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_org_14(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -2383,14 +2516,14 @@ static int test_org_14(void) the number lost should be minimal. The data bits and parity are specified in Annex C. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_14_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_14_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -2407,6 +2540,8 @@ static int test_org_14(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -2455,9 +2590,13 @@ static int test_org_14(void) } /*- End of function --------------------------------------------------------*/ +static void org_15_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_org_15(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -2473,19 +2612,19 @@ static int test_org_15(void) Purpose: To verify the presence of 980/1180Hz at a different signalling rate than 110 bit/s returns the TUT modem to the "monitor A" state. Preamble: N/A - Method: The tester transmits 980/1180Hz signals at 300 bit/s for 2 seconds. + Method: The tester transmits 980/1180Hz signals at 300 bit/s for 2s. Pass criteria: The TUT should not select EDT or any other mode and should continue to transmit the CI signal. Comments: Echoes of the CI sequences may be detected at 300 bit/s. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_15_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_15_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -2502,6 +2641,8 @@ static int test_org_15(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -2550,9 +2691,13 @@ static int test_org_15(void) } /*- End of function --------------------------------------------------------*/ +static void org_16_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_org_16(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -2567,20 +2712,20 @@ static int test_org_16(void) III.5.4.2.16 980Hz detection Purpose: To confirm correct selection of V.21 reverse mode. Preamble: N/A - Method: The tester sends 980Hz to TUT for 5 seconds. - Pass criteria: 1) TUT should respond with 1650Hz tone after 1.5+-0.1 seconds after start of + Method: The tester sends 980Hz to TUT for 5s. + Pass criteria: 1) TUT should respond with 1650Hz tone after 1.5+-0.1s after start of 980Hz tone. 2) Data should be transmitted and received at 300 bit/s complying with Annex F. Comments: The TUT should indicate that V.21 mode has been selected. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_16_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_16_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -2597,6 +2742,8 @@ static int test_org_16(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -2645,9 +2792,13 @@ static int test_org_16(void) } /*- End of function --------------------------------------------------------*/ +static void org_17_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_org_17(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -2662,18 +2813,18 @@ static int test_org_17(void) III.5.4.2.17 Loss of signal after 980Hz Purpose: To confirm that TUT returns to the Monitor 1 state if 980Hz signal disappears. Preamble: N/A - Method: The tester sends 980Hz to TUT for 1.2 seconds followed by silence for 5 seconds. + Method: The tester sends 980Hz to TUT for 1.2s followed by silence for 5s. Pass criteria: TUT should not respond to the 980Hz tone and resume sending CI signals after a - maximum of 2.4 seconds from the end of the 980Hz tone. + maximum of 2.4s from the end of the 980Hz tone. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_17_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_17_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -2690,6 +2841,8 @@ static int test_org_17(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -2738,9 +2891,13 @@ static int test_org_17(void) } /*- End of function --------------------------------------------------------*/ +static void org_18_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_org_18(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -2755,20 +2912,20 @@ static int test_org_18(void) III.5.4.2.18 Tr timer Purpose: To confirm that TUT returns to the Monitor 1 state if Timer Tr expires. Preamble: N/A - Method: The tester sends 980Hz to TUT for 1.2 seconds followed by 1650Hz for 5 seconds + Method: The tester sends 980Hz to TUT for 1.2s followed by 1650Hz for 5s with no pause. - Pass criteria: TUT should respond with 980Hz after 1.3+-0.1 seconds of 1650Hz. - Comments: This implies timer Tr has expired 2 seconds after the start of the 980Hz tone and - then 1650Hz has been detected for 0.5 seconds. + Pass criteria: TUT should respond with 980Hz after 1.3+-0.1s of 1650Hz. + Comments: This implies timer Tr has expired 2s after the start of the 980Hz tone and + then 1650Hz has been detected for 0.5s. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_18_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_18_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -2785,6 +2942,8 @@ static int test_org_18(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -2833,9 +2992,13 @@ static int test_org_18(void) } /*- End of function --------------------------------------------------------*/ +static void org_19_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_org_19(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -2850,19 +3013,19 @@ static int test_org_19(void) III.5.4.2.19 Bell 103 (1270Hz signal) detection Purpose: To confirm correct selection of Bell 103 reverse mode. Preamble: N/A - Method: The tester sends 1270Hz to TUT for 5 seconds. + Method: The tester sends 1270Hz to TUT for 5s. Pass criteria: 1) TUT should respond with 2225Hz tone after 0.7+-0.1 s. 2) Data should be transmitted and received at 300 bit/s complying with Annex D. Comments: The TUT should indicate that Bell 103 mode has been selected. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_19_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_19_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -2879,6 +3042,8 @@ static int test_org_19(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -2927,9 +3092,13 @@ static int test_org_19(void) } /*- End of function --------------------------------------------------------*/ +static void org_20_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_org_20(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -2956,14 +3125,14 @@ static int test_org_20(void) presence and cadence of the tones for instance by a flashing light. The TUT may disconnect on reception of tones indicating a failed call attempt. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_20_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_20_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -2980,6 +3149,8 @@ static int test_org_20(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -3028,9 +3199,13 @@ static int test_org_20(void) } /*- End of function --------------------------------------------------------*/ +static void org_21_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_org_21(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -3053,14 +3228,14 @@ static int test_org_21(void) Comments: Some high speed modems may fall back to a compatibility mode, e.g. V.21 or V.23 that should be correctly detected by the TUT. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_21_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_21_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -3077,6 +3252,8 @@ static int test_org_21(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -3125,9 +3302,13 @@ static int test_org_21(void) } /*- End of function --------------------------------------------------------*/ +static void org_22_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_org_22(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -3149,14 +3330,14 @@ static int test_org_22(void) Comments: Ideally the TUT should detect the presence of a fax machine and report it back to the user. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_22_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_22_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -3173,6 +3354,8 @@ static int test_org_22(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -3221,9 +3404,13 @@ static int test_org_22(void) } /*- End of function --------------------------------------------------------*/ +static void org_23_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_org_23(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -3245,14 +3432,14 @@ static int test_org_23(void) Comments: Ideally the TUT should report the presence of speech back to the user, e.g. via circuit 135. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_23_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_23_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -3269,6 +3456,8 @@ static int test_org_23(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -3317,9 +3506,13 @@ static int test_org_23(void) } /*- End of function --------------------------------------------------------*/ +static void org_24_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_org_24(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -3337,20 +3530,20 @@ static int test_org_24(void) Preamble: Make a V.18 call from the TUT. Method: The Test System waits for the TUT to stop transmitting a CI and responds with an ANSam signal. The V.21 demodulator is used to decode the CM sequence. ANSam - should be transmitted for 2 seconds. - Pass criteria: 1) No signal should be transmitted by TUT for 0.5 seconds from detection of + should be transmitted for 2s. + Pass criteria: 1) No signal should be transmitted by TUT for 0.5s from detection of ANSam. 2) The TUT should reply with transmission of CM as defined in 5.2.13. 3) Verify that CM sequence has correct bit pattern. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_24_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_24_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -3367,6 +3560,8 @@ static int test_org_24(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -3415,9 +3610,13 @@ static int test_org_24(void) } /*- End of function --------------------------------------------------------*/ +static void org_25_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_org_25(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -3436,14 +3635,14 @@ static int test_org_25(void) Method: The Test System waits for the TUT to start transmitting V.21 carrier (1). Pass criteria: The TUT should connect by sending V.21 carrier (1). */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_25_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, org_25_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -3460,6 +3659,8 @@ static int test_org_25(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -3508,9 +3709,13 @@ static int test_org_25(void) } /*- End of function --------------------------------------------------------*/ +static void ans_01_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_01(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -3523,21 +3728,21 @@ static int test_ans_01(void) /* III.5.4.3.1 Ta timer - Purpose: To ensure that on connecting the call, the DCE starts timer Ta (3 seconds) and on + Purpose: To ensure that on connecting the call, the DCE starts timer Ta (3s) and on expiry begins probing. Preamble: N/A Method: The tester makes a call to the TUT and attempts to determine when the TUT answers the call. It will then monitor for any signal. - Pass criteria: The TUT should start probing 3 seconds after answering the call. + Pass criteria: The TUT should start probing 3s after answering the call. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_01_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_01_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -3554,6 +3759,8 @@ static int test_ans_01(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -3602,9 +3809,13 @@ static int test_ans_01(void) } /*- End of function --------------------------------------------------------*/ +static void ans_02_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_02(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -3619,21 +3830,21 @@ static int test_ans_02(void) III.5.4.3.2 CI signal detection Purpose: To confirm the correct detection and response to the V.18 CI signal. Preamble: N/A - Method: The tester will transmit 2 sequences of 4 CI patterns separated by 2 seconds. It will + Method: The tester will transmit 2 sequences of 4 CI patterns separated by 2s. It will monitor for ANS and measure duration. Pass criteria: 1) The TUT should respond after either the first or second CI with ANSam tone. - 2) ANSam tone should remain for 3 seconds +-0.5 s followed by silence. + 2) ANSam tone should remain for 3s+-0.5s followed by silence. Comments: The ANSam tone is a modulated 2100Hz tone. It may have phase reversals. The XCI signal is tested in a separate test. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_02_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_02_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -3650,6 +3861,8 @@ static int test_ans_02(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -3698,9 +3911,13 @@ static int test_ans_02(void) } /*- End of function --------------------------------------------------------*/ +static void ans_03_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_03(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -3716,24 +3933,24 @@ static int test_ans_03(void) Purpose: To confirm that the TUT will respond correctly to TXP signals, i.e. by stopping ANSam tone on reception of TXP signal. Preamble: N/A - Method: The tester will transmit 2 sequences of 4 CI patterns separated by 2 seconds. On - reception of the ANSam tone the tester will wait 0.5 seconds and then begin + Method: The tester will transmit 2 sequences of 4 CI patterns separated by 2s. On + reception of the ANSam tone the tester will wait 0.5s and then begin transmitting the TXP signal in V.21 (1) mode. - Pass criteria: 1) On reception of the TXP signal, the TUT should remain silent for 75+-5 ms. + Pass criteria: 1) On reception of the TXP signal, the TUT should remain silent for 75+-5ms. 2) The TUT should then transmit 3 TXP sequences in V.21(2) mode. 3) The 3 TXPs should be followed by continuous 1650Hz. 4) Correct transmission and reception of T.140 data should be verified after the V.18 mode connection is completed. Comments: The TUT should indicate V.18 mode. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_03_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_03_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -3750,6 +3967,8 @@ static int test_ans_03(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -3798,9 +4017,13 @@ static int test_ans_03(void) } /*- End of function --------------------------------------------------------*/ +static void ans_04_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_04(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -3817,17 +4040,17 @@ static int test_ans_04(void) timer Tt expires. Preamble: Successful completion of test ANS-03. Method: After completion of test ANS-03 the tester will continue to monitor for signals. - Pass criteria: The TUT should start probing 3 seconds after ANSam disappears. + Pass criteria: The TUT should start probing 3s after ANSam disappears. Comments: It is assumed that timer Ta is restarted on return to Monitor A. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_04_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_04_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -3844,6 +4067,8 @@ static int test_ans_04(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -3892,9 +4117,13 @@ static int test_ans_04(void) } /*- End of function --------------------------------------------------------*/ +static void ans_05_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_05(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -3910,19 +4139,19 @@ static int test_ans_05(void) Purpose: To check correct detection of V.21 modem lower channel when preceded by answer tone. Preamble: N/A - Method: Tester transmits ANS for 2.5 seconds followed by 75 ms of no tone then transmits - 980Hz and starts a 1 s timer. - Pass criteria: TUT should respond with 1650Hz within 400+-100 ms of start of 980Hz. + Method: Tester transmits ANS for 2.5s followed by 75ms of no tone then transmits + 980Hz and starts a 1s timer. + Pass criteria: TUT should respond with 1650Hz within 400+-100ms of start of 980Hz. Comments: The TUT should indicate that V.21 mode has been selected. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_05_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_05_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -3939,6 +4168,8 @@ static int test_ans_05(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -3987,9 +4218,13 @@ static int test_ans_05(void) } /*- End of function --------------------------------------------------------*/ +static void ans_06_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_06(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -4005,19 +4240,19 @@ static int test_ans_06(void) Purpose: To check correct detection of V.23 modem upper channel when preceded by answer tone. Preamble: N/A - Method: Tester transmits ANS for 2.5 seconds followed by 75 ms of no tone then transmits + Method: Tester transmits ANS for 2.5s followed by 75ms of no tone then transmits 1300Hz and starts a 2-s timer. - Pass criteria: TUT should respond with 390Hz after 1.7(+0.2-0.0) seconds of start of 1300Hz. + Pass criteria: TUT should respond with 390Hz after 1.7(+0.2-0.0)s of start of 1300Hz. Comments: The TUT should indicate that V.23 mode has been selected. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_06_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_06_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -4034,6 +4269,8 @@ static int test_ans_06(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -4082,9 +4319,13 @@ static int test_ans_06(void) } /*- End of function --------------------------------------------------------*/ +static void ans_07_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_07(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -4100,19 +4341,19 @@ static int test_ans_07(void) Purpose: To check correct detection of V.21 modem upper channel when preceded by answer tone and to confirm discrimination between V.21 and V.18 modes. Preamble: N/A - Method: Tester transmits ANS for 2.5 seconds followed by 75 ms of no tone then transmits + Method: Tester transmits ANS for 2.5s followed by 75ms of no tone then transmits 1650Hz and starts a 1-second timer. - Pass criteria: TUT should respond with 980Hz within 400+-100 ms of start of 1650Hz. + Pass criteria: TUT should respond with 980Hz within 400+-100ms of start of 1650Hz. Comments: The TUT should indicate that V.21 mode has been selected. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_07_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_07_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -4129,6 +4370,8 @@ static int test_ans_07(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -4177,9 +4420,13 @@ static int test_ans_07(void) } /*- End of function --------------------------------------------------------*/ +static void ans_08_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_08(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -4200,16 +4447,16 @@ static int test_ans_08(void) Pass criteria: The TUT should respond with the appropriate carrier depending on when it connects. Comments: The TUT should indicate a V.21 connection. The time for which each frequency is - transmitted is random and varies between 0.64 and 2.56 seconds. + transmitted is random and varies between 0.64 and 2.56s. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_08_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_08_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -4226,6 +4473,8 @@ static int test_ans_08(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -4274,9 +4523,13 @@ static int test_ans_08(void) } /*- End of function --------------------------------------------------------*/ +static void ans_09_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_09(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -4291,21 +4544,21 @@ static int test_ans_09(void) III.5.4.3.9 980Hz calling tone detection Purpose: To confirm correct detection of 980Hz calling tones as defined in V.25. Preamble: N/A - Method: The tester will send bursts of 980Hz signals (a) 400 ms, (b) 500 ms, (c) 700 ms and - (d) 800 ms followed by 1 second of silence. - Pass criteria: 1) The TUT should not respond to bursts of 400 or 800 ms. - 2) The TUT should immediately begin probing after a burst of 980Hz for 500 or - 700 ms followed by 1 second of silence. + Method: The tester will send bursts of 980Hz signals (a) 400ms, (b) 500ms, (c) 700ms and + (d) 800ms followed by 1s of silence. + Pass criteria: 1) The TUT should not respond to bursts of 400ms or 800ms. + 2) The TUT should immediately begin probing after a burst of 980Hz for 500ms or + 700ms followed by 1s of silence. Comments: The probe sent by the TUT will depend on the country setting. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_09_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_09_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -4322,6 +4575,8 @@ static int test_ans_09(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -4370,9 +4625,13 @@ static int test_ans_09(void) } /*- End of function --------------------------------------------------------*/ +static void ans_10_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_10(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -4388,18 +4647,18 @@ static int test_ans_10(void) Purpose: To confirm correct selection of V.21 calling modem when the received signal is not modulated, i.e. there is no 1180Hz. Preamble: N/A - Method: The tester sends 980Hz to TUT for 2 seconds. - Pass criteria: The TUT should respond with a 1650Hz tone in 1.5+-0.1 seconds. + Method: The tester sends 980Hz to TUT for 2s. + Pass criteria: The TUT should respond with a 1650Hz tone in 1.5+-0.1s. Comments: The TUT should indicate that V.21 mode has been selected. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_10_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_10_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -4416,6 +4675,8 @@ static int test_ans_10(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -4464,9 +4725,13 @@ static int test_ans_10(void) } /*- End of function --------------------------------------------------------*/ +static void ans_11_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_11(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -4490,14 +4755,14 @@ static int test_ans_11(void) be lost during the detection process. However, the number lost should be minimal. The data bits and parity are specified in Annex C. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_11_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_11_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -4514,6 +4779,8 @@ static int test_ans_11(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -4562,9 +4829,13 @@ static int test_ans_11(void) } /*- End of function --------------------------------------------------------*/ +static void ans_12_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_12(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -4589,14 +4860,14 @@ static int test_ans_12(void) (1650Hz) probe. However, it is catered for in V.18. It is more likely that this is where CI or TXP characters would be detected (see test ANS-02). */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_12_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_12_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -4613,6 +4884,8 @@ static int test_ans_12(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -4661,9 +4934,13 @@ static int test_ans_12(void) } /*- End of function --------------------------------------------------------*/ +static void ans_13_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_13(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -4677,24 +4954,24 @@ static int test_ans_13(void) /* III.5.4.3.13 Tr timer Purpose: To ensure that the TUT returns to the Monitor A state on expiry of timer Tr - (2 seconds). Timer Tr is started when a modulated V.21 (1) signal is detected. + (2s). Timer Tr is started when a modulated V.21 (1) signal is detected. Preamble: N/A - Method: The tester will transmit 980Hz for 200 ms followed by alternating 980Hz/1180Hz - at 110 bit/s for 100 ms followed by 980Hz for 1 second. - Pass criteria: The TUT should begin probing 4+-0.5 seconds after the 980Hz signal is removed. + Method: The tester will transmit 980Hz for 200ms followed by alternating 980Hz/1180Hz + at 110 bit/s for 100ms followed by 980Hz for 1s. + Pass criteria: The TUT should begin probing 4+-0.5s after the 980Hz signal is removed. Comments: It is not possible to be precise on timings for this test since the definition of a "modulated signal" as in 5.2.4.4 is not specified. Therefore it is not known exactly when timer Tr will start. It is assumed that timer Ta is restarted on re-entering the Monitor A state. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_13_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_13_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -4711,6 +4988,8 @@ static int test_ans_13(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -4759,9 +5038,13 @@ static int test_ans_13(void) } /*- End of function --------------------------------------------------------*/ +static void ans_14_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_14(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -4775,21 +5058,21 @@ static int test_ans_14(void) /* III.5.4.3.14 Te timer Purpose: To ensure that the TUT returns to the Monitor A on expiry of timer Te - (2.7 seconds). Timer Te is started when a 980Hz signal is detected. + (2.7s). Timer Te is started when a 980Hz signal is detected. Preamble: N/A - Method: The tester will transmit 980Hz for 200 ms followed silence for 7 s. - Pass criteria: The TUT should begin probing 5.5+-0.5 seconds after the 980Hz signal is removed. - Comments: It is assumed that timer Ta (3 seconds) is restarted on re-entering the Monitor A + Method: The tester will transmit 980Hz for 200ms followed silence for 7 s. + Pass criteria: The TUT should begin probing 5.5+-0.5s after the 980Hz signal is removed. + Comments: It is assumed that timer Ta (3s) is restarted on re-entering the Monitor A state. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_14_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_14_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -4806,6 +5089,8 @@ static int test_ans_14(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -4854,9 +5139,13 @@ static int test_ans_14(void) } /*- End of function --------------------------------------------------------*/ +static void ans_15_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_15(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -4887,14 +5176,14 @@ static int test_ans_15(void) automode answer state. The TUT may then select either 45.45 or 50 bit/s for the transmission. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_15_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_15_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -4911,6 +5200,8 @@ static int test_ans_15(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -4959,9 +5250,13 @@ static int test_ans_15(void) } /*- End of function --------------------------------------------------------*/ +static void ans_16_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_16(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -4976,21 +5271,21 @@ static int test_ans_16(void) III.5.4.3.16 DTMF signal detection Purpose: To verify whether the TUT correctly recognizes DTMF signals. Preamble: N/A - Method: The tester will send a single DTMF tone of 40 ms duration to TUT. When TUT + Method: The tester will send a single DTMF tone of 40ms duration to TUT. When TUT indicates a connection, type at least 5 characters back to the tester so that correct selection of mode can be confirmed. Pass criteria: Tester will analyse the received characters to confirm DTMF mode selection. Comments: The TUT should indicate that it has selected DTMF mode. The DTMF capabilities of the TUT should comply with ITU-T Q.24 for the Danish Administration. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_16_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_16_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -5007,6 +5302,8 @@ static int test_ans_16(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -5055,9 +5352,13 @@ static int test_ans_16(void) } /*- End of function --------------------------------------------------------*/ +static void ans_17_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_17(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -5072,18 +5373,18 @@ static int test_ans_17(void) III.5.4.3.17 Bell 103 (1270Hz signal) detection Purpose: To ensure correct detection and selection of Bell 103 modems. Preamble: N/A - Method: The tester sends 1270Hz to TUT for 5 seconds. - Pass criteria: TUT should respond with 2225Hz tone after 0.7+-0.1 s. + Method: The tester sends 1270Hz to TUT for 5s. + Pass criteria: TUT should respond with 2225Hz tone after 0.7+-0.1s. Comments: The TUT should indicate that Bell 103 mode has been selected. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_17_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_17_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -5100,6 +5401,8 @@ static int test_ans_17(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -5148,9 +5451,13 @@ static int test_ans_17(void) } /*- End of function --------------------------------------------------------*/ +static void ans_18_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_18(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -5165,19 +5472,19 @@ static int test_ans_18(void) III.5.4.3.18 Bell 103 (2225Hz signal) detection Purpose: To ensure correct detection and selection of Bell 103 modems in reverse mode. Preamble: N/A - Method: The tester sends 2225Hz to TUT for 5 seconds. - Pass criteria: The TUT should respond with 1270Hz after 1+-0.2 seconds. + Method: The tester sends 2225Hz to TUT for 5s. + Pass criteria: The TUT should respond with 1270Hz after 1+-0.2s. Comments: The TUT should indicate that Bell 103 mode has been selected. Bell 103 modems use 2225Hz as both answer tone and higher frequency of the upper channel. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_18_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_18_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -5194,6 +5501,8 @@ static int test_ans_18(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -5242,9 +5551,13 @@ static int test_ans_18(void) } /*- End of function --------------------------------------------------------*/ +static void ans_19_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_19(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -5259,18 +5572,18 @@ static int test_ans_19(void) III.5.4.3.19 V.21 Reverse mode (1650Hz) detection Purpose: To ensure correct detection and selection of V.21 reverse mode. Preamble: N/A - Method: The tester sends 1650Hz to TUT for 5 seconds. - Pass criteria: The TUT should respond with 980Hz after 0.4+-0.2 seconds. + Method: The tester sends 1650Hz to TUT for 5s. + Pass criteria: The TUT should respond with 980Hz after 0.4+-0.2s. Comments: The TUT should indicate that V.21 mode has been selected. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_19_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_19_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -5287,6 +5600,8 @@ static int test_ans_19(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -5335,9 +5650,13 @@ static int test_ans_19(void) } /*- End of function --------------------------------------------------------*/ +static void ans_20_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_20(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -5352,21 +5671,21 @@ static int test_ans_20(void) III.5.4.3.20 1300Hz calling tone discrimination Purpose: To confirm correct detection of 1300Hz calling tones as defined in ITU-T V.25. Preamble: N/A - Method: The tester will send 1300Hz bursts of (a) 400 ms, (b) 500 ms, (c) 700 ms and - (d) 800 ms followed by 1 second of silence. - Pass criteria: 1) The TUT should not respond to bursts of 400 or 800 ms. - 2) The TUT should immediately begin probing after a burst of 1300Hz for 500 or - 700 ms followed by 1 second of silence. + Method: The tester will send 1300Hz bursts of (a) 400ms, (b) 500ms, (c) 700ms and + (d) 800ms followed by 1s of silence. + Pass criteria: 1) The TUT should not respond to bursts of 400ms or 800ms. + 2) The TUT should immediately begin probing after a burst of 1300Hz for 500ms or + 700ms followed by 1s of silence. Comments: The probe sent by the TUT will depend on the country setting. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_20_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_20_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -5383,6 +5702,8 @@ static int test_ans_20(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -5431,9 +5752,13 @@ static int test_ans_20(void) } /*- End of function --------------------------------------------------------*/ +static void ans_21_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_21(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -5448,18 +5773,18 @@ static int test_ans_21(void) III.5.4.3.21 V.23 Reverse mode (1300Hz) detection Purpose: To ensure correct detection and selection of V.23 reverse mode. Preamble: N/A - Method: The tester sends 1300Hz only, with no XCI signals, to TUT for 5 seconds. - Pass criteria: The TUT should respond with 390Hz after 1.7+-0.1 seconds. + Method: The tester sends 1300Hz only, with no XCI signals, to TUT for 5s. + Pass criteria: The TUT should respond with 390Hz after 1.7+-0.1s. Comments: The TUT should indicate that V.23 mode has been selected. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_21_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_21_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -5476,6 +5801,8 @@ static int test_ans_21(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -5524,9 +5851,13 @@ static int test_ans_21(void) } /*- End of function --------------------------------------------------------*/ +static void ans_22_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_22(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -5542,17 +5873,17 @@ static int test_ans_22(void) Purpose: To ensure correct detection of the XCI signal and selection of V.18 mode. Preamble: N/A Method: The tester sends XCI signal as defined in 3.11. On reception of ANS it will become - silent for 500 ms then transmit the TXP signal in V.21 (1) mode. + silent for 500ms then transmit the TXP signal in V.21 (1) mode. Pass criteria: The TUT should respond with TXP using V.21 (2) and select V.18 mode. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_22_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_22_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -5569,6 +5900,8 @@ static int test_ans_22(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -5617,9 +5950,13 @@ static int test_ans_22(void) } /*- End of function --------------------------------------------------------*/ +static void ans_23_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_23(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -5641,14 +5978,14 @@ static int test_ans_23(void) Pass criteria: The TUT should use the orders described in Appendix I. Comments: The order of the probes is not mandatory. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_23_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_23_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -5665,6 +6002,8 @@ static int test_ans_23(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -5713,9 +6052,13 @@ static int test_ans_23(void) } /*- End of function --------------------------------------------------------*/ +static void ans_24_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_24(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -5734,17 +6077,17 @@ static int test_ans_24(void) Method: The tester will call the TUT, wait for Ta to expire and then monitor the probes sent by the TUT. Pass criteria: The TUT should send the user defined probe message for Annexes A, B, and C - modes followed by a pause of Tm (default 3) seconds. + modes followed by a pause of Tm (default 3)s. Comments: The carrierless modes are those described in Annexes A, B and C. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_24_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_24_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -5761,6 +6104,8 @@ static int test_ans_24(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -5809,9 +6154,13 @@ static int test_ans_24(void) } /*- End of function --------------------------------------------------------*/ +static void ans_25_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_25(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -5825,22 +6174,22 @@ static int test_ans_25(void) /* III.5.4.3.25 Interrupted carrierless mode probe Purpose: To ensure that the TUT continues probing from the point of interruption a maximum - of 20 s after a failed connect attempt. + of 20s after a failed connect attempt. Preamble: The TUT should be configured for the UK country setting. Method: The tester will call the TUT, wait for Ta to expire and then during the pause after - the first Baudot probe it will send a 200 ms burst of 1270Hz followed by silence - for 30 s. + the first Baudot probe it will send a 200ms burst of 1270Hz followed by silence + for 30s. Pass criteria: The TUT should transmit silence on detecting the 1270Hz tone and then continue - probing starting with the V.23 probe 20 seconds after the end of the 1270Hz signal. + probing starting with the V.23 probe 20s after the end of the 1270Hz signal. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_25_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_25_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -5857,6 +6206,8 @@ static int test_ans_25(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -5905,9 +6256,13 @@ static int test_ans_25(void) } /*- End of function --------------------------------------------------------*/ +static void ans_26_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_26(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -5920,23 +6275,23 @@ static int test_ans_26(void) /* III.5.4.3.26 Stimulate carrier mode probe time - Purpose: To ensure that the TUT sends each carrier mode for time Tc (default 6 seconds) + Purpose: To ensure that the TUT sends each carrier mode for time Tc (default 6s) preceded by the correct answer tone. Preamble: None. Method: The tester will call the TUT, wait for Ta to expire and then monitor the probes sent by the TUT. - Pass criteria: The TUT should send the ANS tone (2100Hz) for 1 second followed by silence for - 75+-5 ms and then the 1650Hz, 1300Hz and 2225Hz probes for time Tc. + Pass criteria: The TUT should send the ANS tone (2100Hz) for 1s followed by silence for + 75+-5ms and then the 1650Hz, 1300Hz and 2225Hz probes for time Tc. Comments: The carrier modes are those described in Annexes D, E, and F. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_26_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_26_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -5953,6 +6308,8 @@ static int test_ans_26(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -6001,9 +6358,13 @@ static int test_ans_26(void) } /*- End of function --------------------------------------------------------*/ +static void ans_27_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_27(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -6019,24 +6380,24 @@ static int test_ans_27(void) Purpose: To confirm correct selection of V.23 mode. Preamble: N/A Method: The tester waits until the 1300Hz probe is detected from the TUT and then - transmits 390Hz for 11 seconds. - Pass criteria: 1) After 3 seconds of the 390Hz signal the TUT should indicate that V.23 has + transmits 390Hz for 11s. + Pass criteria: 1) After 3s of the 390Hz signal the TUT should indicate that V.23 has been selected. 2) The tester will confirm that the 1300Hz carrier is maintained for at least - 4 seconds beyond the normal probe duration, i.e. Tc (= 6 s default) + 4 s = - 10 seconds total. + 4s beyond the normal probe duration, i.e. Tc (= 6s default) + 4s = + 10s total. Comments: All known V.23 devices need to receive 1300Hz tone before they will respond with 390Hz. When the 1300Hz probe is not being transmitted, a 390Hz tone may be interpreted as a 400Hz network tone. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_27_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_27_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -6053,6 +6414,8 @@ static int test_ans_27(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -6101,9 +6464,13 @@ static int test_ans_27(void) } /*- End of function --------------------------------------------------------*/ +static void ans_28_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_28(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -6117,24 +6484,24 @@ static int test_ans_28(void) /* III.5.4.3.28 Interrupted carrier mode probe Purpose: To ensure that the TUT continues probing from the point of interruption a maximum - of 4 s after a failed connect attempt. + of 4s after a failed connect attempt. Preamble: The TUT should be configured for the UK country setting. Method: The tester will call the TUT, wait for Ta to expire and then during the first V.21 - probe it will send a 200 ms burst of 1270Hz followed by silence for 30 s. + probe it will send a 200ms burst of 1270Hz followed by silence for 30s. Pass criteria: The TUT should transmit silence on detecting the 1270Hz tone and then continue - probing with the Baudot stored message 4 seconds after the end of the 1270Hz + probing with the Baudot stored message 4s after the end of the 1270Hz burst. - Comments: It is most likely that the TUT will return to probing time Ta (3 seconds) after the + Comments: It is most likely that the TUT will return to probing time Ta (3s) after the 1270Hz tone ceases. This condition needs further clarification. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_28_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_28_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -6151,6 +6518,8 @@ static int test_ans_28(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -6199,9 +6568,13 @@ static int test_ans_28(void) } /*- End of function --------------------------------------------------------*/ +static void ans_29_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_29(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -6224,14 +6597,14 @@ static int test_ans_29(void) Comments: The TUT may not respond to any signals while a carrierless mode probe is being sent since these modes are half duplex. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_29_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_29_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -6248,6 +6621,8 @@ static int test_ans_29(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -6296,9 +6671,13 @@ static int test_ans_29(void) } /*- End of function --------------------------------------------------------*/ +static void ans_30_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_30(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -6323,14 +6702,14 @@ static int test_ans_30(void) tones may be ignored. Some devices may only provide a visual indication of the presence and cadence of the tones for instance by a flashing light. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_30_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_30_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -6347,6 +6726,8 @@ static int test_ans_30(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -6395,9 +6776,13 @@ static int test_ans_30(void) } /*- End of function --------------------------------------------------------*/ +static void ans_31_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_31(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -6413,20 +6798,20 @@ static int test_ans_31(void) Purpose: To determine whether the TUT can discriminate fax calling tones. Preamble: N/A Method: The tester will call the TUT and send the fax calling tone, CNG. This is an 1100Hz - tone with cadence of 0.5 seconds ON and 3 seconds OFF as defined in ITU-T T.30. + tone with cadence of 0.5s ON and 3s OFF as defined in ITU-T T.30. Pass criteria: The TUT should not respond to this signal and may report it as being a calling fax machine. Comments: This is an optional test as detection of the fax calling tone is not required by ITU-T V.18. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_31_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_31_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -6443,6 +6828,8 @@ static int test_ans_31(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -6491,9 +6878,13 @@ static int test_ans_31(void) } /*- End of function --------------------------------------------------------*/ +static void ans_32_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_32(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -6515,14 +6906,14 @@ static int test_ans_32(void) Comments: Ideally the TUT should report the presence of speech back to the user. This is an optional test. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_32_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_32_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -6539,6 +6930,8 @@ static int test_ans_32(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -6587,9 +6980,13 @@ static int test_ans_32(void) } /*- End of function --------------------------------------------------------*/ +static void ans_33_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_ans_33(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -6605,8 +7002,8 @@ static int test_ans_33(void) Purpose: To confirm that the TUT will respond correctly to CM signals and connect according to V.8 procedures. Preamble: N/A - Method: The tester will transmit 2 sequences of 4 CI patterns separated by 2 seconds. On - reception of the ANSam tone the tester will wait 0.5 seconds and then begin + Method: The tester will transmit 2 sequences of 4 CI patterns separated by 2s. On + reception of the ANSam tone the tester will wait 0.5s and then begin transmitting the CM signal with textphone and V.21 specified. Pass criteria: 1) On reception of the CM signal, the TUT should transmit JM with textphone and V.21. @@ -6616,14 +7013,14 @@ static int test_ans_33(void) V.18 mode connection is completed. Comments: The TUT should indicate V.18 mode. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_33_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, ans_33_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -6640,6 +7037,8 @@ static int test_ans_33(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -6688,6 +7087,11 @@ static int test_ans_33(void) } /*- End of function --------------------------------------------------------*/ +static void mon_01_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_mon_01(void) { printf("Test not yet implemented\n"); @@ -6695,9 +7099,13 @@ static int test_mon_01(void) } /*- End of function --------------------------------------------------------*/ +static void mon_21_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_mon_21(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -6710,21 +7118,21 @@ static int test_mon_21(void) /* III.5.4.4.1 Automode monitor Ta timer test - Purpose: To ensure that on entering monitor mode, timer Ta (3 seconds) is not active and that + Purpose: To ensure that on entering monitor mode, timer Ta (3s) is not active and that the TUT does not enter the probing state. Preamble: N/A Method: The TUT should be put into monitor state. The tester will then monitor for signals for 1 minute. Pass criteria: The TUT should not start probing. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, mon_21_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, mon_21_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -6741,6 +7149,8 @@ static int test_mon_21(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -6789,9 +7199,13 @@ static int test_mon_21(void) } /*- End of function --------------------------------------------------------*/ +static void mon_22_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_mon_22(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -6807,22 +7221,22 @@ static int test_mon_22(void) Purpose: To confirm correct detection and reporting of 1300Hz calling tones as defined in ITU-T V.25. Preamble: N/A - Method: The tester will send 1300Hz bursts of (a) 400 ms, (b) 500 ms, (c) 700 ms and - (d) 800 ms followed by 1 second of silence. - Pass criteria: 1) The TUT should not respond to bursts of 400 or 800 ms. + Method: The tester will send 1300Hz bursts of (a) 400ms, (b) 500ms, (c) 700ms and + (d) 800ms followed by 1s of silence. + Pass criteria: 1) The TUT should not respond to bursts of 400ms or 800ms. 2) The TUT should report detection of calling tones to the DTE after a burst of - 1300Hz for 500 or 700 ms followed by 1 second of silence. + 1300Hz for 500ms or 700ms followed by 1s of silence. Comments: In automode answer, the 1300Hz calling causes the DCE to start probing. In monitor mode it should only report detection to the DTE. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, mon_22_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, mon_22_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -6839,6 +7253,8 @@ static int test_mon_22(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -6887,9 +7303,13 @@ static int test_mon_22(void) } /*- End of function --------------------------------------------------------*/ +static void mon_23_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_mon_23(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -6905,22 +7325,22 @@ static int test_mon_23(void) Purpose: To confirm correct detection and reporting of 980Hz calling tones as defined in ITU-T V.25. Preamble: N/A - Method: The tester will send 980Hz bursts of (a) 400 ms, (b) 500 ms, (c) 700 ms and - (d) 800 ms followed by 1 second of silence. - Pass criteria: 1) The TUT should not respond to bursts of 400 or 800 ms. + Method: The tester will send 980Hz bursts of (a) 400ms, (b) 500ms, (c) 700ms and + (d) 800ms followed by 1s of silence. + Pass criteria: 1) The TUT should not respond to bursts of 400ms or 800ms. 2) The TUT should report detection of calling tones to the DTE after a burst of - 980Hz for 500 or 700 ms followed by 1 second of silence. + 980Hz for 500ms or 700ms followed by 1s of silence. Comments: In automode answer, the 980Hz calling causes the DCE to start probing. In monitor mode it should only report detection to the DTE. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, mon_23_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, mon_23_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -6937,6 +7357,8 @@ static int test_mon_23(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -6989,7 +7411,7 @@ static void x_01_put_text_msg(void *user_data, const uint8_t *msg, int len) { printf("1-1 %d '%s'\n", len, msg); if (user_data == NULL) - strcat(result, (const char *) msg); + strcat(result[1], (const char *) msg); else v18_put(v18[1], "abcdefghij", 10); } @@ -7010,26 +7432,26 @@ static int test_x_01(void) /* III.5.4.5.1 Baudot carrier timing and receiver disabling - Purpose: To verify that the TUT sends unmodulated carrier for 150 ms before a new character - and disables its receiver for 300 ms after a character is transmitted. + Purpose: To verify that the TUT sends unmodulated carrier for 150ms before a new character + and disables its receiver for 300ms after a character is transmitted. Preamble: Establish a call between the tester and TUT in Baudot mode. Method: The operator should send a single character from the TUT. The tester will immediately start sending a unique character sequence. Examination of the TUT display will show when its receiver is re-enabled. - Pass criteria: 1) The TUT should send unmodulated carrier for 150 ms before the beginning of + Pass criteria: 1) The TUT should send unmodulated carrier for 150ms before the beginning of the start bit. - 2) The receiver should be re-enabled after 300 ms. + 2) The receiver should be re-enabled after 300ms. 3) The tester will confirm that 1 start bit and at least 1.5 stop bits are used. - Comments: The carrier should be maintained during the 300 ms after a character. + Comments: The carrier should be maintained during the 300ms after a character. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_5BIT_45, x_01_put_text_msg, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_5BIT_4545, V18_AUTOMODING_GLOBAL, x_01_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_5BIT_45, x_01_put_text_msg, (void *) (intptr_t) 1); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_5BIT_4545, V18_AUTOMODING_GLOBAL, x_01_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -7046,7 +7468,9 @@ static int test_x_01(void) exit(2); } - v18_put(v18[0], "z", 1); + result[0][0] = + result[1][0] = '\0'; + v18_put(v18[0], "zabcdefghijklmnopq", -1); for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -7091,17 +7515,21 @@ static int test_x_01(void) v18_free(v18[0]); v18_free(v18[1]); ref = "cdefghij"; - printf("Result:\n%s\n", result); + printf("Result:\n%s\n", result[1]); printf("Reference result:\n%s\n", ref); - if (unexpected_echo || strcmp(result, ref) != 0) + if (unexpected_echo || strcmp(result[1], ref) != 0) return -1; return 1; } /*- End of function --------------------------------------------------------*/ +static void x_02_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_x_02(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -7121,14 +7549,14 @@ static int test_x_02(void) transmit the string "abcdef" at each rate. Pass criteria: The tester will measure the bit timings and confirm the rates. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_5BIT_45, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_5BIT_4545, V18_AUTOMODING_GLOBAL, x_02_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_5BIT_45, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_5BIT_4545, V18_AUTOMODING_GLOBAL, x_02_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -7145,6 +7573,8 @@ static int test_x_02(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -7193,9 +7623,13 @@ static int test_x_02(void) } /*- End of function --------------------------------------------------------*/ +static void x_03_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_x_03(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -7218,14 +7652,14 @@ static int test_x_03(void) Comments: The probe message must be long enough for the tester to establish the bit rate. "GA" may not be sufficient. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_5BIT_45, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_5BIT_4545, V18_AUTOMODING_USA, x_03_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_5BIT_45, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_5BIT_4545, V18_AUTOMODING_USA, x_03_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -7242,6 +7676,8 @@ static int test_x_03(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -7290,24 +7726,27 @@ static int test_x_03(void) } /*- End of function --------------------------------------------------------*/ -static void x_04_put_echo_text_msg(void *user_data, const uint8_t *msg, int len) -{ - printf("Unexpected ECHO received (%d) '%s'\n", len, msg); - unexpected_echo = TRUE; -} -/*- End of function --------------------------------------------------------*/ - static void x_04_put_text_msg(void *user_data, const uint8_t *msg, int len) { + if (user_data == NULL) + { + strcat(result[0], (const char *) msg); +printf("Unexpected ECHO received (%d) '%s'\n", len, msg); + unexpected_echo = true; + } + else + { printf("1-1 %d '%s'\n", len, msg); - strcat(result, (const char *) msg); + strcat(result[1], (const char *) msg); + /* Echo each received character */ + //v18_put(v18[1], msg, len); + } } /*- End of function --------------------------------------------------------*/ static int test_x_04(void) { char msg[1024]; - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -7336,14 +7775,14 @@ static int test_x_04(void) assumed that the character conversion is the same for Baudot at 50 bit/s and any other supported speed. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_5BIT_45, x_04_put_echo_text_msg, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_5BIT_4545 | V18_MODE_REPETITIVE_SHIFTS_OPTION, V18_AUTOMODING_GLOBAL, x_04_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_5BIT_45, x_04_put_text_msg, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_5BIT_4545 | V18_MODE_REPETITIVE_SHIFTS_OPTION, V18_AUTOMODING_GLOBAL, x_04_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -7360,14 +7799,15 @@ static int test_x_04(void) exit(2); } - result[0] = '\0'; - unexpected_echo = FALSE; + result[0][0] = + result[1][0] = '\0'; + unexpected_echo = false; for (i = 0; i < 127; i++) msg[i] = i + 1; msg[127] = '\0'; v18_put(v18[0], msg, 127); - for (i = 0; i < 1000; i++) + for (i = 0; i < 2000; i++) { for (j = 0; j < 2; j++) { @@ -7409,9 +7849,10 @@ static int test_x_04(void) v18_free(v18[0]); v18_free(v18[1]); - printf("Result:\n%s\n", result); + printf("Result:\n%s\n", result[0]); + printf("Result:\n%s\n", result[1]); printf("Reference result:\n%s\n", full_baudot_rx); - if (unexpected_echo || strcmp(result, full_baudot_rx) != 0) + if (unexpected_echo || strcmp(result[1], full_baudot_rx) != 0) return -1; return 0; } @@ -7420,9 +7861,18 @@ static int test_x_04(void) static void x_05_put_text_msg(void *user_data, const uint8_t *msg, int len) { if (user_data == NULL) - strcat(result, (const char *) msg); + { + /* Gather the received characters, which should be like the transmitted characters, + but with the first three characters missing. */ + strcat(result[0], (const char *) msg); + } else + { + /* Receiving a character from the far end should block out its receiver + for a while. If we send a stream of DTMF back, the first few characters + (actually 3 for this particular text string) should be lost. */ v18_put(v18[1], "behknqtwz", 9); + } } /*- End of function --------------------------------------------------------*/ @@ -7441,23 +7891,23 @@ static int test_x_05(void) /* III.5.4.5.5 DTMF receiver disabling - Purpose: To verify that the TUT disables its DTMF receiver for 300 ms when a character is + Purpose: To verify that the TUT disables its DTMF receiver for 300ms when a character is transmitted. Preamble: Establish a call between the tester and TUT in DTMF mode. Method: The operator should send a single "e" character from the TUT which will result in sending a single DTMF tone to the tester. The tester will immediately start sending a unique character sequence using single DTMF tones. Examination of the TUT display will show when its receiver is re-enabled. - Pass criteria: The receiver should be re-enabled after 300 ms. + Pass criteria: The receiver should be re-enabled after 300ms. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, x_05_put_text_msg, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, x_05_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, x_05_put_text_msg, (void *) (intptr_t) 1); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, x_05_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -7474,8 +7924,10 @@ static int test_x_05(void) exit(2); } - result[0] = '\0'; - v18_put(v18[0], "e", 1); + result[0][0] = + result[1][0] = '\0'; + /* Sending a character should block out the receiver for a while */ + v18_put(v18[0], "z", 1); for (i = 0; i < 1000; i++) { @@ -7521,9 +7973,9 @@ static int test_x_05(void) v18_free(v18[0]); v18_free(v18[1]); ref = "knqtwz"; - printf("Result:\n%s\n", result); + printf("Result:\n%s\n", result[0]); printf("Reference result:\n%s\n", ref); - if (strcmp(result, ref) != 0) + if (strcmp(result[0], ref) != 0) return -1; return 0; } @@ -7531,16 +7983,17 @@ static int test_x_05(void) static void x_06_put_text_msg(void *user_data, const uint8_t *msg, int len) { - strcat(result, (const char *) msg); + if (user_data == NULL) + ; + else + strcat(result[1], (const char *) msg); } /*- End of function --------------------------------------------------------*/ static int test_x_06(void) { char msg[128]; - char dtmf[1024]; const char *ref; - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -7560,19 +8013,19 @@ static int test_x_06(void) after each one. Each character should be responded to at the TUT by typing the same character. Pass criteria: The tester will verify that each character is correctly echoed back by the TUT. - Comments: The conversion table is specified in Annex B. The receiver at the tester may be re- - enabled 100 ms after transmission of each character to maximize likelihood of + Comments: The conversion table is specified in Annex B. The receiver at the tester may be + re-enabled 100ms after transmission of each character to maximize likelihood of receiving character from the TUT. It is assumed that the echo delay in the test system is negligible. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, x_06_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, x_06_put_text_msg, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, x_06_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -7589,15 +8042,12 @@ static int test_x_06(void) exit(2); } - result[0] = '\0'; + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 127; i++) msg[i] = i + 1; msg[127] = '\0'; - printf("Original:\n%s\n", msg); - - v18_encode_dtmf(NULL, dtmf, msg); - printf("DTMF:\n%s\n", dtmf); - v18_decode_dtmf(NULL, result, dtmf); + v18_put(v18[0], msg, 127); for (i = 0; i < 10000; i++) { @@ -7640,23 +8090,27 @@ static int test_x_06(void) v18_rx(v18[1], model_amp[0], samples); } - ref = "\b \n\n\n?\n\n\n %+().+,-.0123456789:;(=)" - "?XABCDEFGHIJKLMNOPQRSTUVWXYZ\xC6\xD8\xC5" + ref = "\b \n\n\n?\n\n\n !%+().+,-.0123456789:;(=)?" + "XABCDEFGHIJKLMNOPQRSTUVWXYZ\xC6\xD8\xC5" " abcdefghijklmnopqrstuvwxyz\xE6\xF8\xE5 \b"; - printf("Result:\n%s\n", result); + printf("Result:\n%s\n", result[0]); printf("Reference result:\n%s\n", ref); v18_free(v18[0]); v18_free(v18[1]); - if (strcmp(result, ref) != 0) + if (strcmp(result[1], ref) != 0) return -1; return 0; } /*- End of function --------------------------------------------------------*/ +static void x_07_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_x_07(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -7669,26 +8123,26 @@ static int test_x_07(void) /* III.5.4.5.7 EDT carrier timing and receiver disabling - Purpose: To verify that the TUT sends unmodulated carrier for 300 ms before a character and - disables its receiver for 300 ms after a character is transmitted. + Purpose: To verify that the TUT sends unmodulated carrier for 300ms before a character and + disables its receiver for 300ms after a character is transmitted. Preamble: Establish a call between the tester and TUT in EDT mode. Method: The operator should send a single character from the TUT. The tester will immediately start sending a unique character sequence. Examination of the TUT display will show when its receiver is re-enabled. - Pass criteria: 1) The TUT should send unmodulated carrier for 300 ms before the beginning of + Pass criteria: 1) The TUT should send unmodulated carrier for 300ms before the beginning of the start bit. - 2) The receiver should be re-enabled after 300 ms. + 2) The receiver should be re-enabled after 300ms. 3) The tester will confirm that 1 start bit and at least 1.5 stop bits are used. - Comments: The carrier should be maintained during the 300 ms after a character. + Comments: The carrier should be maintained during the 300ms after a character. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, x_07_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, x_07_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -7705,6 +8159,8 @@ static int test_x_07(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -7753,9 +8209,13 @@ static int test_x_07(void) } /*- End of function --------------------------------------------------------*/ +static void x_08_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_x_08(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -7776,14 +8236,14 @@ static int test_x_08(void) 2) The tester should confirm that 1 start bit, 7 data bits, 1 even parity bit and 2 stop bits are used. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, x_08_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, x_08_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -7800,6 +8260,8 @@ static int test_x_08(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -7848,9 +8310,13 @@ static int test_x_08(void) } /*- End of function --------------------------------------------------------*/ +static void x_09_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_x_09(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -7874,14 +8340,14 @@ static int test_x_09(void) that there are no duplicate characters on the TUT display. 3) The received string should be correctly displayed despite the incorrect parity. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, x_09_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, x_09_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -7898,6 +8364,8 @@ static int test_x_09(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -7946,9 +8414,13 @@ static int test_x_09(void) } /*- End of function --------------------------------------------------------*/ +static void x_10_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_x_10(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -7975,14 +8447,14 @@ static int test_x_10(void) Comments: This test is only applicable to Minitel Dialogue terminals. Prestel and Minitel Normal terminals cannot operate in this mode. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, x_10_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, x_10_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -7999,6 +8471,8 @@ static int test_x_10(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -8047,9 +8521,13 @@ static int test_x_10(void) } /*- End of function --------------------------------------------------------*/ +static void x_11_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_x_11(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -8074,14 +8552,14 @@ static int test_x_11(void) 4) The last five characters on the TUT display should be "12345" (no "6") correctly displayed despite the incorrect parity. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, x_11_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, x_11_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -8098,6 +8576,8 @@ static int test_x_11(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -8146,9 +8626,13 @@ static int test_x_11(void) } /*- End of function --------------------------------------------------------*/ +static void x_12_put_text_msg(void *user_data, const uint8_t *msg, int len) +{ +} +/*- End of function --------------------------------------------------------*/ + static int test_x_12(void) { - v18_state_t *v18[2]; logging_state_t *logging; int16_t amp[2][SAMPLES_PER_CHUNK]; int16_t model_amp[2][SAMPLES_PER_CHUNK]; @@ -8170,14 +8654,14 @@ static int test_x_12(void) Pass criteria: The tester should confirm UTF8 encoded UNICODE characters are used with the controls specified in ITU-T T.140. */ - v18[0] = v18_init(NULL, TRUE, V18_MODE_DTMF, NULL, NULL); + v18[0] = v18_init(NULL, true, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, x_12_put_text_msg, (void *) (intptr_t) 0); logging = v18_get_logging_state(v18[0]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "A"); - v18[1] = v18_init(NULL, FALSE, V18_MODE_DTMF, NULL, NULL); + span_log_set_tag(logging, "Tester"); + v18[1] = v18_init(NULL, false, V18_MODE_DTMF, V18_AUTOMODING_GLOBAL, x_12_put_text_msg, (void *) (intptr_t) 1); logging = v18_get_logging_state(v18[1]); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_tag(logging, "B"); + span_log_set_tag(logging, "TUT"); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, @@ -8194,6 +8678,8 @@ static int test_x_12(void) exit(2); } + result[0][0] = + result[1][0] = '\0'; for (i = 0; i < 10000; i++) { for (j = 0; j < 2; j++) @@ -8267,7 +8753,7 @@ static int decode_test_data_file(int mode, const char *filename) fprintf(stderr, " Cannot open audio file '%s'\n", decode_test_file); exit(2); } - v18_state = v18_init(NULL, FALSE, mode, put_v18_msg, NULL); + v18_state = v18_init(NULL, false, mode, V18_AUTOMODING_GLOBAL, put_v18_msg, NULL); logging = v18_get_logging_state(v18_state); span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); span_log_set_tag(logging, ""); @@ -8393,7 +8879,7 @@ int main(int argc, char *argv[]) { int i; int res; - int hit; + bool hit; const char *match; int test_standard; int opt; @@ -8408,7 +8894,7 @@ int main(int argc, char *argv[]) decode_test_file = optarg; break; case 'l': - log_audio = TRUE; + log_audio = true; break; case 's': test_standard = atoi(optarg); @@ -8439,7 +8925,7 @@ int main(int argc, char *argv[]) } } - hit = FALSE; + hit = false; for (i = 0; test_list[i].title[0]; i++) { if (test_list[i].func @@ -8450,7 +8936,7 @@ int main(int argc, char *argv[]) && test_list[i].title[strlen(match)] == ' '))) { - hit = TRUE; + hit = true; printf("%s\n", test_list[i].title); res = test_list[i].func(); if (res < 0) @@ -8474,8 +8960,8 @@ int main(int argc, char *argv[]) printf("Test not found\n"); exit(2); } - basic_tests(V18_MODE_5BIT_45); - basic_tests(V18_MODE_5BIT_45 | 0x100); + basic_tests(V18_MODE_5BIT_4545); + basic_tests(V18_MODE_5BIT_4545 | V18_MODE_REPETITIVE_SHIFTS_OPTION); if (log_audio) { if (sf_close_telephony(outhandle)) diff --git a/libs/spandsp/tests/v22bis_tests.c b/libs/spandsp/tests/v22bis_tests.c index aade32c726..3729687c35 100644 --- a/libs/spandsp/tests/v22bis_tests.c +++ b/libs/spandsp/tests/v22bis_tests.c @@ -63,7 +63,7 @@ display of modem status is maintained. #define OUT_FILE_NAME "v22bis.wav" char *decode_test_file = NULL; -int use_gui = FALSE; +bool use_gui = false; int rx_bits = 0; @@ -266,11 +266,11 @@ int main(int argc, char *argv[]) int bits_per_test; int noise_level; int signal_level; - int log_audio; int channel_codec; int rbs_pattern; int guard_tone_option; int opt; + bool log_audio; channel_codec = MUNGE_CODEC_NONE; rbs_pattern = 0; @@ -281,7 +281,7 @@ int main(int argc, char *argv[]) signal_level = -13; bits_per_test = 50000; guard_tone_option = V22BIS_GUARD_TONE_1800HZ; - log_audio = FALSE; + log_audio = false; while ((opt = getopt(argc, argv, "b:B:c:d:gG:lm:n:r:s:")) != -1) { switch (opt) @@ -305,7 +305,7 @@ int main(int argc, char *argv[]) break; case 'g': #if defined(ENABLE_GUI) - use_gui = TRUE; + use_gui = true; #else fprintf(stderr, "Graphical monitoring not available\n"); exit(2); @@ -315,7 +315,7 @@ int main(int argc, char *argv[]) guard_tone_option = atoi(optarg); break; case 'l': - log_audio = TRUE; + log_audio = true; break; case 'm': line_model_no = atoi(optarg); diff --git a/libs/spandsp/tests/v27ter_tests.c b/libs/spandsp/tests/v27ter_tests.c index cb1b74a88c..671fd935af 100644 --- a/libs/spandsp/tests/v27ter_tests.c +++ b/libs/spandsp/tests/v27ter_tests.c @@ -78,7 +78,7 @@ display of modem status is maintained. #define OUT_FILE_NAME "v27ter.wav" char *decode_test_file = NULL; -int use_gui = FALSE; +bool use_gui = false; int symbol_no = 0; @@ -341,30 +341,30 @@ int main(int argc, char *argv[]) SNDFILE *outhandle; int outframes; int samples; - int tep; int test_bps; int noise_level; int signal_level; int bits_per_test; int line_model_no; int block_no; - int log_audio; int channel_codec; int rbs_pattern; int opt; + bool tep; + bool log_audio; logging_state_t *logging; channel_codec = MUNGE_CODEC_NONE; rbs_pattern = 0; test_bps = 4800; - tep = FALSE; + tep = false; line_model_no = 0; decode_test_file = NULL; - use_gui = FALSE; + use_gui = false; noise_level = -70; signal_level = -13; bits_per_test = 50000; - log_audio = FALSE; + log_audio = false; while ((opt = getopt(argc, argv, "b:B:c:d:glm:n:r:s:t")) != -1) { switch (opt) @@ -388,14 +388,14 @@ int main(int argc, char *argv[]) break; case 'g': #if defined(ENABLE_GUI) - use_gui = TRUE; + use_gui = true; #else fprintf(stderr, "Graphical monitoring not available\n"); exit(2); #endif break; case 'l': - log_audio = TRUE; + log_audio = true; break; case 'm': line_model_no = atoi(optarg); @@ -410,7 +410,7 @@ int main(int argc, char *argv[]) signal_level = atoi(optarg); break; case 't': - tep = TRUE; + tep = true; break; default: //usage(); @@ -537,7 +537,7 @@ int main(int argc, char *argv[]) signal_level--; v27ter_tx_restart(tx, test_bps, tep); v27ter_tx_power(tx, signal_level); - v27ter_rx_restart(rx, test_bps, FALSE); + v27ter_rx_restart(rx, test_bps, false); bert_init(&bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); bert_set_report(&bert, 10000, reporter, NULL); one_way_line_model_release(line_model); diff --git a/libs/spandsp/tests/v29_tests.c b/libs/spandsp/tests/v29_tests.c index 246c217fd1..ec678c148a 100644 --- a/libs/spandsp/tests/v29_tests.c +++ b/libs/spandsp/tests/v29_tests.c @@ -78,7 +78,7 @@ display of modem status is maintained. #define OUT_FILE_NAME "v29.wav" char *decode_test_file = NULL; -int use_gui = FALSE; +bool use_gui = false; int symbol_no = 0; int rx_bits = 0; @@ -315,30 +315,30 @@ int main(int argc, char *argv[]) SNDFILE *outhandle; int outframes; int samples; - int tep; int test_bps; int noise_level; int signal_level; int bits_per_test; int line_model_no; int block_no; - int log_audio; int channel_codec; int rbs_pattern; int opt; + bool tep; + bool log_audio; logging_state_t *logging; channel_codec = MUNGE_CODEC_NONE; rbs_pattern = 0; test_bps = 9600; - tep = FALSE; + tep = false; line_model_no = 0; decode_test_file = NULL; - use_gui = FALSE; + use_gui = false; noise_level = -70; signal_level = -13; bits_per_test = 50000; - log_audio = FALSE; + log_audio = false; while ((opt = getopt(argc, argv, "b:B:c:d:glm:n:r:s:t")) != -1) { switch (opt) @@ -362,14 +362,14 @@ int main(int argc, char *argv[]) break; case 'g': #if defined(ENABLE_GUI) - use_gui = TRUE; + use_gui = true; #else fprintf(stderr, "Graphical monitoring not available\n"); exit(2); #endif break; case 'l': - log_audio = TRUE; + log_audio = true; break; case 'm': line_model_no = atoi(optarg); @@ -384,7 +384,7 @@ int main(int argc, char *argv[]) signal_level = atoi(optarg); break; case 't': - tep = TRUE; + tep = true; break; default: //usage(); @@ -514,7 +514,7 @@ int main(int argc, char *argv[]) signal_level--; v29_tx_restart(tx, test_bps, tep); v29_tx_power(tx, signal_level); - v29_rx_restart(rx, test_bps, FALSE); + v29_rx_restart(rx, test_bps, false); #if defined(SPANDSP_EXPOSE_INTERNAL_STRUCTURES) rx->eq_put_step = rand()%(48*10/3); #endif diff --git a/libs/spandsp/tests/v42_tests.c b/libs/spandsp/tests/v42_tests.c index fc4a9b17cc..727b5a8b58 100644 --- a/libs/spandsp/tests/v42_tests.c +++ b/libs/spandsp/tests/v42_tests.c @@ -128,14 +128,14 @@ static void v42_put_frames(void *user_data, const uint8_t msg[], int len) { if (++count == 5) { - v42_set_local_busy_status(s, TRUE); + v42_set_local_busy_status(s, true); xxx = 1; } } else { if (xxx && ++count == 45) - v42_set_local_busy_status(caller, FALSE); + v42_set_local_busy_status(caller, false); } } /*- End of function --------------------------------------------------------*/ @@ -144,13 +144,13 @@ int main(int argc, char *argv[]) { int i; int bit; - int insert_caller_bit_errors; - int insert_answerer_bit_errors; + bool insert_caller_bit_errors; + bool insert_answerer_bit_errors; int opt; - insert_caller_bit_errors = FALSE; - insert_answerer_bit_errors = FALSE; - variable_length = FALSE; + insert_caller_bit_errors = false; + insert_answerer_bit_errors = false; + variable_length = false; while ((opt = getopt(argc, argv, "bv")) != -1) { switch (opt) @@ -160,7 +160,7 @@ int main(int argc, char *argv[]) insert_answerer_bit_errors = 10000; break; case 'v': - variable_length = TRUE; + variable_length = true; break; default: //usage(); @@ -169,8 +169,8 @@ int main(int argc, char *argv[]) } } - caller = v42_init(&callerx, TRUE, TRUE, v42_get_frames, v42_put_frames, (void *) &callerx); - answerer = v42_init(&answererx, FALSE, TRUE, v42_get_frames, v42_put_frames, (void *) &answererx); + caller = v42_init(&callerx, true, true, v42_get_frames, v42_put_frames, (void *) &callerx); + answerer = v42_init(&answererx, false, true, v42_get_frames, v42_put_frames, (void *) &answererx); v42_set_status_callback(caller, v42_status, (void *) caller); v42_set_status_callback(answerer, v42_status, (void *) answerer); v42_restart(caller); diff --git a/libs/spandsp/tests/v42bis_tests.c b/libs/spandsp/tests/v42bis_tests.c index cc95967c54..2ce718feba 100644 --- a/libs/spandsp/tests/v42bis_tests.c +++ b/libs/spandsp/tests/v42bis_tests.c @@ -82,8 +82,8 @@ int main(int argc, char *argv[]) int v42bis_fd; int out_fd; int do_compression; - int do_decompression; - int stutter_compression; + bool do_decompression; + bool stutter_compression; int stutter_time; int seg; int opt; @@ -94,21 +94,21 @@ int main(int argc, char *argv[]) const char *decompressed_file; argv0 = argv[0]; - do_compression = FALSE; - do_decompression = FALSE; - stutter_compression = FALSE; + do_compression = false; + do_decompression = false; + stutter_compression = false; while ((opt = getopt(argc, argv, "cds")) != -1) { switch (opt) { case 'c': - do_compression = TRUE; + do_compression = true; break; case 'd': - do_decompression = TRUE; + do_decompression = true; break; case 's': - stutter_compression = TRUE; + stutter_compression = true; break; default: //usage(); diff --git a/libs/spandsp/tests/v8_tests.c b/libs/spandsp/tests/v8_tests.c index d9ef7b82b9..df9243691e 100644 --- a/libs/spandsp/tests/v8_tests.c +++ b/libs/spandsp/tests/v8_tests.c @@ -41,9 +41,6 @@ #include "spandsp.h" #include "spandsp-sim.h" -#define FALSE 0 -#define TRUE (!FALSE) - #define SAMPLES_PER_CHUNK 160 #define OUTPUT_FILE_NAME "v8.wav" @@ -202,7 +199,7 @@ static int v8_calls_v8_tests(SNDFILE *outhandle) negotiations_ok = 0; v8_call_parms.modem_connect_tone = MODEM_CONNECT_TONES_NONE; - v8_call_parms.send_ci = TRUE; + v8_call_parms.send_ci = true; v8_call_parms.v92 = -1; v8_call_parms.call_function = V8_CALL_V_SERIES; v8_call_parms.modulations = caller_available_modulations; @@ -212,12 +209,12 @@ static int v8_calls_v8_tests(SNDFILE *outhandle) v8_call_parms.nsf = -1; v8_call_parms.t66 = -1; v8_caller = v8_init(NULL, - TRUE, + true, &v8_call_parms, handler, (void *) "caller"); v8_answer_parms.modem_connect_tone = MODEM_CONNECT_TONES_ANSAM_PR; - v8_answer_parms.send_ci = TRUE; + v8_answer_parms.send_ci = true; v8_answer_parms.v92 = -1; v8_answer_parms.call_function = V8_CALL_V_SERIES; v8_answer_parms.modulations = answerer_available_modulations; @@ -227,7 +224,7 @@ static int v8_calls_v8_tests(SNDFILE *outhandle) v8_answer_parms.nsf = -1; v8_answer_parms.t66 = -1; v8_answerer = v8_init(NULL, - FALSE, + false, &v8_answer_parms, handler, (void *) "answerer"); @@ -329,7 +326,7 @@ static int non_v8_calls_v8_tests(SNDFILE *outhandle) non_v8_caller_rx = modem_connect_tones_rx_init(NULL, MODEM_CONNECT_TONES_ANS_PR, NULL, NULL); v8_answer_parms.modem_connect_tone = MODEM_CONNECT_TONES_ANSAM_PR; - v8_answer_parms.send_ci = TRUE; + v8_answer_parms.send_ci = true; v8_answer_parms.v92 = -1; v8_answer_parms.call_function = V8_CALL_V_SERIES; v8_answer_parms.modulations = answerer_available_modulations; @@ -339,7 +336,7 @@ static int non_v8_calls_v8_tests(SNDFILE *outhandle) v8_answer_parms.nsf = -1; v8_answer_parms.t66 = -1; v8_answerer = v8_init(NULL, - FALSE, + false, &v8_answer_parms, handler, (void *) "answerer"); @@ -441,7 +438,7 @@ static int v8_calls_non_v8_tests(SNDFILE *outhandle) negotiations_ok = 0; v8_call_parms.modem_connect_tone = MODEM_CONNECT_TONES_NONE; - v8_call_parms.send_ci = TRUE; + v8_call_parms.send_ci = true; v8_call_parms.v92 = -1; v8_call_parms.call_function = V8_CALL_V_SERIES; v8_call_parms.modulations = caller_available_modulations; @@ -451,7 +448,7 @@ static int v8_calls_non_v8_tests(SNDFILE *outhandle) v8_call_parms.nsf = -1; v8_call_parms.t66 = -1; v8_caller = v8_init(NULL, - TRUE, + true, &v8_call_parms, handler, (void *) "caller"); @@ -522,7 +519,7 @@ int main(int argc, char *argv[]) SNDFILE *inhandle; SNDFILE *outhandle; int opt; - int log_audio; + bool log_audio; char *decode_test_file; v8_state_t *v8_caller; v8_state_t *v8_answerer; @@ -531,7 +528,7 @@ int main(int argc, char *argv[]) logging_state_t *logging; decode_test_file = NULL; - log_audio = FALSE; + log_audio = false; while ((opt = getopt(argc, argv, "d:l")) != -1) { switch (opt) @@ -540,7 +537,7 @@ int main(int argc, char *argv[]) decode_test_file = optarg; break; case 'l': - log_audio = TRUE; + log_audio = true; break; default: //usage(); @@ -582,7 +579,7 @@ int main(int argc, char *argv[]) printf("Decode file '%s'\n", decode_test_file); v8_call_parms.modem_connect_tone = MODEM_CONNECT_TONES_NONE; - v8_call_parms.send_ci = TRUE; + v8_call_parms.send_ci = true; v8_call_parms.v92 = -1; v8_call_parms.call_function = V8_CALL_V_SERIES; v8_call_parms.modulations = caller_available_modulations; @@ -592,7 +589,7 @@ int main(int argc, char *argv[]) v8_call_parms.nsf = -1; v8_call_parms.t66 = -1; v8_caller = v8_init(NULL, - TRUE, + true, &v8_call_parms, handler, (void *) "caller"); @@ -601,7 +598,7 @@ int main(int argc, char *argv[]) span_log_set_tag(logging, "caller"); v8_answer_parms.modem_connect_tone = MODEM_CONNECT_TONES_ANSAM_PR; - v8_answer_parms.send_ci = TRUE; + v8_answer_parms.send_ci = true; v8_answer_parms.v92 = -1; v8_answer_parms.call_function = V8_CALL_V_SERIES; v8_answer_parms.modulations = answerer_available_modulations; @@ -611,7 +608,7 @@ int main(int argc, char *argv[]) v8_answer_parms.nsf = -1; v8_answer_parms.t66 = -1; v8_answerer = v8_init(NULL, - FALSE, + false, &v8_answer_parms, handler, (void *) "answerer"); diff --git a/libs/spandsp/tests/vector_float_tests.c b/libs/spandsp/tests/vector_float_tests.c index 26df593864..d6d1b95112 100644 --- a/libs/spandsp/tests/vector_float_tests.c +++ b/libs/spandsp/tests/vector_float_tests.c @@ -54,8 +54,8 @@ static int test_vec_copyf(void) for (i = 0; i < 99; i++) { x[i] = i; - za[i] = -1.0f; - zb[i] = -1.0f; + za[i] = -0.5f; + zb[i] = -0.5f; } vec_copyf_dumb(za + 3, x + 1, 0); vec_copyf(zb + 3, x + 1, 0); @@ -114,8 +114,8 @@ static int test_vec_negatef(void) for (i = 0; i < 99; i++) { x[i] = i; - za[i] = -1.0f; - zb[i] = -1.0f; + za[i] = -0.5f; + zb[i] = -0.5f; } vec_negatef_dumb(za + 3, x + 1, 0); vec_negatef(zb + 3, x + 1, 0); @@ -143,6 +143,7 @@ static int test_vec_negatef(void) vec_negatef(zb + 3, x + 1, 29); for (i = 0; i < 99; i++) { +printf("C %d %f %f %f\n", i, x[i], za[i], zb[i]); if (za[i] != zb[i]) { printf("vec_negatef() - %d %f %f\n", i, za[i], zb[i]); diff --git a/libs/spandsp/yum-prepare.sh b/libs/spandsp/yum-prepare.sh new file mode 100644 index 0000000000..e41200482b --- /dev/null +++ b/libs/spandsp/yum-prepare.sh @@ -0,0 +1,26 @@ +: + +# +# Install the things which need adding to a fresh Fedora or Centos install to make it ready to build +# spandsp and its test suite +# +yum groupinstall "Development tools" +yum install fftw-devel \ + libtiff-tools \ + libtiff-devel \ + libjpeg-turbo-devel \ + libpcap-devel \ + libxml2-devel \ + libsndfile-devel \ + fltk-devel \ + fltk-fluid \ + libstdc++-devel \ + libstdc++-static \ + sox \ + gcc-c++ \ + libtool \ + autconf \ + automake \ + m4 \ + netpbm \ + netpbm-progs